|
| 1 | +#![allow(unsafe_code)] |
| 2 | +use glow::HasContext; |
| 3 | +use std::option::Option::Some; |
| 4 | +#[cfg(target_arch = "wasm32")] |
| 5 | +use wasm_bindgen::JsValue; |
| 6 | + |
| 7 | +pub(crate) fn srgbtexture2d( |
| 8 | + gl: &glow::Context, |
| 9 | + is_webgl_1: bool, |
| 10 | + srgb_support: bool, |
| 11 | + data: &[u8], |
| 12 | + w: usize, |
| 13 | + h: usize, |
| 14 | +) -> glow::Texture { |
| 15 | + assert_eq!(data.len(), w * h * 4); |
| 16 | + assert!(w >= 1); |
| 17 | + assert!(h >= 1); |
| 18 | + unsafe { |
| 19 | + let tex = gl.create_texture().unwrap(); |
| 20 | + gl.bind_texture(glow::TEXTURE_2D, Some(tex)); |
| 21 | + |
| 22 | + gl.tex_parameter_i32( |
| 23 | + glow::TEXTURE_2D, |
| 24 | + glow::TEXTURE_MAG_FILTER, |
| 25 | + glow::LINEAR as i32, |
| 26 | + ); |
| 27 | + gl.tex_parameter_i32( |
| 28 | + glow::TEXTURE_2D, |
| 29 | + glow::TEXTURE_MIN_FILTER, |
| 30 | + glow::LINEAR as i32, |
| 31 | + ); |
| 32 | + gl.tex_parameter_i32( |
| 33 | + glow::TEXTURE_2D, |
| 34 | + glow::TEXTURE_WRAP_S, |
| 35 | + glow::CLAMP_TO_EDGE as i32, |
| 36 | + ); |
| 37 | + gl.tex_parameter_i32( |
| 38 | + glow::TEXTURE_2D, |
| 39 | + glow::TEXTURE_WRAP_T, |
| 40 | + glow::CLAMP_TO_EDGE as i32, |
| 41 | + ); |
| 42 | + if is_webgl_1 { |
| 43 | + let format = if srgb_support { |
| 44 | + glow::SRGB_ALPHA |
| 45 | + } else { |
| 46 | + glow::RGBA |
| 47 | + }; |
| 48 | + gl.tex_image_2d( |
| 49 | + glow::TEXTURE_2D, |
| 50 | + 0, |
| 51 | + format as i32, |
| 52 | + w as i32, |
| 53 | + h as i32, |
| 54 | + 0, |
| 55 | + format, |
| 56 | + glow::UNSIGNED_BYTE, |
| 57 | + Some(data), |
| 58 | + ); |
| 59 | + } else { |
| 60 | + gl.tex_storage_2d(glow::TEXTURE_2D, 1, glow::SRGB8_ALPHA8, w as i32, h as i32); |
| 61 | + gl.tex_sub_image_2d( |
| 62 | + glow::TEXTURE_2D, |
| 63 | + 0, |
| 64 | + 0, |
| 65 | + 0, |
| 66 | + w as i32, |
| 67 | + h as i32, |
| 68 | + glow::RGBA, |
| 69 | + glow::UNSIGNED_BYTE, |
| 70 | + glow::PixelUnpackData::Slice(data), |
| 71 | + ); |
| 72 | + } |
| 73 | + assert_eq!(gl.get_error(), glow::NO_ERROR, "OpenGL error occurred!"); |
| 74 | + tex |
| 75 | + } |
| 76 | +} |
| 77 | + |
| 78 | +pub(crate) unsafe fn as_u8_slice<T>(s: &[T]) -> &[u8] { |
| 79 | + std::slice::from_raw_parts(s.as_ptr().cast::<u8>(), s.len() * std::mem::size_of::<T>()) |
| 80 | +} |
| 81 | + |
| 82 | +#[cfg(target_arch = "wasm32")] |
| 83 | +pub(crate) fn glow_debug_print(s: impl Into<JsValue>) { |
| 84 | + web_sys::console::log_1(&s.into()); |
| 85 | +} |
| 86 | +#[cfg(not(target_arch = "wasm32"))] |
| 87 | +pub(crate) fn glow_debug_print(s: impl std::fmt::Display) { |
| 88 | + println!("{}", s); |
| 89 | +} |
| 90 | + |
| 91 | +pub(crate) unsafe fn compile_shader( |
| 92 | + gl: &glow::Context, |
| 93 | + shader_type: u32, |
| 94 | + source: &str, |
| 95 | +) -> Result<glow::Shader, String> { |
| 96 | + let shader = gl.create_shader(shader_type)?; |
| 97 | + |
| 98 | + gl.shader_source(shader, source); |
| 99 | + |
| 100 | + gl.compile_shader(shader); |
| 101 | + |
| 102 | + if gl.get_shader_compile_status(shader) { |
| 103 | + Ok(shader) |
| 104 | + } else { |
| 105 | + Err(gl.get_shader_info_log(shader)) |
| 106 | + } |
| 107 | +} |
| 108 | + |
| 109 | +pub(crate) unsafe fn link_program<'a, T: IntoIterator<Item = &'a glow::Shader>>( |
| 110 | + gl: &glow::Context, |
| 111 | + shaders: T, |
| 112 | +) -> Result<glow::Program, String> { |
| 113 | + let program = gl.create_program()?; |
| 114 | + |
| 115 | + for shader in shaders { |
| 116 | + gl.attach_shader(program, *shader); |
| 117 | + } |
| 118 | + |
| 119 | + gl.link_program(program); |
| 120 | + |
| 121 | + if gl.get_program_link_status(program) { |
| 122 | + Ok(program) |
| 123 | + } else { |
| 124 | + Err(gl.get_program_info_log(program)) |
| 125 | + } |
| 126 | +} |
| 127 | +///Wrapper around Emulated VAO and GL's VAO |
| 128 | +pub(crate) enum VAO { |
| 129 | + Emulated(crate::vao_emulate::EmulatedVao), |
| 130 | + Native(crate::glow::VertexArray), |
| 131 | +} |
| 132 | + |
| 133 | +impl VAO { |
| 134 | + pub(crate) unsafe fn native(gl: &glow::Context) -> Self { |
| 135 | + Self::Native(gl.create_vertex_array().unwrap()) |
| 136 | + } |
| 137 | + |
| 138 | + pub(crate) unsafe fn emulated() -> Self { |
| 139 | + Self::Emulated(crate::vao_emulate::EmulatedVao::new()) |
| 140 | + } |
| 141 | + |
| 142 | + pub(crate) unsafe fn bind_vertex_array(&self, gl: &glow::Context) { |
| 143 | + match self { |
| 144 | + VAO::Emulated(vao) => vao.bind_vertex_array(gl), |
| 145 | + VAO::Native(vao) => gl.bind_vertex_array(Some(*vao)), |
| 146 | + } |
| 147 | + } |
| 148 | + |
| 149 | + pub(crate) unsafe fn bind_buffer(&mut self, gl: &glow::Context, buffer: &glow::Buffer) { |
| 150 | + match self { |
| 151 | + VAO::Emulated(vao) => vao.bind_buffer(buffer), |
| 152 | + VAO::Native(_) => gl.bind_buffer(glow::ARRAY_BUFFER, Some(*buffer)), |
| 153 | + } |
| 154 | + } |
| 155 | + |
| 156 | + pub(crate) unsafe fn add_new_attribute( |
| 157 | + &mut self, |
| 158 | + gl: &glow::Context, |
| 159 | + buffer_info: crate::vao_emulate::BufferInfo, |
| 160 | + ) { |
| 161 | + match self { |
| 162 | + VAO::Emulated(vao) => vao.add_new_attribute(buffer_info), |
| 163 | + VAO::Native(_) => { |
| 164 | + gl.vertex_attrib_pointer_f32( |
| 165 | + buffer_info.location, |
| 166 | + buffer_info.vector_size, |
| 167 | + buffer_info.data_type, |
| 168 | + buffer_info.normalized, |
| 169 | + buffer_info.stride, |
| 170 | + buffer_info.offset, |
| 171 | + ); |
| 172 | + gl.enable_vertex_attrib_array(buffer_info.location); |
| 173 | + } |
| 174 | + } |
| 175 | + } |
| 176 | + |
| 177 | + pub(crate) unsafe fn unbind_vertex_array(&self, gl: &glow::Context) { |
| 178 | + match self { |
| 179 | + VAO::Emulated(vao) => vao.unbind_vertex_array(gl), |
| 180 | + VAO::Native(_) => { |
| 181 | + gl.bind_vertex_array(None); |
| 182 | + } |
| 183 | + } |
| 184 | + } |
| 185 | +} |
| 186 | + |
| 187 | +pub(crate) unsafe fn need_to_emulate_vao(gl: &glow::Context) -> bool { |
| 188 | + let web_sig = "WebGL "; |
| 189 | + let es_sig = "OpenGL ES "; |
| 190 | + let version_string = gl.get_parameter_string(glow::VERSION); |
| 191 | + if let Some(pos) = version_string.rfind(web_sig) { |
| 192 | + let version_str = &version_string[pos + web_sig.len()..]; |
| 193 | + glow_debug_print(format!( |
| 194 | + "detected WebGL prefix at {}:{}", |
| 195 | + pos + web_sig.len(), |
| 196 | + version_str |
| 197 | + )); |
| 198 | + if version_str.contains("1.0") { |
| 199 | + //need to test OES_vertex_array_object . |
| 200 | + gl.supported_extensions() |
| 201 | + .contains("OES_vertex_array_object") |
| 202 | + } else { |
| 203 | + false |
| 204 | + } |
| 205 | + } else if let Some(pos) = version_string.rfind(es_sig) { |
| 206 | + //glow targets es2.0+ so we don't concern about OpenGL ES-CM,OpenGL ES-CL |
| 207 | + glow_debug_print(format!( |
| 208 | + "detected OpenGL ES prefix at {}:{}", |
| 209 | + pos + es_sig.len(), |
| 210 | + &version_string[pos + es_sig.len()..] |
| 211 | + )); |
| 212 | + if version_string.contains("2.0") { |
| 213 | + //need to test OES_vertex_array_object . |
| 214 | + gl.supported_extensions() |
| 215 | + .contains("OES_vertex_array_object") |
| 216 | + } else { |
| 217 | + false |
| 218 | + } |
| 219 | + } else { |
| 220 | + glow_debug_print(format!("detected OpenGL:{}", version_string)); |
| 221 | + //from OpenGL 3 vao into core |
| 222 | + if version_string.starts_with('2') { |
| 223 | + // I found APPLE_vertex_array_object , GL_ATI_vertex_array_object ,ARB_vertex_array_object |
| 224 | + // but APPLE's and ATI's very old extension. |
| 225 | + gl.supported_extensions() |
| 226 | + .contains("ARB_vertex_array_object") |
| 227 | + } else { |
| 228 | + false |
| 229 | + } |
| 230 | + } |
| 231 | +} |
0 commit comments