WIP: rust WebGL rendering
This commit is contained in:
parent
bfa20be28e
commit
a1ddef742d
22 changed files with 1346 additions and 202 deletions
|
@ -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/
|
||||
|
|
2
build.sh
2
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
|
||||
|
|
3
docs/emgui.d.ts
vendored
3
docs/emgui.d.ts
vendored
|
@ -1,3 +0,0 @@
|
|||
/* tslint:disable */
|
||||
export function show_gui(arg0: string): string;
|
||||
|
102
docs/emgui.js
102
docs/emgui.js
|
@ -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);
|
||||
})();
|
Binary file not shown.
561
docs/emgui_wasm.js
Normal file
561
docs/emgui_wasm.js
Normal file
|
@ -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);
|
||||
})();
|
BIN
docs/emgui_wasm_bg.wasm
Normal file
BIN
docs/emgui_wasm_bg.wasm
Normal file
Binary file not shown.
|
@ -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);
|
||||
|
|
137
docs/frontend.ts
137
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);
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
</script>
|
||||
|
||||
<!-- this is the JS generated by the `wasm-bindgen` CLI tool -->
|
||||
<script src="emgui.js"></script>
|
||||
<script src="emgui_wasm.js"></script>
|
||||
|
||||
<script src="frontend.js" type="module"></script>
|
||||
|
||||
|
|
|
@ -8,5 +8,6 @@ edition = "2018"
|
|||
|
||||
[dependencies]
|
||||
# palette = "0.4"
|
||||
rusttype = "0.7"
|
||||
serde = "1"
|
||||
serde_derive = "1"
|
||||
|
|
BIN
emgui/fonts/DejaVuSansMono.ttf
Normal file
BIN
emgui/fonts/DejaVuSansMono.ttf
Normal file
Binary file not shown.
BIN
emgui/fonts/ProggyClean.ttf
Normal file
BIN
emgui/fonts/ProggyClean.ttf
Normal file
Binary file not shown.
BIN
emgui/fonts/Roboto-Regular.ttf
Normal file
BIN
emgui/fonts/Roboto-Regular.ttf
Normal file
Binary file not shown.
218
emgui/src/font.rs
Normal file
218
emgui/src/font.rs
Normal file
|
@ -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<GlyphInfo>,
|
||||
atlas_width: usize,
|
||||
atlas_height: usize,
|
||||
atlas: Vec<u8>,
|
||||
}
|
||||
|
||||
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<Item = char> {
|
||||
(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<GlyphInfo> {
|
||||
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::<String>());
|
||||
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::<String>());
|
||||
}
|
||||
}
|
||||
|
||||
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!();
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
};
|
||||
|
|
88
emgui/src/painter.rs
Normal file
88
emgui/src/painter.rs
Normal file
|
@ -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<Color>,
|
||||
/// One big triangle strip
|
||||
pub indices: Vec<u32>,
|
||||
pub vertices: Vec<Vertex>,
|
||||
}
|
||||
|
||||
#[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
|
||||
}
|
||||
}
|
|
@ -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 }
|
||||
}
|
||||
|
||||
|
|
|
@ -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',
|
||||
]
|
||||
|
|
|
@ -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, JsValue> {
|
||||
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<Option<State>> = Default::default();
|
||||
}
|
||||
|
||||
let mut state = STATE.lock().unwrap();
|
||||
if state.is_none() {
|
||||
*state = Some(State::new());
|
||||
}
|
||||
let frame = state.as_mut().unwrap().frame(raw_input);
|
||||
webgl_painter.paint(&frame)
|
||||
}
|
||||
|
|
267
emgui_wasm/src/webgl.rs
Normal file
267
emgui_wasm/src/webgl.rs
Normal file
|
@ -0,0 +1,267 @@
|
|||
use {
|
||||
js_sys::WebAssembly,
|
||||
wasm_bindgen::{prelude::*, JsCast},
|
||||
web_sys::{WebGlBuffer, WebGlProgram, WebGlRenderingContext, WebGlShader},
|
||||
};
|
||||
|
||||
use emgui::Frame;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct Painter {
|
||||
canvas: web_sys::HtmlCanvasElement,
|
||||
gl: WebGlRenderingContext,
|
||||
program: WebGlProgram,
|
||||
index_buffer: WebGlBuffer,
|
||||
pos_buffer: WebGlBuffer,
|
||||
color_buffer: WebGlBuffer,
|
||||
}
|
||||
|
||||
impl Painter {
|
||||
pub fn new(canvas_id: &str) -> Result<Painter, JsValue> {
|
||||
let document = web_sys::window().unwrap().document().unwrap();
|
||||
let canvas = document.get_element_by_id(canvas_id).unwrap();
|
||||
let canvas: web_sys::HtmlCanvasElement = canvas.dyn_into::<web_sys::HtmlCanvasElement>()?;
|
||||
|
||||
let gl = canvas
|
||||
.get_context("webgl")?
|
||||
.unwrap()
|
||||
.dyn_into::<WebGlRenderingContext>()?;
|
||||
|
||||
gl.enable(WebGlRenderingContext::BLEND);
|
||||
gl.blend_func(
|
||||
WebGlRenderingContext::SRC_ALPHA,
|
||||
WebGlRenderingContext::ONE_MINUS_SRC_ALPHA,
|
||||
);
|
||||
|
||||
let vert_shader = compile_shader(
|
||||
&gl,
|
||||
WebGlRenderingContext::VERTEX_SHADER,
|
||||
r#"
|
||||
uniform vec2 u_screen_size;
|
||||
attribute vec2 a_pos;
|
||||
attribute vec4 a_color;
|
||||
varying vec4 v_color;
|
||||
void main() {
|
||||
gl_Position = vec4(
|
||||
2.0 * a_pos.x / u_screen_size.x - 1.0,
|
||||
1.0 - 2.0 * a_pos.y / u_screen_size.y,
|
||||
0.0,
|
||||
1.0);
|
||||
// v_color = vec4(1.0, 0.0, 0.0, 0.5);
|
||||
v_color = a_color;
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let frag_shader = compile_shader(
|
||||
&gl,
|
||||
WebGlRenderingContext::FRAGMENT_SHADER,
|
||||
r#"
|
||||
precision highp float;
|
||||
varying vec4 v_color;
|
||||
void main() {
|
||||
gl_FragColor = v_color;
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let program = link_program(&gl, [vert_shader, frag_shader].iter())?;
|
||||
let index_buffer = gl.create_buffer().ok_or("failed to create index_buffer")?;
|
||||
let pos_buffer = gl.create_buffer().ok_or("failed to create pos_buffer")?;
|
||||
let color_buffer = gl.create_buffer().ok_or("failed to create color_buffer")?;
|
||||
|
||||
Ok(Painter {
|
||||
canvas,
|
||||
gl,
|
||||
program,
|
||||
index_buffer,
|
||||
pos_buffer,
|
||||
color_buffer,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn paint(&self, frame: &Frame) -> Result<(), JsValue> {
|
||||
let gl = &self.gl;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
gl.use_program(Some(&self.program));
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
let indices: Vec<u16> = frame.indices.iter().map(|idx| *idx as u16).collect();
|
||||
|
||||
let mut positions = Vec::with_capacity(2 * frame.vertices.len());
|
||||
for v in &frame.vertices {
|
||||
positions.push(v.x);
|
||||
positions.push(v.y);
|
||||
}
|
||||
|
||||
let mut colors = Vec::with_capacity(4 * frame.vertices.len());
|
||||
for v in &frame.vertices {
|
||||
colors.push(v.color.r);
|
||||
colors.push(v.color.g);
|
||||
colors.push(v.color.b);
|
||||
colors.push(v.color.a);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
let indices_memory_buffer = wasm_bindgen::memory()
|
||||
.dyn_into::<WebAssembly::Memory>()?
|
||||
.buffer();
|
||||
let indices_ptr = indices.as_ptr() as u32 / 2;
|
||||
let indices_array = js_sys::Int16Array::new(&indices_memory_buffer)
|
||||
.subarray(indices_ptr, indices_ptr + indices.len() as u32);
|
||||
|
||||
gl.bind_buffer(
|
||||
WebGlRenderingContext::ELEMENT_ARRAY_BUFFER,
|
||||
Some(&self.index_buffer),
|
||||
);
|
||||
gl.buffer_data_with_array_buffer_view(
|
||||
WebGlRenderingContext::ELEMENT_ARRAY_BUFFER,
|
||||
&indices_array,
|
||||
WebGlRenderingContext::STATIC_DRAW, // TODO: STREAM ?
|
||||
);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
let pos_memory_buffer = wasm_bindgen::memory()
|
||||
.dyn_into::<WebAssembly::Memory>()?
|
||||
.buffer();
|
||||
let pos_ptr = positions.as_ptr() as u32 / 4;
|
||||
let pos_array = js_sys::Float32Array::new(&pos_memory_buffer)
|
||||
.subarray(pos_ptr, pos_ptr + positions.len() as u32);
|
||||
|
||||
gl.bind_buffer(WebGlRenderingContext::ARRAY_BUFFER, Some(&self.pos_buffer));
|
||||
gl.buffer_data_with_array_buffer_view(
|
||||
WebGlRenderingContext::ARRAY_BUFFER,
|
||||
&pos_array,
|
||||
WebGlRenderingContext::STATIC_DRAW, // TODO: STREAM ?
|
||||
);
|
||||
|
||||
let a_pos_loc = gl.get_attrib_location(&self.program, "a_pos");
|
||||
assert!(a_pos_loc >= 0);
|
||||
let a_pos_loc = a_pos_loc as u32;
|
||||
|
||||
let normalize = false;
|
||||
let stride = 0;
|
||||
let offset = 0;
|
||||
gl.vertex_attrib_pointer_with_i32(
|
||||
a_pos_loc,
|
||||
2,
|
||||
WebGlRenderingContext::FLOAT,
|
||||
normalize,
|
||||
stride,
|
||||
offset,
|
||||
);
|
||||
gl.enable_vertex_attrib_array(a_pos_loc);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
let colors_memory_buffer = wasm_bindgen::memory()
|
||||
.dyn_into::<WebAssembly::Memory>()?
|
||||
.buffer();
|
||||
let colors_ptr = colors.as_ptr() as u32;
|
||||
let colors_array = js_sys::Uint8Array::new(&colors_memory_buffer)
|
||||
.subarray(colors_ptr, colors_ptr + colors.len() as u32);
|
||||
|
||||
gl.bind_buffer(
|
||||
WebGlRenderingContext::ARRAY_BUFFER,
|
||||
Some(&self.color_buffer),
|
||||
);
|
||||
gl.buffer_data_with_array_buffer_view(
|
||||
WebGlRenderingContext::ARRAY_BUFFER,
|
||||
&colors_array,
|
||||
WebGlRenderingContext::STATIC_DRAW, // TODO: STREAM ?
|
||||
);
|
||||
|
||||
let a_color_loc = gl.get_attrib_location(&self.program, "a_color");
|
||||
assert!(a_color_loc >= 0);
|
||||
let a_color_loc = a_color_loc as u32;
|
||||
|
||||
let normalize = true;
|
||||
let stride = 0;
|
||||
let offset = 0;
|
||||
gl.vertex_attrib_pointer_with_i32(
|
||||
a_color_loc,
|
||||
4,
|
||||
WebGlRenderingContext::UNSIGNED_BYTE,
|
||||
normalize,
|
||||
stride,
|
||||
offset,
|
||||
);
|
||||
gl.enable_vertex_attrib_array(a_color_loc);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
let u_screen_size_loc = gl
|
||||
.get_uniform_location(&self.program, "u_screen_size")
|
||||
.unwrap();
|
||||
gl.uniform2f(
|
||||
Some(&u_screen_size_loc),
|
||||
self.canvas.width() as f32,
|
||||
self.canvas.height() as f32,
|
||||
);
|
||||
// gl.uniform2f(Some(&u_screen_size_loc), 4.0, 1.0);
|
||||
|
||||
gl.clear_color(0.05, 0.05, 0.05, 1.0);
|
||||
gl.clear(WebGlRenderingContext::COLOR_BUFFER_BIT);
|
||||
|
||||
gl.draw_elements_with_i32(
|
||||
WebGlRenderingContext::TRIANGLE_STRIP,
|
||||
indices.len() as i32,
|
||||
WebGlRenderingContext::UNSIGNED_SHORT,
|
||||
0,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_shader(
|
||||
gl: &WebGlRenderingContext,
|
||||
shader_type: u32,
|
||||
source: &str,
|
||||
) -> Result<WebGlShader, String> {
|
||||
let shader = gl
|
||||
.create_shader(shader_type)
|
||||
.ok_or_else(|| String::from("Unable to create shader object"))?;
|
||||
gl.shader_source(&shader, source);
|
||||
gl.compile_shader(&shader);
|
||||
|
||||
if gl
|
||||
.get_shader_parameter(&shader, WebGlRenderingContext::COMPILE_STATUS)
|
||||
.as_bool()
|
||||
.unwrap_or(false)
|
||||
{
|
||||
Ok(shader)
|
||||
} else {
|
||||
Err(gl
|
||||
.get_shader_info_log(&shader)
|
||||
.unwrap_or_else(|| "Unknown error creating shader".into()))
|
||||
}
|
||||
}
|
||||
|
||||
fn link_program<'a, T: IntoIterator<Item = &'a WebGlShader>>(
|
||||
gl: &WebGlRenderingContext,
|
||||
shaders: T,
|
||||
) -> Result<WebGlProgram, String> {
|
||||
let program = gl
|
||||
.create_program()
|
||||
.ok_or_else(|| String::from("Unable to create shader object"))?;
|
||||
for shader in shaders {
|
||||
gl.attach_shader(&program, shader)
|
||||
}
|
||||
gl.link_program(&program);
|
||||
|
||||
if gl
|
||||
.get_program_parameter(&program, WebGlRenderingContext::LINK_STATUS)
|
||||
.as_bool()
|
||||
.unwrap_or(false)
|
||||
{
|
||||
Ok(program)
|
||||
} else {
|
||||
Err(gl
|
||||
.get_program_info_log(&program)
|
||||
.unwrap_or_else(|| "Unknown error creating program object".into()))
|
||||
}
|
||||
}
|
|
@ -1,10 +1,9 @@
|
|||
{
|
||||
"defaultSeverity": "error",
|
||||
"extends": [
|
||||
"tslint:recommended"
|
||||
],
|
||||
"extends": ["tslint:recommended"],
|
||||
"jsRules": {},
|
||||
"rules": {
|
||||
"arrow-parens": [true, "ban-single-arg-parens"],
|
||||
"interface-name": [true, "never-prefix"],
|
||||
"max-classes-per-file": [false],
|
||||
"no-bitwise": false,
|
||||
|
|
Loading…
Reference in a new issue