diff --git a/app-proto/src/display.rs b/app-proto/src/display.rs index 67e36e9..2e9b4f0 100644 --- a/app-proto/src/display.rs +++ b/app-proto/src/display.rs @@ -8,6 +8,7 @@ use web_sys::{ KeyboardEvent, MouseEvent, WebGl2RenderingContext, + WebGlBuffer, WebGlProgram, WebGlShader, WebGlUniformLocation, @@ -81,22 +82,51 @@ fn get_uniform_array_locations( }) } -// load the given data into the vertex input of the given name -fn bind_vertex_attrib( +// find the vertex attribute called `attr_name` in the given program. enable it +// and return its index +fn find_and_enable_attribute( context: &WebGl2RenderingContext, - index: u32, - size: i32, - data: &[f32] + program: &WebGlProgram, + attr_name: &str +) -> u32 { + let attr_index = context.get_attrib_location(program, attr_name) as u32; + context.enable_vertex_attrib_array(attr_index); + attr_index +} + +// bind the given vertex buffer object to the given vertex attribute +fn bind_to_attribute( + context: &WebGl2RenderingContext, + attr_index: u32, + attr_size: i32, + buffer: &Option ) { - // create a data buffer and bind it to ARRAY_BUFFER - let buffer = context.create_buffer().unwrap(); - context.bind_buffer(WebGl2RenderingContext::ARRAY_BUFFER, Some(&buffer)); + context.bind_buffer(WebGl2RenderingContext::ARRAY_BUFFER, buffer.as_ref()); + context.vertex_attrib_pointer_with_i32( + attr_index, + attr_size, + WebGl2RenderingContext::FLOAT, + false, // don't normalize + 0, // zero stride + 0, // zero offset + ); +} + +// load the given data into a new vertex buffer object +fn load_new_buffer( + context: &WebGl2RenderingContext, + data: &[f32] +) -> Option { + // create a buffer and bind it to ARRAY_BUFFER + let buffer = context.create_buffer(); + context.bind_buffer(WebGl2RenderingContext::ARRAY_BUFFER, buffer.as_ref()); - // load the given data into the buffer. the function `Float32Array::view` - // creates a raw view into our module's `WebAssembly.Memory` buffer. - // allocating more memory will change the buffer, invalidating the view. - // that means we have to make sure we don't allocate any memory until the - // view is dropped + // load the given data into the buffer. this block is unsafe because + // `Float32Array::view` creates a raw view into our module's + // `WebAssembly.Memory` buffer. allocating more memory will change the + // buffer, invalidating the view, so we have to make sure we don't allocate + // any memory until the view is dropped. we're okay here because the view is + // used as soon as it's created unsafe { context.buffer_data_with_array_buffer_view( WebGl2RenderingContext::ARRAY_BUFFER, @@ -105,22 +135,7 @@ fn bind_vertex_attrib( ); } - // allow the target attribute to be used - context.enable_vertex_attrib_array(index); - - // take whatever's bound to ARRAY_BUFFER---here, the data buffer created - // above---and bind it to the target attribute - // - // https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/vertexAttribPointer - // - context.vertex_attrib_pointer_with_i32( - index, - size, - WebGl2RenderingContext::FLOAT, - false, // don't normalize - 0, // zero stride - 0, // zero offset - ); + buffer } // the direction in camera space that a mouse event is pointing along @@ -260,9 +275,11 @@ pub fn Display() -> View { &JsValue::from("uniform vectors available") ); - // find indices of sphere vertex attributes and uniforms + // find and enable the sphere program's sole vertex attribute + let viewport_position_attr = find_and_enable_attribute(&ctx, &sphere_program, "position"); + + // find the sphere program's uniforms const SPHERE_MAX: usize = 200; - let viewport_position_index = ctx.get_attrib_location(&sphere_program, "position") as u32; let sphere_cnt_loc = ctx.get_uniform_location(&sphere_program, "sphere_cnt"); let sphere_sp_locs = get_uniform_array_locations::( &ctx, &sphere_program, "sphere_list", Some("sp") @@ -282,7 +299,7 @@ pub fn Display() -> View { let layer_threshold_loc = ctx.get_uniform_location(&sphere_program, "layer_threshold"); let debug_mode_loc = ctx.get_uniform_location(&sphere_program, "debug_mode"); - // set the viewport vertex positions + // load the viewport vertex positions into a new vertex buffer object const VERTEX_CNT: usize = 6; let viewport_positions: [f32; 3*VERTEX_CNT] = [ // northwest triangle @@ -294,9 +311,10 @@ pub fn Display() -> View { 1.0, 1.0, 0.0, 1.0, -1.0, 0.0 ]; + let viewport_position_buffer = load_new_buffer(&ctx, &viewport_positions); - // find indices of point vertex attributes and uniforms - let point_position_index = ctx.get_attrib_location(&point_program, "position") as u32; + // find and enable the point program's sole vertex attribute + let point_position_attr = find_and_enable_attribute(&ctx, &point_program, "position"); // set up a repainting routine let (_, start_animation_loop, _) = create_raf(move || { @@ -512,8 +530,9 @@ pub fn Display() -> View { ctx.uniform1i(layer_threshold_loc.as_ref(), LAYER_THRESHOLD); ctx.uniform1i(debug_mode_loc.as_ref(), DEBUG_MODE); - // pass the viewport vertex positions - bind_vertex_attrib(&ctx, viewport_position_index, 3, &viewport_positions); + // bind the viewport vertex position buffer to the position + // attribute in the vertex shader + bind_to_attribute(&ctx, viewport_position_attr, 3, &viewport_position_buffer); // draw the scene ctx.draw_arrays(WebGl2RenderingContext::TRIANGLES, 0, VERTEX_CNT as i32); @@ -523,8 +542,10 @@ pub fn Display() -> View { // use the point rendering program ctx.use_program(Some(&point_program)); - // pass the point vertex positions - bind_vertex_attrib(&ctx, point_position_index, 3, point_positions.as_slice()); + // load the point positions into a new buffer and bind it to the + // position attribute in the vertex shader + let point_position_buffer = load_new_buffer(&ctx, point_positions.as_slice()); + bind_to_attribute(&ctx, point_position_attr, 3, &point_position_buffer); // draw the scene ctx.draw_arrays(WebGl2RenderingContext::POINTS, 0, point_positions.ncols() as i32);