playdate cake

This commit is contained in:
2025-12-10 15:01:20 -06:00
parent 752479e250
commit d0f5dc6951
14 changed files with 2635 additions and 4 deletions

1
cake/playdate.cm Normal file
View File

@@ -0,0 +1 @@
// cake file for making a playdate package

64
playdate/common.h Normal file
View File

@@ -0,0 +1,64 @@
// playdate/common.h - Common declarations for Playdate Cell integration
// This header declares the global API pointers that are initialized in main_playdate.c
// and used by all the Playdate integration modules.
#ifndef PLAYDATE_COMMON_H
#define PLAYDATE_COMMON_H
#include "pd_api/pd_api_file.h"
#include "pd_api/pd_api_gfx.h"
#include "pd_api/pd_api_sys.h"
#include "pd_api/pd_api_sound.h"
#include "pd_api/pd_api_sprite.h"
#include "pd_api/pd_api_display.h"
#include "pd_api/pd_api_json.h"
#include "pd_api/pd_api_lua.h"
#include "pd_api/pd_api_network.h"
#include "pd_api/pd_api_scoreboards.h"
// Forward declare the main PlaydateAPI struct
typedef struct PlaydateAPI PlaydateAPI;
struct PlaydateAPI
{
const struct playdate_sys *system;
const struct playdate_file *file;
const struct playdate_graphics *graphics;
const struct playdate_sprite *sprite;
const struct playdate_display *display;
const struct playdate_sound *sound;
const struct playdate_lua *lua;
const struct playdate_json *json;
const struct playdate_scoreboards *scoreboards;
const struct playdate_network *network;
};
// System events
typedef enum
{
kEventInit,
kEventInitLua,
kEventLock,
kEventUnlock,
kEventPause,
kEventResume,
kEventTerminate,
kEventKeyPressed,
kEventKeyReleased,
kEventLowPower
} PDSystemEvent;
// Global API pointers - defined in main_playdate.c
extern PlaydateAPI *pd;
extern const struct playdate_file *pd_file;
extern const struct playdate_sys *pd_sys;
extern const struct playdate_graphics *pd_gfx;
extern const struct playdate_sprite *pd_sprite;
extern const struct playdate_display *pd_display;
extern const struct playdate_sound *pd_sound;
extern const struct playdate_lua *pd_lua;
extern const struct playdate_json *pd_json;
extern const struct playdate_scoreboards *pd_scoreboards;
extern const struct playdate_network *pd_network;
#endif // PLAYDATE_COMMON_H

View File

@@ -0,0 +1,91 @@
// display_playdate.c - Cell integration for Playdate Display API
// Wraps pd_api_display.h functions for JavaScript access
#include "cell.h"
#include "common.h"
// --- Display API Wrappers ---
JSC_CCALL(display_getWidth,
if (!pd_display) return JS_ThrowInternalError(js, "display not initialized");
return JS_NewInt32(js, pd_display->getWidth());
)
JSC_CCALL(display_getHeight,
if (!pd_display) return JS_ThrowInternalError(js, "display not initialized");
return JS_NewInt32(js, pd_display->getHeight());
)
JSC_CCALL(display_setRefreshRate,
if (!pd_display) return JS_ThrowInternalError(js, "display not initialized");
float rate = (float)js2number(js, argv[0]);
pd_display->setRefreshRate(rate);
return JS_UNDEFINED;
)
JSC_CCALL(display_getRefreshRate,
if (!pd_display) return JS_ThrowInternalError(js, "display not initialized");
return JS_NewFloat64(js, pd_display->getRefreshRate());
)
JSC_CCALL(display_getFPS,
if (!pd_display) return JS_ThrowInternalError(js, "display not initialized");
return JS_NewFloat64(js, pd_display->getFPS());
)
JSC_CCALL(display_setInverted,
if (!pd_display) return JS_ThrowInternalError(js, "display not initialized");
int flag = JS_ToBool(js, argv[0]);
pd_display->setInverted(flag);
return JS_UNDEFINED;
)
JSC_CCALL(display_setScale,
if (!pd_display) return JS_ThrowInternalError(js, "display not initialized");
unsigned int scale = (unsigned int)js2number(js, argv[0]);
pd_display->setScale(scale);
return JS_UNDEFINED;
)
JSC_CCALL(display_setMosaic,
if (!pd_display) return JS_ThrowInternalError(js, "display not initialized");
unsigned int x = (unsigned int)js2number(js, argv[0]);
unsigned int y = (unsigned int)js2number(js, argv[1]);
pd_display->setMosaic(x, y);
return JS_UNDEFINED;
)
JSC_CCALL(display_setFlipped,
if (!pd_display) return JS_ThrowInternalError(js, "display not initialized");
int x = JS_ToBool(js, argv[0]);
int y = JS_ToBool(js, argv[1]);
pd_display->setFlipped(x, y);
return JS_UNDEFINED;
)
JSC_CCALL(display_setOffset,
if (!pd_display) return JS_ThrowInternalError(js, "display not initialized");
int x = (int)js2number(js, argv[0]);
int y = (int)js2number(js, argv[1]);
pd_display->setOffset(x, y);
return JS_UNDEFINED;
)
static const JSCFunctionListEntry js_display_funcs[] = {
MIST_FUNC_DEF(display, getWidth, 0),
MIST_FUNC_DEF(display, getHeight, 0),
MIST_FUNC_DEF(display, setRefreshRate, 1),
MIST_FUNC_DEF(display, getRefreshRate, 0),
MIST_FUNC_DEF(display, getFPS, 0),
MIST_FUNC_DEF(display, setInverted, 1),
MIST_FUNC_DEF(display, setScale, 1),
MIST_FUNC_DEF(display, setMosaic, 2),
MIST_FUNC_DEF(display, setFlipped, 2),
MIST_FUNC_DEF(display, setOffset, 2),
};
JSValue js_display_use(JSContext *js) {
JSValue mod = JS_NewObject(js);
JS_SetPropertyFunctionList(js, mod, js_display_funcs, countof(js_display_funcs));
return mod;
}

175
playdate/file_playdate.c Normal file
View File

@@ -0,0 +1,175 @@
// file_playdate.c - Cell integration for Playdate File API
// Wraps pd_api_file.h functions for JavaScript access
// Note: fd_playdate.c already provides the main file operations.
// This module provides additional raw file API access.
#include "cell.h"
#include "common.h"
#include <string.h>
// --- Helpers ---
static SDFile* js2sdfile(JSContext *js, JSValueConst val) {
int64_t ptr;
if (JS_ToInt64(js, &ptr, val) < 0) return NULL;
return (SDFile*)(intptr_t)ptr;
}
// --- File Functions ---
JSC_CCALL(file_geterr,
if (!pd_file) return JS_ThrowInternalError(js, "file not initialized");
const char *err = pd_file->geterr();
return err ? JS_NewString(js, err) : JS_NULL;
)
JSC_SCALL(file_stat,
if (!pd_file) return JS_ThrowInternalError(js, "file not initialized");
FileStat st;
if (pd_file->stat(str, &st) != 0) {
ret = JS_NULL;
} else {
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "isdir", JS_NewBool(js, st.isdir));
JS_SetPropertyStr(js, obj, "size", JS_NewInt64(js, st.size));
JS_SetPropertyStr(js, obj, "year", JS_NewInt32(js, st.m_year));
JS_SetPropertyStr(js, obj, "month", JS_NewInt32(js, st.m_month));
JS_SetPropertyStr(js, obj, "day", JS_NewInt32(js, st.m_day));
JS_SetPropertyStr(js, obj, "hour", JS_NewInt32(js, st.m_hour));
JS_SetPropertyStr(js, obj, "minute", JS_NewInt32(js, st.m_minute));
JS_SetPropertyStr(js, obj, "second", JS_NewInt32(js, st.m_second));
ret = obj;
}
)
JSC_SCALL(file_mkdir,
if (!pd_file) return JS_ThrowInternalError(js, "file not initialized");
ret = JS_NewBool(js, pd_file->mkdir(str) == 0);
)
JSC_SCALL(file_unlink,
if (!pd_file) return JS_ThrowInternalError(js, "file not initialized");
int recursive = argc > 1 ? JS_ToBool(js, argv[1]) : 0;
ret = JS_NewBool(js, pd_file->unlink(str, recursive) == 0);
)
JSC_SCALL(file_rename,
if (!pd_file) return JS_ThrowInternalError(js, "file not initialized");
const char *to = JS_ToCString(js, argv[1]);
int result = pd_file->rename(str, to);
JS_FreeCString(js, to);
ret = JS_NewBool(js, result == 0);
)
JSC_SCALL(file_open,
if (!pd_file) return JS_ThrowInternalError(js, "file not initialized");
FileOptions mode = kFileRead;
if (argc > 1) mode = (FileOptions)(int)js2number(js, argv[1]);
SDFile *f = pd_file->open(str, mode);
ret = f ? JS_NewInt64(js, (int64_t)(intptr_t)f) : JS_NULL;
)
JSC_CCALL(file_close,
if (!pd_file) return JS_ThrowInternalError(js, "file not initialized");
SDFile *f = js2sdfile(js, argv[0]);
return JS_NewBool(js, pd_file->close(f) == 0);
)
JSC_CCALL(file_read,
if (!pd_file) return JS_ThrowInternalError(js, "file not initialized");
SDFile *f = js2sdfile(js, argv[0]);
unsigned int len = (unsigned int)js2number(js, argv[1]);
void *buf = malloc(len);
if (!buf) return JS_ThrowInternalError(js, "malloc failed");
int read = pd_file->read(f, buf, len);
if (read < 0) {
free(buf);
return JS_NULL;
}
JSValue blob = js_new_blob_stoned_copy(js, buf, read);
free(buf);
return blob;
)
JSC_CCALL(file_write,
if (!pd_file) return JS_ThrowInternalError(js, "file not initialized");
SDFile *f = js2sdfile(js, argv[0]);
size_t len;
const void *data = js_get_blob_data(js, &len, argv[1]);
if (data == (void*)-1) return JS_EXCEPTION;
int written = pd_file->write(f, data, (unsigned int)len);
return JS_NewInt32(js, written);
)
JSC_CCALL(file_flush,
if (!pd_file) return JS_ThrowInternalError(js, "file not initialized");
SDFile *f = js2sdfile(js, argv[0]);
return JS_NewBool(js, pd_file->flush(f) == 0);
)
JSC_CCALL(file_tell,
if (!pd_file) return JS_ThrowInternalError(js, "file not initialized");
SDFile *f = js2sdfile(js, argv[0]);
return JS_NewInt32(js, pd_file->tell(f));
)
JSC_CCALL(file_seek,
if (!pd_file) return JS_ThrowInternalError(js, "file not initialized");
SDFile *f = js2sdfile(js, argv[0]);
int pos = (int)js2number(js, argv[1]);
int whence = argc > 2 ? (int)js2number(js, argv[2]) : SEEK_SET;
return JS_NewBool(js, pd_file->seek(f, pos, whence) == 0);
)
struct listfiles_ctx {
JSContext *js;
JSValue array;
int index;
};
static void listfiles_cb(const char *path, void *userdata) {
struct listfiles_ctx *ctx = (struct listfiles_ctx*)userdata;
JS_SetPropertyUint32(ctx->js, ctx->array, ctx->index++, JS_NewString(ctx->js, path));
}
JSC_SCALL(file_listfiles,
if (!pd_file) return JS_ThrowInternalError(js, "file not initialized");
int showhidden = argc > 1 ? JS_ToBool(js, argv[1]) : 0;
JSValue arr = JS_NewArray(js);
struct listfiles_ctx ctx = { js, arr, 0 };
if (pd_file->listfiles(str, listfiles_cb, &ctx, showhidden) != 0) {
JS_FreeValue(js, arr);
ret = JS_NULL;
} else {
ret = arr;
}
)
static const JSCFunctionListEntry js_file_funcs[] = {
MIST_FUNC_DEF(file, geterr, 0),
MIST_FUNC_DEF(file, stat, 1),
MIST_FUNC_DEF(file, mkdir, 1),
MIST_FUNC_DEF(file, unlink, 2),
MIST_FUNC_DEF(file, rename, 2),
MIST_FUNC_DEF(file, open, 2),
MIST_FUNC_DEF(file, close, 1),
MIST_FUNC_DEF(file, read, 2),
MIST_FUNC_DEF(file, write, 2),
MIST_FUNC_DEF(file, flush, 1),
MIST_FUNC_DEF(file, tell, 1),
MIST_FUNC_DEF(file, seek, 3),
MIST_FUNC_DEF(file, listfiles, 2),
};
JSValue js_file_use(JSContext *js) {
JSValue mod = JS_NewObject(js);
JS_SetPropertyFunctionList(js, mod, js_file_funcs, countof(js_file_funcs));
// Export constants
JS_SetPropertyStr(js, mod, "READ", JS_NewInt32(js, kFileRead));
JS_SetPropertyStr(js, mod, "READ_DATA", JS_NewInt32(js, kFileReadData));
JS_SetPropertyStr(js, mod, "WRITE", JS_NewInt32(js, kFileWrite));
JS_SetPropertyStr(js, mod, "APPEND", JS_NewInt32(js, kFileAppend));
JS_SetPropertyStr(js, mod, "SEEK_SET", JS_NewInt32(js, SEEK_SET));
JS_SetPropertyStr(js, mod, "SEEK_CUR", JS_NewInt32(js, SEEK_CUR));
JS_SetPropertyStr(js, mod, "SEEK_END", JS_NewInt32(js, SEEK_END));
return mod;
}

339
playdate/gfx_playdate.c Normal file
View File

@@ -0,0 +1,339 @@
// gfx_playdate.c - Cell integration for Playdate Graphics API
// Wraps pd_api_gfx.h functions for JavaScript access
#include "cell.h"
#include "common.h"
#include <string.h>
// --- Helper: Convert JS value to LCDBitmap* ---
static LCDBitmap* js2bitmap(JSContext *js, JSValueConst val) {
int64_t ptr;
if (JS_ToInt64(js, &ptr, val) < 0) return NULL;
return (LCDBitmap*)(intptr_t)ptr;
}
static LCDBitmapTable* js2bitmaptable(JSContext *js, JSValueConst val) {
int64_t ptr;
if (JS_ToInt64(js, &ptr, val) < 0) return NULL;
return (LCDBitmapTable*)(intptr_t)ptr;
}
static LCDFont* js2font(JSContext *js, JSValueConst val) {
int64_t ptr;
if (JS_ToInt64(js, &ptr, val) < 0) return NULL;
return (LCDFont*)(intptr_t)ptr;
}
// --- Drawing Functions ---
JSC_CCALL(gfx_clear,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
LCDColor color = (LCDColor)js2number(js, argv[0]);
pd_gfx->clear(color);
return JS_UNDEFINED;
)
JSC_CCALL(gfx_setBackgroundColor,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
LCDSolidColor color = (LCDSolidColor)(int)js2number(js, argv[0]);
pd_gfx->setBackgroundColor(color);
return JS_UNDEFINED;
)
JSC_CCALL(gfx_setDrawMode,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
LCDBitmapDrawMode mode = (LCDBitmapDrawMode)(int)js2number(js, argv[0]);
LCDBitmapDrawMode prev = pd_gfx->setDrawMode(mode);
return JS_NewInt32(js, prev);
)
JSC_CCALL(gfx_setDrawOffset,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
pd_gfx->setDrawOffset((int)js2number(js, argv[0]), (int)js2number(js, argv[1]));
return JS_UNDEFINED;
)
JSC_CCALL(gfx_setClipRect,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
pd_gfx->setClipRect((int)js2number(js, argv[0]), (int)js2number(js, argv[1]),
(int)js2number(js, argv[2]), (int)js2number(js, argv[3]));
return JS_UNDEFINED;
)
JSC_CCALL(gfx_clearClipRect,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
pd_gfx->clearClipRect();
return JS_UNDEFINED;
)
JSC_CCALL(gfx_setLineCapStyle,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
pd_gfx->setLineCapStyle((LCDLineCapStyle)(int)js2number(js, argv[0]));
return JS_UNDEFINED;
)
JSC_CCALL(gfx_setFont,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
pd_gfx->setFont(js2font(js, argv[0]));
return JS_UNDEFINED;
)
JSC_CCALL(gfx_setTextTracking,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
pd_gfx->setTextTracking((int)js2number(js, argv[0]));
return JS_UNDEFINED;
)
JSC_CCALL(gfx_getTextTracking,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
return JS_NewInt32(js, pd_gfx->getTextTracking());
)
JSC_CCALL(gfx_pushContext,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
pd_gfx->pushContext(argc > 0 ? js2bitmap(js, argv[0]) : NULL);
return JS_UNDEFINED;
)
JSC_CCALL(gfx_popContext,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
pd_gfx->popContext();
return JS_UNDEFINED;
)
// --- Drawing Primitives ---
JSC_CCALL(gfx_drawBitmap,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
LCDBitmap *bmp = js2bitmap(js, argv[0]);
if (!bmp) return JS_ThrowTypeError(js, "invalid bitmap");
pd_gfx->drawBitmap(bmp, (int)js2number(js, argv[1]), (int)js2number(js, argv[2]),
argc > 3 ? (LCDBitmapFlip)(int)js2number(js, argv[3]) : kBitmapUnflipped);
return JS_UNDEFINED;
)
JSC_CCALL(gfx_drawLine,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
pd_gfx->drawLine((int)js2number(js, argv[0]), (int)js2number(js, argv[1]),
(int)js2number(js, argv[2]), (int)js2number(js, argv[3]),
(int)js2number(js, argv[4]), (LCDColor)js2number(js, argv[5]));
return JS_UNDEFINED;
)
JSC_CCALL(gfx_drawRect,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
pd_gfx->drawRect((int)js2number(js, argv[0]), (int)js2number(js, argv[1]),
(int)js2number(js, argv[2]), (int)js2number(js, argv[3]),
(LCDColor)js2number(js, argv[4]));
return JS_UNDEFINED;
)
JSC_CCALL(gfx_fillRect,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
pd_gfx->fillRect((int)js2number(js, argv[0]), (int)js2number(js, argv[1]),
(int)js2number(js, argv[2]), (int)js2number(js, argv[3]),
(LCDColor)js2number(js, argv[4]));
return JS_UNDEFINED;
)
JSC_CCALL(gfx_fillTriangle,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
pd_gfx->fillTriangle((int)js2number(js, argv[0]), (int)js2number(js, argv[1]),
(int)js2number(js, argv[2]), (int)js2number(js, argv[3]),
(int)js2number(js, argv[4]), (int)js2number(js, argv[5]),
(LCDColor)js2number(js, argv[6]));
return JS_UNDEFINED;
)
JSC_CCALL(gfx_drawEllipse,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
pd_gfx->drawEllipse((int)js2number(js, argv[0]), (int)js2number(js, argv[1]),
(int)js2number(js, argv[2]), (int)js2number(js, argv[3]),
(int)js2number(js, argv[4]), (float)js2number(js, argv[5]),
(float)js2number(js, argv[6]), (LCDColor)js2number(js, argv[7]));
return JS_UNDEFINED;
)
JSC_CCALL(gfx_fillEllipse,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
pd_gfx->fillEllipse((int)js2number(js, argv[0]), (int)js2number(js, argv[1]),
(int)js2number(js, argv[2]), (int)js2number(js, argv[3]),
(float)js2number(js, argv[4]), (float)js2number(js, argv[5]),
(LCDColor)js2number(js, argv[6]));
return JS_UNDEFINED;
)
JSC_SCALL(gfx_drawText,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
int w = pd_gfx->drawText(str, strlen(str), kUTF8Encoding,
(int)js2number(js, argv[1]), (int)js2number(js, argv[2]));
ret = JS_NewInt32(js, w);
)
JSC_CCALL(gfx_drawScaledBitmap,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
LCDBitmap *bmp = js2bitmap(js, argv[0]);
if (!bmp) return JS_ThrowTypeError(js, "invalid bitmap");
pd_gfx->drawScaledBitmap(bmp, (int)js2number(js, argv[1]), (int)js2number(js, argv[2]),
(float)js2number(js, argv[3]), (float)js2number(js, argv[4]));
return JS_UNDEFINED;
)
JSC_CCALL(gfx_drawRotatedBitmap,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
LCDBitmap *bmp = js2bitmap(js, argv[0]);
if (!bmp) return JS_ThrowTypeError(js, "invalid bitmap");
pd_gfx->drawRotatedBitmap(bmp, (int)js2number(js, argv[1]), (int)js2number(js, argv[2]),
(float)js2number(js, argv[3]), (float)js2number(js, argv[4]),
(float)js2number(js, argv[5]), (float)js2number(js, argv[6]),
(float)js2number(js, argv[7]));
return JS_UNDEFINED;
)
JSC_CCALL(gfx_setPixel,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
pd_gfx->setPixel((int)js2number(js, argv[0]), (int)js2number(js, argv[1]),
(LCDColor)js2number(js, argv[2]));
return JS_UNDEFINED;
)
// --- Bitmap Functions ---
JSC_CCALL(gfx_newBitmap,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
LCDBitmap *bmp = pd_gfx->newBitmap((int)js2number(js, argv[0]), (int)js2number(js, argv[1]),
argc > 2 ? (LCDColor)js2number(js, argv[2]) : kColorWhite);
if (!bmp) return JS_ThrowInternalError(js, "failed to create bitmap");
return JS_NewInt64(js, (int64_t)(intptr_t)bmp);
)
JSC_CCALL(gfx_freeBitmap,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
LCDBitmap *bmp = js2bitmap(js, argv[0]);
if (bmp) pd_gfx->freeBitmap(bmp);
return JS_UNDEFINED;
)
JSC_SCALL(gfx_loadBitmap,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
const char *err = NULL;
LCDBitmap *bmp = pd_gfx->loadBitmap(str, &err);
if (!bmp) ret = JS_ThrowInternalError(js, "loadBitmap: %s", err ? err : "unknown");
else ret = JS_NewInt64(js, (int64_t)(intptr_t)bmp);
)
JSC_CCALL(gfx_copyBitmap,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
LCDBitmap *bmp = js2bitmap(js, argv[0]);
if (!bmp) return JS_ThrowTypeError(js, "invalid bitmap");
LCDBitmap *copy = pd_gfx->copyBitmap(bmp);
return copy ? JS_NewInt64(js, (int64_t)(intptr_t)copy) : JS_NULL;
)
JSC_CCALL(gfx_clearBitmap,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
LCDBitmap *bmp = js2bitmap(js, argv[0]);
if (!bmp) return JS_ThrowTypeError(js, "invalid bitmap");
pd_gfx->clearBitmap(bmp, argc > 1 ? (LCDColor)js2number(js, argv[1]) : kColorWhite);
return JS_UNDEFINED;
)
JSC_CCALL(gfx_getBitmapData,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
LCDBitmap *bmp = js2bitmap(js, argv[0]);
if (!bmp) return JS_ThrowTypeError(js, "invalid bitmap");
int w, h, rb; uint8_t *mask, *data;
pd_gfx->getBitmapData(bmp, &w, &h, &rb, &mask, &data);
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "width", JS_NewInt32(js, w));
JS_SetPropertyStr(js, obj, "height", JS_NewInt32(js, h));
JS_SetPropertyStr(js, obj, "rowbytes", JS_NewInt32(js, rb));
return obj;
)
// --- Font Functions ---
JSC_SCALL(gfx_loadFont,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
const char *err = NULL;
LCDFont *font = pd_gfx->loadFont(str, &err);
if (!font) ret = JS_ThrowInternalError(js, "loadFont: %s", err ? err : "unknown");
else ret = JS_NewInt64(js, (int64_t)(intptr_t)font);
)
JSC_CCALL(gfx_getFontHeight,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
LCDFont *font = js2font(js, argv[0]);
return JS_NewInt32(js, pd_gfx->getFontHeight(font));
)
JSC_SCALL(gfx_getTextWidth,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
LCDFont *font = argc > 1 ? js2font(js, argv[1]) : NULL;
int tracking = argc > 2 ? (int)js2number(js, argv[2]) : 0;
ret = JS_NewInt32(js, pd_gfx->getTextWidth(font, str, strlen(str), kUTF8Encoding, tracking));
)
// --- Framebuffer ---
JSC_CCALL(gfx_display,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
pd_gfx->display();
return JS_UNDEFINED;
)
JSC_CCALL(gfx_markUpdatedRows,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
pd_gfx->markUpdatedRows((int)js2number(js, argv[0]), (int)js2number(js, argv[1]));
return JS_UNDEFINED;
)
JSC_CCALL(gfx_copyFrameBufferBitmap,
if (!pd_gfx) return JS_ThrowInternalError(js, "graphics not initialized");
LCDBitmap *bmp = pd_gfx->copyFrameBufferBitmap();
return bmp ? JS_NewInt64(js, (int64_t)(intptr_t)bmp) : JS_NULL;
)
static const JSCFunctionListEntry js_gfx_funcs[] = {
MIST_FUNC_DEF(gfx, clear, 1),
MIST_FUNC_DEF(gfx, setBackgroundColor, 1),
MIST_FUNC_DEF(gfx, setDrawMode, 1),
MIST_FUNC_DEF(gfx, setDrawOffset, 2),
MIST_FUNC_DEF(gfx, setClipRect, 4),
MIST_FUNC_DEF(gfx, clearClipRect, 0),
MIST_FUNC_DEF(gfx, setLineCapStyle, 1),
MIST_FUNC_DEF(gfx, setFont, 1),
MIST_FUNC_DEF(gfx, setTextTracking, 1),
MIST_FUNC_DEF(gfx, getTextTracking, 0),
MIST_FUNC_DEF(gfx, pushContext, 1),
MIST_FUNC_DEF(gfx, popContext, 0),
MIST_FUNC_DEF(gfx, drawBitmap, 4),
MIST_FUNC_DEF(gfx, drawLine, 6),
MIST_FUNC_DEF(gfx, drawRect, 5),
MIST_FUNC_DEF(gfx, fillRect, 5),
MIST_FUNC_DEF(gfx, fillTriangle, 7),
MIST_FUNC_DEF(gfx, drawEllipse, 8),
MIST_FUNC_DEF(gfx, fillEllipse, 7),
MIST_FUNC_DEF(gfx, drawText, 3),
MIST_FUNC_DEF(gfx, drawScaledBitmap, 5),
MIST_FUNC_DEF(gfx, drawRotatedBitmap, 8),
MIST_FUNC_DEF(gfx, setPixel, 3),
MIST_FUNC_DEF(gfx, newBitmap, 3),
MIST_FUNC_DEF(gfx, freeBitmap, 1),
MIST_FUNC_DEF(gfx, loadBitmap, 1),
MIST_FUNC_DEF(gfx, copyBitmap, 1),
MIST_FUNC_DEF(gfx, clearBitmap, 2),
MIST_FUNC_DEF(gfx, getBitmapData, 1),
MIST_FUNC_DEF(gfx, loadFont, 1),
MIST_FUNC_DEF(gfx, getFontHeight, 1),
MIST_FUNC_DEF(gfx, getTextWidth, 3),
MIST_FUNC_DEF(gfx, display, 0),
MIST_FUNC_DEF(gfx, markUpdatedRows, 2),
MIST_FUNC_DEF(gfx, copyFrameBufferBitmap, 0),
};
JSValue js_gfx_use(JSContext *js) {
JSValue mod = JS_NewObject(js);
JS_SetPropertyFunctionList(js, mod, js_gfx_funcs, countof(js_gfx_funcs));
return mod;
}

202
playdate/json_playdate.c Normal file
View File

@@ -0,0 +1,202 @@
// json_playdate.c - Cell integration for Playdate JSON API
// Wraps pd_api_json.h functions for JavaScript access
#include "cell.h"
#include "common.h"
#include <string.h>
#include <stdlib.h>
// --- JSON Decoder Context ---
typedef struct {
JSContext *js;
JSValue result;
JSValue stack[32];
int stack_depth;
} JsonDecodeCtx;
static void json_decode_error(json_decoder *decoder, const char *error, int linenum) {
JsonDecodeCtx *ctx = (JsonDecodeCtx*)decoder->userdata;
ctx->result = JS_ThrowSyntaxError(ctx->js, "JSON parse error at line %d: %s", linenum, error);
}
static void json_decode_will_sublist(json_decoder *decoder, const char *name, json_value_type type) {
JsonDecodeCtx *ctx = (JsonDecodeCtx*)decoder->userdata;
JSValue container = (type == kJSONArray) ? JS_NewArray(ctx->js) : JS_NewObject(ctx->js);
if (ctx->stack_depth < 32) {
ctx->stack[ctx->stack_depth++] = container;
}
}
static void* json_decode_did_sublist(json_decoder *decoder, const char *name, json_value_type type) {
JsonDecodeCtx *ctx = (JsonDecodeCtx*)decoder->userdata;
if (ctx->stack_depth > 0) {
ctx->stack_depth--;
JSValue completed = ctx->stack[ctx->stack_depth];
if (ctx->stack_depth == 0) {
ctx->result = completed;
}
return NULL;
}
return NULL;
}
static void json_decode_table_value(json_decoder *decoder, const char *key, json_value value) {
JsonDecodeCtx *ctx = (JsonDecodeCtx*)decoder->userdata;
if (ctx->stack_depth <= 0) return;
JSValue container = ctx->stack[ctx->stack_depth - 1];
JSValue jsval;
switch (value.type) {
case kJSONNull: jsval = JS_NULL; break;
case kJSONTrue: jsval = JS_TRUE; break;
case kJSONFalse: jsval = JS_FALSE; break;
case kJSONInteger: jsval = JS_NewInt32(ctx->js, value.data.intval); break;
case kJSONFloat: jsval = JS_NewFloat64(ctx->js, value.data.floatval); break;
case kJSONString: jsval = JS_NewString(ctx->js, value.data.stringval); break;
case kJSONArray:
case kJSONTable:
if (ctx->stack_depth > 1) {
jsval = ctx->stack[ctx->stack_depth - 1];
} else {
jsval = JS_UNDEFINED;
}
break;
default: jsval = JS_UNDEFINED; break;
}
JS_SetPropertyStr(ctx->js, container, key, jsval);
}
static void json_decode_array_value(json_decoder *decoder, int pos, json_value value) {
JsonDecodeCtx *ctx = (JsonDecodeCtx*)decoder->userdata;
if (ctx->stack_depth <= 0) return;
JSValue container = ctx->stack[ctx->stack_depth - 1];
JSValue jsval;
switch (value.type) {
case kJSONNull: jsval = JS_NULL; break;
case kJSONTrue: jsval = JS_TRUE; break;
case kJSONFalse: jsval = JS_FALSE; break;
case kJSONInteger: jsval = JS_NewInt32(ctx->js, value.data.intval); break;
case kJSONFloat: jsval = JS_NewFloat64(ctx->js, value.data.floatval); break;
case kJSONString: jsval = JS_NewString(ctx->js, value.data.stringval); break;
default: jsval = JS_UNDEFINED; break;
}
JS_SetPropertyUint32(ctx->js, container, pos, jsval);
}
// --- JSON Encoder Context ---
typedef struct {
char *buffer;
size_t len;
size_t cap;
} JsonEncodeCtx;
static void json_encode_write(void *userdata, const char *str, int len) {
JsonEncodeCtx *ctx = (JsonEncodeCtx*)userdata;
if (ctx->len + len + 1 > ctx->cap) {
ctx->cap = (ctx->cap + len + 1) * 2;
ctx->buffer = realloc(ctx->buffer, ctx->cap);
}
memcpy(ctx->buffer + ctx->len, str, len);
ctx->len += len;
ctx->buffer[ctx->len] = '\0';
}
static void encode_js_value(json_encoder *enc, JSContext *js, JSValue val);
static void encode_js_object(json_encoder *enc, JSContext *js, JSValue obj) {
enc->startTable(enc);
JSPropertyEnum *props;
uint32_t len;
if (JS_GetOwnPropertyNames(js, &props, &len, obj, JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY) == 0) {
for (uint32_t i = 0; i < len; i++) {
const char *key = JS_AtomToCString(js, props[i].atom);
JSValue val = JS_GetProperty(js, obj, props[i].atom);
enc->addTableMember(enc, key, strlen(key));
encode_js_value(enc, js, val);
JS_FreeValue(js, val);
JS_FreeCString(js, key);
JS_FreeAtom(js, props[i].atom);
}
js_free(js, props);
}
enc->endTable(enc);
}
static void encode_js_array(json_encoder *enc, JSContext *js, JSValue arr) {
enc->startArray(enc);
JSValue lenVal = JS_GetPropertyStr(js, arr, "length");
int len = (int)js2number(js, lenVal);
JS_FreeValue(js, lenVal);
for (int i = 0; i < len; i++) {
enc->addArrayMember(enc);
JSValue val = JS_GetPropertyUint32(js, arr, i);
encode_js_value(enc, js, val);
JS_FreeValue(js, val);
}
enc->endArray(enc);
}
static void encode_js_value(json_encoder *enc, JSContext *js, JSValue val) {
if (JS_IsNull(val) || JS_IsUndefined(val)) {
enc->writeNull(enc);
} else if (JS_IsBool(val)) {
if (JS_ToBool(js, val)) enc->writeTrue(enc);
else enc->writeFalse(enc);
} else if (JS_IsNumber(val)) {
double d = js2number(js, val);
if (d == (int)d) enc->writeInt(enc, (int)d);
else enc->writeDouble(enc, d);
} else if (JS_IsString(val)) {
size_t len;
const char *str = JS_ToCStringLen(js, &len, val);
enc->writeString(enc, str, len);
JS_FreeCString(js, str);
} else if (JS_IsArray(js, val)) {
encode_js_array(enc, js, val);
} else if (JS_IsObject(val)) {
encode_js_object(enc, js, val);
} else {
enc->writeNull(enc);
}
}
// --- API Functions ---
JSC_SCALL(json_decodeString,
if (!pd_json) return JS_ThrowInternalError(js, "json not initialized");
JsonDecodeCtx ctx = { js, JS_UNDEFINED, {}, 0 };
json_decoder decoder = {0};
decoder.decodeError = json_decode_error;
decoder.willDecodeSublist = json_decode_will_sublist;
decoder.didDecodeSublist = json_decode_did_sublist;
decoder.didDecodeTableValue = json_decode_table_value;
decoder.didDecodeArrayValue = json_decode_array_value;
decoder.userdata = &ctx;
json_value outval;
pd_json->decodeString(&decoder, str, &outval);
ret = ctx.result;
)
JSC_CCALL(json_encode,
if (!pd_json) return JS_ThrowInternalError(js, "json not initialized");
JsonEncodeCtx ctx = { malloc(256), 0, 256 };
if (!ctx.buffer) return JS_ThrowInternalError(js, "malloc failed");
ctx.buffer[0] = '\0';
json_encoder enc;
int pretty = argc > 1 ? JS_ToBool(js, argv[1]) : 0;
pd_json->initEncoder(&enc, json_encode_write, &ctx, pretty);
encode_js_value(&enc, js, argv[0]);
JSValue result = JS_NewStringLen(js, ctx.buffer, ctx.len);
free(ctx.buffer);
return result;
)
static const JSCFunctionListEntry js_json_funcs[] = {
MIST_FUNC_DEF(json, decodeString, 1),
MIST_FUNC_DEF(json, encode, 2),
};
JSValue js_json_use(JSContext *js) {
JSValue mod = JS_NewObject(js);
JS_SetPropertyFunctionList(js, mod, js_json_funcs, countof(js_json_funcs));
return mod;
}

157
playdate/lua_playdate.c Normal file
View File

@@ -0,0 +1,157 @@
// lua_playdate.c - Cell integration for Playdate Lua API
// Wraps pd_api_lua.h functions for JavaScript access
// Note: This provides interop with Playdate's Lua runtime if needed
#include "cell.h"
#include "common.h"
#include <string.h>
// --- Lua API Functions ---
JSC_CCALL(lua_stop,
if (!pd_lua) return JS_ThrowInternalError(js, "lua not initialized");
pd_lua->stop();
return JS_UNDEFINED;
)
JSC_CCALL(lua_start,
if (!pd_lua) return JS_ThrowInternalError(js, "lua not initialized");
pd_lua->start();
return JS_UNDEFINED;
)
JSC_CCALL(lua_getArgCount,
if (!pd_lua) return JS_ThrowInternalError(js, "lua not initialized");
return JS_NewInt32(js, pd_lua->getArgCount());
)
JSC_CCALL(lua_getArgType,
if (!pd_lua) return JS_ThrowInternalError(js, "lua not initialized");
int pos = (int)js2number(js, argv[0]);
const char *outClass = NULL;
enum LuaType type = pd_lua->getArgType(pos, &outClass);
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "type", JS_NewInt32(js, type));
JS_SetPropertyStr(js, obj, "class", outClass ? JS_NewString(js, outClass) : JS_NULL);
return obj;
)
JSC_CCALL(lua_argIsNil,
if (!pd_lua) return JS_ThrowInternalError(js, "lua not initialized");
return JS_NewBool(js, pd_lua->argIsNil((int)js2number(js, argv[0])));
)
JSC_CCALL(lua_getArgBool,
if (!pd_lua) return JS_ThrowInternalError(js, "lua not initialized");
return JS_NewBool(js, pd_lua->getArgBool((int)js2number(js, argv[0])));
)
JSC_CCALL(lua_getArgInt,
if (!pd_lua) return JS_ThrowInternalError(js, "lua not initialized");
return JS_NewInt32(js, pd_lua->getArgInt((int)js2number(js, argv[0])));
)
JSC_CCALL(lua_getArgFloat,
if (!pd_lua) return JS_ThrowInternalError(js, "lua not initialized");
return JS_NewFloat64(js, pd_lua->getArgFloat((int)js2number(js, argv[0])));
)
JSC_CCALL(lua_getArgString,
if (!pd_lua) return JS_ThrowInternalError(js, "lua not initialized");
const char *str = pd_lua->getArgString((int)js2number(js, argv[0]));
return str ? JS_NewString(js, str) : JS_NULL;
)
JSC_CCALL(lua_getArgBytes,
if (!pd_lua) return JS_ThrowInternalError(js, "lua not initialized");
size_t len;
const char *bytes = pd_lua->getArgBytes((int)js2number(js, argv[0]), &len);
if (!bytes) return JS_NULL;
return js_new_blob_stoned_copy(js, bytes, len);
)
JSC_CCALL(lua_pushNil,
if (!pd_lua) return JS_ThrowInternalError(js, "lua not initialized");
pd_lua->pushNil();
return JS_UNDEFINED;
)
JSC_CCALL(lua_pushBool,
if (!pd_lua) return JS_ThrowInternalError(js, "lua not initialized");
pd_lua->pushBool(JS_ToBool(js, argv[0]));
return JS_UNDEFINED;
)
JSC_CCALL(lua_pushInt,
if (!pd_lua) return JS_ThrowInternalError(js, "lua not initialized");
pd_lua->pushInt((int)js2number(js, argv[0]));
return JS_UNDEFINED;
)
JSC_CCALL(lua_pushFloat,
if (!pd_lua) return JS_ThrowInternalError(js, "lua not initialized");
pd_lua->pushFloat((float)js2number(js, argv[0]));
return JS_UNDEFINED;
)
JSC_SCALL(lua_pushString,
if (!pd_lua) return JS_ThrowInternalError(js, "lua not initialized");
pd_lua->pushString(str);
)
JSC_CCALL(lua_pushBytes,
if (!pd_lua) return JS_ThrowInternalError(js, "lua not initialized");
size_t len;
const char *data = js_get_blob_data(js, &len, argv[0]);
if (data == (void*)-1) return JS_EXCEPTION;
pd_lua->pushBytes(data, len);
return JS_UNDEFINED;
)
JSC_SCALL(lua_callFunction,
if (!pd_lua) return JS_ThrowInternalError(js, "lua not initialized");
int nargs = argc > 1 ? (int)js2number(js, argv[1]) : 0;
const char *outerr = NULL;
int result = pd_lua->callFunction(str, nargs, &outerr);
if (result == 0 && outerr) {
ret = JS_ThrowInternalError(js, "Lua error: %s", outerr);
} else {
ret = JS_NewBool(js, result);
}
)
static const JSCFunctionListEntry js_lua_funcs[] = {
MIST_FUNC_DEF(lua, stop, 0),
MIST_FUNC_DEF(lua, start, 0),
MIST_FUNC_DEF(lua, getArgCount, 0),
MIST_FUNC_DEF(lua, getArgType, 1),
MIST_FUNC_DEF(lua, argIsNil, 1),
MIST_FUNC_DEF(lua, getArgBool, 1),
MIST_FUNC_DEF(lua, getArgInt, 1),
MIST_FUNC_DEF(lua, getArgFloat, 1),
MIST_FUNC_DEF(lua, getArgString, 1),
MIST_FUNC_DEF(lua, getArgBytes, 1),
MIST_FUNC_DEF(lua, pushNil, 0),
MIST_FUNC_DEF(lua, pushBool, 1),
MIST_FUNC_DEF(lua, pushInt, 1),
MIST_FUNC_DEF(lua, pushFloat, 1),
MIST_FUNC_DEF(lua, pushString, 1),
MIST_FUNC_DEF(lua, pushBytes, 1),
MIST_FUNC_DEF(lua, callFunction, 2),
};
JSValue js_lua_use(JSContext *js) {
JSValue mod = JS_NewObject(js);
JS_SetPropertyFunctionList(js, mod, js_lua_funcs, countof(js_lua_funcs));
// Export type constants
JS_SetPropertyStr(js, mod, "TYPE_NIL", JS_NewInt32(js, kTypeNil));
JS_SetPropertyStr(js, mod, "TYPE_BOOL", JS_NewInt32(js, kTypeBool));
JS_SetPropertyStr(js, mod, "TYPE_INT", JS_NewInt32(js, kTypeInt));
JS_SetPropertyStr(js, mod, "TYPE_FLOAT", JS_NewInt32(js, kTypeFloat));
JS_SetPropertyStr(js, mod, "TYPE_STRING", JS_NewInt32(js, kTypeString));
JS_SetPropertyStr(js, mod, "TYPE_TABLE", JS_NewInt32(js, kTypeTable));
JS_SetPropertyStr(js, mod, "TYPE_FUNCTION", JS_NewInt32(js, kTypeFunction));
JS_SetPropertyStr(js, mod, "TYPE_THREAD", JS_NewInt32(js, kTypeThread));
JS_SetPropertyStr(js, mod, "TYPE_OBJECT", JS_NewInt32(js, kTypeObject));
return mod;
}

290
playdate/network_playdate.c Normal file
View File

@@ -0,0 +1,290 @@
// network_playdate.c - Cell integration for Playdate Network API
// Wraps pd_api_network.h functions for JavaScript access
#include "cell.h"
#include "common.h"
#include <string.h>
#include <stdlib.h>
// --- Helpers ---
static HTTPConnection* js2http(JSContext *js, JSValueConst val) {
int64_t ptr;
if (JS_ToInt64(js, &ptr, val) < 0) return NULL;
return (HTTPConnection*)(intptr_t)ptr;
}
static TCPConnection* js2tcp(JSContext *js, JSValueConst val) {
int64_t ptr;
if (JS_ToInt64(js, &ptr, val) < 0) return NULL;
return (TCPConnection*)(intptr_t)ptr;
}
// --- Network Status ---
JSC_CCALL(network_getStatus,
if (!pd_network) return JS_ThrowInternalError(js, "network not initialized");
return JS_NewInt32(js, pd_network->getStatus());
)
JSC_CCALL(network_setEnabled,
if (!pd_network) return JS_ThrowInternalError(js, "network not initialized");
// Note: callback not implemented for simplicity
pd_network->setEnabled(JS_ToBool(js, argv[0]), NULL);
return JS_UNDEFINED;
)
// --- HTTP Functions ---
JSC_SCALL(http_newConnection,
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
int port = (int)js2number(js, argv[1]);
int usessl = argc > 2 ? JS_ToBool(js, argv[2]) : 0;
HTTPConnection *conn = pd_network->http->newConnection(str, port, usessl);
ret = conn ? JS_NewInt64(js, (int64_t)(intptr_t)conn) : JS_NULL;
)
JSC_CCALL(http_retain,
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
HTTPConnection *conn = js2http(js, argv[0]);
HTTPConnection *ret_conn = pd_network->http->retain(conn);
return ret_conn ? JS_NewInt64(js, (int64_t)(intptr_t)ret_conn) : JS_NULL;
)
JSC_CCALL(http_release,
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
HTTPConnection *conn = js2http(js, argv[0]);
if (conn) pd_network->http->release(conn);
return JS_UNDEFINED;
)
JSC_CCALL(http_setConnectTimeout,
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
pd_network->http->setConnectTimeout(js2http(js, argv[0]), (int)js2number(js, argv[1]));
return JS_UNDEFINED;
)
JSC_CCALL(http_setKeepAlive,
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
pd_network->http->setKeepAlive(js2http(js, argv[0]), JS_ToBool(js, argv[1]));
return JS_UNDEFINED;
)
JSC_CCALL(http_setByteRange,
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
pd_network->http->setByteRange(js2http(js, argv[0]), (int)js2number(js, argv[1]), (int)js2number(js, argv[2]));
return JS_UNDEFINED;
)
JSC_SCALL(http_get,
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
HTTPConnection *conn = js2http(js, argv[0]);
const char *headers = argc > 2 ? JS_ToCString(js, argv[2]) : NULL;
size_t hlen = headers ? strlen(headers) : 0;
PDNetErr err = pd_network->http->get(conn, str, headers, hlen);
if (headers) JS_FreeCString(js, headers);
ret = JS_NewInt32(js, err);
)
JSC_SCALL(http_post,
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
HTTPConnection *conn = js2http(js, argv[0]);
const char *headers = argc > 2 ? JS_ToCString(js, argv[2]) : NULL;
size_t hlen = headers ? strlen(headers) : 0;
size_t blen;
const char *body = argc > 3 ? js_get_blob_data(js, &blen, argv[3]) : NULL;
if (body == (void*)-1) body = NULL;
PDNetErr err = pd_network->http->post(conn, str, headers, hlen, body, body ? blen : 0);
if (headers) JS_FreeCString(js, headers);
ret = JS_NewInt32(js, err);
)
JSC_CCALL(http_getError,
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
return JS_NewInt32(js, pd_network->http->getError(js2http(js, argv[0])));
)
JSC_CCALL(http_getProgress,
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
int read, total;
pd_network->http->getProgress(js2http(js, argv[0]), &read, &total);
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "read", JS_NewInt32(js, read));
JS_SetPropertyStr(js, obj, "total", JS_NewInt32(js, total));
return obj;
)
JSC_CCALL(http_getResponseStatus,
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
return JS_NewInt32(js, pd_network->http->getResponseStatus(js2http(js, argv[0])));
)
JSC_CCALL(http_getBytesAvailable,
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
return JS_NewInt64(js, pd_network->http->getBytesAvailable(js2http(js, argv[0])));
)
JSC_CCALL(http_setReadTimeout,
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
pd_network->http->setReadTimeout(js2http(js, argv[0]), (int)js2number(js, argv[1]));
return JS_UNDEFINED;
)
JSC_CCALL(http_setReadBufferSize,
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
pd_network->http->setReadBufferSize(js2http(js, argv[0]), (int)js2number(js, argv[1]));
return JS_UNDEFINED;
)
JSC_CCALL(http_read,
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
HTTPConnection *conn = js2http(js, argv[0]);
unsigned int buflen = (unsigned int)js2number(js, argv[1]);
void *buf = malloc(buflen);
if (!buf) return JS_ThrowInternalError(js, "malloc failed");
int read = pd_network->http->read(conn, buf, buflen);
if (read < 0) {
free(buf);
return JS_NULL;
}
JSValue blob = js_new_blob_stoned_copy(js, buf, read);
free(buf);
return blob;
)
JSC_CCALL(http_close,
if (!pd_network || !pd_network->http) return JS_ThrowInternalError(js, "network not initialized");
pd_network->http->close(js2http(js, argv[0]));
return JS_UNDEFINED;
)
// --- TCP Functions ---
JSC_SCALL(tcp_newConnection,
if (!pd_network || !pd_network->tcp) return JS_ThrowInternalError(js, "network not initialized");
int port = (int)js2number(js, argv[1]);
int usessl = argc > 2 ? JS_ToBool(js, argv[2]) : 0;
TCPConnection *conn = pd_network->tcp->newConnection(str, port, usessl);
ret = conn ? JS_NewInt64(js, (int64_t)(intptr_t)conn) : JS_NULL;
)
JSC_CCALL(tcp_retain,
if (!pd_network || !pd_network->tcp) return JS_ThrowInternalError(js, "network not initialized");
TCPConnection *conn = js2tcp(js, argv[0]);
TCPConnection *ret_conn = pd_network->tcp->retain(conn);
return ret_conn ? JS_NewInt64(js, (int64_t)(intptr_t)ret_conn) : JS_NULL;
)
JSC_CCALL(tcp_release,
if (!pd_network || !pd_network->tcp) return JS_ThrowInternalError(js, "network not initialized");
TCPConnection *conn = js2tcp(js, argv[0]);
if (conn) pd_network->tcp->release(conn);
return JS_UNDEFINED;
)
JSC_CCALL(tcp_getError,
if (!pd_network || !pd_network->tcp) return JS_ThrowInternalError(js, "network not initialized");
return JS_NewInt32(js, pd_network->tcp->getError(js2tcp(js, argv[0])));
)
JSC_CCALL(tcp_setConnectTimeout,
if (!pd_network || !pd_network->tcp) return JS_ThrowInternalError(js, "network not initialized");
pd_network->tcp->setConnectTimeout(js2tcp(js, argv[0]), (int)js2number(js, argv[1]));
return JS_UNDEFINED;
)
JSC_CCALL(tcp_close,
if (!pd_network || !pd_network->tcp) return JS_ThrowInternalError(js, "network not initialized");
return JS_NewInt32(js, pd_network->tcp->close(js2tcp(js, argv[0])));
)
JSC_CCALL(tcp_setReadTimeout,
if (!pd_network || !pd_network->tcp) return JS_ThrowInternalError(js, "network not initialized");
pd_network->tcp->setReadTimeout(js2tcp(js, argv[0]), (int)js2number(js, argv[1]));
return JS_UNDEFINED;
)
JSC_CCALL(tcp_setReadBufferSize,
if (!pd_network || !pd_network->tcp) return JS_ThrowInternalError(js, "network not initialized");
pd_network->tcp->setReadBufferSize(js2tcp(js, argv[0]), (int)js2number(js, argv[1]));
return JS_UNDEFINED;
)
JSC_CCALL(tcp_getBytesAvailable,
if (!pd_network || !pd_network->tcp) return JS_ThrowInternalError(js, "network not initialized");
return JS_NewInt64(js, pd_network->tcp->getBytesAvailable(js2tcp(js, argv[0])));
)
JSC_CCALL(tcp_read,
if (!pd_network || !pd_network->tcp) return JS_ThrowInternalError(js, "network not initialized");
TCPConnection *conn = js2tcp(js, argv[0]);
size_t len = (size_t)js2number(js, argv[1]);
void *buf = malloc(len);
if (!buf) return JS_ThrowInternalError(js, "malloc failed");
int read = pd_network->tcp->read(conn, buf, len);
if (read < 0) {
free(buf);
return JS_NewInt32(js, read); // Return error code
}
JSValue blob = js_new_blob_stoned_copy(js, buf, read);
free(buf);
return blob;
)
JSC_CCALL(tcp_write,
if (!pd_network || !pd_network->tcp) return JS_ThrowInternalError(js, "network not initialized");
TCPConnection *conn = js2tcp(js, argv[0]);
size_t len;
const void *data = js_get_blob_data(js, &len, argv[1]);
if (data == (void*)-1) return JS_EXCEPTION;
return JS_NewInt32(js, pd_network->tcp->write(conn, data, len));
)
static const JSCFunctionListEntry js_network_funcs[] = {
MIST_FUNC_DEF(network, getStatus, 0),
MIST_FUNC_DEF(network, setEnabled, 1),
// HTTP
MIST_FUNC_DEF(http, newConnection, 3),
MIST_FUNC_DEF(http, retain, 1),
MIST_FUNC_DEF(http, release, 1),
MIST_FUNC_DEF(http, setConnectTimeout, 2),
MIST_FUNC_DEF(http, setKeepAlive, 2),
MIST_FUNC_DEF(http, setByteRange, 3),
MIST_FUNC_DEF(http, get, 3),
MIST_FUNC_DEF(http, post, 4),
MIST_FUNC_DEF(http, getError, 1),
MIST_FUNC_DEF(http, getProgress, 1),
MIST_FUNC_DEF(http, getResponseStatus, 1),
MIST_FUNC_DEF(http, getBytesAvailable, 1),
MIST_FUNC_DEF(http, setReadTimeout, 2),
MIST_FUNC_DEF(http, setReadBufferSize, 2),
MIST_FUNC_DEF(http, read, 2),
MIST_FUNC_DEF(http, close, 1),
// TCP
MIST_FUNC_DEF(tcp, newConnection, 3),
MIST_FUNC_DEF(tcp, retain, 1),
MIST_FUNC_DEF(tcp, release, 1),
MIST_FUNC_DEF(tcp, getError, 1),
MIST_FUNC_DEF(tcp, setConnectTimeout, 2),
MIST_FUNC_DEF(tcp, close, 1),
MIST_FUNC_DEF(tcp, setReadTimeout, 2),
MIST_FUNC_DEF(tcp, setReadBufferSize, 2),
MIST_FUNC_DEF(tcp, getBytesAvailable, 1),
MIST_FUNC_DEF(tcp, read, 2),
MIST_FUNC_DEF(tcp, write, 2),
};
JSValue js_network_use(JSContext *js) {
JSValue mod = JS_NewObject(js);
JS_SetPropertyFunctionList(js, mod, js_network_funcs, countof(js_network_funcs));
// Export constants
JS_SetPropertyStr(js, mod, "NET_OK", JS_NewInt32(js, NET_OK));
JS_SetPropertyStr(js, mod, "NET_NO_DEVICE", JS_NewInt32(js, NET_NO_DEVICE));
JS_SetPropertyStr(js, mod, "NET_BUSY", JS_NewInt32(js, NET_BUSY));
JS_SetPropertyStr(js, mod, "NET_WRITE_ERROR", JS_NewInt32(js, NET_WRITE_ERROR));
JS_SetPropertyStr(js, mod, "NET_READ_ERROR", JS_NewInt32(js, NET_READ_ERROR));
JS_SetPropertyStr(js, mod, "NET_CONNECTION_CLOSED", JS_NewInt32(js, NET_CONNECTION_CLOSED));
JS_SetPropertyStr(js, mod, "WIFI_NOT_CONNECTED", JS_NewInt32(js, kWifiNotConnected));
JS_SetPropertyStr(js, mod, "WIFI_CONNECTED", JS_NewInt32(js, kWifiConnected));
JS_SetPropertyStr(js, mod, "WIFI_NOT_AVAILABLE", JS_NewInt32(js, kWifiNotAvailable));
return mod;
}

View File

@@ -0,0 +1,176 @@
// scoreboards_playdate.c - Cell integration for Playdate Scoreboards API
// Wraps pd_api_scoreboards.h functions for JavaScript access
#include "cell.h"
#include "common.h"
#include <string.h>
// --- Callback Contexts ---
// Note: These callbacks are async. For simplicity, we store results globally.
// A more robust implementation would use promises or callback registration.
static JSContext *g_scoreboard_js = NULL;
static JSValue g_add_score_callback = JS_UNDEFINED;
static JSValue g_personal_best_callback = JS_UNDEFINED;
static JSValue g_boards_list_callback = JS_UNDEFINED;
static JSValue g_scores_callback = JS_UNDEFINED;
static JSValue score_to_js(JSContext *js, PDScore *score) {
if (!score) return JS_NULL;
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "rank", JS_NewInt64(js, score->rank));
JS_SetPropertyStr(js, obj, "value", JS_NewInt64(js, score->value));
JS_SetPropertyStr(js, obj, "player", score->player ? JS_NewString(js, score->player) : JS_NULL);
return obj;
}
static void add_score_cb(PDScore *score, const char *errorMessage) {
if (!g_scoreboard_js || JS_IsUndefined(g_add_score_callback)) return;
JSValue args[2];
args[0] = score_to_js(g_scoreboard_js, score);
args[1] = errorMessage ? JS_NewString(g_scoreboard_js, errorMessage) : JS_NULL;
JSValue ret = JS_Call(g_scoreboard_js, g_add_score_callback, JS_UNDEFINED, 2, args);
JS_FreeValue(g_scoreboard_js, ret);
JS_FreeValue(g_scoreboard_js, args[0]);
JS_FreeValue(g_scoreboard_js, args[1]);
}
static void personal_best_cb(PDScore *score, const char *errorMessage) {
if (!g_scoreboard_js || JS_IsUndefined(g_personal_best_callback)) return;
JSValue args[2];
args[0] = score_to_js(g_scoreboard_js, score);
args[1] = errorMessage ? JS_NewString(g_scoreboard_js, errorMessage) : JS_NULL;
JSValue ret = JS_Call(g_scoreboard_js, g_personal_best_callback, JS_UNDEFINED, 2, args);
JS_FreeValue(g_scoreboard_js, ret);
JS_FreeValue(g_scoreboard_js, args[0]);
JS_FreeValue(g_scoreboard_js, args[1]);
}
static void boards_list_cb(PDBoardsList *boards, const char *errorMessage) {
if (!g_scoreboard_js || JS_IsUndefined(g_boards_list_callback)) return;
JSValue args[2];
if (boards) {
JSValue arr = JS_NewArray(g_scoreboard_js);
for (unsigned int i = 0; i < boards->count; i++) {
JSValue board = JS_NewObject(g_scoreboard_js);
JS_SetPropertyStr(g_scoreboard_js, board, "boardID",
boards->boards[i].boardID ? JS_NewString(g_scoreboard_js, boards->boards[i].boardID) : JS_NULL);
JS_SetPropertyStr(g_scoreboard_js, board, "name",
boards->boards[i].name ? JS_NewString(g_scoreboard_js, boards->boards[i].name) : JS_NULL);
JS_SetPropertyUint32(g_scoreboard_js, arr, i, board);
}
args[0] = arr;
} else {
args[0] = JS_NULL;
}
args[1] = errorMessage ? JS_NewString(g_scoreboard_js, errorMessage) : JS_NULL;
JSValue ret = JS_Call(g_scoreboard_js, g_boards_list_callback, JS_UNDEFINED, 2, args);
JS_FreeValue(g_scoreboard_js, ret);
JS_FreeValue(g_scoreboard_js, args[0]);
JS_FreeValue(g_scoreboard_js, args[1]);
}
static void scores_cb(PDScoresList *scores, const char *errorMessage) {
if (!g_scoreboard_js || JS_IsUndefined(g_scores_callback)) return;
JSValue args[2];
if (scores) {
JSValue obj = JS_NewObject(g_scoreboard_js);
JS_SetPropertyStr(g_scoreboard_js, obj, "boardID",
scores->boardID ? JS_NewString(g_scoreboard_js, scores->boardID) : JS_NULL);
JS_SetPropertyStr(g_scoreboard_js, obj, "count", JS_NewInt32(g_scoreboard_js, scores->count));
JS_SetPropertyStr(g_scoreboard_js, obj, "lastUpdated", JS_NewInt64(g_scoreboard_js, scores->lastUpdated));
JS_SetPropertyStr(g_scoreboard_js, obj, "playerIncluded", JS_NewBool(g_scoreboard_js, scores->playerIncluded));
JS_SetPropertyStr(g_scoreboard_js, obj, "limit", JS_NewInt32(g_scoreboard_js, scores->limit));
JSValue arr = JS_NewArray(g_scoreboard_js);
for (unsigned int i = 0; i < scores->count; i++) {
JS_SetPropertyUint32(g_scoreboard_js, arr, i, score_to_js(g_scoreboard_js, &scores->scores[i]));
}
JS_SetPropertyStr(g_scoreboard_js, obj, "scores", arr);
args[0] = obj;
} else {
args[0] = JS_NULL;
}
args[1] = errorMessage ? JS_NewString(g_scoreboard_js, errorMessage) : JS_NULL;
JSValue ret = JS_Call(g_scoreboard_js, g_scores_callback, JS_UNDEFINED, 2, args);
JS_FreeValue(g_scoreboard_js, ret);
JS_FreeValue(g_scoreboard_js, args[0]);
JS_FreeValue(g_scoreboard_js, args[1]);
}
// --- API Functions ---
JSC_SCALL(scoreboards_addScore,
if (!pd_scoreboards) return JS_ThrowInternalError(js, "scoreboards not initialized");
uint32_t value = (uint32_t)js2number(js, argv[1]);
if (argc > 2 && JS_IsFunction(js, argv[2])) {
g_scoreboard_js = js;
JS_FreeValue(js, g_add_score_callback);
g_add_score_callback = JS_DupValue(js, argv[2]);
}
ret = JS_NewBool(js, pd_scoreboards->addScore(str, value, add_score_cb));
)
JSC_SCALL(scoreboards_getPersonalBest,
if (!pd_scoreboards) return JS_ThrowInternalError(js, "scoreboards not initialized");
if (argc > 1 && JS_IsFunction(js, argv[1])) {
g_scoreboard_js = js;
JS_FreeValue(js, g_personal_best_callback);
g_personal_best_callback = JS_DupValue(js, argv[1]);
}
ret = JS_NewBool(js, pd_scoreboards->getPersonalBest(str, personal_best_cb));
)
JSC_CCALL(scoreboards_freeScore,
if (!pd_scoreboards) return JS_ThrowInternalError(js, "scoreboards not initialized");
// Note: PDScore from callbacks is managed by Playdate, this is for user-allocated scores
// In practice, JS doesn't allocate PDScore directly, so this is a no-op wrapper
return JS_UNDEFINED;
)
JSC_CCALL(scoreboards_getScoreboards,
if (!pd_scoreboards) return JS_ThrowInternalError(js, "scoreboards not initialized");
if (argc > 0 && JS_IsFunction(js, argv[0])) {
g_scoreboard_js = js;
JS_FreeValue(js, g_boards_list_callback);
g_boards_list_callback = JS_DupValue(js, argv[0]);
}
return JS_NewBool(js, pd_scoreboards->getScoreboards(boards_list_cb));
)
JSC_CCALL(scoreboards_freeBoardsList,
if (!pd_scoreboards) return JS_ThrowInternalError(js, "scoreboards not initialized");
// Managed by Playdate after callback
return JS_UNDEFINED;
)
JSC_SCALL(scoreboards_getScores,
if (!pd_scoreboards) return JS_ThrowInternalError(js, "scoreboards not initialized");
if (argc > 1 && JS_IsFunction(js, argv[1])) {
g_scoreboard_js = js;
JS_FreeValue(js, g_scores_callback);
g_scores_callback = JS_DupValue(js, argv[1]);
}
ret = JS_NewBool(js, pd_scoreboards->getScores(str, scores_cb));
)
JSC_CCALL(scoreboards_freeScoresList,
if (!pd_scoreboards) return JS_ThrowInternalError(js, "scoreboards not initialized");
// Managed by Playdate after callback
return JS_UNDEFINED;
)
static const JSCFunctionListEntry js_scoreboards_funcs[] = {
MIST_FUNC_DEF(scoreboards, addScore, 3),
MIST_FUNC_DEF(scoreboards, getPersonalBest, 2),
MIST_FUNC_DEF(scoreboards, freeScore, 1),
MIST_FUNC_DEF(scoreboards, getScoreboards, 1),
MIST_FUNC_DEF(scoreboards, freeBoardsList, 1),
MIST_FUNC_DEF(scoreboards, getScores, 2),
MIST_FUNC_DEF(scoreboards, freeScoresList, 1),
};
JSValue js_scoreboards_use(JSContext *js) {
JSValue mod = JS_NewObject(js);
JS_SetPropertyFunctionList(js, mod, js_scoreboards_funcs, countof(js_scoreboards_funcs));
return mod;
}

448
playdate/sound_playdate.c Normal file
View File

@@ -0,0 +1,448 @@
// sound_playdate.c - Cell integration for Playdate Sound API
// Wraps pd_api_sound.h functions for JavaScript access
#include "cell.h"
#include "common.h"
// --- Helpers ---
static FilePlayer* js2fileplayer(JSContext *js, JSValueConst val) {
int64_t ptr; if (JS_ToInt64(js, &ptr, val) < 0) return NULL;
return (FilePlayer*)(intptr_t)ptr;
}
static SamplePlayer* js2sampleplayer(JSContext *js, JSValueConst val) {
int64_t ptr; if (JS_ToInt64(js, &ptr, val) < 0) return NULL;
return (SamplePlayer*)(intptr_t)ptr;
}
static AudioSample* js2sample(JSContext *js, JSValueConst val) {
int64_t ptr; if (JS_ToInt64(js, &ptr, val) < 0) return NULL;
return (AudioSample*)(intptr_t)ptr;
}
static PDSynth* js2synth(JSContext *js, JSValueConst val) {
int64_t ptr; if (JS_ToInt64(js, &ptr, val) < 0) return NULL;
return (PDSynth*)(intptr_t)ptr;
}
static SoundChannel* js2channel(JSContext *js, JSValueConst val) {
int64_t ptr; if (JS_ToInt64(js, &ptr, val) < 0) return NULL;
return (SoundChannel*)(intptr_t)ptr;
}
// --- Global ---
JSC_CCALL(sound_getCurrentTime,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
return JS_NewInt64(js, pd_sound->getCurrentTime());
)
JSC_CCALL(sound_getDefaultChannel,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
SoundChannel *ch = pd_sound->getDefaultChannel();
return ch ? JS_NewInt64(js, (int64_t)(intptr_t)ch) : JS_NULL;
)
JSC_CCALL(sound_addChannel,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
return JS_NewBool(js, pd_sound->addChannel(js2channel(js, argv[0])));
)
JSC_CCALL(sound_removeChannel,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
return JS_NewBool(js, pd_sound->removeChannel(js2channel(js, argv[0])));
)
JSC_CCALL(sound_setOutputsActive,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
pd_sound->setOutputsActive(JS_ToBool(js, argv[0]), JS_ToBool(js, argv[1]));
return JS_UNDEFINED;
)
JSC_CCALL(sound_getError,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
const char *err = pd_sound->getError();
return err ? JS_NewString(js, err) : JS_NULL;
)
// --- FilePlayer ---
JSC_CCALL(sound_newFilePlayer,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
FilePlayer *p = pd_sound->fileplayer->newPlayer();
return p ? JS_NewInt64(js, (int64_t)(intptr_t)p) : JS_NULL;
)
JSC_CCALL(sound_freeFilePlayer,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
FilePlayer *p = js2fileplayer(js, argv[0]);
if (p) pd_sound->fileplayer->freePlayer(p);
return JS_UNDEFINED;
)
JSC_SCALL(sound_loadIntoFilePlayer,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
FilePlayer *p = js2fileplayer(js, argv[0]);
ret = JS_NewBool(js, pd_sound->fileplayer->loadIntoPlayer(p, str));
)
JSC_CCALL(sound_filePlayerPlay,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
FilePlayer *p = js2fileplayer(js, argv[0]);
int repeat = argc > 1 ? (int)js2number(js, argv[1]) : 1;
return JS_NewBool(js, pd_sound->fileplayer->play(p, repeat));
)
JSC_CCALL(sound_filePlayerIsPlaying,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
return JS_NewBool(js, pd_sound->fileplayer->isPlaying(js2fileplayer(js, argv[0])));
)
JSC_CCALL(sound_filePlayerPause,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
pd_sound->fileplayer->pause(js2fileplayer(js, argv[0]));
return JS_UNDEFINED;
)
JSC_CCALL(sound_filePlayerStop,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
pd_sound->fileplayer->stop(js2fileplayer(js, argv[0]));
return JS_UNDEFINED;
)
JSC_CCALL(sound_filePlayerSetVolume,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
pd_sound->fileplayer->setVolume(js2fileplayer(js, argv[0]), (float)js2number(js, argv[1]), (float)js2number(js, argv[2]));
return JS_UNDEFINED;
)
JSC_CCALL(sound_filePlayerGetVolume,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
float l, r; pd_sound->fileplayer->getVolume(js2fileplayer(js, argv[0]), &l, &r);
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "left", JS_NewFloat64(js, l));
JS_SetPropertyStr(js, obj, "right", JS_NewFloat64(js, r));
return obj;
)
JSC_CCALL(sound_filePlayerGetLength,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
return JS_NewFloat64(js, pd_sound->fileplayer->getLength(js2fileplayer(js, argv[0])));
)
JSC_CCALL(sound_filePlayerSetOffset,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
pd_sound->fileplayer->setOffset(js2fileplayer(js, argv[0]), (float)js2number(js, argv[1]));
return JS_UNDEFINED;
)
JSC_CCALL(sound_filePlayerGetOffset,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
return JS_NewFloat64(js, pd_sound->fileplayer->getOffset(js2fileplayer(js, argv[0])));
)
JSC_CCALL(sound_filePlayerSetRate,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
pd_sound->fileplayer->setRate(js2fileplayer(js, argv[0]), (float)js2number(js, argv[1]));
return JS_UNDEFINED;
)
JSC_CCALL(sound_filePlayerGetRate,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
return JS_NewFloat64(js, pd_sound->fileplayer->getRate(js2fileplayer(js, argv[0])));
)
JSC_CCALL(sound_filePlayerSetLoopRange,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
pd_sound->fileplayer->setLoopRange(js2fileplayer(js, argv[0]), (float)js2number(js, argv[1]), (float)js2number(js, argv[2]));
return JS_UNDEFINED;
)
JSC_CCALL(sound_filePlayerDidUnderrun,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
return JS_NewBool(js, pd_sound->fileplayer->didUnderrun(js2fileplayer(js, argv[0])));
)
JSC_CCALL(sound_filePlayerSetStopOnUnderrun,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
pd_sound->fileplayer->setStopOnUnderrun(js2fileplayer(js, argv[0]), JS_ToBool(js, argv[1]));
return JS_UNDEFINED;
)
JSC_CCALL(sound_filePlayerSetBufferLength,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
pd_sound->fileplayer->setBufferLength(js2fileplayer(js, argv[0]), (float)js2number(js, argv[1]));
return JS_UNDEFINED;
)
// --- Sample ---
JSC_SCALL(sound_loadSample,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
AudioSample *s = pd_sound->sample->load(str);
ret = s ? JS_NewInt64(js, (int64_t)(intptr_t)s) : JS_NULL;
)
JSC_CCALL(sound_freeSample,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
AudioSample *s = js2sample(js, argv[0]);
if (s) pd_sound->sample->freeSample(s);
return JS_UNDEFINED;
)
JSC_CCALL(sound_getSampleLength,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
return JS_NewFloat64(js, pd_sound->sample->getLength(js2sample(js, argv[0])));
)
JSC_CCALL(sound_newSampleBuffer,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
AudioSample *s = pd_sound->sample->newSampleBuffer((int)js2number(js, argv[0]));
return s ? JS_NewInt64(js, (int64_t)(intptr_t)s) : JS_NULL;
)
// --- SamplePlayer ---
JSC_CCALL(sound_newSamplePlayer,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
SamplePlayer *p = pd_sound->sampleplayer->newPlayer();
return p ? JS_NewInt64(js, (int64_t)(intptr_t)p) : JS_NULL;
)
JSC_CCALL(sound_freeSamplePlayer,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
SamplePlayer *p = js2sampleplayer(js, argv[0]);
if (p) pd_sound->sampleplayer->freePlayer(p);
return JS_UNDEFINED;
)
JSC_CCALL(sound_samplePlayerSetSample,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
pd_sound->sampleplayer->setSample(js2sampleplayer(js, argv[0]), js2sample(js, argv[1]));
return JS_UNDEFINED;
)
JSC_CCALL(sound_samplePlayerPlay,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
SamplePlayer *p = js2sampleplayer(js, argv[0]);
int repeat = argc > 1 ? (int)js2number(js, argv[1]) : 1;
float rate = argc > 2 ? (float)js2number(js, argv[2]) : 1.0f;
return JS_NewBool(js, pd_sound->sampleplayer->play(p, repeat, rate));
)
JSC_CCALL(sound_samplePlayerIsPlaying,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
return JS_NewBool(js, pd_sound->sampleplayer->isPlaying(js2sampleplayer(js, argv[0])));
)
JSC_CCALL(sound_samplePlayerStop,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
pd_sound->sampleplayer->stop(js2sampleplayer(js, argv[0]));
return JS_UNDEFINED;
)
JSC_CCALL(sound_samplePlayerSetVolume,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
pd_sound->sampleplayer->setVolume(js2sampleplayer(js, argv[0]), (float)js2number(js, argv[1]), (float)js2number(js, argv[2]));
return JS_UNDEFINED;
)
JSC_CCALL(sound_samplePlayerGetVolume,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
float l, r; pd_sound->sampleplayer->getVolume(js2sampleplayer(js, argv[0]), &l, &r);
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "left", JS_NewFloat64(js, l));
JS_SetPropertyStr(js, obj, "right", JS_NewFloat64(js, r));
return obj;
)
JSC_CCALL(sound_samplePlayerGetLength,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
return JS_NewFloat64(js, pd_sound->sampleplayer->getLength(js2sampleplayer(js, argv[0])));
)
JSC_CCALL(sound_samplePlayerSetOffset,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
pd_sound->sampleplayer->setOffset(js2sampleplayer(js, argv[0]), (float)js2number(js, argv[1]));
return JS_UNDEFINED;
)
JSC_CCALL(sound_samplePlayerGetOffset,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
return JS_NewFloat64(js, pd_sound->sampleplayer->getOffset(js2sampleplayer(js, argv[0])));
)
JSC_CCALL(sound_samplePlayerSetRate,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
pd_sound->sampleplayer->setRate(js2sampleplayer(js, argv[0]), (float)js2number(js, argv[1]));
return JS_UNDEFINED;
)
JSC_CCALL(sound_samplePlayerGetRate,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
return JS_NewFloat64(js, pd_sound->sampleplayer->getRate(js2sampleplayer(js, argv[0])));
)
JSC_CCALL(sound_samplePlayerSetPlayRange,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
pd_sound->sampleplayer->setPlayRange(js2sampleplayer(js, argv[0]), (int)js2number(js, argv[1]), (int)js2number(js, argv[2]));
return JS_UNDEFINED;
)
JSC_CCALL(sound_samplePlayerSetPaused,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
pd_sound->sampleplayer->setPaused(js2sampleplayer(js, argv[0]), JS_ToBool(js, argv[1]));
return JS_UNDEFINED;
)
// --- Synth ---
JSC_CCALL(sound_newSynth,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
PDSynth *s = pd_sound->synth->newSynth();
return s ? JS_NewInt64(js, (int64_t)(intptr_t)s) : JS_NULL;
)
JSC_CCALL(sound_freeSynth,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
PDSynth *s = js2synth(js, argv[0]);
if (s) pd_sound->synth->freeSynth(s);
return JS_UNDEFINED;
)
JSC_CCALL(sound_synthSetWaveform,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
pd_sound->synth->setWaveform(js2synth(js, argv[0]), (SoundWaveform)(int)js2number(js, argv[1]));
return JS_UNDEFINED;
)
JSC_CCALL(sound_synthSetAttackTime,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
pd_sound->synth->setAttackTime(js2synth(js, argv[0]), (float)js2number(js, argv[1]));
return JS_UNDEFINED;
)
JSC_CCALL(sound_synthSetDecayTime,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
pd_sound->synth->setDecayTime(js2synth(js, argv[0]), (float)js2number(js, argv[1]));
return JS_UNDEFINED;
)
JSC_CCALL(sound_synthSetSustainLevel,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
pd_sound->synth->setSustainLevel(js2synth(js, argv[0]), (float)js2number(js, argv[1]));
return JS_UNDEFINED;
)
JSC_CCALL(sound_synthSetReleaseTime,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
pd_sound->synth->setReleaseTime(js2synth(js, argv[0]), (float)js2number(js, argv[1]));
return JS_UNDEFINED;
)
JSC_CCALL(sound_synthSetTranspose,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
pd_sound->synth->setTranspose(js2synth(js, argv[0]), (float)js2number(js, argv[1]));
return JS_UNDEFINED;
)
JSC_CCALL(sound_synthPlayNote,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
PDSynth *s = js2synth(js, argv[0]);
float freq = (float)js2number(js, argv[1]);
float vel = argc > 2 ? (float)js2number(js, argv[2]) : 1.0f;
float len = argc > 3 ? (float)js2number(js, argv[3]) : -1.0f;
uint32_t when = argc > 4 ? (uint32_t)js2number(js, argv[4]) : 0;
pd_sound->synth->playNote(s, freq, vel, len, when);
return JS_UNDEFINED;
)
JSC_CCALL(sound_synthPlayMIDINote,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
PDSynth *s = js2synth(js, argv[0]);
MIDINote note = (MIDINote)js2number(js, argv[1]);
float vel = argc > 2 ? (float)js2number(js, argv[2]) : 1.0f;
float len = argc > 3 ? (float)js2number(js, argv[3]) : -1.0f;
uint32_t when = argc > 4 ? (uint32_t)js2number(js, argv[4]) : 0;
pd_sound->synth->playMIDINote(s, note, vel, len, when);
return JS_UNDEFINED;
)
JSC_CCALL(sound_synthNoteOff,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
pd_sound->synth->noteOff(js2synth(js, argv[0]), argc > 1 ? (uint32_t)js2number(js, argv[1]) : 0);
return JS_UNDEFINED;
)
JSC_CCALL(sound_synthStop,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
pd_sound->synth->stop(js2synth(js, argv[0]));
return JS_UNDEFINED;
)
JSC_CCALL(sound_synthSetVolume,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
pd_sound->synth->setVolume(js2synth(js, argv[0]), (float)js2number(js, argv[1]), (float)js2number(js, argv[2]));
return JS_UNDEFINED;
)
JSC_CCALL(sound_synthGetVolume,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
float l, r; pd_sound->synth->getVolume(js2synth(js, argv[0]), &l, &r);
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "left", JS_NewFloat64(js, l));
JS_SetPropertyStr(js, obj, "right", JS_NewFloat64(js, r));
return obj;
)
JSC_CCALL(sound_synthIsPlaying,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
return JS_NewBool(js, pd_sound->synth->isPlaying(js2synth(js, argv[0])));
)
JSC_CCALL(sound_synthGetParameterCount,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
return JS_NewInt32(js, pd_sound->synth->getParameterCount(js2synth(js, argv[0])));
)
JSC_CCALL(sound_synthSetParameter,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
return JS_NewBool(js, pd_sound->synth->setParameter(js2synth(js, argv[0]), (int)js2number(js, argv[1]), (float)js2number(js, argv[2])));
)
// --- Channel ---
JSC_CCALL(sound_newChannel,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
SoundChannel *ch = pd_sound->channel->newChannel();
return ch ? JS_NewInt64(js, (int64_t)(intptr_t)ch) : JS_NULL;
)
JSC_CCALL(sound_freeChannel,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
SoundChannel *ch = js2channel(js, argv[0]);
if (ch) pd_sound->channel->freeChannel(ch);
return JS_UNDEFINED;
)
JSC_CCALL(sound_channelSetVolume,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
pd_sound->channel->setVolume(js2channel(js, argv[0]), (float)js2number(js, argv[1]));
return JS_UNDEFINED;
)
JSC_CCALL(sound_channelGetVolume,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
return JS_NewFloat64(js, pd_sound->channel->getVolume(js2channel(js, argv[0])));
)
JSC_CCALL(sound_channelSetPan,
if (!pd_sound) return JS_ThrowInternalError(js, "sound not initialized");
pd_sound->channel->setPan(js2channel(js, argv[0]), (float)js2number(js, argv[1]));
return JS_UNDEFINED;
)
static const JSCFunctionListEntry js_sound_funcs[] = {
MIST_FUNC_DEF(sound, getCurrentTime, 0),
MIST_FUNC_DEF(sound, getDefaultChannel, 0),
MIST_FUNC_DEF(sound, addChannel, 1),
MIST_FUNC_DEF(sound, removeChannel, 1),
MIST_FUNC_DEF(sound, setOutputsActive, 2),
MIST_FUNC_DEF(sound, getError, 0),
MIST_FUNC_DEF(sound, newFilePlayer, 0),
MIST_FUNC_DEF(sound, freeFilePlayer, 1),
MIST_FUNC_DEF(sound, loadIntoFilePlayer, 2),
MIST_FUNC_DEF(sound, filePlayerPlay, 2),
MIST_FUNC_DEF(sound, filePlayerIsPlaying, 1),
MIST_FUNC_DEF(sound, filePlayerPause, 1),
MIST_FUNC_DEF(sound, filePlayerStop, 1),
MIST_FUNC_DEF(sound, filePlayerSetVolume, 3),
MIST_FUNC_DEF(sound, filePlayerGetVolume, 1),
MIST_FUNC_DEF(sound, filePlayerGetLength, 1),
MIST_FUNC_DEF(sound, filePlayerSetOffset, 2),
MIST_FUNC_DEF(sound, filePlayerGetOffset, 1),
MIST_FUNC_DEF(sound, filePlayerSetRate, 2),
MIST_FUNC_DEF(sound, filePlayerGetRate, 1),
MIST_FUNC_DEF(sound, filePlayerSetLoopRange, 3),
MIST_FUNC_DEF(sound, filePlayerDidUnderrun, 1),
MIST_FUNC_DEF(sound, filePlayerSetStopOnUnderrun, 2),
MIST_FUNC_DEF(sound, filePlayerSetBufferLength, 2),
MIST_FUNC_DEF(sound, loadSample, 1),
MIST_FUNC_DEF(sound, freeSample, 1),
MIST_FUNC_DEF(sound, getSampleLength, 1),
MIST_FUNC_DEF(sound, newSampleBuffer, 1),
MIST_FUNC_DEF(sound, newSamplePlayer, 0),
MIST_FUNC_DEF(sound, freeSamplePlayer, 1),
MIST_FUNC_DEF(sound, samplePlayerSetSample, 2),
MIST_FUNC_DEF(sound, samplePlayerPlay, 3),
MIST_FUNC_DEF(sound, samplePlayerIsPlaying, 1),
MIST_FUNC_DEF(sound, samplePlayerStop, 1),
MIST_FUNC_DEF(sound, samplePlayerSetVolume, 3),
MIST_FUNC_DEF(sound, samplePlayerGetVolume, 1),
MIST_FUNC_DEF(sound, samplePlayerGetLength, 1),
MIST_FUNC_DEF(sound, samplePlayerSetOffset, 2),
MIST_FUNC_DEF(sound, samplePlayerGetOffset, 1),
MIST_FUNC_DEF(sound, samplePlayerSetRate, 2),
MIST_FUNC_DEF(sound, samplePlayerGetRate, 1),
MIST_FUNC_DEF(sound, samplePlayerSetPlayRange, 3),
MIST_FUNC_DEF(sound, samplePlayerSetPaused, 2),
MIST_FUNC_DEF(sound, newSynth, 0),
MIST_FUNC_DEF(sound, freeSynth, 1),
MIST_FUNC_DEF(sound, synthSetWaveform, 2),
MIST_FUNC_DEF(sound, synthSetAttackTime, 2),
MIST_FUNC_DEF(sound, synthSetDecayTime, 2),
MIST_FUNC_DEF(sound, synthSetSustainLevel, 2),
MIST_FUNC_DEF(sound, synthSetReleaseTime, 2),
MIST_FUNC_DEF(sound, synthSetTranspose, 2),
MIST_FUNC_DEF(sound, synthPlayNote, 5),
MIST_FUNC_DEF(sound, synthPlayMIDINote, 5),
MIST_FUNC_DEF(sound, synthNoteOff, 2),
MIST_FUNC_DEF(sound, synthStop, 1),
MIST_FUNC_DEF(sound, synthSetVolume, 3),
MIST_FUNC_DEF(sound, synthGetVolume, 1),
MIST_FUNC_DEF(sound, synthIsPlaying, 1),
MIST_FUNC_DEF(sound, synthGetParameterCount, 1),
MIST_FUNC_DEF(sound, synthSetParameter, 3),
MIST_FUNC_DEF(sound, newChannel, 0),
MIST_FUNC_DEF(sound, freeChannel, 1),
MIST_FUNC_DEF(sound, channelSetVolume, 2),
MIST_FUNC_DEF(sound, channelGetVolume, 1),
MIST_FUNC_DEF(sound, channelSetPan, 2),
};
JSValue js_sound_use(JSContext *js) {
JSValue mod = JS_NewObject(js);
JS_SetPropertyFunctionList(js, mod, js_sound_funcs, countof(js_sound_funcs));
return mod;
}

395
playdate/sprite_playdate.c Normal file
View File

@@ -0,0 +1,395 @@
// 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_UNDEFINED;
)
JSC_CCALL(sprite_drawSprites,
if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized");
pd_sprite->drawSprites();
return JS_UNDEFINED;
)
JSC_CCALL(sprite_updateAndDrawSprites,
if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized");
pd_sprite->updateAndDrawSprites();
return JS_UNDEFINED;
)
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_UNDEFINED;
)
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_UNDEFINED;
)
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_UNDEFINED;
)
JSC_CCALL(sprite_removeAllSprites,
if (!pd_sprite) return JS_ThrowInternalError(js, "sprite not initialized");
pd_sprite->removeAllSprites();
return JS_UNDEFINED;
)
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_UNDEFINED;
)
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_UNDEFINED;
)
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_UNDEFINED;
)
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_UNDEFINED;
)
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_UNDEFINED;
)
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_UNDEFINED;
)
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_UNDEFINED;
)
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_UNDEFINED;
)
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_UNDEFINED;
)
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_UNDEFINED;
)
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_UNDEFINED;
)
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_UNDEFINED;
)
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_UNDEFINED;
)
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_UNDEFINED;
)
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_UNDEFINED;
)
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_UNDEFINED;
)
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_UNDEFINED;
)
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_UNDEFINED;
)
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_UNDEFINED;
)
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;
}

267
playdate/sys_playdate.c Normal file
View File

@@ -0,0 +1,267 @@
// sys_playdate.c - Cell integration for Playdate System API
// Wraps pd_api_sys.h functions for JavaScript access
#include "cell.h"
#include "common.h"
#include <string.h>
// --- System Functions ---
JSC_CCALL(sys_logToConsole,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
const char *str = JS_ToCString(js, argv[0]);
if (str) {
pd_sys->logToConsole("%s", str);
JS_FreeCString(js, str);
}
return JS_UNDEFINED;
)
JSC_CCALL(sys_error,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
const char *str = JS_ToCString(js, argv[0]);
if (str) {
pd_sys->error("%s", str);
JS_FreeCString(js, str);
}
return JS_UNDEFINED;
)
JSC_CCALL(sys_getLanguage,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
PDLanguage lang = pd_sys->getLanguage();
return JS_NewInt32(js, lang);
)
JSC_CCALL(sys_getCurrentTimeMilliseconds,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
return JS_NewInt64(js, pd_sys->getCurrentTimeMilliseconds());
)
JSC_CCALL(sys_getSecondsSinceEpoch,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
unsigned int ms = 0;
unsigned int secs = pd_sys->getSecondsSinceEpoch(&ms);
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "seconds", JS_NewInt64(js, secs));
JS_SetPropertyStr(js, obj, "milliseconds", JS_NewInt32(js, ms));
return obj;
)
JSC_CCALL(sys_drawFPS,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
int x = (int)js2number(js, argv[0]);
int y = (int)js2number(js, argv[1]);
pd_sys->drawFPS(x, y);
return JS_UNDEFINED;
)
JSC_CCALL(sys_getButtonState,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
PDButtons current, pushed, released;
pd_sys->getButtonState(&current, &pushed, &released);
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "current", JS_NewInt32(js, current));
JS_SetPropertyStr(js, obj, "pushed", JS_NewInt32(js, pushed));
JS_SetPropertyStr(js, obj, "released", JS_NewInt32(js, released));
return obj;
)
JSC_CCALL(sys_setPeripheralsEnabled,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
PDPeripherals mask = (PDPeripherals)(int)js2number(js, argv[0]);
pd_sys->setPeripheralsEnabled(mask);
return JS_UNDEFINED;
)
JSC_CCALL(sys_getAccelerometer,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
float x, y, z;
pd_sys->getAccelerometer(&x, &y, &z);
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "x", JS_NewFloat64(js, x));
JS_SetPropertyStr(js, obj, "y", JS_NewFloat64(js, y));
JS_SetPropertyStr(js, obj, "z", JS_NewFloat64(js, z));
return obj;
)
JSC_CCALL(sys_getCrankChange,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
return JS_NewFloat64(js, pd_sys->getCrankChange());
)
JSC_CCALL(sys_getCrankAngle,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
return JS_NewFloat64(js, pd_sys->getCrankAngle());
)
JSC_CCALL(sys_isCrankDocked,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
return JS_NewBool(js, pd_sys->isCrankDocked());
)
JSC_CCALL(sys_setCrankSoundsDisabled,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
int flag = JS_ToBool(js, argv[0]);
int prev = pd_sys->setCrankSoundsDisabled(flag);
return JS_NewBool(js, prev);
)
JSC_CCALL(sys_getFlipped,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
return JS_NewBool(js, pd_sys->getFlipped());
)
JSC_CCALL(sys_setAutoLockDisabled,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
pd_sys->setAutoLockDisabled(JS_ToBool(js, argv[0]));
return JS_UNDEFINED;
)
JSC_CCALL(sys_getReduceFlashing,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
return JS_NewBool(js, pd_sys->getReduceFlashing());
)
JSC_CCALL(sys_getElapsedTime,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
return JS_NewFloat64(js, pd_sys->getElapsedTime());
)
JSC_CCALL(sys_resetElapsedTime,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
pd_sys->resetElapsedTime();
return JS_UNDEFINED;
)
JSC_CCALL(sys_getBatteryPercentage,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
return JS_NewFloat64(js, pd_sys->getBatteryPercentage());
)
JSC_CCALL(sys_getBatteryVoltage,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
return JS_NewFloat64(js, pd_sys->getBatteryVoltage());
)
JSC_CCALL(sys_getTimezoneOffset,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
return JS_NewInt32(js, pd_sys->getTimezoneOffset());
)
JSC_CCALL(sys_shouldDisplay24HourTime,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
return JS_NewBool(js, pd_sys->shouldDisplay24HourTime());
)
JSC_CCALL(sys_convertEpochToDateTime,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
uint32_t epoch = (uint32_t)js2number(js, argv[0]);
struct PDDateTime dt;
pd_sys->convertEpochToDateTime(epoch, &dt);
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "year", JS_NewInt32(js, dt.year));
JS_SetPropertyStr(js, obj, "month", JS_NewInt32(js, dt.month));
JS_SetPropertyStr(js, obj, "day", JS_NewInt32(js, dt.day));
JS_SetPropertyStr(js, obj, "weekday", JS_NewInt32(js, dt.weekday));
JS_SetPropertyStr(js, obj, "hour", JS_NewInt32(js, dt.hour));
JS_SetPropertyStr(js, obj, "minute", JS_NewInt32(js, dt.minute));
JS_SetPropertyStr(js, obj, "second", JS_NewInt32(js, dt.second));
return obj;
)
JSC_CCALL(sys_convertDateTimeToEpoch,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
struct PDDateTime dt = {0};
dt.year = (uint16_t)js2number(js, JS_GetPropertyStr(js, argv[0], "year"));
dt.month = (uint8_t)js2number(js, JS_GetPropertyStr(js, argv[0], "month"));
dt.day = (uint8_t)js2number(js, JS_GetPropertyStr(js, argv[0], "day"));
dt.hour = (uint8_t)js2number(js, JS_GetPropertyStr(js, argv[0], "hour"));
dt.minute = (uint8_t)js2number(js, JS_GetPropertyStr(js, argv[0], "minute"));
dt.second = (uint8_t)js2number(js, JS_GetPropertyStr(js, argv[0], "second"));
return JS_NewInt64(js, pd_sys->convertDateTimeToEpoch(&dt));
)
JSC_CCALL(sys_clearICache,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
pd_sys->clearICache();
return JS_UNDEFINED;
)
JSC_CCALL(sys_delay,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
pd_sys->delay((uint32_t)js2number(js, argv[0]));
return JS_UNDEFINED;
)
JSC_SCALL(sys_restartGame,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
pd_sys->restartGame(str);
)
JSC_CCALL(sys_getLaunchArgs,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
const char *path = NULL;
const char *args = pd_sys->getLaunchArgs(&path);
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "args", args ? JS_NewString(js, args) : JS_NULL);
JS_SetPropertyStr(js, obj, "path", path ? JS_NewString(js, path) : JS_NULL);
return obj;
)
JSC_CCALL(sys_getSystemInfo,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
const struct PDInfo *info = pd_sys->getSystemInfo();
if (!info) return JS_NULL;
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "osversion", JS_NewInt64(js, info->osversion));
JS_SetPropertyStr(js, obj, "language", JS_NewInt32(js, info->language));
return obj;
)
// --- Menu Functions ---
JSC_CCALL(sys_removeAllMenuItems,
if (!pd_sys) return JS_ThrowInternalError(js, "system not initialized");
pd_sys->removeAllMenuItems();
return JS_UNDEFINED;
)
static const JSCFunctionListEntry js_sys_funcs[] = {
MIST_FUNC_DEF(sys, logToConsole, 1),
MIST_FUNC_DEF(sys, error, 1),
MIST_FUNC_DEF(sys, getLanguage, 0),
MIST_FUNC_DEF(sys, getCurrentTimeMilliseconds, 0),
MIST_FUNC_DEF(sys, getSecondsSinceEpoch, 0),
MIST_FUNC_DEF(sys, drawFPS, 2),
MIST_FUNC_DEF(sys, getButtonState, 0),
MIST_FUNC_DEF(sys, setPeripheralsEnabled, 1),
MIST_FUNC_DEF(sys, getAccelerometer, 0),
MIST_FUNC_DEF(sys, getCrankChange, 0),
MIST_FUNC_DEF(sys, getCrankAngle, 0),
MIST_FUNC_DEF(sys, isCrankDocked, 0),
MIST_FUNC_DEF(sys, setCrankSoundsDisabled, 1),
MIST_FUNC_DEF(sys, getFlipped, 0),
MIST_FUNC_DEF(sys, setAutoLockDisabled, 1),
MIST_FUNC_DEF(sys, getReduceFlashing, 0),
MIST_FUNC_DEF(sys, getElapsedTime, 0),
MIST_FUNC_DEF(sys, resetElapsedTime, 0),
MIST_FUNC_DEF(sys, getBatteryPercentage, 0),
MIST_FUNC_DEF(sys, getBatteryVoltage, 0),
MIST_FUNC_DEF(sys, getTimezoneOffset, 0),
MIST_FUNC_DEF(sys, shouldDisplay24HourTime, 0),
MIST_FUNC_DEF(sys, convertEpochToDateTime, 1),
MIST_FUNC_DEF(sys, convertDateTimeToEpoch, 1),
MIST_FUNC_DEF(sys, clearICache, 0),
MIST_FUNC_DEF(sys, delay, 1),
MIST_FUNC_DEF(sys, restartGame, 1),
MIST_FUNC_DEF(sys, getLaunchArgs, 0),
MIST_FUNC_DEF(sys, getSystemInfo, 0),
MIST_FUNC_DEF(sys, removeAllMenuItems, 0),
};
JSValue js_sys_use(JSContext *js) {
JSValue mod = JS_NewObject(js);
JS_SetPropertyFunctionList(js, mod, js_sys_funcs, countof(js_sys_funcs));
return mod;
}

View File

@@ -3,12 +3,19 @@
// and initializes the global Playdate API pointers used by other modules.
#include "cell.h"
#include "pd_api.h"
#include "playdate/common.h"
// Global Playdate API pointers - used by fd_playdate.c, http_playdate.c, etc.
// Global Playdate API pointers - used by all playdate integration modules
PlaydateAPI *pd = NULL;
const struct playdate_file *pd_file = NULL;
const struct playdate_sys *pd_sys = NULL;
const struct playdate_graphics *pd_gfx = NULL;
const struct playdate_sprite *pd_sprite = NULL;
const struct playdate_display *pd_display = NULL;
const struct playdate_sound *pd_sound = NULL;
const struct playdate_lua *pd_lua = NULL;
const struct playdate_json *pd_json = NULL;
const struct playdate_scoreboards *pd_scoreboards = NULL;
const struct playdate_network *pd_network = NULL;
// Forward declaration
@@ -34,6 +41,13 @@ int eventHandler(PlaydateAPI *playdate, PDSystemEvent event, uint32_t arg)
pd = playdate;
pd_file = playdate->file;
pd_sys = playdate->system;
pd_gfx = playdate->graphics;
pd_sprite = playdate->sprite;
pd_display = playdate->display;
pd_sound = playdate->sound;
pd_lua = playdate->lua;
pd_json = playdate->json;
pd_scoreboards = playdate->scoreboards;
pd_network = playdate->network;
// Set up the update callback

View File

@@ -10,8 +10,20 @@ return {
cpu_family: 'arm',
cpu: 'cortex-m7',
endian: 'little',
c_args: ['-mcpu=cortex-m7', '-mthumb', '-mfloat-abi=hard', '-mfpu=fpv5-sp-d16', '-fno-exceptions'],
c_link_args: ['-mcpu=cortex-m7', '-mthumb', '-mfloat-abi=hard', '-mfpu=fpv5-sp-d16', '-nostartfiles', "-T/Users/john/Developer/PlaydateSDK/C_API/buildsupport/link_map.ld"]
c_args: ['-DTARGET_PLAYDATE=1', '-DTARGET_EXTENSION=1', '-mcpu=cortex-m7', '-mthumb', '-mfloat-abi=hard', '-mfpu=fpv5-sp-d16', '-fno-exceptions'],
c_link_args: ['-mcpu=cortex-m7', '-mthumb', '-mfloat-abi=hard', '-mfpu=fpv5-sp-d16', '-nostartfiles', '-T/Users/john/Developer/PlaydateSDK/C_API/buildsupport/link_map.ld']
},
playdate_simulator: {
c: 'clang',
cpp: 'clang++',
ar: 'ar',
strip: 'strip',
system: 'playdate',
cpu_family: 'x86_64',
cpu: 'x86_64',
endian: 'little',
c_args: ['-U__APPLE__ -DTARGET_SIMULATOR=1', '-DTARGET_EXTENSION=1', '-fPIC'],
c_link_args: ['-shared']
},
windows: {
c: 'x86_64-w64-mingw32-gcc',