summaryrefslogtreecommitdiff
path: root/webhogg/wasm/src/context
diff options
context:
space:
mode:
Diffstat (limited to 'webhogg/wasm/src/context')
-rw-r--r--webhogg/wasm/src/context/graphics.rs81
-rw-r--r--webhogg/wasm/src/context/logic.rs11
-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.rs26
-rw-r--r--webhogg/wasm/src/context/shader.rs34
-rw-r--r--webhogg/wasm/src/context/webgl.rs134
7 files changed, 304 insertions, 0 deletions
diff --git a/webhogg/wasm/src/context/graphics.rs b/webhogg/wasm/src/context/graphics.rs
new file mode 100644
index 0000000..6af35a2
--- /dev/null
+++ b/webhogg/wasm/src/context/graphics.rs
@@ -0,0 +1,81 @@
+use crate::error::WasmError;
+use wasm_bindgen::JsCast;
+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: WebGl2,
+ frame_nr: u64,
+ shader: ShaderProgram,
+ vao: webgl::WebGlVertexArrayObject,
+ buffer: webgl::WebGlBuffer,
+}
+
+impl GraphicsContext {
+ pub fn from_canvas(canvas: web_sys::OffscreenCanvas) -> Result<Self, WasmError> {
+ let context = canvas.get_context("webgl2")
+ .map_err(|_| WasmError::WebGl2ContextCreation(
+ format!("context cration failed: getContext returned an exception")))?
+ .ok_or_else(|| WasmError::WebGl2ContextCreation(
+ format!("context cration failed: getContext returned nothing")))?;
+ let context = context
+ .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, 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) / speed;
+ let a = f32::abs(f32::sin(a));
+ let b = f32::abs(f32::cos(a));
+ let (a, b) = (a * light, b * light);
+
+ 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;
+
+ Ok(())
+ }
+}
diff --git a/webhogg/wasm/src/context/logic.rs b/webhogg/wasm/src/context/logic.rs
new file mode 100644
index 0000000..71dfea4
--- /dev/null
+++ b/webhogg/wasm/src/context/logic.rs
@@ -0,0 +1,11 @@
+use crate::error::WasmError;
+
+pub struct LogicContext {
+}
+
+impl LogicContext {
+ pub fn new() -> Result<Self, WasmError> {
+ Ok(Self {
+ })
+ }
+}
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
new file mode 100644
index 0000000..09902ce
--- /dev/null
+++ b/webhogg/wasm/src/context/mod.rs
@@ -0,0 +1,26 @@
+mod shader;
+mod webgl;
+pub mod graphics;
+pub mod logic;
+
+use graphics::GraphicsContext;
+use logic::LogicContext;
+
+static mut GTX: Option<GraphicsContext> = None;
+static mut LTX: Option<LogicContext> = None;
+
+pub fn get_graphics() -> &'static mut GraphicsContext {
+ unsafe { GTX.as_mut().unwrap() }
+}
+
+pub fn get_logic() -> &'static mut LogicContext {
+ unsafe { LTX.as_mut().unwrap() }
+}
+
+pub fn set_graphics(gtx: GraphicsContext) {
+ unsafe { GTX = Some(gtx) }
+}
+
+pub fn set_logic(ltx: LogicContext) {
+ unsafe { LTX = Some(ltx) }
+}
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))
+ }
+}