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 bind(&self, context: &WebGLRenderingContext, target: u32) {
54        context.send_command(WebGLCommand::BindTransformFeedback(target, self.id()));
55        self.has_been_bound.set(true);
56    }
57
58    pub(crate) fn begin(&self, context: &WebGLRenderingContext, primitive_mode: u32) {
59        if self.has_been_bound.get() && !self.is_active() {
60            context.send_command(WebGLCommand::BeginTransformFeedback(primitive_mode));
61            self.set_active(true);
62        }
63    }
64
65    pub(crate) fn end(&self, context: &WebGLRenderingContext) {
66        if self.has_been_bound.get() && self.is_active() {
67            if self.is_paused() {
68                context.send_command(WebGLCommand::ResumeTransformFeedback());
69            }
70            context.send_command(WebGLCommand::EndTransformFeedback());
71            self.set_active(false);
72        }
73    }
74
75    pub(crate) fn resume(&self, context: &WebGLRenderingContext) {
76        if self.is_active() && self.is_paused() {
77            context.send_command(WebGLCommand::ResumeTransformFeedback());
78            self.set_pause(false);
79        }
80    }
81
82    pub(crate) fn pause(&self, context: &WebGLRenderingContext) {
83        if self.is_active() && !self.is_paused() {
84            context.send_command(WebGLCommand::PauseTransformFeedback());
85            self.set_pause(true);
86        }
87    }
88
89    pub(crate) fn id(&self) -> u32 {
90        self.id
91    }
92
93    pub(crate) fn is_valid(&self) -> bool {
94        !self.marked_for_deletion.get()
95    }
96
97    pub(crate) fn is_active(&self) -> bool {
98        self.is_active.get()
99    }
100
101    pub(crate) fn is_paused(&self) -> bool {
102        self.is_paused.get()
103    }
104
105    pub(crate) fn delete(&self, operation_fallibility: Operation) {
106        if self.is_valid() && self.id() != 0 {
107            self.marked_for_deletion.set(true);
108            let context = self.upcast::<WebGLObject>().context();
109            let cmd = WebGLCommand::DeleteTransformFeedback(self.id);
110            match operation_fallibility {
111                Operation::Fallible => context.send_command_ignored(cmd),
112                Operation::Infallible => context.send_command(cmd),
113            }
114        }
115    }
116
117    pub(crate) fn set_active(&self, value: bool) {
118        if self.is_valid() && self.has_been_bound.get() {
119            self.is_active.set(value);
120        }
121    }
122
123    pub(crate) fn set_pause(&self, value: bool) {
124        if self.is_valid() && self.is_active() {
125            self.is_active.set(value);
126        }
127    }
128}
129
130impl Drop for WebGLTransformFeedback {
131    fn drop(&mut self) {
132        self.delete(Operation::Fallible);
133    }
134}