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 self.upcast().send_with_fallibility(
102 WebGLCommand::DeleteSampler(self.gl_id),
103 operation_fallibility,
104 );
105 }
106 }
107
108 pub(crate) fn is_valid(&self) -> bool {
109 !self.marked_for_deletion.get()
110 }
111
112 pub(crate) fn bind(
113 &self,
114 context: &WebGLRenderingContext,
115 unit: u32,
116 ) -> Result<(), canvas_traits::webgl::WebGLError> {
117 if !self.is_valid() {
118 return Err(InvalidOperation);
119 }
120 context.send_command(WebGLCommand::BindSampler(unit, self.gl_id));
121 Ok(())
122 }
123
124 pub(crate) fn set_parameter(
125 &self,
126 context: &WebGLRenderingContext,
127 pname: u32,
128 value: WebGLSamplerValue,
129 ) -> Result<(), canvas_traits::webgl::WebGLError> {
130 if !self.is_valid() {
131 return Err(InvalidOperation);
132 }
133 if !validate_params(pname, value) {
134 return Err(InvalidEnum);
135 }
136 let command = match value {
137 WebGLSamplerValue::GLenum(value) => {
138 WebGLCommand::SetSamplerParameterInt(self.gl_id, pname, value as i32)
139 },
140 WebGLSamplerValue::Float(value) => {
141 WebGLCommand::SetSamplerParameterFloat(self.gl_id, pname, value)
142 },
143 };
144 context.send_command(command);
145 Ok(())
146 }
147
148 pub(crate) fn get_parameter(
149 &self,
150 context: &WebGLRenderingContext,
151 pname: u32,
152 ) -> Result<WebGLSamplerValue, canvas_traits::webgl::WebGLError> {
153 if !self.is_valid() {
154 return Err(InvalidOperation);
155 }
156 match pname {
157 constants::TEXTURE_MIN_FILTER |
158 constants::TEXTURE_MAG_FILTER |
159 constants::TEXTURE_WRAP_R |
160 constants::TEXTURE_WRAP_S |
161 constants::TEXTURE_WRAP_T |
162 constants::TEXTURE_COMPARE_FUNC |
163 constants::TEXTURE_COMPARE_MODE => {
164 let (sender, receiver) = webgl_channel().unwrap();
165 context.send_command(WebGLCommand::GetSamplerParameterInt(
166 self.gl_id, pname, sender,
167 ));
168 Ok(WebGLSamplerValue::GLenum(receiver.recv().unwrap() as u32))
169 },
170 constants::TEXTURE_MIN_LOD | constants::TEXTURE_MAX_LOD => {
171 let (sender, receiver) = webgl_channel().unwrap();
172 context.send_command(WebGLCommand::GetSamplerParameterFloat(
173 self.gl_id, pname, sender,
174 ));
175 Ok(WebGLSamplerValue::Float(receiver.recv().unwrap()))
176 },
177 _ => Err(InvalidEnum),
178 }
179 }
180}
181
182impl Drop for WebGLSampler {
183 fn drop(&mut self) {
184 self.delete(Operation::Fallible);
185 }
186}