diff --git a/Cargo.toml b/Cargo.toml index 3c785576..2ce49eb4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -78,6 +78,7 @@ members = [ "examples/smorgasboard", "examples/wasm-in-wasm", "examples/webaudio", + "examples/webgl", "tests/no-std", ] diff --git a/examples/webgl/.gitignore b/examples/webgl/.gitignore new file mode 100755 index 00000000..fc819eeb --- /dev/null +++ b/examples/webgl/.gitignore @@ -0,0 +1,4 @@ +package-lock.json +wasm_bindgen_webgl_demo.js +wasm_bindgen_webgl_demo_bg.js +wasm_bindgen_webgl_demo_bg.wasm diff --git a/examples/webgl/Cargo.toml b/examples/webgl/Cargo.toml new file mode 100755 index 00000000..7dd6581f --- /dev/null +++ b/examples/webgl/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "wasm-bindgen-webgl-demo" +version = "0.1.0" +authors = ["The wasm-bindgen Developers"] + +[lib] +crate-type = ["cdylib"] + +[dependencies] +js-sys = { path = "../../crates/js-sys" } +wasm-bindgen = { path = "../.." } + +[dependencies.web-sys] +path = "../../crates/web-sys" +features = [ + 'Document', + 'Element', + 'HtmlCanvasElement', + 'WebGlBuffer', + 'WebGlRenderingContext', + 'WebGlProgram', + 'WebGlShader', + 'Window', +] diff --git a/examples/webgl/README.md b/examples/webgl/README.md new file mode 100755 index 00000000..b31d41c7 --- /dev/null +++ b/examples/webgl/README.md @@ -0,0 +1,15 @@ +# WebGL Example + +This directory is an example of using the `web-sys` crate to interact with +a WebGL context. + +You can build and run the example with: + +``` +$ ./build.sh +``` + +(or running the commands on Windows manually) + +and then opening up `http://localhost:8080/` in a web browser should show a +nice triangle. diff --git a/examples/webgl/build.sh b/examples/webgl/build.sh new file mode 100755 index 00000000..55a54b0e --- /dev/null +++ b/examples/webgl/build.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +# For more coments about what's going on here, see the `hello_world` example + +set -ex +cd "$(dirname $0)" + +cargo +nightly build --target wasm32-unknown-unknown + +cargo +nightly run --manifest-path ../../crates/cli/Cargo.toml \ + --bin wasm-bindgen -- \ + ../../target/wasm32-unknown-unknown/debug/wasm_bindgen_webgl_demo.wasm --out-dir . + +npm install +npm run serve diff --git a/examples/webgl/index.html b/examples/webgl/index.html new file mode 100755 index 00000000..c13b999e --- /dev/null +++ b/examples/webgl/index.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/examples/webgl/index.js b/examples/webgl/index.js new file mode 100755 index 00000000..cb5f7a9a --- /dev/null +++ b/examples/webgl/index.js @@ -0,0 +1,5 @@ +// For more comments about what's going on here, check out the `hello_world` +// example. +import('./wasm_bindgen_webgl_demo').then(webgl => { + webgl.draw(); +}); diff --git a/examples/webgl/package.json b/examples/webgl/package.json new file mode 100755 index 00000000..176a69a4 --- /dev/null +++ b/examples/webgl/package.json @@ -0,0 +1,11 @@ +{ + "scripts": { + "serve": "webpack-dev-server" + }, + "devDependencies": { + "html-webpack-plugin": "^3.2.0", + "webpack": "^4.11.1", + "webpack-cli": "^2.0.10", + "webpack-dev-server": "^3.1.0" + } +} diff --git a/examples/webgl/src/lib.rs b/examples/webgl/src/lib.rs new file mode 100755 index 00000000..d584f71d --- /dev/null +++ b/examples/webgl/src/lib.rs @@ -0,0 +1,121 @@ +extern crate js_sys; +extern crate wasm_bindgen; +extern crate web_sys; + +use wasm_bindgen::prelude::*; +use wasm_bindgen::JsCast; +use web_sys::{WebGlProgram, WebGlRenderingContext, WebGlShader}; + +#[wasm_bindgen] +pub fn draw() { + let document = web_sys::Window::document().unwrap(); + let canvas = document.get_element_by_id("canvas").unwrap(); + let canvas: web_sys::HtmlCanvasElement = canvas + .dyn_into::() + .map_err(|_| ()) + .unwrap(); + + let context = canvas + .get_context("webgl") + .unwrap() + .unwrap() + .dyn_into::() + .unwrap(); + + let vert_shader = compile_shader( + &context, + WebGlRenderingContext::VERTEX_SHADER, + r#" + attribute vec4 position; + void main() { + gl_Position = position; + } + "#, + ).unwrap(); + let frag_shader = compile_shader( + &context, + WebGlRenderingContext::FRAGMENT_SHADER, + r#" + void main() { + gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); + } + "#, + ).unwrap(); + let program = link_program(&context, [vert_shader, frag_shader].iter()).unwrap(); + context.use_program(Some(&program)); + + let vertices = [-0.7, -0.7, 0.0, 0.7, -0.7, 0.0, 0.0, 0.7, 0.0]; + let vert_array = js_sys::Float32Array::new(&wasm_bindgen::JsValue::from(vertices.len() as u32)); + for (i, f) in vertices.iter().enumerate() { + vert_array.fill(*f, i as u32, (i + 1) as u32); + } + + let buffer = context.create_buffer().unwrap(); + context.bind_buffer(WebGlRenderingContext::ARRAY_BUFFER, Some(&buffer)); + context.buffer_data_with_opt_array_buffer( + WebGlRenderingContext::ARRAY_BUFFER, + Some(&vert_array.buffer()), + WebGlRenderingContext::STATIC_DRAW, + ); + context.vertex_attrib_pointer_with_i32(0, + 3, + WebGlRenderingContext::FLOAT, + false, + 0, + 0); + context.enable_vertex_attrib_array(0); + + context.clear_color(0.0, 0.0, 0.0, 1.0); + context.clear(WebGlRenderingContext::COLOR_BUFFER_BIT); + + context.draw_arrays(WebGlRenderingContext::TRIANGLES, 0, (vertices.len() / 3) as i32); +} + +pub fn compile_shader( + context: &WebGlRenderingContext, + 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, WebGlRenderingContext::COMPILE_STATUS) + .as_bool() + .unwrap_or(false) + { + Ok(shader) + } else { + Err(context + .get_shader_info_log(&shader) + .unwrap_or_else(|| "Unknown error creating shader".into())) + } +} + +pub fn link_program<'a, T: IntoIterator>( + context: &WebGlRenderingContext, + shaders: T, +) -> Result { + let program = context + .create_program() + .ok_or_else(|| String::from("Unable to create shader object"))?; + for shader in shaders { + context.attach_shader(&program, shader) + } + context.link_program(&program); + + if context + .get_program_parameter(&program, WebGlRenderingContext::LINK_STATUS) + .as_bool() + .unwrap_or(false) + { + Ok(program) + } else { + Err(context + .get_program_info_log(&program) + .unwrap_or_else(|| "Unknown error creating program object".into())) + } +} diff --git a/examples/webgl/webpack.config.js b/examples/webgl/webpack.config.js new file mode 100755 index 00000000..453a1a59 --- /dev/null +++ b/examples/webgl/webpack.config.js @@ -0,0 +1,16 @@ +const path = require('path'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); + +module.exports = { + entry: './index.js', + output: { + path: path.resolve(__dirname, 'dist'), + filename: 'index.js', + }, + plugins: [ + new HtmlWebpackPlugin({ + template: "index.html" + }) + ], + mode: 'development' +}; diff --git a/guide/src/SUMMARY.md b/guide/src/SUMMARY.md index 97069f78..8bf8d337 100644 --- a/guide/src/SUMMARY.md +++ b/guide/src/SUMMARY.md @@ -62,6 +62,7 @@ - [The `fetch` API](./web-sys/examples/fetch.md) - [2D Canvas](./web-sys/examples/2d-canvas.md) - [WebAudio](./web-sys/examples/web-audio.md) + - [WebGL](./web-sys/examples/webgl.md) - [A Simple Paint Program](./web-sys/examples/paint.md) -------------------------------------------------------------------------------- diff --git a/guide/src/web-sys/examples/webgl.md b/guide/src/web-sys/examples/webgl.md new file mode 100644 index 00000000..38a886f8 --- /dev/null +++ b/guide/src/web-sys/examples/webgl.md @@ -0,0 +1,25 @@ +# 2D Canvas + +This example draws a triangle to the screen using the WebGL API. + +[See the full source at +`wasm-bindgen/examples/webgl`.](https://github.com/rustwasm/wasm-bindgen/tree/master/examples/webgl) + +## `Cargo.toml` + +The `Cargo.toml` enables features necessary to obtain and use a WebGL +rendering context. + +```toml +{{#include ../../../../examples/webgl/Cargo.toml}} +``` + +## `src/lib.rs` + +This source file handles all of the necessary logic to obtain a rendering +context, compile shaders, fill a buffer with vertex coordinates, and draw a +triangle to the screen. + +```rust +{{#include ../../../../examples/webgl/src/lib.rs}} +```