From 856bbf4dae4a69693a0324da34e8b0dd3754dfdf Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Sun, 23 Dec 2018 19:42:30 +0100 Subject: [PATCH] Initial commit: Closed loop of TS->Rust->TS --- .gitignore | 2 + Cargo.toml | 22 +++++ README.md | 21 +++++ build.sh | 33 ++++++++ build_and_run.sh | 6 ++ docs/emgui.d.ts | 11 +++ docs/emgui.js | 151 +++++++++++++++++++++++++++++++++ docs/emgui_bg.wasm | Bin 0 -> 125328 bytes docs/frontend.js | 112 ++++++++++++++++++++++++ docs/frontend.ts | 206 +++++++++++++++++++++++++++++++++++++++++++++ docs/index.html | 44 ++++++++++ src/lib.rs | 70 +++++++++++++++ tsconfig.json | 8 ++ tslint.json | 15 ++++ 14 files changed, 701 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 README.md create mode 100755 build.sh create mode 100755 build_and_run.sh create mode 100644 docs/emgui.d.ts create mode 100644 docs/emgui.js create mode 100644 docs/emgui_bg.wasm create mode 100644 docs/frontend.js create mode 100644 docs/frontend.ts create mode 100644 docs/index.html create mode 100644 src/lib.rs create mode 100644 tsconfig.json create mode 100644 tslint.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..1d09522cd --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.sublime* +/target diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 000000000..787860ae3 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "emgui" +version = "0.1.0" +authors = ["Emil Ernerfeldt "] + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +# rand = { version="0.6", features = ['wasm-bindgen'] } +serde = "1" +serde_derive = "1" +serde_json = "1" +wasm-bindgen = "0.2" +web-sys = { version = "0.3.5", features = ['console', 'Performance', 'Window'] } + +# Optimize for small code size: +[profile.dev] +opt-level = "s" + +[profile.release] +opt-level = "s" diff --git a/README.md b/README.md new file mode 100644 index 000000000..6d134d20a --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +# Emgui – An Experimental, Modularized immediate mode Graphical User Interface + +Here are the steps, in chronological order of execution: + +CODE: Input bindings, i.e. gathering GuiInput data from the system (web browser, Mac Window, iPhone App, ...) +DATA: GuiInput: mouse and keyboard state + window size +DATA: GuiSizes: this is a configuration of the ImLayout system, sets sizes of e.g. a slider. +CODE: ImLayout: Immediate mode layout Gui elements. THIS IS WHAT YOUR APP CODE CALLS! +DATA: GuiPaint: High-level commands to render e.g. a checked box with a hover-effect at a certain position. +DATA: GuiStyle: The colors/shading of the gui. +CODE: GuiPainter: Renders GuiPaint + GuiStyle into DrawCommands +DATA: PaintCommands: low-level commands (e.g. "Draw a rectangle with this color here") +CODE: Painter: paints the the PaintCommands to the screen (HTML canvas, OpenGL, ...) + +This is similar to Dear ImGui but separates the layout from the rendering, and adds another step to the rendering. + +# Implementation + +Input is gathered in TypeScript. +PaintCommands rendered to a HTML canvas. +Everything else is written in Rust, compiled to WASM. diff --git a/build.sh b/build.sh new file mode 100755 index 000000000..828efa0af --- /dev/null +++ b/build.sh @@ -0,0 +1,33 @@ +#!/bin/bash +set -eu + +# Pre-requisites: +rustup target add wasm32-unknown-unknown +if ! [[ $(wasm-bindgen --version) ]]; then + cargo install wasm-bindgen-cli +fi + +BUILD=debug +# BUILD=release + +# Clear output from old stuff: +rm -rf docs/*.d.ts +rm -rf docs/*.js +rm -rf docs/*.wasm + +echo "Build rust:" +cargo build --target wasm32-unknown-unknown + +echo "Lint and clean up typescript:" +tslint --fix docs/*.ts + +echo "Compile typescript:" +tsc + +echo "Generate JS bindings for wasm:" + +FOLDER_NAME=${PWD##*/} +TARGET_NAME="$FOLDER_NAME.wasm" +wasm-bindgen "target/wasm32-unknown-unknown/$BUILD/$TARGET_NAME" \ + --out-dir docs --no-modules + # --no-modules-global hoboho diff --git a/build_and_run.sh b/build_and_run.sh new file mode 100755 index 000000000..ea1e91e05 --- /dev/null +++ b/build_and_run.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -eu + +./build.sh + +open "docs/index.html" diff --git a/docs/emgui.d.ts b/docs/emgui.d.ts new file mode 100644 index 000000000..7eec4b075 --- /dev/null +++ b/docs/emgui.d.ts @@ -0,0 +1,11 @@ +/* tslint:disable */ +export function show_gui(arg0: string): string; + +export class Input { +free(): void; +screen_width: number +screen_height: number +mouse_x: number +mouse_y: number + +} diff --git a/docs/emgui.js b/docs/emgui.js new file mode 100644 index 000000000..eec87cd10 --- /dev/null +++ b/docs/emgui.js @@ -0,0 +1,151 @@ +(function() { + var wasm; + const __exports = {}; + + + let cachedTextEncoder = new TextEncoder('utf-8'); + + let cachegetUint8Memory = null; + function getUint8Memory() { + if (cachegetUint8Memory === null || cachegetUint8Memory.buffer !== wasm.memory.buffer) { + cachegetUint8Memory = new Uint8Array(wasm.memory.buffer); + } + return cachegetUint8Memory; + } + + function passStringToWasm(arg) { + + const buf = cachedTextEncoder.encode(arg); + const ptr = wasm.__wbindgen_malloc(buf.length); + getUint8Memory().set(buf, ptr); + return [ptr, buf.length]; + } + + let cachedTextDecoder = new TextDecoder('utf-8'); + + function getStringFromWasm(ptr, len) { + return cachedTextDecoder.decode(getUint8Memory().subarray(ptr, ptr + len)); + } + + let cachedGlobalArgumentPtr = null; + function globalArgumentPtr() { + if (cachedGlobalArgumentPtr === null) { + cachedGlobalArgumentPtr = wasm.__wbindgen_global_argument_ptr(); + } + return cachedGlobalArgumentPtr; + } + + let cachegetUint32Memory = null; + function getUint32Memory() { + if (cachegetUint32Memory === null || cachegetUint32Memory.buffer !== wasm.memory.buffer) { + cachegetUint32Memory = new Uint32Array(wasm.memory.buffer); + } + return cachegetUint32Memory; + } + /** + * @param {string} arg0 + * @returns {string} + */ + __exports.show_gui = function(arg0) { + const [ptr0, len0] = passStringToWasm(arg0); + const retptr = globalArgumentPtr(); + try { + wasm.show_gui(retptr, ptr0, len0); + const mem = getUint32Memory(); + const rustptr = mem[retptr / 4]; + const rustlen = mem[retptr / 4 + 1]; + + const realRet = getStringFromWasm(rustptr, rustlen).slice(); + wasm.__wbindgen_free(rustptr, rustlen * 1); + return realRet; + + + } finally { + wasm.__wbindgen_free(ptr0, len0 * 1); + + } + + }; + + function freeInput(ptr) { + + wasm.__wbg_input_free(ptr); + } + /** + */ + class Input { + + free() { + const ptr = this.ptr; + this.ptr = 0; + freeInput(ptr); + } + + /** + * @returns {number} + */ + get screen_width() { + return wasm.__wbg_get_input_screen_width(this.ptr); + } + set screen_width(arg0) { + return wasm.__wbg_set_input_screen_width(this.ptr, arg0); + } + /** + * @returns {number} + */ + get screen_height() { + return wasm.__wbg_get_input_screen_height(this.ptr); + } + set screen_height(arg0) { + return wasm.__wbg_set_input_screen_height(this.ptr, arg0); + } + /** + * @returns {number} + */ + get mouse_x() { + return wasm.__wbg_get_input_mouse_x(this.ptr); + } + set mouse_x(arg0) { + return wasm.__wbg_set_input_mouse_x(this.ptr, arg0); + } + /** + * @returns {number} + */ + get mouse_y() { + return wasm.__wbg_get_input_mouse_y(this.ptr); + } + set mouse_y(arg0) { + return wasm.__wbg_set_input_mouse_y(this.ptr, arg0); + } + } + __exports.Input = Input; + + __exports.__wbindgen_throw = function(ptr, len) { + throw new Error(getStringFromWasm(ptr, len)); + }; + + function init(path_or_module) { + let instantiation; + const imports = { './emgui': __exports }; + if (path_or_module instanceof WebAssembly.Module) { + instantiation = WebAssembly.instantiate(path_or_module, imports) + .then(instance => { + return { instance, module: module_or_path } + }); + } else { + const data = fetch(path_or_module); + if (typeof WebAssembly.instantiateStreaming === 'function') { + instantiation = WebAssembly.instantiateStreaming(data, imports); + } else { + instantiation = data + .then(response => response.arrayBuffer()) + .then(buffer => WebAssembly.instantiate(buffer, imports)); + } + } + return instantiation.then(({instance}) => { + wasm = init.wasm = instance.exports; + return; + }); +}; +self.wasm_bindgen = Object.assign(init, __exports); +})(); diff --git a/docs/emgui_bg.wasm b/docs/emgui_bg.wasm new file mode 100644 index 0000000000000000000000000000000000000000..526b6f0be557c388716ae36e20d1c1ae44cd4bd2 GIT binary patch literal 125328 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 literal 0 HcmV?d00001 diff --git a/docs/frontend.js b/docs/frontend.js new file mode 100644 index 000000000..381b2a497 --- /dev/null +++ b/docs/frontend.js @@ -0,0 +1,112 @@ +// ---------------------------------------------------------------------------- +// Paint module: +function paintCommand(canvas, cmd) { + var ctx = canvas.getContext("2d"); + switch (cmd.kind) { + case "clear": + ctx.fillStyle = cmd.fill_style; + ctx.clearRect(0, 0, canvas.width, canvas.height); + return; + case "line": + ctx.beginPath(); + ctx.lineWidth = cmd.line_width; + ctx.strokeStyle = cmd.stroke_style; + ctx.moveTo(cmd.from[0], cmd.from[1]); + ctx.lineTo(cmd.to[0], cmd.to[1]); + ctx.stroke(); + return; + case "circle": + ctx.fillStyle = cmd.fill_style; + ctx.beginPath(); + ctx.arc(cmd.center[0], cmd.center[1], cmd.radius, 0, 2 * Math.PI, false); + ctx.fill(); + return; + case "rounded_rect": + ctx.fillStyle = cmd.fill_style; + var x = cmd.pos[0]; + var y = cmd.pos[1]; + var width = cmd.size[0]; + var height = cmd.size[1]; + var radius = cmd.radius; + ctx.beginPath(); + ctx.moveTo(x + radius, y); + ctx.lineTo(x + width - radius, y); + ctx.quadraticCurveTo(x + width, y, x + width, y + radius); + ctx.lineTo(x + width, y + height - radius); + ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height); + ctx.lineTo(x + radius, y + height); + ctx.quadraticCurveTo(x, y + height, x, y + height - radius); + ctx.lineTo(x, y + radius); + ctx.quadraticCurveTo(x, y, x + radius, y); + ctx.closePath(); + ctx.fill(); + return; + case "text": + ctx.font = cmd.font; + ctx.fillStyle = cmd.fill_style; + ctx.textAlign = cmd.text_align; + ctx.fillText(cmd.text, cmd.pos[0], cmd.pos[1]); + return; + } +} +// we'll defer our execution until the wasm is ready to go +function wasm_loaded() { + console.log("wasm loaded"); + initialize(); +} +// here we tell bindgen the path to the wasm file so it can start +// initialization and return to us a promise when it's done +wasm_bindgen("./emgui_bg.wasm") + .then(wasm_loaded)["catch"](console.error); +function rust_gui(input) { + return JSON.parse(wasm_bindgen.show_gui(JSON.stringify(input))); +} +// ---------------------------------------------------------------------------- +function js_gui(input) { + var commands = []; + commands.push({ + fillStyle: "#111111", + kind: "clear" + }); + commands.push({ + fillStyle: "#ff1111", + kind: "rounded_rect", + pos: [100, 100], + radius: 20, + size: [200, 100] + }); + return commands; +} +function paint_gui(canvas, mouse_pos) { + var input = { + mouse_x: mouse_pos.x, + mouse_y: mouse_pos.y, + screen_height: canvas.height, + screen_width: canvas.width + }; + var commands = rust_gui(input); + for (var _i = 0, commands_1 = commands; _i < commands_1.length; _i++) { + var cmd = commands_1[_i]; + paintCommand(canvas, cmd); + } +} +// ---------------------------------------------------------------------------- +function mouse_pos_from_event(canvas, evt) { + var rect = canvas.getBoundingClientRect(); + return { + x: evt.clientX - rect.left, + y: evt.clientY - rect.top + }; +} +function initialize() { + var canvas = document.getElementById("canvas"); + canvas.addEventListener("mousemove", function (evt) { + var mouse_pos = mouse_pos_from_event(canvas, evt); + paint_gui(canvas, mouse_pos); + }, false); + canvas.addEventListener("mousedown", function (evt) { + var mouse_pos = mouse_pos_from_event(canvas, evt); + paint_gui(canvas, mouse_pos); + }, false); + paint_gui(canvas, { x: 0, y: 0 }); +} diff --git a/docs/frontend.ts b/docs/frontend.ts new file mode 100644 index 000000000..ac0bc5ba2 --- /dev/null +++ b/docs/frontend.ts @@ -0,0 +1,206 @@ +// ---------------------------------------------------------------------------- +// Paint module: + +interface Clear { + kind: "clear"; + fill_style: string; +} + +interface Line { + kind: "line"; + from: [number, number]; + line_width: number; + stroke_style: string; + to: [number, number]; +} + +interface Circle { + kind: "circle"; + center: [number, number]; + fill_style: string; + radius: number; +} + +interface RoundedRect { + kind: "rounded_rect"; + fill_style: string; + pos: [number, number]; + radius: number; + size: [number, number]; +} + +interface Text { + kind: "text"; + fill_style: string; + font: string; + pos: [number, number]; + text: string; + text_align: "start" | "center" | "end"; +} + +type PaintCmd = Clear | Line | Circle | RoundedRect | Text; + +function paintCommand(canvas, cmd: PaintCmd) { + const ctx = canvas.getContext("2d"); + + switch (cmd.kind) { + case "clear": + ctx.fillStyle = cmd.fill_style; + ctx.clearRect(0, 0, canvas.width, canvas.height); + return; + + case "line": + ctx.beginPath(); + ctx.lineWidth = cmd.line_width; + ctx.strokeStyle = cmd.stroke_style; + ctx.moveTo(cmd.from[0], cmd.from[1]); + ctx.lineTo(cmd.to[0], cmd.to[1]); + ctx.stroke(); + return; + + case "circle": + ctx.fillStyle = cmd.fill_style; + ctx.beginPath(); + ctx.arc(cmd.center[0], cmd.center[1], cmd.radius, 0, 2 * Math.PI, false); + ctx.fill(); + return; + + case "rounded_rect": + ctx.fillStyle = cmd.fill_style; + const x = cmd.pos[0]; + const y = cmd.pos[1]; + const width = cmd.size[0]; + const height = cmd.size[1]; + const radius = cmd.radius; + ctx.beginPath(); + ctx.moveTo(x + radius, y); + ctx.lineTo(x + width - radius, y); + ctx.quadraticCurveTo(x + width, y, x + width, y + radius); + ctx.lineTo(x + width, y + height - radius); + ctx.quadraticCurveTo( + x + width, + y + height, + x + width - radius, + y + height, + ); + ctx.lineTo(x + radius, y + height); + ctx.quadraticCurveTo(x, y + height, x, y + height - radius); + ctx.lineTo(x, y + radius); + ctx.quadraticCurveTo(x, y, x + radius, y); + ctx.closePath(); + ctx.fill(); + return; + + case "text": + ctx.font = cmd.font; + ctx.fillStyle = cmd.fill_style; + ctx.textAlign = cmd.text_align; + ctx.fillText(cmd.text, cmd.pos[0], cmd.pos[1]); + return; + } +} + +// ---------------------------------------------------------------------------- + +interface Coord { + x: number; + y: number; +} + +interface Input { + mouse_x: number; + mouse_y: number; + screen_height: number; + screen_width: number; + // TODO: mouse down etc +} + +// ---------------------------------------------------------------------------- + +// the `wasm_bindgen` global is set to the exports of the Rust module. Override with wasm-bindgen --no-modules-global +declare var wasm_bindgen: any; + +// we'll defer our execution until the wasm is ready to go +function wasm_loaded() { + console.log(`wasm loaded`); + initialize(); +} + +// here we tell bindgen the path to the wasm file so it can start +// initialization and return to us a promise when it's done +wasm_bindgen("./emgui_bg.wasm") + .then(wasm_loaded) + .catch(console.error); + +function rust_gui(input: Input): PaintCmd[] { + return JSON.parse(wasm_bindgen.show_gui(JSON.stringify(input))); +} + +// ---------------------------------------------------------------------------- + +function js_gui(input: Input): PaintCmd[] { + const commands = []; + + commands.push({ + fillStyle: "#111111", + kind: "clear", + }); + + commands.push({ + fillStyle: "#ff1111", + kind: "rounded_rect", + pos: [100, 100], + radius: 20, + size: [200, 100], + }); + + return commands; +} + +function paint_gui(canvas, mouse_pos) { + const input = { + mouse_x: mouse_pos.x, + mouse_y: mouse_pos.y, + screen_height: canvas.height, + screen_width: canvas.width, + }; + const commands = rust_gui(input); + + for (const cmd of commands) { + paintCommand(canvas, cmd); + } +} + +// ---------------------------------------------------------------------------- + +function mouse_pos_from_event(canvas, evt): Coord { + const rect = canvas.getBoundingClientRect(); + return { + x: evt.clientX - rect.left, + y: evt.clientY - rect.top, + }; +} + +function initialize() { + const canvas = document.getElementById("canvas"); + + canvas.addEventListener( + "mousemove", + (evt) => { + const mouse_pos = mouse_pos_from_event(canvas, evt); + paint_gui(canvas, mouse_pos); + }, + false, + ); + + canvas.addEventListener( + "mousedown", + (evt) => { + const mouse_pos = mouse_pos_from_event(canvas, evt); + paint_gui(canvas, mouse_pos); + }, + false, + ); + + paint_gui(canvas, { x: 0, y: 0 }); +} diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 000000000..89e659037 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,44 @@ + + + + + Gui Experiment + + + + + + + + + + + + + + + + diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 000000000..0f4b0e1f2 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,70 @@ +extern crate serde; +extern crate serde_json; +extern crate wasm_bindgen; +extern crate web_sys; +#[macro_use] +extern crate serde_derive; + +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +#[derive(Deserialize)] +pub struct Input { + pub screen_width: f32, + pub screen_height: f32, + pub mouse_x: f32, + pub mouse_y: f32, +} + +#[derive(Serialize)] +#[serde(rename_all = "snake_case")] +enum TextAlign { + Start, + Center, + End, +} + +#[derive(Serialize)] +#[serde(rename_all = "snake_case", tag = "kind")] +enum PaintCmd { + Clear { + fill_style: String, + }, + RoundedRect { + fill_style: String, + pos: [f32; 2], + size: [f32; 2], + radius: f32, + }, + Text { + fill_style: String, + font: String, + pos: [f32; 2], + text: String, + text_align: TextAlign, + }, +} + +#[wasm_bindgen] +pub fn show_gui(input_json: &str) -> String { + let input: Input = serde_json::from_str(input_json).unwrap(); + let commands = [ + PaintCmd::Clear { + fill_style: "#44444400".to_string(), + }, + PaintCmd::RoundedRect { + fill_style: "#1111ff".to_string(), + pos: [100.0, 100.0], + radius: 40.0, + size: [200.0, 200.0], + }, + PaintCmd::Text { + fill_style: "#11ff00".to_string(), + font: "14px Palatino".to_string(), + pos: [200.0, 32.0], + text: format!("Mouse pos: {} {}", input.mouse_x, input.mouse_y), + text_align: TextAlign::Center, + }, + ]; + serde_json::to_string(&commands).unwrap() +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 000000000..1683d98ec --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "module": "es2015", + }, + "include": [ + "docs/**/*" + ] +} diff --git a/tslint.json b/tslint.json new file mode 100644 index 000000000..6983dcaf1 --- /dev/null +++ b/tslint.json @@ -0,0 +1,15 @@ +{ + "defaultSeverity": "error", + "extends": [ + "tslint:recommended" + ], + "jsRules": {}, + "rules": { + "interface-name": [true, "never-prefix"], + "max-classes-per-file": [false], + "no-bitwise": false, + "no-console": false, + "variable-name": false + }, + "rulesDirectory": [] +}