actor cleanup

This commit is contained in:
2025-01-18 18:15:15 -06:00
parent aa38fd2c19
commit a142b6d1f4
11 changed files with 179 additions and 269 deletions

View File

@@ -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;
};

View File

@@ -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(), {

View File

@@ -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) {

View File

@@ -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);
});

View File

@@ -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,

View File

@@ -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);

View File

@@ -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');

View File

@@ -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;

View File

@@ -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; }\
\

View File

@@ -2,9 +2,10 @@
#include <string.h>
#include <stdio.h>
#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)

View File

@@ -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);