script/dom/webgl/
webglsampler.rs1use 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}