This commit is contained in:
John Alanbrook 2024-10-17 17:23:33 -05:00
parent f1b2984f61
commit 83a19eec27
17 changed files with 489 additions and 673 deletions

View file

@ -1452,20 +1452,6 @@ var replpanel = Object.copy(inputpanel, {
guibody() { guibody() {
this.win.selectable = true; this.win.selectable = true;
var log = console.transcript; var log = console.transcript;
return [
Mum.text({
str: log,
anchor: [0, 0],
offset: [0, -300].sub(this.scrolloffset),
selectable: true,
}),
Mum.text({
str: this.value,
color: Color.green,
offset: [0, -290],
caret: this.caret,
}),
];
}, },
prevmark: -1, prevmark: -1,
prevthis: [], prevthis: [],
@ -1608,109 +1594,6 @@ replpanel.inputs.pgdown = function () {
}; };
replpanel.inputs.pgdown.rep = true; replpanel.inputs.pgdown.rep = true;
var objectexplorer = Object.copy(inputpanel, {
title: "object explorer",
obj: undefined,
previous: [],
start() {
this.previous = [];
},
goto_obj(obj) {
if (obj === this.obj) return;
this.previous.push(this.obj);
this.obj = obj;
},
prev_obj() {
this.obj = this.previous.pop();
},
guibody() {
var items = [];
items.push(Mum.text({ str: "Examining " + this.obj.toString() + " entity" }));
items.push(Mum.text({ str: JSON.stringify(this.obj, undefined, 1) }));
return items;
var n = 0;
var curobj = this.obj;
while (curobj) {
n++;
curobj = curobj.__proto__;
}
n--;
curobj = this.obj.__proto__;
while (curobj) {
items.push(Mum.text({ str: curobj.toString(), action: this.goto_obj(curobj) }));
curobj = curobj.__proto__;
}
if (!Object.empty(this.previous))
items.push(
Mum.text({
str: "prev: " + this.previous.last(),
action: this.prev_obj,
}),
);
Object.getOwnPropertyNames(this.obj).forEach(key => {
var descriptor = Object.getOwnPropertyDescriptor(this.obj, key);
if (!descriptor) return;
var hidden = !descriptor.enumerable;
var writable = descriptor.writable;
var configurable = descriptor.configurable;
if (!descriptor.configurable) return;
if (hidden) return;
var name = (hidden ? "[hidden] " : "") + key;
var val = this.obj[key];
switch (typeof val) {
case "object":
if (val) {
items.push(Mum.text({ str: name }));
items.push(
Mum.text({
str: val.toString(),
action: this.goto_obj.bind(val),
}),
);
}
break;
case "function":
items.push(Mum.text({ str: name }));
items.push(Mum.text({ str: "function" }));
break;
default:
items.push(Mum.text({ str: name }));
items.push(Mum.text({ str: val.toString() }));
break;
}
});
items.push(Mum.text({ str: "Properties that can be pulled in ..." }));
var pullprops = [];
for (var key in this.obj.__proto__) {
if (!this.obj.hasOwn(key)) {
if (typeof this.obj[key] === "object" || typeof this.obj[key] === "function") continue;
pullprops.push(key);
}
}
pullprops = pullprops.sort();
pullprops.forEach(function (key) {
items.push(Mum.text({ str: key }));
});
return items;
},
});
var openlevelpanel = Object.copy(inputpanel, { var openlevelpanel = Object.copy(inputpanel, {
title: "open entity", title: "open entity",
action() { action() {
@ -1720,8 +1603,6 @@ var openlevelpanel = Object.copy(inputpanel, {
assets: [], assets: [],
allassets: [], allassets: [],
mumlist: {},
submit_check() { submit_check() {
if (this.assets.length === 0) return false; if (this.assets.length === 0) return false;
@ -1739,32 +1620,15 @@ var openlevelpanel = Object.copy(inputpanel, {
this.submit(); this.submit();
}; };
click_ur = click_ur.bind(this); click_ur = click_ur.bind(this);
this.mumlist = [];
this.assets.forEach(function (x) {
this.mumlist[x] = Mum.text({
str: x,
action: click_ur,
color: Color.blue,
hovered: { color: Color.red },
selectable: true,
});
}, this);
}, },
keycb() { keycb() {
if (this.value) this.assets = this.allassets.filter(x => x.startsWith(this.value)); if (this.value) this.assets = this.allassets.filter(x => x.startsWith(this.value));
else this.assets = this.allassets.slice(); else this.assets = this.allassets.slice();
for (var m in this.mumlist) this.mumlist[m].hide = true;
this.assets.forEach(function (x) {
this.mumlist[x].hide = false;
}, this); }, this);
}, },
guibody() { guibody() {
var a = [Mum.text({ str: this.value, color: Color.green, caret: this.caret })];
var b = a.concat(Object.values(this.mumlist));
return Mum.column({ items: b, offset: [0, -10] });
}, },
}); });
@ -1789,17 +1653,6 @@ var groupsaveaspanel = Object.copy(inputpanel, {
}, },
}); });
var quitpanel = Object.copy(inputpanel, {
title: "really quit?",
action() {
os.quit();
},
guibody() {
return Mum.text({ str: "Really quit?" });
},
});
var allfiles = []; var allfiles = [];
allfiles.push(Resources.scripts, Resources.images, Resources.sounds); allfiles.push(Resources.scripts, Resources.images, Resources.sounds);
allfiles = allfiles.flat(); allfiles = allfiles.flat();
@ -1815,26 +1668,6 @@ var assetexplorer = Object.copy(openlevelpanel, {
}, },
}); });
var componentexplorer = Object.copy(inputpanel, {
title: "component menu",
assets: ["sprite", "model", "edge2d", "polygon2d", "circle2d"],
click(name) {
if (editor.selectlist.length !== 1) return;
editor.selectlist[0].add_component(component[name]);
},
guibody() {
return componentexplorer.assets.map(x =>
Mum.text({
str: x,
action: this.click,
color: Color.blue,
hovered: { Color: Color.red },
selectable: true,
}),
);
},
});
var entitylistpanel = Object.copy(inputpanel, { var entitylistpanel = Object.copy(inputpanel, {
title: "Level object list", title: "Level object list",
level: {}, level: {},

View file

@ -104,6 +104,8 @@ prosperon.textinput = function (c) {
player[0].raw_input("char", "pressed", c); player[0].raw_input("char", "pressed", c);
}; };
prosperon.mousemove = function (pos, dx) { prosperon.mousemove = function (pos, dx) {
pos.y *= -1;
dx.y *= -1;
mousepos = pos; mousepos = pos;
player[0].mouse_input("move", pos, dx); player[0].mouse_input("move", pos, dx);
}; };

View file

@ -1,24 +1,258 @@
layout.flag = {}; // Layout code
layout.flag.row = 0x002; // Contain is for how it will treat its children. If they should be laid out as a row, or column, or in a flex style, etc.
layout.flag.column = 0x003; layout.contain = {};
layout.flag.layout = 0x000; layout.contain.row = 0x002;
layout.flag.flex = 0x002; layout.contain.column = 0x003;
layout.flag.nowrap = 0x000; layout.contain.layout = 0x000;
layout.flag.wrap = 0x004; layout.contain.flex = 0x002;
layout.flag.start = 0x008; layout.contain.nowrap = 0x000;
layout.flag.middle = 0x000; layout.contain.wrap = 0x004;
layout.flag.end = 0x010; layout.contain.start = 0x008;
layout.flag.justify = 0x018; layout.contain.middle = 0x000;
layout.contain.end = 0x010;
layout.contain.justify = 0x018;
layout.flag.left = 0x020; // Behave is for how it behaves to its parent. How it should be aligned, directions it should fill, etc.
layout.flag.top = 0x040; layout.behave = {};
layout.flag.right = 0x080; layout.behave.left = 0x020;
layout.flag.bottom = 0x100; layout.behave.top = 0x040;
layout.flag.hfill = 0x0a0; layout.behave.right = 0x080;
layout.flag.vfill = 0x140; layout.behave.bottom = 0x100;
layout.flag.hcenter = 0x000; layout.behave.hfill = 0x0a0;
layout.flag.vcenter = 0x000; layout.behave.vfill = 0x140;
layout.flag.center = 0x000; layout.behave.hcenter = 0x000;
layout.flag.fill = 0x1e0; layout.behave.vcenter = 0x000;
layout.flag.break = 0x200; layout.behave.center = 0x000;
layout.behave.fill = 0x1e0;
layout.behave.break = 0x200;
var clay_base = {
font: undefined,
background_image: undefined,
slice: 0,
font: 'smalle.16',
font_size: undefined,
color: [1,1,1,1],
spacing:0,
padding:0,
margin:0,
offset:[0,0],
size:[0,0]
};
var root_item;
var root_config;
var boxes = [];
globalThis.clay = {};
clay.normalizeSpacing = function(spacing) {
if (typeof spacing === 'number') {
return {l: spacing, r: spacing, t: spacing, b: spacing};
} else if (Array.isArray(spacing)) {
if (spacing.length === 2) {
return {l: spacing[0], r: spacing[0], t: spacing[1], b: spacing[1]};
} else if (spacing.length === 4) {
return {l: spacing[0], r: spacing[1], t: spacing[2], b: spacing[3]};
}
} else if (typeof spacing === 'object') {
return {l: spacing.l || 0, r: spacing.r || 0, t: spacing.t || 0, b: spacing.b || 0};
} else {
return {l:0, r:0, t:0, b:0};
}
}
clay.draw = function(size, fn, )
{
layout.reset();
boxes = [];
var root = layout.item({
size:size,
contain: layout.contain.row,
});
root_item = root;
root_config = Object.assign({}, clay_base);
boxes.push({
id:root,
config:root_config
});
fn();
layout.run();
// Adjust bounding boxes for padding
for (var i = 0; i < boxes.length; i++) {
var box = boxes[i];
box.content = layout.get_rect(box.id);
box.boundingbox = Object.assign({}, box.content);
var padding = clay.normalizeSpacing(box.config.padding || 0);
if (padding.l || padding.r || padding.t || padding.b) {
// Adjust the boundingbox to include the padding
box.boundingbox.x -= padding.l;
box.boundingbox.y -= padding.t;
box.boundingbox.width += padding.l + padding.r;
box.boundingbox.height += padding.t + padding.b;
}
box.marginbox = Object.assign({}, box.content);
var margin = clay.normalizeSpacing(box.config.margin || 0);
box.marginbox.x -= margin.l;
box.marginbox.y -= margin.t;
box.marginbox.width += margin.l+margin.r;
box.marginbox.height += margin.t+margin.b;
box.content.y *= -1;
box.boundingbox.y *= -1
box.content.anchor_y = 1;
box.boundingbox.anchor_y = 1;
}
return boxes;
}
var last_config;
function create_view_fn(base_config)
{
var base = Object.assign(Object.create(clay_base), base_config);
return function(config = {}, fn) {
config.__proto__ = base;
var item = add_item(config);
var prev_item = root_item;
var prev_config = root_config;
root_item = item;
root_config = config;
root_config._childIndex = 0; // Initialize child index
fn?.();
root_item = prev_item;
root_config = prev_config;
}
}
clay.vstack = create_view_fn({
contain: layout.contain.column | layout.contain.start,
});
clay.hstack = create_view_fn({
contain: layout.contain.row | layout.contain.start,
});
clay.spacer = create_view_fn({
behave: layout.behave.hfill | layout.behave.vfill
});
function image_size(img)
{
return [img.rect[2]*img.texture.width, img.rect[3]*img.texture.height];
}
var add_item = function(config)
{
// Normalize the child's margin
var margin = clay.normalizeSpacing(config.margin || 0);
var padding = clay.normalizeSpacing(config.padding || 0);
var childGap = root_config.child_gap || 0;
// Adjust for child_gap
if (root_config._childIndex > 0) {
var parentContain = root_config.contain || 0;
var isVStack = (parentContain & layout.contain.column) !== 0;
var isHStack = (parentContain & layout.contain.row) !== 0;
if (isVStack) {
margin.t += childGap;
} else if (isHStack) {
margin.l += childGap;
}
}
var use_config = Object.create(config);
use_config.margin = {
t: margin.t+padding.t,
b: margin.b+padding.b,
r:margin.r+padding.r,
l:margin.l+padding.l
};
var item = layout.item(use_config);
boxes.push({
id:item,
config:use_config
});
layout.insert(root_item,item);
// Increment the parent's child index
root_config._childIndex++;
return item;
}
clay.image = function(path, config = {})
{
config.__proto__ = clay_base;
config.image = path;
var image = game.texture(path);
config.size ??= [image.texture.width, image.texture.height];
add_item(config);
}
clay.text = function(str, config = {})
{
config.__proto__ = clay_base;
var tsize = render.text_size(str, config.font);
config.size = config.size.map((x,i) => Math.max(x, tsize[i]));
add_item(config);
config.text = str;
}
/*
For a given size,
the layout engine should "see" size + margin
but its interior content should "see" size - padding
hence, the layout box should be size-padding, with margin of margin+padding
*/
var button_base = Object.assign(Object.create(clay_base), {
padding:0,
hovered:{
}
});
clay.button = function(str, action, config = {})
{
config.__proto__ = button_base;
config.size = render.text_size(str,config.font);
add_item(config);
config.text = str;
config.action = action;
}
layout.draw_commands = function(cmds, pos = [0,0])
{
var mousepos = input.mouse.screenpos();
for (var cmd of cmds) {
cmd.boundingbox.x += pos.x;
cmd.boundingbox.y += pos.y;
cmd.content.x += pos.x;
cmd.content.y += pos.y;
var config = cmd.config;
if (config.hovered && geometry.rect_point_inside(cmd.content, mousepos)) {
config.hovered.__proto__ = config;
config = config.hovered;
}
if (config.background_image)
if (render.slice)
render.slice9(config.background_image, cmd.boundingbox, config.slice, config.background_color);
else
render.image(config.background_image, cmd.boundingbox, 0, config.color);
else if (config.background_color)
render.rectangle(cmd.boundingbox, config.background_color);
if (config.text)
render.text(config.text, cmd.content, config.font, config.font_size, config.color);
if (config.image)
render.image(config.image, cmd.content, 0, config.color);
render.rectangle(cmd.content, [1,0,0,0]);
// render.rectangle(cmd.boundingbox, [0,1,0,0.1]);
// render.rectangle(cmd.marginbox, [0,0,1,0.1]);
}
}

View file

@ -1,6 +1,5 @@
this.hud = function () { this.hud = function () {
mum.label("No game yet! Make game.js to get started!", { layout.draw_commands(clay.draw([], _ => {
pos: game.size.scale(0.5), clay.text("No game yet! Make game.js to get started!");
anchor: [0.5, 0.5], }));
});
}; };

View file

@ -76,20 +76,6 @@ game.engine_start = function (s) {
camera.size = game.size; camera.size = game.size;
gamestate.camera = camera; gamestate.camera = camera;
prosperon.hudcam = prosperon.make_camera();
var hudcam = prosperon.hudcam;
hudcam.near = 0;
hudcam.size = camera.size;
hudcam.mode = "keep";
hudcam.break = "fit";
prosperon.appcam = prosperon.make_camera();
var appcam = prosperon.appcam;
appcam.near = 0;
appcam.size = window.size;
appcam.transform.pos = [window.size.x, window.size.y, -100];
prosperon.screencolor = render.screencolor();
globalThis.imgui = render.imgui_init(); globalThis.imgui = render.imgui_init();
s(); s();
@ -110,22 +96,6 @@ game.engine_start = function (s) {
count: 6, count: 6,
}; };
shape.flipquad = {
pos: os.make_buffer([
0, 0, 0,
0, 1, 0,
1, 0, 0,
1, 1, 0], 0),
verts: 4,
uv: os.make_buffer([
0, 1,
0, 0,
1, 1,
1, 0], 2),
index: os.make_buffer([0, 1, 2, 2, 1, 3], 1),
count: 6,
};
shape.triangle = { shape.triangle = {
pos: os.make_buffer([0, 0, 0, 0.5, 1, 0, 1, 0, 0], 0), pos: os.make_buffer([0, 0, 0, 0.5, 1, 0, 1, 0, 0], 0),
uv: os.make_buffer([0, 0, 0.5, 1, 1, 0], 2), uv: os.make_buffer([0, 0, 0.5, 1, 1, 0], 2),
@ -254,7 +224,7 @@ var sheetsize = 1024;
function pack_into_sheet(images) function pack_into_sheet(images)
{ {
if (!Array.isArray(images)) images = [images]; if (!Array.isArray(images)) images = [images];
if (images[0].texture.width > 300 && images[0].texture.height > 300) return; if (images[0].texture.width > 1 && images[0].texture.height > 1) return;
sheet_frames = sheet_frames.concat(images); sheet_frames = sheet_frames.concat(images);
var sizes = sheet_frames.map(x => [x.rect[2]*x.texture.width, x.rect[3]*x.texture.height]); var sizes = sheet_frames.map(x => [x.rect[2]*x.texture.width, x.rect[3]*x.texture.height]);
var pos = os.rectpack(sheetsize, sheetsize, sizes); var pos = os.rectpack(sheetsize, sheetsize, sizes);
@ -483,10 +453,13 @@ var Register = {
if (!flush) { if (!flush) {
prosperon[name] = function (...args) { prosperon[name] = function (...args) {
profile.report(name);
fns.forEach(fn => fn(...args)); fns.forEach(fn => fn(...args));
profile.endreport(name);
}; };
} else } else
prosperon[name] = function (...args) { prosperon[name] = function (...args) {
profile.report(name);
var layer = undefined; var layer = undefined;
for (var fn of fns) { for (var fn of fns) {
if (layer !== fn.layer) { if (layer !== fn.layer) {
@ -495,6 +468,7 @@ var Register = {
} }
fn(); fn();
} }
profile.endreport(name);
}; };
prosperon[name].fns = fns; prosperon[name].fns = fns;
@ -516,6 +490,7 @@ Register.add_cb("gui", true);
Register.add_cb("hud", true, render.flush); Register.add_cb("hud", true, render.flush);
Register.add_cb("draw", true, render.flush); Register.add_cb("draw", true, render.flush);
Register.add_cb("imgui", true, render.flush); Register.add_cb("imgui", true, render.flush);
Register.add_cb("app", true, render.flush);
var Event = { var Event = {
events: {}, events: {},
@ -596,8 +571,7 @@ function world_start() {
} }
global.mixin("scripts/physics"); global.mixin("scripts/physics");
global.mixin("scripts/widget"); global.mixin("scripts/layout");
global.mixin("scripts/mum");
window.title = `Prosperon v${prosperon.version}`; window.title = `Prosperon v${prosperon.version}`;
window.size = [500, 500]; window.size = [500, 500];

View file

@ -1,3 +1,5 @@
var unit_transform = os.make_transform();
/* /*
Anatomy of rendering an image Anatomy of rendering an image
render.image(path) render.image(path)
@ -222,16 +224,10 @@ render.face_map = face_map;
render.compare = compare; render.compare = compare;
render.blendfactor = blendfactor; render.blendfactor = blendfactor;
render.use_pipeline = function use_pipeline(pipeline)
{
}
var pipe_shaders = new WeakMap(); var pipe_shaders = new WeakMap();
// Uses the shader with the specified pipeline. If none specified, uses the base pipeline // Uses the shader with the specified pipeline. If none specified, uses the base pipeline
render.use_shader = function use_shader(shader, pipeline) { render.use_shader = function use_shader(shader, pipeline = base_pipeline) {
pipeline ??= base_pipeline;
if (typeof shader === "string") shader = make_shader(shader); if (typeof shader === "string") shader = make_shader(shader);
if (cur.shader === shader) return; if (cur.shader === shader) return;
@ -352,16 +348,6 @@ function set_global_uni(uni, stage) {
uni_globals[uni.name]?.(stage, uni.slot); uni_globals[uni.name]?.(stage, uni.slot);
} }
var setcam = render.set_camera;
render.set_camera = function (cam) {
if (nextflush) {
nextflush();
nextflush = undefined;
}
delete cur.shader;
setcam(cam);
};
var shader_cache = {}; var shader_cache = {};
var shader_times = {}; var shader_times = {};
@ -531,11 +517,11 @@ var shader_unisize = {
function shader_globals(shader) { function shader_globals(shader) {
for (var p in shader.vs.unimap) set_global_uni(shader.vs.unimap[p], 0); for (var p in shader.vs.unimap) set_global_uni(shader.vs.unimap[p], 0);
for (var p in shader.fs.unimap) set_global_uni(shader.fs.unimap[p], 1); for (var p in shader.fs.unimap) set_global_uni(shader.fs.unimap[p], 1);
} }
function shader_apply_material(shader, material = {}, old = {}) { function shader_apply_material(shader, material = {}, old = {}) {
render.setpipeline(cur.pipeline);
for (var p in shader.vs.unimap) { for (var p in shader.vs.unimap) {
if (!(p in material)) continue; if (!(p in material)) continue;
if (material[p] === old[p]) continue; if (material[p] === old[p]) continue;
@ -719,6 +705,7 @@ render.draw_gizmos = true;
render.buckets = []; render.buckets = [];
render.sprites = function render_sprites() { render.sprites = function render_sprites() {
profile.report("sprites");
profile.report("drawing"); profile.report("drawing");
render.use_shader(spritessboshader); render.use_shader(spritessboshader);
var buckets = component.sprite_buckets(); var buckets = component.sprite_buckets();
@ -734,6 +721,7 @@ render.sprites = function render_sprites() {
} }
} }
profile.endreport("drawing"); profile.endreport("drawing");
profile.endreport("sprites");
}; };
render.circle = function render_circle(pos, radius, color, inner_radius = 1) { render.circle = function render_circle(pos, radius, color, inner_radius = 1) {
@ -783,6 +771,7 @@ render.forceflush = function()
{ {
if (nextflush) nextflush(); if (nextflush) nextflush();
nextflush = undefined; nextflush = undefined;
cur.shader = undefined;
} }
var poly_cache = []; var poly_cache = [];
@ -821,7 +810,7 @@ render.line = function render_line(points, color = Color.white, thickness = 1) {
var poly = poly_e(); var poly = poly_e();
var dist = vector.distance(a, b); var dist = vector.distance(a, b);
poly.transform.move(vector.midpoint(a, b)); poly.transform.move(vector.midpoint(a, b));
poly.transform.rotate([0, 0, -1], vector.angle([b.x - a.x, b.y - a.y])); poly.transform.rotate([0, 0, 1], vector.angle([b.x - a.x, b.y - a.y]));
poly.transform.scale = [dist, thickness, 1]; poly.transform.scale = [dist, thickness, 1];
poly.color = color; poly.color = color;
} }
@ -854,17 +843,15 @@ render.coordinate = function render_coordinate(pos, size, color) {
render.point(pos, 2, color); render.point(pos, 2, color);
}; };
render.boundingbox = function render_boundingbox(bb, color = Color.white) {
render.line(bbox.topoints(bb).wrapped(1), color);
};
var queued_shader; var queued_shader;
var queued_pipe; var queued_pipe;
render.rectangle = function render_rectangle(lowerleft, upperright, color, shader = polyssboshader, pipe = base_pipeline) { render.rectangle = function render_rectangle(rect, color, shader = polyssboshader, pipe = base_pipeline) {
var transform = os.make_transform(); var transform = os.make_transform();
var wh = [upperright.x - lowerleft.x, upperright.y - lowerleft.y]; var wh = [rect.width, rect.height];
var poly = poly_e(); var poly = poly_e();
poly.transform.move(vector.midpoint(lowerleft, upperright)); var pos = [rect.x,rect.y].add([rect.width,rect.height].scale(0.5));
pos = pos.sub([rect.width,rect.height].scale([rect.anchor_x,rect.anchor_y]));
poly.transform.move(pos);
poly.transform.scale = [wh.x, wh.y, 1]; poly.transform.scale = [wh.x, wh.y, 1];
poly.color = color; poly.color = color;
@ -873,23 +860,6 @@ render.rectangle = function render_rectangle(lowerleft, upperright, color, shade
check_flush(flush_poly); check_flush(flush_poly);
}; };
// brect is x,y,width,height, with x,y in the upper left corner
render.brect = function(brect, color = Color.white)
{
render.rectangle([brect.x,brect.y], [brect.x+brect.width, brect.y+brect.height], color);
}
// brect is x,y,width,height, with x,y in the upper left corner
render.urect = function(brect, color = Color.white)
{
render.rectangle([brect.x,brect.y], [brect.x+brect.width, brect.y], color);
}
render.rect = function(rect, color, shader, pipe)
{
render.rectangle([rect.x-rect.w/2, rect.y-rect.h/2], [rect.x+rect.w/2, rect.y+rect.h/2], color, shader, pipe);
}
render.box = function render_box(pos, wh, color = Color.white) { render.box = function render_box(pos, wh, color = Color.white) {
var poly = poly_e(); var poly = poly_e();
poly.transform.move(pos); poly.transform.move(pos);
@ -902,11 +872,15 @@ render.window = function render_window(pos, wh, color) {
render.box(pos.add(wh.scale(0.5)), wh, color); render.box(pos.add(wh.scale(0.5)), wh, color);
}; };
render.text = function (str, pos, font = cur_font, size = 0, color = Color.white, wrap = -1) { render.text = function (str, rect, font = cur_font, size = 0, color = Color.white, wrap = -1, ) {
if (typeof font === 'string') if (typeof font === 'string')
font = render.get_font(font); font = render.get_font(font);
if (!font) return; if (!font) return;
var pos = [rect.x,rect.y];
pos.y -= font.descent;
if (rect.anchor_y)
pos.y -= rect.anchor_y*(font.ascent-font.descent);
gui.text(str, pos, size, color, wrap, font); // this puts text into buffer gui.text(str, pos, size, color, wrap, font); // this puts text into buffer
cur_font = font; cur_font = font;
check_flush(render.flush_text); check_flush(render.flush_text);
@ -1008,38 +982,38 @@ render.invertmask = function()
render.draw(shape.quad); render.draw(shape.quad);
} }
render.mask = function mask(tex, pos, scale, rotation = 0, ref = 1) render.mask = function mask(image, pos, scale, rotation = 0, ref = 1)
{ {
if (typeof tex === 'string') if (typeof image === 'string')
tex = game.texture(tex); image = game.texture(image);
var tex = image.texture;
if (scale) scale = sacle.div([tex.width,tex.height]);
else scale = vector.v3one;
var pipe = stencil_writer(ref); var pipe = stencil_writer(ref);
render.use_shader('shaders/sprite.cg', pipe); render.use_shader('shaders/sprite.cg', pipe);
var t = os.make_transform(); var t = os.make_transform();
t.pos = pos; t.trs(pos, undefined,scale);
t.scale = scale.div(tex.dimensions);
set_model(t); set_model(t);
render.use_mat({ render.use_mat({
diffuse:tex.texture, diffuse:image.texture,
rect: tex.rect, rect: image.rect,
shade: Color.white shade: Color.white
}); });
render.draw(shape.quad); render.draw(shape.quad);
} }
render.image = function image(image, pos, scale, rotation = 0, color = Color.white) { render.image = function image(image, rect = [0,0], rotation = 0, color = Color.white) {
if (typeof image === "string") if (typeof image === "string")
image = game.texture(image); image = game.texture(image);
var tex = image.texture; var tex = image.texture;
if (scale)
scale = scale.div([tex.width, tex.height]);
else
scale = vector.v3one;
if (!tex) return; if (!tex) return;
var size = [rect.width ? rect.width : tex.width, rect.height ? rect.height : tex.height];
if (!lasttex) { if (!lasttex) {
check_flush(flush_img); check_flush(flush_img);
lasttex = tex; lasttex = tex;
@ -1051,30 +1025,26 @@ render.image = function image(image, pos, scale, rotation = 0, color = Color.whi
} }
var e = img_e(); var e = img_e();
e.transform.trs(pos, undefined, scale); var pos = [rect.x,rect.y].sub(size.scale([rect.anchor_x, rect.anchor_y]));
e.transform.trs(pos, undefined, size.div([tex.width,tex.height]));
e.image = image; e.image = image;
e.shade = color; e.shade = color;
return; return;
var bb = {};
bb.b = pos.y;
bb.l = pos.x;
bb.t = pos.y + tex.height * scale;
bb.r = pos.x + tex.width * scale;
return bb;
}; };
// pos is the lower left corner, scale is the width and height // pos is the lower left corner, scale is the width and height
render.slice9 = function (image, pos, bb, scale = [tex.width, tex.height], color = Color.white) { render.slice9 = function (image, rect = [0,0], slice = 0, color = Color.white) {
if (typeof image === 'string') if (typeof image === 'string')
image = game.texture(image); image = game.texture(image);
var tex = image.texture; var tex = image.texture;
var size = [rect.width ? rect.width : tex.width, rect.height ? rect.height : tex.height];
var t = os.make_transform(); var t = os.make_transform();
t.pos = pos; t.pos = pos;
t.scale = [scale.x / tex.width, scale.y / tex.height, 1]; t.scale = size.div([tex.width,tex.height]);
var border; slice = clay.normalizeSpacing(slice);
if (typeof bb === "number") border = [bb / tex.width, bb / tex.height, bb / tex.width, bb / tex.height]; var border = [slice.l / tex.width, slice.b / tex.height, slice.r / tex.width, slice.t / tex.height];
else border = [bb.l / tex.width, bb.b / tex.height, bb.r / tex.width, bb.t / tex.height];
render.use_shader(slice9shader); render.use_shader(slice9shader);
set_model(t); set_model(t);
@ -1083,7 +1053,7 @@ render.slice9 = function (image, pos, bb, scale = [tex.width, tex.height], color
diffuse: tex, diffuse: tex,
rect: [0, 0, 1, 1], rect: [0, 0, 1, 1],
border: border, border: border,
scale: [scale.x / tex.width, scale.y / tex.height], scale: [size.x / tex.width, size.y / tex.height],
}); });
render.draw(shape.quad); render.draw(shape.quad);
@ -1142,8 +1112,7 @@ render.draw = function render_draw(mesh, ssbo, inst = 1, e_start = 0) {
profile.endreport("gpu_draw"); profile.endreport("gpu_draw");
}; };
// Returns an array in the form of [left, bottom, right, top] in pixels of the camera to render to // Camera viewport is a rectangle with the bottom left corner defined as x,y. Units are pixels on the window.
// Camera viewport is [left,bottom,width,height] in relative values
function camviewport() { function camviewport() {
var aspect = (((this.viewport[2] - this.viewport[0]) / (this.viewport[3] - this.viewport[1])) * window.size.x) / window.size.y; var aspect = (((this.viewport[2] - this.viewport[0]) / (this.viewport[3] - this.viewport[1])) * window.size.x) / window.size.y;
var raspect = this.size.x / this.size.y; var raspect = this.size.x / this.size.y;
@ -1162,20 +1131,45 @@ function camviewport() {
switch (usemode) { switch (usemode) {
case "stretch": case "stretch":
case "expand": case "expand":
return [0, 0, window.size.x, window.size.y]; return {
x: 0,
y: 0,
width: window.size.x,
height: window.size.y
};
case "keep": case "keep":
return [left, bottom, left + this.size.x, bottom + this.size.y]; return {
x: left,
y: bottom,
width:left+this.size.x,
height:bottom+this.size.y
}
case "height": case "height":
var ret = [left, 0, this.size.x * (window.size.y / this.size.y), window.size.y]; var ret = {
ret[0] = (window.size.x - (ret[2] - ret[0])) / 2; x:left,
y:0,
width:this.size.x*(window.size.y/this.size.y),
height:window.size.y
};
ret.x = (window.size.x - (ret.width-ret.x))/2;
return ret; return ret;
case "width": case "width":
var ret = [0, bottom, window.size.x, this.size.y * (window.size.x / this.size.x)]; var ret = {
ret[1] = (window.size.y - (ret[3] - ret[1])) / 2; x:0,
y:bottom,
width:window.size.x,
height:this.size.y*(window.size.x/this.size.x)
};
ret.y = (window.size.y - (ret.height-ret.y))/2;
return ret; return ret;
} }
return [0, 0, window.size.x, window.size.y]; return {
x:0,
y:0,
width:window.size.x,
height:window.size.y
};
} }
// pos is pixels on the screen, lower left[0,0] // pos is pixels on the screen, lower left[0,0]
@ -1183,8 +1177,8 @@ function camscreen2world(pos) {
var view = this.screen2cam(pos); var view = this.screen2cam(pos);
view.x *= this.size.x; view.x *= this.size.x;
view.y *= this.size.y; view.y *= this.size.y;
view = view.sub([this.size.x / 2, this.size.y / 2]);
view = view.add(this.pos.xy); view = view.add(this.pos.xy);
view = view.scale(this.transform.scale);
return view; return view;
} }
@ -1197,11 +1191,12 @@ camscreen2world.doc = "Convert a view position for a camera to world.";
// return camera coordinates given a screen position // return camera coordinates given a screen position
function screen2cam(pos) { function screen2cam(pos) {
var winsize = window.size.slice();
var viewport = this.view(); var viewport = this.view();
var width = viewport[2]; var viewpos = pos.sub([viewport.x,viewport.y]);
var height = viewport[3]; viewpos = viewpos.div([viewport.width,viewport.height]);
var viewpos = pos.sub([viewport[0], viewport[1]]); viewpos.y += 1;
return viewpos.div([width, height]); return viewpos;
} }
function camextents() { function camextents() {
@ -1224,21 +1219,17 @@ prosperon.gizmos = function () {
prosperon.make_camera = function () { prosperon.make_camera = function () {
var cam = world.spawn(); var cam = world.spawn();
cam.near = -1; cam.near = 1;
cam.far = 1000; cam.far = -1000;
cam.ortho = true; cam.ortho = true;
cam.viewport = [0, 0, 1, 1]; cam.viewport = [0, 0, 1, 1]; // normalized screen coordinates of where to draw
cam.size = window.size.slice(); // The render size of this camera in pixels cam.size = window.size.slice(); // The render size of this camera in pixels
// In ortho mode, this determines how many pixels it will see // In ortho mode, this determines how many pixels it will see
cam.mode = "stretch"; cam.mode = "stretch";
cam.screen2world = camscreen2world; cam.screen2world = camscreen2world;
cam.screen2cam = screen2cam; cam.screen2cam = screen2cam;
cam.extents = camextents; cam.extents = camextents;
cam.mousepos = function () {
return this.screen2world(input.mouse.screenpos());
};
cam.view = camviewport; cam.view = camviewport;
cam.offscreen = false;
return cam; return cam;
}; };
@ -1323,13 +1314,8 @@ var imgui_fn = function () {
render.imgui_end(); render.imgui_end();
}; };
prosperon.postvals = {};
prosperon.postvals.offset_amt = 300;
prosperon.render = function () {
profile.report("world");
render.set_camera(prosperon.camera);
// figure out the highest resolution we can render at that's an integer // figure out the highest resolution we can render at that's an integer
var basesize = prosperon.camera.size.slice(); /* var basesize = prosperon.camera.size.slice();
var baseview = prosperon.camera.view(); var baseview = prosperon.camera.view();
var wh = [baseview[2]-baseview[0], baseview[3]-baseview[1]]; var wh = [baseview[2]-baseview[0], baseview[3]-baseview[1]];
var mult = 1; var mult = 1;
@ -1342,65 +1328,52 @@ prosperon.render = function () {
mult--; mult--;
prosperon.window_render(basesize.scale(mult)); prosperon.window_render(basesize.scale(mult));
profile.report("sprites"); */
prosperon.render = function () {
render.glue_pass();
render.set_view(prosperon.camera.transform);
render.set_projection_ortho({
l:-prosperon.camera.size.x/2,
r:prosperon.camera.size.x/2,
b:-prosperon.camera.size.y/2,
t:prosperon.camera.size.y/2
}, prosperon.camera.near,prosperon.camera.far);
render.viewport(prosperon.camera.view(), false);
if (render.draw_sprites) render.sprites(); if (render.draw_sprites) render.sprites();
if (render.draw_particles) draw_emitters(); if (render.draw_particles) draw_emitters();
profile.endreport("sprites");
profile.report("draws");
prosperon.draw(); prosperon.draw();
profile.endreport("draws");
profile.endreport("world");
render.fillmask(0); render.fillmask(0);
prosperon.hudcam.size = prosperon.camera.size.slice(); render.forceflush();
prosperon.hudcam.transform.pos = [prosperon.hudcam.size.x / 2, prosperon.hudcam.size.y / 2, -100];
prosperon.hudcam.size.y *= -1;
render.set_camera(prosperon.hudcam);
profile.report("hud"); render.set_projection_ortho({
l:0,
r:prosperon.camera.size.x,
b:-prosperon.camera.size.y,
t:0
},-1,1);
render.set_view(unit_transform);
if (render.draw_hud) prosperon.hud(); if (render.draw_hud) prosperon.hud();
render.flush_text(); render.forceflush();
render.set_camera(prosperon.camera); render.set_projection_ortho({
//if (render.draw_gizmos && prosperon.gizmos) prosperon.gizmos(); l:0,
render.flush_text(); r:window.size.x,
b:-window.size.y,
render.end_pass(); t:0
},-1,1);
profile.endreport("hud"); render.viewport({
/* draw the image of the game world first */ t:0,
render.glue_pass(); height:window.size.y,
profile.report("frame"); width:window.size.x,
profile.report("render"); l:0
profile.report("post process"); }, false);
render.viewport(...prosperon.camera.view()); prosperon.app();
render.use_shader(render.postshader);
prosperon.postvals.diffuse = prosperon.screencolor;
render.use_mat(prosperon.postvals);
render.draw(shape.quad);
//render.draw((os.backend() === "directx" || os.backend() === 'metal') ? shape.flipquad : shape.quad);
profile.endreport("post process");
profile.report("app");
// Flush & render
prosperon.appcam.transform.pos = [window.size.x / 2, window.size.y / 2, -100];
prosperon.appcam.size = window.size.slice();
render.set_camera(prosperon.appcam);
render.viewport(...prosperon.appcam.view());
// Call gui functions
if (render.draw_gui) prosperon.gui();
check_flush();
profile.endreport("app");
profile.report("imgui"); profile.report("imgui");
if (debug.show) imgui_fn(); if (debug.show) imgui_fn();
profile.endreport("imgui"); profile.endreport("imgui");
render.end_pass(); render.end_pass();

View file

@ -68,7 +68,7 @@ var texteditor = Object.copy(inputpanel, {
src: "NEW FILE", src: "NEW FILE",
guibody() { guibody() {
return [Mum.text({ str: `EDITING ${this.src}` }), Mum.text({ str: this.value, caret: this.cursor, offset: [0, -16] })]; // TODO: new render here
}, },
insert_char(char) { insert_char(char) {

View file

@ -1,210 +0,0 @@
var inputpanel = {
title: "untitled",
toString() {
return this.title;
},
value: "",
on: false,
pos: [20, window.size.y - 20],
wh: [100, 100],
anchor: [0, 1],
padding: [5, -15],
gui() {
this.win ??= Mum.window({
width: this.wh.x,
height: this.wh.y,
color: Color.black.alpha(0.1),
anchor: this.anchor,
padding: this.padding,
});
var itms = this.guibody();
if (!Array.isArray(itms)) itms = [itms];
if (this.title) this.win.items = [Mum.column({ items: [Mum.text({ str: this.title }), ...itms] })];
else this.win.items = itms;
this.win.draw([100, window.size.y - 50]);
},
guibody() {
return [Mum.text({ str: this.value, color: Color.green }), Mum.button({ str: "SUBMIT", action: this.submit.bind(this) })];
},
open() {
this.on = true;
this.value = "";
this.start();
this.keycb();
},
start() {},
close() {
player[0].uncontrol(this);
this.on = false;
if ("on_close" in this) this.on_close();
},
action() {},
closeonsubmit: true,
submit() {
if (!this.submit_check()) return;
this.action();
if (this.closeonsubmit) this.close();
},
submit_check() {
return true;
},
keycb() {},
caret: 0,
reset_value() {
this.value = "";
this.caret = 0;
},
input_backspace_pressrep() {
this.value = this.value.slice(0, -1);
this.keycb();
},
};
inputpanel.inputs = {};
inputpanel.inputs.block = true;
inputpanel.inputs.post = function () {
this.keycb();
};
inputpanel.inputs.char = function (c) {
this.value = this.value.slice(0, this.caret) + c + this.value.slice(this.caret);
this.caret++;
};
inputpanel.inputs["C-d"] = function () {
this.value = this.value.slice(0, this.caret) + this.value.slice(this.caret + 1);
};
inputpanel.inputs["C-d"].rep = true;
inputpanel.inputs.tab = function () {
this.value = input.tabcomplete(this.value, this.assets);
this.caret = this.value.length;
};
inputpanel.inputs.escape = function () {
this.close();
};
inputpanel.inputs["C-b"] = function () {
if (this.caret === 0) return;
this.caret--;
};
inputpanel.inputs["C-b"].rep = true;
inputpanel.inputs["C-u"] = function () {
this.value = this.value.slice(this.caret);
this.caret = 0;
};
inputpanel.inputs["C-f"] = function () {
if (this.caret === this.value.length) return;
this.caret++;
};
inputpanel.inputs["C-f"].rep = true;
inputpanel.inputs["C-a"] = function () {
this.caret = 0;
};
inputpanel.inputs["C-e"] = function () {
this.caret = this.value.length;
};
inputpanel.inputs.backspace = function () {
if (this.caret === 0) return;
this.value = this.value.slice(0, this.caret - 1) + this.value.slice(this.caret);
this.caret--;
};
inputpanel.inputs.backspace.rep = true;
inputpanel.inputs.enter = function () {
this.submit();
};
inputpanel.inputs["C-k"] = function () {
this.value = this.value.slice(0, this.caret);
};
inputpanel.inputs.lm = function () {
gui.controls.check_submit();
};
var notifypanel = Object.copy(inputpanel, {
title: "notification",
msg: "Refusing to save. File already exists.",
action() {
this.close();
},
guibody() {
return Mum.column({
items: [Mum.text({ str: this.msg }), Mum.button({ str: "OK", action: this.close.bind(this) })],
});
},
});
var gen_notify = function (val, fn) {
var panel = Object.create(notifypanel);
panel.msg = val;
panel.yes = fn;
panel.inputs = {};
panel.inputs.y = function () {
panel.yes();
panel.close();
};
panel.inputs.y.doc = "Confirm yes.";
panel.inputs.enter = function () {
panel.close();
};
panel.inputs.enter.doc = "Close.";
return panel;
};
var listpanel = Object.copy(inputpanel, {
assets: [],
allassets: [],
mumlist: {},
submit_check() {
if (this.assets.length === 0) return false;
this.value = this.assets[0];
return true;
},
start() {
this.assets = this.allassets.slice();
this.caret = 0;
this.mumlist = [];
this.assets.forEach(function (x) {
this.mumlist[x] = Mum.text({
str: x,
action: this.action,
color: Color.blue,
hovered: { color: Color.red },
selectable: true,
});
}, this);
},
keycb() {
if (this.value) this.assets = this.allassets.filter(x => x.startsWith(this.value));
else this.assets = this.allassets.slice();
for (var m in this.mumlist) this.mumlist[m].hide = true;
this.assets.forEach(function (x) {
this.mumlist[x].hide = false;
}, this);
},
guibody() {
var a = [Mum.text({ str: this.value, color: Color.green, caret: this.caret })];
var b = a.concat(Object.values(this.mumlist));
return Mum.column({ items: b, offset: [0, -10] });
},
});
return { inputpanel, gen_notify, notifypanel, listpanel };

View file

@ -12,8 +12,8 @@ const HMM_Vec3 vZ = {0.0,0.0,1.0};
const HMM_Vec3 vUP = {0,1,0}; const HMM_Vec3 vUP = {0,1,0};
const HMM_Vec3 vDOWN = {0,-1,0}; const HMM_Vec3 vDOWN = {0,-1,0};
const HMM_Vec3 vFWD = {0,0,1}; const HMM_Vec3 vFWD = {0,0,-1};
const HMM_Vec3 vBKWD = {0,0,-1}; const HMM_Vec3 vBKWD = {0,0,1};
const HMM_Vec3 vLEFT = {-1,0,0}; const HMM_Vec3 vLEFT = {-1,0,0};
const HMM_Vec3 vRIGHT = {1,0,0}; const HMM_Vec3 vRIGHT = {1,0,0};
@ -1231,11 +1231,9 @@ HMM_Mat4 HMM_Orthographic_DX(float l, float r, float b, float t, float near, flo
HMM_Mat4 HMM_Orthographic_GL(float l, float r, float b, float t, float near, float far) HMM_Mat4 HMM_Orthographic_GL(float l, float r, float b, float t, float near, float far)
{ {
// return HMM_MulM4(HMM_Orthographic_LH_NO(l,r,b,t,near,far), HMM_Scale((HMM_Vec3){1,-1,1}));
return HMM_Orthographic_LH_NO(l,r,b,t,near,far); return HMM_Orthographic_LH_NO(l,r,b,t,near,far);
} }
HMM_Mat4 HMM_Orthographic_Metal(float l, float r, float b, float t, float near, float far) HMM_Mat4 HMM_Orthographic_Metal(float l, float r, float b, float t, float near, float far)
{ {
HMM_Mat4 adjust = {0}; HMM_Mat4 adjust = {0};
@ -1774,6 +1772,7 @@ HMM_Mat4 HMM_QToM4(HMM_Quat Left) {
return Result; return Result;
} }
// this is right handed
HMM_Mat4 HMM_M4TRS(HMM_Vec3 t, HMM_Quat q, HMM_Vec3 s) HMM_Mat4 HMM_M4TRS(HMM_Vec3 t, HMM_Quat q, HMM_Vec3 s)
{ {
HMM_Mat4 l; HMM_Mat4 l;
@ -1802,7 +1801,6 @@ HMM_Mat4 HMM_M4TRS(HMM_Vec3 t, HMM_Quat q, HMM_Vec3 s)
return l; return l;
} }
// This method taken from Mike Day at Insomniac Games. // This method taken from Mike Day at Insomniac Games.
// https://d3cw3dd2w32x2b.cloudfront.net/wp-content/uploads/2015/01/matrix-to-quat.pdf // https://d3cw3dd2w32x2b.cloudfront.net/wp-content/uploads/2015/01/matrix-to-quat.pdf
// //

View file

@ -7,6 +7,17 @@
#include "sokol/sokol_args.h" #include "sokol/sokol_args.h"
#include "sokol/sokol_gfx.h" #include "sokol/sokol_gfx.h"
#include "sokol/sokol_app.h" #include "sokol/sokol_app.h"
#include "sokol/util/sokol_gl.h"
#define LAY_FLOAT 1
#define LAY_IMPLEMENTATION
#include "layout.h"
#define STB_PERLIN_IMPLEMENTATION
#include "stb_perlin.h"
#define STB_RECT_PACK_IMPLEMENTATION
#include "stb_rect_pack.h"
#define MSF_GIF_IMPL #define MSF_GIF_IMPL
#include "msf_gif.h" #include "msf_gif.h"

View file

@ -121,8 +121,8 @@ struct sFont *MakeFont(const char *fontfile, int height) {
struct rect r; struct rect r;
r.x = (glyph.x0) / (float)packsize; r.x = (glyph.x0) / (float)packsize;
r.w = (glyph.x1-glyph.x0) / (float)packsize; r.w = (glyph.x1-glyph.x0) / (float)packsize;
r.y = (glyph.y0) / (float)packsize; r.y = (glyph.y1) / (float)packsize;
r.h = (glyph.y1-glyph.y0) / (float)packsize; r.h = (glyph.y0-glyph.y1) / (float)packsize;
newfont->Characters[c].size = (HMM_Vec2){ newfont->Characters[c].size = (HMM_Vec2){
.x = glyph.x1-glyph.x0, .x = glyph.x1-glyph.x0,
@ -132,7 +132,7 @@ struct sFont *MakeFont(const char *fontfile, int height) {
newfont->Characters[c].Advance = glyph.xadvance; /* x distance from this char to the next */ newfont->Characters[c].Advance = glyph.xadvance; /* x distance from this char to the next */
newfont->Characters[c].leftbearing = glyph.xoff; newfont->Characters[c].leftbearing = glyph.xoff;
// printf("char %c: ascent %g, yoff %g, yoff2 %g\n", c, newfont->ascent, glyph.yoff, glyph.yoff2); // printf("char %c: ascent %g, yoff %g, yoff2 %g\n", c, newfont->ascent, glyph.yoff, glyph.yoff2);
newfont->Characters[c].topbearing = newfont->ascent + glyph.yoff; newfont->Characters[c].topbearing = -glyph.yoff2;//newfont->ascent - glyph.yoff;
newfont->Characters[c].rect = r; newfont->Characters[c].rect = r;
} }
@ -216,6 +216,7 @@ HMM_Vec2 measure_text(const char *text, font *f, float size, float letterSpacing
float maxWidth = 0; // max width of any line float maxWidth = 0; // max width of any line
float lineWidth = 0; // current line width float lineWidth = 0; // current line width
float scale = size/f->height; float scale = size/f->height;
scale = 1;
float lineHeight = f->ascent - f->descent; float lineHeight = f->ascent - f->descent;
lineHeight *= scale; lineHeight *= scale;
letterSpacing *= scale; letterSpacing *= scale;
@ -244,6 +245,7 @@ void renderText(const char *text, HMM_Vec2 pos, font *f, float scale, struct rgb
HMM_Vec2 cursor = pos; HMM_Vec2 cursor = pos;
float lineHeight = f->ascent - f->descent; float lineHeight = f->ascent - f->descent;
float lineWidth = 0;
for (char *c = text; *c != 0; c++) { for (char *c = text; *c != 0; c++) {
if (*c == '\n') { if (*c == '\n') {
@ -294,7 +296,6 @@ void renderText(const char *text, HMM_Vec2 pos, font *f, float scale, struct rgb
if (*wordstart == '\e') if (*wordstart == '\e')
wordstart = esc_color(wordstart, &usecolor, color); wordstart = esc_color(wordstart, &usecolor, color);
//sdrawCharacter(f->Characters[*wordstart], HMM_AddV2(cursor, HMM_MulV2F((HMM_Vec2){1,-1},scale)), scale, (rgba){0,0,0,255});
sdrawCharacter(f->Characters[*wordstart], cursor, scale, usecolor); sdrawCharacter(f->Characters[*wordstart], cursor, scale, usecolor);
cursor.X += f->Characters[*wordstart].Advance * scale; cursor.X += f->Characters[*wordstart].Advance * scale;

View file

@ -5,6 +5,13 @@
#include "render.h" #include "render.h"
#include "HandmadeMath.h" #include "HandmadeMath.h"
typedef enum {
LEFT,
RIGHT,
CENTER,
JUSTIFY
} ALIGN;
struct shader; struct shader;
struct window; struct window;

View file

@ -11,7 +11,6 @@
#include "datastream.h" #include "datastream.h"
#include "sound.h" #include "sound.h"
#include "stb_ds.h" #include "stb_ds.h"
#define STB_RECT_PACK_IMPLEMENTATION
#include "stb_rect_pack.h" #include "stb_rect_pack.h"
#include "string.h" #include "string.h"
#include "window.h" #include "window.h"
@ -34,7 +33,6 @@
#include "par/par_streamlines.h" #include "par/par_streamlines.h"
#include "par/par_shapes.h" #include "par/par_shapes.h"
#include "sokol_glue.h" #include "sokol_glue.h"
#define SOKOL_GL_IMPL
#include "sokol/util/sokol_gl.h" #include "sokol/util/sokol_gl.h"
#include <chipmunk/chipmunk_unsafe.h> #include <chipmunk/chipmunk_unsafe.h>
#include <chipmunk/chipmunk_structs.h> #include <chipmunk/chipmunk_structs.h>
@ -43,14 +41,12 @@
#include "timer.h" #include "timer.h"
#define LAY_FLOAT 1 #define LAY_FLOAT 1
#define LAY_IMPLEMENTATION
#include "layout.h" #include "layout.h"
#ifndef _WIN32 #ifndef _WIN32
#include <sys/resource.h> #include <sys/resource.h>
#endif #endif
#define STB_PERLIN_IMPLEMENTATION
#include "stb_perlin.h" #include "stb_perlin.h"
#if (defined(_WIN32) || defined(__WIN32__)) #if (defined(_WIN32) || defined(__WIN32__))
@ -58,8 +54,26 @@
#define mkdir(x,y) _mkdir(x) #define mkdir(x,y) _mkdir(x)
#endif #endif
static JSValue globalThis; struct lrtb {
float l;
float r;
float t;
float b;
};
typedef struct lrtb lrtb;
lrtb js2lrtb(JSValue v)
{
lrtb ret = {0};
ret.l = js2number(js_getpropstr(v,"l"));
ret.b = js2number(js_getpropstr(v,"b"));
ret.t = js2number(js_getpropstr(v,"t"));
ret.r = js2number(js_getpropstr(v,"r"));
return ret;
}
static JSValue globalThis;
JSValue str2js(const char *c, ...) { JSValue str2js(const char *c, ...) {
if (!c) return JS_UNDEFINED; if (!c) return JS_UNDEFINED;
char *result = NULL; char *result = NULL;
@ -600,6 +614,12 @@ struct rect js2rect(JSValue v) {
rect.y = js2number(js_getpropstr(v, "y")); rect.y = js2number(js_getpropstr(v, "y"));
rect.w = js2number(js_getpropstr(v, "width")); rect.w = js2number(js_getpropstr(v, "width"));
rect.h = js2number(js_getpropstr(v, "height")); rect.h = js2number(js_getpropstr(v, "height"));
float anchor_x = js2number(js_getpropstr(v, "anchor_x"));
float anchor_y = js2number(js_getpropstr(v, "anchor_y"));
rect.y -= anchor_y*rect.h;
rect.x -= anchor_x*rect.w;
return rect; return rect;
} }
@ -781,7 +801,8 @@ JSC_CCALL(render_glue_pass,
// Set the portion of the window to be rendered to // Set the portion of the window to be rendered to
JSC_CCALL(render_viewport, JSC_CCALL(render_viewport,
sg_apply_viewportf(js2number(argv[0]), js2number(argv[1]), js2number(argv[2]), js2number(argv[3]), 0); rect view = js2rect(argv[0]);
sg_apply_viewportf(view.x, view.y,view.w,view.h, js2boolean(argv[1]));
) )
JSC_CCALL(render_commit, sg_commit()) JSC_CCALL(render_commit, sg_commit())
@ -790,33 +811,9 @@ JSC_CCALL(render_end_pass, sg_end_pass())
HMM_Mat4 transform2view(transform *t) HMM_Mat4 transform2view(transform *t)
{ {
HMM_Vec3 look = HMM_AddV3(t->pos, transform_direction(t, vFWD)); HMM_Vec3 look = HMM_AddV3(t->pos, transform_direction(t, vFWD));
return HMM_LookAt_LH(t->pos, look, vUP); HMM_Mat4 ret = HMM_LookAt_RH(t->pos, look, vUP);
} ret = HMM_MulM4(ret, HMM_Scale(t->scale));
return ret;
HMM_Mat4 camera2projection(JSValue cam) {
int ortho = js2boolean(js_getpropstr(cam, "ortho"));
float near = js2number(js_getpropstr(cam, "near"));
float far = js2number(js_getpropstr(cam, "far"));
float fov = js2number(js_getpropstr(cam, "fov"))*HMM_DegToRad;
HMM_Vec2 size = js2vec2(js_getpropstr(cam,"size"));
if (ortho)
#ifdef SOKOL_GLCORE
return HMM_Orthographic_GL(
#elifdef SOKOL_D3D11
return HMM_Orthographic_DX(
#else
return HMM_Orthographic_Metal(
#endif
-size.x/2,
size.x/2,
-size.y/2,
size.y/2,
near,
far
);
else
return HMM_Perspective_Metal(fov, size.x/size.y, near, far);
} }
JSC_CCALL(render_camera_screen2world, JSC_CCALL(render_camera_screen2world,
@ -826,8 +823,27 @@ JSC_CCALL(render_camera_screen2world,
return vec42js(HMM_MulM4V4(view, p)); return vec42js(HMM_MulM4V4(view, p));
) )
JSC_CCALL(render_set_projection, JSC_CCALL(render_set_projection_ortho,
globalview.p = camera2projection(argv[0]); lrtb extents = js2lrtb(argv[0]);
float near = js2number(argv[1]);
float far = js2number(argv[2]);
globalview.p = HMM_Orthographic_RH_NO(
extents.l,
extents.r,
extents.b,
extents.t,
near,
far
);
globalview.vp = HMM_MulM4(globalview.p, globalview.v);
)
JSC_CCALL(render_set_projection_perspective,
float fov = js2number(argv[0]);
float aspect = js2number(argv[1]);
float near = js2number(argv[2]);
float far = js2number(argv[3]);
globalview.p = HMM_Perspective_RH_NO(fov, aspect, near, far);
globalview.vp = HMM_MulM4(globalview.p, globalview.v); globalview.vp = HMM_MulM4(globalview.p, globalview.v);
) )
@ -836,13 +852,6 @@ JSC_CCALL(render_set_view,
globalview.vp = HMM_MulM4(globalview.p, globalview.v); globalview.vp = HMM_MulM4(globalview.p, globalview.v);
) )
JSC_CCALL(render_set_camera,
JSValue cam = argv[0];
globalview.p = camera2projection(argv[0]);
globalview.v = transform2view(js2transform(js_getpropstr(cam, "transform")));
globalview.vp = HMM_MulM4(globalview.p, globalview.v);
)
sg_shader_uniform_block_desc js2uniform_block(JSValue v) sg_shader_uniform_block_desc js2uniform_block(JSValue v)
{ {
sg_shader_uniform_block_desc desc = {0}; sg_shader_uniform_block_desc desc = {0};
@ -1250,13 +1259,6 @@ JSC_CCALL(render_spdraw,
) )
JSC_CCALL(render_setpipeline, sg_apply_pipeline(*js2sg_pipeline(argv[0]));) JSC_CCALL(render_setpipeline, sg_apply_pipeline(*js2sg_pipeline(argv[0]));)
JSC_CCALL(render_screencolor,
texture *t = calloc(sizeof(*t), 1);
t->id = screencolor;
return texture2js(&screencolor)
)
JSC_CCALL(render_imgui_new, gui_newframe(js2number(argv[0]),js2number(argv[1]),js2number(argv[2])); ) JSC_CCALL(render_imgui_new, gui_newframe(js2number(argv[0]),js2number(argv[1]),js2number(argv[2])); )
JSC_CCALL(render_imgui_end, gui_endframe()) JSC_CCALL(render_imgui_end, gui_endframe())
@ -1280,8 +1282,8 @@ static const JSCFunctionListEntry js_render_funcs[] = {
MIST_FUNC_DEF(render, commit, 0), MIST_FUNC_DEF(render, commit, 0),
MIST_FUNC_DEF(render, glue_pass, 0), MIST_FUNC_DEF(render, glue_pass, 0),
MIST_FUNC_DEF(render, text_size, 5), MIST_FUNC_DEF(render, text_size, 5),
MIST_FUNC_DEF(render, set_camera, 1), MIST_FUNC_DEF(render, set_projection_ortho, 3),
MIST_FUNC_DEF(render, set_projection, 1), MIST_FUNC_DEF(render, set_projection_perspective, 4),
MIST_FUNC_DEF(render, set_view, 1), MIST_FUNC_DEF(render, set_view, 1),
MIST_FUNC_DEF(render, make_pipeline, 1), MIST_FUNC_DEF(render, make_pipeline, 1),
MIST_FUNC_DEF(render, setuniv3, 2), MIST_FUNC_DEF(render, setuniv3, 2),
@ -1296,7 +1298,6 @@ static const JSCFunctionListEntry js_render_funcs[] = {
MIST_FUNC_DEF(render, setuniv2, 2), MIST_FUNC_DEF(render, setuniv2, 2),
MIST_FUNC_DEF(render, setuniv4, 2), MIST_FUNC_DEF(render, setuniv4, 2),
MIST_FUNC_DEF(render, setpipeline, 1), MIST_FUNC_DEF(render, setpipeline, 1),
MIST_FUNC_DEF(render, screencolor, 0),
MIST_FUNC_DEF(render, imgui_new, 3), MIST_FUNC_DEF(render, imgui_new, 3),
MIST_FUNC_DEF(render, imgui_end, 0), MIST_FUNC_DEF(render, imgui_end, 0),
MIST_FUNC_DEF(render, imgui_init, 0), MIST_FUNC_DEF(render, imgui_init, 0),
@ -2188,15 +2189,15 @@ JSC_CCALL(transform_move, transform_move(js2transform(self), js2vec3(argv[0]));
JSC_CCALL(transform_lookat, JSC_CCALL(transform_lookat,
HMM_Vec3 point = js2vec3(argv[0]); HMM_Vec3 point = js2vec3(argv[0]);
transform *go = js2transform(self); transform *go = js2transform(self);
HMM_Mat4 m = HMM_LookAt_LH(go->pos, point, vUP); HMM_Mat4 m = HMM_LookAt_RH(go->pos, point, vUP);
go->rotation = HMM_M4ToQ_LH(m); go->rotation = HMM_M4ToQ_RH(m);
go->dirty = true; go->dirty = true;
) )
JSC_CCALL(transform_rotate, JSC_CCALL(transform_rotate,
HMM_Vec3 axis = js2vec3(argv[0]); HMM_Vec3 axis = js2vec3(argv[0]);
transform *t = js2transform(self); transform *t = js2transform(self);
HMM_Quat rot = HMM_QFromAxisAngle_LH(axis, js2angle(argv[1])); HMM_Quat rot = HMM_QFromAxisAngle_RH(axis, js2angle(argv[1]));
t->rotation = HMM_MulQ(t->rotation,rot); t->rotation = HMM_MulQ(t->rotation,rot);
t->dirty = true; t->dirty = true;
) )
@ -2221,7 +2222,7 @@ JSC_CCALL(transform_phys2d,
float av = js2number(argv[1]); float av = js2number(argv[1]);
float dt = js2number(argv[2]); float dt = js2number(argv[2]);
transform_move(t, (HMM_Vec3){v.x*dt,v.y*dt,0}); transform_move(t, (HMM_Vec3){v.x*dt,v.y*dt,0});
HMM_Quat rot = HMM_QFromAxisAngle_LH((HMM_Vec3){0,0,1}, av*dt); HMM_Quat rot = HMM_QFromAxisAngle_RH((HMM_Vec3){0,0,1}, av*dt);
t->rotation = HMM_MulQ(t->rotation, rot); t->rotation = HMM_MulQ(t->rotation, rot);
) )
@ -2837,10 +2838,14 @@ static const JSCFunctionListEntry js_timer_funcs[] = {
JSC_GETSET(font, linegap, number) JSC_GETSET(font, linegap, number)
JSC_GET(font, height, number) JSC_GET(font, height, number)
JSC_GET(font, ascent, number)
JSC_GET(font, descent, number)
static const JSCFunctionListEntry js_font_funcs[] = { static const JSCFunctionListEntry js_font_funcs[] = {
CGETSET_ADD(font, linegap), CGETSET_ADD(font, linegap),
MIST_GET(font, height), MIST_GET(font, height),
MIST_GET(font, ascent),
MIST_GET(font, descent)
}; };
const char *STRTEST = "TEST STRING"; const char *STRTEST = "TEST STRING";
@ -2903,7 +2908,7 @@ JSC_CCALL(geometry_rect_random,
JSC_CCALL(geometry_rect_point_inside, JSC_CCALL(geometry_rect_point_inside,
rect a = js2rect(argv[0]); rect a = js2rect(argv[0]);
HMM_Vec2 p = js2vec2(argv[1]); HMM_Vec2 p = js2vec2(argv[1]);
return boolean2js(p.x >= a.x && p.x <= a.x+a.w && p.y <= a.y+a.h && p.y >= a.y-a.h); return boolean2js(p.x >= a.x && p.x <= a.x+a.w && p.y <= a.y+a.h && p.y >= a.y);
) )
JSC_CCALL(geometry_cwh2rect, JSC_CCALL(geometry_cwh2rect,
@ -3712,25 +3717,6 @@ static const JSCFunctionListEntry js_os_funcs[] = {
static lay_context lay_ctx; static lay_context lay_ctx;
struct lrtb {
float l;
float r;
float t;
float b;
};
typedef struct lrtb lrtb;
lrtb js2lrtb(JSValue v)
{
lrtb ret = {0};
ret.l = js2number(js_getpropstr(v,"l"));
ret.b = js2number(js_getpropstr(v,"b"));
ret.t = js2number(js_getpropstr(v,"t"));
ret.r = js2number(js_getpropstr(v,"r"));
return ret;
}
JSC_CCALL(layout_item, JSC_CCALL(layout_item,
lay_id item = lay_item(&lay_ctx); lay_id item = lay_item(&lay_ctx);
HMM_Vec2 size = js2vec2(js_getpropstr(argv[0], "size")); HMM_Vec2 size = js2vec2(js_getpropstr(argv[0], "size"));

View file

@ -77,6 +77,7 @@ struct boundingbox {
float l; float l;
}; };
// rectangles are always defined with [x,y] in the bottom left
struct rect { struct rect {
float x,y,w,h; float x,y,w,h;
}; };

View file

@ -175,6 +175,8 @@ struct texture *texture_from_file(const char *path) {
struct texture *tex = calloc(1, sizeof(*tex)); struct texture *tex = calloc(1, sizeof(*tex));
stbi_set_flip_vertically_on_load(1);
int n; int n;
char *ext = strrchr(path, '.'); char *ext = strrchr(path, '.');

View file

@ -57,6 +57,11 @@ HMM_Vec3 mat3_t_dir(HMM_Mat4 m, HMM_Vec3 dir)
HMM_Mat4 transform2mat(transform *t) { HMM_Mat4 transform2mat(transform *t) {
return HMM_M4TRS(t->pos, t->rotation, t->scale); return HMM_M4TRS(t->pos, t->rotation, t->scale);
HMM_Mat4 scale = HMM_Scale(t->scale);
HMM_Mat4 rot = HMM_QToM4(t->rotation);
HMM_Mat4 pos = HMM_Translate(t->pos);
return HMM_MulM4(pos, HMM_MulM4(rot, scale));
if (t->dirty) { if (t->dirty) {
t->cache = HMM_M4TRS(t->pos, t->rotation, t->scale); t->cache = HMM_M4TRS(t->pos, t->rotation, t->scale);
@ -68,7 +73,7 @@ HMM_Mat4 transform2mat(transform *t) {
HMM_Quat angle2rotation(float angle) HMM_Quat angle2rotation(float angle)
{ {
return HMM_QFromAxisAngle_LH(vBKWD, angle); return HMM_QFromAxisAngle_RH(vBKWD, angle);
} }
transform mat2transform(HMM_Mat4 m) transform mat2transform(HMM_Mat4 m)
@ -79,6 +84,6 @@ transform mat2transform(HMM_Mat4 m)
t.scale.Elements[i] = HMM_LenV3(m.Columns[i].xyz); t.scale.Elements[i] = HMM_LenV3(m.Columns[i].xyz);
// for (int i = 0; i < 2; i++) // for (int i = 0; i < 2; i++)
// m.Columns[i].xyz = HMM_MulV3(m.Columns[i].xyz, t.scale.Elements[i]); // m.Columns[i].xyz = HMM_MulV3(m.Columns[i].xyz, t.scale.Elements[i]);
t.rotation = HMM_M4ToQ_LH(m); t.rotation = HMM_M4ToQ_RH(m);
return t; return t;
} }

View file

@ -115,7 +115,7 @@ void c_event(const sapp_event *e)
switch (e->type) { switch (e->type) {
case SAPP_EVENTTYPE_MOUSE_MOVE: case SAPP_EVENTTYPE_MOUSE_MOVE:
if (gui_wantmouse()) return; if (gui_wantmouse()) return;
script_evalf("prosperon.mousemove([%g, %g], [%g, %g]);", e->mouse_x, e->mouse_y, e->mouse_dx, -e->mouse_dy); script_evalf("prosperon.mousemove([%g, %g], [%g, %g]);", e->mouse_x, e->mouse_y, e->mouse_dx, e->mouse_dy);
break; break;
case SAPP_EVENTTYPE_MOUSE_SCROLL: case SAPP_EVENTTYPE_MOUSE_SCROLL: