diff --git a/qjs_sdl.c b/camera.c similarity index 97% rename from qjs_sdl.c rename to camera.c index 78947e5d..7a6463f7 100644 --- a/qjs_sdl.c +++ b/camera.c @@ -275,16 +275,10 @@ static const JSCFunctionListEntry js_SDL_Camera_funcs[] = MIST_FUNC_DEF(camera, get_format, 0), }; -JSValue js_camera_use(JSContext *js) { +CELL_USE_INIT( SDL_Init(SDL_INIT_CAMERA); JSValue mod = JS_NewObject(js); JS_SetPropertyFunctionList(js,mod,js_camera_funcs,countof(js_camera_funcs)); QJSCLASSPREP_FUNCS(SDL_Camera) return mod; -} - -JSValue js_sdl_use(JSContext *js) { - JSValue mod = JS_NewObject(js); - JS_SetPropertyStr(js, mod, "camera", js_camera_use(js)); - return mod; -} +) diff --git a/datastream.c b/datastream.c index 2cdbafa1..4d5605bc 100644 --- a/datastream.c +++ b/datastream.c @@ -105,8 +105,4 @@ static const JSCFunctionListEntry js_video_funcs[] = { MIST_FUNC_DEF(os, make_video, 1), }; -JSValue js_video_use(JSContext *js) { - JSValue mod = JS_NewObject(js); - JS_SetPropertyFunctionList(js,mod,js_video_funcs,countof(js_video_funcs)); - return mod; -} +CELL_USE_FUNCS(js_video_funcs) diff --git a/qjs_geometry.c b/geometry.c similarity index 99% rename from qjs_geometry.c rename to geometry.c index 9db106d0..5f60ef35 100644 --- a/qjs_geometry.c +++ b/geometry.c @@ -13,6 +13,7 @@ extern void *get_gpu_buffer(JSContext *js, JSValue argv, size_t *stride, size_t // GEOMETRY FUNCTIONS + JSC_CCALL(geometry_rect_intersection, rect a = js2rect(js,argv[0]); rect b = js2rect(js,argv[1]); @@ -1185,8 +1186,4 @@ static const JSCFunctionListEntry js_geometry_funcs[] = { MIST_FUNC_DEF(geometry, make_rect_quad, 3), }; -JSValue js_geometry_use(JSContext *js) { - JSValue mod = JS_NewObject(js); - JS_SetPropertyFunctionList(js,mod,js_geometry_funcs,countof(js_geometry_funcs)); - return mod; -} +CELL_USE_FUNCS(js_geometry_funcs) diff --git a/graphics.c b/graphics.c index b254bdc5..dd9f7638 100644 --- a/graphics.c +++ b/graphics.c @@ -280,8 +280,4 @@ const JSCFunctionListEntry js_graphics_funcs[] = { MIST_FUNC_DEF(graphics, hsl_to_rgb, 3), }; -JSValue js_graphics_use(JSContext *js) { - JSValue mod = JS_NewObject(js); - JS_SetPropertyFunctionList(js,mod,js_graphics_funcs,countof(js_graphics_funcs)); - return mod; -} \ No newline at end of file +CELL_USE_FUNCS(js_graphics_funcs) diff --git a/qjs_layout.c b/layout.c similarity index 99% rename from qjs_layout.c rename to layout.c index a0ca127b..ec114d72 100644 --- a/qjs_layout.c +++ b/layout.c @@ -1,4 +1,4 @@ -#include "quickjs.h" +#include "cell.h" #include #include @@ -188,8 +188,7 @@ static const JSCFunctionListEntry js_layout_funcs[] = { JS_CFUNC_DEF("make_context", 0, js_layout_context_new) }; -JSValue js_layout_use(JSContext *js) -{ +CELL_USE_INIT( JS_NewClassID(&js_layout_class_id); JS_NewClass(JS_GetRuntime(js), js_layout_class_id, &js_layout_class); @@ -229,4 +228,4 @@ JSValue js_layout_use(JSContext *js) JS_SetPropertyStr(js, export, "contain", contain); return export; -} +) diff --git a/qjs_math.c b/math.c similarity index 98% rename from qjs_math.c rename to math.c index 3c45b141..93e92d75 100644 --- a/qjs_math.c +++ b/math.c @@ -505,8 +505,4 @@ static const JSCFunctionListEntry js_math_funcs[] = { MIST_FUNC_DEF(math, from_to, 5), }; -JSValue js_math_use(JSContext *js) { - JSValue mod = JS_NewObject(js); - JS_SetPropertyFunctionList(js,mod,js_math_funcs,countof(js_math_funcs)); - return mod; -} +CELL_USE_FUNCS(js_math_funcs) diff --git a/prosperon.h b/prosperon.h index dd9ad24b..9c167237 100644 --- a/prosperon.h +++ b/prosperon.h @@ -31,7 +31,6 @@ SDL_Window *js2SDL_Window(JSContext *js, JSValue v); JSValue SDL_Window2js(JSContext *js, SDL_Window *w); void *get_gpu_buffer(JSContext *js, JSValue argv, size_t *stride, size_t *size); double js_getnum_str(JSContext *js, JSValue v, const char *str); -sprite *js2sprite(JSContext *js, JSValue v); HMM_Vec3 js2vec3(JSContext *js, JSValue v); JSValue vec32js(JSContext *js, HMM_Vec3 v); HMM_Vec4 js2vec4(JSContext *js, JSValue v); diff --git a/qjs_dmon.c.old b/qjs_dmon.c.old index cc5c8597..3b6e7db1 100644 --- a/qjs_dmon.c.old +++ b/qjs_dmon.c.old @@ -122,12 +122,11 @@ static const JSCFunctionListEntry js_dmon_funcs[] = { JS_CFUNC_DEF("poll", 1, js_dmon_poll) }; -JSValue js_dmon_use(JSContext *js) -{ +CELL_USE_INIT( JSValue export = JS_NewObject(js); JS_SetPropertyFunctionList(js, export, js_dmon_funcs, sizeof(js_dmon_funcs)/sizeof(JSCFunctionListEntry)); dmon_init(); return export; -} +) diff --git a/qjs_renderer.c.old b/qjs_renderer.c.old index 3bceba94..a5954490 100644 --- a/qjs_renderer.c.old +++ b/qjs_renderer.c.old @@ -505,8 +505,7 @@ static const JSCFunctionListEntry js_mod_funcs[] = { JS_CFUNC_DEF("create", 1, js_mod_create) }; -JSValue js_renderer_use(JSContext *ctx) { - // Create an object that will hold all the "renderer" methods +CELL_USE_INIT( JSValue obj = JS_NewObject(ctx); // Add all the above C functions as properties of that object @@ -514,4 +513,4 @@ JSValue js_renderer_use(JSContext *ctx) { js_renderer_funcs, sizeof(js_renderer_funcs)/sizeof(JSCFunctionListEntry)); return obj; -} +) diff --git a/qjs_sdl.h b/qjs_sdl.h index f8fc1ed8..b341bb5b 100644 --- a/qjs_sdl.h +++ b/qjs_sdl.h @@ -4,11 +4,6 @@ #include #include "cell.h" -JSValue js_input_use(JSContext *ctx); -JSValue js_camera_use(JSContext *ctx); -JSValue js_sdl_audio_use(JSContext *ctx); -JSValue js_sdl_use(JSContext *js); - SDL_PixelFormat str2pixelformat(const char *str); SDL_PixelFormat js2pixelformat(JSContext *js, JSValue v); JSValue pixelformat2js(JSContext *js, SDL_PixelFormat format); @@ -31,4 +26,4 @@ typedef struct SDL_Surface SDL_Surface; SDL_Surface *js2SDL_Surface(JSContext *js, JSValue v); JSValue SDL_Surface2js(JSContext *js, SDL_Surface *s); -#endif /* QJS_SDL_H */ +#endif diff --git a/qjs_sdl_gpu.h b/qjs_sdl_gpu.h deleted file mode 100644 index d5bc0bc6..00000000 --- a/qjs_sdl_gpu.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef QJS_SDL_GPU_H -#define QJS_SDL_GPU_H - -#include "cell.h" -#include "sprite.h" - -// Forward declarations for sprite sorting functions -int sort_sprite(const sprite *a, const sprite *b); -int sort_sprite_backtofront(const sprite *a, const sprite *b); -int sort_sprite_fronttoback(const sprite *a, const sprite *b); -int sort_sprite_texture(const sprite *a, const sprite *b); - -JSValue js_sdl_gpu_use(JSContext *js); - -#endif diff --git a/qjs_sdl_input.h b/qjs_sdl_input.h deleted file mode 100644 index 8eb369c1..00000000 --- a/qjs_sdl_input.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef QJS_SDL_INPUT_H -#define QJS_SDL_INPUT_H - -#include - -const char* event_type_to_string(uint32_t event_type); -const char* mouse_button_to_string(int mouse); - -// JavaScript module entry point -JSValue js_input_use(JSContext *js); - -#endif // QJS_SDL_INPUT_H \ No newline at end of file diff --git a/qjs_sdl_surface.h b/qjs_sdl_surface.h index 1ebe89dd..6961ba49 100644 --- a/qjs_sdl_surface.h +++ b/qjs_sdl_surface.h @@ -4,8 +4,6 @@ #include "cell.h" #include -JSValue js_sdl_surface_use(JSContext *js); - // Functions generated by QJSCLASS macro JSValue SDL_Surface2js(JSContext *js, SDL_Surface *s); SDL_Surface *js2SDL_Surface(JSContext *js, JSValue val); diff --git a/qjs_sprite.c b/qjs_sprite.c deleted file mode 100644 index bb0fc1cd..00000000 --- a/qjs_sprite.c +++ /dev/null @@ -1,107 +0,0 @@ -#include "qjs_sprite.h" -#include "prosperon.h" -#include "qjs_macros.h" - -#include "sprite.h" -#include "HandmadeMath.h" - -// Sprite class definitions -static JSClassID js_sprite_id; -static void js_sprite_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) { - sprite *sp = JS_GetOpaque(val, js_sprite_id); - if (!sp) return; - JS_MarkValue(rt, sp->image, mark_func); -} - -// Class definition for sprite with mark function for GC -QJSCLASSMARK(sprite,) - -// SPRITE GETTER/SETTER FUNCTIONS -JSC_GETSET(sprite, pos, vec2) -JSC_GETSET(sprite, center, vec2) -JSC_GETSET(sprite, layer, number) -JSC_GETSET(sprite, color, color) -JSC_GETSET(sprite, skew, vec2) -JSC_GETSET(sprite, scale, vec2) -JSC_GETSET(sprite, rotation, number) - -// SPRITE ACTION FUNCTIONS - -JSC_CCALL(sprite_move, - sprite *sp = js2sprite(js,self); - HMM_Vec2 mv = js2vec2(js,argv[0]); - sp->pos.x += mv.x; - sp->pos.y += mv.y; -) - -JSC_CCALL(sprite_set_affine, - sprite *sp = js2sprite(js,self); - sprite_apply(sp); -) - -JSC_CCALL(sprite_set_image, - sprite *sp = js2sprite(js,self); - if (!JS_IsNull(sp->image)) - JS_FreeValue(js,sp->image); - sp->image = JS_DupValue(js, argv[0]); -) - -static const JSCFunctionListEntry js_sprite_funcs[] = { - MIST_FUNC_DEF(sprite, set_affine, 0), - MIST_FUNC_DEF(sprite, set_image, 1), - MIST_FUNC_DEF(sprite, move, 1), - JS_CGETSET_DEF("pos", js_sprite_get_pos, js_sprite_set_pos), - JS_CGETSET_DEF("scale", js_sprite_get_scale, js_sprite_set_scale), - JS_CGETSET_DEF("skew", js_sprite_get_skew, js_sprite_set_skew), - JS_CGETSET_DEF("layer", js_sprite_get_layer, js_sprite_set_layer), - JS_CGETSET_DEF("color", js_sprite_get_color, js_sprite_set_color), - JS_CGETSET_DEF("center", js_sprite_get_center, js_sprite_set_center), - JS_CGETSET_DEF("rotation", js_sprite_get_rotation, js_sprite_set_rotation), -}; - -// 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_IsNull(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/qjs_sprite.h b/qjs_sprite.h deleted file mode 100644 index 783f7f30..00000000 --- a/qjs_sprite.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef QJS_SPRITE_H -#define QJS_SPRITE_H - -#include "cell.h" - -#include "sprite.h" - -JSValue js_sprite_use(JSContext *ctx); - -sprite *js2sprite(JSContext *js, JSValue v); - -#endif /* QJS_SPRITE_H */ diff --git a/qjs_transform.c b/qjs_transform.c deleted file mode 100644 index b251fce9..00000000 --- a/qjs_transform.c +++ /dev/null @@ -1,245 +0,0 @@ -#include "cell.h" -#include "prosperon.h" -#include "qjs_macros.h" -#include "stb_ds.h" - -#include "transform.h" -#include "HandmadeMath.h" - -// Transform class definitions -JSClassID js_transform_id; -static void js_transform_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) { - transform *t = JS_GetOpaque(val, js_transform_id); - if (!t) return; - // Mark the JSValue references stored in your struct - JS_MarkValue(rt, t->change_hook, mark_func); - JS_MarkValue(rt, t->jsparent, mark_func); - // Mark the array elements - for (int i = 0; i < arrlen(t->jschildren); i++) - JS_MarkValue(rt, t->jschildren[i], mark_func); -} - -QJSCLASSMARK_EXTERN(transform,) - -// TRANSFORM GETTER/SETTER FUNCTIONS -JSC_GETSET_APPLY(transform, pos, vec3) -JSC_GETSET_APPLY(transform, scale, vec3) -JSC_GETSET_APPLY(transform, rotation, quat) - -static JSValue js_transform_get_change_hook(JSContext *js, JSValueConst self) -{ - transform *t = js2transform(js,self); - return JS_DupValue(js,t->change_hook); -} - -static JSValue js_transform_set_change_hook(JSContext *js, JSValueConst self, JSValue v) -{ - transform *t = js2transform(js,self); - if (!JS_IsNull(v) && !JS_IsFunction(js,v)) return JS_ThrowReferenceError(js, "Hook must be a function."); - JS_FreeValue(js,t->change_hook); - t->change_hook = JS_DupValue(js,v); - return JS_NULL; -} - -static JSValue js_transform_get_parent(JSContext *js, JSValueConst self) -{ - transform *t = js2transform(js,self); - if (t->parent) return JS_DupValue(js,t->jsparent); - return JS_NULL; -} - -static JSValue js_transform_set_parent(JSContext *js, JSValueConst self, JSValue v) -{ - transform *p = js2transform(js,v); - if (!JS_IsNull(v) && !p) - return JS_ThrowReferenceError(js,"Parent must be another transform."); - - transform *t = js2transform(js,self); - - if (t == p) - return JS_ThrowReferenceError(js, "A transform cannot be its own parent."); - - if (t->parent) { - transform *cur_parent = t->parent; - JS_FreeValue(js,t->jsparent); - t->jsparent = JS_NULL; - - for (int i = 0; i < arrlen(cur_parent->children); i++) { - if (cur_parent->children[i] == t) { - arrdelswap(cur_parent->children,i); - break; - } - } - - for (int i = 0; i < arrlen(cur_parent->jschildren); i++) { - if (JS_SameValue(js,cur_parent->jschildren[i],self)) { - JS_FreeValue(js,cur_parent->jschildren[i]); - arrdelswap(cur_parent->jschildren,i); - break; - } - } - } - - t->parent = p; - t->jsparent = JS_DupValue(js,v); - - if (p) { - arrput(p->children, t); - JSValue child = JS_DupValue(js,self); - arrput(p->jschildren,child); - } - - transform_apply(t); - - return JS_NULL; -} - -// TRANSFORM ACTION FUNCTIONS - -JSC_CCALL(transform_move, - transform *t = js2transform(js,self); - transform_move(t, js2vec3(js,argv[0])); -) - -JSC_CCALL(transform_lookat, - HMM_Vec3 point = js2vec3(js,argv[0]); - transform *go = js2transform(js,self); - HMM_Mat4 m = HMM_LookAt_RH(go->pos, point, vUP); - go->rotation = HMM_M4ToQ_RH(m); - transform_apply(go); -) - -JSC_CCALL(transform_rotate, - HMM_Vec3 axis = js2vec3(js,argv[0]); - transform *t = js2transform(js,self); - HMM_Quat rot = HMM_QFromAxisAngle_RH(axis, js2angle(js,argv[1])); - t->rotation = HMM_MulQ(t->rotation,rot); - transform_apply(t); -) - -JSC_CCALL(transform_angle, - HMM_Vec3 axis = js2vec3(js,argv[0]); - transform *t = js2transform(js,self); - if (axis.x) return angle2js(js,HMM_Q_Roll(t->rotation)); - if (axis.y) return angle2js(js,HMM_Q_Pitch(t->rotation)); - if (axis.z) return angle2js(js,HMM_Q_Yaw(t->rotation)); - return angle2js(js,0); -) - -JSC_CCALL(transform_direction, - transform *t = js2transform(js,self); - return vec32js(js, HMM_QVRot(js2vec3(js,argv[0]), t->rotation)); -) - -JSC_CCALL(transform_phys2d, - transform *t = js2transform(js,self); - HMM_Vec2 v = js2vec2(js,argv[0]); - float av = js2number(js,argv[1]); - float dt = js2number(js,argv[2]); - transform_move(t, (HMM_Vec3){v.x*dt,v.y*dt,0}); - HMM_Quat rot = HMM_QFromAxisAngle_RH((HMM_Vec3){0,0,1}, av*dt); - t->rotation = HMM_MulQ(t->rotation, rot); - transform_apply(t); -) - -JSC_CCALL(transform_unit, - transform *t = js2transform(js,self); - t->pos = v3zero; - t->rotation = QUAT1; - t->scale = v3one; - transform_apply(t); -) - -JSC_CCALL(transform_trs, - transform *t = js2transform(js,self); - t->pos = JS_IsNull(argv[0]) ? v3zero : js2vec3(js,argv[0]); - t->rotation = JS_IsNull(argv[1]) ? QUAT1 : js2quat(js,argv[1]); - t->scale = JS_IsNull(argv[2]) ? v3one : js2vec3(js,argv[2]); - transform_apply(t); -) - -JSC_CCALL(transform_rect, - transform *t = js2transform(js,self); - rect r = js2rect(js,argv[0]); - t->pos = (HMM_Vec3){r.x,r.y,0}; - t->scale = (HMM_Vec3){r.w,r.h,1}; - t->rotation = QUAT1; - transform_apply(t); -) - -JSC_CCALL(transform_array, - transform *t = js2transform(js,self); - HMM_Mat4 m= transform2mat(t); - ret = JS_NewArray(js); - for (int i = 0; i < 16; i++) - JS_SetPropertyUint32(js,ret,i, number2js(js,m.em[i])); -) - -JSC_CCALL(transform_torect, - transform *t = js2transform(js,self); - return rect2js(js,transform2rect(t)); -) - -JSC_CCALL(transform_children, - transform *t = js2transform(js,self); - ret = JS_NewArray(js); - for (int i = 0; i < arrlen(t->jschildren); i++) - JS_SetPropertyUint32(js,ret,i,JS_DupValue(js,t->jschildren[i])); -) - -static const JSCFunctionListEntry js_transform_funcs[] = { - CGETSET_ADD(transform, pos), - CGETSET_ADD(transform, scale), - CGETSET_ADD(transform, rotation), - CGETSET_ADD(transform, parent), - CGETSET_ADD(transform, change_hook), - MIST_FUNC_DEF(transform, trs, 3), - MIST_FUNC_DEF(transform, phys2d, 3), - MIST_FUNC_DEF(transform, move, 1), - MIST_FUNC_DEF(transform, rotate, 2), - MIST_FUNC_DEF(transform, angle, 1), - MIST_FUNC_DEF(transform, lookat, 1), - MIST_FUNC_DEF(transform, direction, 1), - MIST_FUNC_DEF(transform, unit, 0), - MIST_FUNC_DEF(transform, rect, 1), - MIST_FUNC_DEF(transform, array, 0), - MIST_FUNC_DEF(transform, torect, 0), - MIST_FUNC_DEF(transform, children, 0), -}; - -// 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/cell_qoi.c b/qoi.c similarity index 97% rename from cell_qoi.c rename to qoi.c index e879746d..ad93e76b 100644 --- a/cell_qoi.c +++ b/qoi.c @@ -172,9 +172,4 @@ static const JSCFunctionListEntry js_qoi_funcs[] = { MIST_FUNC_DEF(qoi, decode, 1) }; -JSValue js_qoi_use(JSContext *js) -{ - JSValue mod = JS_NewObject(js); - JS_SetPropertyFunctionList(js, mod, js_qoi_funcs, countof(js_qoi_funcs)); - return mod; -} +CELL_USE_FUNCS(js_qoi_funcs) diff --git a/qjs_sdl_audio.c b/sdl_audio.c similarity index 99% rename from qjs_sdl_audio.c rename to sdl_audio.c index 301b4d9a..e72b430c 100644 --- a/qjs_sdl_audio.c +++ b/sdl_audio.c @@ -1,6 +1,3 @@ -#include "qjs_macros.h" -#include "quickjs.h" - #include #include #include "cell.h" @@ -359,8 +356,7 @@ static const JSCFunctionListEntry js_sdl_audio_funcs[] = { JS_CFUNC_DEF("mix_audio", 4, js_mix_audio), }; -// Use function -JSValue js_sdl_audio_use(JSContext *js) { +CELL_USE_INIT( JS_NewClassID(&js_SDL_AudioStream_id); JS_NewClass(JS_GetRuntime(js), js_SDL_AudioStream_id, &js_SDL_AudioStream_class); JSValue proto = JS_NewObject(js); @@ -370,4 +366,4 @@ JSValue js_sdl_audio_use(JSContext *js) { JSValue export = JS_NewObject(js); JS_SetPropertyFunctionList(js, export, js_sdl_audio_funcs, countof(js_sdl_audio_funcs)); return export; -} +) diff --git a/qjs_sdl_gpu.c b/sdl_gpu.c similarity index 99% rename from qjs_sdl_gpu.c rename to sdl_gpu.c index be0de473..ca282218 100644 --- a/qjs_sdl_gpu.c +++ b/sdl_gpu.c @@ -1656,8 +1656,7 @@ static JSValue js_gpu_constructor(JSContext *js, JSValueConst new_target, int ar } // Function to register module -JSValue js_sdl_gpu_use(JSContext *js) -{ +CELL_USE_INIT( JSValue ret = JS_NewObject(js); // Initialize classes @@ -1708,4 +1707,4 @@ JSValue js_sdl_gpu_use(JSContext *js) JS_SetPropertyStr(js, ret, "texture", texture_ctor); return ret; -} +) diff --git a/qjs_sdl_input.c b/sdl_input.c similarity index 99% rename from qjs_sdl_input.c rename to sdl_input.c index 125f825e..9a9f85f7 100644 --- a/qjs_sdl_input.c +++ b/sdl_input.c @@ -783,8 +783,4 @@ static const JSCFunctionListEntry js_input_funcs[] = { MIST_FUNC_DEF(input, gamepad_id_to_type, 1), }; -JSValue js_input_use(JSContext *js) { - JSValue mod = JS_NewObject(js); - JS_SetPropertyFunctionList(js,mod,js_input_funcs,countof(js_input_funcs)); - return mod; -} \ No newline at end of file +CELL_USE_FUNCS(js_input_funcs) diff --git a/qjs_sdl_surface.c b/sdl_surface.c similarity index 99% rename from qjs_sdl_surface.c rename to sdl_surface.c index 8f896d0b..1f5f0eba 100644 --- a/qjs_sdl_surface.c +++ b/sdl_surface.c @@ -1056,8 +1056,7 @@ JSC_CCALL(surface_convert_generic, return result; ) -JSValue js_sdl_surface_use(JSContext *js) -{ +CELL_USE_INIT( QJSCLASSPREP_FUNCS(SDL_Surface) // Add the surface constructor @@ -1084,4 +1083,4 @@ JSValue js_sdl_surface_use(JSContext *js) JS_SetPropertyStr(js, ctor, "dup", JS_NewCFunction(js, js_surface_dup_img, "dup", 1)); return ctor; -} \ No newline at end of file +) \ No newline at end of file diff --git a/qjs_sdl_video.c b/sdl_video.c similarity index 99% rename from qjs_sdl_video.c rename to sdl_video.c index 3667a5f5..e9112a73 100644 --- a/qjs_sdl_video.c +++ b/sdl_video.c @@ -749,7 +749,7 @@ JSC_CCALL(sdl_set_cursor, SDL_SetCursor(cursor); ) -JSValue js_sdl_video_use(JSContext *js) { +CELL_USE_INIT( if (!SDL_Init(SDL_INIT_VIDEO)) return JS_ThrowInternalError(js, "Unable to initialize video subsystem: %s", SDL_GetError()); @@ -775,4 +775,4 @@ JSValue js_sdl_video_use(JSContext *js) { JS_NewCFunction(js, js_sdl_set_cursor, "setCursor", 1)); return ret; -} +) diff --git a/spline.h b/spline.h deleted file mode 100644 index 4ee0e8c1..00000000 --- a/spline.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef SPLINE_H -#define SPLINE_H - -#include "HandmadeMath.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - These were already in your original header: -*/ - -// Adaptive Catmull–Rom in 2D / 3D / 4D (by minimum angle): -HMM_Vec2 *catmull_rom_ma_v2(HMM_Vec2 *cp, float ma); -HMM_Vec3 *catmull_rom_ma_v3(HMM_Vec3 *cp, float ma); /* not yet implemented in .c, placeholder */ -HMM_Vec4 *catmull_rom_ma_v4(HMM_Vec4 *cp, float ma); /* not yet implemented in .c, placeholder */ - -// Adaptive Bezier in 2D (by minimum angle): -HMM_Vec2 *bezier_cb_ma_v2(HMM_Vec2 *cp, float ma); - -// Generic “single-segment” query for 2D control points + basis matrix: -HMM_Vec2 spline_query(HMM_Vec2 *cp, float d, HMM_Mat4 *basis); - -// Catmull–Rom “entire spline” queries: -HMM_Vec2 catmull_rom_pos(HMM_Vec2 *cp, float d); // position -HMM_Vec2 catmull_rom_tan(HMM_Vec2 *cp, float d); // tangent -HMM_Vec2 catmull_rom_curv(HMM_Vec2 *cp, float d); // curvature -HMM_Vec2 catmull_rom_wig(HMM_Vec2 *cp, float d); // 3rd derivative (“wiggle”) - -// Computes approximate length of a 2D Catmull–Rom spline: -float catmull_rom_len(HMM_Vec2 *cp); - -// Returns closest point on a 2D Catmull–Rom curve given an external 2D point `p`: -HMM_Vec2 catmull_rom_closest(HMM_Vec2 *cp, HMM_Vec2 p); - - -/* - Additional convenience functions for *single-segment* cubic splines: - - Each of these expects exactly 4 control points in `p[0..3]`, - and a parameter t in [0..1]. They pick the appropriate matrix internally. -*/ - -// Hermite: -HMM_Vec2 cubic_hermite_pos(HMM_Vec2 *p, float d); -HMM_Vec2 cubic_hermite_tan(HMM_Vec2 *p, float d); -HMM_Vec2 cubic_hermite_curv(HMM_Vec2 *p, float d); -HMM_Vec2 cubic_hermite_wig(HMM_Vec2 *p, float d); - -// B-spline: -HMM_Vec2 b_spline_pos(HMM_Vec2 *p, float d); -HMM_Vec2 b_spline_tan(HMM_Vec2 *p, float d); -HMM_Vec2 b_spline_curv(HMM_Vec2 *p, float d); -HMM_Vec2 b_spline_wig(HMM_Vec2 *p, float d); - -// Bezier: -HMM_Vec2 bezier_pos(HMM_Vec2 *p, float d); -HMM_Vec2 bezier_tan(HMM_Vec2 *p, float d); -HMM_Vec2 bezier_curv(HMM_Vec2 *p, float d); -HMM_Vec2 bezier_wig(HMM_Vec2 *p, float d); - - -/* - Uniform sampling of a *single* 4-point segment in 2D: - Returns an array of points (stb_ds dynamic array). -*/ -HMM_Vec2 *spline_v2(HMM_Vec2 *p, HMM_Mat4 *m, int segs); - -/* - Adaptive subdivision routines (single-segment) in 2D: - - Subdivide by min segment length - - Subdivide by “max angle” proxy -*/ -HMM_Vec2 *spline2d_min_seg(float u0, float u1, float min_seg, HMM_Mat4 *C, HMM_Vec2 *ret); -HMM_Vec2 *catmull_rom_min_seg(HMM_Vec2 *a, HMM_Vec2 *b, HMM_Vec2 *c, HMM_Vec2 *d, float min_seg); - -HMM_Vec2 *spline2d_min_angle_2(float u0, float u1, float max_angle, HMM_Mat4 *C, HMM_Vec2 *arr); -HMM_Vec2 *spline_min_angle(HMM_Vec2 *p, const HMM_Mat4 *B, float min_angle, HMM_Vec2 *arr); - -#ifdef __cplusplus -} -#endif - -#endif /* SPLINE_H */ diff --git a/sprite.c b/sprite.c index 49937b69..45fc1a72 100644 --- a/sprite.c +++ b/sprite.c @@ -1,4 +1,9 @@ +#include "qjs_sprite.h" +#include "prosperon.h" +#include "qjs_macros.h" + #include "sprite.h" +#include "HandmadeMath.h" sprite *make_sprite(void) { @@ -27,3 +32,105 @@ void sprite_apply(sprite *sp) .y = -k.y * s + c }; } + + +// Sprite class definitions +static JSClassID js_sprite_id; +static void js_sprite_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) { + sprite *sp = JS_GetOpaque(val, js_sprite_id); + if (!sp) return; + JS_MarkValue(rt, sp->image, mark_func); +} + +// Class definition for sprite with mark function for GC +QJSCLASSMARK(sprite,) + +// SPRITE GETTER/SETTER FUNCTIONS +JSC_GETSET(sprite, pos, vec2) +JSC_GETSET(sprite, center, vec2) +JSC_GETSET(sprite, layer, number) +JSC_GETSET(sprite, color, color) +JSC_GETSET(sprite, skew, vec2) +JSC_GETSET(sprite, scale, vec2) +JSC_GETSET(sprite, rotation, number) + +// SPRITE ACTION FUNCTIONS + +JSC_CCALL(sprite_move, + sprite *sp = js2sprite(js,self); + HMM_Vec2 mv = js2vec2(js,argv[0]); + sp->pos.x += mv.x; + sp->pos.y += mv.y; +) + +JSC_CCALL(sprite_set_affine, + sprite *sp = js2sprite(js,self); + sprite_apply(sp); +) + +JSC_CCALL(sprite_set_image, + sprite *sp = js2sprite(js,self); + if (!JS_IsNull(sp->image)) + JS_FreeValue(js,sp->image); + sp->image = JS_DupValue(js, argv[0]); +) + +static const JSCFunctionListEntry js_sprite_funcs[] = { + MIST_FUNC_DEF(sprite, set_affine, 0), + MIST_FUNC_DEF(sprite, set_image, 1), + MIST_FUNC_DEF(sprite, move, 1), + JS_CGETSET_DEF("pos", js_sprite_get_pos, js_sprite_set_pos), + JS_CGETSET_DEF("scale", js_sprite_get_scale, js_sprite_set_scale), + JS_CGETSET_DEF("skew", js_sprite_get_skew, js_sprite_set_skew), + JS_CGETSET_DEF("layer", js_sprite_get_layer, js_sprite_set_layer), + JS_CGETSET_DEF("color", js_sprite_get_color, js_sprite_set_color), + JS_CGETSET_DEF("center", js_sprite_get_center, js_sprite_set_center), + JS_CGETSET_DEF("rotation", js_sprite_get_rotation, js_sprite_set_rotation), +}; + +// 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_IsNull(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); +} + +CELL_USE_INIT( + // 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/qjs_staef.c b/staef.c similarity index 99% rename from qjs_staef.c rename to staef.c index 0b30a5b5..f56cb3b1 100644 --- a/qjs_staef.c +++ b/staef.c @@ -124,8 +124,7 @@ static JSValue js_font_constructor(JSContext *ctx, JSValueConst new_target, int } // Initialize the staef module -JSValue js_staef_use(JSContext *js) -{ +CELL_USE_INIT( JSValue mod = JS_NewObject(js); JSValue proto; @@ -144,4 +143,4 @@ JSValue js_staef_use(JSContext *js) JS_SetPropertyStr(js, mod, "font", font_ctor); return mod; -} +) diff --git a/transform.c b/transform.c index 08f47c8f..3476776d 100644 --- a/transform.c +++ b/transform.c @@ -1,7 +1,12 @@ -#include "transform.h" +#include "cell.h" +#include "prosperon.h" +#include "qjs_macros.h" +#include "stb_ds.h" #include #include -#include "stb_ds.h" +#include "transform.h" +#include "HandmadeMath.h" + static transform **dirties; @@ -154,3 +159,241 @@ transform mat2transform(HMM_Mat4 m) t.rotation = HMM_M4ToQ_RH(m); return t; } + +// Transform class definitions +JSClassID js_transform_id; +static void js_transform_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) { + transform *t = JS_GetOpaque(val, js_transform_id); + if (!t) return; + // Mark the JSValue references stored in your struct + JS_MarkValue(rt, t->change_hook, mark_func); + JS_MarkValue(rt, t->jsparent, mark_func); + // Mark the array elements + for (int i = 0; i < arrlen(t->jschildren); i++) + JS_MarkValue(rt, t->jschildren[i], mark_func); +} + +QJSCLASSMARK_EXTERN(transform,) + +// TRANSFORM GETTER/SETTER FUNCTIONS +JSC_GETSET_APPLY(transform, pos, vec3) +JSC_GETSET_APPLY(transform, scale, vec3) +JSC_GETSET_APPLY(transform, rotation, quat) + +static JSValue js_transform_get_change_hook(JSContext *js, JSValueConst self) +{ + transform *t = js2transform(js,self); + return JS_DupValue(js,t->change_hook); +} + +static JSValue js_transform_set_change_hook(JSContext *js, JSValueConst self, JSValue v) +{ + transform *t = js2transform(js,self); + if (!JS_IsNull(v) && !JS_IsFunction(js,v)) return JS_ThrowReferenceError(js, "Hook must be a function."); + JS_FreeValue(js,t->change_hook); + t->change_hook = JS_DupValue(js,v); + return JS_NULL; +} + +static JSValue js_transform_get_parent(JSContext *js, JSValueConst self) +{ + transform *t = js2transform(js,self); + if (t->parent) return JS_DupValue(js,t->jsparent); + return JS_NULL; +} + +static JSValue js_transform_set_parent(JSContext *js, JSValueConst self, JSValue v) +{ + transform *p = js2transform(js,v); + if (!JS_IsNull(v) && !p) + return JS_ThrowReferenceError(js,"Parent must be another transform."); + + transform *t = js2transform(js,self); + + if (t == p) + return JS_ThrowReferenceError(js, "A transform cannot be its own parent."); + + if (t->parent) { + transform *cur_parent = t->parent; + JS_FreeValue(js,t->jsparent); + t->jsparent = JS_NULL; + + for (int i = 0; i < arrlen(cur_parent->children); i++) { + if (cur_parent->children[i] == t) { + arrdelswap(cur_parent->children,i); + break; + } + } + + for (int i = 0; i < arrlen(cur_parent->jschildren); i++) { + if (JS_SameValue(js,cur_parent->jschildren[i],self)) { + JS_FreeValue(js,cur_parent->jschildren[i]); + arrdelswap(cur_parent->jschildren,i); + break; + } + } + } + + t->parent = p; + t->jsparent = JS_DupValue(js,v); + + if (p) { + arrput(p->children, t); + JSValue child = JS_DupValue(js,self); + arrput(p->jschildren,child); + } + + transform_apply(t); + + return JS_NULL; +} + +// TRANSFORM ACTION FUNCTIONS + +JSC_CCALL(transform_move, + transform *t = js2transform(js,self); + transform_move(t, js2vec3(js,argv[0])); +) + +JSC_CCALL(transform_lookat, + HMM_Vec3 point = js2vec3(js,argv[0]); + transform *go = js2transform(js,self); + HMM_Mat4 m = HMM_LookAt_RH(go->pos, point, vUP); + go->rotation = HMM_M4ToQ_RH(m); + transform_apply(go); +) + +JSC_CCALL(transform_rotate, + HMM_Vec3 axis = js2vec3(js,argv[0]); + transform *t = js2transform(js,self); + HMM_Quat rot = HMM_QFromAxisAngle_RH(axis, js2angle(js,argv[1])); + t->rotation = HMM_MulQ(t->rotation,rot); + transform_apply(t); +) + +JSC_CCALL(transform_angle, + HMM_Vec3 axis = js2vec3(js,argv[0]); + transform *t = js2transform(js,self); + if (axis.x) return angle2js(js,HMM_Q_Roll(t->rotation)); + if (axis.y) return angle2js(js,HMM_Q_Pitch(t->rotation)); + if (axis.z) return angle2js(js,HMM_Q_Yaw(t->rotation)); + return angle2js(js,0); +) + +JSC_CCALL(transform_direction, + transform *t = js2transform(js,self); + return vec32js(js, HMM_QVRot(js2vec3(js,argv[0]), t->rotation)); +) + +JSC_CCALL(transform_phys2d, + transform *t = js2transform(js,self); + HMM_Vec2 v = js2vec2(js,argv[0]); + float av = js2number(js,argv[1]); + float dt = js2number(js,argv[2]); + transform_move(t, (HMM_Vec3){v.x*dt,v.y*dt,0}); + HMM_Quat rot = HMM_QFromAxisAngle_RH((HMM_Vec3){0,0,1}, av*dt); + t->rotation = HMM_MulQ(t->rotation, rot); + transform_apply(t); +) + +JSC_CCALL(transform_unit, + transform *t = js2transform(js,self); + t->pos = v3zero; + t->rotation = QUAT1; + t->scale = v3one; + transform_apply(t); +) + +JSC_CCALL(transform_trs, + transform *t = js2transform(js,self); + t->pos = JS_IsNull(argv[0]) ? v3zero : js2vec3(js,argv[0]); + t->rotation = JS_IsNull(argv[1]) ? QUAT1 : js2quat(js,argv[1]); + t->scale = JS_IsNull(argv[2]) ? v3one : js2vec3(js,argv[2]); + transform_apply(t); +) + +JSC_CCALL(transform_rect, + transform *t = js2transform(js,self); + rect r = js2rect(js,argv[0]); + t->pos = (HMM_Vec3){r.x,r.y,0}; + t->scale = (HMM_Vec3){r.w,r.h,1}; + t->rotation = QUAT1; + transform_apply(t); +) + +JSC_CCALL(transform_array, + transform *t = js2transform(js,self); + HMM_Mat4 m= transform2mat(t); + ret = JS_NewArray(js); + for (int i = 0; i < 16; i++) + JS_SetPropertyUint32(js,ret,i, number2js(js,m.em[i])); +) + +JSC_CCALL(transform_torect, + transform *t = js2transform(js,self); + return rect2js(js,transform2rect(t)); +) + +JSC_CCALL(transform_children, + transform *t = js2transform(js,self); + ret = JS_NewArray(js); + for (int i = 0; i < arrlen(t->jschildren); i++) + JS_SetPropertyUint32(js,ret,i,JS_DupValue(js,t->jschildren[i])); +) + +static const JSCFunctionListEntry js_transform_funcs[] = { + CGETSET_ADD(transform, pos), + CGETSET_ADD(transform, scale), + CGETSET_ADD(transform, rotation), + CGETSET_ADD(transform, parent), + CGETSET_ADD(transform, change_hook), + MIST_FUNC_DEF(transform, trs, 3), + MIST_FUNC_DEF(transform, phys2d, 3), + MIST_FUNC_DEF(transform, move, 1), + MIST_FUNC_DEF(transform, rotate, 2), + MIST_FUNC_DEF(transform, angle, 1), + MIST_FUNC_DEF(transform, lookat, 1), + MIST_FUNC_DEF(transform, direction, 1), + MIST_FUNC_DEF(transform, unit, 0), + MIST_FUNC_DEF(transform, rect, 1), + MIST_FUNC_DEF(transform, array, 0), + MIST_FUNC_DEF(transform, torect, 0), + MIST_FUNC_DEF(transform, children, 0), +}; + +// 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), +}; + +CELL_USE_INIT( + // 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; +) \ No newline at end of file