Files
cell/playdate/sprite_playdate.c
2025-12-11 14:42:30 -06:00

396 lines
14 KiB
C

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