Mum gui init

This commit is contained in:
John Alanbrook 2023-10-04 13:18:09 +00:00
parent 2b402d7a2d
commit e02054bd10
13 changed files with 228 additions and 197 deletions

View file

@ -94,7 +94,7 @@
/* dump the occurence of the automatic GC */
#define DUMP_GC
/* dump objects freed by the garbage collector */
#define DUMP_GC_FREE
//#define DUMP_GC_FREE
/* dump objects leaking when freeing the runtime */
#define DUMP_LEAKS 1
/* dump memory usage before running the garbage collector */

View file

@ -828,6 +828,10 @@ function bb_from_objects(objs) {
return bb;
};
var Boundingbox = {};
Boundingbox.width = function(bb) { return bb.r - bb.l; };
Boundingbox.height = function(bb) { return bb.t - bb.b; };
Boundingbox.bl = function(bb) { return [bb.l, bb.b] };
/* VECTORS */
var Vector = {

View file

@ -87,7 +87,7 @@ var Debug = {
if (this.draw_bb)
Game.objects.forEach(function(x) { Debug.boundingbox(x.boundingbox(), Color.Debug.boundingbox.alpha(0.05)); });
if (Game.paused()) gui_text("PAUSED", [0,0],1);
if (Game.paused()) GUI.text("PAUSED", [0,0],1);
if (this.draw_gizmos)
Game.objects.forEach(function(x) {
@ -105,7 +105,7 @@ var Debug = {
gui_text(Time.seconds_to_timecode(Time.time - Debug.Options.gif.start_time, Debug.Options.gif.fps), [0,30], 1);
}
gui_text(Game.playing() ? "PLAYING"
GUI.text(Game.playing() ? "PLAYING"
: Game.stepping() ?
"STEP" :
Game.paused() ?

View file

@ -377,7 +377,6 @@ var editor = {
GUI.text("WORKING LAYER: " + this.working_layer, [0,520]);
GUI.text("MODE: " + this.edit_mode, [0,500]);
Debug.point(world2screen(this.cursor), 2, Color.green);
if (this.comp_info && this.sel_comp) {
@ -753,7 +752,7 @@ editor.inputs['C-M-p'] = function() {
editor.inputs['C-M-p'].doc = "Start game from currently edited level.";
editor.inputs['C-q'] = function() {
};
editor.inputs['C-q'].doc = "Quit simulation and return to editor.";
@ -1378,9 +1377,17 @@ var replpanel = Object.copy(inputpanel, {
title: "REPL",
closeonsubmit:false,
guibody() {
cmd(141);
var w = 700;
var h = 300;
var p = [50,50];
var log = cmd(84);
GUI.text(log, [400,60], 1, Color.white, 600, [0,0]);
GUI.text(this.value, [400,50], 1, Color.green, 600);
GUI.window(p, [w,h], Color.black.alpha(0.1));
GUI.scissor(p.x,p.y,w,h);
GUI.text(log, p.add([0,10]), 1, Color.white, w, [0,0]);
GUI.text(this.value, p, 1, Color.green, w);
cmd(141);
GUI.scissor(0,0,Window.width, Window.height);
},
action() {
@ -1565,6 +1572,8 @@ var openlevelpanel = Object.copy(inputpanel, {
assets: [],
allassets: [],
mumlist: {},
submit_check() {
if (this.assets.length === 0) return false;
@ -1575,25 +1584,24 @@ var openlevelpanel = Object.copy(inputpanel, {
start() {
this.allassets = prototypes.list.sort();
this.assets = this.allassets.slice();
this.mumlist = [];
this.assets.forEach(function(x) {
this.mumlist[x] = Mum.text({str:x});
}, this);
},
keycb() { this.assets = this.allassets.filter(x => x.search(this.value) !== -1); },
keycb() {
this.assets = this.allassets.filter(x => x.search(this.value) !== -1);
for (var m in this.mumlist)
this.mumlist[m].hide = true;
this.assets.forEach(function(x) {
this.mumlist[x].hide = false;
}, this);
},
guibody() {
GUI.text(this.value, [100,600], 1, Color.green, 600);
this.assets.forEach(function(x) {
if (Nuke.button(x)) {
this.value = x;
this.submit();
}
}, this);
Nuke.newline(2);
if (Nuke.button("submit")) {
this.submit();
}
Mum.column({items:Object.values(this.mumlist)}).draw([100,100]);
},
});

View file

@ -504,6 +504,13 @@ var Signal = {
},
};
var game_quit = function()
{
Primum.kill();
}
Signal.register("quit", game_quit);
var Window = {
set width(w) { cmd(125, w); },
set height(h) { cmd(126, h); },
@ -511,6 +518,14 @@ var Window = {
get height() { return cmd(49); },
get dimensions() { return [this.width, this.height]; },
set name(str) { cmd(134, str); },
boundingbox() {
return {
t: Window.height,
b: 0,
r: Window.width,
l: 0
};
},
};
Window.icon = function(path) { cmd(90, path); };

View file

@ -372,13 +372,13 @@ var gameobject = {
return;
}
Register.endofloop(() => {
// Register.endofloop(() => {
cmd(2, this.body);
delete Game.objects[this.body];
this.level.remove_obj(this);
if (this.level)
this.level.remove_obj(this);
Player.uncontrol(this);
this.instances.remove(this);
Register.unregister_obj(this);
this.body = -1;
@ -387,10 +387,12 @@ var gameobject = {
this.components[key].kill();
}
this.objects.forEach(x => x.kill());
for (var key in this.objects)
this.objects[key].kill();
if (typeof this.stop === 'function')
this.stop();
});
// });
},
remove_obj(obj) {

View file

@ -1,9 +1,10 @@
var GUI = {
text(str, pos, size, color, wrap, anchor) {
text(str, pos, size, color, wrap, anchor, frame) {
size ??= 1;
color ??= Color.white;
wrap ??= -1;
anchor ??= [0,1];
frame ??= Window.boundingbox();
var bb = cmd(118, str, size, wrap);
var w = bb.r*2;
@ -17,7 +18,7 @@ var GUI = {
p.y += h * (1 - anchor.y);
bb.t += h*(1-anchor.y);
bb.b += h*(1-anchor.y);
ui_text(str, p, size, color, wrap);
ui_text(str, p, size, color, wrap, bb);
return bb;
},
@ -26,145 +27,18 @@ var GUI = {
cursor_text(str,pos,size,Color.white,cursor);
},
scissor(x,y,w,h) {
cmd(140,x,y,w,h);
},
scissor_win() { cmd(140,0,0,Window.width,Window.height); },
image(path,pos) {
var wh = cmd(64,path);
gui_img(path,pos, [1.0,1.0], 0.0, 0.0, [0.0,0.0], 0.0, Color.black);
return cwh2bb([0,0], wh);
},
image_fn(defn) {
var def = Object.create(this.defaults);
Object.assign(def,defn);
if (!def.path) {
Log.warn("GUI image needs a path.");
def.draw = function(){};
return def;
}
var tex_wh = cmd(64,def.path);
var wh = tex_wh.slice();
if (def.width !== 0)
wh.x = def.width;
if (def.height !== 0)
wh.y = def.height;
wh = wh.scale(def.scale);
var sendscale = [];
sendscale.x = wh.x / tex_wh.x;
sendscale.y = wh.y / tex_wh.y;
def.draw = function(pos) {
def.calc_bb(pos);
gui_img(def.path, pos.sub(def.anchor.scale(wh)), sendscale, def.angle, def.image_repeat, def.image_repeat_offset, def.color);
};
def.calc_bb = function(cursor) {
def.bb = cwh2bb(wh.scale([0.5,0.5]), wh);
def.bb = movebb(def.bb, cursor.sub(wh.scale(def.anchor)));
};
return def;
},
defaults: {
padding:[2,2], /* Each element inset with this padding on all sides */
font: "fonts/LessPerfectDOSVGA.ttf",
font_size: 1,
text_align: "left",
scale: 1,
angle: 0,
anchor: [0,0],
text_shadow: {
pos: [0,0],
color: Color.white,
},
text_outline: 1, /* outline in pixels */
color: Color.white,
margin: [5,5], /* Distance between elements for things like columns */
width: 0,
height: 0,
image_repeat: false,
image_repeat_offset: [0,0],
debug: false, /* set to true to draw debug boxes */
},
text_fn(str, defn)
{
var def = Object.create(this.defaults);
Object.assign(def,defn);
def.draw = function(cursor) {
def.calc_bb(cursor);
if (def.debug)
Debug.boundingbox(def.bb, def.debug_colors.bounds);
var old = def;
def = Object.create(def);
/* if (pointinbb(def.bb, Mouse.screenpos)) {
Object.assign(def, def.hovered);
def.calc_bb(cursor);
GUI.selected = def;
def.selected = true;
}
*/
if (def.selected) {
Object.assign(def, def.hovered);
def.calc_bb(cursor);
}
var pos = cursor.sub(bb2wh(def.bb).scale(def.anchor));
ui_text(str, pos, def.font_size, def.color, def.width);
def = old;
};
def.calc_bb = function(cursor) {
var bb = cmd(118, str, def.font_size, def.width);
var wh = bb2wh(bb);
var pos = cursor.sub(wh.scale(def.anchor));
def.bb = movebb(bb,pos);
};
return def;
},
column(defn) {
var def = Object.create(this.defaults);
Object.assign(def,defn);
if (!def.items) {
Log.warn("Columns needs items.");
def.draw = function(){};
return def;
};
def.items.forEach(function(item,idx) {
def.items[idx].__proto__ = def;
if (def.items[idx-1])
def.up = def.items[idx-1];
if (def.items[idx+1])
def.down = def.items[idx+1];
});
def.draw = function(pos) {
def.items.forEach(function(item) {
item.draw.call(this,pos);
var wh = bb2wh(item.bb);
pos.y -= wh.y;
pos.y -= def.padding.x*2;
});
};
return def;
},
input_lmouse_pressed() {
if (GUI.selected)
GUI.selected.action();
@ -193,14 +67,119 @@ var GUI = {
}
};
GUI.defaults.debug_colors = {
var Mum = {
padding:[2,2], /* Each element inset with this padding on all sides */
font: "fonts/LessPerfectDOSVGA.ttf",
font_size: 1,
text_align: "left",
scale: 1,
angle: 0,
anchor: [0,0],
text_shadow: {
pos: [0,0],
color: Color.white,
},
text_outline: 1, /* outline in pixels */
color: Color.white,
margin: [5,5], /* Distance between elements for things like columns */
width: 0,
height: 0,
image_repeat: false,
image_repeat_offset: [0,0],
debug: false, /* set to true to draw debug boxes */
make(def) {
var n = Object.create(this);
Object.assign(n, def);
return n;
},
extend(def) {
var n = Object.create(this);
Object.assign(n, def);
return function(def) { var p = n.make(def); p.start(); return p; };
},
}
Mum.text = Mum.extend({
draw(cursor) {
if (this.hide) return;
this.calc_bb(cursor);
if (this.selected) {
Object.assign(this,this.hovered);
this.calc_bb(cursor);
}
var pos = cursor.sub(bb2wh(this.bb).scale(this.anchor));
ui_text(this.str, pos, this.font_size, this.color, this.width);
},
calc_bb(cursor) {
var bb = cmd(118,this.str, this.font_size, this.width);
var wh = bb2wh(bb);
var pos = cursor.sub(wh.scale(this.anchor));
this.bb = movebb(bb,pos);
},
});
Mum.image = Mum.extend({
start() {
if (!this.path) {
Log.warn("Mum image needs a path.");
this.draw = function(){};
return;
}
var tex_wh = cmd(64, this.path);
var wh = tex_wh.slice();
if (this.width !== 0) wh.x = this.width;
if (this.height !== 0) wh.y = this.height;
this.wh = wh.scale(this.scale);
this.sendscale = [wh.x/tex_wh.x, wh.y/tex_wh.y];
},
draw(pos) {
this.calc_bb(pos);
gui_img(this.path, pos.sub(this.anchor.scale([this.width, this.height])), this.sendscale, this.angle, this.image_repeat, this.image_repeat_offset, this.color);
},
calc_bb(pos) {
this.bb = cwh2bb(this.wh.scale([0.5,0.5]), wh);
this.bb = movebb(this.bb, pos.sub(this.wh.scale(this.anchor)));
}
});
Mum.column = Mum.extend({
draw(cursor) {
if (this.hide) return;
this.items.forEach(function(item) {
if (item.hide) return;
item.draw(cursor);
var wh = bb2wh(item.bb);
cursor.y -= wh.y*2;
cursor.y -= this.padding.y*2;
}, this);
},
});
GUI.window = function(pos, wh, color)
{
var p = pos.slice();
p.x += wh.x/2;
p.y += wh.y/2;
Debug.box(p,wh,color);
}
GUI.flush = function() { cmd(141); };
Mum.debug_colors = {
bounds: Color.red.slice(),
margin: Color.blue.slice(),
padding: Color.green.slice()
};
Object.values(GUI.defaults.debug_colors).forEach(function(v) { v.a = 100; });
Object.values(Mum.debug_colors).forEach(function(v) { v.a = 100; });
/* Take numbers from 0 to 1 and remap them to easing functions */
var Ease = {

View file

@ -187,6 +187,17 @@ struct rgba js2color(JSValue v) {
return color;
}
struct boundingbox js2bb(JSValue v)
{
struct boundingbox bb;
bb.t = js2number(js_getpropstr(v,"t"));
bb.b = js2number(js_getpropstr(v,"b"));
bb.r = js2number(js_getpropstr(v,"r"));
bb.l = js2number(js_getpropstr(v,"l"));
return bb;
}
HMM_Vec2 js2hmmv2(JSValue v)
{
HMM_Vec2 v2;
@ -264,16 +275,6 @@ JSValue vecarr2js(cpVect *points, int n) {
return array;
}
JSValue duk_gui_text(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) {
const char *s = JS_ToCString(js, argv[0]);
HMM_Vec2 pos = js2hmmv2(argv[1]);
float size = js2number(argv[2]);
renderText(s, pos, size, color_white, 500, -1, 1.0);
JS_FreeCString(js, s);
return JS_NULL;
}
JSValue duk_ui_text(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) {
const char *s = JS_ToCString(js, argv[0]);
HMM_Vec2 pos = js2hmmv2(argv[1]);
@ -281,7 +282,8 @@ JSValue duk_ui_text(JSContext *js, JSValueConst this, int argc, JSValueConst *ar
float size = js2number(argv[2]);
struct rgba c = js2color(argv[3]);
int wrap = js2int(argv[4]);
JSValue ret = JS_NewInt64(js, renderText(s, pos, size, c, wrap, -1, 1.0));
struct boundingbox bb = js2bb(argv[5]);
JSValue ret = JS_NewInt64(js, renderText(s, pos, size, c, wrap, -1, 1.0, bb));
JS_FreeCString(js, s);
return ret;
}
@ -294,7 +296,8 @@ JSValue duk_cursor_text(JSContext *js, JSValueConst this, int argc, JSValueConst
struct rgba c = js2color(argv[3]);
int wrap = js2int(argv[5]);
int cursor = js2int(argv[4]);
renderText(s, pos, size, c, wrap, cursor, 1.0);
struct boundingbox bb = js2bb(argv[6]);
renderText(s, pos, size, c, wrap, cursor, 1.0,bb);
JS_FreeCString(js, s);
return JS_NULL;
}
@ -335,6 +338,7 @@ JSValue bb2js(struct boundingbox bb)
return obj;
}
JSValue duk_spline_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) {
static_assert(sizeof(tsReal) * 2 == sizeof(cpVect));
@ -1064,6 +1068,14 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
str = JS_ToCString(js,argv[1]);
ret = JS_NewInt64(js, gif_nframes(str));
break;
case 140:
sg_apply_scissor_rectf(js2number(argv[1]), js2number(argv[2]), js2number(argv[3]), js2number(argv[4]), 0);
break;
case 141:
text_flush(&hudproj);
break;
}
if (str)
@ -1554,7 +1566,8 @@ JSValue duk_anim(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
for (double i = 0; i < 3.0; i = i + 0.1) {
YughInfo("Val is now %f at time %f", anim_val(a, i), i);
JSValue vv = num2js(anim_val(a, i));
JS_Call(js, prop, globalThis, 1, &vv);
JSValue e = JS_Call(js, prop, globalThis, 1, &vv);
JS_FreeValue(js,e);
JS_FreeValue(js,vv);
}
@ -1565,7 +1578,7 @@ JSValue duk_make_timer(JSContext *js, JSValueConst this, int argc, JSValueConst
double secs = js2number(argv[1]);
struct callee *c = malloc(sizeof(*c));
c->fn = JS_DupValue(js, argv[0]);
c->obj = JS_DupValue(js, globalThis);
c->obj = globalThis;
int id = timer_make(secs, call_callee, c, 1, js2bool(argv[2]));
return JS_NewInt64(js, id);
@ -1623,7 +1636,6 @@ void ffi_load() {
DUK_FUNC(register, 3)
DUK_FUNC(register_collide, 6)
DUK_FUNC(gui_text, 6)
DUK_FUNC(ui_text, 5)
DUK_FUNC(cursor_text, 5)
DUK_FUNC(gui_img, 10)
@ -1631,4 +1643,5 @@ void ffi_load() {
DUK_FUNC(inflate_cpv, 3)
DUK_FUNC(anim, 2)
JS_FreeValue(js,globalThis);
}

View file

@ -197,25 +197,25 @@ void draw_char_box(struct Character c, HMM_Vec2 cursor, float scale, struct rgba
void text_flush(HMM_Mat4 *proj) {
if (curchar == 0) return;
sg_apply_pipeline(pipe_text);
sg_apply_bindings(&bind_text);
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(*proj));
sg_range verts;
verts.ptr = text_buffer;
verts.size = sizeof(struct text_vert) * curchar;
sg_update_buffer(bind_text.vertex_buffers[0], &verts);
int offset = sg_append_buffer(bind_text.vertex_buffers[0], &verts);
bind_text.vertex_buffer_offsets[0] = offset;
sg_apply_pipeline(pipe_text);
sg_apply_bindings(&bind_text);
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(*proj));
sg_draw(0, 4, curchar);
curchar = 0;
}
static int drawcaret = 0;
void sdrawCharacter(struct Character c, HMM_Vec2 cursor, float scale, struct rgba color) {
void sdrawCharacter(struct Character c, HMM_Vec2 cursor, float scale, struct rgba color, struct boundingbox frame) {
if (curchar == max_chars)
return;
struct text_vert vert;
float lsize = 1.0 / 1024.0;
@ -226,6 +226,9 @@ void sdrawCharacter(struct Character c, HMM_Vec2 cursor, float scale, struct rgb
vert.pos.y = cursor.Y - c.Bearing[1] * scale - oline;
vert.wh.x = c.Size[0] * scale + (oline*2);
vert.wh.y = c.Size[1] * scale + (oline*2);
// if (vert.pos.x > frame.l || vert.pos.y > frame.t || (vert.pos.y + vert.wh.y) < frame.b || (vert.pos.x + vert.wh.x) < frame.l) return;
vert.uv.u = (c.rect.s0 - oline*lsize)*USHRT_MAX;
vert.uv.v = (c.rect.t0 - oline*lsize)*USHRT_MAX;
vert.st.u = (c.rect.s1-c.rect.s0+oline*lsize*2.0)*USHRT_MAX;
@ -280,7 +283,7 @@ struct boundingbox text_bb(const char *text, float scale, float lw, float tracki
}
/* pos given in screen coordinates */
int renderText(const char *text, HMM_Vec2 pos, float scale, struct rgba color, float lw, int caret, float tracking) {
int renderText(const char *text, HMM_Vec2 pos, float scale, struct rgba color, float lw, int caret, float tracking, struct boundingbox frame) {
int len = strlen(text);
drawcaret = caret;
@ -296,11 +299,11 @@ int renderText(const char *text, HMM_Vec2 pos, float scale, struct rgba color, f
draw_char_box(font->Characters[69], cursor, scale, color);
if (isblank(*line)) {
sdrawCharacter(font->Characters[*line], cursor, scale, usecolor);
sdrawCharacter(font->Characters[*line], cursor, scale, usecolor, frame);
cursor.X += font->Characters[*line].Advance * tracking * scale;
line++;
} else if (isspace(*line)) {
sdrawCharacter(font->Characters[*line], cursor, scale, usecolor);
sdrawCharacter(font->Characters[*line], cursor, scale, usecolor, frame);
cursor.Y -= scale * font->linegap;
cursor.X = pos.X;
line++;
@ -319,7 +322,7 @@ int renderText(const char *text, HMM_Vec2 pos, float scale, struct rgba color, f
}
while (wordstart < line) {
sdrawCharacter(font->Characters[*wordstart], cursor, scale, usecolor);
sdrawCharacter(font->Characters[*wordstart], cursor, scale, usecolor, frame);
cursor.X += font->Characters[*wordstart].Advance * tracking * scale;
wordstart++;
}

View file

@ -31,10 +31,10 @@ struct sFont {
void font_init();
struct sFont *MakeFont(const char *fontfile, int height);
void sdrawCharacter(struct Character c, HMM_Vec2 cursor, float scale, struct rgba color);
void sdrawCharacter(struct Character c, HMM_Vec2 cursor, float scale, struct rgba color, struct boundingbox frame);
void text_settype(struct sFont *font);
struct boundingbox text_bb(const char *text, float scale, float lw, float tracking);
int renderText(const char *text, HMM_Vec2 pos, float scale, struct rgba color, float lw, int caret, float tracking);
int renderText(const char *text, HMM_Vec2 pos, float scale, struct rgba color, float lw, int caret, float tracking, struct boundingbox frame);
// void text_frame();
void text_flush(HMM_Mat4 *proj);

View file

@ -198,6 +198,7 @@ void gameobject_clean(int id) {
/* Really more of a "mark for deletion" ... */
void gameobject_delete(int id) {
id2go(id)->next = first;
JS_FreeValue(js, id2go(id)->ref);
first = id;
if (cpSpaceIsLocked(space))

View file

@ -51,6 +51,7 @@ void script_startup() {
void script_stop()
{
send_signal("quit",0,NULL);
JS_RunGC(rt);
JS_FreeRuntime(rt);
}
@ -114,7 +115,8 @@ uint8_t *compile_script(const char *file, size_t *len) {
JSValue obj = JS_Eval(js, script, *len, file, JS_EVAL_FLAG_COMPILE_ONLY | JS_EVAL_TYPE_GLOBAL | JS_EVAL_FLAGS);
free(script);
size_t out_len;
uint8_t *out = JS_WriteObject(js, &out_len, obj, JS_WRITE_OBJ_BYTECODE);
uint8_t *out = JS_WriteObject(js, &out_len, obj, JS_WRITE_OBJ_BYTECODE);
JS_FreeValue(js,obj);
return out;
}
@ -157,6 +159,7 @@ time_t jso_file(const char *file)
JSValue obj = JS_ReadObject(js, byte, len, JS_READ_OBJ_BYTECODE);
JSValue ret = JS_EvalFunction(js, obj);
js_print_exception(ret);
JS_FreeValue(js,ret);
free(byte);
return file_mod_secs(file);
}
@ -169,7 +172,7 @@ JSValue script_runfile(const char *file)
JSValue obj = JS_Eval(js, script, len, file, JS_EVAL_FLAGS);
js_print_exception(obj);
free(script);
return obj;
}
@ -247,13 +250,15 @@ void send_signal(const char *signal, int argc, JSValue *argv)
{
JSValue globalThis = JS_GetGlobalObject(js);
JSValue sig = JS_GetPropertyStr(js, globalThis, "Signal");
JS_FreeValue(js, globalThis);
JSValue fn = JS_GetPropertyStr(js, sig, "call");
JSValue args[argc+1];
args[0] = str2js(signal);
for (int i = 0; i < argc; i++)
args[1+i] = argv[i];
JS_Call(js, fn, sig, argc+1, args);
JS_FreeValue(js,JS_Call(js, fn, sig, argc+1, args));
JS_FreeValue(js,sig);
}
static struct callee update_callee;

View file

@ -17,6 +17,7 @@ extern JSValue num_cache[100];
void js_stacktrace();
void script_startup();
void script_stop();
void script_run(const char *script, const char *file);
void script_evalf(const char *format, ...);
int script_dofile(const char *file);