diff options
author | Dennis Kobert <d-kobert@web.de> | 2019-05-31 04:18:45 +0200 |
---|---|---|
committer | Dennis Kobert <d-kobert@web.de> | 2019-05-31 04:18:45 +0200 |
commit | 15ebdb46e906aceef5cea09e2db63650e66369d1 (patch) | |
tree | 7fd5a716b10b835ebcc961142130a3bdba6bf2f1 /WebInterface/wasm | |
parent | 3f539662518609390964c60acf2f38d9a08aee6d (diff) | |
parent | a6d2d62fae44b6d8c96e51055f7222bc679efc48 (diff) |
Merge branch 'wasm' of github.com:TrueDoctor/DiscoBot into wasm
Diffstat (limited to 'WebInterface/wasm')
-rw-r--r-- | WebInterface/wasm/asm-paint/Cargo.toml | 21 | ||||
-rwxr-xr-x | WebInterface/wasm/asm-paint/build.sh | 3 | ||||
-rwxr-xr-x | WebInterface/wasm/asm-paint/deploy | 4 | ||||
-rwxr-xr-x | WebInterface/wasm/asm-paint/deploy.py | 102 | ||||
-rw-r--r-- | WebInterface/wasm/asm-paint/index.html | 14 | ||||
-rw-r--r-- | WebInterface/wasm/asm-paint/lighttpd.config | 29 | ||||
-rw-r--r-- | WebInterface/wasm/asm-paint/loader.js | 4 | ||||
-rwxr-xr-x | WebInterface/wasm/asm-paint/run | 3 | ||||
-rw-r--r-- | WebInterface/wasm/asm-paint/src/app.rs | 19 | ||||
-rw-r--r-- | WebInterface/wasm/asm-paint/src/canvas.rs | 39 | ||||
-rw-r--r-- | WebInterface/wasm/asm-paint/src/client_logger.rs | 46 | ||||
-rw-r--r-- | WebInterface/wasm/asm-paint/src/lib.rs | 31 | ||||
-rw-r--r-- | WebInterface/wasm/asm-paint/src/shader.rs | 97 | ||||
-rw-r--r-- | WebInterface/wasm/asm-paint/src/site.rs | 28 |
14 files changed, 309 insertions, 131 deletions
diff --git a/WebInterface/wasm/asm-paint/Cargo.toml b/WebInterface/wasm/asm-paint/Cargo.toml index 5713415..ceb1866 100644 --- a/WebInterface/wasm/asm-paint/Cargo.toml +++ b/WebInterface/wasm/asm-paint/Cargo.toml @@ -1,7 +1,10 @@ [package] name = "asm-paint-rs" version = "0.1.0" -authors = ["Dennis Kobert <d-kobert@web.de>"] +authors = [ + "natrixaeria", + "TrueDoctor" +] edition = "2018" [lib] @@ -9,4 +12,18 @@ crate-type = ["cdylib"] [dependencies] wasm-bindgen = "0.2" -web-sys = {version="0.3.22", features=["Window", "Document", "HtmlElement", "Node", "Element"]} +log = "0.4" +fern = "0.5" + +[dependencies.web-sys] +version = "0.3.22" +features = [ + 'Document', + 'Element', + 'HtmlCanvasElement', + 'WebGl2RenderingContext', + 'WebGlShader', + 'WebGlProgram', + 'WebGlBuffer', + 'Window' +] diff --git a/WebInterface/wasm/asm-paint/build.sh b/WebInterface/wasm/asm-paint/build.sh deleted file mode 100755 index 61c1997..0000000 --- a/WebInterface/wasm/asm-paint/build.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -wasm-pack build --target web diff --git a/WebInterface/wasm/asm-paint/deploy b/WebInterface/wasm/asm-paint/deploy index 9f7f823..13d1d0a 100755 --- a/WebInterface/wasm/asm-paint/deploy +++ b/WebInterface/wasm/asm-paint/deploy @@ -1,4 +1,2 @@ #!/bin/sh - -./build.sh -./deploy.py +lighttpd -f ./lighttpd.config diff --git a/WebInterface/wasm/asm-paint/deploy.py b/WebInterface/wasm/asm-paint/deploy.py deleted file mode 100755 index b64c322..0000000 --- a/WebInterface/wasm/asm-paint/deploy.py +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env python3 - -from socket import (socket, AF_INET, SOCK_STREAM, IPPROTO_TCP, - SOL_SOCKET, SO_REUSEADDR) -from threading import Thread - -WASM_MIME = 'application/wasm' -JS_MIME = 'application/javascript' -PLAIN_MIME = 'text/plain' -HTML_MIME = 'text/html' - -REQUESTS = { - '/': ('index.html', HTML_MIME), - '/loader.js': ('loader.js', JS_MIME), - '/asm_paint_rs.js': ('pkg/asm_paint_rs.js', JS_MIME), - '/asm_paint_rs_bg.wasm': ('pkg/asm_paint_rs_bg.wasm', WASM_MIME), -} - -PAGE_404 = '''<!doctype html><html><head></head> -<body> - <marquee><h1>Request '404 Not Found'</h1></marquee> - <span>resource <address>'<strong>{}</strong>'</address> not found</span> -</body> -</html>''' - -def header_line_to_entry(line): - key, value = line.decode('utf-8').split(': ') - return key, value - - -class Server: - def __init__(self): - self.s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) - self.s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) - self.threads = [] - - def rec_http(self, client): - headers = b'' - while not headers.endswith(b'\r\n' * 2): - headers += client.recv(1) - headers = headers.split(b'\r\n') - head, headers = headers[0], headers[1:] - method, url, _ = head.split(b' ') - url = url.decode('utf-8') - headers = dict(header_line_to_entry(v) for v in headers if v) - if 'Content-Length' in headers: - client.recv(int(headers['Content-Length'])) - return method, url, headers - - def sen_http(self, client, status='200 OK', payload=b'', mime=PLAIN_MIME): - print('sende...') - client.send((f'HTTP/1.1 {status}\r\n' - f'Content-Length: {len(payload)}\r\n' - f'Content-Type: {mime}\r\n\r\n').encode('utf-8') - + payload) - print('gesendet') - - def run_client(self, client, addr): - while True: - print('wait for receive') - method, url, headers = self.rec_http(client) - print('got receive') - if method == b'GET': - if not url.startswith('/'): - url += '/' - print(f'got request for "{url}"') - if url in REQUESTS: - path, mime = REQUESTS[url] - f = open(path, 'rb') - payload = f.read() - f.close() - self.sen_http(client, '200 OK', payload, mime) - elif url == '/close': - client.close() - self.kill() - exit() - else: - self.sen_http(client, '404 Not Found', - PAGE_404.format(url).encode('utf-8'), - HTML_MIME) - else: - self.sen_http(client, '400 Bad Request', b'only supporting GET') - - def deploy(self, host='localhost', port=8080): - self.s.bind((host, port)) - self.s.listen(1) - while True: - client, addr = self.s.accept() - thread = Thread(target=self.run_client, args=(client,addr)) - self.threads.append(thread) - thread.run() - - def kill(self): - self.s.close() - - -if __name__ == '__main__': - try: - server = Server() - server.deploy() - finally: - server.kill() diff --git a/WebInterface/wasm/asm-paint/index.html b/WebInterface/wasm/asm-paint/index.html index 46be213..c4f3734 100644 --- a/WebInterface/wasm/asm-paint/index.html +++ b/WebInterface/wasm/asm-paint/index.html @@ -4,7 +4,21 @@ <meta charset="UTF-8"> <title> Scribblio </title> <script src='loader.js' type='module'></script> + <style> + body { + margin: 0; + background: black; + } + #canvas { + width: 100%; + height: 100%; + } + img { + background: violet; + } + </style> </head> <body> + <canvas id='canvas'></canvas> </body> </html> diff --git a/WebInterface/wasm/asm-paint/lighttpd.config b/WebInterface/wasm/asm-paint/lighttpd.config new file mode 100644 index 0000000..5fae32d --- /dev/null +++ b/WebInterface/wasm/asm-paint/lighttpd.config @@ -0,0 +1,29 @@ +server.http-parseopts = ( + "header-strict" => "enable", + "host-strict" => "enable", + "host-normalize" => "enable", + "url-normalize" => "enable", + "url-normalize-unreserved" => "enable", + "url-normalize-required" => "enable", + "url-ctrls-reject" => "enable", + "url-path-2f-decode" => "enable", + "url-path-dotseg-remove" => "enable", + "url-query-20-plus" => "enable" +) + +server.document-root = "/home/jan/projects/DiscoBot/WebInterface/wasm/asm-paint" +server.port = 8080 +dir-listing.activate = "enable" +index-file.names = ( "index.html" ) +mimetype.assign = ( + ".html" => "text/html", + ".txt" => "text/plain", + ".css" => "text/css", + ".js" => "application/x-javascript", + ".jpg" => "image/jpeg", + ".jpeg" => "image/jpeg", + ".gif" => "image/gif", + ".png" => "image/png", + ".wasm" => "application/wasm", + "" => "application/octet-stream" +) diff --git a/WebInterface/wasm/asm-paint/loader.js b/WebInterface/wasm/asm-paint/loader.js index f1d15ef..4566ee1 100644 --- a/WebInterface/wasm/asm-paint/loader.js +++ b/WebInterface/wasm/asm-paint/loader.js @@ -1,2 +1,2 @@ -import {default as init} from './asm_paint_rs.js' -init('asm_paint_rs_bg.wasm'); +import {default as init} from './pkg/asm_paint_rs.js' +init('./pkg/asm_paint_rs_bg.wasm'); diff --git a/WebInterface/wasm/asm-paint/run b/WebInterface/wasm/asm-paint/run new file mode 100755 index 0000000..1da1e35 --- /dev/null +++ b/WebInterface/wasm/asm-paint/run @@ -0,0 +1,3 @@ +#!/bin/sh + +wasm-pack build --release --target web diff --git a/WebInterface/wasm/asm-paint/src/app.rs b/WebInterface/wasm/asm-paint/src/app.rs new file mode 100644 index 0000000..005764d --- /dev/null +++ b/WebInterface/wasm/asm-paint/src/app.rs @@ -0,0 +1,19 @@ +use crate::site::Site; + +pub struct App { + site: Site, +} + +impl App { + pub fn new() -> Option<Self> { + Some(Self { + site: Site::from_current()?, + }) + } + + pub fn run(&mut self) { + let mut canvas = self.site.create_canvas().unwrap(); + canvas.init().unwrap(); + info!("canvas initialisation was succuessfull"); + } +} diff --git a/WebInterface/wasm/asm-paint/src/canvas.rs b/WebInterface/wasm/asm-paint/src/canvas.rs new file mode 100644 index 0000000..400e258 --- /dev/null +++ b/WebInterface/wasm/asm-paint/src/canvas.rs @@ -0,0 +1,39 @@ +use web_sys; +use web_sys::{WebGl2RenderingContext}; +use wasm_bindgen::JsCast; +use crate::shader::Shaders; + +pub struct Canvas { + element: web_sys::HtmlCanvasElement, + ctx: WebGl2RenderingContext, + shaders: Shaders, +} + +impl Canvas { + pub fn new(element: web_sys::Element) -> Option<Self> { + let element: web_sys::HtmlCanvasElement = + element.dyn_into::<web_sys::HtmlCanvasElement>() + .ok()?; + debug!("create webgl2 context"); + let ctx = element.get_context("webgl2").ok()?? + .dyn_into::<WebGl2RenderingContext>().ok()?; + info!("created webgl2 context successfully"); + Some(Self { + element, ctx, + shaders: Shaders::new(), + }) + } + + pub fn init(&mut self) -> Result<(), ()> { + self.shaders.init(&self.ctx).map_err(|_|())?; + self.ctx.clear_color(1.0, 0.2, 1.0, 1.0); + self.ctx.clear(WebGl2RenderingContext::COLOR_BUFFER_BIT); + Ok(()) + } +} + +impl Drop for Canvas { + fn drop(&mut self) { + self.shaders.remove(&self.ctx); + } +} diff --git a/WebInterface/wasm/asm-paint/src/client_logger.rs b/WebInterface/wasm/asm-paint/src/client_logger.rs new file mode 100644 index 0000000..f71918f --- /dev/null +++ b/WebInterface/wasm/asm-paint/src/client_logger.rs @@ -0,0 +1,46 @@ +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(js_namespace=console, js_name=debug)] + fn __console_debug_colored2(f: &str, c1: &str, c2: &str); + #[wasm_bindgen(js_namespace=console, js_name=info)] + fn __console_info_colored2(f: &str, c1: &str, c2: &str); + #[wasm_bindgen(js_namespace=console, js_name=warn)] + fn __console_warn_colored2(f: &str, c1: &str, c2: &str); + #[wasm_bindgen(js_namespace=console, js_name=error)] + fn __console_error_colored2(f: &str, c1: &str, c2: &str); +} + +fn log(rec: &log::Record) { + let log_fn = match rec.level() { + log::Level::Trace | log::Level::Debug => __console_debug_colored2, + log::Level::Info => __console_info_colored2, + log::Level::Warn => __console_warn_colored2, + log::Level::Error => __console_error_colored2, + }; + log_fn(&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/WebInterface/wasm/asm-paint/src/lib.rs b/WebInterface/wasm/asm-paint/src/lib.rs index 462a89d..6c773c5 100644 --- a/WebInterface/wasm/asm-paint/src/lib.rs +++ b/WebInterface/wasm/asm-paint/src/lib.rs @@ -1,27 +1,20 @@ -use wasm_bindgen::prelude::*; +mod client_logger; +mod shader; +mod canvas; +mod site; +mod app; -macro_rules! console_log { - ($($t:tt)*) => (log(&format_args!($($t)*).to_string())) -} +use wasm_bindgen::prelude::*; -#[wasm_bindgen] -extern "C" { - #[wasm_bindgen(js_namespace = console)] - fn log(s: &str); -} +#[macro_use] +extern crate log; #[wasm_bindgen(start)] pub fn entry() { - use web_sys; - console_log!("hello {} wasm", 42); - - let window = web_sys::window().unwrap(); - - let document = window.document().unwrap(); - - let body = document.body().unwrap(); + client_logger::init_logger(); - //body.set_inner_html("<marquee><h1 style='font-size: 100px'>Hello from WASM</h1></marquee>"); + info!("begin running wasm application"); - body.set_inner_html("oho"); + let mut app = app::App::new().unwrap(); + app.run(); } diff --git a/WebInterface/wasm/asm-paint/src/shader.rs b/WebInterface/wasm/asm-paint/src/shader.rs new file mode 100644 index 0000000..3352bcf --- /dev/null +++ b/WebInterface/wasm/asm-paint/src/shader.rs @@ -0,0 +1,97 @@ +use web_sys::{WebGlProgram, WebGl2RenderingContext}; + +const VERTEX_SHADER: &str = +r#"#version 300 es +in vec4 pos; +void main() { + gl_Position = pos; +} +"#; + +const FRAGMENT_SHADER: &str = +r#"#version 300 es +precision mediump float; +out vec4 color; + +void main() { + color = vec4(1, 0, 0, 1); +} +"#; + +pub struct Shaders { + program: Option<WebGlProgram>, + pos_loc: i32, +} + +impl Shaders { + pub fn new() -> Self { + Self { + program: None, + pos_loc: -1 + } + } + + fn create_program(&mut self, ctx: &WebGl2RenderingContext) -> Result<(), String> { + self.program = Some(ctx.create_program().ok_or("could not create program id")?); + Ok(()) + } + + fn create_shader(&mut self, ctx: &WebGl2RenderingContext, + shader_type: u32, source: &str) -> Result<(), String> { + let program = self.program.as_ref().ok_or("could not find created program")?; + let shader = ctx.create_shader(shader_type) + .ok_or("could not create shader")?; + ctx.shader_source(&shader, source); + ctx.compile_shader(&shader); + let status = ctx.get_shader_parameter(&shader, WebGl2RenderingContext::COMPILE_STATUS); + if status == wasm_bindgen::JsValue::TRUE { + ctx.attach_shader(program, &shader); + Ok(()) + } else { + Err(format!("\n{}", ctx.get_shader_info_log(&shader).unwrap_or_default())) + } + } + + fn create_vertex_shader(&mut self, ctx: &WebGl2RenderingContext) -> Result<(), String> { + self.create_shader(ctx, WebGl2RenderingContext::VERTEX_SHADER, VERTEX_SHADER) + } + + fn create_fragment_shader(&mut self, ctx: &WebGl2RenderingContext) -> Result<(), String> { + self.create_shader(ctx, WebGl2RenderingContext::FRAGMENT_SHADER, FRAGMENT_SHADER) + } + + fn compile(&mut self, ctx: &WebGl2RenderingContext) -> Result<(), String> { + let program = self.program.as_ref().ok_or("could not find created program")?; + ctx.link_program(program); + let status = ctx.get_program_parameter(program, WebGl2RenderingContext::LINK_STATUS); + if status == wasm_bindgen::JsValue::TRUE { + Ok(()) + } else { + Err(format!("\n{}", ctx.get_program_info_log(program).unwrap_or_default())) + } + } + + pub fn init(&mut self, ctx: &WebGl2RenderingContext) -> Result<(), String> { + debug!("create program"); + self.create_program(ctx) + .map_err(|e| { error!("webgl2 create program: {}", e); e})?; + debug!("create vertex shader"); + self.create_vertex_shader(ctx) + .map_err(|e| { error!("webgl2 create vertex shader: {}", e); e})?; + debug!("create fragment shader"); + self.create_fragment_shader(ctx) + .map_err(|e| { error!("webgl2 create fragment shader: {}", e); e})?; + debug!("compile shader program"); + self.compile(ctx) + .map_err(|e| { error!("webgl2 shader: {}", e); e})?; + let program = self.program.as_ref().ok_or("could not find created program")?; + self.pos_loc = ctx.get_attrib_location(program, "pos"); + trace!("got attrib location 'pos'({})", self.pos_loc); + info!("initialised shader program"); + Ok(()) + } + + pub fn remove(&mut self, ctx: &WebGl2RenderingContext) { + ctx.delete_program(self.program.as_ref()) + } +} diff --git a/WebInterface/wasm/asm-paint/src/site.rs b/WebInterface/wasm/asm-paint/src/site.rs new file mode 100644 index 0000000..4ae0237 --- /dev/null +++ b/WebInterface/wasm/asm-paint/src/site.rs @@ -0,0 +1,28 @@ +use web_sys; +use crate::canvas::Canvas; + +pub struct Site { + window: web_sys::Window, + document: web_sys::Document, +} + +impl Site { + pub fn from_current() -> Option<Self> { + let window = web_sys::window() + .or_else(|| {error!("unable to query window"); None})?; + let document = window.document() + .or_else(|| {error!("unable to query document"); None})?; + Some(Self { + window, document + }) + } + + pub fn create_canvas(&self) -> Option<Canvas> { + debug!("gain canvas element"); + let element = self.document.get_element_by_id("canvas") + .or_else(|| {error!("could not gain canvas element"); None})?; + Canvas::new(element) + .or_else(|| {error!("could not create a webgl2 canvas. + Your browser doesn't seem to support webgl2"); None}) + } +} |