script/dom/webgl/
webgltransformfeedback.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::cell::Cell;
6
7use canvas_traits::webgl::{WebGLCommand, webgl_channel};
8use dom_struct::dom_struct;
9
10use crate::dom::bindings::inheritance::Castable;
11use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
12use crate::dom::bindings::root::DomRoot;
13use crate::dom::webgl::webglobject::WebGLObject;
14use crate::dom::webgl::webglrenderingcontext::{Operation, WebGLRenderingContext};
15use crate::script_runtime::CanGc;
16
17#[dom_struct]
18pub(crate) struct WebGLTransformFeedback {
19    webgl_object: WebGLObject,
20    id: u32,
21    marked_for_deletion: Cell<bool>,
22    has_been_bound: Cell<bool>,
23    is_active: Cell<bool>,
24    is_paused: Cell<bool>,
25}
26
27impl WebGLTransformFeedback {
28    fn new_inherited(context: &WebGLRenderingContext, id: u32) -> Self {
29        Self {
30            webgl_object: WebGLObject::new_inherited(context),
31            id,
32            marked_for_deletion: Cell::new(false),
33            has_been_bound: Cell::new(false),
34            is_active: Cell::new(false),
35            is_paused: Cell::new(false),
36        }
37    }
38
39    pub(crate) fn new(context: &WebGLRenderingContext, can_gc: CanGc) -> DomRoot<Self> {
40        let (sender, receiver) = webgl_channel().unwrap();
41        context.send_command(WebGLCommand::CreateTransformFeedback(sender));
42        let id = receiver.recv().unwrap();
43
44        reflect_dom_object(
45            Box::new(WebGLTransformFeedback::new_inherited(context, id)),
46            &*context.global(),
47            can_gc,
48        )
49    }
50}
51
52impl WebGLTransformFeedback {
53    pub(crate) fn context(&self) -> &WebGLRenderingContext {
54        self.upcast::<WebGLObject>().context()
55    }
56
57    pub(crate) fn bind(&self, context: &WebGLRenderingContext, target: u32) {
58        context.send_command(WebGLCommand::BindTransformFeedback(target, self.id()));
59        self.has_been_bound.set(true);
60    }
61
62    pub(crate) fn begin(&self, context: &WebGLRenderingContext, primitive_mode: u32) {
63        if self.has_been_bound.get() && !self.is_active() {
64            context.send_command(WebGLCommand::BeginTransformFeedback(primitive_mode));
65            self.set_active(true);
66        }
67    }
68
69    pub(crate) fn end(&self, context: &WebGLRenderingContext) {
70        if self.has_been_bound.get() && self.is_active() {
71            if self.is_paused() {
72                context.send_command(WebGLCommand::ResumeTransformFeedback());
73            }
74            context.send_command(WebGLCommand::EndTransformFeedback());
75            self.set_active(false);
76        }
77    }
78
79    pub(crate) fn resume(&self, context: &WebGLRenderingContext) {
80        if self.is_active() && self.is_paused() {
81            context.send_command(WebGLCommand::ResumeTransformFeedback());
82            self.set_pause(false);
83        }
84    }
85
86    pub(crate) fn pause(&self, context: &WebGLRenderingContext) {
87        if self.is_active() && !self.is_paused() {
88            context.send_command(WebGLCommand::PauseTransformFeedback());
89            self.set_pause(true);
90        }
91    }
92
93    pub(crate) fn id(&self) -> u32 {
94        self.id
95    }
96
97    pub(crate) fn is_valid(&self) -> bool {
98        !self.marked_for_deletion.get()
99    }
100
101    pub(crate) fn is_active(&self) -> bool {
102        self.is_active.get()
103    }
104
105    pub(crate) fn is_paused(&self) -> bool {
106        self.is_paused.get()
107    }
108
109    pub(crate) fn delete(&self, operation_fallibility: Operation) {
110        if self.is_valid() && self.id() != 0 {
111            self.marked_for_deletion.set(true);
112            let context = self.upcast::<WebGLObject>().context();
113            let cmd = WebGLCommand::DeleteTransformFeedback(self.id);
114            match operation_fallibility {
115                Operation::Fallible => context.send_command_ignored(cmd),
116                Operation::Infallible => context.send_command(cmd),
117            }
118        }
119    }
120
121    pub(crate) fn set_active(&self, value: bool) {
122        if self.is_valid() && self.has_been_bound.get() {
123            self.is_active.set(value);
124        }
125    }
126
127    pub(crate) fn set_pause(&self, value: bool) {
128        if self.is_valid() && self.is_active() {
129            self.is_active.set(value);
130        }
131    }
132}
133
134impl Drop for WebGLTransformFeedback {
135    fn drop(&mut self) {
136        self.delete(Operation::Fallible);
137    }
138}