init: ready, set, go!
This commit is contained in:
commit
04e65b1ea3
|
@ -0,0 +1,6 @@
|
|||
/target
|
||||
/bin
|
||||
/pkg
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
||||
wasm-pack.log
|
|
@ -0,0 +1,27 @@
|
|||
[package]
|
||||
name = "rust-webgl-rectangle"
|
||||
version = "0.1.0"
|
||||
authors = ["thetek <git@thetek.de>"]
|
||||
description = "drawing a colored rectangle using rust, webassembly and webgl"
|
||||
repository = "https://git.tjdev.de/thetek/rust-webgl-rectangle"
|
||||
license = "MIT"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[features]
|
||||
default = ["console_error_panic_hook"]
|
||||
|
||||
[dependencies]
|
||||
wasm-bindgen = "0.2.84"
|
||||
console_error_panic_hook = { version = "0.1.7", optional = true } # better debugging for errors, not great for code size
|
||||
wee_alloc = { version = "0.4.5", optional = true } # smaller, but slower allocator
|
||||
js-sys = "0.3.61"
|
||||
|
||||
[dependencies.web-sys]
|
||||
version = "0.3.61"
|
||||
features = ["Document", "Element", "HtmlCanvasElement", "WebGlBuffer", "WebGlProgram", "WebGl2RenderingContext", "WebGlShader", "WebGlVertexArrayObject", "Window"]
|
||||
|
||||
[profile.release]
|
||||
opt-level = "s" # optimize for small code size
|
|
@ -0,0 +1,25 @@
|
|||
Copyright (c) 2023 thetek <git@thetek.de>
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,342 @@
|
|||
use std::mem::size_of;
|
||||
|
||||
use js_sys::WebAssembly;
|
||||
use wasm_bindgen::{JsCast, JsValue};
|
||||
use web_sys::{
|
||||
HtmlCanvasElement, WebGl2RenderingContext, WebGl2RenderingContext as WebGl, WebGlProgram,
|
||||
WebGlShader,
|
||||
};
|
||||
|
||||
use crate::{f32_array, u16_array, utils};
|
||||
|
||||
/// vertex shader source code
|
||||
const VERT_SRC: &str = include_str!("./shader/vert.glsl");
|
||||
const FRAG_SRC: &str = include_str!("./shader/frag.glsl");
|
||||
|
||||
/// stores game state and other attributes required for running the game, such as the webgl
|
||||
/// rendering context.
|
||||
struct Game {
|
||||
canvas: HtmlCanvasElement,
|
||||
gl: WebGl2RenderingContext,
|
||||
}
|
||||
|
||||
impl Game {
|
||||
/// initialize the canvas by obtaining a valid graphics context
|
||||
fn new() -> Result<Self, JsValue> {
|
||||
let document = web_sys::window().unwrap().document().unwrap();
|
||||
let canvas = document
|
||||
.get_element_by_id("canvas")
|
||||
.ok_or("failed to get canvas element")?
|
||||
.dyn_into::<HtmlCanvasElement>()?;
|
||||
let gl = canvas
|
||||
.get_context("webgl2")?
|
||||
.ok_or("failed to get webgl rendering context")?
|
||||
.dyn_into::<WebGl2RenderingContext>()?;
|
||||
|
||||
Ok(Game { canvas, gl })
|
||||
}
|
||||
|
||||
/// draw the game to the canvas
|
||||
fn draw(&self) -> Result<(), JsValue> {
|
||||
let gl = &self.gl;
|
||||
|
||||
// define vertex data for drawing the rectangle. since opengl is a 3D rendering library,
|
||||
// the coordinates have to be specified as three-dimensional values (x, y and z). since we
|
||||
// only want to draw a two-dimensional scene, the z coordinate will simply be zero. also,
|
||||
// the coordinates are given as normalized device coordinates in order to avoid being
|
||||
// dependant on a single, hard-coded resolution. these coordinates are transformed
|
||||
// according to the values provided to the glViewport function.
|
||||
//
|
||||
// (-1,1) (0,1) (1,1)
|
||||
// ┌───────────┬───────────┐
|
||||
// │ ╷ │
|
||||
// │ ╷ │
|
||||
// (-1,0) ├─ ─ ─ ─ ─(0,0)─ ─ ─ ─ ─┤ (1,0)
|
||||
// │ ╵ │
|
||||
// │ ╵ │
|
||||
// └───────────┴───────────┘
|
||||
// (-1,-1) (0,-1) (1,-1)
|
||||
//
|
||||
// in addition to the coordinates, the colors for the vertices are stored. immediately
|
||||
// after the coordinates. thus, the layout of this data structure is:
|
||||
//
|
||||
// ┌─────────────────┬─────────────────┐
|
||||
// │ coordinates │ color │
|
||||
// │ ╷ ╷ │ ╷ ╷ │
|
||||
// │ X │ Y │ Z │ R │ G │ B │
|
||||
// └─────┴─────┴─────┴─────┴─────┴─────┘
|
||||
//
|
||||
let vertices: [f32; 24] = [
|
||||
-0.5, 0.5, 0.0, 1.0, 0.0, 0.0, //
|
||||
-0.5, -0.5, 0.0, 1.0, 1.0, 0.0, //
|
||||
0.5, -0.5, 0.0, 0.0, 1.0, 0.0, //
|
||||
0.5, 0.5, 0.0, 0.0, 0.0, 1.0, //
|
||||
];
|
||||
let vertices_array = f32_array!(vertices);
|
||||
|
||||
// define the indices of the vertices to draw. since we only defined four vertices in the
|
||||
// vertex array but want to draw a rectangle that consists of two triangles, we need to
|
||||
// specify which vertices should be used for the construction of each triangle. the drawing
|
||||
// below, albeit very minimal due to constrains with the unicode system, shows the
|
||||
// rectangle split up into two triangles labelled with their appropriate vertex indices.
|
||||
//
|
||||
// 0 3
|
||||
// ┌──────────────────┐
|
||||
// │ ¯--_ Δ023 │
|
||||
// │ ¯--_ │
|
||||
// │ ¯--_ │
|
||||
// │ Δ012 ¯--_ │
|
||||
// └──────────────────┘
|
||||
// 1 2
|
||||
//
|
||||
let indices: [u16; 6] = [
|
||||
0, 1, 2, //
|
||||
0, 2, 3, //
|
||||
];
|
||||
let index_array = u16_array!(indices);
|
||||
|
||||
// for sending the vertex data to the gpu, we need to allocate some memory on the gpu where
|
||||
// we can store the data. this memory is managed through vertex buffer objects. with these
|
||||
// buffers, we can send large batches of data to the graphics card. the buffer that we
|
||||
// created is identified by a unique id, which is returned by the glGenBuffer (or in the
|
||||
// case of webgl, gl.create_buffer) function.
|
||||
let vertex_buffer = gl.create_buffer().ok_or("failed to create buffer")?;
|
||||
|
||||
// since opengl supports multiple types of buffers, we need to specify that our vertex
|
||||
// buffer is an array buffer using the glBindBuffer function. opengl allows us to bind
|
||||
// multiple buffers at once, as long as they have a different buffer type. in order to bind
|
||||
// a buffer that has the same buffer type as another already bound buffer, the bound buffer
|
||||
// will have to be unbound before binding the new buffer.
|
||||
gl.bind_buffer(WebGl::ARRAY_BUFFER, Some(&vertex_buffer));
|
||||
|
||||
// after the buffer is bound, any buffer calls will affect the buffer specified in the
|
||||
// glBindBuffer function. through a call to the glBufferData function, we can copy the
|
||||
// previously defined vertex data into the buffer's memory on the gpu. in this case, it
|
||||
// will get copied into the previously created array buffer. the third parameter specifies
|
||||
// how the graphics card should manage the data. STATIC_DRAW specifies that the buffer data
|
||||
// is set only once and used many times. other options include STREAM_DRAW (set once, used
|
||||
// at most a few times) and DYNAMIC_DRAW (data changed often and used many times). the gpu
|
||||
// can then place the buffer in the most suitable location (e.g. a location with faster
|
||||
// writes for DYNAMIC_DRAW).
|
||||
gl.buffer_data_with_array_buffer_view(
|
||||
WebGl::ARRAY_BUFFER,
|
||||
&vertices_array,
|
||||
WebGl::STATIC_DRAW,
|
||||
);
|
||||
|
||||
// similarly, create a buffer that holds the vertex indices. in this case, we have to set
|
||||
// the buffer type to ELEMENT_ARRAY_BUFFER, and not ARRAY_BUFFER as before.
|
||||
let index_buffer = gl.create_buffer().ok_or("failed to create buffer")?;
|
||||
gl.bind_buffer(WebGl::ELEMENT_ARRAY_BUFFER, Some(&index_buffer));
|
||||
gl.buffer_data_with_array_buffer_view(
|
||||
WebGl::ELEMENT_ARRAY_BUFFER,
|
||||
&index_array,
|
||||
WebGl::STATIC_DRAW,
|
||||
);
|
||||
|
||||
// unbind the array and element array buffers
|
||||
gl.bind_buffer(WebGl::ARRAY_BUFFER, None);
|
||||
gl.bind_buffer(WebGl::ELEMENT_ARRAY_BUFFER, None);
|
||||
|
||||
// compile both vertex and fragment shaders. the compilation process is handled by the
|
||||
// compile_shader helper function, see below. note that the shaders are compiled
|
||||
// dynamically at run-time.
|
||||
let vert_shader = self.compile_shader(WebGl::VERTEX_SHADER, VERT_SRC)?;
|
||||
let frag_shader = self.compile_shader(WebGl::FRAGMENT_SHADER, FRAG_SRC)?;
|
||||
|
||||
// both shaders are now compiled. now, they need to be combined in a shader program. the
|
||||
// program linking process is handled by the link_program helper function, see below. when
|
||||
// linking shaders, the output of one shader will be used as the input of the next shader.
|
||||
// when outputs and inputs do not match, linker errors will occur.
|
||||
let shader_program = self.link_program(&vert_shader, &frag_shader)?;
|
||||
|
||||
// activate the shader program by calling glUseProgram. the program's shaders will be used
|
||||
// when rendering objects.
|
||||
gl.use_program(Some(&shader_program));
|
||||
|
||||
// since we do not need the shader objects anymore, they can be deleted.
|
||||
gl.delete_shader(Some(&vert_shader));
|
||||
gl.delete_shader(Some(&frag_shader));
|
||||
|
||||
// introduce and bind a vertex array buffer. this is required in order to add vertex buffer
|
||||
// objects to it and to make the configuration of vertex data and attributes easier.
|
||||
let vao = gl
|
||||
.create_vertex_array()
|
||||
.ok_or("failed to create vertex array object")?;
|
||||
gl.bind_vertex_array(Some(&vao));
|
||||
|
||||
// re-bind the buffers since we unbound them earlier
|
||||
gl.bind_buffer(WebGl::ARRAY_BUFFER, Some(&vertex_buffer));
|
||||
gl.bind_buffer(WebGl::ELEMENT_ARRAY_BUFFER, Some(&index_buffer));
|
||||
|
||||
// we have to specify what part of our input data goes to which vertex attribute in the
|
||||
// vertex shader. this means we have to specify how opengl should interpret the vertex data
|
||||
// before rendering. in this case, the vertex coordinates are specified as three floats,
|
||||
// followed by three values specifying the vertex color. first, we obtain the location of
|
||||
// the `coords` attribute within the vertex shader through the function
|
||||
// glGetAttribLocation, which will be used later for the glVertexAttribPointer function.
|
||||
let coord_attrib = gl.get_attrib_location(&shader_program, "aCoord") as u32;
|
||||
let color_attrib = gl.get_attrib_location(&shader_program, "aColor") as u32;
|
||||
|
||||
// with knowledge of our data layout and attribute locations, we can tell opengl how it
|
||||
// should interpret the data. the parameters glVertexAttribPointer function are as follows:
|
||||
// - index: specifies which vertex attribute we want to configure, in this case `aCoord`
|
||||
// and `aColor`
|
||||
// - size: size of the vertex attribute, in this case 3 since the attribute is a vec3
|
||||
// - type: type of the data, in this case float (f32), since vec3 consists of floats
|
||||
// - normalized: specifies if integer data should be normalized, not relevant.
|
||||
// - stride: stride between vertex data. if the data is tightly packed together, a stride
|
||||
// of 0 can be used to let opengl detrmine it automatically. however, since we combined
|
||||
// coordinates and colors, we need to manually specify the stride.
|
||||
// - offset: offset of where data begins within the buffer. the coordinates start at the
|
||||
// beginning of the buffer, while the colors are offset by 3 elements.
|
||||
//
|
||||
// ┌─────────────────┬─────────────────╥─────────────────┬─────────────────┐
|
||||
// │ coordinates │ color ║ coordinates │ color │
|
||||
// │ ╷ ╷ │ ╷ ╷ ║ ╷ ╷ │ ╷ ╷ │
|
||||
// │ X │ Y │ Z │ R │ G │ B ║ X │ Y │ Z │ R │ G │ B │
|
||||
// └─────┴─────┴─────┴─────┴─────┴─────╨─────┴─────┴─────┴─────┴─────┴─────┘
|
||||
// coordinates ─┨ offset: 0
|
||||
// ┠───────────────────────────────────┨ stride: 6 * f32 = 24
|
||||
// ┖─ ─ ─ ─ ─ ─ ─ ─ ─┨ data ┖─ ─ ─ ─ ─ ─ ─ ─ ─┨ data
|
||||
//
|
||||
// color ───────────────────┨ offset: 3 * f32 = 12
|
||||
// ┠───────────────────────────────────┨ stride: 6 * f32 = 24
|
||||
// ┖─ ─ ─ ─ ─ ─ ─ ─ ─┨ data ┖─ ─ ─ ─ ─ ─ ─ ─ ─┨ data
|
||||
gl.vertex_attrib_pointer_with_i32(
|
||||
coord_attrib,
|
||||
3,
|
||||
WebGl::FLOAT,
|
||||
false,
|
||||
6 * size_of::<f32>() as i32,
|
||||
0,
|
||||
);
|
||||
gl.vertex_attrib_pointer_with_i32(
|
||||
color_attrib,
|
||||
3,
|
||||
WebGl::FLOAT,
|
||||
false,
|
||||
6 * size_of::<f32>() as i32,
|
||||
3 * size_of::<f32>() as i32,
|
||||
);
|
||||
|
||||
// vertex attributes are disabled by default. thus, we need to enable them with
|
||||
// glEnableVertexAttribArray giving the vertex attribute location as its argument.
|
||||
gl.enable_vertex_attrib_array(coord_attrib);
|
||||
gl.enable_vertex_attrib_array(color_attrib);
|
||||
|
||||
// specify the color to clear the screen with. this will act as the background color of our
|
||||
// canvas. arguments formatted as (r, g, b, a), each represented using floats. glClearColor
|
||||
// is a state-setting function, and its state is to be used by the glClear function.
|
||||
gl.clear_color(0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
// clear the screen. if the screen is not cleared, the contents of the previous frame would
|
||||
// still be visible. the parameter specifies which buffers should be cleared. in this case,
|
||||
// only the color buffer should be cleared. other options include depth and stencil buffer.
|
||||
// glClear is a state-using function that uses the sate set by functions such as
|
||||
// glClearColor.
|
||||
gl.clear(WebGl::COLOR_BUFFER_BIT);
|
||||
|
||||
// tell opengl about the size of the rendering window (canvas) so that opengl knows how to
|
||||
// display the data and coordinates with respect to the window. the first two parameters
|
||||
// set the location of the lower left corner of the window. the third and fourth parameter
|
||||
// set the width and height of the rendering window in pixels, in this case the size of the
|
||||
// canvas element. behind the scenes, opengl uses the data specified by glViewport to
|
||||
// transform the 2d coordinates it processed (ranging from -1.0 to 1.0) to coordinates on
|
||||
// the screen. since the canvas will not be resized in this application, this only needs to
|
||||
// be called once.
|
||||
gl.viewport(
|
||||
0,
|
||||
0,
|
||||
self.canvas.width() as i32,
|
||||
self.canvas.height() as i32,
|
||||
);
|
||||
|
||||
// draw the rectangle. the second parameter defines the number of vertices to draw, the
|
||||
// third parameter specifies the offset within the element buffer object, which in this
|
||||
// case is zero.
|
||||
gl.draw_elements_with_i32(
|
||||
WebGl::TRIANGLES,
|
||||
indices.len() as i32,
|
||||
WebGl::UNSIGNED_SHORT,
|
||||
0,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// compile an opengl shader
|
||||
fn compile_shader(&self, shader_type: u32, source: &str) -> Result<WebGlShader, String> {
|
||||
let gl = &self.gl;
|
||||
|
||||
// create the shader object. the type of shader (e.g. VERTEX_SHADER, FRAGMENT_SHADER) is
|
||||
// provided as the first argument to glCreateShader.
|
||||
let shader = gl
|
||||
.create_shader(shader_type)
|
||||
.ok_or("unable to create shader object")?;
|
||||
|
||||
// attach the shader source code to the shader object, and then compile it.
|
||||
gl.shader_source(&shader, source);
|
||||
gl.compile_shader(&shader);
|
||||
|
||||
// since the compilation might not be successful, check for any errors that occured during
|
||||
// compilation of of the shader. return the error message in case of an error.
|
||||
if gl
|
||||
.get_shader_parameter(&shader, WebGl::COMPILE_STATUS)
|
||||
.as_bool()
|
||||
.unwrap_or(false)
|
||||
{
|
||||
Ok(shader)
|
||||
} else {
|
||||
Err(gl
|
||||
.get_shader_info_log(&shader)
|
||||
.unwrap_or_else(|| String::from("unknown error creating shader")))
|
||||
}
|
||||
}
|
||||
|
||||
/// link a vertex and fragment shader into one opengl shader program
|
||||
fn link_program(
|
||||
&self,
|
||||
vert_shader: &WebGlShader,
|
||||
frag_shader: &WebGlShader,
|
||||
) -> Result<WebGlProgram, String> {
|
||||
let gl = &self.gl;
|
||||
|
||||
// create a shader program object using the glCreateProgram function
|
||||
let program = gl
|
||||
.create_program()
|
||||
.ok_or("unable to create shader program")?;
|
||||
|
||||
// attach both vertex and fragment shader to the previously created program using the
|
||||
// glAttachShader function, then link the program using glLinkProgram.
|
||||
gl.attach_shader(&program, vert_shader);
|
||||
gl.attach_shader(&program, frag_shader);
|
||||
gl.link_program(&program);
|
||||
|
||||
// since linking the program might not be successful, check for any errors that occured
|
||||
// during the linking. return the error message in case of an error.
|
||||
if gl
|
||||
.get_program_parameter(&program, WebGl::LINK_STATUS)
|
||||
.as_bool()
|
||||
.unwrap_or(false)
|
||||
{
|
||||
Ok(program)
|
||||
} else {
|
||||
Err(gl
|
||||
.get_program_info_log(&program)
|
||||
.unwrap_or_else(|| String::from("unknown error linking shader program")))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// run the game
|
||||
pub fn run() {
|
||||
match Game::new() {
|
||||
Ok(game) => {
|
||||
game.draw().unwrap_or_else(|err| utils::alert_err(&err));
|
||||
}
|
||||
Err(err) => {
|
||||
utils::alert_err(&err);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
use wasm_bindgen::prelude::*;
|
||||
|
||||
mod draw;
|
||||
mod utils;
|
||||
|
||||
#[cfg(feature = "wee_alloc")]
|
||||
#[global_allocator]
|
||||
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn wasm_main() {
|
||||
#[cfg(feature = "console_error_panic_hook")]
|
||||
utils::set_panic_hook();
|
||||
|
||||
draw::run();
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
precision mediump float;
|
||||
|
||||
varying vec3 vColor;
|
||||
|
||||
void main(void) {
|
||||
gl_FragColor = vec4(vColor, 1.0);
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
precision mediump float;
|
||||
|
||||
attribute vec3 aCoord;
|
||||
attribute vec3 aColor;
|
||||
|
||||
varying vec3 vColor;
|
||||
|
||||
void main(void) {
|
||||
gl_Position = vec4(aCoord, 1.0);
|
||||
vColor = aColor;
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
//! various utilities for usage with webassembly and webgl.
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
/// set panic hook to the console_error_panic_hook crate. this allows for better debugging, but it
|
||||
/// will result in a higher code size. requires the console_error_panic_hook feature.
|
||||
pub fn set_panic_hook() {
|
||||
#[cfg(feature = "console_error_panic_hook")]
|
||||
console_error_panic_hook::set_once();
|
||||
}
|
||||
|
||||
/// prints an error message via alert(). the error message is provided as a JsValue in order to be
|
||||
/// compatible with errors thrown by the javascript runtime.
|
||||
pub fn alert_err(msg: &JsValue) {
|
||||
let mut s = String::from("an error occured! --- ");
|
||||
s.push_str(
|
||||
&msg.as_string()
|
||||
.unwrap_or_else(|| "(unknown error message)".to_string()),
|
||||
);
|
||||
web_sys::window().unwrap().alert_with_message(&s).unwrap();
|
||||
}
|
||||
|
||||
/// create a javascript Float32Array from a regular rust array
|
||||
#[macro_export]
|
||||
macro_rules! f32_array {
|
||||
($arr: expr) => {{
|
||||
let memory_buffer = wasm_bindgen::memory()
|
||||
.dyn_into::<WebAssembly::Memory>()?
|
||||
.buffer();
|
||||
let arr_location = $arr.as_ptr() as u32 / 4;
|
||||
let array = js_sys::Float32Array::new(&memory_buffer)
|
||||
.subarray(arr_location, arr_location + $arr.len() as u32);
|
||||
array
|
||||
}};
|
||||
}
|
||||
|
||||
/// create a javascript Uint16Array from a regular rust array
|
||||
#[macro_export]
|
||||
macro_rules! u16_array {
|
||||
($arr: expr) => {{
|
||||
let memory_buffer = wasm_bindgen::memory()
|
||||
.dyn_into::<WebAssembly::Memory>()?
|
||||
.buffer();
|
||||
let arr_location = $arr.as_ptr() as u32 / 2;
|
||||
let array = js_sys::Uint16Array::new(&memory_buffer)
|
||||
.subarray(arr_location, arr_location + $arr.len() as u32);
|
||||
array
|
||||
}};
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
node_modules
|
||||
dist
|
|
@ -0,0 +1,5 @@
|
|||
// a dependency graph that contains any wasm must all be imported
|
||||
// asynchronously. this `bootstrap.js` file does the single async import, so
|
||||
// that no one else needs to worry about it again.
|
||||
import('./index.js')
|
||||
.catch(e => console.error('error importing `index.js`:', e))
|
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Rust WebGL Rectangle</title>
|
||||
<style>
|
||||
html, body {
|
||||
background-color: #111;
|
||||
color: #bbb;
|
||||
font-family: monospace;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
}
|
||||
canvas {
|
||||
margin: calc(50vh - 300px) auto;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>This page contains WebAssembly and JavaScript content, please enable JavaScript in your browser.</noscript>
|
||||
<script src="./bootstrap.js"></script>
|
||||
<canvas id="canvas" width="800" height="600">This page contains WebGL content, please enable WebGL in your browser.</canvas>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,3 @@
|
|||
import * as wasm from 'rust-webgl-rectangle-wasm'
|
||||
|
||||
wasm.wasm_main()
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"name": "rust-wasm-rectangle",
|
||||
"version": "0.1.0",
|
||||
"description": "drawing a colored rectangle using rust, webassembly and webgl",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "webpack --config webpack.config.js",
|
||||
"start": "webpack serve"
|
||||
},
|
||||
"keywords": ["webassembly", "wasm", "rust", "webpack"],
|
||||
"author": "thetek <git@thetek.de>",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"rust-webgl-rectangle-wasm": "file:../pkg"
|
||||
},
|
||||
"devDependencies": {
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
"webpack": "^5.76.2",
|
||||
"webpack-cli": "^5.0.1",
|
||||
"webpack-dev-server": "^4.13.1"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
||||
const path = require('path')
|
||||
|
||||
module.exports = {
|
||||
entry: './bootstrap.js',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'bootstrap.js',
|
||||
},
|
||||
mode: 'development',
|
||||
plugins: [
|
||||
new CopyWebpackPlugin({
|
||||
patterns: [{ from: 'index.html' }],
|
||||
})
|
||||
],
|
||||
experiments: {
|
||||
asyncWebAssembly: true,
|
||||
syncWebAssembly: true,
|
||||
},
|
||||
devServer: {
|
||||
static: {
|
||||
directory: path.join(__dirname, "dist"),
|
||||
},
|
||||
compress: true,
|
||||
port: 3000,
|
||||
},
|
||||
}
|
Loading…
Reference in New Issue