/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use std::cell::Cell; use canvas_traits::webgl::WebGLError::*; use canvas_traits::webgl::{WebGLCommand, WebGLSamplerId, webgl_channel}; use dom_struct::dom_struct; use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants as constants; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object}; use crate::dom::bindings::root::DomRoot; use crate::dom::webglobject::WebGLObject; use crate::dom::webglrenderingcontext::{Operation, WebGLRenderingContext}; use crate::script_runtime::CanGc; #[dom_struct] pub(crate) struct WebGLSampler { webgl_object: WebGLObject, #[no_trace] gl_id: WebGLSamplerId, marked_for_deletion: Cell, } #[derive(Clone, Copy)] pub(crate) enum WebGLSamplerValue { Float(f32), GLenum(u32), } fn validate_params(pname: u32, value: WebGLSamplerValue) -> bool { match value { WebGLSamplerValue::GLenum(value) => { let allowed_values = match pname { constants::TEXTURE_MIN_FILTER => &[ constants::NEAREST, constants::LINEAR, constants::NEAREST_MIPMAP_NEAREST, constants::LINEAR_MIPMAP_NEAREST, constants::NEAREST_MIPMAP_LINEAR, constants::LINEAR_MIPMAP_LINEAR, ][..], constants::TEXTURE_MAG_FILTER => &[constants::NEAREST, constants::LINEAR][..], constants::TEXTURE_WRAP_R | constants::TEXTURE_WRAP_S | constants::TEXTURE_WRAP_T => &[ constants::CLAMP_TO_EDGE, constants::MIRRORED_REPEAT, constants::REPEAT, ][..], constants::TEXTURE_COMPARE_MODE => { &[constants::NONE, constants::COMPARE_REF_TO_TEXTURE][..] }, constants::TEXTURE_COMPARE_FUNC => &[ constants::LEQUAL, constants::GEQUAL, constants::LESS, constants::GREATER, constants::EQUAL, constants::NOTEQUAL, constants::ALWAYS, constants::NEVER, ][..], _ => &[][..], }; allowed_values.contains(&value) }, WebGLSamplerValue::Float(_) => matches!( pname, constants::TEXTURE_MIN_LOD | constants::TEXTURE_MAX_LOD ), } } impl WebGLSampler { fn new_inherited(context: &WebGLRenderingContext, id: WebGLSamplerId) -> Self { Self { webgl_object: WebGLObject::new_inherited(context), gl_id: id, marked_for_deletion: Cell::new(false), } } pub(crate) fn new(context: &WebGLRenderingContext, can_gc: CanGc) -> DomRoot { let (sender, receiver) = webgl_channel().unwrap(); context.send_command(WebGLCommand::GenerateSampler(sender)); let id = receiver.recv().unwrap(); reflect_dom_object( Box::new(Self::new_inherited(context, id)), &*context.global(), can_gc, ) } pub(crate) fn delete(&self, operation_fallibility: Operation) { if !self.marked_for_deletion.get() { self.marked_for_deletion.set(true); let command = WebGLCommand::DeleteSampler(self.gl_id); let context = self.upcast::().context(); match operation_fallibility { Operation::Fallible => context.send_command_ignored(command), Operation::Infallible => context.send_command(command), } } } pub(crate) fn is_valid(&self) -> bool { !self.marked_for_deletion.get() } pub(crate) fn bind( &self, context: &WebGLRenderingContext, unit: u32, ) -> Result<(), canvas_traits::webgl::WebGLError> { if !self.is_valid() { return Err(InvalidOperation); } context.send_command(WebGLCommand::BindSampler(unit, self.gl_id)); Ok(()) } pub(crate) fn set_parameter( &self, context: &WebGLRenderingContext, pname: u32, value: WebGLSamplerValue, ) -> Result<(), canvas_traits::webgl::WebGLError> { if !self.is_valid() { return Err(InvalidOperation); } if !validate_params(pname, value) { return Err(InvalidEnum); } let command = match value { WebGLSamplerValue::GLenum(value) => { WebGLCommand::SetSamplerParameterInt(self.gl_id, pname, value as i32) }, WebGLSamplerValue::Float(value) => { WebGLCommand::SetSamplerParameterFloat(self.gl_id, pname, value) }, }; context.send_command(command); Ok(()) } pub(crate) fn get_parameter( &self, context: &WebGLRenderingContext, pname: u32, ) -> Result { if !self.is_valid() { return Err(InvalidOperation); } match pname { constants::TEXTURE_MIN_FILTER | constants::TEXTURE_MAG_FILTER | constants::TEXTURE_WRAP_R | constants::TEXTURE_WRAP_S | constants::TEXTURE_WRAP_T | constants::TEXTURE_COMPARE_FUNC | constants::TEXTURE_COMPARE_MODE => { let (sender, receiver) = webgl_channel().unwrap(); context.send_command(WebGLCommand::GetSamplerParameterInt( self.gl_id, pname, sender, )); Ok(WebGLSamplerValue::GLenum(receiver.recv().unwrap() as u32)) }, constants::TEXTURE_MIN_LOD | constants::TEXTURE_MAX_LOD => { let (sender, receiver) = webgl_channel().unwrap(); context.send_command(WebGLCommand::GetSamplerParameterFloat( self.gl_id, pname, sender, )); Ok(WebGLSamplerValue::Float(receiver.recv().unwrap())) }, _ => Err(InvalidEnum), } } } impl Drop for WebGLSampler { fn drop(&mut self) { self.delete(Operation::Fallible); } }