From 18c5bc6a56f677d292e4d2f0a1b8ec457eea8ca3 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Thu, 16 May 2024 08:21:13 -0500 Subject: [PATCH] Add mum rendering camera --- scripts/base.js | 2 +- scripts/engine.js | 4 +- scripts/gui.js | 18 ++- scripts/render.js | 309 ++++++++++++++++++++++-------------------- source/engine/jsffi.c | 11 +- 5 files changed, 191 insertions(+), 153 deletions(-) diff --git a/scripts/base.js b/scripts/base.js index 43a2ac6..552e26d 100644 --- a/scripts/base.js +++ b/scripts/base.js @@ -1605,7 +1605,7 @@ yaml.tojson = function(yaml) yaml = yaml.replace(/\s/g, ''); yaml = yaml.replace(/,}/g, '}'); yaml = yaml.replace(/,]/g, ']'); - yaml = yaml.replace(/,"[^"]+"\:,/, ','); + yaml = yaml.replace(/,"[^"]+"\:,/g, ','); return yaml; } diff --git a/scripts/engine.js b/scripts/engine.js index 80450eb..e447c79 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -129,7 +129,7 @@ qq = 'ms'; profile.report = function(start, msg = "[undefined report]") { - say(`${msg} in ${profile.best_t(profile.now()-start)}`); + console.info(`${msg} in ${profile.best_t(profile.now()-start)}`); } profile.addreport = function(cache, line, start) @@ -297,6 +297,8 @@ game.engine_start = function(s) { Object.readonly(window.__proto__, 'sample_count'); s(); + render.polyshader = render.make_shader("poly.sglsl"); + shape.quad = { pos:os.make_buffer([ 0,0,0, diff --git a/scripts/gui.js b/scripts/gui.js index 0c2c3ef..7ebe104 100644 --- a/scripts/gui.js +++ b/scripts/gui.js @@ -164,6 +164,16 @@ Mum.button = Mum.text._int.extend({ action() { console.warn("Button has no action."); }, }); +var mumcam = {}; +mumcam.transform = os.make_transform(); +mumcam.ortho = true; +mumcam.near = 0; +mumcam.far = 1000; +mumcam.transform.pos = [100,100,-100]; +mumcam.app = true; + +var textssbo = render.text_ssbo(); + Mum.window = Mum.extend({ start() { this.wh = [this.width, this.height]; @@ -173,7 +183,6 @@ Mum.window = Mum.extend({ var p = cursor.sub(this.wh.scale(this.anchor)).add(this.padding); render.window(p,this.wh, this.color); this.bb = bbox.blwh(p, this.wh); - gui.flush(); this.max_width = this.width; if (this.selectable) gui.controls.check_bb(this); var pos = [this.bb.l, this.bb.t].add(this.padding); @@ -181,7 +190,12 @@ Mum.window = Mum.extend({ if (item.hide) return; item.draw(pos.slice(),this); }, this); - gui.flush(); + render.set_camera(mumcam); + render.setpipeline(render.textshader.pipe); + render.shader_apply_material(render.textshader); + var bind = render.sg_bind(render.textshader, shape.quad, {text:render.font.texture}, textssbo); + bind.inst = render.flushtext(); + render.spdraw(bind); gui.scissor_win(); }, }); diff --git a/scripts/render.js b/scripts/render.js index 49e8b8d..52b9500 100644 --- a/scripts/render.js +++ b/scripts/render.js @@ -4,145 +4,6 @@ render.doc = { wireframe: "Show only wireframes of models." }; -render.device = { - pc: [1920,1080], - macbook_m2: [2560,1664, 13.6], - ds_top: [400,240, 3.53], - ds_bottom: [320,240, 3.02], - playdate: [400,240,2.7], - switch: [1280,720, 6.2], - switch_lite: [1280,720,5.5], - switch_oled: [1280,720,7], - dsi: [256,192,3.268], - ds: [256,192, 3], - dsixl: [256,192,4.2], - ipad_air_m2: [2360,1640, 11.97], - iphone_se: [1334, 750, 4.7], - iphone_12_pro: [2532,1170,6.06], - iphone_15: [2556,1179,6.1], - gba: [240,160,2.9], - gameboy: [160,144,2.48], - gbc: [160,144,2.28], - steamdeck: [1280,800,7], - vita: [960,544,5], - psp: [480,272,4.3], - imac_m3: [4480,2520,23.5], - macbook_pro_m3: [3024,1964, 14.2], - ps1: [320,240,5], - ps2: [640,480], - snes: [256,224], - gamecube: [640,480], - n64: [320,240], - c64: [320,200], - macintosh: [512,342,9], - gamegear: [160,144,3.2], -}; - -render.device.doc = `Device resolutions given as [x,y,inches diagonal].`; - -/* All draw in screen space */ -render.point = function(pos,size,color = Color.blue) { - render.circle(pos,size,size,color); -}; - -var tmpline = render.line; -render.line = function(points, color = Color.white, thickness = 1) { - tmpline(points,color,thickness); -}; - -render.cross = function(pos, size, color = Color.red) { - var a = [ - pos.add([0,size]), - pos.add([0,-size]) - ]; - var b = [ - pos.add([size,0]), - pos.add([-size,0]) - ]; - - render.line(a,color); - render.line(b,color); - }; - -render.arrow = function(start, end, color = Color.red, wingspan = 4, wingangle = 10) { - var dir = end.sub(start).normalized(); - var wing1 = [ - Vector.rotate(dir, wingangle).scale(wingspan).add(end), - end - ]; - var wing2 = [ - Vector.rotate(dir,-wingangle).scale(wingspan).add(end), - end - ]; - render.line([start,end],color); - render.line(wing1,color); - render.line(wing2,color); -}; - -render.coordinate = function(pos, size, color) { - render.text(JSON.stringify(pos.map(p=>Math.round(p))), pos, size, color); - render.point(pos, 2, color); -} - -render.boundingbox = function(bb, color = Color.white) { - render.poly(bbox.topoints(bb), color); -} - -render.rectangle = function(lowerleft, upperright, color) { - var points = [lowerleft, lowerleft.add([upperright.x-lowerleft.x,0]), upperright, lowerleft.add([0,upperright.y-lowerleft.y])]; - render.poly(points, color); -}; - -render.box = function(pos, wh, color = Color.white) { - var lower = pos.sub(wh.scale(0.5)); - var upper = pos.add(wh.scale(0.5)); - render.rectangle(lower,upper,color); -}; - -render.window = function(pos, wh, color) { - var p = pos.slice(); - p = p.add(wh.scale(0.5)); - render.box(p,wh,color); -}; - -render.text = function(str, pos, size = 1, color = Color.white, wrap = -1, anchor = [0,1], cursor = -1) { - var bb = render.text_size(str, size, wrap); - var w = bb.r*2; - var h = bb.t*2; - - //render.text draws with an anchor on top left corner - var p = pos.slice(); - p.x -= w * anchor.x; - bb.r += (w*anchor.x); - bb.l += (w*anchor.x); - p.y += h * (1 - anchor.y); - bb.t += h*(1-anchor.y); - bb.b += h*(1-anchor.y); - gui.text(str, p, size, color, wrap, cursor); - - return bb; -}; - -render.image = function(tex, pos, rotation = 0, color = Color.white, dimensions = [tex.width, tex.height]) { - //var scale = [dimensions.x/tex.width, dimensions.y/tex.height]; - //gui.img(tex,pos, scale, 0.0, false, [0.0,0.0], color); - //return bbox.fromcwh([0,0], [tex.width,tex.height]); -} - -render.fontcache = {}; -render.set_font = function(path, size) { - var fontstr = `${path}-${size}`; - if (!render.fontcache[fontstr]) render.fontcache[fontstr] = os.make_font(path, size); - - gui.font_set(render.fontcache[fontstr]); - render.font = render.fontcache[fontstr]; -} - -render.doc = "Draw shapes in screen space."; -//render.circle.doc = "Draw a circle at pos, with a given radius and color."; -render.cross.doc = "Draw a cross centered at pos, with arm length size."; -render.arrow.doc = "Draw an arrow from start to end, with wings of length wingspan at angle wingangle."; -render.rectangle.doc = "Draw a rectangle, with its corners at lowerleft and upperright."; var shaderlang = { macos: "metal_macos", @@ -152,8 +13,6 @@ var shaderlang = { ios: "metal_ios", } -say(`shaderlang is ${shaderlang[os.sys()]}`); - var attr_map = { a_pos: 0, a_uv: 1, @@ -224,12 +83,13 @@ function shader_directive(shader, name, map) { var reg = new RegExp(`#${name}.*`, 'g'); var mat = shader.match(reg); - if (!mat) return 0; + if (!mat) return undefined; reg = new RegExp(`#${name}\s*`, 'g'); var ff = mat.map(d=>d.replace(reg,''))[0].trim(); - return map[ff]; + if (map) return map[ff]; + return ff; } function global_uni(uni, stage) @@ -291,6 +151,10 @@ render.make_shader = function(shader) var cull = shader_directive(shader, 'cull', cull_map); var depth = shader_directive(shader, 'depth', depth_map); var face = shader_directive(shader, 'face', face_map); + var indexed = shader_directive(shader, 'indexed'); + + if (typeof indexed == 'undefined') indexed = true; + if (indexed === 'false') indexed = false; shader = shader.replace(/uniform\s+(\w+)\s+(\w+);/g, "uniform _$2 { $1 $2; };"); shader = shader.replace(/(texture2D|sampler) /g, "uniform $1 "); @@ -303,12 +167,14 @@ render.make_shader = function(shader) console.info(`error compiling shader`); return; } - io.rm(out); +// io.rm(out); /* Take YAML and create the shader object */ var yamlfile = `${out}_reflection.yaml`; console.info(`slurping ${yamlfile}`); - var obj = json.decode(yaml.tojson(io.slurp(yamlfile))); + var jjson = yaml.tojson(io.slurp(yamlfile)); + say(jjson); + var obj = json.decode(jjson); io.rm(yamlfile); obj = obj.shaders[0].programs[0]; @@ -332,6 +198,7 @@ render.make_shader = function(shader) obj.primitive = primitive; obj.depth = depth; obj.face = face; + obj.indexed = indexed; if (obj.vs.inputs) for (var i of obj.vs.inputs) { @@ -428,7 +295,7 @@ render.sg_bind = function(shader, mesh = {}, material = {}, ssbo) bind.images.push(game.texture("icons/no_tex.gif")); } - if (mesh.index) { + if (shader.indexed) { bind.index = mesh.index; bind.count = mesh.count; } else @@ -442,4 +309,154 @@ render.sg_bind = function(shader, mesh = {}, material = {}, ssbo) return bind; } +render.device = { + pc: [1920,1080], + macbook_m2: [2560,1664, 13.6], + ds_top: [400,240, 3.53], + ds_bottom: [320,240, 3.02], + playdate: [400,240,2.7], + switch: [1280,720, 6.2], + switch_lite: [1280,720,5.5], + switch_oled: [1280,720,7], + dsi: [256,192,3.268], + ds: [256,192, 3], + dsixl: [256,192,4.2], + ipad_air_m2: [2360,1640, 11.97], + iphone_se: [1334, 750, 4.7], + iphone_12_pro: [2532,1170,6.06], + iphone_15: [2556,1179,6.1], + gba: [240,160,2.9], + gameboy: [160,144,2.48], + gbc: [160,144,2.28], + steamdeck: [1280,800,7], + vita: [960,544,5], + psp: [480,272,4.3], + imac_m3: [4480,2520,23.5], + macbook_pro_m3: [3024,1964, 14.2], + ps1: [320,240,5], + ps2: [640,480], + snes: [256,224], + gamecube: [640,480], + n64: [320,240], + c64: [320,200], + macintosh: [512,342,9], + gamegear: [160,144,3.2], +}; + +render.device.doc = `Device resolutions given as [x,y,inches diagonal].`; + +/* All draw in screen space */ +render.point = function(pos,size,color = Color.blue) { + render.circle(pos,size,size,color); +}; + +var tmpline = render.line; +render.line = function(points, color = Color.white, thickness = 1) { + tmpline(points,color,thickness); +}; + +render.cross = function(pos, size, color = Color.red) { + var a = [ + pos.add([0,size]), + pos.add([0,-size]) + ]; + var b = [ + pos.add([size,0]), + pos.add([-size,0]) + ]; + + render.line(a,color); + render.line(b,color); + }; + +render.arrow = function(start, end, color = Color.red, wingspan = 4, wingangle = 10) { + var dir = end.sub(start).normalized(); + var wing1 = [ + Vector.rotate(dir, wingangle).scale(wingspan).add(end), + end + ]; + var wing2 = [ + Vector.rotate(dir,-wingangle).scale(wingspan).add(end), + end + ]; + render.line([start,end],color); + render.line(wing1,color); + render.line(wing2,color); +}; + +render.coordinate = function(pos, size, color) { + render.text(JSON.stringify(pos.map(p=>Math.round(p))), pos, size, color); + render.point(pos, 2, color); +} + +render.boundingbox = function(bb, color = Color.white) { + render.poly(bbox.topoints(bb), color); +} + +render.poly = function(points, color) +{ + return; + render.setpipeline(render.polyshader.pipe); + var poly = render.poly_prim(points); + render.shader_apply_material(render.polyshader, {shade:color}); + render.spdraw(render.sg_bind(render.polyshader, poly)); +} + +render.rectangle = function(lowerleft, upperright, color) { + var points = [lowerleft, lowerleft.add([upperright.x-lowerleft.x,0]), upperright, lowerleft.add([0,upperright.y-lowerleft.y])]; + render.poly(points, color); +}; + +render.box = function(pos, wh, color = Color.white) { + var lower = pos.sub(wh.scale(0.5)); + var upper = pos.add(wh.scale(0.5)); + render.rectangle(lower,upper,color); +}; + +render.window = function(pos, wh, color) { + var p = pos.slice(); + p = p.add(wh.scale(0.5)); + render.box(p,wh,color); +}; + +render.text = function(str, pos, size = 1, color = Color.white, wrap = -1, anchor = [0,1], cursor = -1) { + var bb = render.text_size(str, size, wrap); + var w = bb.r*2; + var h = bb.t*2; + + //render.text draws with an anchor on top left corner + var p = pos.slice(); + p.x -= w * anchor.x; + bb.r += (w*anchor.x); + bb.l += (w*anchor.x); + p.y += h * (1 - anchor.y); + bb.t += h*(1-anchor.y); + bb.b += h*(1-anchor.y); + gui.text(str, p, size, color, wrap, cursor); + + return bb; +}; + +render.image = function(tex, pos, rotation = 0, color = Color.white, dimensions = [tex.width, tex.height]) { + //var scale = [dimensions.x/tex.width, dimensions.y/tex.height]; + //gui.img(tex,pos, scale, 0.0, false, [0.0,0.0], color); + //return bbox.fromcwh([0,0], [tex.width,tex.height]); +} + +render.fontcache = {}; +render.set_font = function(path, size) { + var fontstr = `${path}-${size}`; + if (!render.fontcache[fontstr]) render.fontcache[fontstr] = os.make_font(path, size); + + gui.font_set(render.fontcache[fontstr]); + render.font = render.fontcache[fontstr]; +} + +render.doc = "Draw shapes in screen space."; +//render.circle.doc = "Draw a circle at pos, with a given radius and color."; +render.cross.doc = "Draw a cross centered at pos, with arm length size."; +render.arrow.doc = "Draw an arrow from start to end, with wings of length wingspan at angle wingangle."; +render.rectangle.doc = "Draw a rectangle, with its corners at lowerleft and upperright."; + + return {render}; diff --git a/source/engine/jsffi.c b/source/engine/jsffi.c index 15729e9..89c935e 100644 --- a/source/engine/jsffi.c +++ b/source/engine/jsffi.c @@ -73,6 +73,7 @@ char *js2strdup(JSValue v) { void sg_buffer_free(sg_buffer *b) { + printf("DESTROYED BUFFER AT %p\n", b); sg_destroy_buffer(*b); free(b); } @@ -715,6 +716,7 @@ JSC_SCALL(render_text_size, ret = bb2js(text_bb(str, js2number(argv[1]), js2numb JSC_CCALL(render_set_camera, JSValue cam = argv[0]; int ortho = js2boolean(js_getpropstr(cam, "ortho")); + int app = js2boolean(js_getpropstr(cam, "app")); float near = js2number(js_getpropstr(cam, "near")); float far = js2number(js_getpropstr(cam, "far")); float fov = js2number(js_getpropstr(cam, "fov"))*HMM_DegToRad; @@ -725,6 +727,9 @@ JSC_CCALL(render_set_camera, globalview.v = HMM_LookAt_LH(t->pos, look, vUP); HMM_Vec2 size = mainwin.mode == MODE_FULL ? mainwin.size : mainwin.rendersize; + if (ortho && app) + size = mainwin.size; + if (ortho) globalview.p = HMM_Orthographic_Metal( -size.x/2, @@ -760,6 +765,7 @@ sg_shader js2shader(JSValue v) int atin = js_arrlen(attrs); for (int i = 0; i < atin; i++) { JSValue u = js_getpropidx(attrs, i); + desc.attrs[i].name = js2strdup(js_getpropstr(u, "name")); desc.attrs[i].sem_name = js2strdup(js_getpropstr(u,"sem_name")); desc.attrs[i].sem_index = js2number(js_getpropstr(u, "sem_index")); } @@ -848,7 +854,8 @@ JSC_CCALL(render_pipeline, p.primitive_type = js2number(js_getpropstr(argv[0], "primitive")); //p.face_winding = js2number(js_getpropstr(argv[0], "face")); p.face_winding = 1; - p.index_type = SG_INDEXTYPE_UINT16; + if (js2boolean(js_getpropstr(argv[0], "indexed"))) + p.index_type = SG_INDEXTYPE_UINT16; if (js2boolean(js_getpropstr(argv[0], "blend"))) p.colors[0].blend = blend_trans; @@ -961,7 +968,6 @@ static const JSCFunctionListEntry js_render_funcs[] = { MIST_FUNC_DEF(render, commit, 0), }; -JSC_CCALL(gui_flush, text_flush()); JSC_CCALL(gui_scissor, sg_apply_scissor_rect(js2number(argv[0]), js2number(argv[1]), js2number(argv[2]), js2number(argv[3]), 0)) JSC_CCALL(gui_text, const char *s = JS_ToCString(js, argv[0]); @@ -979,7 +985,6 @@ JSC_CCALL(gui_text, JSC_CCALL(gui_font_set, font_set(js2font(argv[0]))) static const JSCFunctionListEntry js_gui_funcs[] = { - MIST_FUNC_DEF(gui, flush, 0), MIST_FUNC_DEF(gui, scissor, 4), MIST_FUNC_DEF(gui, text, 6), MIST_FUNC_DEF(gui, font_set,1)