diff --git a/emigui/src/mesher.rs b/emigui/src/mesher.rs index a09c6462..575471a8 100644 --- a/emigui/src/mesher.rs +++ b/emigui/src/mesher.rs @@ -41,6 +41,8 @@ impl Mesh { /// Uniformly colored rectangle pub fn add_rect(&mut self, top_left: Vertex, bottom_right: Vertex) { + debug_assert_eq!(top_left.color, bottom_right.color); + let idx = self.vertices.len() as u32; self.triangle(idx + 0, idx + 1, idx + 2); self.triangle(idx + 2, idx + 1, idx + 3); @@ -60,6 +62,58 @@ impl Mesh { self.vertices.push(botom_left); self.vertices.push(bottom_right); } + + /// Split a large mesh into many small. + /// All the returned meshes will have indices that fit into u16. + pub fn split_to_u16(self) -> Vec { + const MAX_SIZE: u32 = 1 << 16; + + if self.vertices.len() < MAX_SIZE as usize { + return vec![self]; // Common-case optimization + } + + let mut output = vec![]; + let mut index_cursor = 0; + + while index_cursor < self.indices.len() { + let span_start = index_cursor; + let mut min_vindex = self.indices[index_cursor]; + let mut max_vindex = self.indices[index_cursor]; + + while index_cursor < self.indices.len() { + let (mut new_min, mut new_max) = (min_vindex, max_vindex); + for i in 0..3 { + let idx = self.indices[index_cursor + i]; + new_min = new_min.min(idx); + new_max = new_max.max(idx); + } + + if new_max - new_min < MAX_SIZE { + // Triangle fits + min_vindex = new_min; + max_vindex = new_max; + index_cursor += 3; + } else { + break; + } + } + + assert!( + index_cursor > span_start, + "One triangle spanned more than {} vertices", + MAX_SIZE + ); + + output.push(Mesh { + indices: self.indices[span_start..index_cursor] + .iter() + .map(|vi| vi - min_vindex) + .collect(), + vertices: self.vertices[(min_vindex as usize)..=(max_vindex as usize)].to_vec(), + }); + } + return output; + } } #[derive(Clone, Copy, PartialEq)] diff --git a/emigui/src/types.rs b/emigui/src/types.rs index 7e601196..543c9f2b 100644 --- a/emigui/src/types.rs +++ b/emigui/src/types.rs @@ -60,7 +60,7 @@ impl GuiInput { // ---------------------------------------------------------------------------- /// 0-255 sRGBA -#[derive(Clone, Copy, Debug, Default, Serialize)] +#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd, Serialize)] pub struct Color { pub r: u8, pub g: u8, diff --git a/emigui_wasm/src/webgl.rs b/emigui_wasm/src/webgl.rs index fc45aeb8..0735d306 100644 --- a/emigui_wasm/src/webgl.rs +++ b/emigui_wasm/src/webgl.rs @@ -145,7 +145,7 @@ impl Painter { pub fn paint( &mut self, - mesh: &Mesh, + mesh: Mesh, texture: &Texture, pixels_per_point: f32, ) -> Result<(), JsValue> { @@ -153,16 +153,49 @@ impl Painter { let gl = &self.gl; - // -------------------------------------------------------------------- - gl.enable(Gl::BLEND); gl.blend_func(Gl::SRC_ALPHA, Gl::ONE_MINUS_SRC_ALPHA); gl.use_program(Some(&self.program)); gl.active_texture(Gl::TEXTURE0); gl.bind_texture(Gl::TEXTURE_2D, Some(&self.texture)); - // -------------------------------------------------------------------- + let u_screen_size_loc = gl + .get_uniform_location(&self.program, "u_screen_size") + .unwrap(); + gl.uniform2f( + Some(&u_screen_size_loc), + self.canvas.width() as f32 / pixels_per_point, + self.canvas.height() as f32 / pixels_per_point, + ); + let u_tex_size_loc = gl + .get_uniform_location(&self.program, "u_tex_size") + .unwrap(); + gl.uniform2f( + Some(&u_tex_size_loc), + f32::from(self.tex_size.0), + f32::from(self.tex_size.1), + ); + + let u_sampler_loc = gl.get_uniform_location(&self.program, "u_sampler").unwrap(); + gl.uniform1i(Some(&u_sampler_loc), 0); + + gl.viewport( + 0, + 0, + self.canvas.width() as i32, + self.canvas.height() as i32, + ); + gl.clear_color(0.05, 0.05, 0.05, 1.0); + gl.clear(Gl::COLOR_BUFFER_BIT); + + for mesh in mesh.split_to_u16() { + self.paint_mesh(&mesh)?; + } + Ok(()) + } + + fn paint_mesh(&mut self, mesh: &Mesh) -> Result<(), JsValue> { let indices: Vec = mesh.indices.iter().map(|idx| *idx as u16).collect(); let mut positions: Vec = Vec::with_capacity(2 * mesh.vertices.len()); @@ -184,6 +217,8 @@ impl Painter { // -------------------------------------------------------------------- + let gl = &self.gl; + let indices_memory_buffer = wasm_bindgen::memory() .dyn_into::()? .buffer(); @@ -280,36 +315,6 @@ impl Painter { // -------------------------------------------------------------------- - let u_screen_size_loc = gl - .get_uniform_location(&self.program, "u_screen_size") - .unwrap(); - gl.uniform2f( - Some(&u_screen_size_loc), - self.canvas.width() as f32 / pixels_per_point, - self.canvas.height() as f32 / pixels_per_point, - ); - - let u_tex_size_loc = gl - .get_uniform_location(&self.program, "u_tex_size") - .unwrap(); - gl.uniform2f( - Some(&u_tex_size_loc), - f32::from(self.tex_size.0), - f32::from(self.tex_size.1), - ); - - let u_sampler_loc = gl.get_uniform_location(&self.program, "u_sampler").unwrap(); - gl.uniform1i(Some(&u_sampler_loc), 0); - - gl.viewport( - 0, - 0, - self.canvas.width() as i32, - self.canvas.height() as i32, - ); - gl.clear_color(0.05, 0.05, 0.05, 1.0); - gl.clear(Gl::COLOR_BUFFER_BIT); - gl.draw_elements_with_i32(Gl::TRIANGLES, indices.len() as i32, Gl::UNSIGNED_SHORT, 0); Ok(()) diff --git a/example/src/lib.rs b/example/src/lib.rs index 93d854a9..c20acba0 100644 --- a/example/src/lib.rs +++ b/example/src/lib.rs @@ -53,7 +53,7 @@ impl State { let mesh = self.emigui.paint(); let result = self.webgl_painter - .paint(&mesh, self.emigui.texture(), raw_input.pixels_per_point); + .paint(mesh, self.emigui.texture(), raw_input.pixels_per_point); self.everything_ms = 1000.0 * (now_sec() - everything_start);