summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDennis Kobert <d-kobert@web.de>2019-06-14 17:46:52 +0200
committerDennis Kobert <d-kobert@web.de>2019-06-14 17:46:52 +0200
commit031f63755aada2f1b51eb945fda2a18ad0d24aad (patch)
tree67ec62726748e734e0032e621107dd7a5fe1423a
parent6fc34ce9e0485a093487baf50738fc1ffb70ce82 (diff)
parenta4532a3f034850c9fe8e26cc210bda618136dcbf (diff)
Merge branch 'wasm' of https://github.com/TrueDoctor/DiscoBot into wasm
-rw-r--r--webhogg/wasm/Cargo.toml6
-rw-r--r--webhogg/wasm/index.html9
-rw-r--r--webhogg/wasm/src/context/graphics.rs55
-rw-r--r--webhogg/wasm/src/context/main.fs9
-rw-r--r--webhogg/wasm/src/context/main.vs9
-rw-r--r--webhogg/wasm/src/context/mod.rs2
-rw-r--r--webhogg/wasm/src/context/shader.rs34
-rw-r--r--webhogg/wasm/src/context/webgl.rs134
-rw-r--r--webhogg/wasm/src/error.rs6
-rw-r--r--webhogg/wasm/src/graphics.rs5
10 files changed, 256 insertions, 13 deletions
diff --git a/webhogg/wasm/Cargo.toml b/webhogg/wasm/Cargo.toml
index 2d69f41..8f44389 100644
--- a/webhogg/wasm/Cargo.toml
+++ b/webhogg/wasm/Cargo.toml
@@ -24,5 +24,9 @@ js-sys = "0.3"
version = "0.3"
features = [
"OffscreenCanvas",
- "WebGl2RenderingContext"
+ "WebGl2RenderingContext",
+ "WebGlShader",
+ "WebGlProgram",
+ "WebGlBuffer",
+ "WebGlVertexArrayObject"
]
diff --git a/webhogg/wasm/index.html b/webhogg/wasm/index.html
index 9624ad8..a992390 100644
--- a/webhogg/wasm/index.html
+++ b/webhogg/wasm/index.html
@@ -4,10 +4,15 @@
<meta charset='utf-8'/>
<title>webhogg</title>
</head>
- <body style='margin: 0; width: 100%; height: 100%;position:fixed;display:block;top:0;bottom:0;left:0;right:0;'>
- <canvas id='c' style='width: 100%; height: 100%;position:fixed;display:block;top:0;bottom:0;left:0;right:0;'>
+ <body style='margin: 0; width: 100%; height: 100%; posisiton: fixed; display: block;'>
+ <canvas id='c' style='width: 100%; height: 100%; position: fixed; display: block; overflow: hidden;'>
your browser is incompetent
</canvas>
+ <script>
+ let canvas = document.getElementById('c');
+ canvas.width = window.innerWidth;
+ canvas.height = window.innerHeight;
+ </script>
<script src='pkg/main.js'></script>
</body>
</html>
diff --git a/webhogg/wasm/src/context/graphics.rs b/webhogg/wasm/src/context/graphics.rs
index b94441d..6af35a2 100644
--- a/webhogg/wasm/src/context/graphics.rs
+++ b/webhogg/wasm/src/context/graphics.rs
@@ -1,11 +1,18 @@
-use log::*;
use crate::error::WasmError;
use wasm_bindgen::JsCast;
-use web_sys::WebGl2RenderingContext as Gl;
+use web_sys::WebGl2RenderingContext as GlContext;
+
+use super::webgl;
+use super::webgl::{Color4, ShaderType, WebGl2};
+use super::shader::{MAIN_VERTEX_SHADER, MAIN_FRAGMENT_SHADER};
+use super::shader::ShaderProgram;
pub struct GraphicsContext {
- gl: Gl,
+ gl: WebGl2,
frame_nr: u64,
+ shader: ShaderProgram,
+ vao: webgl::WebGlVertexArrayObject,
+ buffer: webgl::WebGlBuffer,
}
impl GraphicsContext {
@@ -16,26 +23,56 @@ impl GraphicsContext {
.ok_or_else(|| WasmError::WebGl2ContextCreation(
format!("context cration failed: getContext returned nothing")))?;
let context = context
- .dyn_into::<Gl>()
+ .dyn_into::<GlContext>()
.map_err(|_| WasmError::WebGl2ContextCreation(
format!("context object is not a context")))?;
+
+ let gl = WebGl2::from_context(context);
+ let shader = ShaderProgram::from_sources(&gl, &[
+ (ShaderType::Vertex, MAIN_VERTEX_SHADER.to_string()),
+ (ShaderType::Fragment, MAIN_FRAGMENT_SHADER.to_string()),
+ ])?;
+
+ let vao = gl.create_vertex_array()
+ .map_err(|_| WasmError::WebGlBuffer(
+ format!("glGenVertexArrays failed")))?;
+ gl.bind_vertex_array(&vao);
+
+ let buffer = gl.create_buffer()
+ .map_err(|_| WasmError::WebGlBuffer(
+ format!("glCreateBuffer failed")))?;
+ gl.bind_array_buffer(&buffer);
+ gl.array_buffer_data_f32(&[
+ 0.0, 0.0,
+ 1.0, 0.0,
+ 0.0, 1.0,
+ 1.0, 1.0,
+ 0.0, 1.0,
+ 1.0, 0.0,
+ ]);
+ gl.enable_vertex_attrib_array(0);
Ok(Self {
- gl: context,
- frame_nr: 0,
+ gl, frame_nr: 0,
+ shader, vao, buffer
})
}
pub fn update(&mut self) -> Result<(), WasmError> {
let light = 0.5;
+ let speed = 60.0;
- let a = (self.frame_nr as f32) / 60.0;
+ let a = (self.frame_nr as f32) / speed;
let a = f32::abs(f32::sin(a));
let b = f32::abs(f32::cos(a));
let (a, b) = (a * light, b * light);
- self.gl.clear_color(a, light - a, b, 1.0);
- self.gl.clear(Gl::COLOR_BUFFER_BIT);
+ self.gl.set_viewport();
+ self.gl.clear(&Color4::new(a, light - a, b, 1.0));
+
+ self.shader.run(&self.gl);
+ self.gl.vertex_attrib_f32_pointer(0, 2);
+ self.gl.draw_triangle_arrays(6);
self.frame_nr += 1;
diff --git a/webhogg/wasm/src/context/main.fs b/webhogg/wasm/src/context/main.fs
new file mode 100644
index 0000000..971d2db
--- /dev/null
+++ b/webhogg/wasm/src/context/main.fs
@@ -0,0 +1,9 @@
+#version 300 es
+
+precision highp float;
+
+out vec4 color;
+
+void main() {
+ color = vec4(0.0, 1.0, 1.0, 1.0);
+}
diff --git a/webhogg/wasm/src/context/main.vs b/webhogg/wasm/src/context/main.vs
new file mode 100644
index 0000000..18df0a0
--- /dev/null
+++ b/webhogg/wasm/src/context/main.vs
@@ -0,0 +1,9 @@
+#version 300 es
+
+precision highp float;
+
+layout(location=0) in vec2 position;
+
+void main() {
+ gl_Position = vec4(position, 0.0, 0.0);
+}
diff --git a/webhogg/wasm/src/context/mod.rs b/webhogg/wasm/src/context/mod.rs
index 3e8261b..09902ce 100644
--- a/webhogg/wasm/src/context/mod.rs
+++ b/webhogg/wasm/src/context/mod.rs
@@ -1,3 +1,5 @@
+mod shader;
+mod webgl;
pub mod graphics;
pub mod logic;
diff --git a/webhogg/wasm/src/context/shader.rs b/webhogg/wasm/src/context/shader.rs
new file mode 100644
index 0000000..9ccb9fc
--- /dev/null
+++ b/webhogg/wasm/src/context/shader.rs
@@ -0,0 +1,34 @@
+use crate::error::WasmError;
+use super::webgl;
+use super::webgl::{WebGl2, ShaderType};
+
+pub const MAIN_VERTEX_SHADER: &str = include_str!("main.vs");
+pub const MAIN_FRAGMENT_SHADER: &str = include_str!("main.fs");
+
+pub struct ShaderProgram {
+ program: webgl::WebGlProgram,
+}
+
+impl ShaderProgram {
+ pub fn from_sources(gl: &WebGl2, sources: &[(ShaderType, String)]) -> Result<Self, WasmError> {
+ let program = gl.create_program()
+ .map_err(|_| WasmError::Shader(format!("glCreateProgram failed ({})", gl.get_error())))?;
+ for (shader_type, source) in sources {
+ let shader = gl.create_shader(shader_type)
+ .map_err(|_| WasmError::Shader(format!("glCreateShader failed ({})", gl.get_error())))?;
+ gl.shader_source(&shader, source);
+ gl.compile_shader(&shader)
+ .map_err(|e| WasmError::Shader(format!("compile error in {} shader: {}", shader_type, e)))?;
+ gl.attach_shader(&program, &shader)
+ }
+ gl.link_program(&program)
+ .map_err(|e| WasmError::Shader(format!("linker error in program: {}", e)))?;
+ Ok(Self {
+ program
+ })
+ }
+
+ pub fn run(&self, gl: &WebGl2) {
+ gl.use_program(&self.program)
+ }
+}
diff --git a/webhogg/wasm/src/context/webgl.rs b/webhogg/wasm/src/context/webgl.rs
new file mode 100644
index 0000000..8883835
--- /dev/null
+++ b/webhogg/wasm/src/context/webgl.rs
@@ -0,0 +1,134 @@
+pub use web_sys::{
+ WebGl2RenderingContext as GlContext,
+ WebGlProgram, WebGlShader,
+ WebGlBuffer, WebGlVertexArrayObject,
+};
+use wasm_bindgen::prelude::*;
+use std::fmt::Display;
+
+pub struct Color4(f32, f32, f32, f32);
+
+#[wasm_bindgen]
+extern "C" {
+ #[wasm_bindgen(js_namespace=Float32Array, js_name=of, variadic)]
+ fn _create_f32_buffer(args: &[f32]) -> js_sys::Float32Array;
+}
+
+#[derive(Debug)]
+pub enum ShaderType {
+ Vertex,
+ Fragment,
+}
+
+impl Display for ShaderType {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(f, "{:?}", self)
+ }
+}
+
+impl ShaderType {
+ pub fn to_id(&self) -> u32 {
+ match self {
+ ShaderType::Vertex => GlContext::VERTEX_SHADER,
+ ShaderType::Fragment => GlContext::FRAGMENT_SHADER,
+ }
+ }
+}
+
+impl Color4 {
+ pub fn new(r: f32, g: f32, b: f32, a: f32) -> Color4 {
+ Color4(r, g, b, a)
+ }
+}
+
+pub fn create_f32_buffer(buffer: &[f32]) -> js_sys::Float32Array {
+ _create_f32_buffer(buffer)
+}
+
+pub struct WebGl2 {
+ gl: GlContext,
+}
+
+impl WebGl2 {
+ pub fn from_context(context: GlContext) -> Self {
+ WebGl2 {
+ gl: context,
+ }
+ }
+
+ pub fn create_program(&self) -> Result<WebGlProgram, ()> {
+ self.gl.create_program().ok_or(())
+ }
+
+ pub fn create_shader(&self, shader_type: &ShaderType) -> Result<WebGlShader, ()> {
+ self.gl.create_shader(shader_type.to_id()).ok_or(())
+ }
+
+ pub fn get_error(&self) -> u32 { self.gl.get_error() }
+ pub fn shader_source(&self, id: &WebGlShader, source: &str) { self.gl.shader_source(id, source) }
+ pub fn compile_shader(&self, id: &WebGlShader) -> Result<(), String> {
+ self.gl.compile_shader(id);
+ if self.gl.get_shader_parameter(id, GlContext::COMPILE_STATUS) == JsValue::FALSE {
+ Err(self.gl.get_shader_info_log(id)
+ .unwrap_or("/could not retrieve program information/".to_string()))
+ } else { Ok(()) }
+ }
+ pub fn link_program(&self, id: &WebGlProgram) -> Result<(), String> {
+ self.gl.link_program(id);
+ if self.gl.get_program_parameter(id, GlContext::LINK_STATUS) == JsValue::FALSE {
+ Err(self.gl.get_program_info_log(id)
+ .unwrap_or("/could not retrieve program information/".to_string()))
+ } else { Ok(()) }
+ }
+ pub fn attach_shader(&self, program: &WebGlProgram, shader: &WebGlShader) {
+ self.gl.attach_shader(program, shader)
+ }
+
+ pub fn clear(&self, color: &Color4) {
+ self.gl.clear_color(color.0, color.1, color.2, color.3);
+ self.gl.clear(GlContext::COLOR_BUFFER_BIT);
+ }
+
+ pub fn set_viewport(&self) {
+ self.gl.viewport(0, 0, self.gl.drawing_buffer_width(), self.gl.drawing_buffer_height());
+ }
+
+ pub fn create_buffer(&self) -> Result<WebGlBuffer, ()> {
+ self.gl.create_buffer().ok_or(())
+ }
+
+ pub fn bind_array_buffer(&self, buffer: &WebGlBuffer) {
+ self.gl.bind_buffer(GlContext::ARRAY_BUFFER, Some(buffer))
+ }
+ pub fn unbind_array_buffer(&self) { self.gl.bind_buffer(GlContext::ARRAY_BUFFER, None) }
+
+ pub fn array_buffer_data_f32(&self, data: &[f32]) {
+ self.gl.buffer_data_with_opt_array_buffer(
+ GlContext::ARRAY_BUFFER,
+ Some(&create_f32_buffer(data).buffer()),
+ GlContext::STATIC_DRAW)
+ }
+
+ pub fn create_vertex_array(&self) -> Result<WebGlVertexArrayObject, ()> {
+ self.gl.create_vertex_array().ok_or(())
+ }
+ pub fn bind_vertex_array(&self, array: &WebGlVertexArrayObject) {
+ self.gl.bind_vertex_array(Some(array))
+ }
+ pub fn unbind_vertex_array(&self) { self.gl.bind_vertex_array(None) }
+ pub fn vertex_attrib_f32_pointer(&self, location: u32, dim: i32) {
+ self.gl.vertex_attrib_pointer_with_i32(location, dim, GlContext::FLOAT, false, 0, 0)
+ }
+
+ pub fn draw_triangle_arrays(&self, count: i32) {
+ self.gl.draw_arrays(GlContext::TRIANGLES, 0, count)
+ }
+
+ pub fn enable_vertex_attrib_array(&self, location: u32) {
+ self.gl.enable_vertex_attrib_array(location)
+ }
+
+ pub fn use_program(&self, program: &WebGlProgram) {
+ self.gl.use_program(Some(program))
+ }
+}
diff --git a/webhogg/wasm/src/error.rs b/webhogg/wasm/src/error.rs
index 1c6ec27..fbb6bf8 100644
--- a/webhogg/wasm/src/error.rs
+++ b/webhogg/wasm/src/error.rs
@@ -3,6 +3,8 @@ use std::error::Error;
#[derive(Debug)]
pub enum WasmError {
WebGl2ContextCreation(String),
+ Shader(String),
+ WebGlBuffer(String),
}
impl std::fmt::Display for WasmError {
@@ -15,6 +17,8 @@ impl Error for WasmError {
fn description(&self) -> &str {
match self {
WasmError::WebGl2ContextCreation(msg) => msg,
+ WasmError::Shader(msg) => msg,
+ WasmError::WebGlBuffer(msg) => msg,
}
}
@@ -25,6 +29,8 @@ impl WasmError {
pub fn name(&self) -> &str {
match self {
WasmError::WebGl2ContextCreation(_) => "WebGl2ContextCreationError",
+ WasmError::Shader(_) => "ShaderError",
+ WasmError::WebGlBuffer(_) => "WebGlBufferError",
}
}
}
diff --git a/webhogg/wasm/src/graphics.rs b/webhogg/wasm/src/graphics.rs
index c4902ae..219c652 100644
--- a/webhogg/wasm/src/graphics.rs
+++ b/webhogg/wasm/src/graphics.rs
@@ -10,7 +10,10 @@ pub fn start_graphics(canvas: web_sys::OffscreenCanvas) {
match context::graphics::GraphicsContext::from_canvas(canvas) {
Ok(ctx) => context::set_graphics(ctx),
- Err(e) => error!("graphics {}", e)
+ Err(e) => {
+ error!("graphics {}", e);
+ panic!()
+ }
}
}