├── .gitignore ├── examples └── hello │ ├── Cargo.toml │ ├── README.md │ ├── index.html │ └── src │ └── main.rs ├── README.md ├── LICENSE-MIT ├── Cargo.toml ├── LICENSE-APACHE └── src ├── native.rs └── web.rs /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | /target 3 | **/*.rs.bk 4 | Cargo.lock 5 | generated 6 | -------------------------------------------------------------------------------- /examples/hello/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [dependencies] 7 | glow = { path = "../../" } 8 | 9 | [target.'cfg(not(any(target_arch = "wasm32")))'.dependencies] 10 | glutin = "0.19" 11 | 12 | [target.wasm32-unknown-unknown.dependencies] 13 | web-sys = { version = "0.3", features=["console"] } 14 | wasm-bindgen = "0.2" 15 | -------------------------------------------------------------------------------- /examples/hello/README.md: -------------------------------------------------------------------------------- 1 | # How to Build 2 | 3 | ## Native 4 | 5 | ```shell 6 | cargo run 7 | ``` 8 | 9 | ## Web 10 | 11 | `cd` to `examples/hello` directory 12 | 13 | ```shell 14 | cargo +nightly build --target wasm32-unknown-unknown 15 | mkdir -p generated 16 | wasm-bindgen ../../target/wasm32-unknown-unknown/debug/hello.wasm --out-dir generated --no-modules 17 | cp index.html generated 18 | ``` 19 | -------------------------------------------------------------------------------- /examples/hello/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # glow 2 | 3 | GL on Whatever: a set of bindings to run GL anywhere (Open GL, OpenGL ES, and WebGL) and avoid target-specific code. 4 | 5 | This is heavily work-in-progress and should be considered experimental. 6 | 7 | ## License 8 | 9 | This project is licensed under either of [Apache License, Version 10 | 2.0](LICENSE-APACHE) or [MIT license](LICENSE-MIT), at your option. 11 | 12 | ## Contribution 13 | 14 | Unless you explicitly state otherwise, any contribution intentionally submitted 15 | for inclusion in this project by you, as defined in the Apache 2.0 license, 16 | shall be dual licensed as above, without any additional terms or conditions. 17 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "glow" 3 | version = "0.1.0" 4 | description = "GL on Whatever: a set of bindings to run GL anywhere (Open GL, OpenGL ES, and WebGL) and avoid target-specific code." 5 | authors = ["Joshua Groves "] 6 | homepage = "https://github.com/grovesNL/glow.git" 7 | license = "MIT OR Apache-2.0" 8 | build = "build.rs" 9 | edition = "2018" 10 | 11 | [lib] 12 | name = "glow" 13 | path = "src/lib.rs" 14 | 15 | [target.'cfg(not(any(target_arch = "wasm32")))'.dependencies] 16 | glutin = "0.19" 17 | 18 | [target.wasm32-unknown-unknown.dependencies] 19 | js-sys = "0.3" 20 | wasm-bindgen = "0.2" 21 | slotmap = "0.3" 22 | 23 | [target.wasm32-unknown-unknown.dependencies.web-sys] 24 | version = "0.3" 25 | features = [ 26 | "Document", 27 | "Element", 28 | "HtmlCanvasElement", 29 | "WebGlBuffer", 30 | "WebGlFramebuffer", 31 | "WebGlProgram", 32 | "WebGlRenderbuffer", 33 | "WebGlRenderingContext", 34 | "WebGl2RenderingContext", 35 | "WebGlSampler", 36 | "WebGlShader", 37 | "WebGlSync", 38 | "WebGlTexture", 39 | "WebGlUniformLocation", 40 | "WebGlVertexArrayObject", 41 | "Window", 42 | ] 43 | 44 | [build-dependencies] 45 | gl_generator = "0.9" 46 | 47 | [workspace] 48 | members = [ 49 | "examples/hello", 50 | ] 51 | -------------------------------------------------------------------------------- /examples/hello/src/main.rs: -------------------------------------------------------------------------------- 1 | use glow::{self, Context, RenderLoop}; 2 | 3 | #[cfg(target_arch = "wasm32")] 4 | use wasm_bindgen::prelude::*; 5 | 6 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen(start))] 7 | pub fn wasm_main() { 8 | main(); 9 | } 10 | 11 | fn main() { 12 | unsafe { 13 | // Create a context from a WebGL2 context on wasm32 targets 14 | #[cfg(target_arch = "wasm32")] 15 | let (_window, gl, _events_loop, render_loop, shader_version) = { 16 | use wasm_bindgen::JsCast; 17 | let canvas = web_sys::window() 18 | .unwrap() 19 | .document() 20 | .unwrap() 21 | .get_element_by_id("canvas") 22 | .unwrap() 23 | .dyn_into::() 24 | .unwrap(); 25 | let webgl2_context = canvas 26 | .get_context("webgl2") 27 | .unwrap() 28 | .unwrap() 29 | .dyn_into::() 30 | .unwrap(); 31 | ( 32 | (), 33 | glow::web::Context::from_webgl2_context(webgl2_context), 34 | (), 35 | glow::web::RenderLoop::from_request_animation_frame(), 36 | "#version 300 es", 37 | ) 38 | }; 39 | 40 | // Create a context from a glutin window on non-wasm32 targets 41 | #[cfg(not(target_arch = "wasm32"))] 42 | let (window, gl, mut events_loop, render_loop, shader_version) = { 43 | use glutin::GlContext; 44 | let events_loop = glutin::EventsLoop::new(); 45 | let window_builder = glutin::WindowBuilder::new() 46 | .with_title("Hello triangle!") 47 | .with_dimensions(glutin::dpi::LogicalSize::new(1024.0, 768.0)); 48 | let context_builder = glutin::ContextBuilder::new().with_vsync(true); 49 | let window = 50 | glutin::GlWindow::new(window_builder, context_builder, &events_loop).unwrap(); 51 | let context = glow::native::Context::from_loader_function(|s| { 52 | window.get_proc_address(s) as *const _ 53 | }); 54 | window.make_current().unwrap(); 55 | let render_loop = glow::native::RenderLoop::from_window(); 56 | (window, context, events_loop, render_loop, "#version 410") 57 | }; 58 | 59 | let vertex_array = gl 60 | .create_vertex_array() 61 | .expect("Cannot create vertex array"); 62 | gl.bind_vertex_array(Some(vertex_array)); 63 | 64 | let program = gl.create_program().expect("Cannot create program"); 65 | 66 | let (vertex_shader_source, fragment_shader_source) = ( 67 | r#"const vec2 verts[3] = vec2[3]( 68 | vec2(0.5f, 1.0f), 69 | vec2(0.0f, 0.0f), 70 | vec2(1.0f, 0.0f) 71 | ); 72 | out vec2 vert; 73 | void main() { 74 | vert = verts[gl_VertexID]; 75 | gl_Position = vec4(vert - 0.5, 0.0, 1.0); 76 | }"#, 77 | r#"precision mediump float; 78 | in vec2 vert; 79 | out vec4 color; 80 | void main() { 81 | color = vec4(vert, 0.5, 1.0); 82 | }"#, 83 | ); 84 | 85 | let shader_sources = [ 86 | (glow::VERTEX_SHADER, vertex_shader_source), 87 | (glow::FRAGMENT_SHADER, fragment_shader_source), 88 | ]; 89 | 90 | let mut shaders = Vec::with_capacity(shader_sources.len()); 91 | 92 | for (shader_type, shader_source) in shader_sources.iter() { 93 | let shader = gl 94 | .create_shader(*shader_type) 95 | .expect("Cannot create shader"); 96 | gl.shader_source(shader, &format!("{}\n{}", shader_version, shader_source)); 97 | gl.compile_shader(shader); 98 | if !gl.get_shader_compile_status(shader) { 99 | panic!(gl.get_shader_info_log(shader)); 100 | } 101 | gl.attach_shader(program, shader); 102 | shaders.push(shader); 103 | } 104 | 105 | gl.link_program(program); 106 | if !gl.get_program_link_status(program) { 107 | panic!(gl.get_program_info_log(program)); 108 | } 109 | 110 | for shader in shaders { 111 | gl.detach_shader(program, shader); 112 | gl.delete_shader(shader); 113 | } 114 | 115 | gl.use_program(Some(program)); 116 | gl.clear_color(0.1, 0.2, 0.3, 1.0); 117 | 118 | render_loop.run(move |running: &mut bool| { 119 | // Handle events differently between targets 120 | #[cfg(not(target_arch = "wasm32"))] 121 | { 122 | events_loop.poll_events(|event| match event { 123 | glutin::Event::WindowEvent { event, .. } => match event { 124 | glutin::WindowEvent::CloseRequested => *running = false, 125 | _ => (), 126 | }, 127 | _ => (), 128 | }); 129 | window.swap_buffers().unwrap(); 130 | } 131 | 132 | gl.clear(glow::COLOR_BUFFER_BIT); 133 | gl.draw_arrays(glow::TRIANGLES, 0, 3); 134 | 135 | if !*running { 136 | gl.delete_program(program); 137 | gl.delete_vertex_array(vertex_array); 138 | } 139 | }); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /src/native.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | use std::ffi::CString; 4 | use std::sync::Arc; 5 | 6 | mod native_gl { 7 | include!(concat!(env!("OUT_DIR"), "/opengl_bindings.rs")); 8 | } 9 | 10 | pub struct Context { 11 | raw: native_gl::Gl, 12 | } 13 | 14 | impl Context { 15 | pub fn from_loader_function(loader_function: F) -> Self 16 | where 17 | F: FnMut(&str) -> *const std::os::raw::c_void, 18 | { 19 | let raw = native_gl::Gl::load_with(loader_function); 20 | Context { raw } 21 | } 22 | } 23 | 24 | impl std::fmt::Debug for Context { 25 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 26 | // TODO 27 | write!(f, "TODO") 28 | } 29 | } 30 | 31 | impl super::Context for Context { 32 | type Shader = native_gl::types::GLuint; 33 | type Program = native_gl::types::GLuint; 34 | type Buffer = native_gl::types::GLuint; 35 | type VertexArray = native_gl::types::GLuint; 36 | type Texture = native_gl::types::GLuint; 37 | type Sampler = native_gl::types::GLuint; 38 | type Fence = native_gl::types::GLsync; 39 | type Framebuffer = native_gl::types::GLuint; 40 | type Renderbuffer = native_gl::types::GLuint; 41 | type UniformLocation = native_gl::types::GLuint; 42 | 43 | unsafe fn create_framebuffer(&self) -> Result { 44 | let gl = &self.raw; 45 | let mut name = 0; 46 | gl.GenFramebuffers(1, &mut name); 47 | Ok(name) 48 | } 49 | 50 | unsafe fn create_renderbuffer(&self) -> Result { 51 | let gl = &self.raw; 52 | let mut name = 0; 53 | gl.GenRenderbuffers(1, &mut name); 54 | Ok(name) 55 | } 56 | 57 | unsafe fn create_sampler(&self) -> Result { 58 | let gl = &self.raw; 59 | let mut name = 0; 60 | gl.GenSamplers(1, &mut name); 61 | Ok(name) 62 | } 63 | 64 | unsafe fn create_shader(&self, shader_type: u32) -> Result { 65 | let gl = &self.raw; 66 | Ok(gl.CreateShader(shader_type as u32)) 67 | } 68 | 69 | unsafe fn create_texture(&self) -> Result { 70 | let gl = &self.raw; 71 | let mut name = 0; 72 | gl.GenTextures(1, &mut name); 73 | Ok(name) 74 | } 75 | 76 | unsafe fn delete_shader(&self, shader: Self::Shader) { 77 | let gl = &self.raw; 78 | gl.DeleteShader(shader); 79 | } 80 | 81 | unsafe fn shader_source(&self, shader: Self::Shader, source: &str) { 82 | let gl = &self.raw; 83 | gl.ShaderSource( 84 | shader, 85 | 1, 86 | &(source.as_ptr() as *const native_gl::types::GLchar), 87 | &(source.len() as native_gl::types::GLint), 88 | ); 89 | } 90 | 91 | unsafe fn compile_shader(&self, shader: Self::Shader) { 92 | let gl = &self.raw; 93 | gl.CompileShader(shader); 94 | } 95 | 96 | unsafe fn get_shader_compile_status(&self, shader: Self::Shader) -> bool { 97 | let gl = &self.raw; 98 | let mut status = 0; 99 | gl.GetShaderiv(shader, COMPILE_STATUS, &mut status); 100 | 1 == status 101 | } 102 | 103 | unsafe fn get_shader_info_log(&self, shader: Self::Shader) -> String { 104 | let gl = &self.raw; 105 | let mut length = 0; 106 | gl.GetShaderiv(shader, INFO_LOG_LENGTH, &mut length); 107 | if length > 0 { 108 | let mut log = String::with_capacity(length as usize); 109 | log.extend(std::iter::repeat('\0').take(length as usize)); 110 | gl.GetShaderInfoLog( 111 | shader, 112 | length, 113 | &mut length, 114 | (&log[..]).as_ptr() as *mut native_gl::types::GLchar, 115 | ); 116 | log.truncate(length as usize); 117 | log 118 | } else { 119 | String::from("") 120 | } 121 | } 122 | 123 | unsafe fn get_tex_image( 124 | &self, 125 | target: u32, 126 | level: i32, 127 | format: u32, 128 | ty: u32, 129 | pixels: Option<&[u8]>, 130 | ) { 131 | let gl = &self.raw; 132 | gl.GetTexImage( 133 | target, 134 | level, 135 | format, 136 | ty, 137 | pixels.map(|p| p.as_ptr()).unwrap_or(std::ptr::null()) as *mut std::ffi::c_void, 138 | ); 139 | } 140 | 141 | unsafe fn create_program(&self) -> Result { 142 | let gl = &self.raw; 143 | Ok(gl.CreateProgram()) 144 | } 145 | 146 | unsafe fn delete_program(&self, program: Self::Program) { 147 | let gl = &self.raw; 148 | gl.DeleteProgram(program); 149 | } 150 | 151 | unsafe fn attach_shader(&self, program: Self::Program, shader: Self::Shader) { 152 | let gl = &self.raw; 153 | gl.AttachShader(program, shader); 154 | } 155 | 156 | unsafe fn detach_shader(&self, program: Self::Program, shader: Self::Shader) { 157 | let gl = &self.raw; 158 | gl.DetachShader(program, shader); 159 | } 160 | 161 | unsafe fn link_program(&self, program: Self::Program) { 162 | let gl = &self.raw; 163 | gl.LinkProgram(program); 164 | } 165 | 166 | unsafe fn get_program_link_status(&self, program: Self::Program) -> bool { 167 | let gl = &self.raw; 168 | let mut status = 0; 169 | gl.GetProgramiv(program, LINK_STATUS, &mut status); 170 | 1 == status 171 | } 172 | 173 | unsafe fn get_program_info_log(&self, program: Self::Program) -> String { 174 | let gl = &self.raw; 175 | let mut length = 0; 176 | gl.GetProgramiv(program, INFO_LOG_LENGTH, &mut length); 177 | if length > 0 { 178 | let mut log = String::with_capacity(length as usize); 179 | log.extend(std::iter::repeat('\0').take(length as usize)); 180 | gl.GetProgramInfoLog( 181 | program, 182 | length, 183 | &mut length, 184 | (&log[..]).as_ptr() as *mut native_gl::types::GLchar, 185 | ); 186 | log.truncate(length as usize); 187 | log 188 | } else { 189 | String::from("") 190 | } 191 | } 192 | 193 | unsafe fn use_program(&self, program: Option) { 194 | let gl = &self.raw; 195 | gl.UseProgram(program.unwrap_or(0)); 196 | } 197 | 198 | unsafe fn create_buffer(&self) -> Result { 199 | let gl = &self.raw; 200 | let mut buffer = 0; 201 | gl.GenBuffers(1, &mut buffer); 202 | Ok(buffer) 203 | } 204 | 205 | unsafe fn bind_buffer(&self, target: u32, buffer: Option) { 206 | let gl = &self.raw; 207 | gl.BindBuffer(target, buffer.unwrap_or(0)); 208 | } 209 | 210 | unsafe fn bind_buffer_range( 211 | &self, 212 | target: u32, 213 | index: u32, 214 | buffer: Option, 215 | offset: i32, 216 | size: i32, 217 | ) { 218 | let gl = &self.raw; 219 | gl.BindBufferRange( 220 | target, 221 | index, 222 | buffer.unwrap_or(0), 223 | offset as isize, 224 | size as isize, 225 | ); 226 | } 227 | 228 | unsafe fn bind_framebuffer(&self, target: u32, framebuffer: Option) { 229 | let gl = &self.raw; 230 | gl.BindFramebuffer(target, framebuffer.unwrap_or(0)); 231 | } 232 | 233 | unsafe fn bind_renderbuffer(&self, target: u32, renderbuffer: Option) { 234 | let gl = &self.raw; 235 | gl.BindRenderbuffer(target, renderbuffer.unwrap_or(0)); 236 | } 237 | 238 | unsafe fn create_vertex_array(&self) -> Result { 239 | let gl = &self.raw; 240 | let mut vertex_array = 0; 241 | gl.GenVertexArrays(1, &mut vertex_array); 242 | Ok(vertex_array) 243 | } 244 | 245 | unsafe fn delete_vertex_array(&self, vertex_array: Self::VertexArray) { 246 | let gl = &self.raw; 247 | gl.DeleteVertexArrays(1, &vertex_array); 248 | } 249 | 250 | unsafe fn bind_vertex_array(&self, vertex_array: Option) { 251 | let gl = &self.raw; 252 | gl.BindVertexArray(vertex_array.unwrap_or(0)); 253 | } 254 | 255 | unsafe fn clear_color(&self, red: f32, green: f32, blue: f32, alpha: f32) { 256 | let gl = &self.raw; 257 | gl.ClearColor(red, green, blue, alpha); 258 | } 259 | 260 | unsafe fn supports_f64_precision() -> bool { 261 | // TODO: Handle OpenGL ES 262 | true 263 | } 264 | 265 | unsafe fn clear_depth_f64(&self, depth: f64) { 266 | let gl = &self.raw; 267 | gl.ClearDepth(depth); 268 | } 269 | 270 | unsafe fn clear_depth_f32(&self, depth: f32) { 271 | let gl = &self.raw; 272 | gl.ClearDepthf(depth); 273 | } 274 | 275 | unsafe fn clear_stencil(&self, stencil: i32) { 276 | let gl = &self.raw; 277 | gl.ClearStencil(stencil); 278 | } 279 | 280 | unsafe fn clear(&self, mask: u32) { 281 | let gl = &self.raw; 282 | gl.Clear(mask); 283 | } 284 | 285 | unsafe fn patch_parameter_i32(&self, parameter: u32, value: i32) { 286 | let gl = &self.raw; 287 | gl.PatchParameteri(parameter, value); 288 | } 289 | 290 | unsafe fn pixel_store_i32(&self, parameter: u32, value: i32) { 291 | let gl = &self.raw; 292 | gl.PixelStorei(parameter, value); 293 | } 294 | 295 | unsafe fn pixel_store_bool(&self, parameter: u32, value: bool) { 296 | let gl = &self.raw; 297 | gl.PixelStorei(parameter, value as i32); 298 | } 299 | 300 | unsafe fn bind_frag_data_location( 301 | &self, 302 | program: Self::Program, 303 | color_number: u32, 304 | name: &str, 305 | ) { 306 | let gl = &self.raw; 307 | gl.BindFragDataLocation(program, color_number, name.as_ptr() as *const i8); 308 | } 309 | 310 | unsafe fn buffer_data_size(&self, target: u32, size: i32, usage: u32) { 311 | let gl = &self.raw; 312 | gl.BufferData(target, size as isize, std::ptr::null(), usage); 313 | } 314 | 315 | unsafe fn buffer_data_u8_slice(&self, target: u32, data: &[u8], usage: u32) { 316 | let gl = &self.raw; 317 | gl.BufferData( 318 | target, 319 | data.len() as isize, 320 | data.as_ptr() as *const std::ffi::c_void, 321 | usage, 322 | ); 323 | } 324 | 325 | unsafe fn buffer_storage(&self, target: u32, size: i32, data: Option<&mut [u8]>, flags: u32) { 326 | let gl = &self.raw; 327 | gl.BufferStorage( 328 | target, 329 | size as isize, 330 | data.map(|p| p.as_ptr()).unwrap_or(std::ptr::null()) as *const std::ffi::c_void, 331 | flags, 332 | ); 333 | } 334 | 335 | unsafe fn check_framebuffer_status(&self, target: u32) -> u32 { 336 | let gl = &self.raw; 337 | gl.CheckFramebufferStatus(target) 338 | } 339 | 340 | unsafe fn clear_buffer_i32_slice(&self, target: u32, draw_buffer: u32, values: &mut [i32]) { 341 | let gl = &self.raw; 342 | gl.ClearBufferiv(target, draw_buffer as i32, values.as_ptr()); 343 | } 344 | 345 | unsafe fn clear_buffer_u32_slice(&self, target: u32, draw_buffer: u32, values: &mut [u32]) { 346 | let gl = &self.raw; 347 | gl.ClearBufferuiv(target, draw_buffer as i32, values.as_ptr()); 348 | } 349 | 350 | unsafe fn clear_buffer_f32_slice(&self, target: u32, draw_buffer: u32, values: &mut [f32]) { 351 | let gl = &self.raw; 352 | gl.ClearBufferfv(target, draw_buffer as i32, values.as_ptr()); 353 | } 354 | 355 | unsafe fn clear_buffer_depth_stencil( 356 | &self, 357 | target: u32, 358 | draw_buffer: u32, 359 | depth: f32, 360 | stencil: i32, 361 | ) { 362 | let gl = &self.raw; 363 | gl.ClearBufferfi(target, draw_buffer as i32, depth, stencil); 364 | } 365 | 366 | unsafe fn client_wait_sync(&self, fence: Self::Fence, flags: u32, timeout: i32) -> u32 { 367 | let gl = &self.raw; 368 | gl.ClientWaitSync(fence, flags, timeout as u64) 369 | } 370 | 371 | unsafe fn copy_buffer_sub_data( 372 | &self, 373 | src_target: u32, 374 | dst_target: u32, 375 | src_offset: i32, 376 | dst_offset: i32, 377 | size: i32, 378 | ) { 379 | let gl = &self.raw; 380 | gl.CopyBufferSubData( 381 | src_target, 382 | dst_target, 383 | src_offset as isize, 384 | dst_offset as isize, 385 | size as isize, 386 | ); 387 | } 388 | 389 | unsafe fn delete_buffer(&self, buffer: Self::Buffer) { 390 | let gl = &self.raw; 391 | gl.DeleteBuffers(1, &buffer); 392 | } 393 | 394 | unsafe fn delete_framebuffer(&self, framebuffer: Self::Framebuffer) { 395 | let gl = &self.raw; 396 | gl.DeleteFramebuffers(1, &framebuffer); 397 | } 398 | 399 | unsafe fn delete_renderbuffer(&self, renderbuffer: Self::Renderbuffer) { 400 | let gl = &self.raw; 401 | gl.DeleteRenderbuffers(1, &renderbuffer); 402 | } 403 | 404 | unsafe fn delete_sampler(&self, sampler: Self::Sampler) { 405 | let gl = &self.raw; 406 | gl.DeleteSamplers(1, &sampler); 407 | } 408 | 409 | unsafe fn delete_sync(&self, fence: Self::Fence) { 410 | let gl = &self.raw; 411 | gl.DeleteSync(fence); 412 | } 413 | 414 | unsafe fn delete_texture(&self, texture: Self::Texture) { 415 | let gl = &self.raw; 416 | gl.DeleteTextures(1, &texture); 417 | } 418 | 419 | unsafe fn disable(&self, parameter: u32) { 420 | let gl = &self.raw; 421 | gl.Disable(parameter); 422 | } 423 | 424 | unsafe fn disable_draw_buffer(&self, parameter: u32, draw_buffer: u32) { 425 | let gl = &self.raw; 426 | gl.Disablei(draw_buffer, parameter); 427 | } 428 | 429 | unsafe fn disable_vertex_attrib_array(&self, index: u32) { 430 | let gl = &self.raw; 431 | gl.DisableVertexAttribArray(index); 432 | } 433 | 434 | unsafe fn dispatch_compute(&self, groups_x: u32, groups_y: u32, groups_z: u32) { 435 | let gl = &self.raw; 436 | gl.DispatchCompute(groups_x, groups_y, groups_z); 437 | } 438 | 439 | unsafe fn dispatch_compute_indirect(&self, offset: i32) { 440 | let gl = &self.raw; 441 | gl.DispatchComputeIndirect(offset as isize); 442 | } 443 | 444 | unsafe fn draw_arrays(&self, mode: u32, first: i32, count: i32) { 445 | let gl = &self.raw; 446 | gl.DrawArrays(mode as u32, first, count); 447 | } 448 | 449 | unsafe fn draw_arrays_instanced(&self, mode: u32, first: i32, count: i32, instance_count: i32) { 450 | let gl = &self.raw; 451 | gl.DrawArraysInstanced(mode as u32, first, count, instance_count); 452 | } 453 | 454 | unsafe fn draw_arrays_instanced_base_instance( 455 | &self, 456 | mode: u32, 457 | first: i32, 458 | count: i32, 459 | instance_count: i32, 460 | base_instance: u32, 461 | ) { 462 | let gl = &self.raw; 463 | gl.DrawArraysInstancedBaseInstance( 464 | mode as u32, 465 | first, 466 | count, 467 | instance_count, 468 | base_instance, 469 | ); 470 | } 471 | 472 | unsafe fn draw_buffer(&self, draw_buffer: u32) { 473 | let gl = &self.raw; 474 | gl.DrawBuffer(draw_buffer); 475 | } 476 | 477 | unsafe fn draw_buffers(&self, buffers: &[u32]) { 478 | let gl = &self.raw; 479 | gl.DrawBuffers(buffers.len() as i32, buffers.as_ptr()); 480 | } 481 | 482 | unsafe fn draw_elements(&self, mode: u32, count: i32, element_type: u32, offset: i32) { 483 | let gl = &self.raw; 484 | gl.DrawElements( 485 | mode as u32, 486 | count, 487 | element_type as u32, 488 | offset as *const std::ffi::c_void, 489 | ); 490 | } 491 | 492 | unsafe fn draw_elements_base_vertex( 493 | &self, 494 | mode: u32, 495 | count: i32, 496 | element_type: u32, 497 | offset: i32, 498 | base_vertex: i32, 499 | ) { 500 | let gl = &self.raw; 501 | gl.DrawElementsBaseVertex( 502 | mode as u32, 503 | count, 504 | element_type as u32, 505 | offset as *const std::ffi::c_void, 506 | base_vertex, 507 | ); 508 | } 509 | 510 | unsafe fn draw_elements_instanced( 511 | &self, 512 | mode: u32, 513 | count: i32, 514 | element_type: u32, 515 | offset: i32, 516 | instance_count: i32, 517 | ) { 518 | let gl = &self.raw; 519 | gl.DrawElementsInstanced( 520 | mode as u32, 521 | count, 522 | element_type as u32, 523 | offset as *const std::ffi::c_void, 524 | instance_count, 525 | ); 526 | } 527 | 528 | unsafe fn draw_elements_instanced_base_vertex( 529 | &self, 530 | mode: u32, 531 | count: i32, 532 | element_type: u32, 533 | offset: i32, 534 | instance_count: i32, 535 | base_vertex: i32, 536 | ) { 537 | let gl = &self.raw; 538 | gl.DrawElementsInstancedBaseVertex( 539 | mode as u32, 540 | count, 541 | element_type as u32, 542 | offset as *const std::ffi::c_void, 543 | instance_count, 544 | base_vertex, 545 | ); 546 | } 547 | 548 | unsafe fn draw_elements_instanced_base_vertex_base_instance( 549 | &self, 550 | mode: u32, 551 | count: i32, 552 | element_type: u32, 553 | offset: i32, 554 | instance_count: i32, 555 | base_vertex: i32, 556 | base_instance: u32, 557 | ) { 558 | let gl = &self.raw; 559 | gl.DrawElementsInstancedBaseVertexBaseInstance( 560 | mode as u32, 561 | count, 562 | element_type as u32, 563 | offset as *const std::ffi::c_void, 564 | instance_count, 565 | base_vertex, 566 | base_instance, 567 | ); 568 | } 569 | 570 | unsafe fn enable(&self, parameter: u32) { 571 | let gl = &self.raw; 572 | gl.Enable(parameter); 573 | } 574 | 575 | unsafe fn enable_draw_buffer(&self, parameter: u32, draw_buffer: u32) { 576 | let gl = &self.raw; 577 | gl.Enablei(parameter, draw_buffer); 578 | } 579 | 580 | unsafe fn enable_vertex_attrib_array(&self, index: u32) { 581 | let gl = &self.raw; 582 | gl.EnableVertexAttribArray(index); 583 | } 584 | 585 | unsafe fn flush(&self) { 586 | let gl = &self.raw; 587 | gl.Flush(); 588 | } 589 | 590 | unsafe fn framebuffer_renderbuffer( 591 | &self, 592 | target: u32, 593 | attachment: u32, 594 | renderbuffer_target: u32, 595 | renderbuffer: Option, 596 | ) { 597 | let gl = &self.raw; 598 | gl.FramebufferRenderbuffer( 599 | target, 600 | attachment, 601 | renderbuffer_target, 602 | renderbuffer.unwrap_or(0), 603 | ); 604 | } 605 | 606 | unsafe fn framebuffer_texture( 607 | &self, 608 | target: u32, 609 | attachment: u32, 610 | texture: Option, 611 | level: i32, 612 | ) { 613 | let gl = &self.raw; 614 | gl.FramebufferTexture(target, attachment, texture.unwrap_or(0), level); 615 | } 616 | 617 | unsafe fn framebuffer_texture_2d( 618 | &self, 619 | target: u32, 620 | attachment: u32, 621 | texture_target: u32, 622 | texture: Option, 623 | level: i32, 624 | ) { 625 | let gl = &self.raw; 626 | gl.FramebufferTexture2D( 627 | target, 628 | attachment, 629 | texture_target, 630 | texture.unwrap_or(0), 631 | level, 632 | ); 633 | } 634 | 635 | unsafe fn framebuffer_texture_3d( 636 | &self, 637 | target: u32, 638 | attachment: u32, 639 | texture_target: u32, 640 | texture: Option, 641 | level: i32, 642 | layer: i32, 643 | ) { 644 | let gl = &self.raw; 645 | gl.FramebufferTexture3D( 646 | target, 647 | attachment, 648 | texture_target, 649 | texture.unwrap_or(0), 650 | level, 651 | layer, 652 | ); 653 | } 654 | 655 | unsafe fn framebuffer_texture_layer( 656 | &self, 657 | target: u32, 658 | attachment: u32, 659 | texture: Option, 660 | level: i32, 661 | layer: i32, 662 | ) { 663 | let gl = &self.raw; 664 | gl.FramebufferTextureLayer(target, attachment, texture.unwrap_or(0), level, layer); 665 | } 666 | 667 | unsafe fn front_face(&self, value: u32) { 668 | let gl = &self.raw; 669 | gl.FrontFace(value as u32); 670 | } 671 | 672 | unsafe fn get_error(&self) -> u32 { 673 | let gl = &self.raw; 674 | gl.GetError() 675 | } 676 | 677 | unsafe fn get_parameter_i32(&self, parameter: u32) -> i32 { 678 | let gl = &self.raw; 679 | let mut value = 0; 680 | gl.GetIntegerv(parameter, &mut value); 681 | value 682 | } 683 | 684 | unsafe fn get_parameter_indexed_i32(&self, parameter: u32, index: u32) -> i32 { 685 | let gl = &self.raw; 686 | let mut value = 0; 687 | gl.GetIntegeri_v(parameter, index, &mut value); 688 | value 689 | } 690 | 691 | unsafe fn get_parameter_indexed_string(&self, parameter: u32, index: u32) -> String { 692 | let gl = &self.raw; 693 | let raw_ptr = gl.GetStringi(parameter, index); 694 | std::ffi::CStr::from_ptr(raw_ptr as *const i8) 695 | .to_str() 696 | .unwrap() 697 | .to_owned() 698 | } 699 | 700 | unsafe fn get_parameter_string(&self, parameter: u32) -> String { 701 | let gl = &self.raw; 702 | let raw_ptr = gl.GetString(parameter); 703 | std::ffi::CStr::from_ptr(raw_ptr as *const i8) 704 | .to_str() 705 | .unwrap() 706 | .to_owned() 707 | } 708 | 709 | unsafe fn get_uniform_location( 710 | &self, 711 | program: Self::Program, 712 | name: &str, 713 | ) -> Option { 714 | let gl = &self.raw; 715 | let name = CString::new(name).unwrap(); 716 | Some(gl.GetUniformLocation(program, name.as_ptr() as *const i8) as u32) 717 | } 718 | 719 | unsafe fn get_attrib_location( 720 | &self, 721 | program: Self::Program, 722 | name: &str 723 | ) -> i32 { 724 | let gl = &self.raw; 725 | let name = CString::new(name).unwrap(); 726 | gl.GetAttribLocation(program, name.as_ptr() as *const i8) as i32 727 | } 728 | 729 | unsafe fn is_sync(&self, fence: Self::Fence) -> bool { 730 | let gl = &self.raw; 731 | 1 == gl.IsSync(fence) 732 | } 733 | 734 | unsafe fn renderbuffer_storage( 735 | &self, 736 | target: u32, 737 | internal_format: u32, 738 | width: i32, 739 | height: i32, 740 | ) { 741 | let gl = &self.raw; 742 | gl.RenderbufferStorage(target, internal_format, width, height); 743 | } 744 | 745 | unsafe fn sampler_parameter_f32(&self, sampler: Self::Sampler, name: u32, value: f32) { 746 | let gl = &self.raw; 747 | gl.SamplerParameterf(sampler, name, value); 748 | } 749 | 750 | unsafe fn sampler_parameter_f32_slice( 751 | &self, 752 | sampler: Self::Sampler, 753 | name: u32, 754 | value: &mut [f32], 755 | ) { 756 | let gl = &self.raw; 757 | gl.SamplerParameterfv(sampler, name, value.as_ptr()); 758 | } 759 | 760 | unsafe fn sampler_parameter_i32(&self, sampler: Self::Sampler, name: u32, value: i32) { 761 | let gl = &self.raw; 762 | gl.SamplerParameteri(sampler, name, value); 763 | } 764 | 765 | unsafe fn tex_image_2d( 766 | &self, 767 | target: u32, 768 | level: i32, 769 | internal_format: i32, 770 | width: i32, 771 | height: i32, 772 | border: i32, 773 | format: u32, 774 | ty: u32, 775 | pixels: Option<&[u8]>, 776 | ) { 777 | let gl = &self.raw; 778 | gl.TexImage2D( 779 | target, 780 | level, 781 | internal_format, 782 | width, 783 | height, 784 | border, 785 | format, 786 | ty, 787 | pixels.map(|p| p.as_ptr()).unwrap_or(std::ptr::null()) as *const std::ffi::c_void, 788 | ); 789 | } 790 | 791 | unsafe fn tex_storage_2d( 792 | &self, 793 | target: u32, 794 | levels: i32, 795 | internal_format: u32, 796 | width: i32, 797 | height: i32, 798 | ) { 799 | let gl = &self.raw; 800 | gl.TexStorage2D(target, levels, internal_format, width, height); 801 | } 802 | 803 | unsafe fn uniform_1_i32(&self, location: Option, x: i32) { 804 | let gl = &self.raw; 805 | gl.Uniform1i(location.unwrap_or(0) as i32, x); 806 | } 807 | 808 | unsafe fn uniform_2_i32(&self, location: Option, x: i32, y: i32) { 809 | let gl = &self.raw; 810 | gl.Uniform2i(location.unwrap_or(0) as i32, x, y); 811 | } 812 | 813 | unsafe fn uniform_3_i32(&self, location: Option, x: i32, y: i32, z: i32) { 814 | let gl = &self.raw; 815 | gl.Uniform3i(location.unwrap_or(0) as i32, x, y, z); 816 | } 817 | 818 | unsafe fn uniform_4_i32(&self, location: Option, x: i32, y: i32, z: i32, w: i32) { 819 | let gl = &self.raw; 820 | gl.Uniform4i(location.unwrap_or(0) as i32, x, y, z, w); 821 | } 822 | 823 | unsafe fn uniform_1_i32_slice(&self, location: Option, v: &mut [i32; 1]) { 824 | let gl = &self.raw; 825 | gl.Uniform1iv(location.unwrap_or(0) as i32, 1, v.as_ptr()); 826 | } 827 | 828 | unsafe fn uniform_2_i32_slice(&self, location: Option, v: &mut [i32; 2]) { 829 | let gl = &self.raw; 830 | gl.Uniform2iv(location.unwrap_or(0) as i32, 1, v.as_ptr()); 831 | } 832 | 833 | unsafe fn uniform_3_i32_slice(&self, location: Option, v: &mut [i32; 3]) { 834 | let gl = &self.raw; 835 | gl.Uniform3iv(location.unwrap_or(0) as i32, 1, v.as_ptr()); 836 | } 837 | 838 | unsafe fn uniform_4_i32_slice(&self, location: Option, v: &mut [i32; 4]) { 839 | let gl = &self.raw; 840 | gl.Uniform4iv(location.unwrap_or(0) as i32, 1, v.as_ptr()); 841 | } 842 | 843 | unsafe fn uniform_1_f32(&self, location: Option, x: f32) { 844 | let gl = &self.raw; 845 | gl.Uniform1f(location.unwrap_or(0) as i32, x); 846 | } 847 | 848 | unsafe fn uniform_2_f32(&self, location: Option, x: f32, y: f32) { 849 | let gl = &self.raw; 850 | gl.Uniform2f(location.unwrap_or(0) as i32, x, y); 851 | } 852 | 853 | unsafe fn uniform_3_f32(&self, location: Option, x: f32, y: f32, z: f32) { 854 | let gl = &self.raw; 855 | gl.Uniform3f(location.unwrap_or(0) as i32, x, y, z); 856 | } 857 | 858 | unsafe fn uniform_4_f32(&self, location: Option, x: f32, y: f32, z: f32, w: f32) { 859 | let gl = &self.raw; 860 | gl.Uniform4f(location.unwrap_or(0) as i32, x, y, z, w); 861 | } 862 | 863 | unsafe fn uniform_1_f32_slice(&self, location: Option, v: &[f32; 1]) { 864 | let gl = &self.raw; 865 | gl.Uniform1fv(location.unwrap_or(0) as i32, 1, v.as_ptr()); 866 | } 867 | 868 | unsafe fn uniform_2_f32_slice(&self, location: Option, v: &[f32; 2]) { 869 | let gl = &self.raw; 870 | gl.Uniform2fv(location.unwrap_or(0) as i32, 1, v.as_ptr()); 871 | } 872 | 873 | unsafe fn uniform_3_f32_slice(&self, location: Option, v: &[f32; 3]) { 874 | let gl = &self.raw; 875 | gl.Uniform3fv(location.unwrap_or(0) as i32, 1, v.as_ptr()); 876 | } 877 | 878 | unsafe fn uniform_4_f32_slice(&self, location: Option, v: &[f32; 4]) { 879 | let gl = &self.raw; 880 | gl.Uniform4fv(location.unwrap_or(0) as i32, 1, v.as_ptr()); 881 | } 882 | 883 | unsafe fn uniform_matrix_2_f32_slice(&self, location: Option, transpose: bool, v: &[f32; 4]) { 884 | let gl = &self.raw; 885 | gl.UniformMatrix2fv(location.unwrap_or(0) as i32, 1, transpose as u8, v.as_ptr()); 886 | } 887 | 888 | unsafe fn uniform_matrix_3_f32_slice(&self, location: Option, transpose: bool, v: &[f32; 9]) { 889 | let gl = &self.raw; 890 | gl.UniformMatrix3fv(location.unwrap_or(0) as i32, 1, transpose as u8, v.as_ptr()); 891 | } 892 | 893 | unsafe fn uniform_matrix_4_f32_slice(&self, location: Option, transpose: bool, v: &[f32; 16]) { 894 | let gl = &self.raw; 895 | gl.UniformMatrix4fv(location.unwrap_or(0) as i32, 1, transpose as u8, v.as_ptr()); 896 | } 897 | 898 | unsafe fn unmap_buffer(&self, target: u32) { 899 | let gl = &self.raw; 900 | gl.UnmapBuffer(target); 901 | } 902 | 903 | unsafe fn cull_face(&self, value: u32) { 904 | let gl = &self.raw; 905 | gl.CullFace(value as u32); 906 | } 907 | 908 | unsafe fn color_mask(&self, red: bool, green: bool, blue: bool, alpha: bool) { 909 | let gl = &self.raw; 910 | gl.ColorMask(red as u8, green as u8, blue as u8, alpha as u8); 911 | } 912 | 913 | unsafe fn color_mask_draw_buffer( 914 | &self, 915 | draw_buffer: u32, 916 | red: bool, 917 | green: bool, 918 | blue: bool, 919 | alpha: bool, 920 | ) { 921 | let gl = &self.raw; 922 | gl.ColorMaski(draw_buffer, red as u8, green as u8, blue as u8, alpha as u8); 923 | } 924 | 925 | unsafe fn depth_mask(&self, value: bool) { 926 | let gl = &self.raw; 927 | gl.DepthMask(value as u8); 928 | } 929 | 930 | unsafe fn blend_color(&self, red: f32, green: f32, blue: f32, alpha: f32) { 931 | let gl = &self.raw; 932 | gl.BlendColor(red, green, blue, alpha); 933 | } 934 | 935 | unsafe fn line_width(&self, width: f32) { 936 | let gl = &self.raw; 937 | gl.LineWidth(width); 938 | } 939 | 940 | unsafe fn map_buffer_range( 941 | &self, 942 | target: u32, 943 | offset: i32, 944 | length: i32, 945 | access: u32, 946 | ) -> *mut u8 { 947 | let gl = &self.raw; 948 | gl.MapBufferRange(target, offset as isize, length as isize, access) as *mut u8 949 | } 950 | 951 | unsafe fn polygon_offset(&self, factor: f32, units: f32) { 952 | let gl = &self.raw; 953 | gl.PolygonOffset(factor, units); 954 | } 955 | 956 | unsafe fn polygon_mode(&self, face: u32, mode: u32) { 957 | let gl = &self.raw; 958 | gl.PolygonMode(face as u32, mode as u32); 959 | } 960 | 961 | unsafe fn finish(&self) { 962 | let gl = &self.raw; 963 | gl.Finish(); 964 | } 965 | 966 | unsafe fn bind_texture(&self, target: u32, texture: Option) { 967 | let gl = &self.raw; 968 | gl.BindTexture(target, texture.unwrap_or(0)); 969 | } 970 | 971 | unsafe fn bind_sampler(&self, unit: u32, sampler: Option) { 972 | let gl = &self.raw; 973 | gl.BindSampler(unit, sampler.unwrap_or(0)); 974 | } 975 | 976 | unsafe fn active_texture(&self, unit: u32) { 977 | let gl = &self.raw; 978 | gl.ActiveTexture(unit); 979 | } 980 | 981 | unsafe fn fence_sync(&self, condition: u32, flags: u32) -> Result { 982 | let gl = &self.raw; 983 | Ok(gl.FenceSync(condition as u32, flags)) 984 | } 985 | 986 | unsafe fn tex_parameter_f32(&self, target: u32, parameter: u32, value: f32) { 987 | let gl = &self.raw; 988 | gl.TexParameterf(target, parameter, value); 989 | } 990 | 991 | unsafe fn tex_parameter_i32(&self, target: u32, parameter: u32, value: i32) { 992 | let gl = &self.raw; 993 | gl.TexParameteri(target, parameter, value); 994 | } 995 | 996 | unsafe fn tex_parameter_f32_slice(&self, target: u32, parameter: u32, values: &[f32]) { 997 | let gl = &self.raw; 998 | gl.TexParameterfv(target, parameter, values.as_ptr()); 999 | } 1000 | 1001 | unsafe fn tex_parameter_i32_slice(&self, target: u32, parameter: u32, values: &[i32]) { 1002 | let gl = &self.raw; 1003 | gl.TexParameteriv(target, parameter, values.as_ptr()); 1004 | } 1005 | 1006 | unsafe fn tex_sub_image_2d_u8_slice( 1007 | &self, 1008 | target: u32, 1009 | level: i32, 1010 | x_offset: i32, 1011 | y_offset: i32, 1012 | width: i32, 1013 | height: i32, 1014 | format: u32, 1015 | ty: u32, 1016 | pixels: Option<&[u8]>, 1017 | ) { 1018 | let gl = &self.raw; 1019 | gl.TexSubImage2D( 1020 | target, 1021 | level, 1022 | x_offset, 1023 | y_offset, 1024 | width, 1025 | height, 1026 | format, 1027 | ty, 1028 | pixels.map(|p| p.as_ptr()).unwrap_or(std::ptr::null()) as *const std::ffi::c_void, 1029 | ); 1030 | } 1031 | 1032 | unsafe fn tex_sub_image_2d_pixel_buffer_offset( 1033 | &self, 1034 | target: u32, 1035 | level: i32, 1036 | x_offset: i32, 1037 | y_offset: i32, 1038 | width: i32, 1039 | height: i32, 1040 | format: u32, 1041 | ty: u32, 1042 | pixel_buffer_offset: i32, 1043 | ) { 1044 | let gl = &self.raw; 1045 | gl.TexSubImage2D( 1046 | target, 1047 | level, 1048 | x_offset, 1049 | y_offset, 1050 | width, 1051 | height, 1052 | format, 1053 | ty, 1054 | pixel_buffer_offset as *const std::ffi::c_void, 1055 | ); 1056 | } 1057 | 1058 | unsafe fn depth_func(&self, func: u32) { 1059 | let gl = &self.raw; 1060 | gl.DepthFunc(func as u32); 1061 | } 1062 | 1063 | unsafe fn depth_range_f32(&self, near: f32, far: f32) { 1064 | let gl = &self.raw; 1065 | gl.DepthRangef(near, far); 1066 | } 1067 | 1068 | unsafe fn depth_range_f64(&self, near: f64, far: f64) { 1069 | let gl = &self.raw; 1070 | gl.DepthRange(near, far); 1071 | } 1072 | 1073 | unsafe fn depth_range_f64_slice(&self, first: u32, count: i32, values: &[[f64; 2]]) { 1074 | let gl = &self.raw; 1075 | gl.DepthRangeArrayv(first, count, values.as_ptr() as *const f64); 1076 | } 1077 | 1078 | unsafe fn scissor(&self, x: i32, y: i32, width: i32, height: i32) { 1079 | let gl = &self.raw; 1080 | gl.Scissor(x, y, width, height); 1081 | } 1082 | 1083 | unsafe fn scissor_slice(&self, first: u32, count: i32, scissors: &[[i32; 4]]) { 1084 | let gl = &self.raw; 1085 | gl.ScissorArrayv(first, count, scissors.as_ptr() as *const i32); 1086 | } 1087 | 1088 | unsafe fn vertex_attrib_divisor(&self, index: u32, divisor: u32) { 1089 | let gl = &self.raw; 1090 | gl.VertexAttribDivisor(index, divisor); 1091 | } 1092 | 1093 | unsafe fn vertex_attrib_pointer_f32( 1094 | &self, 1095 | index: u32, 1096 | size: i32, 1097 | data_type: u32, 1098 | normalized: bool, 1099 | stride: i32, 1100 | offset: i32, 1101 | ) { 1102 | let gl = &self.raw; 1103 | gl.VertexAttribPointer( 1104 | index, 1105 | size, 1106 | data_type, 1107 | normalized as u8, 1108 | stride, 1109 | offset as *const std::ffi::c_void, 1110 | ); 1111 | } 1112 | 1113 | unsafe fn vertex_attrib_pointer_i32( 1114 | &self, 1115 | index: u32, 1116 | size: i32, 1117 | data_type: u32, 1118 | stride: i32, 1119 | offset: i32, 1120 | ) { 1121 | let gl = &self.raw; 1122 | gl.VertexAttribIPointer( 1123 | index, 1124 | size, 1125 | data_type, 1126 | stride, 1127 | offset as *const std::ffi::c_void, 1128 | ); 1129 | } 1130 | 1131 | unsafe fn vertex_attrib_pointer_f64( 1132 | &self, 1133 | index: u32, 1134 | size: i32, 1135 | data_type: u32, 1136 | stride: i32, 1137 | offset: i32, 1138 | ) { 1139 | let gl = &self.raw; 1140 | gl.VertexAttribLPointer( 1141 | index, 1142 | size, 1143 | data_type, 1144 | stride, 1145 | offset as *const std::ffi::c_void, 1146 | ); 1147 | } 1148 | 1149 | unsafe fn viewport(&self, x: i32, y: i32, width: i32, height: i32) { 1150 | let gl = &self.raw; 1151 | gl.Viewport(x, y, width, height); 1152 | } 1153 | 1154 | unsafe fn viewport_f32_slice(&self, first: u32, count: i32, values: &[[f32; 4]]) { 1155 | let gl = &self.raw; 1156 | gl.ViewportArrayv(first, count, values.as_ptr() as *const f32); 1157 | } 1158 | 1159 | unsafe fn blend_equation(&self, mode: u32) { 1160 | let gl = &self.raw; 1161 | gl.BlendEquation(mode as u32); 1162 | } 1163 | 1164 | unsafe fn blend_equation_draw_buffer(&self, draw_buffer: u32, mode: u32) { 1165 | let gl = &self.raw; 1166 | gl.BlendEquationi(draw_buffer, mode as u32); 1167 | } 1168 | 1169 | unsafe fn blend_equation_separate(&self, mode_rgb: u32, mode_alpha: u32) { 1170 | let gl = &self.raw; 1171 | gl.BlendEquationSeparate(mode_rgb as u32, mode_alpha as u32); 1172 | } 1173 | 1174 | unsafe fn blend_equation_separate_draw_buffer( 1175 | &self, 1176 | draw_buffer: u32, 1177 | mode_rgb: u32, 1178 | mode_alpha: u32, 1179 | ) { 1180 | let gl = &self.raw; 1181 | gl.BlendEquationSeparatei(draw_buffer, mode_rgb as u32, mode_alpha as u32); 1182 | } 1183 | 1184 | unsafe fn blend_func(&self, src: u32, dst: u32) { 1185 | let gl = &self.raw; 1186 | gl.BlendFunc(src as u32, dst as u32); 1187 | } 1188 | 1189 | unsafe fn blend_func_draw_buffer(&self, draw_buffer: u32, src: u32, dst: u32) { 1190 | let gl = &self.raw; 1191 | gl.BlendFunci(draw_buffer, src as u32, dst as u32); 1192 | } 1193 | 1194 | unsafe fn blend_func_separate( 1195 | &self, 1196 | src_rgb: u32, 1197 | dst_rgb: u32, 1198 | src_alpha: u32, 1199 | dst_alpha: u32, 1200 | ) { 1201 | let gl = &self.raw; 1202 | gl.BlendFuncSeparate( 1203 | src_rgb as u32, 1204 | dst_rgb as u32, 1205 | src_alpha as u32, 1206 | dst_alpha as u32, 1207 | ); 1208 | } 1209 | 1210 | unsafe fn blend_func_separate_draw_buffer( 1211 | &self, 1212 | draw_buffer: u32, 1213 | src_rgb: u32, 1214 | dst_rgb: u32, 1215 | src_alpha: u32, 1216 | dst_alpha: u32, 1217 | ) { 1218 | let gl = &self.raw; 1219 | gl.BlendFuncSeparatei( 1220 | draw_buffer, 1221 | src_rgb as u32, 1222 | dst_rgb as u32, 1223 | src_alpha as u32, 1224 | dst_alpha as u32, 1225 | ); 1226 | } 1227 | 1228 | unsafe fn stencil_func(&self, func: u32, reference: i32, mask: u32) { 1229 | let gl = &self.raw; 1230 | gl.StencilFunc(func as u32, reference, mask); 1231 | } 1232 | 1233 | unsafe fn stencil_func_separate(&self, face: u32, func: u32, reference: i32, mask: u32) { 1234 | let gl = &self.raw; 1235 | gl.StencilFuncSeparate(face as u32, func as u32, reference, mask); 1236 | } 1237 | 1238 | unsafe fn stencil_mask(&self, mask: u32) { 1239 | let gl = &self.raw; 1240 | gl.StencilMask(mask); 1241 | } 1242 | 1243 | unsafe fn stencil_mask_separate(&self, face: u32, mask: u32) { 1244 | let gl = &self.raw; 1245 | gl.StencilMaskSeparate(face as u32, mask); 1246 | } 1247 | 1248 | unsafe fn stencil_op(&self, stencil_fail: u32, depth_fail: u32, pass: u32) { 1249 | let gl = &self.raw; 1250 | gl.StencilOp(stencil_fail as u32, depth_fail as u32, pass as u32); 1251 | } 1252 | 1253 | unsafe fn stencil_op_separate(&self, face: u32, stencil_fail: u32, depth_fail: u32, pass: u32) { 1254 | let gl = &self.raw; 1255 | gl.StencilOpSeparate( 1256 | face as u32, 1257 | stencil_fail as u32, 1258 | depth_fail as u32, 1259 | pass as u32, 1260 | ); 1261 | } 1262 | } 1263 | 1264 | pub struct RenderLoop; 1265 | 1266 | impl RenderLoop { 1267 | pub fn from_window() -> Self { 1268 | RenderLoop 1269 | } 1270 | } 1271 | 1272 | impl super::RenderLoop for RenderLoop { 1273 | type Window = Arc; 1274 | 1275 | fn run(&self, mut callback: F) { 1276 | let mut running = true; 1277 | while running { 1278 | callback(&mut running); 1279 | } 1280 | } 1281 | } 1282 | -------------------------------------------------------------------------------- /src/web.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | use slotmap::{new_key_type, SecondaryMap, SlotMap}; 4 | use std::cell::RefCell; 5 | use wasm_bindgen::prelude::*; 6 | use web_sys::{ 7 | WebGl2RenderingContext, WebGlBuffer, WebGlFramebuffer, WebGlProgram, WebGlRenderbuffer, 8 | WebGlRenderingContext, WebGlSampler, WebGlShader, WebGlSync, WebGlTexture, 9 | WebGlUniformLocation, WebGlVertexArrayObject, 10 | }; 11 | 12 | #[derive(Debug)] 13 | enum RawRenderingContext { 14 | WebGl1(WebGlRenderingContext), 15 | WebGl2(WebGl2RenderingContext), 16 | } 17 | 18 | // Workaround for stable Rust 19 | // See https://github.com/orlp/slotmap/blob/b5df4ac7ee8aa795668bf79ebf8929d2f39bec8e/src/lib.rs#L198 20 | type SlotMapWithoutCopy = (SlotMap, SecondaryMap); 21 | 22 | type TrackedResource = RefCell>; 23 | 24 | fn tracked_resource() -> TrackedResource { 25 | RefCell::new((SlotMap::with_key(), SecondaryMap::new())) 26 | } 27 | 28 | #[derive(Debug)] 29 | pub struct Context { 30 | raw: RawRenderingContext, 31 | shaders: TrackedResource, 32 | programs: TrackedResource, 33 | buffers: TrackedResource, 34 | vertex_arrays: TrackedResource, 35 | textures: TrackedResource, 36 | samplers: TrackedResource, 37 | fences: TrackedResource, 38 | framebuffers: TrackedResource, 39 | renderbuffers: TrackedResource, 40 | uniform_locations: TrackedResource, 41 | } 42 | 43 | impl Context { 44 | pub fn from_webgl1_context(context: WebGlRenderingContext) -> Self { 45 | Context { 46 | raw: RawRenderingContext::WebGl1(context), 47 | shaders: tracked_resource(), 48 | programs: tracked_resource(), 49 | buffers: tracked_resource(), 50 | vertex_arrays: tracked_resource(), 51 | textures: tracked_resource(), 52 | samplers: tracked_resource(), 53 | fences: tracked_resource(), 54 | framebuffers: tracked_resource(), 55 | renderbuffers: tracked_resource(), 56 | uniform_locations: tracked_resource(), 57 | } 58 | } 59 | 60 | pub fn from_webgl2_context(context: WebGl2RenderingContext) -> Self { 61 | Context { 62 | raw: RawRenderingContext::WebGl2(context), 63 | shaders: tracked_resource(), 64 | programs: tracked_resource(), 65 | buffers: tracked_resource(), 66 | vertex_arrays: tracked_resource(), 67 | textures: tracked_resource(), 68 | samplers: tracked_resource(), 69 | fences: tracked_resource(), 70 | framebuffers: tracked_resource(), 71 | renderbuffers: tracked_resource(), 72 | uniform_locations: tracked_resource(), 73 | } 74 | } 75 | } 76 | 77 | new_key_type! { pub struct WebShaderKey; } 78 | new_key_type! { pub struct WebProgramKey; } 79 | new_key_type! { pub struct WebBufferKey; } 80 | new_key_type! { pub struct WebVertexArrayKey; } 81 | new_key_type! { pub struct WebTextureKey; } 82 | new_key_type! { pub struct WebSamplerKey; } 83 | new_key_type! { pub struct WebFenceKey; } 84 | new_key_type! { pub struct WebFramebufferKey; } 85 | new_key_type! { pub struct WebRenderbufferKey; } 86 | new_key_type! { pub struct WebUniformLocationKey; } 87 | 88 | impl super::Context for Context { 89 | type Shader = WebShaderKey; 90 | type Program = WebProgramKey; 91 | type Buffer = WebBufferKey; 92 | type VertexArray = WebVertexArrayKey; 93 | type Texture = WebTextureKey; 94 | type Sampler = WebSamplerKey; 95 | type Fence = WebFenceKey; 96 | type Framebuffer = WebFramebufferKey; 97 | type Renderbuffer = WebRenderbufferKey; 98 | type UniformLocation = WebUniformLocationKey; 99 | 100 | unsafe fn create_framebuffer(&self) -> Result { 101 | let raw_framebuffer = match self.raw { 102 | RawRenderingContext::WebGl1(ref gl) => gl.create_framebuffer(), 103 | RawRenderingContext::WebGl2(ref gl) => gl.create_framebuffer(), 104 | }; 105 | 106 | match raw_framebuffer { 107 | Some(s) => { 108 | let key = self.framebuffers.borrow_mut().0.insert(()); 109 | self.framebuffers.borrow_mut().1.insert(key, s); 110 | Ok(key) 111 | } 112 | None => Err(String::from("Unable to create framebuffer object")), 113 | } 114 | } 115 | 116 | unsafe fn create_renderbuffer(&self) -> Result { 117 | let raw_renderbuffer = match self.raw { 118 | RawRenderingContext::WebGl1(ref gl) => gl.create_renderbuffer(), 119 | RawRenderingContext::WebGl2(ref gl) => gl.create_renderbuffer(), 120 | }; 121 | 122 | match raw_renderbuffer { 123 | Some(s) => { 124 | let key = self.renderbuffers.borrow_mut().0.insert(()); 125 | self.renderbuffers.borrow_mut().1.insert(key, s); 126 | Ok(key) 127 | } 128 | None => Err(String::from("Unable to create renderbuffer object")), 129 | } 130 | } 131 | 132 | unsafe fn create_sampler(&self) -> Result { 133 | let raw_sampler = match self.raw { 134 | RawRenderingContext::WebGl1(ref _gl) => panic!("Sampler objects are not supported"), 135 | RawRenderingContext::WebGl2(ref gl) => gl.create_sampler(), 136 | }; 137 | 138 | match raw_sampler { 139 | Some(s) => { 140 | let key = self.samplers.borrow_mut().0.insert(()); 141 | self.samplers.borrow_mut().1.insert(key, s); 142 | Ok(key) 143 | } 144 | None => Err(String::from("Unable to create sampler object")), 145 | } 146 | } 147 | 148 | unsafe fn create_shader(&self, shader_type: u32) -> Result { 149 | let raw_shader = match self.raw { 150 | RawRenderingContext::WebGl1(ref gl) => gl.create_shader(shader_type as u32), 151 | RawRenderingContext::WebGl2(ref gl) => gl.create_shader(shader_type as u32), 152 | }; 153 | 154 | match raw_shader { 155 | Some(s) => { 156 | let key = self.shaders.borrow_mut().0.insert(()); 157 | self.shaders.borrow_mut().1.insert(key, s); 158 | Ok(key) 159 | } 160 | None => Err(String::from("Unable to create shader object")), 161 | } 162 | } 163 | 164 | unsafe fn create_texture(&self) -> Result { 165 | let raw_texture = match self.raw { 166 | RawRenderingContext::WebGl1(ref gl) => gl.create_texture(), 167 | RawRenderingContext::WebGl2(ref gl) => gl.create_texture(), 168 | }; 169 | 170 | match raw_texture { 171 | Some(t) => { 172 | let key = self.textures.borrow_mut().0.insert(()); 173 | self.textures.borrow_mut().1.insert(key, t); 174 | Ok(key) 175 | } 176 | None => Err(String::from("Unable to create texture object")), 177 | } 178 | } 179 | 180 | unsafe fn delete_shader(&self, shader: Self::Shader) { 181 | let mut shaders = self.shaders.borrow_mut(); 182 | match shaders.1.remove(shader) { 183 | Some(ref s) => match self.raw { 184 | RawRenderingContext::WebGl1(ref gl) => gl.delete_shader(Some(s)), 185 | RawRenderingContext::WebGl2(ref gl) => gl.delete_shader(Some(s)), 186 | }, 187 | None => {} 188 | } 189 | } 190 | 191 | unsafe fn shader_source(&self, shader: Self::Shader, source: &str) { 192 | let shaders = self.shaders.borrow(); 193 | let raw_shader = shaders.1.get_unchecked(shader); 194 | match self.raw { 195 | RawRenderingContext::WebGl1(ref gl) => gl.shader_source(raw_shader, source), 196 | RawRenderingContext::WebGl2(ref gl) => gl.shader_source(raw_shader, source), 197 | } 198 | } 199 | 200 | unsafe fn compile_shader(&self, shader: Self::Shader) { 201 | let shaders = self.shaders.borrow(); 202 | let raw_shader = shaders.1.get_unchecked(shader); 203 | match self.raw { 204 | RawRenderingContext::WebGl1(ref gl) => gl.compile_shader(raw_shader), 205 | RawRenderingContext::WebGl2(ref gl) => gl.compile_shader(raw_shader), 206 | } 207 | } 208 | 209 | unsafe fn get_shader_compile_status(&self, shader: Self::Shader) -> bool { 210 | let shaders = self.shaders.borrow(); 211 | let raw_shader = shaders.1.get_unchecked(shader); 212 | match self.raw { 213 | RawRenderingContext::WebGl1(ref gl) => { 214 | gl.get_shader_parameter(raw_shader, COMPILE_STATUS) 215 | } 216 | RawRenderingContext::WebGl2(ref gl) => { 217 | gl.get_shader_parameter(raw_shader, COMPILE_STATUS) 218 | } 219 | } 220 | .as_bool() 221 | .unwrap_or(false) 222 | } 223 | 224 | unsafe fn get_shader_info_log(&self, shader: Self::Shader) -> String { 225 | let shaders = self.shaders.borrow(); 226 | let raw_shader = shaders.1.get_unchecked(shader); 227 | match self.raw { 228 | RawRenderingContext::WebGl1(ref gl) => gl.get_shader_info_log(raw_shader), 229 | RawRenderingContext::WebGl2(ref gl) => gl.get_shader_info_log(raw_shader), 230 | } 231 | .unwrap_or_else(|| String::from("")) 232 | } 233 | 234 | unsafe fn get_tex_image( 235 | &self, 236 | _target: u32, 237 | _level: i32, 238 | _format: u32, 239 | _ty: u32, 240 | _pixels: Option<&[u8]>, 241 | ) { 242 | panic!("Get tex image is not supported"); 243 | } 244 | 245 | unsafe fn create_program(&self) -> Result { 246 | let raw_program = match self.raw { 247 | RawRenderingContext::WebGl1(ref gl) => gl.create_program(), 248 | RawRenderingContext::WebGl2(ref gl) => gl.create_program(), 249 | }; 250 | 251 | match raw_program { 252 | Some(p) => { 253 | let key = self.programs.borrow_mut().0.insert(()); 254 | self.programs.borrow_mut().1.insert(key, p); 255 | Ok(key) 256 | } 257 | None => Err(String::from("Unable to create program object")), 258 | } 259 | } 260 | 261 | unsafe fn delete_program(&self, program: Self::Program) { 262 | let mut programs = self.programs.borrow_mut(); 263 | match programs.1.remove(program) { 264 | Some(ref p) => match self.raw { 265 | RawRenderingContext::WebGl1(ref gl) => gl.delete_program(Some(p)), 266 | RawRenderingContext::WebGl2(ref gl) => gl.delete_program(Some(p)), 267 | }, 268 | None => {} 269 | } 270 | } 271 | 272 | unsafe fn attach_shader(&self, program: Self::Program, shader: Self::Shader) { 273 | let programs = self.programs.borrow(); 274 | let shaders = self.shaders.borrow(); 275 | let raw_program = programs.1.get_unchecked(program); 276 | let raw_shader = shaders.1.get_unchecked(shader); 277 | match self.raw { 278 | RawRenderingContext::WebGl1(ref gl) => gl.attach_shader(raw_program, raw_shader), 279 | RawRenderingContext::WebGl2(ref gl) => gl.attach_shader(raw_program, raw_shader), 280 | } 281 | } 282 | 283 | unsafe fn detach_shader(&self, program: Self::Program, shader: Self::Shader) { 284 | let programs = self.programs.borrow(); 285 | let shaders = self.shaders.borrow(); 286 | let raw_program = programs.1.get_unchecked(program); 287 | let raw_shader = shaders.1.get_unchecked(shader); 288 | match self.raw { 289 | RawRenderingContext::WebGl1(ref gl) => gl.detach_shader(raw_program, raw_shader), 290 | RawRenderingContext::WebGl2(ref gl) => gl.detach_shader(raw_program, raw_shader), 291 | } 292 | } 293 | 294 | unsafe fn link_program(&self, program: Self::Program) { 295 | let programs = self.programs.borrow(); 296 | let raw_program = programs.1.get_unchecked(program); 297 | match self.raw { 298 | RawRenderingContext::WebGl1(ref gl) => gl.link_program(raw_program), 299 | RawRenderingContext::WebGl2(ref gl) => gl.link_program(raw_program), 300 | } 301 | } 302 | 303 | unsafe fn get_program_link_status(&self, program: Self::Program) -> bool { 304 | let programs = self.programs.borrow(); 305 | let raw_program = programs.1.get_unchecked(program); 306 | match self.raw { 307 | RawRenderingContext::WebGl1(ref gl) => { 308 | gl.get_program_parameter(raw_program, LINK_STATUS) 309 | } 310 | RawRenderingContext::WebGl2(ref gl) => { 311 | gl.get_program_parameter(raw_program, LINK_STATUS) 312 | } 313 | } 314 | .as_bool() 315 | .unwrap_or(false) 316 | } 317 | 318 | unsafe fn get_program_info_log(&self, program: Self::Program) -> String { 319 | let programs = self.programs.borrow(); 320 | let raw_program = programs.1.get_unchecked(program); 321 | match self.raw { 322 | RawRenderingContext::WebGl1(ref gl) => gl.get_program_info_log(raw_program), 323 | RawRenderingContext::WebGl2(ref gl) => gl.get_program_info_log(raw_program), 324 | } 325 | .unwrap_or_else(|| String::from("")) 326 | } 327 | 328 | unsafe fn use_program(&self, program: Option) { 329 | let programs = self.programs.borrow(); 330 | let raw_program = program.map(|p| programs.1.get_unchecked(p)); 331 | match self.raw { 332 | RawRenderingContext::WebGl1(ref gl) => gl.use_program(raw_program), 333 | RawRenderingContext::WebGl2(ref gl) => gl.use_program(raw_program), 334 | } 335 | } 336 | 337 | unsafe fn create_buffer(&self) -> Result { 338 | let raw_buffer = match self.raw { 339 | RawRenderingContext::WebGl1(ref gl) => gl.create_buffer(), 340 | RawRenderingContext::WebGl2(ref gl) => gl.create_buffer(), 341 | }; 342 | 343 | match raw_buffer { 344 | Some(p) => { 345 | let key = self.buffers.borrow_mut().0.insert(()); 346 | self.buffers.borrow_mut().1.insert(key, p); 347 | Ok(key) 348 | } 349 | None => Err(String::from("Unable to create buffer object")), 350 | } 351 | } 352 | 353 | unsafe fn bind_buffer(&self, target: u32, buffer: Option) { 354 | let buffers = self.buffers.borrow(); 355 | let raw_buffer = buffer.map(|b| buffers.1.get_unchecked(b)); 356 | match self.raw { 357 | RawRenderingContext::WebGl1(ref gl) => gl.bind_buffer(target, raw_buffer), 358 | RawRenderingContext::WebGl2(ref gl) => gl.bind_buffer(target, raw_buffer), 359 | } 360 | } 361 | 362 | unsafe fn bind_buffer_range( 363 | &self, 364 | _target: u32, 365 | _index: u32, 366 | _buffer: Option, 367 | _offset: i32, 368 | _size: i32, 369 | ) { 370 | // Blocked by https://github.com/rustwasm/wasm-bindgen/issues/1038 371 | panic!("Bind buffer range is not supported yet"); 372 | } 373 | 374 | unsafe fn bind_framebuffer(&self, target: u32, framebuffer: Option) { 375 | let framebuffers = self.framebuffers.borrow(); 376 | let raw_framebuffer = framebuffer.map(|f| framebuffers.1.get_unchecked(f)); 377 | match self.raw { 378 | RawRenderingContext::WebGl1(ref gl) => gl.bind_framebuffer(target, raw_framebuffer), 379 | RawRenderingContext::WebGl2(ref gl) => gl.bind_framebuffer(target, raw_framebuffer), 380 | } 381 | } 382 | 383 | unsafe fn bind_renderbuffer(&self, target: u32, renderbuffer: Option) { 384 | let renderbuffers = self.renderbuffers.borrow(); 385 | let raw_renderbuffer = renderbuffer.map(|r| renderbuffers.1.get_unchecked(r)); 386 | match self.raw { 387 | RawRenderingContext::WebGl1(ref gl) => gl.bind_renderbuffer(target, raw_renderbuffer), 388 | RawRenderingContext::WebGl2(ref gl) => gl.bind_renderbuffer(target, raw_renderbuffer), 389 | } 390 | } 391 | 392 | unsafe fn create_vertex_array(&self) -> Result { 393 | let raw_vertex_array = match self.raw { 394 | RawRenderingContext::WebGl1(ref _gl) => { 395 | panic!("Vertex array objects are not supported"); // TODO: Extension 396 | } 397 | RawRenderingContext::WebGl2(ref gl) => gl.create_vertex_array(), 398 | }; 399 | 400 | match raw_vertex_array { 401 | Some(va) => { 402 | let key = self.vertex_arrays.borrow_mut().0.insert(()); 403 | self.vertex_arrays.borrow_mut().1.insert(key, va); 404 | Ok(key) 405 | } 406 | None => Err(String::from("Unable to create vertex array object")), 407 | } 408 | } 409 | 410 | unsafe fn delete_vertex_array(&self, vertex_array: Self::VertexArray) { 411 | let mut vertex_arrays = self.vertex_arrays.borrow_mut(); 412 | match vertex_arrays.1.remove(vertex_array) { 413 | Some(ref va) => match self.raw { 414 | RawRenderingContext::WebGl1(ref _gl) => { 415 | panic!("Vertex array objects are not supported"); // TODO: Extension 416 | } 417 | RawRenderingContext::WebGl2(ref gl) => gl.delete_vertex_array(Some(va)), 418 | }, 419 | None => {} 420 | } 421 | } 422 | 423 | unsafe fn bind_vertex_array(&self, vertex_array: Option) { 424 | let vertex_arrays = self.vertex_arrays.borrow(); 425 | let raw_vertex_array = vertex_array.map(|va| vertex_arrays.1.get_unchecked(va)); 426 | match self.raw { 427 | RawRenderingContext::WebGl1(ref _gl) => { 428 | panic!("Vertex array objects are not supported"); // TODO: Extension 429 | } 430 | RawRenderingContext::WebGl2(ref gl) => gl.bind_vertex_array(raw_vertex_array), 431 | } 432 | } 433 | 434 | unsafe fn clear_color(&self, red: f32, green: f32, blue: f32, alpha: f32) { 435 | match self.raw { 436 | RawRenderingContext::WebGl1(ref gl) => gl.clear_color(red, green, blue, alpha), 437 | RawRenderingContext::WebGl2(ref gl) => gl.clear_color(red, green, blue, alpha), 438 | } 439 | } 440 | 441 | unsafe fn supports_f64_precision() -> bool { 442 | false 443 | } 444 | 445 | unsafe fn clear_depth_f64(&self, _depth: f64) { 446 | panic!("64-bit float precision is not supported in WebGL"); 447 | } 448 | 449 | unsafe fn clear_depth_f32(&self, depth: f32) { 450 | match self.raw { 451 | RawRenderingContext::WebGl1(ref gl) => gl.clear_depth(depth), 452 | RawRenderingContext::WebGl2(ref gl) => gl.clear_depth(depth), 453 | } 454 | } 455 | 456 | unsafe fn clear_stencil(&self, stencil: i32) { 457 | match self.raw { 458 | RawRenderingContext::WebGl1(ref gl) => gl.clear_stencil(stencil), 459 | RawRenderingContext::WebGl2(ref gl) => gl.clear_stencil(stencil), 460 | } 461 | } 462 | 463 | unsafe fn clear(&self, mask: u32) { 464 | match self.raw { 465 | RawRenderingContext::WebGl1(ref gl) => gl.clear(mask), 466 | RawRenderingContext::WebGl2(ref gl) => gl.clear(mask), 467 | } 468 | } 469 | 470 | unsafe fn patch_parameter_i32(&self, _parameter: u32, _value: i32) { 471 | panic!("Patch parameter is not supported"); 472 | } 473 | 474 | unsafe fn pixel_store_i32(&self, parameter: u32, value: i32) { 475 | match self.raw { 476 | RawRenderingContext::WebGl1(ref gl) => gl.pixel_storei(parameter, value), 477 | RawRenderingContext::WebGl2(ref gl) => gl.pixel_storei(parameter, value), 478 | } 479 | } 480 | 481 | unsafe fn pixel_store_bool(&self, parameter: u32, value: bool) { 482 | match self.raw { 483 | RawRenderingContext::WebGl1(ref gl) => gl.pixel_storei(parameter, value as i32), 484 | RawRenderingContext::WebGl2(ref gl) => gl.pixel_storei(parameter, value as i32), 485 | } 486 | } 487 | 488 | unsafe fn bind_frag_data_location( 489 | &self, 490 | _program: Self::Program, 491 | _color_number: u32, 492 | _name: &str, 493 | ) { 494 | panic!("Bind frag data location is not supported"); 495 | } 496 | 497 | unsafe fn buffer_data_size(&self, target: u32, size: i32, usage: u32) { 498 | match self.raw { 499 | RawRenderingContext::WebGl1(ref gl) => gl.buffer_data_with_i32(target, size, usage), 500 | RawRenderingContext::WebGl2(ref gl) => gl.buffer_data_with_i32(target, size, usage), 501 | } 502 | } 503 | 504 | unsafe fn buffer_data_u8_slice(&self, target: u32, data: &[u8], usage: u32) { 505 | match self.raw { 506 | RawRenderingContext::WebGl1(ref gl) => { 507 | gl.buffer_data_with_u8_array(target, data, usage) 508 | } 509 | RawRenderingContext::WebGl2(ref gl) => { 510 | gl.buffer_data_with_u8_array(target, data, usage) 511 | } 512 | } 513 | } 514 | 515 | unsafe fn buffer_storage( 516 | &self, 517 | _target: u32, 518 | _size: i32, 519 | _data: Option<&mut [u8]>, 520 | _flags: u32, 521 | ) { 522 | panic!("Buffer storage is not supported"); 523 | } 524 | 525 | unsafe fn check_framebuffer_status(&self, target: u32) -> u32 { 526 | match self.raw { 527 | RawRenderingContext::WebGl1(ref gl) => gl.check_framebuffer_status(target), 528 | RawRenderingContext::WebGl2(ref gl) => gl.check_framebuffer_status(target), 529 | } 530 | } 531 | 532 | unsafe fn clear_buffer_i32_slice(&self, target: u32, draw_buffer: u32, values: &mut [i32]) { 533 | match self.raw { 534 | RawRenderingContext::WebGl1(ref _gl) => { 535 | panic!("Clear buffer with `i32` slice is not supported"); 536 | } 537 | RawRenderingContext::WebGl2(ref gl) => { 538 | gl.clear_bufferiv_with_i32_array(target, draw_buffer as i32, values); 539 | } 540 | } 541 | } 542 | 543 | unsafe fn clear_buffer_u32_slice(&self, target: u32, draw_buffer: u32, values: &mut [u32]) { 544 | match self.raw { 545 | RawRenderingContext::WebGl1(ref _gl) => { 546 | panic!("Clear buffer with `u32` slice is not supported") 547 | } 548 | RawRenderingContext::WebGl2(ref gl) => { 549 | gl.clear_bufferuiv_with_u32_array(target, draw_buffer as i32, values) 550 | } 551 | } 552 | } 553 | 554 | unsafe fn clear_buffer_f32_slice(&self, target: u32, draw_buffer: u32, values: &mut [f32]) { 555 | match self.raw { 556 | RawRenderingContext::WebGl1(ref _gl) => { 557 | panic!("Clear buffer with `f32` slice is not supported") 558 | } 559 | RawRenderingContext::WebGl2(ref gl) => { 560 | gl.clear_bufferfv_with_f32_array(target, draw_buffer as i32, values) 561 | } 562 | } 563 | } 564 | 565 | unsafe fn clear_buffer_depth_stencil( 566 | &self, 567 | target: u32, 568 | draw_buffer: u32, 569 | depth: f32, 570 | stencil: i32, 571 | ) { 572 | match self.raw { 573 | RawRenderingContext::WebGl1(ref _gl) => { 574 | panic!("Clear buffer depth stencil is not supported") 575 | } 576 | RawRenderingContext::WebGl2(ref gl) => { 577 | gl.clear_bufferfi(target, draw_buffer as i32, depth, stencil) 578 | } 579 | } 580 | } 581 | 582 | unsafe fn client_wait_sync(&self, _fence: Self::Fence, _flags: u32, _timeout: i32) -> u32 { 583 | panic!("Client wait sync is not supported") 584 | } 585 | 586 | unsafe fn copy_buffer_sub_data( 587 | &self, 588 | src_target: u32, 589 | dst_target: u32, 590 | src_offset: i32, 591 | dst_offset: i32, 592 | size: i32, 593 | ) { 594 | match self.raw { 595 | RawRenderingContext::WebGl1(ref _gl) => panic!("Copy buffer subdata is not supported"), 596 | RawRenderingContext::WebGl2(ref gl) => gl 597 | .copy_buffer_sub_data_with_i32_and_i32_and_i32( 598 | src_target, dst_target, src_offset, dst_offset, size, 599 | ), 600 | } 601 | } 602 | 603 | unsafe fn delete_buffer(&self, buffer: Self::Buffer) { 604 | let mut buffers = self.buffers.borrow_mut(); 605 | match buffers.1.remove(buffer) { 606 | Some(ref b) => match self.raw { 607 | RawRenderingContext::WebGl1(ref gl) => gl.delete_buffer(Some(b)), 608 | RawRenderingContext::WebGl2(ref gl) => gl.delete_buffer(Some(b)), 609 | }, 610 | None => {} 611 | } 612 | } 613 | 614 | unsafe fn delete_framebuffer(&self, framebuffer: Self::Framebuffer) { 615 | let mut framebuffers = self.framebuffers.borrow_mut(); 616 | match framebuffers.1.remove(framebuffer) { 617 | Some(ref f) => match self.raw { 618 | RawRenderingContext::WebGl1(ref gl) => gl.delete_framebuffer(Some(f)), 619 | RawRenderingContext::WebGl2(ref gl) => gl.delete_framebuffer(Some(f)), 620 | }, 621 | None => {} 622 | } 623 | } 624 | 625 | unsafe fn delete_renderbuffer(&self, renderbuffer: Self::Renderbuffer) { 626 | let mut renderbuffers = self.renderbuffers.borrow_mut(); 627 | match renderbuffers.1.remove(renderbuffer) { 628 | Some(ref r) => match self.raw { 629 | RawRenderingContext::WebGl1(ref gl) => gl.delete_renderbuffer(Some(r)), 630 | RawRenderingContext::WebGl2(ref gl) => gl.delete_renderbuffer(Some(r)), 631 | }, 632 | None => {} 633 | } 634 | } 635 | 636 | unsafe fn delete_sampler(&self, sampler: Self::Sampler) { 637 | let mut samplers = self.samplers.borrow_mut(); 638 | match samplers.1.remove(sampler) { 639 | Some(ref s) => match self.raw { 640 | RawRenderingContext::WebGl1(ref _gl) => panic!("Samplers are not supported"), 641 | RawRenderingContext::WebGl2(ref gl) => gl.delete_sampler(Some(s)), 642 | }, 643 | None => {} 644 | } 645 | } 646 | 647 | unsafe fn delete_sync(&self, fence: Self::Fence) { 648 | let mut fences = self.fences.borrow_mut(); 649 | match fences.1.remove(fence) { 650 | Some(ref f) => match self.raw { 651 | RawRenderingContext::WebGl1(ref _gl) => panic!("Fences are not supported"), 652 | RawRenderingContext::WebGl2(ref gl) => gl.delete_sync(Some(f)), 653 | }, 654 | None => {} 655 | } 656 | } 657 | 658 | unsafe fn delete_texture(&self, texture: Self::Texture) { 659 | let mut textures = self.textures.borrow_mut(); 660 | match textures.1.remove(texture) { 661 | Some(ref t) => match self.raw { 662 | RawRenderingContext::WebGl1(ref gl) => gl.delete_texture(Some(t)), 663 | RawRenderingContext::WebGl2(ref gl) => gl.delete_texture(Some(t)), 664 | }, 665 | None => {} 666 | } 667 | } 668 | 669 | unsafe fn disable(&self, parameter: u32) { 670 | match self.raw { 671 | RawRenderingContext::WebGl1(ref gl) => gl.disable(parameter), 672 | RawRenderingContext::WebGl2(ref gl) => gl.disable(parameter), 673 | } 674 | } 675 | 676 | unsafe fn disable_draw_buffer(&self, _parameter: u32, _draw_buffer: u32) { 677 | panic!("Draw buffer disable is not supported"); 678 | } 679 | 680 | unsafe fn disable_vertex_attrib_array(&self, index: u32) { 681 | match self.raw { 682 | RawRenderingContext::WebGl1(ref gl) => gl.disable_vertex_attrib_array(index), 683 | RawRenderingContext::WebGl2(ref gl) => gl.disable_vertex_attrib_array(index), 684 | } 685 | } 686 | 687 | unsafe fn dispatch_compute(&self, _groups_x: u32, _groups_y: u32, _groups_z: u32) { 688 | panic!("Dispatch compute is not supported"); 689 | } 690 | 691 | unsafe fn dispatch_compute_indirect(&self, _offset: i32) { 692 | panic!("Dispatch compute indirect is not supported"); 693 | } 694 | 695 | unsafe fn draw_arrays(&self, mode: u32, first: i32, count: i32) { 696 | match self.raw { 697 | RawRenderingContext::WebGl1(ref gl) => gl.draw_arrays(mode as u32, first, count), 698 | RawRenderingContext::WebGl2(ref gl) => gl.draw_arrays(mode as u32, first, count), 699 | } 700 | } 701 | 702 | unsafe fn draw_arrays_instanced(&self, mode: u32, first: i32, count: i32, instance_count: i32) { 703 | match self.raw { 704 | RawRenderingContext::WebGl1(ref _gl) => { 705 | panic!("Draw arrays instanced is not supported") // TODO: Extension 706 | } 707 | RawRenderingContext::WebGl2(ref gl) => { 708 | gl.draw_arrays_instanced(mode as u32, first, count, instance_count) 709 | } 710 | } 711 | } 712 | 713 | unsafe fn draw_arrays_instanced_base_instance( 714 | &self, 715 | _mode: u32, 716 | _first: i32, 717 | _count: i32, 718 | _instance_count: i32, 719 | _base_instance: u32, 720 | ) { 721 | panic!("Draw arrays instanced base instance is not supported"); 722 | } 723 | 724 | unsafe fn draw_buffer(&self, _draw_buffer: u32) { 725 | // Blocked by https://github.com/rustwasm/wasm-bindgen/issues/1038 726 | panic!("Draw buffer is not supported yet"); 727 | } 728 | 729 | unsafe fn draw_buffers(&self, _buffers: &[u32]) { 730 | // Blocked by https://github.com/rustwasm/wasm-bindgen/issues/1038 731 | panic!("Draw buffers is not supported yet"); 732 | } 733 | 734 | unsafe fn draw_elements(&self, mode: u32, count: i32, element_type: u32, offset: i32) { 735 | match self.raw { 736 | RawRenderingContext::WebGl1(ref gl) => { 737 | gl.draw_elements_with_i32(mode as u32, count, element_type as u32, offset); 738 | } 739 | RawRenderingContext::WebGl2(ref gl) => { 740 | gl.draw_elements_with_i32(mode as u32, count, element_type as u32, offset); 741 | } 742 | } 743 | } 744 | 745 | unsafe fn draw_elements_base_vertex( 746 | &self, 747 | _mode: u32, 748 | _count: i32, 749 | _element_type: u32, 750 | _offset: i32, 751 | _base_vertex: i32, 752 | ) { 753 | panic!("Draw elements base vertex is not supported"); 754 | } 755 | 756 | unsafe fn draw_elements_instanced( 757 | &self, 758 | mode: u32, 759 | count: i32, 760 | element_type: u32, 761 | offset: i32, 762 | instance_count: i32, 763 | ) { 764 | match self.raw { 765 | RawRenderingContext::WebGl1(ref _gl) => { 766 | panic!("Draw elements instanced is not supported") // TODO: Extension 767 | } 768 | RawRenderingContext::WebGl2(ref gl) => { 769 | gl.draw_elements_instanced_with_i32( 770 | mode as u32, 771 | count, 772 | element_type as u32, 773 | offset, 774 | instance_count, 775 | ); 776 | } 777 | } 778 | } 779 | 780 | unsafe fn draw_elements_instanced_base_vertex( 781 | &self, 782 | _mode: u32, 783 | _count: i32, 784 | _element_type: u32, 785 | _offset: i32, 786 | _instance_count: i32, 787 | _base_vertex: i32, 788 | ) { 789 | panic!("Draw elements instanced base vertex is not supported"); 790 | } 791 | 792 | unsafe fn draw_elements_instanced_base_vertex_base_instance( 793 | &self, 794 | _mode: u32, 795 | _count: i32, 796 | _element_type: u32, 797 | _offset: i32, 798 | _instance_count: i32, 799 | _base_vertex: i32, 800 | _base_instance: u32, 801 | ) { 802 | panic!("Draw elements instanced base vertex base instance is not supported"); 803 | } 804 | 805 | unsafe fn enable(&self, parameter: u32) { 806 | match self.raw { 807 | RawRenderingContext::WebGl1(ref gl) => gl.enable(parameter), 808 | RawRenderingContext::WebGl2(ref gl) => gl.enable(parameter), 809 | } 810 | } 811 | 812 | unsafe fn enable_draw_buffer(&self, _parameter: u32, _draw_buffer: u32) { 813 | panic!("Draw buffer enable is not supported"); 814 | } 815 | 816 | unsafe fn enable_vertex_attrib_array(&self, index: u32) { 817 | match self.raw { 818 | RawRenderingContext::WebGl1(ref gl) => gl.enable_vertex_attrib_array(index), 819 | RawRenderingContext::WebGl2(ref gl) => gl.enable_vertex_attrib_array(index), 820 | } 821 | } 822 | 823 | unsafe fn flush(&self) { 824 | match self.raw { 825 | RawRenderingContext::WebGl1(ref gl) => gl.flush(), 826 | RawRenderingContext::WebGl2(ref gl) => gl.flush(), 827 | } 828 | } 829 | 830 | unsafe fn framebuffer_renderbuffer( 831 | &self, 832 | target: u32, 833 | attachment: u32, 834 | renderbuffer_target: u32, 835 | renderbuffer: Option, 836 | ) { 837 | let renderbuffers = self.renderbuffers.borrow(); 838 | let raw_renderbuffer = renderbuffer.map(|r| renderbuffers.1.get_unchecked(r)); 839 | match self.raw { 840 | RawRenderingContext::WebGl1(ref _gl) => { 841 | panic!("Framebuffer renderbuffer is not supported"); 842 | } 843 | RawRenderingContext::WebGl2(ref gl) => gl.framebuffer_renderbuffer( 844 | target, 845 | attachment, 846 | renderbuffer_target, 847 | raw_renderbuffer, 848 | ), 849 | } 850 | } 851 | 852 | unsafe fn framebuffer_texture( 853 | &self, 854 | _target: u32, 855 | _attachment: u32, 856 | _texture: Option, 857 | _level: i32, 858 | ) { 859 | panic!("Framebuffer texture is not supported"); 860 | } 861 | 862 | unsafe fn framebuffer_texture_2d( 863 | &self, 864 | target: u32, 865 | attachment: u32, 866 | texture_target: u32, 867 | texture: Option, 868 | level: i32, 869 | ) { 870 | let textures = self.textures.borrow(); 871 | let raw_texture = texture.map(|t| textures.1.get_unchecked(t)); 872 | match self.raw { 873 | RawRenderingContext::WebGl1(ref gl) => { 874 | gl.framebuffer_texture_2d(target, attachment, texture_target, raw_texture, level); 875 | } 876 | RawRenderingContext::WebGl2(ref gl) => { 877 | gl.framebuffer_texture_2d(target, attachment, texture_target, raw_texture, level); 878 | } 879 | } 880 | } 881 | 882 | unsafe fn framebuffer_texture_3d( 883 | &self, 884 | _target: u32, 885 | _attachment: u32, 886 | _texture_target: u32, 887 | _texture: Option, 888 | _level: i32, 889 | _layer: i32, 890 | ) { 891 | panic!("Framebuffer texture 3D is not supported"); 892 | } 893 | 894 | unsafe fn framebuffer_texture_layer( 895 | &self, 896 | target: u32, 897 | attachment: u32, 898 | texture: Option, 899 | level: i32, 900 | layer: i32, 901 | ) { 902 | let textures = self.textures.borrow(); 903 | let raw_texture = texture.map(|t| textures.1.get_unchecked(t)); 904 | match self.raw { 905 | RawRenderingContext::WebGl1(ref _gl) => { 906 | panic!("Framebuffer texture layer is not supported"); 907 | } 908 | RawRenderingContext::WebGl2(ref gl) => { 909 | gl.framebuffer_texture_layer(target, attachment, raw_texture, level, layer); 910 | } 911 | } 912 | } 913 | 914 | unsafe fn front_face(&self, value: u32) { 915 | match self.raw { 916 | RawRenderingContext::WebGl1(ref gl) => gl.front_face(value as u32), 917 | RawRenderingContext::WebGl2(ref gl) => gl.front_face(value as u32), 918 | } 919 | } 920 | 921 | unsafe fn get_error(&self) -> u32 { 922 | match self.raw { 923 | RawRenderingContext::WebGl1(ref gl) => gl.get_error(), 924 | RawRenderingContext::WebGl2(ref gl) => gl.get_error(), 925 | } 926 | } 927 | 928 | unsafe fn get_parameter_i32(&self, parameter: u32) -> i32 { 929 | match self.raw { 930 | RawRenderingContext::WebGl1(ref gl) => gl.get_parameter(parameter), 931 | RawRenderingContext::WebGl2(ref gl) => gl.get_parameter(parameter), 932 | } 933 | .unwrap() 934 | .as_f64() 935 | .map(|v| v as i32) 936 | // Errors will be caught by the browser or through `get_error` 937 | // so return a default instead 938 | .unwrap_or(0) 939 | } 940 | 941 | unsafe fn get_parameter_indexed_i32(&self, parameter: u32, index: u32) -> i32 { 942 | match self.raw { 943 | RawRenderingContext::WebGl1(ref _gl) => { 944 | panic!("Get parameter indexed is not supported") 945 | } 946 | RawRenderingContext::WebGl2(ref gl) => gl.get_indexed_parameter(parameter, index), 947 | } 948 | .unwrap() 949 | .as_f64() 950 | .map(|v| v as i32) 951 | // Errors will be caught by the browser or through `get_error` 952 | // so return a default instead 953 | .unwrap_or(0) 954 | } 955 | 956 | unsafe fn get_parameter_indexed_string(&self, parameter: u32, index: u32) -> String { 957 | match self.raw { 958 | RawRenderingContext::WebGl1(ref _gl) => { 959 | panic!("Get parameter indexed is not supported") 960 | } 961 | RawRenderingContext::WebGl2(ref gl) => gl.get_indexed_parameter(parameter, index), 962 | } 963 | .unwrap() 964 | .as_string() 965 | // Errors will be caught by the browser or through `get_error` 966 | // so return a default instead 967 | .unwrap_or(String::from("")) 968 | } 969 | 970 | unsafe fn get_parameter_string(&self, parameter: u32) -> String { 971 | match self.raw { 972 | RawRenderingContext::WebGl1(ref gl) => gl.get_parameter(parameter), 973 | RawRenderingContext::WebGl2(ref gl) => gl.get_parameter(parameter), 974 | } 975 | .unwrap() 976 | .as_string() 977 | // Errors will be caught by the browser or through `get_error` 978 | // so return a default instead 979 | .unwrap_or(String::from("")) 980 | } 981 | 982 | unsafe fn get_uniform_location( 983 | &self, 984 | program: Self::Program, 985 | name: &str, 986 | ) -> Option { 987 | let programs = self.programs.borrow(); 988 | let raw_program = programs.1.get_unchecked(program); 989 | let raw_uniform = match self.raw { 990 | RawRenderingContext::WebGl1(ref gl) => gl.get_uniform_location(raw_program, name), 991 | RawRenderingContext::WebGl2(ref gl) => gl.get_uniform_location(raw_program, name), 992 | }; 993 | if let Some(u) = raw_uniform { 994 | let mut uniform_locations = self.uniform_locations.borrow_mut(); 995 | let key = uniform_locations.0.insert(()); 996 | uniform_locations.1.insert(key, u); 997 | Some(key) 998 | } else { 999 | None 1000 | } 1001 | } 1002 | 1003 | unsafe fn get_attrib_location( 1004 | &self, 1005 | program: Self::Program, 1006 | name: &str, 1007 | ) -> i32 { 1008 | let programs = self.programs.borrow(); 1009 | let raw_program = programs.1.get_unchecked(program); 1010 | match self.raw { 1011 | RawRenderingContext::WebGl1(ref gl) => gl.get_attrib_location(raw_program, name), 1012 | RawRenderingContext::WebGl2(ref gl) => gl.get_attrib_location(raw_program, name), 1013 | } 1014 | } 1015 | 1016 | unsafe fn is_sync(&self, fence: Self::Fence) -> bool { 1017 | let fences = self.fences.borrow(); 1018 | let raw_fence = fences.1.get_unchecked(fence); 1019 | match self.raw { 1020 | RawRenderingContext::WebGl1(ref _gl) => panic!("Sync is not supported"), 1021 | RawRenderingContext::WebGl2(ref gl) => gl.is_sync(Some(raw_fence)), 1022 | } 1023 | } 1024 | 1025 | unsafe fn renderbuffer_storage( 1026 | &self, 1027 | target: u32, 1028 | internal_format: u32, 1029 | width: i32, 1030 | height: i32, 1031 | ) { 1032 | match self.raw { 1033 | RawRenderingContext::WebGl1(ref gl) => { 1034 | gl.renderbuffer_storage(target, internal_format, width, height); 1035 | } 1036 | RawRenderingContext::WebGl2(ref gl) => { 1037 | gl.renderbuffer_storage(target, internal_format, width, height); 1038 | } 1039 | } 1040 | } 1041 | 1042 | unsafe fn sampler_parameter_f32(&self, sampler: Self::Sampler, name: u32, value: f32) { 1043 | let samplers = self.samplers.borrow(); 1044 | let raw_sampler = samplers.1.get_unchecked(sampler); 1045 | match self.raw { 1046 | RawRenderingContext::WebGl1(ref _gl) => { 1047 | panic!("Samper parameter for `f32` is not supported") 1048 | } 1049 | RawRenderingContext::WebGl2(ref gl) => { 1050 | gl.sampler_parameterf(raw_sampler, name, value); 1051 | } 1052 | } 1053 | } 1054 | 1055 | unsafe fn sampler_parameter_f32_slice( 1056 | &self, 1057 | _sampler: Self::Sampler, 1058 | _name: u32, 1059 | _value: &mut [f32], 1060 | ) { 1061 | panic!("Sampler parameter for `f32` slice is not supported"); 1062 | } 1063 | 1064 | unsafe fn sampler_parameter_i32(&self, sampler: Self::Sampler, name: u32, value: i32) { 1065 | let samplers = self.samplers.borrow(); 1066 | let raw_sampler = samplers.1.get_unchecked(sampler); 1067 | match self.raw { 1068 | RawRenderingContext::WebGl1(ref _gl) => { 1069 | panic!("Samper parameter for `i32` is not supported") 1070 | } 1071 | RawRenderingContext::WebGl2(ref gl) => { 1072 | gl.sampler_parameteri(raw_sampler, name, value); 1073 | } 1074 | } 1075 | } 1076 | 1077 | unsafe fn tex_image_2d( 1078 | &self, 1079 | target: u32, 1080 | level: i32, 1081 | internal_format: i32, 1082 | width: i32, 1083 | height: i32, 1084 | border: i32, 1085 | format: u32, 1086 | ty: u32, 1087 | pixels: Option<&[u8]>, 1088 | ) { 1089 | match self.raw { 1090 | RawRenderingContext::WebGl1(ref gl) => { 1091 | // TODO: Handle return value? 1092 | gl.tex_image_2d_with_i32_and_i32_and_i32_and_format_and_type_and_opt_u8_array( 1093 | target, 1094 | level, 1095 | internal_format, 1096 | width, 1097 | height, 1098 | border, 1099 | format, 1100 | ty, 1101 | pixels, 1102 | ) 1103 | .unwrap(); 1104 | } 1105 | RawRenderingContext::WebGl2(ref gl) => { 1106 | // TODO: Handle return value? 1107 | gl.tex_image_2d_with_i32_and_i32_and_i32_and_format_and_type_and_opt_u8_array( 1108 | target, 1109 | level, 1110 | internal_format, 1111 | width, 1112 | height, 1113 | border, 1114 | format, 1115 | ty, 1116 | pixels, 1117 | ) 1118 | .unwrap(); 1119 | } 1120 | } 1121 | } 1122 | 1123 | unsafe fn tex_storage_2d( 1124 | &self, 1125 | target: u32, 1126 | levels: i32, 1127 | internal_format: u32, 1128 | width: i32, 1129 | height: i32, 1130 | ) { 1131 | match self.raw { 1132 | RawRenderingContext::WebGl1(ref _gl) => panic!("Tex storage 2D is not supported"), 1133 | RawRenderingContext::WebGl2(ref gl) => { 1134 | gl.tex_storage_2d(target, levels, internal_format, width, height); 1135 | } 1136 | } 1137 | } 1138 | 1139 | unsafe fn uniform_1_i32(&self, uniform_location: Option, x: i32) { 1140 | let uniform_locations = self.uniform_locations.borrow(); 1141 | let raw_uniform_location = uniform_location.map(|u| uniform_locations.1.get_unchecked(u)); 1142 | match self.raw { 1143 | RawRenderingContext::WebGl1(ref gl) => gl.uniform1i(raw_uniform_location, x), 1144 | RawRenderingContext::WebGl2(ref gl) => gl.uniform1i(raw_uniform_location, x), 1145 | } 1146 | } 1147 | 1148 | unsafe fn uniform_2_i32(&self, uniform_location: Option, x: i32, y: i32) { 1149 | let uniform_locations = self.uniform_locations.borrow(); 1150 | let raw_uniform_location = uniform_location.map(|u| uniform_locations.1.get_unchecked(u)); 1151 | match self.raw { 1152 | RawRenderingContext::WebGl1(ref gl) => gl.uniform2i(raw_uniform_location, x, y), 1153 | RawRenderingContext::WebGl2(ref gl) => gl.uniform2i(raw_uniform_location, x, y), 1154 | } 1155 | } 1156 | 1157 | unsafe fn uniform_3_i32(&self, uniform_location: Option, x: i32, y: i32, z: i32) { 1158 | let uniform_locations = self.uniform_locations.borrow(); 1159 | let raw_uniform_location = uniform_location.map(|u| uniform_locations.1.get_unchecked(u)); 1160 | match self.raw { 1161 | RawRenderingContext::WebGl1(ref gl) => gl.uniform3i(raw_uniform_location, x, y, z), 1162 | RawRenderingContext::WebGl2(ref gl) => gl.uniform3i(raw_uniform_location, x, y, z), 1163 | } 1164 | } 1165 | 1166 | unsafe fn uniform_4_i32(&self, uniform_location: Option, x: i32, y: i32, z: i32, w: i32) { 1167 | let uniform_locations = self.uniform_locations.borrow(); 1168 | let raw_uniform_location = uniform_location.map(|u| uniform_locations.1.get_unchecked(u)); 1169 | match self.raw { 1170 | RawRenderingContext::WebGl1(ref gl) => gl.uniform4i(raw_uniform_location, x, y, z, w), 1171 | RawRenderingContext::WebGl2(ref gl) => gl.uniform4i(raw_uniform_location, x, y, z, w), 1172 | } 1173 | } 1174 | 1175 | unsafe fn uniform_1_i32_slice(&self, uniform_location: Option, v: &mut [i32; 1]) { 1176 | let uniform_locations = self.uniform_locations.borrow(); 1177 | let raw_uniform_location = uniform_location.map(|u| uniform_locations.1.get_unchecked(u)); 1178 | match self.raw { 1179 | RawRenderingContext::WebGl1(ref gl) => gl.uniform1iv_with_i32_array(raw_uniform_location, v), 1180 | RawRenderingContext::WebGl2(ref gl) => gl.uniform1iv_with_i32_array(raw_uniform_location, v), 1181 | } 1182 | } 1183 | 1184 | unsafe fn uniform_2_i32_slice(&self, uniform_location: Option, v: &mut [i32; 2]) { 1185 | let uniform_locations = self.uniform_locations.borrow(); 1186 | let raw_uniform_location = uniform_location.map(|u| uniform_locations.1.get_unchecked(u)); 1187 | match self.raw { 1188 | RawRenderingContext::WebGl1(ref gl) => gl.uniform2iv_with_i32_array(raw_uniform_location, v), 1189 | RawRenderingContext::WebGl2(ref gl) => gl.uniform2iv_with_i32_array(raw_uniform_location, v), 1190 | } 1191 | } 1192 | 1193 | unsafe fn uniform_3_i32_slice(&self, uniform_location: Option, v: &mut [i32; 3]) { 1194 | let uniform_locations = self.uniform_locations.borrow(); 1195 | let raw_uniform_location = uniform_location.map(|u| uniform_locations.1.get_unchecked(u)); 1196 | match self.raw { 1197 | RawRenderingContext::WebGl1(ref gl) => gl.uniform3iv_with_i32_array(raw_uniform_location, v), 1198 | RawRenderingContext::WebGl2(ref gl) => gl.uniform3iv_with_i32_array(raw_uniform_location, v), 1199 | } 1200 | } 1201 | 1202 | unsafe fn uniform_4_i32_slice(&self, uniform_location: Option, v: &mut [i32; 4]) { 1203 | let uniform_locations = self.uniform_locations.borrow(); 1204 | let raw_uniform_location = uniform_location.map(|u| uniform_locations.1.get_unchecked(u)); 1205 | match self.raw { 1206 | RawRenderingContext::WebGl1(ref gl) => gl.uniform4iv_with_i32_array(raw_uniform_location, v), 1207 | RawRenderingContext::WebGl2(ref gl) => gl.uniform4iv_with_i32_array(raw_uniform_location, v), 1208 | } 1209 | } 1210 | 1211 | unsafe fn uniform_1_f32(&self, uniform_location: Option, x: f32) { 1212 | let uniform_locations = self.uniform_locations.borrow(); 1213 | let raw_uniform_location = uniform_location.map(|u| uniform_locations.1.get_unchecked(u)); 1214 | match self.raw { 1215 | RawRenderingContext::WebGl1(ref gl) => gl.uniform1f(raw_uniform_location, x), 1216 | RawRenderingContext::WebGl2(ref gl) => gl.uniform1f(raw_uniform_location, x), 1217 | } 1218 | } 1219 | 1220 | unsafe fn uniform_2_f32(&self, uniform_location: Option, x: f32, y: f32) { 1221 | let uniform_locations = self.uniform_locations.borrow(); 1222 | let raw_uniform_location = uniform_location.map(|u| uniform_locations.1.get_unchecked(u)); 1223 | match self.raw { 1224 | RawRenderingContext::WebGl1(ref gl) => gl.uniform2f(raw_uniform_location, x, y), 1225 | RawRenderingContext::WebGl2(ref gl) => gl.uniform2f(raw_uniform_location, x, y), 1226 | } 1227 | } 1228 | 1229 | unsafe fn uniform_3_f32(&self, uniform_location: Option, x: f32, y: f32, z: f32) { 1230 | let uniform_locations = self.uniform_locations.borrow(); 1231 | let raw_uniform_location = uniform_location.map(|u| uniform_locations.1.get_unchecked(u)); 1232 | match self.raw { 1233 | RawRenderingContext::WebGl1(ref gl) => gl.uniform3f(raw_uniform_location, x, y, z), 1234 | RawRenderingContext::WebGl2(ref gl) => gl.uniform3f(raw_uniform_location, x, y, z), 1235 | } 1236 | } 1237 | 1238 | unsafe fn uniform_4_f32(&self, uniform_location: Option, x: f32, y: f32, z: f32, w: f32) { 1239 | let uniform_locations = self.uniform_locations.borrow(); 1240 | let raw_uniform_location = uniform_location.map(|u| uniform_locations.1.get_unchecked(u)); 1241 | match self.raw { 1242 | RawRenderingContext::WebGl1(ref gl) => gl.uniform4f(raw_uniform_location, x, y, z, w), 1243 | RawRenderingContext::WebGl2(ref gl) => gl.uniform4f(raw_uniform_location, x, y, z, w), 1244 | } 1245 | } 1246 | 1247 | unsafe fn uniform_1_f32_slice(&self, uniform_location: Option, v: &[f32; 1]) { 1248 | let uniform_locations = self.uniform_locations.borrow(); 1249 | let raw_uniform_location = uniform_location.map(|u| uniform_locations.1.get_unchecked(u)); 1250 | match self.raw { 1251 | RawRenderingContext::WebGl1(ref gl) => gl.uniform1fv_with_f32_array(raw_uniform_location, v), 1252 | RawRenderingContext::WebGl2(ref gl) => gl.uniform1fv_with_f32_array(raw_uniform_location, v), 1253 | } 1254 | } 1255 | 1256 | unsafe fn uniform_2_f32_slice(&self, uniform_location: Option, v: &[f32; 2]) { 1257 | let uniform_locations = self.uniform_locations.borrow(); 1258 | let raw_uniform_location = uniform_location.map(|u| uniform_locations.1.get_unchecked(u)); 1259 | match self.raw { 1260 | RawRenderingContext::WebGl1(ref gl) => gl.uniform2fv_with_f32_array(raw_uniform_location, v), 1261 | RawRenderingContext::WebGl2(ref gl) => gl.uniform2fv_with_f32_array(raw_uniform_location, v), 1262 | } 1263 | } 1264 | 1265 | unsafe fn uniform_3_f32_slice(&self, uniform_location: Option, v: &[f32; 3]) { 1266 | let uniform_locations = self.uniform_locations.borrow(); 1267 | let raw_uniform_location = uniform_location.map(|u| uniform_locations.1.get_unchecked(u)); 1268 | match self.raw { 1269 | RawRenderingContext::WebGl1(ref gl) => gl.uniform3fv_with_f32_array(raw_uniform_location, v), 1270 | RawRenderingContext::WebGl2(ref gl) => gl.uniform3fv_with_f32_array(raw_uniform_location, v), 1271 | } 1272 | } 1273 | 1274 | unsafe fn uniform_4_f32_slice(&self, uniform_location: Option, v: &[f32; 4]) { 1275 | let uniform_locations = self.uniform_locations.borrow(); 1276 | let raw_uniform_location = uniform_location.map(|u| uniform_locations.1.get_unchecked(u)); 1277 | match self.raw { 1278 | RawRenderingContext::WebGl1(ref gl) => gl.uniform4fv_with_f32_array(raw_uniform_location, v), 1279 | RawRenderingContext::WebGl2(ref gl) => gl.uniform4fv_with_f32_array(raw_uniform_location, v), 1280 | } 1281 | } 1282 | 1283 | unsafe fn uniform_matrix_2_f32_slice(&self, uniform_location: Option, transpose: bool, v: &[f32; 4]) { 1284 | let uniform_locations = self.uniform_locations.borrow(); 1285 | let raw_uniform_location = uniform_location.map(|u| uniform_locations.1.get_unchecked(u)); 1286 | match self.raw { 1287 | RawRenderingContext::WebGl1(ref gl) => gl.uniform_matrix2fv_with_f32_array(raw_uniform_location, transpose, v), 1288 | RawRenderingContext::WebGl2(ref gl) => gl.uniform_matrix2fv_with_f32_array(raw_uniform_location, transpose, v), 1289 | } 1290 | } 1291 | 1292 | unsafe fn uniform_matrix_3_f32_slice(&self, uniform_location: Option, transpose: bool, v: &[f32; 9]) { 1293 | let uniform_locations = self.uniform_locations.borrow(); 1294 | let raw_uniform_location = uniform_location.map(|u| uniform_locations.1.get_unchecked(u)); 1295 | match self.raw { 1296 | RawRenderingContext::WebGl1(ref gl) => gl.uniform_matrix3fv_with_f32_array(raw_uniform_location, transpose, v), 1297 | RawRenderingContext::WebGl2(ref gl) => gl.uniform_matrix3fv_with_f32_array(raw_uniform_location, transpose, v), 1298 | } 1299 | } 1300 | 1301 | unsafe fn uniform_matrix_4_f32_slice(&self, uniform_location: Option, transpose: bool, v: &[f32; 16]) { 1302 | let uniform_locations = self.uniform_locations.borrow(); 1303 | let raw_uniform_location = uniform_location.map(|u| uniform_locations.1.get_unchecked(u)); 1304 | match self.raw { 1305 | RawRenderingContext::WebGl1(ref gl) => gl.uniform_matrix4fv_with_f32_array(raw_uniform_location, transpose, v), 1306 | RawRenderingContext::WebGl2(ref gl) => gl.uniform_matrix4fv_with_f32_array(raw_uniform_location, transpose, v), 1307 | } 1308 | } 1309 | 1310 | unsafe fn unmap_buffer(&self, _target: u32) { 1311 | panic!("Unmap buffer is not supported"); 1312 | } 1313 | 1314 | unsafe fn cull_face(&self, value: u32) { 1315 | match self.raw { 1316 | RawRenderingContext::WebGl1(ref gl) => gl.cull_face(value as u32), 1317 | RawRenderingContext::WebGl2(ref gl) => gl.cull_face(value as u32), 1318 | } 1319 | } 1320 | 1321 | unsafe fn color_mask(&self, red: bool, green: bool, blue: bool, alpha: bool) { 1322 | match self.raw { 1323 | RawRenderingContext::WebGl1(ref gl) => gl.color_mask(red, green, blue, alpha), 1324 | RawRenderingContext::WebGl2(ref gl) => gl.color_mask(red, green, blue, alpha), 1325 | } 1326 | } 1327 | 1328 | unsafe fn color_mask_draw_buffer( 1329 | &self, 1330 | _draw_buffer: u32, 1331 | _red: bool, 1332 | _green: bool, 1333 | _blue: bool, 1334 | _alpha: bool, 1335 | ) { 1336 | panic!("Draw buffer color masks are not supported"); 1337 | } 1338 | 1339 | unsafe fn depth_mask(&self, value: bool) { 1340 | match self.raw { 1341 | RawRenderingContext::WebGl1(ref gl) => gl.depth_mask(value), 1342 | RawRenderingContext::WebGl2(ref gl) => gl.depth_mask(value), 1343 | } 1344 | } 1345 | 1346 | unsafe fn blend_color(&self, red: f32, green: f32, blue: f32, alpha: f32) { 1347 | match self.raw { 1348 | RawRenderingContext::WebGl1(ref gl) => gl.blend_color(red, green, blue, alpha), 1349 | RawRenderingContext::WebGl2(ref gl) => gl.blend_color(red, green, blue, alpha), 1350 | } 1351 | } 1352 | 1353 | unsafe fn line_width(&self, width: f32) { 1354 | match self.raw { 1355 | RawRenderingContext::WebGl1(ref gl) => gl.line_width(width), 1356 | RawRenderingContext::WebGl2(ref gl) => gl.line_width(width), 1357 | } 1358 | } 1359 | 1360 | unsafe fn map_buffer_range( 1361 | &self, 1362 | _target: u32, 1363 | _offset: i32, 1364 | _length: i32, 1365 | _access: u32, 1366 | ) -> *mut u8 { 1367 | panic!("Map buffer range is not supported") 1368 | } 1369 | 1370 | unsafe fn polygon_offset(&self, factor: f32, units: f32) { 1371 | match self.raw { 1372 | RawRenderingContext::WebGl1(ref gl) => gl.polygon_offset(factor, units), 1373 | RawRenderingContext::WebGl2(ref gl) => gl.polygon_offset(factor, units), 1374 | } 1375 | } 1376 | 1377 | unsafe fn polygon_mode(&self, _face: u32, _mode: u32) { 1378 | panic!("Polygon mode is not supported"); 1379 | } 1380 | 1381 | unsafe fn finish(&self) { 1382 | match self.raw { 1383 | RawRenderingContext::WebGl1(ref gl) => gl.finish(), 1384 | RawRenderingContext::WebGl2(ref gl) => gl.finish(), 1385 | } 1386 | } 1387 | 1388 | unsafe fn bind_texture(&self, target: u32, texture: Option) { 1389 | let textures = self.textures.borrow(); 1390 | let raw_texture = texture.map(|t| textures.1.get_unchecked(t)); 1391 | match self.raw { 1392 | RawRenderingContext::WebGl1(ref gl) => gl.bind_texture(target, raw_texture), 1393 | RawRenderingContext::WebGl2(ref gl) => gl.bind_texture(target, raw_texture), 1394 | } 1395 | } 1396 | 1397 | unsafe fn bind_sampler(&self, unit: u32, sampler: Option) { 1398 | let samplers = self.samplers.borrow(); 1399 | let raw_sampler = sampler.map(|s| samplers.1.get_unchecked(s)); 1400 | match self.raw { 1401 | RawRenderingContext::WebGl1(ref _gl) => panic!("Bind sampler is not supported"), 1402 | RawRenderingContext::WebGl2(ref gl) => gl.bind_sampler(unit, raw_sampler), 1403 | } 1404 | } 1405 | 1406 | unsafe fn active_texture(&self, unit: u32) { 1407 | match self.raw { 1408 | RawRenderingContext::WebGl1(ref gl) => gl.active_texture(unit), 1409 | RawRenderingContext::WebGl2(ref gl) => gl.active_texture(unit), 1410 | } 1411 | } 1412 | 1413 | unsafe fn fence_sync(&self, condition: u32, flags: u32) -> Result { 1414 | let raw_fence = match self.raw { 1415 | RawRenderingContext::WebGl1(ref _gl) => panic!("Fences are not supported"), // TODO: Extension 1416 | RawRenderingContext::WebGl2(ref gl) => gl.fence_sync(condition as u32, flags), 1417 | }; 1418 | match raw_fence { 1419 | Some(f) => { 1420 | let key = self.fences.borrow_mut().0.insert(()); 1421 | self.fences.borrow_mut().1.insert(key, f); 1422 | Ok(key) 1423 | } 1424 | None => Err(String::from("Unable to create fence object")), 1425 | } 1426 | } 1427 | 1428 | unsafe fn tex_parameter_f32(&self, target: u32, parameter: u32, value: f32) { 1429 | match self.raw { 1430 | RawRenderingContext::WebGl1(ref gl) => gl.tex_parameterf(target, parameter, value), 1431 | RawRenderingContext::WebGl2(ref gl) => gl.tex_parameterf(target, parameter, value), 1432 | } 1433 | } 1434 | 1435 | unsafe fn tex_parameter_i32(&self, target: u32, parameter: u32, value: i32) { 1436 | match self.raw { 1437 | RawRenderingContext::WebGl1(ref gl) => gl.tex_parameteri(target, parameter, value), 1438 | RawRenderingContext::WebGl2(ref gl) => gl.tex_parameteri(target, parameter, value), 1439 | } 1440 | } 1441 | 1442 | unsafe fn tex_parameter_f32_slice(&self, _target: u32, _parameter: u32, _values: &[f32]) { 1443 | // Blocked by https://github.com/rustwasm/wasm-bindgen/issues/1038 1444 | panic!("Texture parameters for `&[f32]` are not supported yet"); 1445 | } 1446 | 1447 | unsafe fn tex_parameter_i32_slice(&self, _target: u32, _parameter: u32, _values: &[i32]) { 1448 | panic!("Texture parameters for `&[i32]` are not supported yet"); 1449 | } 1450 | 1451 | unsafe fn tex_sub_image_2d_u8_slice( 1452 | &self, 1453 | target: u32, 1454 | level: i32, 1455 | x_offset: i32, 1456 | y_offset: i32, 1457 | width: i32, 1458 | height: i32, 1459 | format: u32, 1460 | ty: u32, 1461 | pixels: Option<&[u8]>, 1462 | ) { 1463 | match self.raw { 1464 | RawRenderingContext::WebGl1(ref gl) => { 1465 | gl.tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_opt_u8_array( 1466 | target, level, x_offset, y_offset, width, height, format, ty, pixels, 1467 | ) 1468 | .unwrap(); // TODO: Handle return value? 1469 | } 1470 | RawRenderingContext::WebGl2(ref gl) => { 1471 | gl.tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_opt_u8_array( 1472 | target, level, x_offset, y_offset, width, height, format, ty, pixels, 1473 | ) 1474 | .unwrap(); // TODO: Handle return value? 1475 | } 1476 | } 1477 | } 1478 | 1479 | unsafe fn tex_sub_image_2d_pixel_buffer_offset( 1480 | &self, 1481 | target: u32, 1482 | level: i32, 1483 | x_offset: i32, 1484 | y_offset: i32, 1485 | width: i32, 1486 | height: i32, 1487 | format: u32, 1488 | ty: u32, 1489 | pixel_buffer_offset: i32, 1490 | ) { 1491 | match self.raw { 1492 | RawRenderingContext::WebGl1(ref _gl) => { 1493 | panic!("Sub image 2D pixel buffer offset is not supported") 1494 | } 1495 | RawRenderingContext::WebGl2(ref gl) => { 1496 | gl.tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_i32( 1497 | target, 1498 | level, 1499 | x_offset, 1500 | y_offset, 1501 | width, 1502 | height, 1503 | format, 1504 | ty, 1505 | pixel_buffer_offset, 1506 | ) 1507 | .unwrap(); // TODO: Handle return value? 1508 | } 1509 | } 1510 | } 1511 | 1512 | unsafe fn depth_func(&self, func: u32) { 1513 | match self.raw { 1514 | RawRenderingContext::WebGl1(ref gl) => gl.depth_func(func as u32), 1515 | RawRenderingContext::WebGl2(ref gl) => gl.depth_func(func as u32), 1516 | } 1517 | } 1518 | 1519 | unsafe fn depth_range_f32(&self, near: f32, far: f32) { 1520 | match self.raw { 1521 | RawRenderingContext::WebGl1(ref gl) => gl.depth_range(near, far), 1522 | RawRenderingContext::WebGl2(ref gl) => gl.depth_range(near, far), 1523 | } 1524 | } 1525 | 1526 | unsafe fn depth_range_f64(&self, _near: f64, _far: f64) { 1527 | panic!("Depth range with 64-bit float values is not supported"); 1528 | } 1529 | 1530 | unsafe fn depth_range_f64_slice(&self, _first: u32, _count: i32, _values: &[[f64; 2]]) { 1531 | panic!("Depth range with 64-bit float slices is not supported"); 1532 | } 1533 | 1534 | unsafe fn scissor(&self, x: i32, y: i32, width: i32, height: i32) { 1535 | match self.raw { 1536 | RawRenderingContext::WebGl1(ref gl) => gl.scissor(x, y, width, height), 1537 | RawRenderingContext::WebGl2(ref gl) => gl.scissor(x, y, width, height), 1538 | } 1539 | } 1540 | 1541 | unsafe fn scissor_slice(&self, _first: u32, _count: i32, _scissors: &[[i32; 4]]) { 1542 | panic!("Scissor slice is not supported"); 1543 | } 1544 | 1545 | unsafe fn vertex_attrib_divisor(&self, index: u32, divisor: u32) { 1546 | match self.raw { 1547 | RawRenderingContext::WebGl1(ref _gl) => { 1548 | panic!("Vertex attrib divisor is not supported"); // TODO: Extension 1549 | } 1550 | RawRenderingContext::WebGl2(ref gl) => gl.vertex_attrib_divisor(index, divisor), 1551 | } 1552 | } 1553 | 1554 | unsafe fn vertex_attrib_pointer_f32( 1555 | &self, 1556 | index: u32, 1557 | size: i32, 1558 | data_type: u32, 1559 | normalized: bool, 1560 | stride: i32, 1561 | offset: i32, 1562 | ) { 1563 | match self.raw { 1564 | RawRenderingContext::WebGl1(ref gl) => gl 1565 | .vertex_attrib_pointer_with_i32(index, size, data_type, normalized, stride, offset), 1566 | RawRenderingContext::WebGl2(ref gl) => gl 1567 | .vertex_attrib_pointer_with_i32(index, size, data_type, normalized, stride, offset), 1568 | } 1569 | } 1570 | 1571 | unsafe fn vertex_attrib_pointer_i32( 1572 | &self, 1573 | index: u32, 1574 | size: i32, 1575 | data_type: u32, 1576 | stride: i32, 1577 | offset: i32, 1578 | ) { 1579 | match self.raw { 1580 | RawRenderingContext::WebGl1(ref _gl) => { 1581 | panic!("Integer vertex attrib pointer is not supported") 1582 | } 1583 | RawRenderingContext::WebGl2(ref gl) => { 1584 | gl.vertex_attrib_i_pointer_with_i32(index, size, data_type, stride, offset) 1585 | } 1586 | } 1587 | } 1588 | 1589 | unsafe fn vertex_attrib_pointer_f64( 1590 | &self, 1591 | _index: u32, 1592 | _size: i32, 1593 | _data_type: u32, 1594 | _stride: i32, 1595 | _offset: i32, 1596 | ) { 1597 | panic!("64-bit float precision is not supported in WebGL"); 1598 | } 1599 | 1600 | unsafe fn viewport(&self, x: i32, y: i32, width: i32, height: i32) { 1601 | match self.raw { 1602 | RawRenderingContext::WebGl1(ref gl) => gl.viewport(x, y, width, height), 1603 | RawRenderingContext::WebGl2(ref gl) => gl.viewport(x, y, width, height), 1604 | } 1605 | } 1606 | 1607 | unsafe fn viewport_f32_slice(&self, _first: u32, _count: i32, _values: &[[f32; 4]]) { 1608 | panic!("Viewport `f32` slice is not supported"); 1609 | } 1610 | 1611 | unsafe fn blend_func(&self, src: u32, dst: u32) { 1612 | match self.raw { 1613 | RawRenderingContext::WebGl1(ref gl) => gl.blend_func(src as u32, dst as u32), 1614 | RawRenderingContext::WebGl2(ref gl) => gl.blend_func(src as u32, dst as u32), 1615 | } 1616 | } 1617 | 1618 | unsafe fn blend_func_draw_buffer(&self, _draw_buffer: u32, _src: u32, _dst: u32) { 1619 | panic!("Draw buffer blend func is not supported"); 1620 | } 1621 | 1622 | unsafe fn blend_func_separate( 1623 | &self, 1624 | src_rgb: u32, 1625 | dst_rgb: u32, 1626 | src_alpha: u32, 1627 | dst_alpha: u32, 1628 | ) { 1629 | match self.raw { 1630 | RawRenderingContext::WebGl1(ref gl) => gl.blend_func_separate( 1631 | src_rgb as u32, 1632 | dst_rgb as u32, 1633 | src_alpha as u32, 1634 | dst_alpha as u32, 1635 | ), 1636 | RawRenderingContext::WebGl2(ref gl) => gl.blend_func_separate( 1637 | src_rgb as u32, 1638 | dst_rgb as u32, 1639 | src_alpha as u32, 1640 | dst_alpha as u32, 1641 | ), 1642 | } 1643 | } 1644 | 1645 | unsafe fn blend_func_separate_draw_buffer( 1646 | &self, 1647 | _draw_buffer: u32, 1648 | _src_rgb: u32, 1649 | _dst_rgb: u32, 1650 | _src_alpha: u32, 1651 | _dst_alpha: u32, 1652 | ) { 1653 | panic!("Draw buffer blend func separate is not supported"); 1654 | } 1655 | 1656 | unsafe fn blend_equation(&self, mode: u32) { 1657 | match self.raw { 1658 | RawRenderingContext::WebGl1(ref gl) => gl.blend_equation(mode as u32), 1659 | RawRenderingContext::WebGl2(ref gl) => gl.blend_equation(mode as u32), 1660 | } 1661 | } 1662 | 1663 | unsafe fn blend_equation_draw_buffer(&self, _draw_buffer: u32, _mode: u32) { 1664 | panic!("Draw buffer blend equation is not supported"); 1665 | } 1666 | 1667 | unsafe fn blend_equation_separate(&self, mode_rgb: u32, mode_alpha: u32) { 1668 | match self.raw { 1669 | RawRenderingContext::WebGl1(ref gl) => { 1670 | gl.blend_equation_separate(mode_rgb as u32, mode_alpha as u32) 1671 | } 1672 | RawRenderingContext::WebGl2(ref gl) => { 1673 | gl.blend_equation_separate(mode_rgb as u32, mode_alpha as u32) 1674 | } 1675 | } 1676 | } 1677 | 1678 | unsafe fn blend_equation_separate_draw_buffer( 1679 | &self, 1680 | _draw_buffer: u32, 1681 | _mode_rgb: u32, 1682 | _mode_alpha: u32, 1683 | ) { 1684 | panic!("Draw buffer blend equation separate is not supported"); 1685 | } 1686 | 1687 | unsafe fn stencil_func(&self, func: u32, reference: i32, mask: u32) { 1688 | match self.raw { 1689 | RawRenderingContext::WebGl1(ref gl) => gl.stencil_func(func as u32, reference, mask), 1690 | RawRenderingContext::WebGl2(ref gl) => gl.stencil_func(func as u32, reference, mask), 1691 | } 1692 | } 1693 | 1694 | unsafe fn stencil_func_separate(&self, face: u32, func: u32, reference: i32, mask: u32) { 1695 | match self.raw { 1696 | RawRenderingContext::WebGl1(ref gl) => { 1697 | gl.stencil_func_separate(face as u32, func as u32, reference, mask) 1698 | } 1699 | RawRenderingContext::WebGl2(ref gl) => { 1700 | gl.stencil_func_separate(face as u32, func as u32, reference, mask) 1701 | } 1702 | } 1703 | } 1704 | 1705 | unsafe fn stencil_mask(&self, mask: u32) { 1706 | match self.raw { 1707 | RawRenderingContext::WebGl1(ref gl) => gl.stencil_mask(mask), 1708 | RawRenderingContext::WebGl2(ref gl) => gl.stencil_mask(mask), 1709 | } 1710 | } 1711 | 1712 | unsafe fn stencil_mask_separate(&self, face: u32, mask: u32) { 1713 | match self.raw { 1714 | RawRenderingContext::WebGl1(ref gl) => gl.stencil_mask_separate(face as u32, mask), 1715 | RawRenderingContext::WebGl2(ref gl) => gl.stencil_mask_separate(face as u32, mask), 1716 | } 1717 | } 1718 | 1719 | unsafe fn stencil_op(&self, stencil_fail: u32, depth_fail: u32, pass: u32) { 1720 | match self.raw { 1721 | RawRenderingContext::WebGl1(ref gl) => { 1722 | gl.stencil_op(stencil_fail as u32, depth_fail as u32, pass as u32) 1723 | } 1724 | RawRenderingContext::WebGl2(ref gl) => { 1725 | gl.stencil_op(stencil_fail as u32, depth_fail as u32, pass as u32) 1726 | } 1727 | } 1728 | } 1729 | 1730 | unsafe fn stencil_op_separate(&self, face: u32, stencil_fail: u32, depth_fail: u32, pass: u32) { 1731 | match self.raw { 1732 | RawRenderingContext::WebGl1(ref gl) => gl.stencil_op_separate( 1733 | face as u32, 1734 | stencil_fail as u32, 1735 | depth_fail as u32, 1736 | pass as u32, 1737 | ), 1738 | RawRenderingContext::WebGl2(ref gl) => gl.stencil_op_separate( 1739 | face as u32, 1740 | stencil_fail as u32, 1741 | depth_fail as u32, 1742 | pass as u32, 1743 | ), 1744 | } 1745 | } 1746 | } 1747 | 1748 | pub struct RenderLoop; 1749 | 1750 | impl RenderLoop { 1751 | pub fn from_request_animation_frame() -> Self { 1752 | RenderLoop 1753 | } 1754 | } 1755 | 1756 | impl super::RenderLoop for RenderLoop { 1757 | type Window = (); 1758 | 1759 | fn run(&self, mut callback: F) { 1760 | fn request_animation_frame(f: &Closure) { 1761 | use wasm_bindgen::JsCast; 1762 | web_sys::window() 1763 | .unwrap() 1764 | .request_animation_frame(f.as_ref().unchecked_ref()) 1765 | .unwrap(); 1766 | } 1767 | 1768 | let mut running = true; 1769 | let f = std::rc::Rc::new(std::cell::RefCell::new(None)); 1770 | let g = f.clone(); 1771 | *g.borrow_mut() = Some(Closure::wrap(Box::new(move || { 1772 | callback(&mut running); 1773 | if !running { 1774 | let _ = f.borrow_mut().take(); 1775 | return; 1776 | } 1777 | request_animation_frame(f.borrow().as_ref().unwrap()); 1778 | }) as Box)); 1779 | 1780 | request_animation_frame(g.borrow().as_ref().unwrap()); 1781 | } 1782 | } 1783 | --------------------------------------------------------------------------------