Skip to content

Create basic WebGL example #835

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ members = [
"examples/smorgasboard",
"examples/wasm-in-wasm",
"examples/webaudio",
"examples/webgl",
"tests/no-std",
]

Expand Down
4 changes: 4 additions & 0 deletions examples/webgl/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package-lock.json
wasm_bindgen_webgl_demo.js
wasm_bindgen_webgl_demo_bg.js
wasm_bindgen_webgl_demo_bg.wasm
24 changes: 24 additions & 0 deletions examples/webgl/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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',
]
15 changes: 15 additions & 0 deletions examples/webgl/README.md
Original file line number Diff line number Diff line change
@@ -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.
15 changes: 15 additions & 0 deletions examples/webgl/build.sh
Original file line number Diff line number Diff line change
@@ -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
9 changes: 9 additions & 0 deletions examples/webgl/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
</head>
<body>
<canvas id="canvas" height="150" width="150" />
<script src='./index.js'></script>
</body>
</html>
5 changes: 5 additions & 0 deletions examples/webgl/index.js
Original file line number Diff line number Diff line change
@@ -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();
});
11 changes: 11 additions & 0 deletions examples/webgl/package.json
Original file line number Diff line number Diff line change
@@ -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"
}
}
121 changes: 121 additions & 0 deletions examples/webgl/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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::<web_sys::HtmlCanvasElement>()
.map_err(|_| ())
.unwrap();

let context = canvas
.get_context("webgl")
.unwrap()
.unwrap()
.dyn_into::<WebGlRenderingContext>()
.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<WebGlShader, String> {
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<Item = &'a WebGlShader>>(
context: &WebGlRenderingContext,
shaders: T,
) -> Result<WebGlProgram, String> {
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()))
}
}
16 changes: 16 additions & 0 deletions examples/webgl/webpack.config.js
Original file line number Diff line number Diff line change
@@ -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'
};
1 change: 1 addition & 0 deletions guide/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,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)

--------------------------------------------------------------------------------
Expand Down
25 changes: 25 additions & 0 deletions guide/src/web-sys/examples/webgl.md
Original file line number Diff line number Diff line change
@@ -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}}
```