use super::*; use js_sys::{self, Array}; use slotmap::{new_key_type, SlotMap}; use std::cell::RefCell; use web_sys::{ self, HtmlCanvasElement, HtmlImageElement, HtmlVideoElement, ImageBitmap, WebGl2RenderingContext, WebGlBuffer, WebGlFramebuffer, WebGlProgram, WebGlQuery, WebGlRenderbuffer, WebGlRenderingContext, WebGlSampler, WebGlShader, WebGlSync, WebGlTexture, WebGlTransformFeedback, WebGlUniformLocation, WebGlVertexArrayObject, }; #[cfg(web_sys_unstable_apis)] use web_sys::VideoFrame; #[derive(Debug)] enum RawRenderingContext { WebGl1(WebGlRenderingContext), WebGl2(WebGl2RenderingContext), } #[allow(dead_code)] #[derive(Debug)] struct Extensions { pub angle_instanced_arrays: Option, pub ext_blend_minmax: Option, pub ext_color_buffer_float: Option, pub ext_color_buffer_half_float: Option, pub ext_disjoint_timer_query: Option, pub ext_disjoint_timer_query_webgl2: Option<()>, pub ext_float_blend: Option<()>, pub ext_frag_depth: Option, pub ext_shader_texture_lod: Option, pub ext_srgb: Option, pub ext_texture_compression_bptc: Option<()>, pub ext_texture_compression_rgtc: Option<()>, pub ext_texture_filter_anisotropic: Option, pub khr_parallel_shader_compile: Option<()>, pub oes_element_index_uint: Option, pub oes_fbo_render_mipmap: Option<()>, pub oes_standard_derivatives: Option, pub oes_texture_float: Option, pub oes_texture_float_linear: Option, pub oes_texture_half_float: Option, pub oes_texture_half_float_linear: Option, pub oes_vertex_array_object: Option, pub ovr_multiview2: Option, pub webgl_color_buffer_float: Option, pub webgl_compressed_texture_astc: Option, pub webgl_compressed_texture_etc: Option, pub webgl_compressed_texture_etc1: Option, pub webgl_compressed_texture_pvrtc: Option, pub webgl_compressed_texture_s3tc: Option, pub webgl_compressed_texture_s3tc_srgb: Option, pub webgl_debug_renderer_info: Option, pub webgl_debug_shaders: Option, pub webgl_depth_texture: Option, pub webgl_draw_buffers: Option, pub webgl_lose_context: Option, } type TrackedResource = RefCell>; fn tracked_resource() -> TrackedResource { RefCell::new(SlotMap::with_key()) } #[derive(Debug)] pub struct Context { raw: RawRenderingContext, extensions: Extensions, version: Version, supported_extensions: HashSet, shaders: TrackedResource, programs: TrackedResource, buffers: TrackedResource, vertex_arrays: TrackedResource, textures: TrackedResource, samplers: TrackedResource, fences: TrackedResource, framebuffers: TrackedResource, renderbuffers: TrackedResource, queries: TrackedResource, transform_feedbacks: TrackedResource, } // bindgen's gl context don't share an interface so a macro is used to deduplicate a bunch of code here macro_rules! build_extensions { ($context:ident, $context_type:ty) => {{ fn get_extension(context: &$context_type, name: &str) -> Option where T: wasm_bindgen::JsCast, { use wasm_bindgen::JsCast; // `unchecked_into` is used here because WebGL extensions aren't actually JS classes // these objects are duck-type representations of the actual Rust classes // https://github.com/rustwasm/wasm-bindgen/pull/1449 context .get_extension(name) .ok() .and_then(|maybe_ext| maybe_ext.map(|ext| ext.unchecked_into::())) } fn get_extension_no_object(context: &$context_type, name: &str) -> Option<()> { context .get_extension(name) .ok() .and_then(|maybe_ext| maybe_ext.map(|_| ())) } let extensions = Extensions { angle_instanced_arrays: get_extension::( &$context, "ANGLE_instanced_arrays", ), ext_blend_minmax: get_extension::( &$context, "EXT_blend_minmax", ), ext_color_buffer_float: get_extension::( &$context, "EXT_color_buffer_float", ), ext_color_buffer_half_float: get_extension::( &$context, "EXT_color_buffer_half_float", ), ext_disjoint_timer_query: get_extension::( &$context, "EXT_disjoint_timer_query", ), ext_disjoint_timer_query_webgl2: get_extension_no_object( &$context, "EXT_disjoint_timer_query_webgl2", ), ext_float_blend: get_extension_no_object(&$context, "EXT_float_blend"), ext_frag_depth: get_extension::(&$context, "EXT_frag_depth"), ext_shader_texture_lod: get_extension::( &$context, "EXT_shader_texture_lod", ), ext_srgb: get_extension::(&$context, "EXT_sRGB"), ext_texture_compression_bptc: get_extension_no_object( &$context, "EXT_texture_compression_bptc", ), ext_texture_compression_rgtc: get_extension_no_object( &$context, "EXT_texture_compression_rgtc", ), ext_texture_filter_anisotropic: get_extension::( &$context, "EXT_texture_filter_anisotropic", ), khr_parallel_shader_compile: get_extension_no_object( &$context, "KHR_parallel_shader_compile", ), oes_element_index_uint: get_extension::( &$context, "OES_element_index_uint", ), oes_fbo_render_mipmap: get_extension_no_object(&$context, "OES_fbo_render_mipmap"), oes_standard_derivatives: get_extension::( &$context, "OES_standard_derivatives", ), oes_texture_float: get_extension::( &$context, "OES_texture_float", ), oes_texture_float_linear: get_extension::( &$context, "OES_texture_float_linear", ), oes_texture_half_float: get_extension::( &$context, "OES_texture_half_float", ), oes_texture_half_float_linear: get_extension::( &$context, "OES_texture_half_float_linear", ), oes_vertex_array_object: get_extension::( &$context, "OES_vertex_array_object", ), ovr_multiview2: get_extension::(&$context, "OVR_multiview2"), webgl_color_buffer_float: get_extension::( &$context, "WEBGL_color_buffer_float", ), webgl_compressed_texture_astc: get_extension::( &$context, "WEBGL_compressed_texture_astc", ), webgl_compressed_texture_etc: get_extension::( &$context, "WEBGL_compressed_texture_etc", ), webgl_compressed_texture_etc1: get_extension::( &$context, "WEBGL_compressed_texture_etc1", ), webgl_compressed_texture_pvrtc: get_extension::( &$context, "WEBGL_compressed_texture_pvrtc", ), webgl_compressed_texture_s3tc: get_extension::( &$context, "WEBGL_compressed_texture_s3tc", ), webgl_compressed_texture_s3tc_srgb: get_extension::< web_sys::WebglCompressedTextureS3tcSrgb, >( &$context, "WEBGL_compressed_texture_s3tc_srgb" ), webgl_debug_renderer_info: get_extension::( &$context, "WEBGL_debug_renderer_info", ), webgl_debug_shaders: get_extension::( &$context, "WEBGL_debug_shaders", ), webgl_depth_texture: get_extension::( &$context, "WEBGL_depth_texture", ), webgl_draw_buffers: get_extension::( &$context, "WEBGL_draw_buffers", ), webgl_lose_context: get_extension::( &$context, "WEBGL_lose_context", ), }; let supported_extensions = $context .get_supported_extensions() .unwrap() .iter() .map(|val| val.as_string().unwrap()) .collect::>(); (extensions, supported_extensions) }}; } impl Context { pub fn from_webgl1_context(context: WebGlRenderingContext) -> Self { let (extensions, supported_extensions) = build_extensions!(context, WebGlRenderingContext); // Retrieve and parse `GL_VERSION` let raw_string = context.get_parameter(VERSION).unwrap().as_string().unwrap(); let version = Version::parse(&raw_string).unwrap(); Self { raw: RawRenderingContext::WebGl1(context), extensions, supported_extensions, version, shaders: tracked_resource(), programs: tracked_resource(), buffers: tracked_resource(), vertex_arrays: tracked_resource(), textures: tracked_resource(), samplers: tracked_resource(), fences: tracked_resource(), framebuffers: tracked_resource(), renderbuffers: tracked_resource(), queries: tracked_resource(), transform_feedbacks: tracked_resource(), } } pub fn from_webgl2_context(context: WebGl2RenderingContext) -> Self { let (extensions, supported_extensions) = build_extensions!(context, WebGl2RenderingContext); // Retrieve and parse `GL_VERSION` let raw_string = context.get_parameter(VERSION).unwrap().as_string().unwrap(); let version = Version::parse(&raw_string).unwrap(); Self { raw: RawRenderingContext::WebGl2(context), extensions, supported_extensions, version, shaders: tracked_resource(), programs: tracked_resource(), buffers: tracked_resource(), vertex_arrays: tracked_resource(), textures: tracked_resource(), samplers: tracked_resource(), fences: tracked_resource(), framebuffers: tracked_resource(), renderbuffers: tracked_resource(), queries: tracked_resource(), transform_feedbacks: tracked_resource(), } } // These functions are defined in this order: // // - image_bitmap // - html_canvas // - html_image // - html_video // - video_frame pub unsafe fn tex_image_2d_with_image_bitmap( &self, target: u32, level: i32, internal_format: i32, format: u32, ty: u32, pixels: &ImageBitmap, ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { // TODO: Handle return value? gl.tex_image_2d_with_u32_and_u32_and_image_bitmap( target, level, internal_format, format, ty, pixels, ) .unwrap(); } RawRenderingContext::WebGl2(ref gl) => { // TODO: Handle return value? gl.tex_image_2d_with_u32_and_u32_and_image_bitmap( target, level, internal_format, format, ty, pixels, ) .unwrap(); } } } /// WebGL2 Only pub unsafe fn tex_image_2d_with_image_bitmap_and_width_and_height( &self, target: u32, level: i32, internal_format: i32, width: i32, height: i32, format: u32, ty: u32, pixels: &ImageBitmap, ) { match self.raw { RawRenderingContext::WebGl1(_) => { panic!("Width and height not supported") } RawRenderingContext::WebGl2(ref gl) => { // TODO: Handle return value? gl.tex_image_2d_with_i32_and_i32_and_i32_and_format_and_type_and_image_bitmap( target, level, internal_format, width, height, 0, // required to be zero format, ty, pixels, ) .unwrap(); } } } pub unsafe fn tex_image_2d_with_html_canvas( &self, target: u32, level: i32, internal_format: i32, format: u32, ty: u32, canvas: &HtmlCanvasElement, ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { // TODO: Handle return value? gl.tex_image_2d_with_u32_and_u32_and_canvas( target, level, internal_format, format, ty, canvas, ) .unwrap(); } RawRenderingContext::WebGl2(ref gl) => { // TODO: Handle return value? gl.tex_image_2d_with_u32_and_u32_and_html_canvas_element( target, level, internal_format, format, ty, canvas, ) .unwrap(); } } } /// WebGL2 Only pub unsafe fn tex_image_2d_with_html_canvas_and_width_and_height( &self, target: u32, level: i32, internal_format: i32, width: i32, height: i32, format: u32, ty: u32, canvas: &HtmlCanvasElement, ) { match self.raw { RawRenderingContext::WebGl1(_) => { panic!("Width and height not supported") } RawRenderingContext::WebGl2(ref gl) => { // TODO: Handle return value? gl.tex_image_2d_with_i32_and_i32_and_i32_and_format_and_type_and_html_canvas_element( target, level, internal_format, width, height, 0, // required to be zero format, ty, canvas, ) .unwrap(); } } } pub unsafe fn tex_image_2d_with_html_image( &self, target: u32, level: i32, internal_format: i32, format: u32, ty: u32, image: &HtmlImageElement, ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { // TODO: Handle return value? gl.tex_image_2d_with_u32_and_u32_and_image( target, level, internal_format, format, ty, image, ) .unwrap(); } RawRenderingContext::WebGl2(ref gl) => { // TODO: Handle return value? gl.tex_image_2d_with_u32_and_u32_and_html_image_element( target, level, internal_format, format, ty, image, ) .unwrap(); } } } /// WebGL2 Only pub unsafe fn tex_image_2d_with_html_image_and_width_and_height( &self, target: u32, level: i32, internal_format: i32, width: i32, height: i32, format: u32, ty: u32, image: &HtmlImageElement, ) { match self.raw { RawRenderingContext::WebGl1(_) => { panic!("Width and height not supported") } RawRenderingContext::WebGl2(ref gl) => { // TODO: Handle return value? gl.tex_image_2d_with_i32_and_i32_and_i32_and_format_and_type_and_html_image_element( target, level, internal_format, width, height, 0, // required to be zero format, ty, image, ) .unwrap(); } } } pub unsafe fn tex_image_2d_with_html_video( &self, target: u32, level: i32, internal_format: i32, format: u32, ty: u32, video: &HtmlVideoElement, ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { // TODO: Handle return value? gl.tex_image_2d_with_u32_and_u32_and_video( target, level, internal_format, format, ty, video, ) .unwrap(); } RawRenderingContext::WebGl2(ref gl) => { // TODO: Handle return value? gl.tex_image_2d_with_u32_and_u32_and_html_video_element( target, level, internal_format, format, ty, video, ) .unwrap(); } } } /// WebGL2 Only pub unsafe fn tex_image_2d_with_html_video_and_width_and_height( &self, target: u32, level: i32, internal_format: i32, width: i32, height: i32, format: u32, ty: u32, video: &HtmlVideoElement, ) { match self.raw { RawRenderingContext::WebGl1(_) => { panic!("Width and height not supported") } RawRenderingContext::WebGl2(ref gl) => { // TODO: Handle return value? gl.tex_image_2d_with_i32_and_i32_and_i32_and_format_and_type_and_html_video_element( target, level, internal_format, width, height, 0, // required to be zero format, ty, video, ) .unwrap(); } } } #[cfg(web_sys_unstable_apis)] pub unsafe fn tex_image_2d_with_video_frame( &self, target: u32, level: i32, internal_format: i32, format: u32, ty: u32, video_frame: &VideoFrame, ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { // TODO: Handle return value? gl.tex_image_2d_with_u32_and_u32_and_video_frame( target, level, internal_format, format, ty, video_frame, ) .unwrap(); } RawRenderingContext::WebGl2(ref gl) => { // TODO: Handle return value? gl.tex_image_2d_with_u32_and_u32_and_video_frame( target, level, internal_format, format, ty, video_frame, ) .unwrap(); } } } #[cfg(web_sys_unstable_apis)] /// WebGL2 Only pub unsafe fn tex_image_2d_with_video_frame_and_width_and_height( &self, target: u32, level: i32, internal_format: i32, width: i32, height: i32, format: u32, ty: u32, video_frame: &VideoFrame, ) { match self.raw { RawRenderingContext::WebGl1(_) => { panic!("Width and height not supported") } RawRenderingContext::WebGl2(ref gl) => { // TODO: Handle return value? gl.tex_image_2d_with_i32_and_i32_and_i32_and_format_and_type_and_video_frame( target, level, internal_format, width, height, 0, format, ty, video_frame, ) .unwrap(); } } } pub unsafe fn tex_sub_image_2d_with_image_bitmap( &self, target: u32, level: i32, x_offset: i32, y_offset: i32, format: u32, ty: u32, image: &ImageBitmap, ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.tex_sub_image_2d_with_u32_and_u32_and_image_bitmap( target, level, x_offset, y_offset, format, ty, image, ) .unwrap(); // TODO: Handle return value? } RawRenderingContext::WebGl2(ref gl) => { gl.tex_sub_image_2d_with_u32_and_u32_and_image_bitmap( target, level, x_offset, y_offset, format, ty, image, ) .unwrap(); // TODO: Handle return value? } } } /// WebGL2 Only pub unsafe fn tex_sub_image_2d_with_image_bitmap_and_width_and_height( &self, target: u32, level: i32, x_offset: i32, y_offset: i32, width: i32, height: i32, format: u32, ty: u32, image: &ImageBitmap, ) { match self.raw { RawRenderingContext::WebGl1(_) => { panic!("Width and height not supported") } RawRenderingContext::WebGl2(ref gl) => { gl.tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_image_bitmap( target, level, x_offset, y_offset, width, height, format, ty, image, ) .unwrap(); // TODO: Handle return value? } } } pub unsafe fn tex_sub_image_2d_with_html_canvas( &self, target: u32, level: i32, x_offset: i32, y_offset: i32, format: u32, ty: u32, image: &HtmlCanvasElement, ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.tex_sub_image_2d_with_u32_and_u32_and_canvas( target, level, x_offset, y_offset, format, ty, image, ) .unwrap(); // TODO: Handle return value? } RawRenderingContext::WebGl2(ref gl) => { gl.tex_sub_image_2d_with_u32_and_u32_and_html_canvas_element( target, level, x_offset, y_offset, format, ty, image, ) .unwrap(); // TODO: Handle return value? } } } /// WebGL2 Only pub unsafe fn tex_sub_image_2d_with_html_canvas_and_width_and_height( &self, target: u32, level: i32, x_offset: i32, y_offset: i32, width: i32, height: i32, format: u32, ty: u32, image: &HtmlCanvasElement, ) { match self.raw { RawRenderingContext::WebGl1(_) => { panic!("Width and height not supported") } RawRenderingContext::WebGl2(ref gl) => { gl.tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_html_canvas_element( target, level, x_offset, y_offset, width, height, format, ty, image, ) .unwrap(); // TODO: Handle return value? } } } pub unsafe fn tex_sub_image_2d_with_html_image( &self, target: u32, level: i32, x_offset: i32, y_offset: i32, format: u32, ty: u32, image: &HtmlImageElement, ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.tex_sub_image_2d_with_u32_and_u32_and_image( target, level, x_offset, y_offset, format, ty, image, ) .unwrap(); // TODO: Handle return value? } RawRenderingContext::WebGl2(ref gl) => { gl.tex_sub_image_2d_with_u32_and_u32_and_html_image_element( target, level, x_offset, y_offset, format, ty, image, ) .unwrap(); // TODO: Handle return value? } } } /// WebGL2 Only pub unsafe fn tex_sub_image_2d_with_html_image_and_width_and_height( &self, target: u32, level: i32, x_offset: i32, y_offset: i32, width: i32, height: i32, format: u32, ty: u32, image: &HtmlImageElement, ) { match self.raw { RawRenderingContext::WebGl1(_) => { panic!("Width and height not supported") } RawRenderingContext::WebGl2(ref gl) => { gl.tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_html_image_element( target, level, x_offset, y_offset, width, height, format, ty, image, ) .unwrap(); // TODO: Handle return value? } } } pub unsafe fn tex_sub_image_2d_with_html_video( &self, target: u32, level: i32, x_offset: i32, y_offset: i32, format: u32, ty: u32, image: &HtmlVideoElement, ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.tex_sub_image_2d_with_u32_and_u32_and_video( target, level, x_offset, y_offset, format, ty, image, ) .unwrap(); // TODO: Handle return value? } RawRenderingContext::WebGl2(ref gl) => { gl.tex_sub_image_2d_with_u32_and_u32_and_html_video_element( target, level, x_offset, y_offset, format, ty, image, ) .unwrap(); // TODO: Handle return value? } } } /// WebGL2 Only pub unsafe fn tex_sub_image_2d_with_html_video_and_width_and_height( &self, target: u32, level: i32, x_offset: i32, y_offset: i32, width: i32, height: i32, format: u32, ty: u32, image: &HtmlVideoElement, ) { match self.raw { RawRenderingContext::WebGl1(_) => { panic!("Width and height not supported") } RawRenderingContext::WebGl2(ref gl) => { gl.tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_html_video_element( target, level, x_offset, y_offset, width, height, format, ty, image, ) .unwrap(); // TODO: Handle return value? } } } #[cfg(web_sys_unstable_apis)] pub unsafe fn tex_sub_image_2d_with_video_frame( &self, target: u32, level: i32, x_offset: i32, y_offset: i32, width: i32, height: i32, format: u32, ty: u32, video_frame: &VideoFrame, ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.tex_sub_image_2d_with_u32_and_u32_and_video_frame( target, level, x_offset, y_offset, format, ty, video_frame, ) .unwrap(); // TODO: Handle return value? } RawRenderingContext::WebGl2(ref gl) => { gl.tex_sub_image_2d_with_u32_and_u32_and_video_frame( target, level, x_offset, y_offset, format, ty, video_frame, ) .unwrap(); // TODO: Handle return value? } } } #[cfg(web_sys_unstable_apis)] /// WebGL2 Only pub unsafe fn tex_sub_image_2d_with_video_frame_and_width_and_height( &self, target: u32, level: i32, x_offset: i32, y_offset: i32, width: i32, height: i32, format: u32, ty: u32, video_frame: &VideoFrame, ) { match self.raw { RawRenderingContext::WebGl1(_) => { panic!("Width and height not supported") } RawRenderingContext::WebGl2(ref gl) => { gl.tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_video_frame( target, level, x_offset, y_offset, width, height, format, ty, video_frame, ) .unwrap(); // TODO: Handle return value? } } } /// WebGL2 Only pub unsafe fn tex_image_3d_with_image_bitmap( &self, target: u32, level: i32, internal_format: i32, width: i32, height: i32, depth: i32, border: i32, format: u32, ty: u32, image: &ImageBitmap, ) { match self.raw { RawRenderingContext::WebGl1(_) => panic!("3D images not supported"), RawRenderingContext::WebGl2(ref gl) => { gl.tex_image_3d_with_image_bitmap( target, level, internal_format, width, height, depth, border, format, ty, image, ) .unwrap(); // TODO: Handle return value? } } } /// WebGL2 Only pub unsafe fn tex_image_3d_with_html_canvas_element( &self, target: u32, level: i32, internal_format: i32, width: i32, height: i32, depth: i32, border: i32, format: u32, ty: u32, image: &HtmlCanvasElement, ) { match self.raw { RawRenderingContext::WebGl1(_) => panic!("3D images not supported"), RawRenderingContext::WebGl2(ref gl) => { gl.tex_image_3d_with_html_canvas_element( target, level, internal_format, width, height, depth, border, format, ty, image, ) .unwrap(); // TODO: Handle return value? } } } /// WebGL2 Only pub unsafe fn tex_image_3d_with_html_image_element( &self, target: u32, level: i32, internal_format: i32, width: i32, height: i32, depth: i32, border: i32, format: u32, ty: u32, image: &HtmlImageElement, ) { match self.raw { RawRenderingContext::WebGl1(_) => panic!("3D images not supported"), RawRenderingContext::WebGl2(ref gl) => { gl.tex_image_3d_with_html_image_element( target, level, internal_format, width, height, depth, border, format, ty, image, ) .unwrap(); // TODO: Handle return value? } } } /// WebGL2 Only pub unsafe fn tex_image_3d_with_html_video_element( &self, target: u32, level: i32, internal_format: i32, width: i32, height: i32, depth: i32, border: i32, format: u32, ty: u32, image: &HtmlVideoElement, ) { match self.raw { RawRenderingContext::WebGl1(_) => panic!("3D images not supported"), RawRenderingContext::WebGl2(ref gl) => { gl.tex_image_3d_with_html_video_element( target, level, internal_format, width, height, depth, border, format, ty, image, ) .unwrap(); // TODO: Handle return value? } } } #[cfg(web_sys_unstable_apis)] /// WebGL2 Only pub unsafe fn tex_image_3d_with_video_frame( &self, target: u32, level: i32, internal_format: i32, width: i32, height: i32, depth: i32, border: i32, format: u32, ty: u32, video_frame: &VideoFrame, ) { match self.raw { RawRenderingContext::WebGl1(_) => panic!("3D images not supported"), RawRenderingContext::WebGl2(ref gl) => { gl.tex_image_3d_with_video_frame( target, level, internal_format, width, height, depth, border, format, ty, video_frame, ) .unwrap(); // TODO: Handle return value? } } } /// WebGL2 Only pub unsafe fn tex_sub_image_3d_with_image_bitmap( &self, target: u32, level: i32, x_offset: i32, y_offset: i32, z_offset: i32, width: i32, height: i32, depth: i32, format: u32, ty: u32, image: &ImageBitmap, ) { match self.raw { RawRenderingContext::WebGl1(_) => panic!("3D images not supported"), RawRenderingContext::WebGl2(ref gl) => { gl.tex_sub_image_3d_with_image_bitmap( target, level, x_offset, y_offset, z_offset, width, height, depth, format, ty, image, ) .unwrap(); // TODO: Handle return value? } } } /// WebGL2 Only pub unsafe fn tex_sub_image_3d_with_html_canvas_element( &self, target: u32, level: i32, x_offset: i32, y_offset: i32, z_offset: i32, width: i32, height: i32, depth: i32, format: u32, ty: u32, image: &HtmlCanvasElement, ) { match self.raw { RawRenderingContext::WebGl1(_) => panic!("3D images not supported"), RawRenderingContext::WebGl2(ref gl) => { gl.tex_sub_image_3d_with_html_canvas_element( target, level, x_offset, y_offset, z_offset, width, height, depth, format, ty, image, ) .unwrap(); // TODO: Handle return value? } } } /// WebGL2 Only pub unsafe fn tex_sub_image_3d_with_html_image_element( &self, target: u32, level: i32, x_offset: i32, y_offset: i32, z_offset: i32, width: i32, height: i32, depth: i32, format: u32, ty: u32, image: &HtmlImageElement, ) { match self.raw { RawRenderingContext::WebGl1(_) => panic!("3D images not supported"), RawRenderingContext::WebGl2(ref gl) => { gl.tex_sub_image_3d_with_html_image_element( target, level, x_offset, y_offset, z_offset, width, height, depth, format, ty, image, ) .unwrap(); // TODO: Handle return value? } } } /// WebGL2 Only pub unsafe fn tex_sub_image_3d_with_html_video_element( &self, target: u32, level: i32, x_offset: i32, y_offset: i32, z_offset: i32, width: i32, height: i32, depth: i32, format: u32, ty: u32, image: &HtmlVideoElement, ) { match self.raw { RawRenderingContext::WebGl1(_) => panic!("3D images not supported"), RawRenderingContext::WebGl2(ref gl) => { gl.tex_sub_image_3d_with_html_video_element( target, level, x_offset, y_offset, z_offset, width, height, depth, format, ty, image, ) .unwrap(); // TODO: Handle return value? } } } #[cfg(web_sys_unstable_apis)] /// WebGL2 Only pub unsafe fn tex_sub_image_3d_with_video_frame( &self, target: u32, level: i32, x_offset: i32, y_offset: i32, z_offset: i32, width: i32, height: i32, depth: i32, format: u32, ty: u32, video_frame: &VideoFrame, ) { match self.raw { RawRenderingContext::WebGl1(_) => panic!("3D images not supported"), RawRenderingContext::WebGl2(ref gl) => { gl.tex_sub_image_3d_with_video_frame( target, level, x_offset, y_offset, z_offset, width, height, depth, format, ty, video_frame, ) .unwrap(); // TODO: Handle return value? } } } pub unsafe fn framebuffer_texture_multiview_ovr( &self, target: u32, attachment: u32, texture: Option<::Texture>, level: i32, base_view_index: i32, num_views: i32, ) { let textures = self.textures.borrow(); let raw_texture = texture.map(|t| textures.get_unchecked(t)); match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("OVR_multiview2 is not supported in WebGL1") } RawRenderingContext::WebGl2(ref _gl) => { if let Some(ext) = &self.extensions.ovr_multiview2 { ext.framebuffer_texture_multiview_ovr( target, attachment, raw_texture, level, base_view_index, num_views, ); } } } } pub unsafe fn bind_external_framebuffer(&self, target: u32, framebuffer: &WebGlFramebuffer) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.bind_framebuffer(target, Some(framebuffer)), RawRenderingContext::WebGl2(ref gl) => gl.bind_framebuffer(target, Some(framebuffer)), } } // Returns true if the `WEBGL_compressed_texture_astc` extension is enabled and the "ldr" // profile is supported. pub fn compressed_texture_astc_supports_ldr_profile(&self) -> bool { self.extensions .webgl_compressed_texture_astc .as_ref() .map(|ext| { let profiles = ext.get_supported_profiles().unwrap_or_default(); profiles.includes(&"ldr".into(), 0) }) .unwrap_or(false) } // Returns true if the `WEBGL_compressed_texture_astc` extension is enabled and the "hdr" // profile is supported. pub fn compressed_texture_astc_supports_hdr_profile(&self) -> bool { self.extensions .webgl_compressed_texture_astc .as_ref() .map(|ext| { let profiles = ext.get_supported_profiles().unwrap_or_default(); profiles.includes(&"hdr".into(), 0) }) .unwrap_or(false) } } new_key_type! { pub struct WebShaderKey; } new_key_type! { pub struct WebProgramKey; } new_key_type! { pub struct WebBufferKey; } new_key_type! { pub struct WebVertexArrayKey; } new_key_type! { pub struct WebTextureKey; } new_key_type! { pub struct WebSamplerKey; } new_key_type! { pub struct WebFenceKey; } new_key_type! { pub struct WebFramebufferKey; } new_key_type! { pub struct WebRenderbufferKey; } new_key_type! { pub struct WebQueryKey; } new_key_type! { pub struct WebTransformFeedbackKey; } impl HasContext for Context { type Shader = WebShaderKey; type Program = WebProgramKey; type Buffer = WebBufferKey; type VertexArray = WebVertexArrayKey; type Texture = WebTextureKey; type Sampler = WebSamplerKey; type Fence = WebFenceKey; type Framebuffer = WebFramebufferKey; type Renderbuffer = WebRenderbufferKey; type Query = WebQueryKey; type UniformLocation = WebGlUniformLocation; type TransformFeedback = WebTransformFeedbackKey; fn supported_extensions(&self) -> &HashSet { &self.supported_extensions } fn supports_debug(&self) -> bool { false } fn version(&self) -> &Version { &self.version } unsafe fn create_framebuffer(&self) -> Result { let raw_framebuffer = match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.create_framebuffer(), RawRenderingContext::WebGl2(ref gl) => gl.create_framebuffer(), }; match raw_framebuffer { Some(s) => { let key = self.framebuffers.borrow_mut().insert(s); Ok(key) } None => Err(String::from("Unable to create framebuffer object")), } } unsafe fn is_framebuffer(&self, framebuffer: Self::Framebuffer) -> bool { let framebuffers = self.framebuffers.borrow_mut(); if let Some(ref f) = framebuffers.get(framebuffer) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.is_framebuffer(Some(f)), RawRenderingContext::WebGl2(ref gl) => gl.is_framebuffer(Some(f)), } } else { false } } unsafe fn create_query(&self) -> Result { let raw_query = match self.raw { RawRenderingContext::WebGl1(ref _gl) => { return Err(String::from("Query objects are not supported")); } RawRenderingContext::WebGl2(ref gl) => gl.create_query(), }; match raw_query { Some(s) => { let key = self.queries.borrow_mut().insert(s); Ok(key) } None => Err(String::from("Unable to create query object")), } } unsafe fn create_renderbuffer(&self) -> Result { let raw_renderbuffer = match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.create_renderbuffer(), RawRenderingContext::WebGl2(ref gl) => gl.create_renderbuffer(), }; match raw_renderbuffer { Some(s) => { let key = self.renderbuffers.borrow_mut().insert(s); Ok(key) } None => Err(String::from("Unable to create renderbuffer object")), } } unsafe fn is_renderbuffer(&self, renderbuffer: Self::Renderbuffer) -> bool { let renderbuffers = self.renderbuffers.borrow_mut(); if let Some(ref r) = renderbuffers.get(renderbuffer) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.is_renderbuffer(Some(r)), RawRenderingContext::WebGl2(ref gl) => gl.is_renderbuffer(Some(r)), } } else { false } } unsafe fn create_sampler(&self) -> Result { let raw_sampler = match self.raw { RawRenderingContext::WebGl1(ref _gl) => panic!("Sampler objects are not supported"), RawRenderingContext::WebGl2(ref gl) => gl.create_sampler(), }; match raw_sampler { Some(s) => { let key = self.samplers.borrow_mut().insert(s); Ok(key) } None => Err(String::from("Unable to create sampler object")), } } unsafe fn create_shader(&self, shader_type: u32) -> Result { let raw_shader = match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.create_shader(shader_type as u32), RawRenderingContext::WebGl2(ref gl) => gl.create_shader(shader_type as u32), }; match raw_shader { Some(s) => { let key = self.shaders.borrow_mut().insert(s); Ok(key) } None => Err(String::from("Unable to create shader object")), } } unsafe fn is_shader(&self, shader: Self::Shader) -> bool { let shaders = self.shaders.borrow_mut(); if let Some(ref s) = shaders.get(shader) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.is_shader(Some(s)), RawRenderingContext::WebGl2(ref gl) => gl.is_shader(Some(s)), } } else { false } } unsafe fn create_texture(&self) -> Result { let raw_texture = match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.create_texture(), RawRenderingContext::WebGl2(ref gl) => gl.create_texture(), }; match raw_texture { Some(t) => { let key = self.textures.borrow_mut().insert(t); Ok(key) } None => Err(String::from("Unable to create texture object")), } } unsafe fn create_named_texture(&self, _target: u32) -> Result { unimplemented!() } unsafe fn is_texture(&self, texture: Self::Texture) -> bool { let textures = self.textures.borrow_mut(); if let Some(ref t) = textures.get(texture) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.is_texture(Some(t)), RawRenderingContext::WebGl2(ref gl) => gl.is_texture(Some(t)), } } else { false } } unsafe fn delete_shader(&self, shader: Self::Shader) { let mut shaders = self.shaders.borrow_mut(); if let Some(ref s) = shaders.remove(shader) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.delete_shader(Some(s)), RawRenderingContext::WebGl2(ref gl) => gl.delete_shader(Some(s)), } } } unsafe fn shader_source(&self, shader: Self::Shader, source: &str) { let shaders = self.shaders.borrow(); let raw_shader = shaders.get_unchecked(shader); match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.shader_source(raw_shader, source), RawRenderingContext::WebGl2(ref gl) => gl.shader_source(raw_shader, source), } } unsafe fn compile_shader(&self, shader: Self::Shader) { let shaders = self.shaders.borrow(); let raw_shader = shaders.get_unchecked(shader); match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.compile_shader(raw_shader), RawRenderingContext::WebGl2(ref gl) => gl.compile_shader(raw_shader), } } unsafe fn get_shader_completion_status(&self, shader: Self::Shader) -> bool { let shaders = self.shaders.borrow(); let raw_shader = shaders.get_unchecked(shader); if self.extensions.khr_parallel_shader_compile.is_none() { panic!("Parallel shader compile is not supported") } match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.get_shader_parameter(raw_shader, COMPLETION_STATUS) } RawRenderingContext::WebGl2(ref gl) => { gl.get_shader_parameter(raw_shader, COMPLETION_STATUS) } } .as_bool() .unwrap_or(false) } unsafe fn get_shader_compile_status(&self, shader: Self::Shader) -> bool { let shaders = self.shaders.borrow(); let raw_shader = shaders.get_unchecked(shader); match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.get_shader_parameter(raw_shader, COMPILE_STATUS) } RawRenderingContext::WebGl2(ref gl) => { gl.get_shader_parameter(raw_shader, COMPILE_STATUS) } } .as_bool() .unwrap_or(false) } unsafe fn get_shader_info_log(&self, shader: Self::Shader) -> String { let shaders = self.shaders.borrow(); let raw_shader = shaders.get_unchecked(shader); match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.get_shader_info_log(raw_shader), RawRenderingContext::WebGl2(ref gl) => gl.get_shader_info_log(raw_shader), } .unwrap_or_else(|| String::from("")) } unsafe fn get_tex_image( &self, _target: u32, _level: i32, _format: u32, _ty: u32, _pixels: PixelPackData, ) { panic!("Get tex image is not supported"); } unsafe fn create_program(&self) -> Result { let raw_program = match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.create_program(), RawRenderingContext::WebGl2(ref gl) => gl.create_program(), }; match raw_program { Some(p) => { let key = self.programs.borrow_mut().insert(p); Ok(key) } None => Err(String::from("Unable to create program object")), } } unsafe fn is_program(&self, program: Self::Program) -> bool { let programs = self.programs.borrow_mut(); if let Some(ref p) = programs.get(program) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.is_program(Some(p)), RawRenderingContext::WebGl2(ref gl) => gl.is_program(Some(p)), } } else { false } } unsafe fn delete_program(&self, program: Self::Program) { let mut programs = self.programs.borrow_mut(); if let Some(ref p) = programs.remove(program) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.delete_program(Some(p)), RawRenderingContext::WebGl2(ref gl) => gl.delete_program(Some(p)), } } } unsafe fn attach_shader(&self, program: Self::Program, shader: Self::Shader) { let programs = self.programs.borrow(); let shaders = self.shaders.borrow(); let raw_program = programs.get_unchecked(program); let raw_shader = shaders.get_unchecked(shader); match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.attach_shader(raw_program, raw_shader), RawRenderingContext::WebGl2(ref gl) => gl.attach_shader(raw_program, raw_shader), } } unsafe fn detach_shader(&self, program: Self::Program, shader: Self::Shader) { let programs = self.programs.borrow(); let shaders = self.shaders.borrow(); let raw_program = programs.get_unchecked(program); let raw_shader = shaders.get_unchecked(shader); match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.detach_shader(raw_program, raw_shader), RawRenderingContext::WebGl2(ref gl) => gl.detach_shader(raw_program, raw_shader), } } unsafe fn link_program(&self, program: Self::Program) { let programs = self.programs.borrow(); let raw_program = programs.get_unchecked(program); match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.link_program(raw_program), RawRenderingContext::WebGl2(ref gl) => gl.link_program(raw_program), } } unsafe fn get_program_completion_status(&self, program: Self::Program) -> bool { let programs = self.programs.borrow(); let raw_program = programs.get_unchecked(program); if self.extensions.khr_parallel_shader_compile.is_none() { panic!("Parallel shader compile is not supported") } match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.get_program_parameter(raw_program, COMPLETION_STATUS) } RawRenderingContext::WebGl2(ref gl) => { gl.get_program_parameter(raw_program, COMPLETION_STATUS) } } .as_bool() .unwrap_or(false) } unsafe fn get_program_link_status(&self, program: Self::Program) -> bool { let programs = self.programs.borrow(); let raw_program = programs.get_unchecked(program); match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.get_program_parameter(raw_program, LINK_STATUS) } RawRenderingContext::WebGl2(ref gl) => { gl.get_program_parameter(raw_program, LINK_STATUS) } } .as_bool() .unwrap_or(false) } unsafe fn get_program_info_log(&self, program: Self::Program) -> String { let programs = self.programs.borrow(); let raw_program = programs.get_unchecked(program); match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.get_program_info_log(raw_program), RawRenderingContext::WebGl2(ref gl) => gl.get_program_info_log(raw_program), } .unwrap_or_else(|| String::from("")) } unsafe fn get_program_resource_i32( &self, _program: Self::Program, _interface: u32, _index: u32, _properties: &[u32], ) -> Vec { panic!("get_program_resource_i32 not supported on webgl"); } unsafe fn get_active_uniforms(&self, program: Self::Program) -> u32 { let programs = self.programs.borrow(); let raw_program = programs.get_unchecked(program); match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.get_program_parameter(raw_program, WebGlRenderingContext::ACTIVE_UNIFORMS) } RawRenderingContext::WebGl2(ref gl) => { gl.get_program_parameter(raw_program, WebGl2RenderingContext::ACTIVE_UNIFORMS) } } .as_f64() .map(|v| v as u32) .unwrap_or(0) } unsafe fn get_active_uniform( &self, program: Self::Program, index: u32, ) -> Option { let programs = self.programs.borrow(); let raw_program = programs.get_unchecked(program); match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.get_active_uniform(raw_program, index) .map(|au| ActiveUniform { size: au.size(), utype: au.type_(), name: au.name(), }) } RawRenderingContext::WebGl2(ref gl) => { gl.get_active_uniform(raw_program, index) .map(|au| ActiveUniform { size: au.size(), utype: au.type_(), name: au.name(), }) } } } unsafe fn use_program(&self, program: Option) { let programs = self.programs.borrow(); let raw_program = program.map(|p| programs.get_unchecked(p)); match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.use_program(raw_program), RawRenderingContext::WebGl2(ref gl) => gl.use_program(raw_program), } } unsafe fn create_buffer(&self) -> Result { let raw_buffer = match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.create_buffer(), RawRenderingContext::WebGl2(ref gl) => gl.create_buffer(), }; match raw_buffer { Some(p) => { let key = self.buffers.borrow_mut().insert(p); Ok(key) } None => Err(String::from("Unable to create buffer object")), } } unsafe fn create_named_buffer(&self) -> Result { unimplemented!() } unsafe fn is_buffer(&self, buffer: Self::Buffer) -> bool { let buffers = self.buffers.borrow_mut(); if let Some(ref b) = buffers.get(buffer) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.is_buffer(Some(b)), RawRenderingContext::WebGl2(ref gl) => gl.is_buffer(Some(b)), } } else { false } } unsafe fn bind_buffer(&self, target: u32, buffer: Option) { let buffers = self.buffers.borrow(); let raw_buffer = buffer.map(|b| buffers.get_unchecked(b)); match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.bind_buffer(target, raw_buffer), RawRenderingContext::WebGl2(ref gl) => gl.bind_buffer(target, raw_buffer), } } unsafe fn bind_buffer_base(&self, target: u32, index: u32, buffer: Option) { let buffers = self.buffers.borrow(); let raw_buffer = buffer.map(|b| buffers.get_unchecked(b)); match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("bind_buffer_base not supported on webgl1") } RawRenderingContext::WebGl2(ref gl) => gl.bind_buffer_base(target, index, raw_buffer), } } unsafe fn bind_buffer_range( &self, target: u32, index: u32, buffer: Option, offset: i32, size: i32, ) { let buffers = self.buffers.borrow(); let raw_buffer = buffer.map(|b| buffers.get_unchecked(b)); match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("bind_buffer_range not supported on webgl1"); } RawRenderingContext::WebGl2(ref gl) => { gl.bind_buffer_range_with_i32_and_i32(target, index, raw_buffer, offset, size); } } } unsafe fn bind_vertex_buffer( &self, _binding_index: u32, _buffer: Option, _offset: i32, _stride: i32, ) { panic!("Bind vertex buffer is not supported") } unsafe fn bind_framebuffer(&self, target: u32, framebuffer: Option) { let framebuffers = self.framebuffers.borrow(); let raw_framebuffer = framebuffer.map(|f| framebuffers.get_unchecked(f)); match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.bind_framebuffer(target, raw_framebuffer), RawRenderingContext::WebGl2(ref gl) => gl.bind_framebuffer(target, raw_framebuffer), } } unsafe fn bind_renderbuffer(&self, target: u32, renderbuffer: Option) { let renderbuffers = self.renderbuffers.borrow(); let raw_renderbuffer = renderbuffer.map(|r| renderbuffers.get_unchecked(r)); match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.bind_renderbuffer(target, raw_renderbuffer), RawRenderingContext::WebGl2(ref gl) => gl.bind_renderbuffer(target, raw_renderbuffer), } } unsafe fn blit_framebuffer( &self, src_x0: i32, src_y0: i32, src_x1: i32, src_y1: i32, dst_x0: i32, dst_y0: i32, dst_x1: i32, dst_y1: i32, mask: u32, filter: u32, ) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("framebuffer blitting usupported in webgl1") } RawRenderingContext::WebGl2(ref gl) => { gl.blit_framebuffer( src_x0, src_y0, src_x1, src_y1, dst_x0, dst_y0, dst_x1, dst_y1, mask, filter, ); } } } unsafe fn create_vertex_array(&self) -> Result { let raw_vertex_array = match self.raw { RawRenderingContext::WebGl1(ref _gl) => { match &self.extensions.oes_vertex_array_object { Some(extension) => extension.create_vertex_array_oes(), None => panic!("Vertex array objects are not supported"), } } RawRenderingContext::WebGl2(ref gl) => gl.create_vertex_array(), }; match raw_vertex_array { Some(va) => { let key = self.vertex_arrays.borrow_mut().insert(va); Ok(key) } None => Err(String::from("Unable to create vertex array object")), } } unsafe fn delete_vertex_array(&self, vertex_array: Self::VertexArray) { let mut vertex_arrays = self.vertex_arrays.borrow_mut(); if let Some(ref va) = vertex_arrays.remove(vertex_array) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => { match &self.extensions.oes_vertex_array_object { Some(extension) => extension.delete_vertex_array_oes(Some(va)), None => panic!("Vertex array objects are not supported"), } } RawRenderingContext::WebGl2(ref gl) => gl.delete_vertex_array(Some(va)), } } } unsafe fn bind_vertex_array(&self, vertex_array: Option) { let vertex_arrays = self.vertex_arrays.borrow(); let raw_vertex_array = vertex_array.map(|va| vertex_arrays.get_unchecked(va)); match self.raw { RawRenderingContext::WebGl1(ref _gl) => { match &self.extensions.oes_vertex_array_object { Some(extension) => extension.bind_vertex_array_oes(raw_vertex_array), None => panic!("Vertex array objects are not supported"), } } RawRenderingContext::WebGl2(ref gl) => gl.bind_vertex_array(raw_vertex_array), } } unsafe fn clear_color(&self, red: f32, green: f32, blue: f32, alpha: f32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.clear_color(red, green, blue, alpha), RawRenderingContext::WebGl2(ref gl) => gl.clear_color(red, green, blue, alpha), } } unsafe fn supports_f64_precision() -> bool { false } unsafe fn clear_depth_f64(&self, _depth: f64) { panic!("64-bit float precision is not supported in WebGL"); } unsafe fn clear_depth_f32(&self, depth: f32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.clear_depth(depth), RawRenderingContext::WebGl2(ref gl) => gl.clear_depth(depth), } } unsafe fn clear_stencil(&self, stencil: i32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.clear_stencil(stencil), RawRenderingContext::WebGl2(ref gl) => gl.clear_stencil(stencil), } } unsafe fn clear(&self, mask: u32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.clear(mask), RawRenderingContext::WebGl2(ref gl) => gl.clear(mask), } } unsafe fn patch_parameter_i32(&self, _parameter: u32, _value: i32) { panic!("Patch parameter is not supported"); } unsafe fn pixel_store_i32(&self, parameter: u32, value: i32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.pixel_storei(parameter, value), RawRenderingContext::WebGl2(ref gl) => gl.pixel_storei(parameter, value), } } unsafe fn pixel_store_bool(&self, parameter: u32, value: bool) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.pixel_storei(parameter, value as i32), RawRenderingContext::WebGl2(ref gl) => gl.pixel_storei(parameter, value as i32), } } unsafe fn bind_frag_data_location( &self, _program: Self::Program, _color_number: u32, _name: &str, ) { panic!("Bind frag data location is not supported"); } unsafe fn buffer_data_size(&self, target: u32, size: i32, usage: u32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.buffer_data_with_i32(target, size, usage), RawRenderingContext::WebGl2(ref gl) => gl.buffer_data_with_i32(target, size, usage), } } unsafe fn buffer_data_u8_slice(&self, target: u32, data: &[u8], usage: u32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { let array = js_sys::Uint8Array::view(data); gl.buffer_data_with_array_buffer_view(target, &array, usage); } RawRenderingContext::WebGl2(ref gl) => { let array = js_sys::Uint8Array::view(data); gl.buffer_data_with_array_buffer_view(target, &array, usage); } } } unsafe fn named_buffer_data_u8_slice(&self, _buffer: Self::Buffer, _data: &[u8], _usage: u32) { unimplemented!() } unsafe fn buffer_sub_data_u8_slice(&self, target: u32, offset: i32, src_data: &[u8]) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { let array = js_sys::Uint8Array::view(src_data); gl.buffer_sub_data_with_i32_and_array_buffer_view(target, offset, &array); } RawRenderingContext::WebGl2(ref gl) => { let array = js_sys::Uint8Array::view(src_data); gl.buffer_sub_data_with_i32_and_array_buffer_view(target, offset, &array); } } } unsafe fn get_buffer_sub_data(&self, target: u32, offset: i32, dst_data: &mut [u8]) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => panic!("get_buffer_sub_data not supported"), RawRenderingContext::WebGl2(ref gl) => { let array = js_sys::Uint8Array::view(dst_data); gl.get_buffer_sub_data_with_i32_and_array_buffer_view(target, offset, &array); } } } unsafe fn buffer_storage(&self, _target: u32, _size: i32, _data: Option<&[u8]>, _flags: u32) { panic!("Buffer storage is not supported"); } unsafe fn check_framebuffer_status(&self, target: u32) -> u32 { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.check_framebuffer_status(target), RawRenderingContext::WebGl2(ref gl) => gl.check_framebuffer_status(target), } } unsafe fn clear_buffer_i32_slice(&self, target: u32, draw_buffer: u32, values: &[i32]) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("Clear buffer with `i32` slice is not supported"); } RawRenderingContext::WebGl2(ref gl) => { gl.clear_bufferiv_with_i32_array(target, draw_buffer as i32, values); } } } unsafe fn clear_buffer_u32_slice(&self, target: u32, draw_buffer: u32, values: &[u32]) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("Clear buffer with `u32` slice is not supported") } RawRenderingContext::WebGl2(ref gl) => { gl.clear_bufferuiv_with_u32_array(target, draw_buffer as i32, values) } } } unsafe fn clear_buffer_f32_slice(&self, target: u32, draw_buffer: u32, values: &[f32]) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("Clear buffer with `f32` slice is not supported") } RawRenderingContext::WebGl2(ref gl) => { gl.clear_bufferfv_with_f32_array(target, draw_buffer as i32, values) } } } unsafe fn clear_buffer_depth_stencil( &self, target: u32, draw_buffer: u32, depth: f32, stencil: i32, ) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("Clear buffer depth stencil is not supported") } RawRenderingContext::WebGl2(ref gl) => { gl.clear_bufferfi(target, draw_buffer as i32, depth, stencil) } } } unsafe fn client_wait_sync(&self, fence: Self::Fence, flags: u32, timeout: i32) -> u32 { let fences = self.fences.borrow(); let raw_fence = fences.get_unchecked(fence); match self.raw { RawRenderingContext::WebGl1(ref _gl) => panic!("Client wait sync is not supported"), RawRenderingContext::WebGl2(ref gl) => { gl.client_wait_sync_with_u32(raw_fence, flags, timeout as u32) } } } unsafe fn wait_sync(&self, fence: Self::Fence, flags: u32, timeout: u64) { let fences = self.fences.borrow(); let raw_fence = fences.get_unchecked(fence); match self.raw { RawRenderingContext::WebGl1(ref _gl) => panic!("Wait sync is not supported"), RawRenderingContext::WebGl2(ref gl) => { gl.wait_sync_with_i32(raw_fence, flags, timeout as i32) } } } unsafe fn copy_buffer_sub_data( &self, src_target: u32, dst_target: u32, src_offset: i32, dst_offset: i32, size: i32, ) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => panic!("Copy buffer subdata is not supported"), RawRenderingContext::WebGl2(ref gl) => gl .copy_buffer_sub_data_with_i32_and_i32_and_i32( src_target, dst_target, src_offset, dst_offset, size, ), } } unsafe fn copy_image_sub_data( &self, _src_name: Self::Texture, _src_target: u32, _src_level: i32, _src_x: i32, _src_y: i32, _src_z: i32, _dst_name: Self::Texture, _dst_target: u32, _dst_level: i32, _dst_x: i32, _dst_y: i32, _dst_z: i32, _src_width: i32, _src_height: i32, _src_depth: i32, ) { unimplemented!() } unsafe fn copy_tex_image_2d( &self, target: u32, level: i32, internal_format: u32, x: i32, y: i32, width: i32, height: i32, border: i32, ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.copy_tex_image_2d(target, level, internal_format, x, y, width, height, border); } RawRenderingContext::WebGl2(ref gl) => { gl.copy_tex_image_2d(target, level, internal_format, x, y, width, height, border); } } } unsafe fn copy_tex_sub_image_2d( &self, target: u32, level: i32, x_offset: i32, y_offset: i32, x: i32, y: i32, width: i32, height: i32, ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.copy_tex_sub_image_2d(target, level, x_offset, y_offset, x, y, width, height); } RawRenderingContext::WebGl2(ref gl) => { gl.copy_tex_sub_image_2d(target, level, x_offset, y_offset, x, y, width, height); } } } unsafe fn copy_tex_sub_image_3d( &self, target: u32, level: i32, x_offset: i32, y_offset: i32, z_offset: i32, x: i32, y: i32, width: i32, height: i32, ) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("Copy tex subimage 3D is not supported"); } RawRenderingContext::WebGl2(ref gl) => { gl.copy_tex_sub_image_3d( target, level, x_offset, y_offset, z_offset, x, y, width, height, ); } } } unsafe fn delete_buffer(&self, buffer: Self::Buffer) { let mut buffers = self.buffers.borrow_mut(); if let Some(ref b) = buffers.remove(buffer) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.delete_buffer(Some(b)), RawRenderingContext::WebGl2(ref gl) => gl.delete_buffer(Some(b)), } } } unsafe fn delete_framebuffer(&self, framebuffer: Self::Framebuffer) { let mut framebuffers = self.framebuffers.borrow_mut(); if let Some(ref f) = framebuffers.remove(framebuffer) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.delete_framebuffer(Some(f)), RawRenderingContext::WebGl2(ref gl) => gl.delete_framebuffer(Some(f)), } } } unsafe fn delete_query(&self, query: Self::Query) { let mut queries = self.queries.borrow_mut(); if let Some(ref r) = queries.remove(query) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => panic!("Query objects are not supported"), RawRenderingContext::WebGl2(ref gl) => gl.delete_query(Some(r)), } } } unsafe fn delete_renderbuffer(&self, renderbuffer: Self::Renderbuffer) { let mut renderbuffers = self.renderbuffers.borrow_mut(); if let Some(ref r) = renderbuffers.remove(renderbuffer) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.delete_renderbuffer(Some(r)), RawRenderingContext::WebGl2(ref gl) => gl.delete_renderbuffer(Some(r)), } } } unsafe fn delete_sampler(&self, sampler: Self::Sampler) { let mut samplers = self.samplers.borrow_mut(); if let Some(ref s) = samplers.remove(sampler) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => panic!("Samplers are not supported"), RawRenderingContext::WebGl2(ref gl) => gl.delete_sampler(Some(s)), } } } unsafe fn delete_sync(&self, fence: Self::Fence) { let mut fences = self.fences.borrow_mut(); if let Some(ref f) = fences.remove(fence) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => panic!("Fences are not supported"), RawRenderingContext::WebGl2(ref gl) => gl.delete_sync(Some(f)), } } } unsafe fn delete_texture(&self, texture: Self::Texture) { let mut textures = self.textures.borrow_mut(); if let Some(ref t) = textures.remove(texture) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.delete_texture(Some(t)), RawRenderingContext::WebGl2(ref gl) => gl.delete_texture(Some(t)), } } } unsafe fn disable(&self, parameter: u32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.disable(parameter), RawRenderingContext::WebGl2(ref gl) => gl.disable(parameter), } } unsafe fn disable_draw_buffer(&self, _parameter: u32, _draw_buffer: u32) { panic!("Draw buffer disable is not supported"); } unsafe fn disable_vertex_attrib_array(&self, index: u32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.disable_vertex_attrib_array(index), RawRenderingContext::WebGl2(ref gl) => gl.disable_vertex_attrib_array(index), } } unsafe fn dispatch_compute(&self, _groups_x: u32, _groups_y: u32, _groups_z: u32) { panic!("Dispatch compute is not supported"); } unsafe fn dispatch_compute_indirect(&self, _offset: i32) { panic!("Dispatch compute indirect is not supported"); } unsafe fn draw_arrays(&self, mode: u32, first: i32, count: i32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.draw_arrays(mode as u32, first, count), RawRenderingContext::WebGl2(ref gl) => gl.draw_arrays(mode as u32, first, count), } } unsafe fn draw_arrays_instanced(&self, mode: u32, first: i32, count: i32, instance_count: i32) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => match &self.extensions.angle_instanced_arrays { Some(extension) => { extension.draw_arrays_instanced_angle(mode as u32, first, count, instance_count) } None => panic!("Draw arrays instanced is not supported"), }, RawRenderingContext::WebGl2(ref gl) => { gl.draw_arrays_instanced(mode as u32, first, count, instance_count) } } } unsafe fn draw_arrays_instanced_base_instance( &self, _mode: u32, _first: i32, _count: i32, _instance_count: i32, _base_instance: u32, ) { panic!("Draw arrays instanced base instance is not supported"); } unsafe fn draw_arrays_indirect_offset(&self, _mode: u32, _offset: i32) { panic!("Draw arrays indirect is not supported"); } unsafe fn draw_buffer(&self, draw_buffer: u32) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => { if let Some(ext) = &self.extensions.webgl_draw_buffers { ext.draw_buffers_webgl(&Array::of1(&draw_buffer.into())) } else { panic!("webgl1 WEBGL_draw_buffers extension not available"); } } RawRenderingContext::WebGl2(ref gl) => { gl.draw_buffers(&Array::of1(&draw_buffer.into())); } } } unsafe fn draw_buffers(&self, buffers: &[u32]) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => { if let Some(ext) = &self.extensions.webgl_draw_buffers { let js_buffers = Array::new(); for &b in buffers { js_buffers.push(&b.into()); } ext.draw_buffers_webgl(&Array::of1(&js_buffers)) } else { panic!("webgl1 WEBGL_draw_buffers extension not available"); } } RawRenderingContext::WebGl2(ref gl) => { let js_buffers = Array::new(); for &b in buffers { js_buffers.push(&b.into()); } gl.draw_buffers(&js_buffers); } } } unsafe fn draw_elements(&self, mode: u32, count: i32, element_type: u32, offset: i32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.draw_elements_with_i32(mode as u32, count, element_type as u32, offset); } RawRenderingContext::WebGl2(ref gl) => { gl.draw_elements_with_i32(mode as u32, count, element_type as u32, offset); } } } unsafe fn draw_elements_base_vertex( &self, _mode: u32, _count: i32, _element_type: u32, _offset: i32, _base_vertex: i32, ) { panic!("Draw elements base vertex is not supported"); } unsafe fn draw_elements_instanced( &self, mode: u32, count: i32, element_type: u32, offset: i32, instance_count: i32, ) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => match &self.extensions.angle_instanced_arrays { None => panic!("Draw elements instanced is not supported"), Some(extension) => extension.draw_elements_instanced_angle_with_i32( mode as u32, count, element_type as u32, offset, instance_count, ), }, RawRenderingContext::WebGl2(ref gl) => { gl.draw_elements_instanced_with_i32( mode as u32, count, element_type as u32, offset, instance_count, ); } } } unsafe fn draw_elements_instanced_base_vertex( &self, _mode: u32, _count: i32, _element_type: u32, _offset: i32, _instance_count: i32, _base_vertex: i32, ) { panic!("Draw elements instanced base vertex is not supported"); } unsafe fn draw_elements_instanced_base_vertex_base_instance( &self, _mode: u32, _count: i32, _element_type: u32, _offset: i32, _instance_count: i32, _base_vertex: i32, _base_instance: u32, ) { panic!("Draw elements instanced base vertex base instance is not supported"); } unsafe fn draw_elements_indirect_offset(&self, _mode: u32, _element_type: u32, _offset: i32) { panic!("Draw elements indirect is not supported"); } unsafe fn enable(&self, parameter: u32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.enable(parameter), RawRenderingContext::WebGl2(ref gl) => gl.enable(parameter), } } unsafe fn is_enabled(&self, parameter: u32) -> bool { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.is_enabled(parameter), RawRenderingContext::WebGl2(ref gl) => gl.is_enabled(parameter), } } unsafe fn enable_draw_buffer(&self, _parameter: u32, _draw_buffer: u32) { panic!("Draw buffer enable is not supported"); } unsafe fn enable_vertex_array_attrib(&self, _vao: Self::VertexArray, _index: u32) { unimplemented!() } unsafe fn enable_vertex_attrib_array(&self, index: u32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.enable_vertex_attrib_array(index), RawRenderingContext::WebGl2(ref gl) => gl.enable_vertex_attrib_array(index), } } unsafe fn flush(&self) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.flush(), RawRenderingContext::WebGl2(ref gl) => gl.flush(), } } unsafe fn framebuffer_renderbuffer( &self, target: u32, attachment: u32, renderbuffer_target: u32, renderbuffer: Option, ) { let renderbuffers = self.renderbuffers.borrow(); let raw_renderbuffer = renderbuffer.map(|r| renderbuffers.get_unchecked(r)); match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.framebuffer_renderbuffer( target, attachment, renderbuffer_target, raw_renderbuffer, ), RawRenderingContext::WebGl2(ref gl) => gl.framebuffer_renderbuffer( target, attachment, renderbuffer_target, raw_renderbuffer, ), } } unsafe fn framebuffer_texture( &self, _target: u32, _attachment: u32, _texture: Option, _level: i32, ) { panic!("Framebuffer texture is not supported"); } unsafe fn framebuffer_texture_2d( &self, target: u32, attachment: u32, texture_target: u32, texture: Option, level: i32, ) { let textures = self.textures.borrow(); let raw_texture = texture.map(|t| textures.get_unchecked(t)); match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.framebuffer_texture_2d(target, attachment, texture_target, raw_texture, level); } RawRenderingContext::WebGl2(ref gl) => { gl.framebuffer_texture_2d(target, attachment, texture_target, raw_texture, level); } } } unsafe fn framebuffer_texture_3d( &self, _target: u32, _attachment: u32, _texture_target: u32, _texture: Option, _level: i32, _layer: i32, ) { panic!("Framebuffer texture 3D is not supported"); } unsafe fn framebuffer_texture_layer( &self, target: u32, attachment: u32, texture: Option, level: i32, layer: i32, ) { let textures = self.textures.borrow(); let raw_texture = texture.map(|t| textures.get_unchecked(t)); match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("Framebuffer texture layer is not supported"); } RawRenderingContext::WebGl2(ref gl) => { gl.framebuffer_texture_layer(target, attachment, raw_texture, level, layer); } } } unsafe fn front_face(&self, value: u32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.front_face(value as u32), RawRenderingContext::WebGl2(ref gl) => gl.front_face(value as u32), } } unsafe fn get_error(&self) -> u32 { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.get_error(), RawRenderingContext::WebGl2(ref gl) => gl.get_error(), } } unsafe fn get_tex_parameter_i32(&self, target: u32, parameter: u32) -> i32 { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.get_tex_parameter(target, parameter), RawRenderingContext::WebGl2(ref gl) => gl.get_tex_parameter(target, parameter), } .as_f64() .map(|v| v as i32) // Errors will be caught by the browser or through `get_error` // so return a default instead .unwrap_or(0) } unsafe fn get_buffer_parameter_i32(&self, target: u32, parameter: u32) -> i32 { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.get_buffer_parameter(target, parameter), RawRenderingContext::WebGl2(ref gl) => gl.get_buffer_parameter(target, parameter), } .as_f64() .map(|v| v as i32) // Errors will be caught by the browser or through `get_error` // so return a default instead .unwrap_or(0) } unsafe fn get_parameter_i32(&self, parameter: u32) -> i32 { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.get_parameter(parameter), RawRenderingContext::WebGl2(ref gl) => gl.get_parameter(parameter), } .unwrap() .as_f64() .map(|v| v as i32) // Errors will be caught by the browser or through `get_error` // so return a default instead .unwrap_or(0) } unsafe fn get_parameter_i32_slice(&self, parameter: u32, v: &mut [i32]) { let value = match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.get_parameter(parameter), RawRenderingContext::WebGl2(ref gl) => gl.get_parameter(parameter), } .unwrap(); use wasm_bindgen::JsCast; if let Some(value) = value.as_f64() { v[0] = value as i32; } else if let Some(values) = value.dyn_ref::() { values.copy_to(v) } } unsafe fn get_parameter_f32(&self, parameter: u32) -> f32 { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.get_parameter(parameter), RawRenderingContext::WebGl2(ref gl) => gl.get_parameter(parameter), } .unwrap() .as_f64() .map(|v| v as f32) // Errors will be caught by the browser or through `get_error` // so return a default instead .unwrap_or(0.0) } unsafe fn get_parameter_f32_slice(&self, parameter: u32, v: &mut [f32]) { let value = match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.get_parameter(parameter), RawRenderingContext::WebGl2(ref gl) => gl.get_parameter(parameter), } .unwrap(); use wasm_bindgen::JsCast; if let Some(value) = value.as_f64() { v[0] = value as f32; } else if let Some(values) = value.dyn_ref::() { values.copy_to(v) } } unsafe fn get_parameter_indexed_i32(&self, parameter: u32, index: u32) -> i32 { match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("Get parameter indexed is not supported") } RawRenderingContext::WebGl2(ref gl) => gl.get_indexed_parameter(parameter, index), } .unwrap() .as_f64() .map(|v| v as i32) // Errors will be caught by the browser or through `get_error` // so return a default instead .unwrap_or(0) } unsafe fn get_parameter_indexed_string(&self, parameter: u32, index: u32) -> String { match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("Get parameter indexed is not supported") } RawRenderingContext::WebGl2(ref gl) => gl.get_indexed_parameter(parameter, index), } .unwrap() .as_string() // Errors will be caught by the browser or through `get_error` // so return a default instead .unwrap_or_else(|| String::from("")) } unsafe fn get_parameter_string(&self, parameter: u32) -> String { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.get_parameter(parameter), RawRenderingContext::WebGl2(ref gl) => gl.get_parameter(parameter), } .unwrap() .as_string() // Errors will be caught by the browser or through `get_error` // so return a default instead .unwrap_or_else(|| String::from("")) } unsafe fn get_uniform_location( &self, program: Self::Program, name: &str, ) -> Option { let programs = self.programs.borrow(); let raw_program = programs.get_unchecked(program); match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.get_uniform_location(raw_program, name), RawRenderingContext::WebGl2(ref gl) => gl.get_uniform_location(raw_program, name), } } unsafe fn get_attrib_location(&self, program: Self::Program, name: &str) -> Option { let programs = self.programs.borrow(); let raw_program = programs.get_unchecked(program); let attrib_location = match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.get_attrib_location(raw_program, name), RawRenderingContext::WebGl2(ref gl) => gl.get_attrib_location(raw_program, name), }; if attrib_location < 0 { None } else { Some(attrib_location as u32) } } unsafe fn bind_attrib_location(&self, program: Self::Program, index: u32, name: &str) { let programs = self.programs.borrow(); let raw_program = programs.get_unchecked(program); match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.bind_attrib_location(raw_program, index, name) } RawRenderingContext::WebGl2(ref gl) => { gl.bind_attrib_location(raw_program, index, name) } } } unsafe fn get_active_attributes(&self, program: Self::Program) -> u32 { let programs = self.programs.borrow(); let raw_program = programs.get_unchecked(program); match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.get_program_parameter(raw_program, WebGlRenderingContext::ACTIVE_ATTRIBUTES) } RawRenderingContext::WebGl2(ref gl) => { gl.get_program_parameter(raw_program, WebGl2RenderingContext::ACTIVE_ATTRIBUTES) } } .as_f64() .map(|v| v as u32) .unwrap_or(0) } unsafe fn get_active_attribute( &self, program: Self::Program, index: u32, ) -> Option { let programs = self.programs.borrow(); let raw_program = programs.get_unchecked(program); match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.get_active_attrib(raw_program, index) .map(|au| ActiveAttribute { size: au.size(), atype: au.type_(), name: au.name(), }) } RawRenderingContext::WebGl2(ref gl) => { gl.get_active_attrib(raw_program, index) .map(|au| ActiveAttribute { size: au.size(), atype: au.type_(), name: au.name(), }) } } } unsafe fn get_sync_status(&self, fence: Self::Fence) -> u32 { let fences = self.fences.borrow(); let raw_fence = fences.get_unchecked(fence); match self.raw { RawRenderingContext::WebGl1(ref _gl) => panic!("Sync is not supported"), RawRenderingContext::WebGl2(ref gl) => gl .get_sync_parameter(raw_fence, SYNC_STATUS) .as_f64() .map(|v| v as u32) .unwrap_or(UNSIGNALED), } } unsafe fn is_sync(&self, fence: Self::Fence) -> bool { let fences = self.fences.borrow(); let raw_fence = fences.get_unchecked(fence); match self.raw { RawRenderingContext::WebGl1(ref _gl) => panic!("Sync is not supported"), RawRenderingContext::WebGl2(ref gl) => gl.is_sync(Some(raw_fence)), } } unsafe fn renderbuffer_storage( &self, target: u32, internal_format: u32, width: i32, height: i32, ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.renderbuffer_storage(target, internal_format, width, height); } RawRenderingContext::WebGl2(ref gl) => { gl.renderbuffer_storage(target, internal_format, width, height); } } } unsafe fn renderbuffer_storage_multisample( &self, target: u32, samples: i32, internal_format: u32, width: i32, height: i32, ) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("Renderbuffer storage multisample is not supported"); } RawRenderingContext::WebGl2(ref gl) => { gl.renderbuffer_storage_multisample( target, samples, internal_format, width, height, ); } } } unsafe fn sampler_parameter_f32(&self, sampler: Self::Sampler, name: u32, value: f32) { let samplers = self.samplers.borrow(); let raw_sampler = samplers.get_unchecked(sampler); match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("Samper parameter for `f32` is not supported") } RawRenderingContext::WebGl2(ref gl) => { gl.sampler_parameterf(raw_sampler, name, value); } } } unsafe fn sampler_parameter_f32_slice( &self, _sampler: Self::Sampler, _name: u32, _value: &[f32], ) { panic!("Sampler parameter for `f32` slice is not supported"); } unsafe fn sampler_parameter_i32(&self, sampler: Self::Sampler, name: u32, value: i32) { let samplers = self.samplers.borrow(); let raw_sampler = samplers.get_unchecked(sampler); match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("Samper parameter for `i32` is not supported") } RawRenderingContext::WebGl2(ref gl) => { gl.sampler_parameteri(raw_sampler, name, value); } } } unsafe fn generate_mipmap(&self, target: u32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.generate_mipmap(target); } RawRenderingContext::WebGl2(ref gl) => { gl.generate_mipmap(target); } } } unsafe fn generate_texture_mipmap(&self, _texture: Self::Texture) { unimplemented!() } unsafe fn tex_image_1d( &self, _target: u32, _level: i32, _internal_format: i32, _width: i32, _border: i32, _format: u32, _ty: u32, _pixels: Option<&[u8]>, ) { panic!("Tex image 1D is not supported"); } unsafe fn compressed_tex_image_1d( &self, _target: u32, _level: i32, _internal_format: i32, _width: i32, _border: i32, _image_size: i32, _pixels: &[u8], ) { panic!("Compressed tex image 1D is not supported"); } unsafe fn tex_image_2d( &self, target: u32, level: i32, internal_format: i32, width: i32, height: i32, border: i32, format: u32, ty: u32, pixels: Option<&[u8]>, ) { let pixels = pixels.map(|bytes| texture_data_view(ty, bytes)); match self.raw { RawRenderingContext::WebGl1(ref gl) => { // TODO: Handle return value? gl.tex_image_2d_with_i32_and_i32_and_i32_and_format_and_type_and_opt_array_buffer_view( target, level, internal_format, width, height, border, format, ty, pixels.as_ref(), ) .unwrap(); } RawRenderingContext::WebGl2(ref gl) => { // TODO: Handle return value? gl.tex_image_2d_with_i32_and_i32_and_i32_and_format_and_type_and_opt_array_buffer_view( target, level, internal_format, width, height, border, format, ty, pixels.as_ref(), ) .unwrap(); } } } unsafe fn tex_image_2d_multisample( &self, _target: u32, _samples: i32, _internal_format: i32, _width: i32, _height: i32, _fixed_sample_locations: bool, ) { panic!("Tex image 2D multisample is not supported"); } unsafe fn compressed_tex_image_2d( &self, target: u32, level: i32, internal_format: i32, width: i32, height: i32, border: i32, _image_size: i32, pixels: &[u8], ) { let src_data = js_sys::Uint8Array::view(pixels); match self.raw { RawRenderingContext::WebGl1(ref gl) => gl .compressed_tex_image_2d_with_array_buffer_view( target, level, internal_format as u32, width, height, border, &src_data, ), RawRenderingContext::WebGl2(ref gl) => gl .compressed_tex_image_2d_with_array_buffer_view( target, level, internal_format as u32, width, height, border, &src_data, ), } } unsafe fn tex_image_3d( &self, target: u32, level: i32, internal_format: i32, width: i32, height: i32, depth: i32, border: i32, format: u32, ty: u32, pixels: Option<&[u8]>, ) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => panic!("3d textures are not supported"), RawRenderingContext::WebGl2(ref gl) => { let pixels = pixels.map(|bytes| texture_data_view(ty, bytes)); // TODO: Handle return value? gl.tex_image_3d_with_opt_array_buffer_view( target, level, internal_format, width, height, depth, border, format, ty, pixels.as_ref(), ) .unwrap(); } } } unsafe fn compressed_tex_image_3d( &self, target: u32, level: i32, internal_format: i32, width: i32, height: i32, depth: i32, border: i32, _image_size: i32, pixels: &[u8], ) { let src_data = js_sys::Uint8Array::view(pixels); match self.raw { RawRenderingContext::WebGl1(_) => { panic!("Compressed 3D textures are not supported.") } RawRenderingContext::WebGl2(ref gl) => gl .compressed_tex_image_3d_with_array_buffer_view( target, level, internal_format as u32, width, height, depth, border, &src_data, ), } } unsafe fn tex_storage_1d( &self, _target: u32, _levels: i32, _internal_format: u32, _width: i32, ) { panic!("Tex storage 1D is not supported"); } unsafe fn tex_storage_2d( &self, target: u32, levels: i32, internal_format: u32, width: i32, height: i32, ) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => panic!("Tex storage 2D is not supported"), RawRenderingContext::WebGl2(ref gl) => { gl.tex_storage_2d(target, levels, internal_format, width, height); } } } unsafe fn tex_storage_2d_multisample( &self, _target: u32, _samples: i32, _internal_format: u32, _width: i32, _height: i32, _fixed_sample_locations: bool, ) { panic!("Tex storage 2D multisample is not supported"); } unsafe fn tex_storage_3d( &self, target: u32, levels: i32, internal_format: u32, width: i32, height: i32, depth: i32, ) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => panic!("Tex storage 3D is not supported"), RawRenderingContext::WebGl2(ref gl) => { gl.tex_storage_3d(target, levels, internal_format, width, height, depth); } } } unsafe fn uniform_1_i32(&self, uniform_location: Option<&Self::UniformLocation>, x: i32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.uniform1i(uniform_location, x), RawRenderingContext::WebGl2(ref gl) => gl.uniform1i(uniform_location, x), } } unsafe fn uniform_2_i32( &self, uniform_location: Option<&Self::UniformLocation>, x: i32, y: i32, ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.uniform2i(uniform_location, x, y), RawRenderingContext::WebGl2(ref gl) => gl.uniform2i(uniform_location, x, y), } } unsafe fn uniform_3_i32( &self, uniform_location: Option<&Self::UniformLocation>, x: i32, y: i32, z: i32, ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.uniform3i(uniform_location, x, y, z), RawRenderingContext::WebGl2(ref gl) => gl.uniform3i(uniform_location, x, y, z), } } unsafe fn uniform_4_i32( &self, uniform_location: Option<&Self::UniformLocation>, x: i32, y: i32, z: i32, w: i32, ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.uniform4i(uniform_location, x, y, z, w), RawRenderingContext::WebGl2(ref gl) => gl.uniform4i(uniform_location, x, y, z, w), } } unsafe fn uniform_1_i32_slice( &self, uniform_location: Option<&Self::UniformLocation>, v: &[i32], ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.uniform1iv_with_i32_array(uniform_location, v) } RawRenderingContext::WebGl2(ref gl) => { gl.uniform1iv_with_i32_array(uniform_location, v) } } } unsafe fn uniform_2_i32_slice( &self, uniform_location: Option<&Self::UniformLocation>, v: &[i32], ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.uniform2iv_with_i32_array(uniform_location, v) } RawRenderingContext::WebGl2(ref gl) => { gl.uniform2iv_with_i32_array(uniform_location, v) } } } unsafe fn uniform_3_i32_slice( &self, uniform_location: Option<&Self::UniformLocation>, v: &[i32], ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.uniform3iv_with_i32_array(uniform_location, v) } RawRenderingContext::WebGl2(ref gl) => { gl.uniform3iv_with_i32_array(uniform_location, v) } } } unsafe fn uniform_4_i32_slice( &self, uniform_location: Option<&Self::UniformLocation>, v: &[i32], ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.uniform4iv_with_i32_array(uniform_location, v) } RawRenderingContext::WebGl2(ref gl) => { gl.uniform4iv_with_i32_array(uniform_location, v) } } } unsafe fn uniform_1_u32(&self, uniform_location: Option<&Self::UniformLocation>, x: u32) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => panic!("Unsigned uniforms are not supported"), RawRenderingContext::WebGl2(ref gl) => gl.uniform1ui(uniform_location, x), } } unsafe fn uniform_2_u32( &self, uniform_location: Option<&Self::UniformLocation>, x: u32, y: u32, ) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => panic!("Unsigned uniforms are not supported"), RawRenderingContext::WebGl2(ref gl) => gl.uniform2ui(uniform_location, x, y), } } unsafe fn uniform_3_u32( &self, uniform_location: Option<&Self::UniformLocation>, x: u32, y: u32, z: u32, ) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => panic!("Unsigned uniforms are not supported"), RawRenderingContext::WebGl2(ref gl) => gl.uniform3ui(uniform_location, x, y, z), } } unsafe fn uniform_4_u32( &self, uniform_location: Option<&Self::UniformLocation>, x: u32, y: u32, z: u32, w: u32, ) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => panic!("Unsigned uniforms are not supported"), RawRenderingContext::WebGl2(ref gl) => gl.uniform4ui(uniform_location, x, y, z, w), } } unsafe fn uniform_1_u32_slice( &self, uniform_location: Option<&Self::UniformLocation>, v: &[u32], ) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("Unsigned uniforms are not supported"); } RawRenderingContext::WebGl2(ref gl) => { gl.uniform1uiv_with_u32_array(uniform_location, v) } } } unsafe fn uniform_2_u32_slice( &self, uniform_location: Option<&Self::UniformLocation>, v: &[u32], ) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("Unsigned uniforms are not supported"); } RawRenderingContext::WebGl2(ref gl) => { gl.uniform2uiv_with_u32_array(uniform_location, v) } } } unsafe fn uniform_3_u32_slice( &self, uniform_location: Option<&Self::UniformLocation>, v: &[u32], ) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("Unsigned uniforms are not supported"); } RawRenderingContext::WebGl2(ref gl) => { gl.uniform3uiv_with_u32_array(uniform_location, v) } } } unsafe fn uniform_4_u32_slice( &self, uniform_location: Option<&Self::UniformLocation>, v: &[u32], ) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("Unsigned uniforms are not supported"); } RawRenderingContext::WebGl2(ref gl) => { gl.uniform4uiv_with_u32_array(uniform_location, v) } } } unsafe fn uniform_1_f32(&self, uniform_location: Option<&Self::UniformLocation>, x: f32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.uniform1f(uniform_location, x), RawRenderingContext::WebGl2(ref gl) => gl.uniform1f(uniform_location, x), } } unsafe fn uniform_2_f32( &self, uniform_location: Option<&Self::UniformLocation>, x: f32, y: f32, ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.uniform2f(uniform_location, x, y), RawRenderingContext::WebGl2(ref gl) => gl.uniform2f(uniform_location, x, y), } } unsafe fn uniform_3_f32( &self, uniform_location: Option<&Self::UniformLocation>, x: f32, y: f32, z: f32, ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.uniform3f(uniform_location, x, y, z), RawRenderingContext::WebGl2(ref gl) => gl.uniform3f(uniform_location, x, y, z), } } unsafe fn uniform_4_f32( &self, uniform_location: Option<&Self::UniformLocation>, x: f32, y: f32, z: f32, w: f32, ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.uniform4f(uniform_location, x, y, z, w), RawRenderingContext::WebGl2(ref gl) => gl.uniform4f(uniform_location, x, y, z, w), } } unsafe fn uniform_1_f32_slice( &self, uniform_location: Option<&Self::UniformLocation>, v: &[f32], ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.uniform1fv_with_f32_array(uniform_location, v) } RawRenderingContext::WebGl2(ref gl) => { gl.uniform1fv_with_f32_array(uniform_location, v) } } } unsafe fn uniform_2_f32_slice( &self, uniform_location: Option<&Self::UniformLocation>, v: &[f32], ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.uniform2fv_with_f32_array(uniform_location, v) } RawRenderingContext::WebGl2(ref gl) => { gl.uniform2fv_with_f32_array(uniform_location, v) } } } unsafe fn uniform_3_f32_slice( &self, uniform_location: Option<&Self::UniformLocation>, v: &[f32], ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.uniform3fv_with_f32_array(uniform_location, v) } RawRenderingContext::WebGl2(ref gl) => { gl.uniform3fv_with_f32_array(uniform_location, v) } } } unsafe fn uniform_4_f32_slice( &self, uniform_location: Option<&Self::UniformLocation>, v: &[f32], ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.uniform4fv_with_f32_array(uniform_location, v) } RawRenderingContext::WebGl2(ref gl) => { gl.uniform4fv_with_f32_array(uniform_location, v) } } } unsafe fn uniform_matrix_2_f32_slice( &self, uniform_location: Option<&Self::UniformLocation>, transpose: bool, v: &[f32], ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.uniform_matrix2fv_with_f32_array(uniform_location, transpose, v) } RawRenderingContext::WebGl2(ref gl) => { gl.uniform_matrix2fv_with_f32_array(uniform_location, transpose, v) } } } unsafe fn uniform_matrix_3_f32_slice( &self, uniform_location: Option<&Self::UniformLocation>, transpose: bool, v: &[f32], ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.uniform_matrix3fv_with_f32_array(uniform_location, transpose, v) } RawRenderingContext::WebGl2(ref gl) => { gl.uniform_matrix3fv_with_f32_array(uniform_location, transpose, v) } } } unsafe fn uniform_matrix_4_f32_slice( &self, uniform_location: Option<&Self::UniformLocation>, transpose: bool, v: &[f32], ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.uniform_matrix4fv_with_f32_array(uniform_location, transpose, v) } RawRenderingContext::WebGl2(ref gl) => { gl.uniform_matrix4fv_with_f32_array(uniform_location, transpose, v) } } } unsafe fn unmap_buffer(&self, _target: u32) { panic!("Unmap buffer is not supported"); } unsafe fn cull_face(&self, value: u32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.cull_face(value as u32), RawRenderingContext::WebGl2(ref gl) => gl.cull_face(value as u32), } } unsafe fn color_mask(&self, red: bool, green: bool, blue: bool, alpha: bool) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.color_mask(red, green, blue, alpha), RawRenderingContext::WebGl2(ref gl) => gl.color_mask(red, green, blue, alpha), } } unsafe fn color_mask_draw_buffer( &self, _draw_buffer: u32, _red: bool, _green: bool, _blue: bool, _alpha: bool, ) { panic!("Draw buffer color masks are not supported"); } unsafe fn depth_mask(&self, value: bool) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.depth_mask(value), RawRenderingContext::WebGl2(ref gl) => gl.depth_mask(value), } } unsafe fn blend_color(&self, red: f32, green: f32, blue: f32, alpha: f32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.blend_color(red, green, blue, alpha), RawRenderingContext::WebGl2(ref gl) => gl.blend_color(red, green, blue, alpha), } } unsafe fn line_width(&self, width: f32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.line_width(width), RawRenderingContext::WebGl2(ref gl) => gl.line_width(width), } } unsafe fn map_buffer_range( &self, _target: u32, _offset: i32, _length: i32, _access: u32, ) -> *mut u8 { panic!("Map buffer range is not supported") } unsafe fn flush_mapped_buffer_range(&self, _target: u32, _offset: i32, _length: i32) { panic!("Flush mapped buffer range is not supported") } unsafe fn invalidate_buffer_sub_data(&self, _target: u32, _offset: i32, _length: i32) { panic!("Invalidate buffer sub data is not supported") } unsafe fn invalidate_framebuffer(&self, target: u32, attachments: &[u32]) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("Invalidate framebuffer is not supported"); } RawRenderingContext::WebGl2(ref gl) => { let js_attachments = Array::new(); for &a in attachments { js_attachments.push(&a.into()); } gl.invalidate_framebuffer(target, &js_attachments).unwrap(); } } } unsafe fn polygon_offset(&self, factor: f32, units: f32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.polygon_offset(factor, units), RawRenderingContext::WebGl2(ref gl) => gl.polygon_offset(factor, units), } } unsafe fn polygon_mode(&self, _face: u32, mode: u32) { if mode != FILL { panic!("Polygon mode other than FILL is not supported"); } } unsafe fn finish(&self) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.finish(), RawRenderingContext::WebGl2(ref gl) => gl.finish(), } } unsafe fn bind_texture(&self, target: u32, texture: Option) { let textures = self.textures.borrow(); let raw_texture = texture.map(|t| textures.get_unchecked(t)); match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.bind_texture(target, raw_texture), RawRenderingContext::WebGl2(ref gl) => gl.bind_texture(target, raw_texture), } } unsafe fn bind_sampler(&self, unit: u32, sampler: Option) { let samplers = self.samplers.borrow(); let raw_sampler = sampler.map(|s| samplers.get_unchecked(s)); match self.raw { RawRenderingContext::WebGl1(ref _gl) => panic!("Bind sampler is not supported"), RawRenderingContext::WebGl2(ref gl) => gl.bind_sampler(unit, raw_sampler), } } unsafe fn active_texture(&self, unit: u32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.active_texture(unit), RawRenderingContext::WebGl2(ref gl) => gl.active_texture(unit), } } unsafe fn fence_sync(&self, condition: u32, flags: u32) -> Result { let raw_fence = match self.raw { RawRenderingContext::WebGl1(ref _gl) => panic!("Fences are not supported"), RawRenderingContext::WebGl2(ref gl) => gl.fence_sync(condition as u32, flags), }; match raw_fence { Some(f) => { let key = self.fences.borrow_mut().insert(f); Ok(key) } None => Err(String::from("Unable to create fence object")), } } unsafe fn tex_parameter_f32(&self, target: u32, parameter: u32, value: f32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.tex_parameterf(target, parameter, value), RawRenderingContext::WebGl2(ref gl) => gl.tex_parameterf(target, parameter, value), } } unsafe fn tex_parameter_i32(&self, target: u32, parameter: u32, value: i32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.tex_parameteri(target, parameter, value), RawRenderingContext::WebGl2(ref gl) => gl.tex_parameteri(target, parameter, value), } } unsafe fn texture_parameter_i32(&self, _texture: Self::Texture, _parameter: u32, _value: i32) { unimplemented!() } unsafe fn tex_parameter_f32_slice(&self, _target: u32, _parameter: u32, _values: &[f32]) { // Blocked by https://github.com/rustwasm/wasm-bindgen/issues/1038 panic!("Texture parameters for `&[f32]` are not supported yet"); } unsafe fn tex_parameter_i32_slice(&self, _target: u32, _parameter: u32, _values: &[i32]) { panic!("Texture parameters for `&[i32]` are not supported yet"); } unsafe fn tex_sub_image_2d( &self, target: u32, level: i32, x_offset: i32, y_offset: i32, width: i32, height: i32, format: u32, ty: u32, pixels: PixelUnpackData, ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { match pixels { PixelUnpackData::BufferOffset(_) => { panic!("Sub image 2D pixel buffer offset is not supported"); } PixelUnpackData::Slice(data) => { let data = texture_data_view(ty, data); gl.tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_opt_array_buffer_view( target, level, x_offset, y_offset, width, height, format, ty, Some(&data), ) } } .unwrap(); // TODO: Handle return value? } RawRenderingContext::WebGl2(ref gl) => { match pixels { PixelUnpackData::BufferOffset(offset) => gl .tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_i32( target, level, x_offset, y_offset, width, height, format, ty, offset as i32, ), PixelUnpackData::Slice(data) => { let data = texture_data_view(ty, data); gl.tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_opt_array_buffer_view( target, level, x_offset, y_offset, width, height, format, ty, Some(&data), ) } } .unwrap(); // TODO: Handle return value? } } } unsafe fn texture_sub_image_3d( &self, _texture: Self::Texture, _level: i32, _x_offset: i32, _y_offset: i32, _z_offset: i32, _width: i32, _height: i32, _depth: i32, _format: u32, _ty: u32, _pixels: PixelUnpackData, ) { unimplemented!() } unsafe fn compressed_tex_sub_image_2d( &self, target: u32, level: i32, x_offset: i32, y_offset: i32, width: i32, height: i32, format: u32, pixels: CompressedPixelUnpackData, ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => match pixels { CompressedPixelUnpackData::BufferRange(_) => { panic!("Compressed sub image 2D pixel buffer range is not supported"); } CompressedPixelUnpackData::Slice(data) => { let data = texture_data_view(BYTE, data); gl.compressed_tex_sub_image_2d_with_array_buffer_view( target, level, x_offset, y_offset, width, height, format, &data, ) } }, RawRenderingContext::WebGl2(ref gl) => match pixels { CompressedPixelUnpackData::BufferRange(range) => gl .compressed_tex_sub_image_2d_with_i32_and_i32( target, level, x_offset, y_offset, width, height, format, (range.end - range.start) as i32, range.start as i32, ), CompressedPixelUnpackData::Slice(data) => { let data = texture_data_view(BYTE, data); gl.compressed_tex_sub_image_2d_with_array_buffer_view( target, level, x_offset, y_offset, width, height, format, &data, ) } }, } } unsafe fn tex_sub_image_3d( &self, target: u32, level: i32, x_offset: i32, y_offset: i32, z_offset: i32, width: i32, height: i32, depth: i32, format: u32, ty: u32, pixels: PixelUnpackData, ) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("Sub image 3D is not supported"); } RawRenderingContext::WebGl2(ref gl) => { match pixels { PixelUnpackData::BufferOffset(offset) => gl.tex_sub_image_3d_with_i32( target, level, x_offset, y_offset, z_offset, width, height, depth, format, ty, offset as i32, ), PixelUnpackData::Slice(slice) => { let slice = texture_data_view(ty, slice); gl.tex_sub_image_3d_with_opt_array_buffer_view( target, level, x_offset, y_offset, z_offset, width, height, depth, format, ty, Some(&slice), ) } } .unwrap(); // TODO: Handle return value? } } } unsafe fn compressed_tex_sub_image_3d( &self, target: u32, level: i32, x_offset: i32, y_offset: i32, z_offset: i32, width: i32, height: i32, depth: i32, format: u32, pixels: CompressedPixelUnpackData, ) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("Compressed sub image 3D is not supported"); } RawRenderingContext::WebGl2(ref gl) => match pixels { CompressedPixelUnpackData::BufferRange(range) => gl .compressed_tex_sub_image_3d_with_i32_and_i32( target, level, x_offset, y_offset, z_offset, width, height, depth, format, (range.end - range.start) as i32, range.start as i32, ), CompressedPixelUnpackData::Slice(data) => { let data = texture_data_view(BYTE, data); gl.compressed_tex_sub_image_3d_with_array_buffer_view( target, level, x_offset, y_offset, z_offset, width, height, depth, format, &data, ) } }, } } unsafe fn depth_func(&self, func: u32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.depth_func(func as u32), RawRenderingContext::WebGl2(ref gl) => gl.depth_func(func as u32), } } unsafe fn depth_range_f32(&self, near: f32, far: f32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.depth_range(near, far), RawRenderingContext::WebGl2(ref gl) => gl.depth_range(near, far), } } unsafe fn depth_range_f64(&self, _near: f64, _far: f64) { panic!("Depth range with 64-bit float values is not supported"); } unsafe fn depth_range_f64_slice(&self, _first: u32, _count: i32, _values: &[[f64; 2]]) { panic!("Depth range with 64-bit float slices is not supported"); } unsafe fn scissor(&self, x: i32, y: i32, width: i32, height: i32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.scissor(x, y, width, height), RawRenderingContext::WebGl2(ref gl) => gl.scissor(x, y, width, height), } } unsafe fn scissor_slice(&self, _first: u32, _count: i32, _scissors: &[[i32; 4]]) { panic!("Scissor slice is not supported"); } unsafe fn vertex_array_attrib_binding_f32( &self, _vao: Self::VertexArray, _index: u32, _binding_index: u32, ) { unimplemented!() } unsafe fn vertex_array_attrib_format_f32( &self, _vao: Self::VertexArray, _index: u32, _size: i32, _data_type: u32, _normalized: bool, _relative_offset: u32, ) { unimplemented!() } unsafe fn vertex_array_attrib_format_i32( &self, _vao: Self::VertexArray, _index: u32, _size: i32, _data_type: u32, _relative_offset: u32, ) { unimplemented!() } unsafe fn vertex_array_element_buffer( &self, _vao: Self::VertexArray, _buffer: Option, ) { unimplemented!() } unsafe fn vertex_array_vertex_buffer( &self, _vao: Self::VertexArray, _binding_index: u32, _buffer: Option, _offset: i32, _stride: i32, ) { unimplemented!() } unsafe fn vertex_attrib_divisor(&self, index: u32, divisor: u32) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => match &self.extensions.angle_instanced_arrays { None => panic!("Vertex attrib divisor is not supported"), Some(extension) => extension.vertex_attrib_divisor_angle(index, divisor), }, RawRenderingContext::WebGl2(ref gl) => gl.vertex_attrib_divisor(index, divisor), } } unsafe fn vertex_attrib_pointer_f32( &self, index: u32, size: i32, data_type: u32, normalized: bool, stride: i32, offset: i32, ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl .vertex_attrib_pointer_with_i32(index, size, data_type, normalized, stride, offset), RawRenderingContext::WebGl2(ref gl) => gl .vertex_attrib_pointer_with_i32(index, size, data_type, normalized, stride, offset), } } unsafe fn vertex_attrib_pointer_i32( &self, index: u32, size: i32, data_type: u32, stride: i32, offset: i32, ) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("Integer vertex attrib pointer is not supported") } RawRenderingContext::WebGl2(ref gl) => { gl.vertex_attrib_i_pointer_with_i32(index, size, data_type, stride, offset) } } } unsafe fn vertex_attrib_pointer_f64( &self, _index: u32, _size: i32, _data_type: u32, _stride: i32, _offset: i32, ) { panic!("64-bit float precision is not supported in WebGL"); } unsafe fn vertex_attrib_format_f32( &self, _index: u32, _size: i32, _data_type: u32, _normalized: bool, _relative_offset: u32, ) { panic!("Vertex attrib format is not supported in WebGL"); } unsafe fn vertex_attrib_format_i32( &self, _index: u32, _size: i32, _data_type: u32, _relative_offset: u32, ) { panic!("Vertex attrib format is not supported in WebGL"); } unsafe fn vertex_attrib_1_f32(&self, index: u32, x: f32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.vertex_attrib1f(index, x), RawRenderingContext::WebGl2(ref gl) => gl.vertex_attrib1f(index, x), } } unsafe fn vertex_attrib_2_f32(&self, index: u32, x: f32, y: f32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.vertex_attrib2f(index, x, y), RawRenderingContext::WebGl2(ref gl) => gl.vertex_attrib2f(index, x, y), } } unsafe fn vertex_attrib_3_f32(&self, index: u32, x: f32, y: f32, z: f32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.vertex_attrib3f(index, x, y, z), RawRenderingContext::WebGl2(ref gl) => gl.vertex_attrib3f(index, x, y, z), } } unsafe fn vertex_attrib_4_f32(&self, index: u32, x: f32, y: f32, z: f32, w: f32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.vertex_attrib4f(index, x, y, z, w), RawRenderingContext::WebGl2(ref gl) => gl.vertex_attrib4f(index, x, y, z, w), } } unsafe fn vertex_attrib_1_f32_slice(&self, index: u32, v: &[f32]) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.vertex_attrib1fv_with_f32_array(index, v), RawRenderingContext::WebGl2(ref gl) => gl.vertex_attrib1fv_with_f32_array(index, v), } } unsafe fn vertex_attrib_2_f32_slice(&self, index: u32, v: &[f32]) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.vertex_attrib2fv_with_f32_array(index, v), RawRenderingContext::WebGl2(ref gl) => gl.vertex_attrib2fv_with_f32_array(index, v), } } unsafe fn vertex_attrib_3_f32_slice(&self, index: u32, v: &[f32]) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.vertex_attrib3fv_with_f32_array(index, v), RawRenderingContext::WebGl2(ref gl) => gl.vertex_attrib3fv_with_f32_array(index, v), } } unsafe fn vertex_attrib_4_f32_slice(&self, index: u32, v: &[f32]) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.vertex_attrib4fv_with_f32_array(index, v), RawRenderingContext::WebGl2(ref gl) => gl.vertex_attrib4fv_with_f32_array(index, v), } } unsafe fn vertex_attrib_binding(&self, _attrib_index: u32, _binding_index: u32) { panic!("Vertex attrib binding is not supported"); } unsafe fn vertex_binding_divisor(&self, _binding_index: u32, _divisor: u32) { panic!("Vertex binding divisor is not supported"); } unsafe fn viewport(&self, x: i32, y: i32, width: i32, height: i32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.viewport(x, y, width, height), RawRenderingContext::WebGl2(ref gl) => gl.viewport(x, y, width, height), } } unsafe fn viewport_f32_slice(&self, _first: u32, _count: i32, _values: &[[f32; 4]]) { panic!("Viewport `f32` slice is not supported"); } unsafe fn blend_func(&self, src: u32, dst: u32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.blend_func(src as u32, dst as u32), RawRenderingContext::WebGl2(ref gl) => gl.blend_func(src as u32, dst as u32), } } unsafe fn blend_func_draw_buffer(&self, _draw_buffer: u32, _src: u32, _dst: u32) { panic!("Draw buffer blend func is not supported"); } unsafe fn blend_func_separate( &self, src_rgb: u32, dst_rgb: u32, src_alpha: u32, dst_alpha: u32, ) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.blend_func_separate( src_rgb as u32, dst_rgb as u32, src_alpha as u32, dst_alpha as u32, ), RawRenderingContext::WebGl2(ref gl) => gl.blend_func_separate( src_rgb as u32, dst_rgb as u32, src_alpha as u32, dst_alpha as u32, ), } } unsafe fn blend_func_separate_draw_buffer( &self, _draw_buffer: u32, _src_rgb: u32, _dst_rgb: u32, _src_alpha: u32, _dst_alpha: u32, ) { panic!("Draw buffer blend func separate is not supported"); } unsafe fn blend_equation(&self, mode: u32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.blend_equation(mode as u32), RawRenderingContext::WebGl2(ref gl) => gl.blend_equation(mode as u32), } } unsafe fn blend_equation_draw_buffer(&self, _draw_buffer: u32, _mode: u32) { panic!("Draw buffer blend equation is not supported"); } unsafe fn blend_equation_separate(&self, mode_rgb: u32, mode_alpha: u32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.blend_equation_separate(mode_rgb as u32, mode_alpha as u32) } RawRenderingContext::WebGl2(ref gl) => { gl.blend_equation_separate(mode_rgb as u32, mode_alpha as u32) } } } unsafe fn blend_equation_separate_draw_buffer( &self, _draw_buffer: u32, _mode_rgb: u32, _mode_alpha: u32, ) { panic!("Draw buffer blend equation separate is not supported"); } unsafe fn stencil_func(&self, func: u32, reference: i32, mask: u32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.stencil_func(func as u32, reference, mask), RawRenderingContext::WebGl2(ref gl) => gl.stencil_func(func as u32, reference, mask), } } unsafe fn stencil_func_separate(&self, face: u32, func: u32, reference: i32, mask: u32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.stencil_func_separate(face as u32, func as u32, reference, mask) } RawRenderingContext::WebGl2(ref gl) => { gl.stencil_func_separate(face as u32, func as u32, reference, mask) } } } unsafe fn stencil_mask(&self, mask: u32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.stencil_mask(mask), RawRenderingContext::WebGl2(ref gl) => gl.stencil_mask(mask), } } unsafe fn stencil_mask_separate(&self, face: u32, mask: u32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.stencil_mask_separate(face as u32, mask), RawRenderingContext::WebGl2(ref gl) => gl.stencil_mask_separate(face as u32, mask), } } unsafe fn stencil_op(&self, stencil_fail: u32, depth_fail: u32, pass: u32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => { gl.stencil_op(stencil_fail as u32, depth_fail as u32, pass as u32) } RawRenderingContext::WebGl2(ref gl) => { gl.stencil_op(stencil_fail as u32, depth_fail as u32, pass as u32) } } } unsafe fn stencil_op_separate(&self, face: u32, stencil_fail: u32, depth_fail: u32, pass: u32) { match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.stencil_op_separate( face as u32, stencil_fail as u32, depth_fail as u32, pass as u32, ), RawRenderingContext::WebGl2(ref gl) => gl.stencil_op_separate( face as u32, stencil_fail as u32, depth_fail as u32, pass as u32, ), } } unsafe fn debug_message_control( &self, _source: u32, _msg_type: u32, _severity: u32, _ids: &[u32], _enabled: bool, ) { panic!("WebGL does not support the KHR_debug extension.") } unsafe fn debug_message_insert( &self, _source: u32, _msg_type: u32, _id: u32, _severity: u32, _msg: S, ) where S: AsRef, { panic!("WebGL does not support the KHR_debug extension.") } unsafe fn debug_message_callback(&self, _callback: F) where F: FnMut(u32, u32, u32, u32, &str), { panic!("WebGL does not support the KHR_debug extension.") } unsafe fn get_debug_message_log(&self, _count: u32) -> Vec { panic!("WebGL does not support the KHR_debug extension.") } unsafe fn push_debug_group(&self, _source: u32, _id: u32, _message: S) where S: AsRef, { panic!("WebGL does not support the KHR_debug extension.") } unsafe fn pop_debug_group(&self) { panic!("WebGL does not support the KHR_debug extension.") } unsafe fn object_label(&self, _identifier: u32, _name: u32, _label: Option) where S: AsRef, { panic!("WebGL does not support the KHR_debug extension.") } unsafe fn get_object_label(&self, _identifier: u32, _name: u32) -> String { panic!("WebGL does not support the KHR_debug extension.") } unsafe fn object_ptr_label(&self, _sync: Self::Fence, _label: Option) where S: AsRef, { panic!("WebGL does not support the KHR_debug extension.") } unsafe fn get_object_ptr_label(&self, _sync: Self::Fence) -> String { panic!("WebGL does not support the KHR_debug extension.") } unsafe fn get_uniform_block_index(&self, program: Self::Program, name: &str) -> Option { let programs = self.programs.borrow(); let raw_program = programs.get_unchecked(program); let index = match self.raw { RawRenderingContext::WebGl1(ref _gl) => panic!("Uniform blocks are not supported"), RawRenderingContext::WebGl2(ref gl) => gl.get_uniform_block_index(raw_program, name), }; if index == INVALID_INDEX { None } else { Some(index) } } unsafe fn uniform_block_binding(&self, program: Self::Program, index: u32, binding: u32) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("Uniform buffer bindings are not supported") } RawRenderingContext::WebGl2(ref gl) => { let programs = self.programs.borrow(); let raw_program = programs.get_unchecked(program); gl.uniform_block_binding(raw_program, index, binding); } } } unsafe fn get_shader_storage_block_index( &self, _program: Self::Program, _name: &str, ) -> Option { panic!("Shader Storage Buffers are not supported by webgl") } unsafe fn shader_storage_block_binding( &self, _program: Self::Program, _index: u32, _binding: u32, ) { panic!("Shader Storage Buffers are not supported by webgl") } unsafe fn read_buffer(&self, src: u32) { match self.raw { RawRenderingContext::WebGl1(..) => panic!("read_buffer is not supported by WebGL1"), RawRenderingContext::WebGl2(ref gl) => gl.read_buffer(src), } } unsafe fn read_pixels( &self, x: i32, y: i32, width: i32, height: i32, format: u32, gltype: u32, pixels: PixelPackData, ) { match pixels { PixelPackData::BufferOffset(offset) => match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("Read pixels into buffer offset is not supported") } RawRenderingContext::WebGl2(ref gl) => gl .read_pixels_with_i32(x, y, width, height, format, gltype, offset as i32) .unwrap(), }, PixelPackData::Slice(bytes) => { let data = texture_data_view(gltype, bytes); match self.raw { RawRenderingContext::WebGl1(ref gl) => gl .read_pixels_with_opt_array_buffer_view( x, y, width, height, format, gltype, Some(&data), ) .unwrap(), RawRenderingContext::WebGl2(ref gl) => gl .read_pixels_with_opt_array_buffer_view( x, y, width, height, format, gltype, Some(&data), ) .unwrap(), } } } } unsafe fn texture_storage_3d( &self, _texture: Self::Texture, _levels: i32, _internal_format: u32, _width: i32, _height: i32, _depth: i32, ) { unimplemented!() } unsafe fn get_uniform_i32( &self, program: Self::Program, location: &Self::UniformLocation, v: &mut [i32], ) { let programs = self.programs.borrow(); let raw_program = programs.get_unchecked(program); let value = match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.get_uniform(&raw_program, location), RawRenderingContext::WebGl2(ref gl) => gl.get_uniform(&raw_program, location), }; use wasm_bindgen::JsCast; if let Some(value) = value.as_f64() { v[0] = value as i32; } else if let Some(values) = value.dyn_ref::() { values.copy_to(v) } } unsafe fn get_uniform_f32( &self, program: Self::Program, location: &Self::UniformLocation, v: &mut [f32], ) { let programs = self.programs.borrow(); let raw_program = programs.get_unchecked(program); let value = match self.raw { RawRenderingContext::WebGl1(ref gl) => gl.get_uniform(&raw_program, location), RawRenderingContext::WebGl2(ref gl) => gl.get_uniform(&raw_program, location), }; use wasm_bindgen::JsCast; if let Some(value) = value.as_f64() { v[0] = value as f32; } else if let Some(values) = value.dyn_ref::() { values.copy_to(v) } } unsafe fn begin_query(&self, target: u32, query: Self::Query) { let queries = self.queries.borrow(); let raw_query = queries.get_unchecked(query); match self.raw { RawRenderingContext::WebGl1(ref _gl) => panic!("Query objects are not supported"), RawRenderingContext::WebGl2(ref gl) => gl.begin_query(target, raw_query), } } unsafe fn end_query(&self, target: u32) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => panic!("Query objects are not supported"), RawRenderingContext::WebGl2(ref gl) => gl.end_query(target), } } unsafe fn get_query_parameter_u32(&self, query: Self::Query, parameter: u32) -> u32 { let queries = self.queries.borrow(); let raw_query = queries.get_unchecked(query); match self.raw { RawRenderingContext::WebGl1(ref _gl) => panic!("Query objects are not supported"), RawRenderingContext::WebGl2(ref gl) => gl .get_query_parameter(raw_query, parameter) .as_f64() .map(|v| v as u32) .unwrap_or(0), } } unsafe fn create_transform_feedback(&self) -> Result { let raw_transform_feedback = match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("TransformFeedback objects are not supported") } RawRenderingContext::WebGl2(ref gl) => gl.create_transform_feedback(), }; match raw_transform_feedback { Some(t) => { let key = self.transform_feedbacks.borrow_mut().insert(t); Ok(key) } None => Err(String::from("Unable to create TransformFeedback object")), } } unsafe fn delete_transform_feedback(&self, transform_feedback: Self::TransformFeedback) { let mut transform_feedbacks = self.transform_feedbacks.borrow_mut(); if let Some(ref t) = transform_feedbacks.remove(transform_feedback) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("TransformFeedback objects are not supported") } RawRenderingContext::WebGl2(ref gl) => gl.delete_transform_feedback(Some(t)), } } } unsafe fn bind_transform_feedback( &self, target: u32, transform_feedback: Option, ) { let transform_feedbacks = self.transform_feedbacks.borrow(); let raw_transform_feedback = transform_feedback.map(|tf| transform_feedbacks.get_unchecked(tf)); match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("TransformFeedback objects are not supported") } RawRenderingContext::WebGl2(ref gl) => { gl.bind_transform_feedback(target, raw_transform_feedback) } } } unsafe fn begin_transform_feedback(&self, primitive_mode: u32) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("TransformFeedback objects are not supported") } RawRenderingContext::WebGl2(ref gl) => gl.begin_transform_feedback(primitive_mode), } } unsafe fn end_transform_feedback(&self) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("TransformFeedback objects are not supported") } RawRenderingContext::WebGl2(ref gl) => gl.end_transform_feedback(), } } unsafe fn pause_transform_feedback(&self) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("TransformFeedback objects are not supported") } RawRenderingContext::WebGl2(ref gl) => gl.pause_transform_feedback(), } } unsafe fn resume_transform_feedback(&self) { match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("TransformFeedback objects are not supported") } RawRenderingContext::WebGl2(ref gl) => gl.resume_transform_feedback(), } } unsafe fn transform_feedback_varyings( &self, program: Self::Program, varyings: &[&str], buffer_mode: u32, ) { let programs = self.programs.borrow(); let raw_program = programs.get_unchecked(program); match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("TransformFeedback objects are not supported") } RawRenderingContext::WebGl2(ref gl) => { let js_varyings = Array::new(); for &v in varyings { js_varyings.push(&v.into()); } gl.transform_feedback_varyings(raw_program, &js_varyings, buffer_mode); } } } unsafe fn get_transform_feedback_varying( &self, program: Self::Program, index: u32, ) -> Option { let programs = self.programs.borrow(); let raw_program = programs.get_unchecked(program); match self.raw { RawRenderingContext::WebGl1(ref _gl) => { panic!("TransformFeedback objects are not supported") } RawRenderingContext::WebGl2(ref gl) => gl .get_transform_feedback_varying(raw_program, index) .map(|info| ActiveTransformFeedback { size: info.size(), tftype: info.type_(), name: info.name(), }), } } unsafe fn memory_barrier(&self, _barriers: u32) { panic!("Memory barriers are not supported") } unsafe fn memory_barrier_by_region(&self, _barriers: u32) { panic!("Memory barriers are not supported") } unsafe fn bind_image_texture( &self, _unit: u32, _texture: Self::Texture, _level: i32, _layered: bool, _layer: i32, _access: u32, _format: u32, ) { panic!("Image load/store is not supported") } unsafe fn get_active_uniform_block_parameter_i32( &self, program: Self::Program, uniform_block_index: u32, parameter: u32, ) -> i32 { let programs = self.programs.borrow(); let raw_program = programs.get_unchecked(program); match self.raw { RawRenderingContext::WebGl1(ref _gl) => panic!("Uniform blocks are not supported"), RawRenderingContext::WebGl2(ref gl) => gl .get_active_uniform_block_parameter(raw_program, uniform_block_index, parameter) .unwrap() .as_f64() .map(|v| v as i32) // Errors will be caught by the browser or through `get_error` // so return a default instead .unwrap_or(0), } } unsafe fn get_active_uniform_block_parameter_i32_slice( &self, program: Self::Program, uniform_block_index: u32, parameter: u32, out: &mut [i32], ) { let programs = self.programs.borrow(); let raw_program = programs.get_unchecked(program); match self.raw { RawRenderingContext::WebGl1(ref _gl) => panic!("Uniform blocks are not supported"), RawRenderingContext::WebGl2(ref gl) => { let value = gl .get_active_uniform_block_parameter(raw_program, uniform_block_index, parameter) .unwrap(); use wasm_bindgen::JsCast; if let Some(value) = value.as_f64() { out[0] = value as i32; } else if let Some(values) = value.dyn_ref::() { // To maintain compatibility with the pointers returned by // desktop GL, which are signed, an extra copy is needed // here. values .to_vec() .into_iter() .zip(out.iter_mut()) .for_each(|(val, target)| *target = val as i32) } } } } unsafe fn get_active_uniform_block_name( &self, program: Self::Program, uniform_block_index: u32, ) -> String { let programs = self.programs.borrow(); let raw_program = programs.get_unchecked(program); match self.raw { RawRenderingContext::WebGl1(ref _gl) => panic!("Uniform blocks are not supported"), RawRenderingContext::WebGl2(ref gl) => gl .get_active_uniform_block_name(raw_program, uniform_block_index) .unwrap(), } } unsafe fn max_shader_compiler_threads(&self, _count: u32) { // WebGL doesn't use this } } /// Sending texture data requires different data views for different data types. /// This function reinterprets the byte data into the correct type for the texture. /// The lookup is generated from this table: https://www.khronos.org/registry/webgl/specs/latest/2.0/#TEXTURE_PIXELS_TYPE_TABLE unsafe fn texture_data_view(ty: u32, bytes: &[u8]) -> js_sys::Object { use std::mem::size_of; use std::slice::from_raw_parts; match ty { BYTE => { let data = from_raw_parts(bytes.as_ptr() as *const i8, bytes.len() / size_of::()); js_sys::Int8Array::view(data).into() } SHORT => { #[allow(clippy::cast_ptr_alignment)] let data = from_raw_parts(bytes.as_ptr() as *const i16, bytes.len() / size_of::()); js_sys::Int16Array::view(data).into() } UNSIGNED_SHORT | UNSIGNED_SHORT_5_6_5 | UNSIGNED_SHORT_5_5_5_1 | UNSIGNED_SHORT_4_4_4_4 | HALF_FLOAT => { #[allow(clippy::cast_ptr_alignment)] let data = from_raw_parts(bytes.as_ptr() as *const u16, bytes.len() / size_of::()); js_sys::Uint16Array::view(data).into() } INT => { #[allow(clippy::cast_ptr_alignment)] let data = from_raw_parts(bytes.as_ptr() as *const i32, bytes.len() / size_of::()); js_sys::Int32Array::view(data).into() } UNSIGNED_INT | UNSIGNED_INT_5_9_9_9_REV | UNSIGNED_INT_2_10_10_10_REV | UNSIGNED_INT_10F_11F_11F_REV | UNSIGNED_INT_24_8 => { #[allow(clippy::cast_ptr_alignment)] let data = from_raw_parts(bytes.as_ptr() as *const u32, bytes.len() / size_of::()); js_sys::Uint32Array::view(data).into() } FLOAT => { #[allow(clippy::cast_ptr_alignment)] let data = from_raw_parts(bytes.as_ptr() as *const f32, bytes.len() / size_of::()); js_sys::Float32Array::view(data).into() } UNSIGNED_BYTE | _ => js_sys::Uint8Array::view(bytes).into(), } }