Add mum rendering camera

This commit is contained in:
John Alanbrook 2024-05-16 08:21:13 -05:00
parent f4ee9d8228
commit 18c5bc6a56
5 changed files with 191 additions and 153 deletions

View file

@ -1605,7 +1605,7 @@ yaml.tojson = function(yaml)
yaml = yaml.replace(/\s/g, ''); yaml = yaml.replace(/\s/g, '');
yaml = yaml.replace(/,}/g, '}'); yaml = yaml.replace(/,}/g, '}');
yaml = yaml.replace(/,]/g, ']'); yaml = yaml.replace(/,]/g, ']');
yaml = yaml.replace(/,"[^"]+"\:,/, ','); yaml = yaml.replace(/,"[^"]+"\:,/g, ',');
return yaml; return yaml;
} }

View file

@ -129,7 +129,7 @@ qq = 'ms';
profile.report = function(start, msg = "[undefined report]") 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) profile.addreport = function(cache, line, start)
@ -297,6 +297,8 @@ game.engine_start = function(s) {
Object.readonly(window.__proto__, 'sample_count'); Object.readonly(window.__proto__, 'sample_count');
s(); s();
render.polyshader = render.make_shader("poly.sglsl");
shape.quad = { shape.quad = {
pos:os.make_buffer([ pos:os.make_buffer([
0,0,0, 0,0,0,

View file

@ -164,6 +164,16 @@ Mum.button = Mum.text._int.extend({
action() { console.warn("Button has no action."); }, 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({ Mum.window = Mum.extend({
start() { start() {
this.wh = [this.width, this.height]; 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); var p = cursor.sub(this.wh.scale(this.anchor)).add(this.padding);
render.window(p,this.wh, this.color); render.window(p,this.wh, this.color);
this.bb = bbox.blwh(p, this.wh); this.bb = bbox.blwh(p, this.wh);
gui.flush();
this.max_width = this.width; this.max_width = this.width;
if (this.selectable) gui.controls.check_bb(this); if (this.selectable) gui.controls.check_bb(this);
var pos = [this.bb.l, this.bb.t].add(this.padding); var pos = [this.bb.l, this.bb.t].add(this.padding);
@ -181,7 +190,12 @@ Mum.window = Mum.extend({
if (item.hide) return; if (item.hide) return;
item.draw(pos.slice(),this); item.draw(pos.slice(),this);
}, 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(); gui.scissor_win();
}, },
}); });

View file

@ -4,145 +4,6 @@ render.doc = {
wireframe: "Show only wireframes of models." 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 = { var shaderlang = {
macos: "metal_macos", macos: "metal_macos",
@ -152,8 +13,6 @@ var shaderlang = {
ios: "metal_ios", ios: "metal_ios",
} }
say(`shaderlang is ${shaderlang[os.sys()]}`);
var attr_map = { var attr_map = {
a_pos: 0, a_pos: 0,
a_uv: 1, a_uv: 1,
@ -224,12 +83,13 @@ function shader_directive(shader, name, map)
{ {
var reg = new RegExp(`#${name}.*`, 'g'); var reg = new RegExp(`#${name}.*`, 'g');
var mat = shader.match(reg); var mat = shader.match(reg);
if (!mat) return 0; if (!mat) return undefined;
reg = new RegExp(`#${name}\s*`, 'g'); reg = new RegExp(`#${name}\s*`, 'g');
var ff = mat.map(d=>d.replace(reg,''))[0].trim(); 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) function global_uni(uni, stage)
@ -291,6 +151,10 @@ render.make_shader = function(shader)
var cull = shader_directive(shader, 'cull', cull_map); var cull = shader_directive(shader, 'cull', cull_map);
var depth = shader_directive(shader, 'depth', depth_map); var depth = shader_directive(shader, 'depth', depth_map);
var face = shader_directive(shader, 'face', face_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(/uniform\s+(\w+)\s+(\w+);/g, "uniform _$2 { $1 $2; };");
shader = shader.replace(/(texture2D|sampler) /g, "uniform $1 "); shader = shader.replace(/(texture2D|sampler) /g, "uniform $1 ");
@ -303,12 +167,14 @@ render.make_shader = function(shader)
console.info(`error compiling shader`); console.info(`error compiling shader`);
return; return;
} }
io.rm(out); // io.rm(out);
/* Take YAML and create the shader object */ /* Take YAML and create the shader object */
var yamlfile = `${out}_reflection.yaml`; var yamlfile = `${out}_reflection.yaml`;
console.info(`slurping ${yamlfile}`); 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); io.rm(yamlfile);
obj = obj.shaders[0].programs[0]; obj = obj.shaders[0].programs[0];
@ -332,6 +198,7 @@ render.make_shader = function(shader)
obj.primitive = primitive; obj.primitive = primitive;
obj.depth = depth; obj.depth = depth;
obj.face = face; obj.face = face;
obj.indexed = indexed;
if (obj.vs.inputs) if (obj.vs.inputs)
for (var i of 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")); bind.images.push(game.texture("icons/no_tex.gif"));
} }
if (mesh.index) { if (shader.indexed) {
bind.index = mesh.index; bind.index = mesh.index;
bind.count = mesh.count; bind.count = mesh.count;
} else } else
@ -442,4 +309,154 @@ render.sg_bind = function(shader, mesh = {}, material = {}, ssbo)
return bind; 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}; return {render};

View file

@ -73,6 +73,7 @@ char *js2strdup(JSValue v) {
void sg_buffer_free(sg_buffer *b) void sg_buffer_free(sg_buffer *b)
{ {
printf("DESTROYED BUFFER AT %p\n", b);
sg_destroy_buffer(*b); sg_destroy_buffer(*b);
free(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, JSC_CCALL(render_set_camera,
JSValue cam = argv[0]; JSValue cam = argv[0];
int ortho = js2boolean(js_getpropstr(cam, "ortho")); int ortho = js2boolean(js_getpropstr(cam, "ortho"));
int app = js2boolean(js_getpropstr(cam, "app"));
float near = js2number(js_getpropstr(cam, "near")); float near = js2number(js_getpropstr(cam, "near"));
float far = js2number(js_getpropstr(cam, "far")); float far = js2number(js_getpropstr(cam, "far"));
float fov = js2number(js_getpropstr(cam, "fov"))*HMM_DegToRad; 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); globalview.v = HMM_LookAt_LH(t->pos, look, vUP);
HMM_Vec2 size = mainwin.mode == MODE_FULL ? mainwin.size : mainwin.rendersize; HMM_Vec2 size = mainwin.mode == MODE_FULL ? mainwin.size : mainwin.rendersize;
if (ortho && app)
size = mainwin.size;
if (ortho) if (ortho)
globalview.p = HMM_Orthographic_Metal( globalview.p = HMM_Orthographic_Metal(
-size.x/2, -size.x/2,
@ -760,6 +765,7 @@ sg_shader js2shader(JSValue v)
int atin = js_arrlen(attrs); int atin = js_arrlen(attrs);
for (int i = 0; i < atin; i++) { for (int i = 0; i < atin; i++) {
JSValue u = js_getpropidx(attrs, 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_name = js2strdup(js_getpropstr(u,"sem_name"));
desc.attrs[i].sem_index = js2number(js_getpropstr(u, "sem_index")); desc.attrs[i].sem_index = js2number(js_getpropstr(u, "sem_index"));
} }
@ -848,6 +854,7 @@ JSC_CCALL(render_pipeline,
p.primitive_type = js2number(js_getpropstr(argv[0], "primitive")); p.primitive_type = js2number(js_getpropstr(argv[0], "primitive"));
//p.face_winding = js2number(js_getpropstr(argv[0], "face")); //p.face_winding = js2number(js_getpropstr(argv[0], "face"));
p.face_winding = 1; p.face_winding = 1;
if (js2boolean(js_getpropstr(argv[0], "indexed")))
p.index_type = SG_INDEXTYPE_UINT16; p.index_type = SG_INDEXTYPE_UINT16;
if (js2boolean(js_getpropstr(argv[0], "blend"))) if (js2boolean(js_getpropstr(argv[0], "blend")))
p.colors[0].blend = blend_trans; p.colors[0].blend = blend_trans;
@ -961,7 +968,6 @@ static const JSCFunctionListEntry js_render_funcs[] = {
MIST_FUNC_DEF(render, commit, 0), 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_scissor, sg_apply_scissor_rect(js2number(argv[0]), js2number(argv[1]), js2number(argv[2]), js2number(argv[3]), 0))
JSC_CCALL(gui_text, JSC_CCALL(gui_text,
const char *s = JS_ToCString(js, argv[0]); 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]))) JSC_CCALL(gui_font_set, font_set(js2font(argv[0])))
static const JSCFunctionListEntry js_gui_funcs[] = { static const JSCFunctionListEntry js_gui_funcs[] = {
MIST_FUNC_DEF(gui, flush, 0),
MIST_FUNC_DEF(gui, scissor, 4), MIST_FUNC_DEF(gui, scissor, 4),
MIST_FUNC_DEF(gui, text, 6), MIST_FUNC_DEF(gui, text, 6),
MIST_FUNC_DEF(gui, font_set,1) MIST_FUNC_DEF(gui, font_set,1)