From 13c2a0ba0c61d278057f226813c1635d966f6907 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Thu, 22 May 2025 17:00:31 -0500 Subject: [PATCH] sprites, rtrees, and transforms made with constructor functions --- examples/chess/main.js | 9 ------- scripts/modules/ext/camera.js | 3 ++- scripts/modules/ext/emitter.js | 3 ++- scripts/modules/ext/sprite.js | 8 +++--- scripts/modules/graphics.js | 5 ---- scripts/modules/lcdsprite.js | 3 ++- scripts/modules/moth.js | 3 ++- scripts/modules/os.js | 3 --- scripts/modules/sdl_gpu.js | 5 ++-- source/jsffi.c | 22 ++------------- source/qjs_os.c | 12 --------- source/qjs_rtree.c | 2 +- source/qjs_sprite.c | 49 +++++++++++++++++++++++++++++++--- source/qjs_transform.c | 39 ++++++++++++++++++++++++--- tests/animation.js | 3 ++- tests/bunnymark.js | 3 ++- tests/camera.js | 5 ++-- tests/qr_drag.js | 3 ++- 18 files changed, 109 insertions(+), 71 deletions(-) diff --git a/examples/chess/main.js b/examples/chess/main.js index 3917b24f..1d62a2f1 100644 --- a/examples/chess/main.js +++ b/examples/chess/main.js @@ -1,14 +1,5 @@ /* main.js – runs the demo with your prototype-based grid */ -var rtree = use('rtree') - -var mytree = new rtree - -mytree.add() -mytree.kill() - -for (var i in mytree) console.log(i) - var moth = use('moth') var json = use('json') diff --git a/scripts/modules/ext/camera.js b/scripts/modules/ext/camera.js index dacd19ba..4a4a9f5c 100644 --- a/scripts/modules/ext/camera.js +++ b/scripts/modules/ext/camera.js @@ -1,6 +1,7 @@ var cam = {} var os = use('os') +var transform = use('transform') var basecam = {} basecam.draw_rect = function(size) @@ -88,7 +89,7 @@ function mode_rect(src,dst,mode = "stretch") cam.make = function() { var c = Object.create(basecam) - c.transform = os.make_transform() + c.transform = new transform c.transform.unit() c.zoom = 1 c.size = [640,360] diff --git a/scripts/modules/ext/emitter.js b/scripts/modules/ext/emitter.js index fce72009..44684f22 100644 --- a/scripts/modules/ext/emitter.js +++ b/scripts/modules/ext/emitter.js @@ -1,6 +1,7 @@ var Color = use('color') var os = use('os') var graphics = use('graphics') +var transform = use('transform') var ex = {} @@ -76,7 +77,7 @@ ex.spawn = function(t) } par = { - transform: os.make_transform(), + transform: new transform, life: this.life, time: 0, color: this.color, diff --git a/scripts/modules/ext/sprite.js b/scripts/modules/ext/sprite.js index 8280b0ee..5ade0f43 100644 --- a/scripts/modules/ext/sprite.js +++ b/scripts/modules/ext/sprite.js @@ -224,15 +224,15 @@ return sprite; --- var Color = use('color') -var os = use('os') -var graphics = use('graphics') +var transform = use('transform') +var sprite = use('sprite') -this.transform = os.make_transform(); +this.transform = new transform; if (this.overling.transform) this.transform.parent = this.overling.transform; this.transform.change_hook = $.t_hook; -var msp = graphics.make_sprite(); +var msp = new sprite this._sprite = msp; msp.color = Color.white; this.transform.sprite = this diff --git a/scripts/modules/graphics.js b/scripts/modules/graphics.js index 021401d3..9e224691 100644 --- a/scripts/modules/graphics.js +++ b/scripts/modules/graphics.js @@ -420,11 +420,6 @@ graphics.make_font[prosperon.DOC] = ` Load a font from TTF/OTF data at the given size. ` -graphics.make_sprite[prosperon.DOC] = ` -:return: A new sprite object, which typically has .rect, .color, .layer, .image, etc. -Create a new sprite object, storing default properties. -` - graphics.make_line_prim[prosperon.DOC] = ` :param points: An array of [x,y] points forming the line. :param thickness: The thickness (width) of the polyline. diff --git a/scripts/modules/lcdsprite.js b/scripts/modules/lcdsprite.js index bf0260b6..c0aa7083 100644 --- a/scripts/modules/lcdsprite.js +++ b/scripts/modules/lcdsprite.js @@ -3,6 +3,7 @@ var sprite = {} var graphics = use('graphics') var render = use('render') var draw2d = use('draw2d') +var sprite = use('sprite') var SPRITE = Symbol() /* raw C sprite */ var POS = Symbol() /* cached JS copies of simple data */ @@ -83,7 +84,7 @@ var def_sprite = Object.freeze({ sprite.create = function(image, info) { info.__proto__ = def_sprite var sp = Object.create(ursprite) - sp[SPRITE] = graphics.make_sprite(info) + sp[SPRITE] = new sprite(info) sp.image = graphics.texture(image) _sprites.push(sp) diff --git a/scripts/modules/moth.js b/scripts/modules/moth.js index 089b8deb..028b1e9a 100644 --- a/scripts/modules/moth.js +++ b/scripts/modules/moth.js @@ -7,6 +7,7 @@ var os = use('os'); var io = use('io'); var render = use('render'); var actor = use('actor'); +var transform = use('transform'); var gameConfig = {}; var gameDir = ""; @@ -35,7 +36,7 @@ function initialize() { // Set up default camera gameConfig.camera = gameConfig.camera || { size: [gameConfig.internal_resolution.width, gameConfig.internal_resolution.height], - transform: os.make_transform(), + transform: new transform, fov: 50, near_z: 0, far_z: 1000, diff --git a/scripts/modules/os.js b/scripts/modules/os.js index 56b23ba9..eea233ce 100644 --- a/scripts/modules/os.js +++ b/scripts/modules/os.js @@ -1,8 +1,5 @@ var os = this -os.make_transform[prosperon.DOC] = "Create a new transform object that can be used for 2D/3D positioning, scaling, and rotation." -os.clean_transforms[prosperon.DOC] = "Force an update on all transforms to remove dangling references or perform house-keeping." - os.platform[prosperon.DOC] = "Return a string with the underlying platform name, like 'Windows', 'Linux', or 'macOS'." os.arch[prosperon.DOC] = "Return the CPU architecture string for this system (e.g. 'x64', 'arm64')." os.totalmem[prosperon.DOC] = "Return the total system RAM in bytes." diff --git a/scripts/modules/sdl_gpu.js b/scripts/modules/sdl_gpu.js index f1c2e97f..77f078e1 100644 --- a/scripts/modules/sdl_gpu.js +++ b/scripts/modules/sdl_gpu.js @@ -6,6 +6,7 @@ var controller = use('controller') var tracy = use('tracy') var graphics = use('graphics') var imgui = use('imgui') +var transform = use('transform') var base_pipeline = { vertex: "sprite.vert", @@ -94,7 +95,7 @@ switch(os.platform()) { break } -var unit_transform = os.make_transform(); +var unit_transform = new transform; var cur = {}; cur.images = []; @@ -659,7 +660,7 @@ function mask(image, pos, scale, rotation = 0, ref = 1) { var pipe = stencil_writer(ref); render.use_shader('sprite.cg', pipe); - var t = os.make_transform(); + var t = new transform; t.trs(pos, undefined, scale); set_model(t); render.use_mat({ diff --git a/source/jsffi.c b/source/jsffi.c index 39c239dc..5d96ea35 100644 --- a/source/jsffi.c +++ b/source/jsffi.c @@ -2162,25 +2162,6 @@ JSC_CCALL(os_make_font, JS_SetPropertyStr(js, ret, "surface", SDL_Surface2js(js,f->surface)); ) -JSC_CCALL(os_make_transform, - transform *t = make_transform(); - ret = transform2js(js,t); -// t->self = JS_DupValue(js,ret); - t->self = ret; -) -JSC_CCALL(os_make_sprite, - /*sprite *sp = make_sprite(); - JS_GETATOM(js, sp->pos, argv[0], pos, vec2) - JS_GETATOM(js, sp->center, argv[0], center, vec2) - JS_GETATOM(js, sp->skew, argv[0], skew, vec2) - JS_GETATOM(js, sp->scale, argv[0], scale, vec2) - JS_GETATOM(js, sp->rotation, argv[0], rotation, angle) - JS_GETATOM(js, sp->layer, argv[0], layer, number) - JS_GETATOM(js, sp->color, argv[0], color, color) - sprite_apply(sp); - return sprite2js(js,sp);*/ -) - JSC_SCALL(os_system, ret = number2js(js,system(str)); ) JSValue make_color_buffer(JSContext *js, colorf c, int verts) @@ -2771,7 +2752,6 @@ static const JSCFunctionListEntry js_graphics_funcs[] = { MIST_FUNC_DEF(os, make_surface, 1), MIST_FUNC_DEF(os, make_cursor, 1), MIST_FUNC_DEF(os, make_font, 2), - MIST_FUNC_DEF(os, make_sprite, 1), MIST_FUNC_DEF(os, make_line_prim, 5), MIST_FUNC_DEF(graphics, hsl_to_rgb, 3), MIST_FUNC_DEF(graphics, save_png, 4), @@ -2897,6 +2877,8 @@ void ffi_load(JSContext *js) arrput(rt->module_registry, ((ModuleEntry){"sdl_audio", js_sdl_audio_use})); arrput(rt->module_registry, MISTLINE(console)); arrput(rt->module_registry, MISTLINE(rtree)); + arrput(rt->module_registry, MISTLINE(sprite)); + arrput(rt->module_registry, MISTLINE(transform)); #ifdef TRACY_ENABLE arrput(rt->module_registry, MISTLINE(tracy)); diff --git a/source/qjs_os.c b/source/qjs_os.c index c943435a..78bfff6c 100644 --- a/source/qjs_os.c +++ b/source/qjs_os.c @@ -113,16 +113,6 @@ JSC_CCALL(os_hostname, #endif ) -JSC_CCALL(os_make_transform, - transform *t = make_transform(); - ret = transform2js(js,t); -// t->self = JS_DupValue(js,ret); - t->self = ret; -) - -JSC_CCALL(os_clean_transforms, - clean_all(js); -) JSC_CCALL(os_arch, #if defined(__x86_64__) || defined(_M_X64) @@ -380,8 +370,6 @@ JSC_CCALL(os_destroy, ) static const JSCFunctionListEntry js_os_funcs[] = { - MIST_FUNC_DEF(os, make_transform, 0), - MIST_FUNC_DEF(os, clean_transforms, 0), MIST_FUNC_DEF(os, platform, 0), MIST_FUNC_DEF(os, arch, 0), diff --git a/source/qjs_rtree.c b/source/qjs_rtree.c index 0e7703ff..57471195 100644 --- a/source/qjs_rtree.c +++ b/source/qjs_rtree.c @@ -192,7 +192,7 @@ JSValue js_rtree_use(JSContext *js) { QJSCLASSPREP_FUNCS(rtree); // Create the constructor function - JSValue ctor = JS_NewCFunction2(js, js_rtree_constructor, "RTree", 0, JS_CFUNC_constructor, 0); + JSValue ctor = JS_NewCFunction2(js, js_rtree_constructor, "rtree", 0, JS_CFUNC_constructor, 0); // Set the prototype on the constructor JSValue proto = JS_GetClassProto(js, js_rtree_id); diff --git a/source/qjs_sprite.c b/source/qjs_sprite.c index 443d87b2..144ff24e 100644 --- a/source/qjs_sprite.c +++ b/source/qjs_sprite.c @@ -59,6 +59,49 @@ static const JSCFunctionListEntry js_sprite_funcs[] = { JS_CGETSET_DEF("rotation", js_sprite_get_rotation, js_sprite_set_rotation), }; -// Note: Like transform, sprite doesn't use MISTUSE because sprite is a C type created via os.make_sprite() -// The sprite functions are registered as methods on the sprite class prototype -// This would be handled in the main FFI loading where QJSCLASSPREP_FUNCS(sprite) is called \ No newline at end of file +// Constructor function for sprite +static JSValue js_sprite_constructor(JSContext *js, JSValueConst new_target, int argc, JSValueConst *argv) { + sprite *sp = make_sprite(); + if (!sp) return JS_ThrowOutOfMemory(js); + + // If an options object is provided, initialize the sprite with it + if (argc > 0 && JS_IsObject(argv[0])) { + JS_GETATOM(js, sp->pos, argv[0], pos, vec2) + JS_GETATOM(js, sp->center, argv[0], center, vec2) + JS_GETATOM(js, sp->skew, argv[0], skew, vec2) + JS_GETATOM(js, sp->scale, argv[0], scale, vec2) + JS_GETATOM(js, sp->rotation, argv[0], rotation, number) + JS_GETATOM(js, sp->layer, argv[0], layer, number) + JS_GETATOM(js, sp->color, argv[0], color, color) + + JSValue image = JS_GetProperty(js, argv[0], JS_NewAtom(js, "image")); + if (!JS_IsUndefined(image)) { + sp->image = image; // Transfer ownership, no need to dup + } + } + + // Default values if not provided + if (sp->scale.x == 0 && sp->scale.y == 0) { + sp->scale.x = 1; + sp->scale.y = 1; + } + if (sp->color.w == 0) sp->color.w = 1; // Default alpha to 1 + + sprite_apply(sp); + return sprite2js(js, sp); +} + +JSValue js_sprite_use(JSContext *js) { + // Register the sprite class + QJSCLASSPREP_FUNCS(sprite); + + // Create the constructor function + JSValue ctor = JS_NewCFunction2(js, js_sprite_constructor, "sprite", 1, JS_CFUNC_constructor, 0); + + // Set the prototype on the constructor + JSValue proto = JS_GetClassProto(js, js_sprite_id); + JS_SetConstructor(js, ctor, proto); + JS_FreeValue(js, proto); + + return ctor; +} \ No newline at end of file diff --git a/source/qjs_transform.c b/source/qjs_transform.c index 6b58a7f1..500a88cf 100644 --- a/source/qjs_transform.c +++ b/source/qjs_transform.c @@ -207,6 +207,39 @@ static const JSCFunctionListEntry js_transform_funcs[] = { MIST_FUNC_DEF(transform, children, 0), }; -// Note: Transform module doesn't use MISTUSE because transform is a C type that's created via os.make_transform() -// The transform functions are registered as methods on the transform class prototype -// This would be handled in the main FFI loading where QJSCLASSPREP_FUNCS(transform) is called +// Constructor function for transform +static JSValue js_transform_constructor(JSContext *js, JSValueConst new_target, int argc, JSValueConst *argv) { + transform *t = make_transform(); + if (!t) return JS_ThrowOutOfMemory(js); + + JSValue ret = transform2js(js, t); + t->self = ret; + + return ret; +} + +JSC_CCALL(transform_clean, + clean_all(js); +) + +static const JSCFunctionListEntry js_transform_ctor_funcs[] = { + MIST_FUNC_DEF(transform, clean, 0), +}; + +JSValue js_transform_use(JSContext *js) { + // Register the transform class + QJSCLASSPREP_FUNCS(transform); + + // Create the constructor function + JSValue ctor = JS_NewCFunction2(js, js_transform_constructor, "transform", 0, JS_CFUNC_constructor, 0); + + // Set the prototype on the constructor + JSValue proto = JS_GetClassProto(js, js_transform_id); + JS_SetConstructor(js, ctor, proto); + JS_FreeValue(js, proto); + + // Add static methods to the constructor + JS_SetPropertyFunctionList(js, ctor, js_transform_ctor_funcs, countof(js_transform_ctor_funcs)); + + return ctor; +} diff --git a/tests/animation.js b/tests/animation.js index 6dec47a4..2e9f2776 100644 --- a/tests/animation.js +++ b/tests/animation.js @@ -45,10 +45,11 @@ render.initialize({width:500, height:500, resolution_x:500, resolution_y:500, var os = use('os'); var draw2d = use('draw2d'); var gfx = use('graphics'); +var transform = use('transform'); var camera = { size: [500,500], - transform: os.make_transform(), + transform: new transform, fov:50, near_z: 0, far_z: 1000, diff --git a/tests/bunnymark.js b/tests/bunnymark.js index 9c5d7ab0..b8e06b1f 100644 --- a/tests/bunnymark.js +++ b/tests/bunnymark.js @@ -1,6 +1,7 @@ // bunnymark var render = use('render') var os = use('os') +var transform = use('transform') var dim = [500,500] render.initialize({ width:dim.x, @@ -13,7 +14,7 @@ render.initialize({ var camera = { size: [500,500], - transform: os.make_transform(), + transform: new transform, fov:50, near_z: 0, far_z: 1000, diff --git a/tests/camera.js b/tests/camera.js index 8ac81749..e9cba186 100644 --- a/tests/camera.js +++ b/tests/camera.js @@ -1,5 +1,6 @@ var render = use('render') var os = use('os') +var transform = use('transform') render.initialize({ width:500, @@ -13,7 +14,7 @@ var draw = use('draw2d') var camera = { size: [500,500], - transform: os.make_transform(), + transform: new transform, fov:50, near_z: 0, far_z: 1000, @@ -25,7 +26,7 @@ var camera = { var hudcam = { size: [500,500], - transform: os.make_transform(), + transform: new transform, fov:50, near_z: 0, far_z: 1000, diff --git a/tests/qr_drag.js b/tests/qr_drag.js index f6baae06..e9d3e086 100644 --- a/tests/qr_drag.js +++ b/tests/qr_drag.js @@ -1,6 +1,7 @@ // bunnymark var render = use('render') var os = use('os') +var transform = use('transform') var dim = [500,500] render.initialize({ width:dim.x, @@ -13,7 +14,7 @@ render.initialize({ var camera = { size: [500,500], - transform: os.make_transform(), + transform: new transform, fov:50, near_z: 0, far_z: 1000,