playdate cake
This commit is contained in:
1
cake/playdate.cm
Normal file
1
cake/playdate.cm
Normal file
@@ -0,0 +1 @@
|
||||
// cake file for making a playdate package
|
||||
64
playdate/common.h
Normal file
64
playdate/common.h
Normal 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
|
||||
91
playdate/display_playdate.c
Normal file
91
playdate/display_playdate.c
Normal 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
175
playdate/file_playdate.c
Normal 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
339
playdate/gfx_playdate.c
Normal 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
202
playdate/json_playdate.c
Normal 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
157
playdate/lua_playdate.c
Normal 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
290
playdate/network_playdate.c
Normal 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;
|
||||
}
|
||||
176
playdate/scoreboards_playdate.c
Normal file
176
playdate/scoreboards_playdate.c
Normal 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
448
playdate/sound_playdate.c
Normal 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
395
playdate/sprite_playdate.c
Normal 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
267
playdate/sys_playdate.c
Normal 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(¤t, &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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user