diff --git a/README.md b/README.md
index 2f99f5a6..e7189c37 100644
--- a/README.md
+++ b/README.md
@@ -24,3 +24,7 @@ Everything else is written in Rust, compiled to WASM.
Make an "any" editor. Store text files, make a VERY SIMPLE text editor, in the web.
Supports MARKDEEP. A place for you ideas. Stored on your computer (local storage).
+
+# Credits / Licenses
+
+ProggyClean.ttf, Copyright (c) 2004, 2005 Tristan Grimmer. MIT License. http://www.proggyfonts.net/
diff --git a/build.sh b/build.sh
index 40409d83..023e9e8a 100755
--- a/build.sh
+++ b/build.sh
@@ -26,7 +26,7 @@ function build_rust
echo "Generate JS bindings for wasm:"
FOLDER_NAME=${PWD##*/}
- TARGET_NAME="$FOLDER_NAME.wasm"
+ TARGET_NAME="emgui_wasm.wasm"
wasm-bindgen "target/wasm32-unknown-unknown/$BUILD/$TARGET_NAME" \
--out-dir docs --no-modules
# --no-modules-global hoboho
diff --git a/docs/emgui.d.ts b/docs/emgui.d.ts
deleted file mode 100644
index 2614fc9a..00000000
--- a/docs/emgui.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-/* tslint:disable */
-export function show_gui(arg0: string): string;
-
diff --git a/docs/emgui.js b/docs/emgui.js
deleted file mode 100644
index 7ae8bf76..00000000
--- a/docs/emgui.js
+++ /dev/null
@@ -1,102 +0,0 @@
-(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;
- }
-
- let WASM_VECTOR_LEN = 0;
-
- function passStringToWasm(arg) {
-
- const buf = cachedTextEncoder.encode(arg);
- const ptr = wasm.__wbindgen_malloc(buf.length);
- getUint8Memory().set(buf, ptr);
- WASM_VECTOR_LEN = buf.length;
- return ptr;
- }
-
- 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 = passStringToWasm(arg0);
- const len0 = WASM_VECTOR_LEN;
- 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);
-
- }
-
- };
-
- __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: path_or_module }
- });
- } 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;
-
- });
-};
-self.wasm_bindgen = Object.assign(init, __exports);
-})();
diff --git a/docs/emgui_bg.wasm b/docs/emgui_bg.wasm
deleted file mode 100644
index 62a3c82b..00000000
Binary files a/docs/emgui_bg.wasm and /dev/null differ
diff --git a/docs/emgui_wasm.js b/docs/emgui_wasm.js
new file mode 100644
index 00000000..a9c002cf
--- /dev/null
+++ b/docs/emgui_wasm.js
@@ -0,0 +1,561 @@
+(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;
+ }
+
+ let WASM_VECTOR_LEN = 0;
+
+ function passStringToWasm(arg) {
+
+ const buf = cachedTextEncoder.encode(arg);
+ const ptr = wasm.__wbindgen_malloc(buf.length);
+ getUint8Memory().set(buf, ptr);
+ WASM_VECTOR_LEN = buf.length;
+ return ptr;
+ }
+
+ 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 = passStringToWasm(arg0);
+ const len0 = WASM_VECTOR_LEN;
+ 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);
+
+ }
+
+ };
+
+ /**
+ * @param {string} arg0
+ * @returns {Painter}
+ */
+ __exports.new_webgl_painter = function(arg0) {
+ const ptr0 = passStringToWasm(arg0);
+ const len0 = WASM_VECTOR_LEN;
+ try {
+ return Painter.__wrap(wasm.new_webgl_painter(ptr0, len0));
+
+ } finally {
+ wasm.__wbindgen_free(ptr0, len0 * 1);
+
+ }
+
+ };
+
+ /**
+ * @param {Painter} arg0
+ * @param {string} arg1
+ * @returns {void}
+ */
+ __exports.paint_webgl = function(arg0, arg1) {
+ const ptr1 = passStringToWasm(arg1);
+ const len1 = WASM_VECTOR_LEN;
+ try {
+ return wasm.paint_webgl(arg0.ptr, ptr1, len1);
+
+ } finally {
+ wasm.__wbindgen_free(ptr1, len1 * 1);
+
+ }
+
+ };
+
+ const heap = new Array(32);
+
+ heap.fill(undefined);
+
+ heap.push(undefined, null, true, false);
+
+function getObject(idx) { return heap[idx]; }
+
+let heap_next = heap.length;
+
+function addHeapObject(obj) {
+ if (heap_next === heap.length) heap.push(heap.length + 1);
+ const idx = heap_next;
+ heap_next = heap[idx];
+
+ heap[idx] = obj;
+ return idx;
+}
+
+function isLikeNone(x) {
+ return x === undefined || x === null;
+}
+
+const __widl_f_get_element_by_id_Document_target = typeof Document === 'undefined' ? null : Document.prototype.getElementById || function() {
+ throw new Error(`wasm-bindgen: Document.getElementById does not exist`);
+};
+
+__exports.__widl_f_get_element_by_id_Document = function(arg0, arg1, arg2) {
+ let varg1 = getStringFromWasm(arg1, arg2);
+
+ const val = __widl_f_get_element_by_id_Document_target.call(getObject(arg0), varg1);
+ return isLikeNone(val) ? 0 : addHeapObject(val);
+
+};
+
+__exports.__widl_instanceof_HTMLCanvasElement = function(idx) {
+ return getObject(idx) instanceof HTMLCanvasElement ? 1 : 0;
+};
+
+const __widl_f_get_context_HTMLCanvasElement_target = typeof HTMLCanvasElement === 'undefined' ? null : HTMLCanvasElement.prototype.getContext || function() {
+ throw new Error(`wasm-bindgen: HTMLCanvasElement.getContext does not exist`);
+};
+
+__exports.__widl_f_get_context_HTMLCanvasElement = function(arg0, arg1, arg2, exnptr) {
+ let varg1 = getStringFromWasm(arg1, arg2);
+ try {
+
+ const val = __widl_f_get_context_HTMLCanvasElement_target.call(getObject(arg0), varg1);
+ return isLikeNone(val) ? 0 : addHeapObject(val);
+
+ } catch (e) {
+ const view = getUint32Memory();
+ view[exnptr / 4] = 1;
+ view[exnptr / 4 + 1] = addHeapObject(e);
+
+ }
+};
+
+function GetOwnOrInheritedPropertyDescriptor(obj, id) {
+ while (obj) {
+ let desc = Object.getOwnPropertyDescriptor(obj, id);
+ if (desc) return desc;
+ obj = Object.getPrototypeOf(obj);
+ }
+return {}
+}
+
+const __widl_f_width_HTMLCanvasElement_target = GetOwnOrInheritedPropertyDescriptor(typeof HTMLCanvasElement === 'undefined' ? null : HTMLCanvasElement.prototype, 'width').get || function() {
+ throw new Error(`wasm-bindgen: HTMLCanvasElement.width does not exist`);
+};
+
+__exports.__widl_f_width_HTMLCanvasElement = function(arg0) {
+ return __widl_f_width_HTMLCanvasElement_target.call(getObject(arg0));
+};
+
+const __widl_f_height_HTMLCanvasElement_target = GetOwnOrInheritedPropertyDescriptor(typeof HTMLCanvasElement === 'undefined' ? null : HTMLCanvasElement.prototype, 'height').get || function() {
+ throw new Error(`wasm-bindgen: HTMLCanvasElement.height does not exist`);
+};
+
+__exports.__widl_f_height_HTMLCanvasElement = function(arg0) {
+ return __widl_f_height_HTMLCanvasElement_target.call(getObject(arg0));
+};
+
+__exports.__widl_instanceof_WebGLRenderingContext = function(idx) {
+ return getObject(idx) instanceof WebGLRenderingContext ? 1 : 0;
+};
+
+const __widl_f_buffer_data_with_array_buffer_view_WebGLRenderingContext_target = typeof WebGLRenderingContext === 'undefined' ? null : WebGLRenderingContext.prototype.bufferData || function() {
+ throw new Error(`wasm-bindgen: WebGLRenderingContext.bufferData does not exist`);
+};
+
+__exports.__widl_f_buffer_data_with_array_buffer_view_WebGLRenderingContext = function(arg0, arg1, arg2, arg3) {
+ __widl_f_buffer_data_with_array_buffer_view_WebGLRenderingContext_target.call(getObject(arg0), arg1, getObject(arg2), arg3);
+};
+
+const __widl_f_attach_shader_WebGLRenderingContext_target = typeof WebGLRenderingContext === 'undefined' ? null : WebGLRenderingContext.prototype.attachShader || function() {
+ throw new Error(`wasm-bindgen: WebGLRenderingContext.attachShader does not exist`);
+};
+
+__exports.__widl_f_attach_shader_WebGLRenderingContext = function(arg0, arg1, arg2) {
+ __widl_f_attach_shader_WebGLRenderingContext_target.call(getObject(arg0), getObject(arg1), getObject(arg2));
+};
+
+const __widl_f_bind_buffer_WebGLRenderingContext_target = typeof WebGLRenderingContext === 'undefined' ? null : WebGLRenderingContext.prototype.bindBuffer || function() {
+ throw new Error(`wasm-bindgen: WebGLRenderingContext.bindBuffer does not exist`);
+};
+
+__exports.__widl_f_bind_buffer_WebGLRenderingContext = function(arg0, arg1, arg2) {
+ __widl_f_bind_buffer_WebGLRenderingContext_target.call(getObject(arg0), arg1, getObject(arg2));
+};
+
+const __widl_f_blend_func_WebGLRenderingContext_target = typeof WebGLRenderingContext === 'undefined' ? null : WebGLRenderingContext.prototype.blendFunc || function() {
+ throw new Error(`wasm-bindgen: WebGLRenderingContext.blendFunc does not exist`);
+};
+
+__exports.__widl_f_blend_func_WebGLRenderingContext = function(arg0, arg1, arg2) {
+ __widl_f_blend_func_WebGLRenderingContext_target.call(getObject(arg0), arg1, arg2);
+};
+
+const __widl_f_clear_WebGLRenderingContext_target = typeof WebGLRenderingContext === 'undefined' ? null : WebGLRenderingContext.prototype.clear || function() {
+ throw new Error(`wasm-bindgen: WebGLRenderingContext.clear does not exist`);
+};
+
+__exports.__widl_f_clear_WebGLRenderingContext = function(arg0, arg1) {
+ __widl_f_clear_WebGLRenderingContext_target.call(getObject(arg0), arg1);
+};
+
+const __widl_f_clear_color_WebGLRenderingContext_target = typeof WebGLRenderingContext === 'undefined' ? null : WebGLRenderingContext.prototype.clearColor || function() {
+ throw new Error(`wasm-bindgen: WebGLRenderingContext.clearColor does not exist`);
+};
+
+__exports.__widl_f_clear_color_WebGLRenderingContext = function(arg0, arg1, arg2, arg3, arg4) {
+ __widl_f_clear_color_WebGLRenderingContext_target.call(getObject(arg0), arg1, arg2, arg3, arg4);
+};
+
+const __widl_f_compile_shader_WebGLRenderingContext_target = typeof WebGLRenderingContext === 'undefined' ? null : WebGLRenderingContext.prototype.compileShader || function() {
+ throw new Error(`wasm-bindgen: WebGLRenderingContext.compileShader does not exist`);
+};
+
+__exports.__widl_f_compile_shader_WebGLRenderingContext = function(arg0, arg1) {
+ __widl_f_compile_shader_WebGLRenderingContext_target.call(getObject(arg0), getObject(arg1));
+};
+
+const __widl_f_create_buffer_WebGLRenderingContext_target = typeof WebGLRenderingContext === 'undefined' ? null : WebGLRenderingContext.prototype.createBuffer || function() {
+ throw new Error(`wasm-bindgen: WebGLRenderingContext.createBuffer does not exist`);
+};
+
+__exports.__widl_f_create_buffer_WebGLRenderingContext = function(arg0) {
+
+ const val = __widl_f_create_buffer_WebGLRenderingContext_target.call(getObject(arg0));
+ return isLikeNone(val) ? 0 : addHeapObject(val);
+
+};
+
+const __widl_f_create_program_WebGLRenderingContext_target = typeof WebGLRenderingContext === 'undefined' ? null : WebGLRenderingContext.prototype.createProgram || function() {
+ throw new Error(`wasm-bindgen: WebGLRenderingContext.createProgram does not exist`);
+};
+
+__exports.__widl_f_create_program_WebGLRenderingContext = function(arg0) {
+
+ const val = __widl_f_create_program_WebGLRenderingContext_target.call(getObject(arg0));
+ return isLikeNone(val) ? 0 : addHeapObject(val);
+
+};
+
+const __widl_f_create_shader_WebGLRenderingContext_target = typeof WebGLRenderingContext === 'undefined' ? null : WebGLRenderingContext.prototype.createShader || function() {
+ throw new Error(`wasm-bindgen: WebGLRenderingContext.createShader does not exist`);
+};
+
+__exports.__widl_f_create_shader_WebGLRenderingContext = function(arg0, arg1) {
+
+ const val = __widl_f_create_shader_WebGLRenderingContext_target.call(getObject(arg0), arg1);
+ return isLikeNone(val) ? 0 : addHeapObject(val);
+
+};
+
+const __widl_f_draw_elements_with_i32_WebGLRenderingContext_target = typeof WebGLRenderingContext === 'undefined' ? null : WebGLRenderingContext.prototype.drawElements || function() {
+ throw new Error(`wasm-bindgen: WebGLRenderingContext.drawElements does not exist`);
+};
+
+__exports.__widl_f_draw_elements_with_i32_WebGLRenderingContext = function(arg0, arg1, arg2, arg3, arg4) {
+ __widl_f_draw_elements_with_i32_WebGLRenderingContext_target.call(getObject(arg0), arg1, arg2, arg3, arg4);
+};
+
+const __widl_f_enable_WebGLRenderingContext_target = typeof WebGLRenderingContext === 'undefined' ? null : WebGLRenderingContext.prototype.enable || function() {
+ throw new Error(`wasm-bindgen: WebGLRenderingContext.enable does not exist`);
+};
+
+__exports.__widl_f_enable_WebGLRenderingContext = function(arg0, arg1) {
+ __widl_f_enable_WebGLRenderingContext_target.call(getObject(arg0), arg1);
+};
+
+const __widl_f_enable_vertex_attrib_array_WebGLRenderingContext_target = typeof WebGLRenderingContext === 'undefined' ? null : WebGLRenderingContext.prototype.enableVertexAttribArray || function() {
+ throw new Error(`wasm-bindgen: WebGLRenderingContext.enableVertexAttribArray does not exist`);
+};
+
+__exports.__widl_f_enable_vertex_attrib_array_WebGLRenderingContext = function(arg0, arg1) {
+ __widl_f_enable_vertex_attrib_array_WebGLRenderingContext_target.call(getObject(arg0), arg1);
+};
+
+const __widl_f_get_attrib_location_WebGLRenderingContext_target = typeof WebGLRenderingContext === 'undefined' ? null : WebGLRenderingContext.prototype.getAttribLocation || function() {
+ throw new Error(`wasm-bindgen: WebGLRenderingContext.getAttribLocation does not exist`);
+};
+
+__exports.__widl_f_get_attrib_location_WebGLRenderingContext = function(arg0, arg1, arg2, arg3) {
+ let varg2 = getStringFromWasm(arg2, arg3);
+ return __widl_f_get_attrib_location_WebGLRenderingContext_target.call(getObject(arg0), getObject(arg1), varg2);
+};
+
+const __widl_f_get_program_info_log_WebGLRenderingContext_target = typeof WebGLRenderingContext === 'undefined' ? null : WebGLRenderingContext.prototype.getProgramInfoLog || function() {
+ throw new Error(`wasm-bindgen: WebGLRenderingContext.getProgramInfoLog does not exist`);
+};
+
+__exports.__widl_f_get_program_info_log_WebGLRenderingContext = function(ret, arg0, arg1) {
+ const val = __widl_f_get_program_info_log_WebGLRenderingContext_target.call(getObject(arg0), getObject(arg1));
+ const retptr = isLikeNone(val) ? [0, 0] : passStringToWasm(val);
+ const retlen = WASM_VECTOR_LEN;
+ const mem = getUint32Memory();
+ mem[ret / 4] = retptr;
+ mem[ret / 4 + 1] = retlen;
+
+};
+
+const __widl_f_get_program_parameter_WebGLRenderingContext_target = typeof WebGLRenderingContext === 'undefined' ? null : WebGLRenderingContext.prototype.getProgramParameter || function() {
+ throw new Error(`wasm-bindgen: WebGLRenderingContext.getProgramParameter does not exist`);
+};
+
+__exports.__widl_f_get_program_parameter_WebGLRenderingContext = function(arg0, arg1, arg2) {
+ return addHeapObject(__widl_f_get_program_parameter_WebGLRenderingContext_target.call(getObject(arg0), getObject(arg1), arg2));
+};
+
+const __widl_f_get_shader_info_log_WebGLRenderingContext_target = typeof WebGLRenderingContext === 'undefined' ? null : WebGLRenderingContext.prototype.getShaderInfoLog || function() {
+ throw new Error(`wasm-bindgen: WebGLRenderingContext.getShaderInfoLog does not exist`);
+};
+
+__exports.__widl_f_get_shader_info_log_WebGLRenderingContext = function(ret, arg0, arg1) {
+ const val = __widl_f_get_shader_info_log_WebGLRenderingContext_target.call(getObject(arg0), getObject(arg1));
+ const retptr = isLikeNone(val) ? [0, 0] : passStringToWasm(val);
+ const retlen = WASM_VECTOR_LEN;
+ const mem = getUint32Memory();
+ mem[ret / 4] = retptr;
+ mem[ret / 4 + 1] = retlen;
+
+};
+
+const __widl_f_get_shader_parameter_WebGLRenderingContext_target = typeof WebGLRenderingContext === 'undefined' ? null : WebGLRenderingContext.prototype.getShaderParameter || function() {
+ throw new Error(`wasm-bindgen: WebGLRenderingContext.getShaderParameter does not exist`);
+};
+
+__exports.__widl_f_get_shader_parameter_WebGLRenderingContext = function(arg0, arg1, arg2) {
+ return addHeapObject(__widl_f_get_shader_parameter_WebGLRenderingContext_target.call(getObject(arg0), getObject(arg1), arg2));
+};
+
+const __widl_f_get_uniform_location_WebGLRenderingContext_target = typeof WebGLRenderingContext === 'undefined' ? null : WebGLRenderingContext.prototype.getUniformLocation || function() {
+ throw new Error(`wasm-bindgen: WebGLRenderingContext.getUniformLocation does not exist`);
+};
+
+__exports.__widl_f_get_uniform_location_WebGLRenderingContext = function(arg0, arg1, arg2, arg3) {
+ let varg2 = getStringFromWasm(arg2, arg3);
+
+ const val = __widl_f_get_uniform_location_WebGLRenderingContext_target.call(getObject(arg0), getObject(arg1), varg2);
+ return isLikeNone(val) ? 0 : addHeapObject(val);
+
+};
+
+const __widl_f_link_program_WebGLRenderingContext_target = typeof WebGLRenderingContext === 'undefined' ? null : WebGLRenderingContext.prototype.linkProgram || function() {
+ throw new Error(`wasm-bindgen: WebGLRenderingContext.linkProgram does not exist`);
+};
+
+__exports.__widl_f_link_program_WebGLRenderingContext = function(arg0, arg1) {
+ __widl_f_link_program_WebGLRenderingContext_target.call(getObject(arg0), getObject(arg1));
+};
+
+const __widl_f_shader_source_WebGLRenderingContext_target = typeof WebGLRenderingContext === 'undefined' ? null : WebGLRenderingContext.prototype.shaderSource || function() {
+ throw new Error(`wasm-bindgen: WebGLRenderingContext.shaderSource does not exist`);
+};
+
+__exports.__widl_f_shader_source_WebGLRenderingContext = function(arg0, arg1, arg2, arg3) {
+ let varg2 = getStringFromWasm(arg2, arg3);
+ __widl_f_shader_source_WebGLRenderingContext_target.call(getObject(arg0), getObject(arg1), varg2);
+};
+
+const __widl_f_uniform2f_WebGLRenderingContext_target = typeof WebGLRenderingContext === 'undefined' ? null : WebGLRenderingContext.prototype.uniform2f || function() {
+ throw new Error(`wasm-bindgen: WebGLRenderingContext.uniform2f does not exist`);
+};
+
+__exports.__widl_f_uniform2f_WebGLRenderingContext = function(arg0, arg1, arg2, arg3) {
+ __widl_f_uniform2f_WebGLRenderingContext_target.call(getObject(arg0), getObject(arg1), arg2, arg3);
+};
+
+const __widl_f_use_program_WebGLRenderingContext_target = typeof WebGLRenderingContext === 'undefined' ? null : WebGLRenderingContext.prototype.useProgram || function() {
+ throw new Error(`wasm-bindgen: WebGLRenderingContext.useProgram does not exist`);
+};
+
+__exports.__widl_f_use_program_WebGLRenderingContext = function(arg0, arg1) {
+ __widl_f_use_program_WebGLRenderingContext_target.call(getObject(arg0), getObject(arg1));
+};
+
+const __widl_f_vertex_attrib_pointer_with_i32_WebGLRenderingContext_target = typeof WebGLRenderingContext === 'undefined' ? null : WebGLRenderingContext.prototype.vertexAttribPointer || function() {
+ throw new Error(`wasm-bindgen: WebGLRenderingContext.vertexAttribPointer does not exist`);
+};
+
+__exports.__widl_f_vertex_attrib_pointer_with_i32_WebGLRenderingContext = function(arg0, arg1, arg2, arg3, arg4, arg5, arg6) {
+ __widl_f_vertex_attrib_pointer_with_i32_WebGLRenderingContext_target.call(getObject(arg0), arg1, arg2, arg3, arg4 !== 0, arg5, arg6);
+};
+
+__exports.__widl_instanceof_Window = function(idx) {
+ return getObject(idx) instanceof Window ? 1 : 0;
+};
+
+__exports.__widl_f_document_Window = function(arg0) {
+
+ const val = getObject(arg0).document;
+ return isLikeNone(val) ? 0 : addHeapObject(val);
+
+};
+
+__exports.__wbg_new_c1b585153cd441ad = function(arg0) {
+ return addHeapObject(new Float32Array(getObject(arg0)));
+};
+
+__exports.__wbg_subarray_6bef35518c0617bd = function(arg0, arg1, arg2) {
+ return addHeapObject(getObject(arg0).subarray(arg1, arg2));
+};
+
+__exports.__wbg_newnoargs_6a80f84471205fc8 = function(arg0, arg1) {
+ let varg0 = getStringFromWasm(arg0, arg1);
+ return addHeapObject(new Function(varg0));
+};
+
+__exports.__wbg_call_582b20dfcad7fee4 = function(arg0, arg1, exnptr) {
+ try {
+ return addHeapObject(getObject(arg0).call(getObject(arg1)));
+ } catch (e) {
+ const view = getUint32Memory();
+ view[exnptr / 4] = 1;
+ view[exnptr / 4 + 1] = addHeapObject(e);
+
+ }
+};
+
+__exports.__wbg_new_b192e0932f97e870 = function(arg0) {
+ return addHeapObject(new Int16Array(getObject(arg0)));
+};
+
+__exports.__wbg_subarray_46088290ce2ce733 = function(arg0, arg1, arg2) {
+ return addHeapObject(getObject(arg0).subarray(arg1, arg2));
+};
+
+__exports.__wbg_new_bc68e7aae4d4f791 = function(arg0) {
+ return addHeapObject(new Uint8Array(getObject(arg0)));
+};
+
+__exports.__wbg_subarray_705096b76e15e94e = function(arg0, arg1, arg2) {
+ return addHeapObject(getObject(arg0).subarray(arg1, arg2));
+};
+
+__exports.__wbg_instanceof_Memory_d223615e29613829 = function(idx) {
+ return getObject(idx) instanceof WebAssembly.Memory ? 1 : 0;
+};
+
+__exports.__wbg_buffer_0413d5edaa0ff323 = function(arg0) {
+ return addHeapObject(getObject(arg0).buffer);
+};
+
+function freePainter(ptr) {
+
+ wasm.__wbg_painter_free(ptr);
+}
+/**
+*/
+class Painter {
+
+ static __wrap(ptr) {
+ const obj = Object.create(Painter.prototype);
+ obj.ptr = ptr;
+
+ return obj;
+ }
+
+ free() {
+ const ptr = this.ptr;
+ this.ptr = 0;
+ freePainter(ptr);
+ }
+
+}
+__exports.Painter = Painter;
+
+__exports.__wbindgen_object_clone_ref = function(idx) {
+ return addHeapObject(getObject(idx));
+};
+
+function dropObject(idx) {
+ if (idx < 36) return;
+ heap[idx] = heap_next;
+ heap_next = idx;
+}
+
+__exports.__wbindgen_object_drop_ref = function(i) { dropObject(i); };
+
+__exports.__wbindgen_string_new = function(p, l) {
+ return addHeapObject(getStringFromWasm(p, l));
+};
+
+__exports.__wbindgen_boolean_get = function(i) {
+ let v = getObject(i);
+ if (typeof(v) === 'boolean') {
+ return v ? 1 : 0;
+ } else {
+ return 2;
+ }
+};
+
+__exports.__wbindgen_memory = function() { return addHeapObject(wasm.memory); };
+
+function takeObject(idx) {
+ const ret = getObject(idx);
+ dropObject(idx);
+ return ret;
+}
+
+__exports.__wbindgen_rethrow = function(idx) { throw takeObject(idx); };
+
+__exports.__wbindgen_throw = function(ptr, len) {
+ throw new Error(getStringFromWasm(ptr, len));
+};
+
+function init(path_or_module) {
+ let instantiation;
+ const imports = { './emgui_wasm': __exports };
+ if (path_or_module instanceof WebAssembly.Module) {
+ instantiation = WebAssembly.instantiate(path_or_module, imports)
+ .then(instance => {
+ return { instance, module: path_or_module }
+ });
+} 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;
+
+});
+};
+self.wasm_bindgen = Object.assign(init, __exports);
+})();
diff --git a/docs/emgui_wasm_bg.wasm b/docs/emgui_wasm_bg.wasm
new file mode 100644
index 00000000..91399a39
Binary files /dev/null and b/docs/emgui_wasm_bg.wasm differ
diff --git a/docs/frontend.js b/docs/frontend.js
index 95b35564..690b0a3c 100644
--- a/docs/frontend.js
+++ b/docs/frontend.js
@@ -1,4 +1,6 @@
-function styleFromColor(color) {
+// ----------------------------------------------------------------------------
+// Canvas painting:
+function style_from_color(color) {
return "rgba(" + color.r + ", " + color.g + ", " + color.b + ", " + color.a / 255.0 + ")";
}
function paint_command(canvas, cmd) {
@@ -9,17 +11,17 @@ function paint_command(canvas, cmd) {
ctx.beginPath();
ctx.arc(cmd.center.x, cmd.center.y, cmd.radius, 0, 2 * Math.PI, false);
if (cmd.fill_color) {
- ctx.fillStyle = styleFromColor(cmd.fill_color);
+ ctx.fillStyle = style_from_color(cmd.fill_color);
ctx.fill();
}
if (cmd.outline) {
ctx.lineWidth = cmd.outline.width;
- ctx.strokeStyle = styleFromColor(cmd.outline.color);
+ ctx.strokeStyle = style_from_color(cmd.outline.color);
ctx.stroke();
}
return;
case "clear":
- ctx.fillStyle = styleFromColor(cmd.fill_color);
+ ctx.fillStyle = style_from_color(cmd.fill_color);
ctx.clearRect(0, 0, canvas.width, canvas.height);
return;
case "line":
@@ -30,7 +32,7 @@ function paint_command(canvas, cmd) {
ctx.lineTo(point.x, point.y);
}
ctx.lineWidth = cmd.width;
- ctx.strokeStyle = styleFromColor(cmd.color);
+ ctx.strokeStyle = style_from_color(cmd.color);
ctx.stroke();
return;
case "rect":
@@ -51,17 +53,17 @@ function paint_command(canvas, cmd) {
ctx.quadraticCurveTo(x, y, x + r, y);
ctx.closePath();
if (cmd.fill_color) {
- ctx.fillStyle = styleFromColor(cmd.fill_color);
+ ctx.fillStyle = style_from_color(cmd.fill_color);
ctx.fill();
}
if (cmd.outline) {
ctx.lineWidth = cmd.outline.width;
- ctx.strokeStyle = styleFromColor(cmd.outline.color);
+ ctx.strokeStyle = style_from_color(cmd.outline.color);
ctx.stroke();
}
return;
case "text":
- ctx.fillStyle = styleFromColor(cmd.fill_color);
+ ctx.fillStyle = style_from_color(cmd.fill_color);
ctx.font = cmd.font_size + "px " + cmd.font_name;
ctx.textBaseline = "middle";
ctx.fillText(cmd.text, cmd.pos.x, cmd.pos.y);
@@ -75,7 +77,7 @@ function wasm_loaded() {
}
// 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")
+wasm_bindgen("./emgui_wasm_bg.wasm")
.then(wasm_loaded)["catch"](console.error);
function rust_gui(input) {
return JSON.parse(wasm_bindgen.show_gui(JSON.stringify(input)));
@@ -96,27 +98,45 @@ function js_gui(input) {
});
return commands;
}
+var WEB_GL = true;
+var g_webgl_painter = null;
function paint_gui(canvas, input) {
- var commands = rust_gui(input);
- commands.unshift({
- fill_color: { r: 0, g: 0, b: 0, a: 0 },
- kind: "clear"
- });
- for (var _i = 0, commands_1 = commands; _i < commands_1.length; _i++) {
- var cmd = commands_1[_i];
- paint_command(canvas, cmd);
+ if (WEB_GL) {
+ if (g_webgl_painter === null) {
+ g_webgl_painter = wasm_bindgen.new_webgl_painter("canvas");
+ }
+ wasm_bindgen.paint_webgl(g_webgl_painter, JSON.stringify(input));
+ }
+ else {
+ var commands = rust_gui(input);
+ for (var _i = 0, commands_1 = commands; _i < commands_1.length; _i++) {
+ var cmd = commands_1[_i];
+ var commands_2 = rust_gui(input);
+ commands_2.unshift({
+ fill_color: { r: 0, g: 0, b: 0, a: 0 },
+ kind: "clear"
+ });
+ paint_command(canvas, cmd);
+ }
}
}
// ----------------------------------------------------------------------------
var g_mouse_pos = { x: -1000.0, y: -1000.0 };
var g_mouse_down = false;
+function auto_resize_canvas(canvas) {
+ if (WEB_GL) {
+ canvas.setAttribute("width", window.innerWidth);
+ canvas.setAttribute("height", window.innerHeight);
+ }
+ else {
+ var pixels_per_point = window.devicePixelRatio || 1;
+ var ctx = canvas.getContext("2d");
+ ctx.scale(pixels_per_point, pixels_per_point);
+ canvas.setAttribute("width", window.innerWidth * pixels_per_point);
+ canvas.setAttribute("height", window.innerHeight * pixels_per_point);
+ }
+}
function get_input(canvas) {
- var pixels_per_point = window.devicePixelRatio || 1;
- var ctx = canvas.getContext("2d");
- ctx.scale(pixels_per_point, pixels_per_point);
- // Resize based on screen size:
- canvas.setAttribute("width", window.innerWidth * pixels_per_point);
- canvas.setAttribute("height", window.innerHeight * pixels_per_point);
return {
mouse_down: g_mouse_down,
mouse_pos: g_mouse_pos,
@@ -133,6 +153,7 @@ function mouse_pos_from_event(canvas, event) {
function initialize() {
console.log("window.devicePixelRatio: " + window.devicePixelRatio);
var canvas = document.getElementById("canvas");
+ auto_resize_canvas(canvas);
var repaint = function () { return paint_gui(canvas, get_input(canvas)); };
canvas.addEventListener("mousemove", function (event) {
g_mouse_pos = mouse_pos_from_event(canvas, event);
diff --git a/docs/frontend.ts b/docs/frontend.ts
index 75f3e268..9213b2c4 100644
--- a/docs/frontend.ts
+++ b/docs/frontend.ts
@@ -60,7 +60,10 @@ interface Text {
type PaintCmd = Circle | Clear | Line | Rect | Text;
-function styleFromColor(color: Color): string {
+// ----------------------------------------------------------------------------
+// Canvas painting:
+
+function style_from_color(color: Color): string {
return `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a / 255.0})`;
}
@@ -74,18 +77,18 @@ function paint_command(canvas, cmd: PaintCmd) {
ctx.beginPath();
ctx.arc(cmd.center.x, cmd.center.y, cmd.radius, 0, 2 * Math.PI, false);
if (cmd.fill_color) {
- ctx.fillStyle = styleFromColor(cmd.fill_color);
+ ctx.fillStyle = style_from_color(cmd.fill_color);
ctx.fill();
}
if (cmd.outline) {
ctx.lineWidth = cmd.outline.width;
- ctx.strokeStyle = styleFromColor(cmd.outline.color);
+ ctx.strokeStyle = style_from_color(cmd.outline.color);
ctx.stroke();
}
return;
case "clear":
- ctx.fillStyle = styleFromColor(cmd.fill_color);
+ ctx.fillStyle = style_from_color(cmd.fill_color);
ctx.clearRect(0, 0, canvas.width, canvas.height);
return;
@@ -96,7 +99,7 @@ function paint_command(canvas, cmd: PaintCmd) {
ctx.lineTo(point.x, point.y);
}
ctx.lineWidth = cmd.width;
- ctx.strokeStyle = styleFromColor(cmd.color);
+ ctx.strokeStyle = style_from_color(cmd.color);
ctx.stroke();
return;
@@ -118,18 +121,18 @@ function paint_command(canvas, cmd: PaintCmd) {
ctx.quadraticCurveTo(x, y, x + r, y);
ctx.closePath();
if (cmd.fill_color) {
- ctx.fillStyle = styleFromColor(cmd.fill_color);
+ ctx.fillStyle = style_from_color(cmd.fill_color);
ctx.fill();
}
if (cmd.outline) {
ctx.lineWidth = cmd.outline.width;
- ctx.strokeStyle = styleFromColor(cmd.outline.color);
+ ctx.strokeStyle = style_from_color(cmd.outline.color);
ctx.stroke();
}
return;
case "text":
- ctx.fillStyle = styleFromColor(cmd.fill_color);
+ ctx.fillStyle = style_from_color(cmd.fill_color);
ctx.font = `${cmd.font_size}px ${cmd.font_name}`;
ctx.textBaseline = "middle";
ctx.fillText(cmd.text, cmd.pos.x, cmd.pos.y);
@@ -164,7 +167,7 @@ function wasm_loaded() {
// 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")
+wasm_bindgen("./emgui_wasm_bg.wasm")
.then(wasm_loaded)
.catch(console.error);
@@ -193,15 +196,26 @@ function js_gui(input: RawInput): PaintCmd[] {
return commands;
}
-function paint_gui(canvas, input: RawInput) {
- const commands = rust_gui(input);
- commands.unshift({
- fill_color: {r: 0, g: 0, b: 0, a: 0},
- kind: "clear",
- });
+const WEB_GL = true;
+let g_webgl_painter = null;
- for (const cmd of commands) {
- paint_command(canvas, cmd);
+function paint_gui(canvas, input: RawInput) {
+ if (WEB_GL) {
+ if (g_webgl_painter === null) {
+ g_webgl_painter = wasm_bindgen.new_webgl_painter("canvas");
+ }
+ wasm_bindgen.paint_webgl(g_webgl_painter, JSON.stringify(input));
+ } else {
+ let commands = rust_gui(input);
+ for (const cmd of commands) {
+ const commands = rust_gui(input);
+ commands.unshift({
+ fill_color: { r: 0, g: 0, b: 0, a: 0 },
+ kind: "clear",
+ });
+
+ paint_command(canvas, cmd);
+ }
}
}
@@ -210,16 +224,22 @@ function paint_gui(canvas, input: RawInput) {
let g_mouse_pos = { x: -1000.0, y: -1000.0 };
let g_mouse_down = false;
+function auto_resize_canvas(canvas) {
+ if (WEB_GL) {
+ canvas.setAttribute("width", window.innerWidth);
+ canvas.setAttribute("height", window.innerHeight);
+ } else {
+ const pixels_per_point = window.devicePixelRatio || 1;
+
+ const ctx = canvas.getContext("2d");
+ ctx.scale(pixels_per_point, pixels_per_point);
+
+ canvas.setAttribute("width", window.innerWidth * pixels_per_point);
+ canvas.setAttribute("height", window.innerHeight * pixels_per_point);
+ }
+}
+
function get_input(canvas): RawInput {
- const pixels_per_point = window.devicePixelRatio || 1;
-
- const ctx = canvas.getContext("2d");
- ctx.scale(pixels_per_point, pixels_per_point);
-
- // Resize based on screen size:
- canvas.setAttribute("width", window.innerWidth * pixels_per_point);
- canvas.setAttribute("height", window.innerHeight * pixels_per_point);
-
return {
mouse_down: g_mouse_down,
mouse_pos: g_mouse_pos,
@@ -239,49 +259,38 @@ function initialize() {
console.log(`window.devicePixelRatio: ${window.devicePixelRatio}`);
const canvas = document.getElementById("canvas");
+ auto_resize_canvas(canvas);
const repaint = () => paint_gui(canvas, get_input(canvas));
- canvas.addEventListener(
- "mousemove",
- (event) => {
- g_mouse_pos = mouse_pos_from_event(canvas, event);
- repaint();
- event.stopPropagation();
- event.preventDefault();
- },
- );
+ canvas.addEventListener("mousemove", event => {
+ g_mouse_pos = mouse_pos_from_event(canvas, event);
+ repaint();
+ event.stopPropagation();
+ event.preventDefault();
+ });
- canvas.addEventListener(
- "mouseleave",
- (event) => {
- g_mouse_pos = { x: -1000.0, y: -1000.0 };
- repaint();
- event.stopPropagation();
- event.preventDefault();
- },
- );
+ canvas.addEventListener("mouseleave", event => {
+ g_mouse_pos = { x: -1000.0, y: -1000.0 };
+ repaint();
+ event.stopPropagation();
+ event.preventDefault();
+ });
- canvas.addEventListener(
- "mousedown",
- (event) => {
- g_mouse_pos = mouse_pos_from_event(canvas, event);
- g_mouse_down = true;
- repaint();
- event.stopPropagation();
- event.preventDefault();
- },
- );
+ canvas.addEventListener("mousedown", event => {
+ g_mouse_pos = mouse_pos_from_event(canvas, event);
+ g_mouse_down = true;
+ repaint();
+ event.stopPropagation();
+ event.preventDefault();
+ });
- canvas.addEventListener(
- "mouseup",
- (event) => {
- g_mouse_pos = mouse_pos_from_event(canvas, event);
- g_mouse_down = false;
- repaint();
- event.stopPropagation();
- event.preventDefault();
- },
- );
+ canvas.addEventListener("mouseup", event => {
+ g_mouse_pos = mouse_pos_from_event(canvas, event);
+ g_mouse_down = false;
+ repaint();
+ event.stopPropagation();
+ event.preventDefault();
+ });
window.addEventListener("load", repaint);
window.addEventListener("pagehide", repaint);
diff --git a/docs/index.html b/docs/index.html
index 31720ec9..27cc38ec 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -32,7 +32,7 @@
-
+
diff --git a/emgui/Cargo.toml b/emgui/Cargo.toml
index 6be652f4..d0de91a9 100644
--- a/emgui/Cargo.toml
+++ b/emgui/Cargo.toml
@@ -8,5 +8,6 @@ edition = "2018"
[dependencies]
# palette = "0.4"
+rusttype = "0.7"
serde = "1"
serde_derive = "1"
diff --git a/emgui/fonts/DejaVuSansMono.ttf b/emgui/fonts/DejaVuSansMono.ttf
new file mode 100644
index 00000000..f5786022
Binary files /dev/null and b/emgui/fonts/DejaVuSansMono.ttf differ
diff --git a/emgui/fonts/ProggyClean.ttf b/emgui/fonts/ProggyClean.ttf
new file mode 100644
index 00000000..0270cdfe
Binary files /dev/null and b/emgui/fonts/ProggyClean.ttf differ
diff --git a/emgui/fonts/Roboto-Regular.ttf b/emgui/fonts/Roboto-Regular.ttf
new file mode 100644
index 00000000..2c97eead
Binary files /dev/null and b/emgui/fonts/Roboto-Regular.ttf differ
diff --git a/emgui/src/font.rs b/emgui/src/font.rs
new file mode 100644
index 00000000..cf7a49ab
--- /dev/null
+++ b/emgui/src/font.rs
@@ -0,0 +1,218 @@
+#![allow(unused)] // TODO
+
+use rusttype::{point, Scale};
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub struct GlyphInfo {
+ /// X offset for nice rendering
+ offset_x: u16,
+
+ /// Y offset for nice rendering
+ offset_y: u16,
+
+ min_x: u16,
+ min_y: u16,
+
+ /// Inclusive.
+ max_x: u16,
+
+ /// Inclusive
+ max_y: u16,
+}
+
+/// Printable ascii characters [33, 126], which excludes 32 (space) and 127 (DEL)
+const NUM_CHARS: usize = 94;
+const FIRST_ASCII: usize = 33;
+/// Inclusive
+const LAST_ASCII: usize = 126;
+
+#[derive(Clone)]
+pub struct Font {
+ /// Maximum character height
+ scale: usize,
+ /// NUM_CHARS big
+ char_rects: Vec,
+ atlas_width: usize,
+ atlas_height: usize,
+ atlas: Vec,
+}
+
+impl Font {
+ pub fn new(scale: usize) -> Font {
+ let font_data = include_bytes!("../fonts/ProggyClean.ttf");
+ let font = rusttype::Font::from_bytes(font_data as &[u8]).expect("Error constructing Font");
+
+ // println!(
+ // "font.v_metrics: {:?}",
+ // font.v_metrics(Scale::uniform(scale as f32))
+ // );
+
+ let glyphs: Vec<_> = Self::supported_characters()
+ .map(|c| {
+ let glyph = font.glyph(c);
+ assert_ne!(
+ glyph.id().0,
+ 0,
+ "Failed to find a glyph for the character '{}'",
+ c
+ );
+ let glyph = glyph.scaled(Scale::uniform(scale as f32));
+ glyph.positioned(point(0.0, 0.0))
+ })
+ .collect();
+
+ // TODO: decide dynamically?
+ let atlas_width = 128;
+
+ let mut atlas_height = 8;
+ let mut atlas = vec![0; atlas_width * atlas_height];
+
+ // Make one white pixel for use for various stuff:
+ atlas[0] = 255;
+
+ let mut cursor_x = 1;
+ let mut cursor_y = 0;
+ let mut row_height = 1;
+
+ let mut char_rects = vec![];
+
+ for glyph in glyphs {
+ let bb = glyph
+ .pixel_bounding_box()
+ .expect("Failed to get pixel bounding box");
+ let glyph_width = bb.width() as usize;
+ let glyph_height = bb.height() as usize;
+ assert!(glyph_width >= 1);
+ assert!(glyph_height >= 1);
+ assert!(glyph_width <= atlas_width);
+ if cursor_x + glyph_width > atlas_width {
+ // New row:
+ cursor_x = 0;
+ cursor_y += row_height;
+ row_height = 0;
+ }
+
+ row_height = row_height.max(glyph_height);
+ while cursor_y + row_height >= atlas_height {
+ atlas_height *= 2;
+ }
+ if atlas_width * atlas_height > atlas.len() {
+ atlas.resize(atlas_width * atlas_height, 0);
+ }
+
+ glyph.draw(|x, y, v| {
+ if v > 0.0 {
+ let x = x as usize;
+ let y = y as usize;
+ let px = cursor_x + x as usize;
+ let py = cursor_y + y as usize;
+ atlas[py * atlas_width + px] = (v * 255.0).round() as u8;
+ }
+ });
+
+ let offset_y = scale as i32 + bb.min.y - 3; // TODO: use font.v_metrics
+ assert!(0 <= bb.min.x);
+ assert!(0 <= offset_y && offset_y < scale as i32);
+ char_rects.push(GlyphInfo {
+ offset_x: bb.min.x as u16,
+ offset_y: offset_y as u16,
+ min_x: cursor_x as u16,
+ min_y: cursor_y as u16,
+ max_x: (cursor_x + glyph_width - 1) as u16,
+ max_y: (cursor_y + glyph_height - 1) as u16,
+ });
+
+ cursor_x += glyph_width;
+ }
+
+ Font {
+ scale,
+ char_rects,
+ atlas_width,
+ atlas_height,
+ atlas,
+ }
+ }
+
+ pub fn supported_characters() -> impl Iterator- {
+ (FIRST_ASCII..=LAST_ASCII).map(|c| c as u8 as char)
+ }
+
+ pub fn texture(&self) -> (usize, usize, &[u8]) {
+ (self.atlas_width, self.atlas_height, &self.atlas)
+ }
+
+ pub fn pixel(&self, x: u16, y: u16) -> u8 {
+ let x = x as usize;
+ let y = y as usize;
+ assert!(x < self.atlas_width);
+ assert!(y < self.atlas_height);
+ self.atlas[y * self.atlas_width + x]
+ }
+
+ pub fn glyph_info(&self, c: char) -> Option {
+ let c = c as usize;
+ if FIRST_ASCII <= c && c <= LAST_ASCII {
+ Some(self.char_rects[c - FIRST_ASCII])
+ } else {
+ None
+ }
+ }
+
+ pub fn debug_print_atlas_ascii_art(&self) {
+ for y in 0..self.atlas_height {
+ println!(
+ "{}",
+ as_ascii(&self.atlas[y * self.atlas_width..(y + 1) * self.atlas_width])
+ );
+ }
+ }
+
+ pub fn debug_print_all_chars(&self) {
+ let max_width = 160;
+ let mut pixel_rows = vec![vec![0; max_width]; self.scale];
+ let mut cursor_x = 0;
+ let mut cursor_y = 0;
+ for c in Self::supported_characters() {
+ if let Some(glyph_info) = self.glyph_info(c) {
+ for x in glyph_info.min_x..=glyph_info.max_x {
+ for y in glyph_info.min_y..=glyph_info.max_y {
+ let pixel = self.pixel(x, y);
+ let rx = glyph_info.offset_x + x - glyph_info.min_x;
+ let ry = glyph_info.offset_y + y - glyph_info.min_y;
+ pixel_rows[cursor_y + ry as usize][cursor_x + rx as usize] = pixel;
+ }
+ }
+ cursor_x += 7; // TODO
+ if cursor_x + 7 >= max_width {
+ println!("{}", (0..max_width).map(|_| "X").collect::());
+ for row in pixel_rows {
+ println!("{}", as_ascii(&row));
+ }
+ pixel_rows = vec![vec![0; max_width]; self.scale];
+ cursor_x = 0;
+ }
+ }
+ }
+ println!("{}", (0..max_width).map(|_| "X").collect::());
+ }
+}
+
+fn as_ascii(pixels: &[u8]) -> String {
+ pixels
+ .iter()
+ .map(|pixel| if *pixel == 0 { ' ' } else { 'X' })
+ .collect()
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ #[test]
+ fn font_test() {
+ let font = Font::new(13);
+ font.debug_print_atlas_ascii_art();
+ font.debug_print_all_chars();
+ panic!();
+ }
+}
diff --git a/emgui/src/lib.rs b/emgui/src/lib.rs
index a8996947..349353b6 100644
--- a/emgui/src/lib.rs
+++ b/emgui/src/lib.rs
@@ -1,16 +1,24 @@
#![deny(warnings)]
+extern crate rusttype;
extern crate serde;
#[macro_use] // TODO: get rid of this
extern crate serde_derive;
mod emgui;
+mod font;
mod layout;
pub mod math;
+mod painter;
mod style;
pub mod types;
pub use crate::{
- emgui::Emgui, layout::Layout, layout::LayoutOptions, style::Style, types::RawInput,
+ emgui::Emgui,
+ layout::Layout,
+ layout::LayoutOptions,
+ painter::{Frame, Painter, Vertex},
+ style::Style,
+ types::RawInput,
};
diff --git a/emgui/src/painter.rs b/emgui/src/painter.rs
new file mode 100644
index 00000000..76df9aae
--- /dev/null
+++ b/emgui/src/painter.rs
@@ -0,0 +1,88 @@
+/// Outputs render info in a format suitable for e.g. OpenGL.
+use crate::{
+ font::Font,
+ types::{Color, PaintCmd},
+};
+
+#[derive(Clone, Copy, Debug, Default)]
+pub struct Vertex {
+ /// Pixel coordinated
+ pub x: f32,
+ /// Pixel coordinated
+ pub y: f32,
+ /// Texel indices into the texture
+ pub u: u16,
+ /// Texel indices into the texture
+ pub v: u16,
+ /// sRGBA
+ pub color: Color,
+}
+
+#[derive(Clone, Debug, Default)]
+pub struct Frame {
+ pub clear_color: Option,
+ /// One big triangle strip
+ pub indices: Vec,
+ pub vertices: Vec,
+}
+
+#[derive(Clone)]
+pub struct Painter {
+ font: Font,
+}
+
+impl Painter {
+ pub fn new() -> Painter {
+ Painter {
+ font: Font::new(13),
+ }
+ }
+
+ /// 8-bit row-major font atlas texture, (width, height, pixels).
+ pub fn texture(&self) -> (usize, usize, &[u8]) {
+ self.font.texture()
+ }
+
+ pub fn paint(&self, commands: &[PaintCmd]) -> Frame {
+ let mut frame = Frame::default();
+ for cmd in commands {
+ match cmd {
+ PaintCmd::Circle { .. } => {} // TODO
+ PaintCmd::Clear { fill_color } => {
+ frame.clear_color = Some(*fill_color);
+ }
+ PaintCmd::Line { .. } => {} // TODO
+ PaintCmd::Rect {
+ pos,
+ size,
+ fill_color,
+ ..
+ } => {
+ // TODO: rounded corners, colors etc.
+ let idx = frame.vertices.len() as u32;
+ frame.indices.push(idx + 0);
+ frame.indices.push(idx + 0);
+ frame.indices.push(idx + 1);
+ frame.indices.push(idx + 2);
+ frame.indices.push(idx + 3);
+ frame.indices.push(idx + 3);
+
+ let vert = |x, y| Vertex {
+ x,
+ y,
+ u: 0,
+ v: 0,
+ color: fill_color.unwrap_or(Color::WHITE),
+ };
+
+ frame.vertices.push(vert(pos.x, pos.y));
+ frame.vertices.push(vert(pos.x + size.x, pos.y));
+ frame.vertices.push(vert(pos.x, pos.y + size.y));
+ frame.vertices.push(vert(pos.x + size.x, pos.y + size.y));
+ }
+ PaintCmd::Text { .. } => {} // TODO
+ }
+ }
+ frame
+ }
+}
diff --git a/emgui/src/types.rs b/emgui/src/types.rs
index 9ea8a417..276b4588 100644
--- a/emgui/src/types.rs
+++ b/emgui/src/types.rs
@@ -57,7 +57,11 @@ pub struct Color {
pub a: u8,
}
-pub fn srgba(r: u8, g: u8, b: u8, a: u8) -> Color {
+impl Color {
+ pub const WHITE: Color = srgba(255, 255, 255, 255);
+}
+
+pub const fn srgba(r: u8, g: u8, b: u8, a: u8) -> Color {
Color { r, g, b, a }
}
diff --git a/emgui_wasm/Cargo.toml b/emgui_wasm/Cargo.toml
index 5aeed7d5..6425783d 100644
--- a/emgui_wasm/Cargo.toml
+++ b/emgui_wasm/Cargo.toml
@@ -8,10 +8,24 @@ edition = "2018"
crate-type = ["cdylib", "rlib"]
[dependencies]
+js-sys = "0.3"
lazy_static = "1"
serde = "1"
serde_json = "1"
wasm-bindgen = "0.2"
-# web-sys = { version = "0.3.5", features = ['console', 'Performance', 'Window'] }
emgui = { path = "../emgui" }
+
+[dependencies.web-sys]
+version = "0.3"
+features = [
+ 'Document',
+ 'Element',
+ 'HtmlCanvasElement',
+ 'WebGlBuffer',
+ 'WebGlProgram',
+ 'WebGlRenderingContext',
+ 'WebGlShader',
+ 'WebGlUniformLocation',
+ 'Window',
+]
diff --git a/emgui_wasm/src/lib.rs b/emgui_wasm/src/lib.rs
index cfddc6f1..0e9a544b 100644
--- a/emgui_wasm/src/lib.rs
+++ b/emgui_wasm/src/lib.rs
@@ -9,11 +9,12 @@ extern crate emgui;
use std::sync::Mutex;
-use emgui::{Emgui, RawInput};
+use emgui::{Emgui, Frame, RawInput};
use wasm_bindgen::prelude::*;
-pub mod app;
+mod app;
+mod webgl;
#[wasm_bindgen]
pub fn show_gui(raw_input_json: &str) -> String {
@@ -40,3 +41,57 @@ pub fn show_gui(raw_input_json: &str) -> String {
let commands = emgui.paint();
serde_json::to_string(&commands).unwrap()
}
+
+#[wasm_bindgen]
+pub fn new_webgl_painter(canvas_id: &str) -> Result {
+ webgl::Painter::new(canvas_id)
+}
+
+struct State {
+ app: app::App,
+ emgui: Emgui,
+ emgui_painter: emgui::Painter,
+}
+
+impl State {
+ fn new() -> State {
+ State {
+ app: Default::default(),
+ emgui: Default::default(),
+ emgui_painter: emgui::Painter::new(),
+ }
+ }
+
+ fn frame(&mut self, raw_input: RawInput) -> Frame {
+ self.emgui.new_frame(raw_input);
+
+ use crate::app::GuiSettings;
+ self.app.show_gui(&mut self.emgui.layout);
+
+ let mut style = self.emgui.style.clone();
+ self.emgui.layout.foldable("Style", |gui| {
+ style.show_gui(gui);
+ });
+ self.emgui.style = style;
+
+ let commands = self.emgui.paint();
+ self.emgui_painter.paint(&commands)
+ }
+}
+
+#[wasm_bindgen]
+pub fn paint_webgl(webgl_painter: &webgl::Painter, raw_input_json: &str) -> Result<(), JsValue> {
+ // TODO: nicer interface than JSON
+ let raw_input: RawInput = serde_json::from_str(raw_input_json).unwrap();
+
+ lazy_static::lazy_static! {
+ static ref STATE: Mutex