summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDennis Kobert <d-kobert@web.de>2019-06-21 23:52:07 +0200
committerDennis Kobert <d-kobert@web.de>2019-06-21 23:52:07 +0200
commit4e0037169db5d0c7d824debedb5513b69676506a (patch)
tree82c56547fa70b499627236efa66c3bf7e5411ead
parent36c89240a87ecb826cf09bc7b3069aa636c9f2f1 (diff)
parent031f63755aada2f1b51eb945fda2a18ad0d24aad (diff)
Merge branch 'wasm' into game_server_refactor
-rw-r--r--webhogg/wasm/Cargo.toml14
-rw-r--r--webhogg/wasm/index.html11
-rw-r--r--webhogg/wasm/pkg/main.js38
-rw-r--r--webhogg/wasm/pkg/worker-graphics.js1
-rw-r--r--webhogg/wasm/pkg/worker.js17
-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
-rw-r--r--webhogg/wasm/src/error.rs36
-rw-r--r--webhogg/wasm/src/graphics.rs25
-rw-r--r--webhogg/wasm/src/lib.rs13
-rw-r--r--webhogg/wasm/src/logger.rs33
-rw-r--r--webhogg/wasm/src/logic.rs19
17 files changed, 498 insertions, 13 deletions
diff --git a/webhogg/wasm/Cargo.toml b/webhogg/wasm/Cargo.toml
index 7978928..8f44389 100644
--- a/webhogg/wasm/Cargo.toml
+++ b/webhogg/wasm/Cargo.toml
@@ -16,3 +16,17 @@ lto = true
[dependencies]
wasm-bindgen = "0.2"
+log = "0.4"
+fern = "0.5"
+js-sys = "0.3"
+
+[dependencies.web-sys]
+version = "0.3"
+features = [
+ "OffscreenCanvas",
+ "WebGl2RenderingContext",
+ "WebGlShader",
+ "WebGlProgram",
+ "WebGlBuffer",
+ "WebGlVertexArrayObject"
+]
diff --git a/webhogg/wasm/index.html b/webhogg/wasm/index.html
index eae1cc2..a992390 100644
--- a/webhogg/wasm/index.html
+++ b/webhogg/wasm/index.html
@@ -4,8 +4,15 @@
<meta charset='utf-8'/>
<title>webhogg</title>
</head>
- <body>
- <canvas id='c'>your browser is incompetent</canvas>
+ <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/pkg/main.js b/webhogg/wasm/pkg/main.js
index eec740d..90b3956 100644
--- a/webhogg/wasm/pkg/main.js
+++ b/webhogg/wasm/pkg/main.js
@@ -1,9 +1,39 @@
+workers = [];
+
+function exit() {
+ for (var worker of workers) {
+ worker.terminate();
+ }
+ console.clear();
+}
+
async function main() {
let fetchingSource = fetch('bin/webhogg-wasm.wasm');
+
+ let canvasElement = document.getElementById('c');
+ let offCanvas = canvasElement.transferControlToOffscreen();
+
let fetchedSource = await fetchingSource;
- let source = await fetchedSource.text();
- //alert(source)
- let workerGraphics = new Worker('pkg/worker-graphics.js');
-}
+ source = await fetchedSource.arrayBuffer();
+ const modules = [
+ { type: 'graphics',
+ source: source,
+ canvas: offCanvas,
+ dt: 16 },
+ { type: 'logic',
+ source: source,
+ canvas: [],
+ dt: 10000 },
+ ];
+ for (var module of modules) {
+ let worker = new Worker('pkg/worker.js');
+ if (module.type === 'graphics') {
+ worker.postMessage(module, [module.canvas]);
+ } else {
+ worker.postMessage(module);
+ }
+ workers.push(worker);
+ }
+}
main();
diff --git a/webhogg/wasm/pkg/worker-graphics.js b/webhogg/wasm/pkg/worker-graphics.js
deleted file mode 100644
index 8360014..0000000
--- a/webhogg/wasm/pkg/worker-graphics.js
+++ /dev/null
@@ -1 +0,0 @@
-console.log('lelel');
diff --git a/webhogg/wasm/pkg/worker.js b/webhogg/wasm/pkg/worker.js
new file mode 100644
index 0000000..780ea6f
--- /dev/null
+++ b/webhogg/wasm/pkg/worker.js
@@ -0,0 +1,17 @@
+let data = null;
+
+onmessage = function (e) {
+ data = e.data;
+
+ importScripts('../bin/webhogg-wasm.js');
+ wasm_bindgen(data.source).then(ctx => {
+ if (data.type === 'graphics') {
+ wasm_bindgen.start_graphics(data.canvas);
+ setInterval(wasm_bindgen.loop_graphics, data.dt);
+ } else if (data.type === 'logic') {
+ wasm_bindgen.start_logic();
+ setInterval(wasm_bindgen.loop_logic, data.dt);
+ }
+
+ });
+}
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))
+ }
+}
diff --git a/webhogg/wasm/src/error.rs b/webhogg/wasm/src/error.rs
new file mode 100644
index 0000000..fbb6bf8
--- /dev/null
+++ b/webhogg/wasm/src/error.rs
@@ -0,0 +1,36 @@
+use std::error::Error;
+
+#[derive(Debug)]
+pub enum WasmError {
+ WebGl2ContextCreation(String),
+ Shader(String),
+ WebGlBuffer(String),
+}
+
+impl std::fmt::Display for WasmError {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
+ write!(f, "{}: {}", self.name(), self.description())
+ }
+}
+
+impl Error for WasmError {
+ fn description(&self) -> &str {
+ match self {
+ WasmError::WebGl2ContextCreation(msg) => msg,
+ WasmError::Shader(msg) => msg,
+ WasmError::WebGlBuffer(msg) => msg,
+ }
+ }
+
+ fn source(&self) -> Option<&'static dyn Error> { None }
+}
+
+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
new file mode 100644
index 0000000..219c652
--- /dev/null
+++ b/webhogg/wasm/src/graphics.rs
@@ -0,0 +1,25 @@
+use wasm_bindgen::prelude::*;
+use log::*;
+use crate::*;
+
+#[wasm_bindgen]
+pub fn start_graphics(canvas: web_sys::OffscreenCanvas) {
+ logger::init_logger();
+ info!("graphics: wasm entry-point reached");
+ //debug!("js value is?: undefined: {}", canvas.is_undefined());
+
+ match context::graphics::GraphicsContext::from_canvas(canvas) {
+ Ok(ctx) => context::set_graphics(ctx),
+ Err(e) => {
+ error!("graphics {}", e);
+ panic!()
+ }
+ }
+}
+
+#[wasm_bindgen]
+pub fn loop_graphics() {
+ context::get_graphics().update()
+ .map_err(|e| error!("gaphics loop {}", e))
+ .unwrap();
+}
diff --git a/webhogg/wasm/src/lib.rs b/webhogg/wasm/src/lib.rs
index cb334fb..7aa4e86 100644
--- a/webhogg/wasm/src/lib.rs
+++ b/webhogg/wasm/src/lib.rs
@@ -1,8 +1,9 @@
-use wasm_bindgen::prelude::*;
+mod logger;
+pub mod error;
+pub mod context;
-#[wasm_bindgen]
-pub fn enrty() {
-}
+pub mod logic;
+pub mod graphics;
-fn main() {
-}
+pub use logic::*;
+pub use graphics::*;
diff --git a/webhogg/wasm/src/logger.rs b/webhogg/wasm/src/logger.rs
new file mode 100644
index 0000000..96c4cbf
--- /dev/null
+++ b/webhogg/wasm/src/logger.rs
@@ -0,0 +1,33 @@
+use wasm_bindgen::prelude::*;
+
+#[wasm_bindgen]
+extern "C" {
+ #[wasm_bindgen(js_namespace=console, js_name=log)]
+ fn __console_log_colored2(f: &str, c1: &str, c2: &str);
+}
+
+fn log(rec: &log::Record) {
+ __console_log_colored2(&format!("{}", rec.args()),
+ &format!("color: {}", match rec.level() {
+ log::Level::Trace => "violet",
+ log::Level::Debug => "blue",
+ log::Level::Info => "green",
+ log::Level::Warn => "orange",
+ log::Level::Error => "red"
+ }), "");
+}
+
+pub fn init_logger() {
+ fern::Dispatch::new().format(|out, message, record|{
+ out.finish(format_args!(
+ "%c{}%c {} > {}",
+ record.level(),
+ record.target(),
+ message
+ )
+ )
+ })
+ .level(log::LevelFilter::Debug)
+ .chain(fern::Output::call(log))
+ .apply().unwrap();
+}
diff --git a/webhogg/wasm/src/logic.rs b/webhogg/wasm/src/logic.rs
new file mode 100644
index 0000000..14272d9
--- /dev/null
+++ b/webhogg/wasm/src/logic.rs
@@ -0,0 +1,19 @@
+use wasm_bindgen::prelude::*;
+use log::*;
+use crate::*;
+
+#[wasm_bindgen]
+pub fn start_logic() {
+ logger::init_logger();
+ info!("logic: wasm entry-point reached");
+
+ match context::logic::LogicContext::new() {
+ Ok(ctx) => context::set_logic(ctx),
+ Err(e) => error!("logic {}", e)
+ }
+}
+
+#[wasm_bindgen]
+pub fn loop_logic() {
+ debug!("logic: loopin'");
+}