script/dom/webgl/
webglsampler.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::WebGLError::*;
8use canvas_traits::webgl::{WebGLCommand, WebGLSamplerId, webgl_channel};
9use dom_struct::dom_struct;
10
11use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants as constants;
12use crate::dom::bindings::inheritance::Castable;
13use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
14use crate::dom::bindings::root::DomRoot;
15use crate::dom::webgl::webglobject::WebGLObject;
16use crate::dom::webgl::webglrenderingcontext::{Operation, WebGLRenderingContext};
17use crate::script_runtime::CanGc;
18
19#[dom_struct]
20pub(crate) struct WebGLSampler {
21    webgl_object: WebGLObject,
22    #[no_trace]
23    gl_id: WebGLSamplerId,
24    marked_for_deletion: Cell<bool>,
25}
26
27#[derive(Clone, Copy)]
28pub(crate) enum WebGLSamplerValue {
29    Float(f32),
30    GLenum(u32),
31}
32
33fn validate_params(pname: u32, value: WebGLSamplerValue) -> bool {
34    match value {
35        WebGLSamplerValue::GLenum(value) => {
36            let allowed_values = match pname {
37                constants::TEXTURE_MIN_FILTER => &[
38                    constants::NEAREST,
39                    constants::LINEAR,
40                    constants::NEAREST_MIPMAP_NEAREST,
41                    constants::LINEAR_MIPMAP_NEAREST,
42                    constants::NEAREST_MIPMAP_LINEAR,
43                    constants::LINEAR_MIPMAP_LINEAR,
44                ][..],
45                constants::TEXTURE_MAG_FILTER => &[constants::NEAREST, constants::LINEAR][..],
46                constants::TEXTURE_WRAP_R |
47                constants::TEXTURE_WRAP_S |
48                constants::TEXTURE_WRAP_T => &[
49                    constants::CLAMP_TO_EDGE,
50                    constants::MIRRORED_REPEAT,
51                    constants::REPEAT,
52                ][..],
53                constants::TEXTURE_COMPARE_MODE => {
54                    &[constants::NONE, constants::COMPARE_REF_TO_TEXTURE][..]
55                },
56                constants::TEXTURE_COMPARE_FUNC => &[
57                    constants::LEQUAL,
58                    constants::GEQUAL,
59                    constants::LESS,
60                    constants::GREATER,
61                    constants::EQUAL,
62                    constants::NOTEQUAL,
63                    constants::ALWAYS,
64                    constants::NEVER,
65                ][..],
66                _ => &[][..],
67            };
68            allowed_values.contains(&value)
69        },
70        WebGLSamplerValue::Float(_) => matches!(
71            pname,
72            constants::TEXTURE_MIN_LOD | constants::TEXTURE_MAX_LOD
73        ),
74    }
75}
76
77impl WebGLSampler {
78    fn new_inherited(context: &WebGLRenderingContext, id: WebGLSamplerId) -> Self {
79        Self {
80            webgl_object: WebGLObject::new_inherited(context),
81            gl_id: id,
82            marked_for_deletion: Cell::new(false),
83        }
84    }
85
86    pub(crate) fn new(context: &WebGLRenderingContext, can_gc: CanGc) -> DomRoot<Self> {
87        let (sender, receiver) = webgl_channel().unwrap();
88        context.send_command(WebGLCommand::GenerateSampler(sender));
89        let id = receiver.recv().unwrap();
90
91        reflect_dom_object(
92            Box::new(Self::new_inherited(context, id)),
93            &*context.global(),
94            can_gc,
95        )
96    }
97
98    pub(crate) fn delete(&self, operation_fallibility: Operation) {
99        if !self.marked_for_deletion.get() {
100            self.marked_for_deletion.set(true);
101
102            let command = WebGLCommand::DeleteSampler(self.gl_id);
103            let context = self.upcast::<WebGLObject>().context();
104            match operation_fallibility {
105                Operation::Fallible => context.send_command_ignored(command),
106                Operation::Infallible => context.send_command(command),
107            }
108        }
109    }
110
111    pub(crate) fn is_valid(&self) -> bool {
112        !self.marked_for_deletion.get()
113    }
114
115    pub(crate) fn bind(
116        &self,
117        context: &WebGLRenderingContext,
118        unit: u32,
119    ) -> Result<(), canvas_traits::webgl::WebGLError> {
120        if !self.is_valid() {
121            return Err(InvalidOperation);
122        }
123        context.send_command(WebGLCommand::BindSampler(unit, self.gl_id));
124        Ok(())
125    }
126
127    pub(crate) fn set_parameter(
128        &self,
129        context: &WebGLRenderingContext,
130        pname: u32,
131        value: WebGLSamplerValue,
132    ) -> Result<(), canvas_traits::webgl::WebGLError> {
133        if !self.is_valid() {
134            return Err(InvalidOperation);
135        }
136        if !validate_params(pname, value) {
137            return Err(InvalidEnum);
138        }
139        let command = match value {
140            WebGLSamplerValue::GLenum(value) => {
141                WebGLCommand::SetSamplerParameterInt(self.gl_id, pname, value as i32)
142            },
143            WebGLSamplerValue::Float(value) => {
144                WebGLCommand::SetSamplerParameterFloat(self.gl_id, pname, value)
145            },
146        };
147        context.send_command(command);
148        Ok(())
149    }
150
151    pub(crate) fn get_parameter(
152        &self,
153        context: &WebGLRenderingContext,
154        pname: u32,
155    ) -> Result<WebGLSamplerValue, canvas_traits::webgl::WebGLError> {
156        if !self.is_valid() {
157            return Err(InvalidOperation);
158        }
159        match pname {
160            constants::TEXTURE_MIN_FILTER |
161            constants::TEXTURE_MAG_FILTER |
162            constants::TEXTURE_WRAP_R |
163            constants::TEXTURE_WRAP_S |
164            constants::TEXTURE_WRAP_T |
165            constants::TEXTURE_COMPARE_FUNC |
166            constants::TEXTURE_COMPARE_MODE => {
167                let (sender, receiver) = webgl_channel().unwrap();
168                context.send_command(WebGLCommand::GetSamplerParameterInt(
169                    self.gl_id, pname, sender,
170                ));
171                Ok(WebGLSamplerValue::GLenum(receiver.recv().unwrap() as u32))
172            },
173            constants::TEXTURE_MIN_LOD | constants::TEXTURE_MAX_LOD => {
174                let (sender, receiver) = webgl_channel().unwrap();
175                context.send_command(WebGLCommand::GetSamplerParameterFloat(
176                    self.gl_id, pname, sender,
177                ));
178                Ok(WebGLSamplerValue::Float(receiver.recv().unwrap()))
179            },
180            _ => Err(InvalidEnum),
181        }
182    }
183}
184
185impl Drop for WebGLSampler {
186    fn drop(&mut self) {
187        self.delete(Operation::Fallible);
188    }
189}