From a142b6d1f4f1cfab9086a74fa69bf5a23d20345c Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Sat, 18 Jan 2025 18:15:15 -0600 Subject: [PATCH] actor cleanup --- scripts/actor.js | 11 ++- scripts/components.js | 89 ++++++++---------- scripts/entity.js | 33 +++---- scripts/input.js | 3 +- scripts/prosperon.js | 208 +++++++++++------------------------------- scripts/render.js | 2 + scripts/std.js | 2 - source/jsffi.c | 75 ++++++++------- source/qjs_macros.h | 4 + source/transform.c | 18 +++- source/transform.h | 3 + 11 files changed, 179 insertions(+), 269 deletions(-) diff --git a/scripts/actor.js b/scripts/actor.js index 87ec18d1..3117c733 100644 --- a/scripts/actor.js +++ b/scripts/actor.js @@ -11,7 +11,7 @@ var script_fn = function script_fn(file) { script = `(function use_${file.name()}() { var self = this; var $ = this.__proto__; ${script}; })`; var fn = os.eval(file,script); return fn; -}.hashify(); +} globalThis.actor_use = function actor_use(script) { @@ -38,20 +38,23 @@ globalThis.class_use = function class_use(script, config, base, callback) { if (!actor_urs[file]) { var newur = Object.create(base); actor_urs[file] = newur; + newur._file = file; + newur._root = file.dir(); actor_spawns[file] = []; + newur._script = script_fn(file) } var padawan = Object.create(actor_urs[file]); actor_spawns[file].push(padawan); - padawan._file = file; - padawan._root = file.dir(); if (callback) callback(padawan); - script_fn(file).call(padawan); + actor_urs[file]._script.call(padawan) if (typeof config === "object") Object.merge(padawan, config); + if (!actor_urs[file].__reggies) actor_urs[file].__reggies = pull_registers(padawan); + return padawan; }; diff --git a/scripts/components.js b/scripts/components.js index 5ad1ccda..eab57e78 100644 --- a/scripts/components.js +++ b/scripts/components.js @@ -21,7 +21,7 @@ frog = { } */ -globalThis.sprite_qt = os.make_rtree(); +if (!globalThis.sprite_qt) globalThis.sprite_qt = os.make_rtree(); //globalThis.sprite_qt = os.make_quadtree({x:-2000,y:2000,w:4000,h:4000}); var sprite = { @@ -35,10 +35,8 @@ var sprite = { anim_speed: 1, play(str, loop = true, reverse = false, fn) { if (!this.animset) { -// console.warn(`Sprite has no animset when trying to play ${str}`); fn?.(); return; -// return parseq.imm(); } if (typeof str === 'string') { @@ -94,12 +92,6 @@ var sprite = { stop = self.gameobject.delay(advance, playing.frames[f].time/self.anim_speed); advance(); }, - tex_sync() { - if (this.anim) this.stop(); - this.play(); - this.transform.scale = [this.image.texture.width, this.image.texture.height]; - this._sprite.set_image(this.image); - }, stop() { this.del_anim?.(); }, @@ -112,7 +104,8 @@ var sprite = { this._p = p; - this.del_anim?.(); + this.stop(); + if (image.texture) this.image = image; else if (image.frames) { @@ -120,6 +113,7 @@ var sprite = { this.anim = image; this.image = image.frames[0]; this.animset = [this.anim] + this.play(); } else { // Maybe an animset; try to grab the first one for (var anim in image) { @@ -127,12 +121,14 @@ var sprite = { this.anim = image[anim]; this.image = image[anim].frames[0]; this.animset = image; + this.play(); break; } } } - - this.tex_sync(); + + this.transform.scale = [this.image.texture.width, this.image.texture.height]; + this._sprite.set_image(this.image); }, get path() { return this._p; @@ -226,57 +222,44 @@ sprite.inputs.kp1 = function () { this.setanchor("ul"); }; +var changed_ts = []; + +function bulkupdate() +{ + for (var t of changed_ts) { + var sprite = t.sprite; + sprite_qt.remove(sprite); + sprite.rect = t.torect(); + sprite.set_affine(t) + sprite_qt.insert(sprite) + } + +// changed_ts.clear(); + changed_ts = []; +} + +Register.registries.prerender.register(bulkupdate) +function sprite_t_hook() +{ + changed_ts.push(this); +} + component.sprite = function (obj) { var sp = Object.create(sprite); - - var msp = os.make_sprite(); - sp._sprite = msp; - msp.color = Color.white; sp.gameobject = obj; sp.transform = os.make_transform(); sp.transform.parent = obj.transform; - sp.transform.change_hook = function() { - sprite_qt.remove(msp); - msp.rect = sp.transform.torect(); - msp.set_affine(sp.transform); - sprite_qt.insert(msp); + sp.transform.change_hook = sprite_t_hook; + + var msp = os.make_sprite(); + sp._sprite = msp; + msp.color = Color.white; + sp.transform.sprite = msp; // or msp -/* sprite_qt.remove(sp) - sp.rect = sp.transform.torect() - sprite_qt.insert(sp) -*/ - } return sp; }; -component.makesprite = function(obj = world, data) -{ - var sp = Object.create(sprite); - - var msp = os.make_sprite(); - sp._sprite = msp; - msp.color = Color.white; - - sp.gameobject = obj; - sp.transform = os.make_transform(); - sp.transform.parent = obj.transform; - sp.transform.change_hook = function() { - sprite_qt.remove(msp); - msp.rect = sp.transform.torect(); - msp.set_affine(sp.transform); - sprite_qt.insert(msp); - - /* sprite_qt.remove(sp) - sp.rect = sp.transform.torect() - sprite_qt.insert(sp) - */ - } - return sp; -} - -sprite.shade = [1, 1, 1, 1]; - return {component}; Object.mixin(os.make_seg2d(), { diff --git a/scripts/entity.js b/scripts/entity.js index 897a9757..ebce0cc1 100644 --- a/scripts/entity.js +++ b/scripts/entity.js @@ -56,11 +56,6 @@ var entity = { this.objects = {}; }, - sync() { - for (var c of Object.values(this.components)) c.sync?.(); - for (var o of Object.values(this.objects)) o.sync(); - }, - delay(fn, seconds) { prosperon.add_timer(this, fn, seconds); }, cry(file) { @@ -125,17 +120,17 @@ var entity = { spawn(text, config, callback) { var ent = class_use(text, config, entity, function (ent) { ent.transform = os.make_transform(); - ent.guid = prosperon.guid(); +// ent.guid = prosperon.guid(); ent.components = {}; ent.objects = {}; ent.timers = []; - ent.ur = {}; - ent.urname = text; +// ent.ur = {}; +// ent.urname = text; }); /* if (!text) ent.ur = emptyur; - else if (text instanceof Object) {// assume it's an ur + else if (typeof text === 'object') {// assume it's an ur ent.ur = text; text = ent.ur.text; config = [ent.ur.data, config].filter(x => x).flat(); @@ -179,24 +174,22 @@ var entity = { check_registers(ent); - if (ent.awake instanceof Function) ent.awake(); + if (typeof ent.awake === 'function') ent.awake(); if (sim.playing()) { ent._started = true; - if (ent.start instanceof Function) ent.start(); + if (typeof ent.start === 'function') ent.start(); } - ent._ed = { +/* ent._ed = { selectable: true, dirty: false, inst: false, urdiff: {}, }; - +*/ // Object.hide(ent, "ur", "components", "objects", "timers", "guid", "master", "guid", "_ed"); - ent.sync(); - - if (!Object.empty(ent.objects)) { +/* if (!Object.empty(ent.objects)) { var o = ent.objects; delete ent.objects; ent.objects = {}; @@ -208,7 +201,7 @@ var entity = { ent.rename_obj(n.toString(), i); } } - +*/ if (ent.tag) game.tag_add(ent.tag, ent); if (callback) callback(ent); @@ -360,7 +353,7 @@ var entity = { delete this.components; this.clear(); - if (this.stop instanceof Function) this.stop(); + if (typeof this.stop === 'function') this.stop(); if (typeof this.garbage === "function") this.garbage(); if (typeof this.then === "function") this.then(); @@ -368,8 +361,8 @@ var entity = { rmactor(this); - for (var i in this) - if (this[i] instanceof Object || this[i] instanceof Function) delete this[i]; +// for (var i in this) +// delete this[i] }, make_objs(objs) { diff --git a/scripts/input.js b/scripts/input.js index 308faeea..351760cd 100644 --- a/scripts/input.js +++ b/scripts/input.js @@ -326,7 +326,8 @@ var Player = { }, }; -input.do_uncontrol = function (pawn) { +input.do_uncontrol = function input_do_uncontrol(pawn) { + if (!pawn.inputs) return; Player.players.forEach(function (p) { p.pawns = p.pawns.filter(x => x !== pawn); }); diff --git a/scripts/prosperon.js b/scripts/prosperon.js index 6b509b46..5a7c1fc4 100644 --- a/scripts/prosperon.js +++ b/scripts/prosperon.js @@ -1,15 +1,39 @@ globalThis.gamestate = {}; -global.check_registers = function check_registers(obj) { +global.pull_registers = function(obj) +{ + var reggies = []; for (var reg in Register.registries) { if (!Register.registries[reg].register) return; - if (typeof obj[reg] === "function") { - var fn = obj[reg].bind(obj); - fn.layer = obj[reg].layer; - var name = obj.ur ? obj.ur.name : obj.toString(); - obj.timers.push(Register.registries[reg].register(fn, name)); - if (!obj[reg].name) Object.defineProperty(obj[reg], 'name', {value:`${obj._file}_${reg}`}); - } + if (typeof obj[reg] === "function") + reggies.push(reg); + } + return reggies; +} + +function register_obj(obj, reg) +{ + var fn = obj[reg].bind(obj); + fn.layer = obj[reg].layer; + var name = obj.ur ? obj.ur.name : obj.toString(); + obj.timers.push(Register.registries[reg].register(fn, name)); + if (!obj[reg].name) Object.defineProperty(obj[reg], 'name', {value:`${obj._file}_${reg}`}); +} + +global.check_registers = function check_registers(obj) { + if (obj.__reggies) { + if (obj.__reggies.length == 0) return; + // fast path + for (var reg of obj.__reggies) + register_obj(obj,reg); + + return; + } + + for (var reg in Register.registries) { + if (!Register.registries[reg].register) return; + if (typeof obj[reg] === "function") + register_obj(obj,reg); } /* for (var k in obj) { @@ -285,124 +309,12 @@ game.texture = function texture(path) { throw new Error('need a string for game.texture') } var parts = path.split(':'); - path = Resources.find_image(parts[0]); + var ipath = Resources.find_image(parts[0]); - game.texture.cache[path] ??= create_image(path); - return game.texture.cache[path]; + game.texture.cache[ipath] ??= create_image(ipath); + return game.texture.cache[ipath]; +} - // Look for a cached version - var frame; - var anim_str; - if (parts.length > 1) { - // it's an animation - parts = parts[1].split('_'); // For a gif, it might be 'water.gif:3', but for an ase it might be 'water.ase:run_3', meaning the third frame of the 'run' animation - if (parts.length === 1) - frame = Number(parts[0]); - else { - anim_str = parts[0]; - frame = Number(parts[1]); - } - } else - parts = undefined; - - var ret; - if (ret = game.texture.cache[path]) { - if (ret.texture) return ret; - if (!parts) return ret; - - return ret[anim_str].frames[frame]; - } - - if (!path) return game.texture("no_tex.gif"); - - if (!io.exists(path)) { - console.error(`Missing texture: ${path}`); - game.texture.cache[path] = game.texture("core/icons/no_tex.gif"); - game.texture.time_cache[path] = io.mod(path); - return game.texture.cache[path]; - } - - // Cache not found; add to the spritesheet - - var ext = path.ext(); - - if (ext === 'ase' || ext === 'aseprite') { - anim = os.make_aseprite(io.slurpbytes(path)); - - if (!anim) return; - if (anim.texture) { - // it was a single image - anim.texture.load_gpu(); - game.texture.cache[path] = anim; - anim.size = calc_image_size(anim); - return anim; - } - // load all into gpu - for (var a in anim) - for (let frame of anim[a].frames) { - frame.texture.load_gpu(); - frame.size = calc_image_size(img); - } - - game.texture.cache[path] = anim; - ret = game.texture.cache[path]; - if (!parts) return ret; - return ret[anim_str].frames[frame]; - } - - if (ext === 'gif') { - anim = os.make_gif(io.slurpbytes(path)); - if (!anim) return; - if (anim.frames.length === 1) { - // in this case, it's just a single image - anim.texture = anim.frames[0].texture; - anim.rect = anim.frames[0].rect; - anim.frames = undefined; - anim.texture.load_gpu(); - anim.size = calc_image_size(anim); - game.texture.cache[path] = anim; - return anim; - } - game.texture.cache[path] = anim; - anim.frames[0].size = calc_image_size(anim.frames[0]); - anim.frames[0].texture.load_gpu(); - return anim; - } - - var tex = os.make_texture(io.slurpbytes(path)); - if (!tex) throw new Error(`Could not make texture from ${path}`); - tex.path = path; - var image; - var anim; - - if (!anim) { - image = { - texture: tex, - rect:{x:0,y:0,width:1,height:1} - }; - pack_into_sheet([image]); - } else if (Object.keys(anim).length === 1) { - image = Object.values(anim)[0]; - image.frames.forEach(x => x.texture = tex); - pack_into_sheet(image.frames); - } else { - var allframes = []; - for (var a in anim) - allframes = allframes.concat(anim[a].frames); - - for (var frame of allframes) frame.texture = tex; - pack_into_sheet(allframes); - image = anim; - } - - game.texture.cache[path] = image; - game.texture.time_cache[path] = io.mod(path); - - image.size = calc_image_size(image); - tex.load_gpu(); - - return game.texture.cache[path]; -}; game.texture.cache = {}; game.texture.time_cache = {}; @@ -476,10 +388,10 @@ global.mixin("geometry"); Factory for creating registries. Register one with 'X.register', which returns a function that, when invoked, cancels the registry. */ -var Register = { +globalThis.Register = { registries: [], - add_cb(name, e_event = false, flush = undefined) { + add_cb(name) { var n = {}; var fns = []; @@ -514,23 +426,11 @@ var Register = { }; }; - if (!flush) { - prosperon[name] = function (...args) { -// tracy.fiber_enter(vector.fib); - fns.forEach(fn => fn(...args)); -// tracy.fiber_leave(vector.fib); - }; - } else - prosperon[name] = function (...args) { - var layer = undefined; - for (var fn of fns) { - if (layer !== fn.layer) { - flush(); - layer = fn.layer; - } - fn(); - } - }; + prosperon[name] = function (...args) { +// tracy.fiber_enter(vector.fib); + fns.forEach(fn => fn(...args)); +// tracy.fiber_leave(vector.fib); + }; Object.defineProperty(prosperon[name], 'name', {value:name}); prosperon[name].fns = fns; @@ -545,14 +445,17 @@ var Register = { }, }; -Register.add_cb("appupdate", true); -Register.add_cb("update", true).doc = "Called once per frame."; -Register.add_cb("physupdate", true); -Register.add_cb("gui", true); -Register.add_cb("hud", true, render.flush); -Register.add_cb("draw", true, render.flush); -Register.add_cb("imgui", true, render.flush); -Register.add_cb("app", true, render.flush); +Register.add_cb("appupdate"); +Register.add_cb("update").doc = "Called once per frame."; +Register.add_cb("physupdate"); +Register.add_cb("gui"); +Register.add_cb("hud"); +Register.add_cb("draw"); +Register.add_cb("imgui"); +Register.add_cb("app"); +Register.add_cb("prerender"); + +global.mixin("components"); var Event = { events: {}, @@ -609,7 +512,7 @@ prosperon.add_timer = function(obj, fn, seconds) } global.mixin("spline"); -global.mixin("components"); + global.mixin("actor"); global.mixin("entity"); @@ -651,7 +554,6 @@ function make_spritesheet(paths, width, height) } return { - Register, sim, frame_t, physlag, diff --git a/scripts/render.js b/scripts/render.js index f5a0ae96..2f70f8f0 100644 --- a/scripts/render.js +++ b/scripts/render.js @@ -675,6 +675,8 @@ prosperon.camera.screen2world = function(pos) var swaps = []; function gpupresent() { + os.clean_transforms(); + prosperon.prerender(); try{ var cmds = render._main.acquire_cmd_buffer(); render_queue = sprites_to_queue().concat(render_queue); diff --git a/scripts/std.js b/scripts/std.js index c180db4a..5a755478 100644 --- a/scripts/std.js +++ b/scripts/std.js @@ -3,8 +3,6 @@ os.env.doc = "Return the value of the environment variable v."; if (os.sys() === "windows") os.user = os.env("USERNAME"); else os.user = os.env("USER"); -console.log(os.user) - /*var ignore; if (ignore = io.slurp('.prosperonignore')) { ignore = ignore.split('\n'); diff --git a/source/jsffi.c b/source/jsffi.c index 94d6072c..08b547cc 100644 --- a/source/jsffi.c +++ b/source/jsffi.c @@ -53,6 +53,10 @@ typedef struct rtree rtree; static JSAtom width_atom; static JSAtom height_atom; +static JSAtom l_atom; +static JSAtom r_atom; +static JSAtom t_atom; +static JSAtom b_atom; static JSAtom x_atom; static JSAtom y_atom; static JSAtom anchor_x_atom; @@ -239,25 +243,15 @@ double js_getnum(JSContext *js, JSValue v, JSAtom prop) return ret; } -#define JS_PULLPROPSTR(JS,VALUE,STR, TYPE) { \ -JSValue __v = JS_GetPropertyStr(JS,VALUE,#STR); \ -STR = js2##TYPE(JS, __v); \ -JS_FreeValue(JS, __v); } - -#define JS_GETPROPSTR(JS, VALUE, TARGET, STR, TYPE) {\ -JSValue STR##__v = JS_GetPropertyStr(JS,VALUE,#STR); \ -TARGET.STR = js2##TYPE(JS, STR##__v); \ -JS_FreeValue(JS,STR##__v); }\ - #define JS_GETPROP(JS, TARGET, VALUE, PROP, TYPE) {\ -JSValue VALUE##__##PROP##__v = JS_GetPropertyStr(JS,VALUE,#PROP); \ -TARGET = js2##TYPE(JS, VALUE##__##PROP##__v); \ -JS_FreeValue(JS,VALUE##__##PROP##__v); }\ +JSValue __##PROP##__v = JS_GetPropertyStr(JS,VALUE,#PROP); \ +TARGET = js2##TYPE(JS, __##PROP##__v); \ +JS_FreeValue(JS,__##PROP##__v); }\ #define JS_GETATOM(JS, TARGET, VALUE, ATOM, TYPE) {\ -JSValue VALUE##__##PROP##__v = JS_GetProperty(JS,VALUE,ATOM); \ -TARGET = js2##TYPE(JS, VALUE##__##PROP##__v); \ -JS_FreeValue(JS,VALUE##__##PROP##__v); }\ +JSValue __##PROP##__v = JS_GetProperty(JS,VALUE,ATOM); \ +TARGET = js2##TYPE(JS, __##PROP##__v); \ +JS_FreeValue(JS,__##PROP##__v); }\ int JS_GETBOOL(JSContext *js, JSValue v, const char *prop) { @@ -1031,10 +1025,10 @@ typedef struct lrtb lrtb; lrtb js2lrtb(JSContext *js, JSValue v) { lrtb ret = {0}; - JS_GETPROPSTR(js,v,ret,l,number) - JS_GETPROPSTR(js,v,ret,b,number) - JS_GETPROPSTR(js,v,ret,t,number) - JS_GETPROPSTR(js,v,ret,r,number) + JS_GETATOM(js,ret.l,v,l_atom,number) + JS_GETATOM(js,ret.r,v,r_atom,number) + JS_GETATOM(js,ret.b,v,b_atom,number) + JS_GETATOM(js,ret.t,v,t_atom,number) return ret; } @@ -1122,6 +1116,7 @@ static void js_transform_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark transform *t = JS_GetOpaque(val, js_transform_id); if (!t) return; // Mark the JSValue references stored in your struct + JS_MarkValue(rt, t->self, mark_func); JS_MarkValue(rt, t->change_hook, mark_func); JS_MarkValue(rt, t->jsparent, mark_func); // Mark the array elements @@ -1441,14 +1436,10 @@ JSValue vecarr2js(JSContext *js,HMM_Vec2 *points, int n) { rect js2rect(JSContext *js,JSValue v) { if (JS_IsUndefined(v)) return (rect){0,0,1,1}; rect rect; - rect.w = js_getnum(js,v,width_atom); - rect.h = js_getnum(js,v,height_atom); - JSValue xv = JS_GetProperty(js,v,x_atom); - rect.x = js2number(js,xv); - JS_FreeValue(js,xv); - JSValue yv = JS_GetProperty(js,v,y_atom); - rect.y = js2number(js,yv); - JS_FreeValue(js,yv); + JS_GETATOM(js,rect.x,v,x_atom,number) + JS_GETATOM(js,rect.y,v,y_atom,number) + JS_GETATOM(js,rect.w,v,width_atom,number) + JS_GETATOM(js,rect.h,v,height_atom,number) float anchor_x = js_getnum(js,v, anchor_x_atom); float anchor_y = js_getnum(js,v, anchor_y_atom); @@ -4131,6 +4122,8 @@ JSC_CCALL(gpu_make_sprite_queue, JS_GETATOM(js,sp.layer,sub,layer_atom,number) JS_GETATOM(js,sp.uv,sub,src_atom,rect) sp.image = JS_GetProperty(js,sub,image_atom); + + JS_GETATOM(js,sp.tex,sp.image,texture_atom,SDL_GPUTexture) arrput(sprites,sp); } JS_FreeValue(js, sub); @@ -4899,8 +4892,8 @@ JSC_CCALL(gpu_slice9, JSC_CCALL(gpu_tile, HMM_Vec2 size; JSValue jstex = argv[0]; - JS_GETPROP(js,size.x,jstex,width,number) - JS_GETPROP(js, size.y, jstex, height, number) + JS_GETATOM(js,size.x,jstex,width_atom,number) + JS_GETATOM(js, size.y, jstex, height_atom, number) rect src_pixels = js2rect(js, argv[1]); // 'src' as pixel dimensions rect dst = js2rect(js, argv[2]); // 'dst' as screen coords @@ -5095,7 +5088,7 @@ JSC_CCALL(cmd_render_pass, JSValue depthval = JS_GetPropertyStr(js, passObj, "depth_stencil"); if (!JS_IsUndefined(depthval)) { has_depth = 1; - JS_GETPROPSTR(js, depthval, depthtar, texture, SDL_GPUTexture) + JS_GETPROP(js, depthtar.texture, depthval, texture, SDL_GPUTexture) JS_GETPROP(js, depthtar.load_op, depthval, load, SDL_GPULoadOp) JS_GETPROP(js, depthtar.store_op, depthval, store, SDL_GPUStoreOp) JS_GETPROP(js, depthtar.stencil_load_op, depthval, stencil_load, SDL_GPULoadOp) @@ -6582,7 +6575,11 @@ JSC_CCALL(os_make_font, JS_SetPropertyStr(js, ret, "surface", SDL_Surface2js(js,f->surface)); ) -JSC_CCALL(os_make_transform, return transform2js(js,make_transform())) +JSC_CCALL(os_make_transform, + transform *t = make_transform(); + ret = transform2js(js,t); + t->self = JS_DupValue(js,ret); +) JSC_CCALL(os_make_sprite, return sprite2js(js,make_sprite())) JSC_SCALL(os_system, return number2js(js,system(str)); ) @@ -7248,9 +7245,14 @@ JSC_CCALL(os_on, on_exception = JS_DupValue(js,argv[1]); ) +JSC_CCALL(os_clean_transforms, + clean_all(); +) + static const JSCFunctionListEntry js_os_funcs[] = { MIST_FUNC_DEF(os, turbulence, 4), MIST_FUNC_DEF(os, model_buffer, 1), + MIST_FUNC_DEF(os, clean_transforms, 0), MIST_FUNC_DEF(os, fbm, 4), MIST_FUNC_DEF(os, ridge, 5), MIST_FUNC_DEF(os, perlin, 3), @@ -7365,8 +7367,10 @@ JSC_CCALL(rtree_insert, max[1] = r.y+r.h; JSValue *ins = malloc(sizeof(*ins)); *ins = JS_DupValue(js,v); - if (!rtree_insert(tree, min, max, ins)) + if (!rtree_insert(tree, min, max, ins)) { + JS_FreeValue(js,*ins); return JS_ThrowOutOfMemory(js); + } ) int rtree_cmp(const JSValue *a, const JSValue *b, JSContext *js) @@ -7708,6 +7712,11 @@ void ffi_load(JSContext *js) { parent_atom = JS_NewAtom(js,"parent"); rect_atom = JS_NewAtom(js,"rect"); + l_atom = JS_NewAtom(js,"l"); + r_atom = JS_NewAtom(js,"r"); + b_atom = JS_NewAtom(js,"b"); + t_atom = JS_NewAtom(js,"t"); + fill_event_atoms(js); global_js = js; diff --git a/source/qjs_macros.h b/source/qjs_macros.h index 33db6464..9d6697d7 100644 --- a/source/qjs_macros.h +++ b/source/qjs_macros.h @@ -85,6 +85,7 @@ JSValue js_##ID##_get_##ENTRY (JSContext *js, JSValue self) { \ static JSClassID js_##TYPE##_id;\ static void js_##TYPE##_finalizer(JSRuntime *rt, JSValue val){\ TYPE *n = JS_GetOpaque(val, js_##TYPE##_id);\ +TracyCFreeN(n, #TYPE); \ TYPE##_free(rt,n);}\ static JSClassDef js_##TYPE##_class = {\ #TYPE,\ @@ -98,12 +99,14 @@ JSValue TYPE##2js(JSContext *js, TYPE *n) { \ JSValue j = JS_NewObjectClass(js,js_##TYPE##_id);\ JS_SetOpaque(j,n);\ __VA_ARGS__ \ + TracyCAllocN(n, 1, #TYPE); \ return j; }\ \ #define QJSCLASSMARK(TYPE, ...)\ static void js_##TYPE##_finalizer(JSRuntime *rt, JSValue val){\ TYPE *n = JS_GetOpaque(val, js_##TYPE##_id);\ +TracyCFreeN(n, #TYPE); \ TYPE##_free(rt,n);}\ static JSClassDef js_##TYPE##_class = {\ #TYPE,\ @@ -118,6 +121,7 @@ JSValue TYPE##2js(JSContext *js, TYPE *n) { \ JSValue j = JS_NewObjectClass(js,js_##TYPE##_id);\ JS_SetOpaque(j,n);\ __VA_ARGS__ \ + TracyCAllocN(n, 1, #TYPE); \ return j; }\ \ diff --git a/source/transform.c b/source/transform.c index 9f581ef2..7b3943a7 100644 --- a/source/transform.c +++ b/source/transform.c @@ -2,9 +2,10 @@ #include #include #include "script.h" - #include "stb_ds.h" +static transform **dirties; + static transform model = { .pos = {0,0,0}, .scale = {1,1,1}, @@ -25,6 +26,7 @@ transform *make_transform() } void transform_free(JSRuntime *rt, transform *t) { + JS_FreeValueRT(rt,t->self); JS_FreeValueRT(rt,t->change_hook); JS_FreeValueRT(rt,t->jsparent); for (int i = 0; i < arrlen(t->jschildren); i++) @@ -33,6 +35,10 @@ void transform_free(JSRuntime *rt, transform *t) { arrfree(t->jschildren); arrfree(t->children); free(t); + + for (int i = arrlen(dirties)-1; i >= 0; i--) { + if (dirties[i] == t) arrdelswap(dirties, i); + } } void transform_clean(transform *t) @@ -51,11 +57,17 @@ void transform_clean(transform *t) } if (!JS_IsUndefined(t->change_hook)) { - JSValue ret = JS_Call(global_js, t->change_hook, JS_UNDEFINED, 0, NULL); + JSValue ret = JS_Call(global_js, t->change_hook, JS_DupValue(global_js,t->self), 0, NULL); JS_FreeValue(global_js,ret); } } +void clean_all() +{ + for (int i = 0; i < arrlen(dirties); i++) + transform_clean(dirties[i]); +} + void transform_move(transform *t, HMM_Vec3 v) { t->pos = HMM_AddV3(t->pos, v); @@ -124,7 +136,7 @@ rect transform2rect(transform *t) void transform_apply(transform *t) { t->dirty = 1; - transform_clean(t); + arrput(dirties,t); } HMM_Quat angle2rotation(float angle) diff --git a/source/transform.h b/source/transform.h index e6cb2506..6d5538e1 100644 --- a/source/transform.h +++ b/source/transform.h @@ -12,6 +12,7 @@ typedef struct transform { HMM_Mat4 cache; HMM_Mat4 gcache; int dirty; + JSValue self; struct transform *parent; JSValue jsparent; struct transform **children; @@ -19,6 +20,8 @@ typedef struct transform { JSValue change_hook; } transform; +void clean_all(); + transform *make_transform(); void transform_free(JSRuntime *rt,transform *t);