// sprite_playdate.c - Cell integration for Playdate Sprite API // Wraps pd_api_sprite.h functions for JavaScript access #include "cell.h" #include "common.h" // --- Helpers --- static LCDSprite* js2sprite(JSContext *js, JSValueConst val) { int64_t ptr; if (JS_ToInt64(js, &ptr, val) < 0) return NULL; return (LCDSprite*)(intptr_t)ptr; } static LCDBitmap* js2bitmap(JSContext *js, JSValueConst val) { int64_t ptr; if (JS_ToInt64(js, &ptr, val) < 0) return NULL; return (LCDBitmap*)(intptr_t)ptr; } // --- Sprite Functions --- JSC_CCALL(sprite_setAlwaysRedraw, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); pd_sprite->setAlwaysRedraw(JS_ToBool(js, argv[0])); return JS_NULL; ) JSC_CCALL(sprite_drawSprites, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); pd_sprite->drawSprites(); return JS_NULL; ) JSC_CCALL(sprite_updateAndDrawSprites, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); pd_sprite->updateAndDrawSprites(); return JS_NULL; ) JSC_CCALL(sprite_newSprite, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = pd_sprite->newSprite(); if (!s) return JS_ThrowInternalError(js, "failed to create sprite"); return JS_NewInt64(js, (int64_t)(intptr_t)s); ) JSC_CCALL(sprite_freeSprite, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (s) pd_sprite->freeSprite(s); return JS_NULL; ) JSC_CCALL(sprite_copy, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); LCDSprite *copy = pd_sprite->copy(s); return copy ? JS_NewInt64(js, (int64_t)(intptr_t)copy) : JS_NULL; ) JSC_CCALL(sprite_addSprite, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); pd_sprite->addSprite(s); return JS_NULL; ) JSC_CCALL(sprite_removeSprite, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); pd_sprite->removeSprite(s); return JS_NULL; ) JSC_CCALL(sprite_removeAllSprites, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); pd_sprite->removeAllSprites(); return JS_NULL; ) JSC_CCALL(sprite_getSpriteCount, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); return JS_NewInt32(js, pd_sprite->getSpriteCount()); ) JSC_CCALL(sprite_setBounds, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); PDRect bounds = { (float)js2number(js, argv[1]), (float)js2number(js, argv[2]), (float)js2number(js, argv[3]), (float)js2number(js, argv[4]) }; pd_sprite->setBounds(s, bounds); return JS_NULL; ) JSC_CCALL(sprite_getBounds, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); PDRect b = pd_sprite->getBounds(s); JSValue obj = JS_NewObject(js); JS_SetPropertyStr(js, obj, "x", JS_NewFloat64(js, b.x)); JS_SetPropertyStr(js, obj, "y", JS_NewFloat64(js, b.y)); JS_SetPropertyStr(js, obj, "width", JS_NewFloat64(js, b.width)); JS_SetPropertyStr(js, obj, "height", JS_NewFloat64(js, b.height)); return obj; ) JSC_CCALL(sprite_moveTo, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); pd_sprite->moveTo(s, (float)js2number(js, argv[1]), (float)js2number(js, argv[2])); return JS_NULL; ) JSC_CCALL(sprite_moveBy, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); pd_sprite->moveBy(s, (float)js2number(js, argv[1]), (float)js2number(js, argv[2])); return JS_NULL; ) JSC_CCALL(sprite_setImage, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); LCDBitmap *img = js2bitmap(js, argv[1]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); LCDBitmapFlip flip = argc > 2 ? (LCDBitmapFlip)(int)js2number(js, argv[2]) : kBitmapUnflipped; pd_sprite->setImage(s, img, flip); return JS_NULL; ) JSC_CCALL(sprite_getImage, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); LCDBitmap *img = pd_sprite->getImage(s); return img ? JS_NewInt64(js, (int64_t)(intptr_t)img) : JS_NULL; ) JSC_CCALL(sprite_setSize, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); pd_sprite->setSize(s, (float)js2number(js, argv[1]), (float)js2number(js, argv[2])); return JS_NULL; ) JSC_CCALL(sprite_setZIndex, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); pd_sprite->setZIndex(s, (int16_t)js2number(js, argv[1])); return JS_NULL; ) JSC_CCALL(sprite_getZIndex, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); return JS_NewInt32(js, pd_sprite->getZIndex(s)); ) JSC_CCALL(sprite_setDrawMode, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); pd_sprite->setDrawMode(s, (LCDBitmapDrawMode)(int)js2number(js, argv[1])); return JS_NULL; ) JSC_CCALL(sprite_setImageFlip, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); pd_sprite->setImageFlip(s, (LCDBitmapFlip)(int)js2number(js, argv[1])); return JS_NULL; ) JSC_CCALL(sprite_getImageFlip, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); return JS_NewInt32(js, pd_sprite->getImageFlip(s)); ) JSC_CCALL(sprite_setVisible, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); pd_sprite->setVisible(s, JS_ToBool(js, argv[1])); return JS_NULL; ) JSC_CCALL(sprite_isVisible, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); return JS_NewBool(js, pd_sprite->isVisible(s)); ) JSC_CCALL(sprite_setOpaque, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); pd_sprite->setOpaque(s, JS_ToBool(js, argv[1])); return JS_NULL; ) JSC_CCALL(sprite_markDirty, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); pd_sprite->markDirty(s); return JS_NULL; ) JSC_CCALL(sprite_setTag, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); pd_sprite->setTag(s, (uint8_t)js2number(js, argv[1])); return JS_NULL; ) JSC_CCALL(sprite_getTag, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); return JS_NewInt32(js, pd_sprite->getTag(s)); ) JSC_CCALL(sprite_setIgnoresDrawOffset, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); pd_sprite->setIgnoresDrawOffset(s, JS_ToBool(js, argv[1])); return JS_NULL; ) JSC_CCALL(sprite_getPosition, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); float x, y; pd_sprite->getPosition(s, &x, &y); JSValue obj = JS_NewObject(js); JS_SetPropertyStr(js, obj, "x", JS_NewFloat64(js, x)); JS_SetPropertyStr(js, obj, "y", JS_NewFloat64(js, y)); return obj; ) JSC_CCALL(sprite_setCenter, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); pd_sprite->setCenter(s, (float)js2number(js, argv[1]), (float)js2number(js, argv[2])); return JS_NULL; ) JSC_CCALL(sprite_getCenter, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); float x, y; pd_sprite->getCenter(s, &x, &y); JSValue obj = JS_NewObject(js); JS_SetPropertyStr(js, obj, "x", JS_NewFloat64(js, x)); JS_SetPropertyStr(js, obj, "y", JS_NewFloat64(js, y)); return obj; ) // --- Collision Functions --- JSC_CCALL(sprite_resetCollisionWorld, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); pd_sprite->resetCollisionWorld(); return JS_NULL; ) JSC_CCALL(sprite_setCollideRect, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); PDRect rect = { (float)js2number(js, argv[1]), (float)js2number(js, argv[2]), (float)js2number(js, argv[3]), (float)js2number(js, argv[4]) }; pd_sprite->setCollideRect(s, rect); return JS_NULL; ) JSC_CCALL(sprite_getCollideRect, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); PDRect r = pd_sprite->getCollideRect(s); JSValue obj = JS_NewObject(js); JS_SetPropertyStr(js, obj, "x", JS_NewFloat64(js, r.x)); JS_SetPropertyStr(js, obj, "y", JS_NewFloat64(js, r.y)); JS_SetPropertyStr(js, obj, "width", JS_NewFloat64(js, r.width)); JS_SetPropertyStr(js, obj, "height", JS_NewFloat64(js, r.height)); return obj; ) JSC_CCALL(sprite_clearCollideRect, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); pd_sprite->clearCollideRect(s); return JS_NULL; ) JSC_CCALL(sprite_setCollisionsEnabled, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); pd_sprite->setCollisionsEnabled(s, JS_ToBool(js, argv[1])); return JS_NULL; ) JSC_CCALL(sprite_collisionsEnabled, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); return JS_NewBool(js, pd_sprite->collisionsEnabled(s)); ) JSC_CCALL(sprite_setUpdatesEnabled, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); pd_sprite->setUpdatesEnabled(s, JS_ToBool(js, argv[1])); return JS_NULL; ) JSC_CCALL(sprite_updatesEnabled, if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized"); LCDSprite *s = js2sprite(js, argv[0]); if (!s) return JS_ThrowTypeError(js, "invalid sprite"); return JS_NewBool(js, pd_sprite->updatesEnabled(s)); ) static const JSCFunctionListEntry js_sprite_funcs[] = { MIST_FUNC_DEF(sprite, setAlwaysRedraw, 1), MIST_FUNC_DEF(sprite, drawSprites, 0), MIST_FUNC_DEF(sprite, updateAndDrawSprites, 0), MIST_FUNC_DEF(sprite, newSprite, 0), MIST_FUNC_DEF(sprite, freeSprite, 1), MIST_FUNC_DEF(sprite, copy, 1), MIST_FUNC_DEF(sprite, addSprite, 1), MIST_FUNC_DEF(sprite, removeSprite, 1), MIST_FUNC_DEF(sprite, removeAllSprites, 0), MIST_FUNC_DEF(sprite, getSpriteCount, 0), MIST_FUNC_DEF(sprite, setBounds, 5), MIST_FUNC_DEF(sprite, getBounds, 1), MIST_FUNC_DEF(sprite, moveTo, 3), MIST_FUNC_DEF(sprite, moveBy, 3), MIST_FUNC_DEF(sprite, setImage, 3), MIST_FUNC_DEF(sprite, getImage, 1), MIST_FUNC_DEF(sprite, setSize, 3), MIST_FUNC_DEF(sprite, setZIndex, 2), MIST_FUNC_DEF(sprite, getZIndex, 1), MIST_FUNC_DEF(sprite, setDrawMode, 2), MIST_FUNC_DEF(sprite, setImageFlip, 2), MIST_FUNC_DEF(sprite, getImageFlip, 1), MIST_FUNC_DEF(sprite, setVisible, 2), MIST_FUNC_DEF(sprite, isVisible, 1), MIST_FUNC_DEF(sprite, setOpaque, 2), MIST_FUNC_DEF(sprite, markDirty, 1), MIST_FUNC_DEF(sprite, setTag, 2), MIST_FUNC_DEF(sprite, getTag, 1), MIST_FUNC_DEF(sprite, setIgnoresDrawOffset, 2), MIST_FUNC_DEF(sprite, getPosition, 1), MIST_FUNC_DEF(sprite, setCenter, 3), MIST_FUNC_DEF(sprite, getCenter, 1), MIST_FUNC_DEF(sprite, resetCollisionWorld, 0), MIST_FUNC_DEF(sprite, setCollideRect, 5), MIST_FUNC_DEF(sprite, getCollideRect, 1), MIST_FUNC_DEF(sprite, clearCollideRect, 1), MIST_FUNC_DEF(sprite, setCollisionsEnabled, 2), MIST_FUNC_DEF(sprite, collisionsEnabled, 1), MIST_FUNC_DEF(sprite, setUpdatesEnabled, 2), MIST_FUNC_DEF(sprite, updatesEnabled, 1), }; JSValue js_sprite_use(JSContext *js) { JSValue mod = JS_NewObject(js); JS_SetPropertyFunctionList(js, mod, js_sprite_funcs, countof(js_sprite_funcs)); return mod; }