Handle more than 2^16 vertices in WebGL renderer
This commit is contained in:
parent
0ba687f521
commit
0be9722af5
|
|
@ -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<Mesh> {
|
||||
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)]
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<u16> = mesh.indices.iter().map(|idx| *idx as u16).collect();
|
||||
|
||||
let mut positions: Vec<f32> = 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::<WebAssembly::Memory>()?
|
||||
.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(())
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue