#include "prosperon.h" #include "cell.h" #include "HandmadeMath.h" struct sprite{ HMM_Vec2 pos; // x,y coordinates of the sprite HMM_Vec2 center; HMM_Vec2 skew; HMM_Vec2 scale; float rotation; HMM_Mat2 affine; JSValue image; // the JS image int layer; // layer this sprite draws onto HMM_Vec4 color; // color in 0-1f }; typedef struct sprite sprite; sprite *make_sprite(void) { sprite *sprite = calloc(sizeof(*sprite),1); sprite->image = JS_NULL; return sprite; } void sprite_free(JSRuntime *rt, sprite *sprite) { JS_FreeValueRT(rt,sprite->image); free(sprite); } void sprite_apply(sprite *sp) { /* -------- rotation + skew → 2×2 affine matrix -------- */ float rot = sp->rotation; HMM_Vec2 k = sp->skew; float c = cosf(rot), s = sinf(rot); sp->affine.Columns[0] = (HMM_Vec2){ .x = c + k.x * s, .y = k.y * c + s }; sp->affine.Columns[1] = (HMM_Vec2){ .x = -s + k.x * c, .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 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]); ) JSC_CCALL(sprite_set, sprite *sp = js2sprite(js,self); if (!JS_IsObject(argv[0])) return JS_NULL; JSValue val; val = JS_GetPropertyStr(js, argv[0], "pos"); if (!JS_IsNull(val)) { sp->pos = js2vec2(js, val); JS_FreeValue(js, val); } val = JS_GetPropertyStr(js, argv[0], "center"); if (!JS_IsNull(val)) { sp->center = js2vec2(js, val); JS_FreeValue(js, val); } val = JS_GetPropertyStr(js, argv[0], "skew"); if (!JS_IsNull(val)) { sp->skew = js2vec2(js, val); JS_FreeValue(js, val); } val = JS_GetPropertyStr(js, argv[0], "scale"); if (!JS_IsNull(val)) { sp->scale = js2vec2(js, val); JS_FreeValue(js, val); } val = JS_GetPropertyStr(js, argv[0], "rotation"); if (!JS_IsNull(val)) { sp->rotation = js2number(js, val); JS_FreeValue(js, val); } val = JS_GetPropertyStr(js, argv[0], "layer"); if (!JS_IsNull(val)) { sp->layer = js2number(js, val); JS_FreeValue(js, val); } val = JS_GetPropertyStr(js, argv[0], "color"); if (!JS_IsNull(val)) { sp->color = js2color(js, val); JS_FreeValue(js, val); } val = JS_GetPropertyStr(js, argv[0], "image"); if (!JS_IsNull(val) && !JS_IsNull(val)) { if (!JS_IsNull(sp->image)) JS_FreeValue(js, sp->image); sp->image = val; // Transfer ownership } else { JS_FreeValue(js, val); } ) 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), MIST_FUNC_DEF(sprite, set, 1), }; // 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( QJSCLASSPREP_FUNCS(sprite); JSValue ctor = JS_NewCFunction2(js, js_sprite_constructor, "sprite", 1, JS_CFUNC_generic, 0); return ctor; )