upgraded to webgl2

This commit is contained in:
dongho
2024-09-03 16:21:56 +09:00
parent f16a721d2d
commit 7bf70c6010
6 changed files with 200 additions and 73 deletions

View File

@ -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"]

View File

@ -1,56 +1,10 @@
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
<script defer src="pkg/ekstrahMap.js"></script>
</head>
<body>
<canvas id="canvas" height="150" width="150">
<!-- Note the usage of `type=module` here as this is an ES6 module -->
<script type="module">
// Use ES module import syntax to import functionality from the module
// that we have compiled.
//
// Note that the `default` import is an initialization function which
// will "boot" the module and make it ready to use. Currently browsers
// don't support natively imported WebAssembly as an ES module, but
// eventually the manual initialization won't be required!
import init, { add } from './pkg/ekstrahMap.js';
async function run() {
// First up we need to actually load the wasm file, so we use the
// default export to inform it where the wasm file is located on the
// server, and then we wait on the returned promise to wait for the
// wasm to be loaded.
//
// It may look like this: `await init('./pkg/without_a_bundler_bg.wasm');`,
// but there is also a handy default inside `init` function, which uses
// `import.meta` to locate the wasm file relatively to js file.
//
// Note that instead of a string you can also pass in any of the
// following things:
//
// * `WebAssembly.Module`
//
// * `ArrayBuffer`
//
// * `Response`
//
// * `Promise` which returns any of the above, e.g. `fetch("./path/to/wasm")`
//
// This gives you complete control over how the module is loaded
// and compiled.
//
// Also note that the promise, when resolved, yields the wasm module's
// exports which is the same as importing the `*_bg` module in other
// modes
await init();
// And afterwards we can use all the functionality defined in wasm.
const result = add(1, 2);
console.log(`1 + 2 = ${result}`);
if (result !== 3)
throw new Error("wasm addition doesn't work!");
}
run();
</script>
</body>
</html>

View File

@ -9,7 +9,7 @@
integrity="sha512-zhHQR0/H5SEBL3Wn6yYSaTTZej12z0hVZKOv3TwCUXT1z5qeqGcXJLLrbERYRScEDDpYIJhPC1fk31gqR783iQ=="
crossorigin="anonymous"
defer></script>
<script src="webgl-demo.js" type="module"></script>
<script src="./webgl-demo.js" type="module"></script>
</head>
<body>
<canvas id="glcanvas" width="640" height="480"></canvas>

56
index_back.html Normal file
View File

@ -0,0 +1,56 @@
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
</head>
<body>
<!-- Note the usage of `type=module` here as this is an ES6 module -->
<script type="module">
// Use ES module import syntax to import functionality from the module
// that we have compiled.
//
// Note that the `default` import is an initialization function which
// will "boot" the module and make it ready to use. Currently browsers
// don't support natively imported WebAssembly as an ES module, but
// eventually the manual initialization won't be required!
import init, { add } from './pkg/ekstrahMap.js';
async function run() {
// First up we need to actually load the wasm file, so we use the
// default export to inform it where the wasm file is located on the
// server, and then we wait on the returned promise to wait for the
// wasm to be loaded.
//
// It may look like this: `await init('./pkg/without_a_bundler_bg.wasm');`,
// but there is also a handy default inside `init` function, which uses
// `import.meta` to locate the wasm file relatively to js file.
//
// Note that instead of a string you can also pass in any of the
// following things:
//
// * `WebAssembly.Module`
//
// * `ArrayBuffer`
//
// * `Response`
//
// * `Promise` which returns any of the above, e.g. `fetch("./path/to/wasm")`
//
// This gives you complete control over how the module is loaded
// and compiled.
//
// Also note that the promise, when resolved, yields the wasm module's
// exports which is the same as importing the `*_bg` module in other
// modes
await init();
// And afterwards we can use all the functionality defined in wasm.
const result = add(1, 2);
console.log(`1 + 2 = ${result}`);
if (result !== 3)
throw new Error("wasm addition doesn't work!");
}
run();
</script>
</body>
</html>

View File

@ -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::<web_sys::HtmlCanvasElement>()?;
// 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::<WebGl2RenderingContext>()?;
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<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, 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<WebGlProgram, String> {
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")))
}
}

View File

@ -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