-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make egui_glow painter to work on web (#868)
Add WebGL1 and WebGL2 support to glow painter. Add "glow" feature to egui_web to use the glow painter there. Make winit an optional part of egui_glow
- Loading branch information
1 parent
1dbe608
commit 804722a
Showing
21 changed files
with
1,093 additions
and
318 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,231 @@ | ||
#![allow(unsafe_code)] | ||
use glow::HasContext; | ||
use std::option::Option::Some; | ||
#[cfg(target_arch = "wasm32")] | ||
use wasm_bindgen::JsValue; | ||
|
||
pub(crate) fn srgbtexture2d( | ||
gl: &glow::Context, | ||
is_webgl_1: bool, | ||
srgb_support: bool, | ||
data: &[u8], | ||
w: usize, | ||
h: usize, | ||
) -> glow::Texture { | ||
assert_eq!(data.len(), w * h * 4); | ||
assert!(w >= 1); | ||
assert!(h >= 1); | ||
unsafe { | ||
let tex = gl.create_texture().unwrap(); | ||
gl.bind_texture(glow::TEXTURE_2D, Some(tex)); | ||
|
||
gl.tex_parameter_i32( | ||
glow::TEXTURE_2D, | ||
glow::TEXTURE_MAG_FILTER, | ||
glow::LINEAR as i32, | ||
); | ||
gl.tex_parameter_i32( | ||
glow::TEXTURE_2D, | ||
glow::TEXTURE_MIN_FILTER, | ||
glow::LINEAR as i32, | ||
); | ||
gl.tex_parameter_i32( | ||
glow::TEXTURE_2D, | ||
glow::TEXTURE_WRAP_S, | ||
glow::CLAMP_TO_EDGE as i32, | ||
); | ||
gl.tex_parameter_i32( | ||
glow::TEXTURE_2D, | ||
glow::TEXTURE_WRAP_T, | ||
glow::CLAMP_TO_EDGE as i32, | ||
); | ||
if is_webgl_1 { | ||
let format = if srgb_support { | ||
glow::SRGB_ALPHA | ||
} else { | ||
glow::RGBA | ||
}; | ||
gl.tex_image_2d( | ||
glow::TEXTURE_2D, | ||
0, | ||
format as i32, | ||
w as i32, | ||
h as i32, | ||
0, | ||
format, | ||
glow::UNSIGNED_BYTE, | ||
Some(data), | ||
); | ||
} else { | ||
gl.tex_storage_2d(glow::TEXTURE_2D, 1, glow::SRGB8_ALPHA8, w as i32, h as i32); | ||
gl.tex_sub_image_2d( | ||
glow::TEXTURE_2D, | ||
0, | ||
0, | ||
0, | ||
w as i32, | ||
h as i32, | ||
glow::RGBA, | ||
glow::UNSIGNED_BYTE, | ||
glow::PixelUnpackData::Slice(data), | ||
); | ||
} | ||
assert_eq!(gl.get_error(), glow::NO_ERROR, "OpenGL error occurred!"); | ||
tex | ||
} | ||
} | ||
|
||
pub(crate) unsafe fn as_u8_slice<T>(s: &[T]) -> &[u8] { | ||
std::slice::from_raw_parts(s.as_ptr().cast::<u8>(), s.len() * std::mem::size_of::<T>()) | ||
} | ||
|
||
#[cfg(target_arch = "wasm32")] | ||
pub(crate) fn glow_debug_print(s: impl Into<JsValue>) { | ||
web_sys::console::log_1(&s.into()); | ||
} | ||
#[cfg(not(target_arch = "wasm32"))] | ||
pub(crate) fn glow_debug_print(s: impl std::fmt::Display) { | ||
println!("{}", s); | ||
} | ||
|
||
pub(crate) unsafe fn compile_shader( | ||
gl: &glow::Context, | ||
shader_type: u32, | ||
source: &str, | ||
) -> Result<glow::Shader, String> { | ||
let shader = gl.create_shader(shader_type)?; | ||
|
||
gl.shader_source(shader, source); | ||
|
||
gl.compile_shader(shader); | ||
|
||
if gl.get_shader_compile_status(shader) { | ||
Ok(shader) | ||
} else { | ||
Err(gl.get_shader_info_log(shader)) | ||
} | ||
} | ||
|
||
pub(crate) unsafe fn link_program<'a, T: IntoIterator<Item = &'a glow::Shader>>( | ||
gl: &glow::Context, | ||
shaders: T, | ||
) -> Result<glow::Program, String> { | ||
let program = gl.create_program()?; | ||
|
||
for shader in shaders { | ||
gl.attach_shader(program, *shader); | ||
} | ||
|
||
gl.link_program(program); | ||
|
||
if gl.get_program_link_status(program) { | ||
Ok(program) | ||
} else { | ||
Err(gl.get_program_info_log(program)) | ||
} | ||
} | ||
///Wrapper around Emulated VAO and GL's VAO | ||
pub(crate) enum VAO { | ||
Emulated(crate::vao_emulate::EmulatedVao), | ||
Native(crate::glow::VertexArray), | ||
} | ||
|
||
impl VAO { | ||
pub(crate) unsafe fn native(gl: &glow::Context) -> Self { | ||
Self::Native(gl.create_vertex_array().unwrap()) | ||
} | ||
|
||
pub(crate) unsafe fn emulated() -> Self { | ||
Self::Emulated(crate::vao_emulate::EmulatedVao::new()) | ||
} | ||
|
||
pub(crate) unsafe fn bind_vertex_array(&self, gl: &glow::Context) { | ||
match self { | ||
VAO::Emulated(vao) => vao.bind_vertex_array(gl), | ||
VAO::Native(vao) => gl.bind_vertex_array(Some(*vao)), | ||
} | ||
} | ||
|
||
pub(crate) unsafe fn bind_buffer(&mut self, gl: &glow::Context, buffer: &glow::Buffer) { | ||
match self { | ||
VAO::Emulated(vao) => vao.bind_buffer(buffer), | ||
VAO::Native(_) => gl.bind_buffer(glow::ARRAY_BUFFER, Some(*buffer)), | ||
} | ||
} | ||
|
||
pub(crate) unsafe fn add_new_attribute( | ||
&mut self, | ||
gl: &glow::Context, | ||
buffer_info: crate::vao_emulate::BufferInfo, | ||
) { | ||
match self { | ||
VAO::Emulated(vao) => vao.add_new_attribute(buffer_info), | ||
VAO::Native(_) => { | ||
gl.vertex_attrib_pointer_f32( | ||
buffer_info.location, | ||
buffer_info.vector_size, | ||
buffer_info.data_type, | ||
buffer_info.normalized, | ||
buffer_info.stride, | ||
buffer_info.offset, | ||
); | ||
gl.enable_vertex_attrib_array(buffer_info.location); | ||
} | ||
} | ||
} | ||
|
||
pub(crate) unsafe fn unbind_vertex_array(&self, gl: &glow::Context) { | ||
match self { | ||
VAO::Emulated(vao) => vao.unbind_vertex_array(gl), | ||
VAO::Native(_) => { | ||
gl.bind_vertex_array(None); | ||
} | ||
} | ||
} | ||
} | ||
|
||
pub(crate) unsafe fn need_to_emulate_vao(gl: &glow::Context) -> bool { | ||
let web_sig = "WebGL "; | ||
let es_sig = "OpenGL ES "; | ||
let version_string = gl.get_parameter_string(glow::VERSION); | ||
if let Some(pos) = version_string.rfind(web_sig) { | ||
let version_str = &version_string[pos + web_sig.len()..]; | ||
glow_debug_print(format!( | ||
"detected WebGL prefix at {}:{}", | ||
pos + web_sig.len(), | ||
version_str | ||
)); | ||
if version_str.contains("1.0") { | ||
//need to test OES_vertex_array_object . | ||
gl.supported_extensions() | ||
.contains("OES_vertex_array_object") | ||
} else { | ||
false | ||
} | ||
} else if let Some(pos) = version_string.rfind(es_sig) { | ||
//glow targets es2.0+ so we don't concern about OpenGL ES-CM,OpenGL ES-CL | ||
glow_debug_print(format!( | ||
"detected OpenGL ES prefix at {}:{}", | ||
pos + es_sig.len(), | ||
&version_string[pos + es_sig.len()..] | ||
)); | ||
if version_string.contains("2.0") { | ||
//need to test OES_vertex_array_object . | ||
gl.supported_extensions() | ||
.contains("OES_vertex_array_object") | ||
} else { | ||
false | ||
} | ||
} else { | ||
glow_debug_print(format!("detected OpenGL:{}", version_string)); | ||
//from OpenGL 3 vao into core | ||
if version_string.starts_with('2') { | ||
// I found APPLE_vertex_array_object , GL_ATI_vertex_array_object ,ARB_vertex_array_object | ||
// but APPLE's and ATI's very old extension. | ||
gl.supported_extensions() | ||
.contains("ARB_vertex_array_object") | ||
} else { | ||
false | ||
} | ||
} | ||
} |
Oops, something went wrong.