diff --git a/Cargo.toml b/Cargo.toml index 3830558..9ebdc75 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,13 +13,7 @@ js-sys = "0.3.70" [dependencies.web-sys] version = "0.3.4" -features = [ - 'Document', - 'Element', - 'HtmlElement', - 'Node', - 'Window', -] +features = ["Document", "Element", "HtmlElement", "Node", "Window", "HtmlCanvasElement", "WebGlBuffer", "WebGlVertexArrayObject", "WebGl2RenderingContext", "WebGlProgram", "WebGlShader"] [lib] crate-type = ["cdylib", "rlib"] diff --git a/index.html b/index.html index 4897314..6b6916a 100644 --- a/index.html +++ b/index.html @@ -1,56 +1,10 @@ + + - diff --git a/index2.html b/index2.html index a6d22ca..af71dcc 100644 --- a/index2.html +++ b/index2.html @@ -9,7 +9,7 @@ integrity="sha512-zhHQR0/H5SEBL3Wn6yYSaTTZej12z0hVZKOv3TwCUXT1z5qeqGcXJLLrbERYRScEDDpYIJhPC1fk31gqR783iQ==" crossorigin="anonymous" defer> - + diff --git a/index_back.html b/index_back.html new file mode 100644 index 0000000..4897314 --- /dev/null +++ b/index_back.html @@ -0,0 +1,56 @@ + + + + + + + + + diff --git a/src/lib.rs b/src/lib.rs index 3f365b5..2515234 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,24 +1,147 @@ use wasm_bindgen::prelude::*; +use web_sys::{WebGl2RenderingContext, WebGlProgram, WebGlShader}; -// Called when the wasm module is instantiated #[wasm_bindgen(start)] -fn main() -> Result<(), JsValue> { - // Use `web_sys`'s global `window` function to get a handle on the global - // window object. - let window = web_sys::window().expect("no global `window` exists"); - let document = window.document().expect("should have a document on window"); - let body = document.body().expect("document should have a body"); +fn start() -> Result<(), JsValue> { + let document = web_sys::window().unwrap().document().unwrap(); + let canvas = document.get_element_by_id("canvas").unwrap(); + let canvas: web_sys::HtmlCanvasElement = canvas.dyn_into::()?; - // Manufacture the element we're gonna append - let val = document.create_element("p")?; - val.set_inner_html("Hello from Rust!"); + let context = canvas + .get_context("webgl2")? + .unwrap() + .dyn_into::()?; - body.append_child(&val)?; + let vert_shader = compile_shader( + &context, + WebGl2RenderingContext::VERTEX_SHADER, + r##"#version 300 es + + in vec4 position; + + void main() { + + gl_Position = position; + } + "##, + )?; + + let frag_shader = compile_shader( + &context, + WebGl2RenderingContext::FRAGMENT_SHADER, + r##"#version 300 es + + precision highp float; + out vec4 outColor; + + void main() { + outColor = vec4(1, 1, 1, 1); + } + "##, + )?; + let program = link_program(&context, &vert_shader, &frag_shader)?; + context.use_program(Some(&program)); + + let vertices: [f32; 9] = [-0.7, -0.7, 0.0, 0.7, -0.7, 0.0, 0.0, 0.7, 0.0]; + + let position_attribute_location = context.get_attrib_location(&program, "position"); + let buffer = context.create_buffer().ok_or("Failed to create buffer")?; + context.bind_buffer(WebGl2RenderingContext::ARRAY_BUFFER, Some(&buffer)); + + // Note that `Float32Array::view` is somewhat dangerous (hence the + // `unsafe`!). This is creating a raw view into our module's + // `WebAssembly.Memory` buffer, but if we allocate more pages for ourself + // (aka do a memory allocation in Rust) it'll cause the buffer to change, + // causing the `Float32Array` to be invalid. + // + // As a result, after `Float32Array::view` we have to be very careful not to + // do any memory allocations before it's dropped. + unsafe { + let positions_array_buf_view = js_sys::Float32Array::view(&vertices); + + context.buffer_data_with_array_buffer_view( + WebGl2RenderingContext::ARRAY_BUFFER, + &positions_array_buf_view, + WebGl2RenderingContext::STATIC_DRAW, + ); + } + + let vao = context + .create_vertex_array() + .ok_or("Could not create vertex array object")?; + context.bind_vertex_array(Some(&vao)); + + context.vertex_attrib_pointer_with_i32( + position_attribute_location as u32, + 3, + WebGl2RenderingContext::FLOAT, + false, + 0, + 0, + ); + context.enable_vertex_attrib_array(position_attribute_location as u32); + + context.bind_vertex_array(Some(&vao)); + + let vert_count = (vertices.len() / 3) as i32; + draw(&context, vert_count); Ok(()) } -#[wasm_bindgen] -pub fn add(a: u32, b: u32) -> u32 { - a + b +fn draw(context: &WebGl2RenderingContext, vert_count: i32) { + context.clear_color(0.0, 0.0, 0.0, 1.0); + context.clear(WebGl2RenderingContext::COLOR_BUFFER_BIT); + + context.draw_arrays(WebGl2RenderingContext::TRIANGLES, 0, vert_count); +} + +pub fn compile_shader( + context: &WebGl2RenderingContext, + shader_type: u32, + source: &str, +) -> Result { + let shader = context + .create_shader(shader_type) + .ok_or_else(|| String::from("Unable to create shader object"))?; + context.shader_source(&shader, source); + context.compile_shader(&shader); + + if context + .get_shader_parameter(&shader, WebGl2RenderingContext::COMPILE_STATUS) + .as_bool() + .unwrap_or(false) + { + Ok(shader) + } else { + Err(context + .get_shader_info_log(&shader) + .unwrap_or_else(|| String::from("Unknown error creating shader"))) + } +} + +pub fn link_program( + context: &WebGl2RenderingContext, + vert_shader: &WebGlShader, + frag_shader: &WebGlShader, +) -> Result { + let program = context + .create_program() + .ok_or_else(|| String::from("Unable to create shader object"))?; + + context.attach_shader(&program, vert_shader); + context.attach_shader(&program, frag_shader); + context.link_program(&program); + + if context + .get_program_parameter(&program, WebGl2RenderingContext::LINK_STATUS) + .as_bool() + .unwrap_or(false) + { + Ok(program) + } else { + Err(context + .get_program_info_log(&program) + .unwrap_or_else(|| String::from("Unknown error creating program object"))) + } } diff --git a/webgl-demo.js b/webgl-demo.js index 66c685e..d4ddae9 100644 --- a/webgl-demo.js +++ b/webgl-demo.js @@ -89,7 +89,7 @@ function bind2DFloat32Data(positions) { function main() { const canvas = document.querySelector("#glcanvas"); // Initialize the GL context - gl = canvas.getContext("webgl"); + gl = canvas.getContext("webgl2"); // Only continue if WebGL is available and working if (gl === null) { @@ -106,12 +106,12 @@ function main() { `; const fsSource = ` void main() { - gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); + gl_FragColor = vec4(0, 1.0, 0, 1.0); } `; const shaderProgram = compileLinkProgram(vsSource, fsSource); const positions = [0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, -0.5]; - + const vao = bind2DFloat32Data(positions); // Set clear color to black, fully opaqe gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear the color buffer with specified clear color