Cleanup of script modules.
This commit is contained in:
+4
-1
@@ -8,4 +8,7 @@ const platformNames = {
|
||||
|
||||
Console.print('Platform: ' + (platformNames[System.platform] || 'Unknown'));
|
||||
|
||||
requireAsync('testscene.js').then(Scene.set).catch(Engine.exit);
|
||||
requireAsync('testscene.js').then(Scene.set).catch(err => {
|
||||
Console.print('Error loading scene: ' + err);
|
||||
Engine.exit();
|
||||
});
|
||||
+14
-11
@@ -4,14 +4,17 @@ var scene = {};
|
||||
// { path: 'test.png', type: Asset.TYPE_TEXTURE, format: Texture.FORMAT_RGBA }
|
||||
// ]);
|
||||
|
||||
// var cam;
|
||||
// var camPos;
|
||||
// var testEntity;
|
||||
// var testPos;
|
||||
// var testRenderable;
|
||||
// var texEntry;
|
||||
var cam;
|
||||
var camPos;
|
||||
var testEntity;
|
||||
var testPos;
|
||||
var testRenderable;
|
||||
var texEntry;
|
||||
|
||||
scene.init = function() {
|
||||
// assets.lock();
|
||||
// await assets.loaded();
|
||||
|
||||
Console.print('Scene Init');
|
||||
// texEntry = assets.entry(0);
|
||||
|
||||
@@ -28,11 +31,11 @@ scene.init = function() {
|
||||
testRenderable = testEntity.add(Component.RENDERABLE);
|
||||
|
||||
// testRenderable.texture = texEntry.texture;
|
||||
testRenderable.type = Renderable.SPRITEBATCH;
|
||||
testRenderable.sprites = [
|
||||
[0, 0, 1, 1, 0, 1, 1, 0]
|
||||
];
|
||||
testPos.localPosition = new Vec3(0, 0, 0);
|
||||
// testRenderable.type = Renderable.SPRITEBATCH;
|
||||
// testRenderable.sprites = [
|
||||
// [0, 0, 1, 1, 0, 1, 1, 0]
|
||||
// ];
|
||||
// testPos.localPosition = new Vec3(0, 0, 0);
|
||||
}
|
||||
|
||||
scene.dispose = function() {
|
||||
|
||||
@@ -10,5 +10,14 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(asset)
|
||||
add_subdirectory(console)
|
||||
add_subdirectory(display)
|
||||
add_subdirectory(engine)
|
||||
add_subdirectory(entity)
|
||||
add_subdirectory(event)
|
||||
add_subdirectory(require)
|
||||
add_subdirectory(input)
|
||||
add_subdirectory(math)
|
||||
add_subdirectory(require)
|
||||
add_subdirectory(scene)
|
||||
add_subdirectory(system)
|
||||
@@ -0,0 +1,11 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
moduleassetentry.c
|
||||
moduleassetbatch.c
|
||||
moduleasset.c
|
||||
)
|
||||
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "moduleasset.h"
|
||||
|
||||
scriptproto_t MODULE_ASSET_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleAssetExists) {
|
||||
moduleBaseRequireArgs(1);
|
||||
moduleBaseRequireString(0);
|
||||
char_t buf[256];
|
||||
moduleBaseToString(args[0], buf, sizeof(buf));
|
||||
return jerry_boolean(assetFileExists(buf));
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetLock) {
|
||||
moduleBaseRequireArgs(2);
|
||||
moduleBaseRequireString(0);
|
||||
moduleBaseRequireNumber(1);
|
||||
|
||||
char_t buf[256];
|
||||
moduleBaseToString(args[0], buf, sizeof(buf));
|
||||
assetloadertype_t type = (assetloadertype_t)moduleBaseArgInt(1);
|
||||
|
||||
assetloaderinput_t input;
|
||||
assetloaderinput_t *inputPtr = NULL;
|
||||
|
||||
if(argc >= 3 && jerry_value_is_number(args[2])) {
|
||||
int32_t inputVal = moduleBaseArgInt(2);
|
||||
switch(type) {
|
||||
case ASSET_LOADER_TYPE_TEXTURE:
|
||||
input.texture = (textureformat_t)inputVal;
|
||||
inputPtr = &input;
|
||||
break;
|
||||
case ASSET_LOADER_TYPE_MESH:
|
||||
input.mesh = (assetmeshinputaxis_t)inputVal;
|
||||
inputPtr = &input;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assetentry_t *entry = assetLock(buf, type, inputPtr);
|
||||
if(!entry) return moduleBaseThrow("Asset.lock: failed to lock asset");
|
||||
jsassetentry_t e = { .entry = entry };
|
||||
return scriptProtoCreateValue(&MODULE_ASSET_ENTRY_PROTO, &e);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetRequireLoaded) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jsassetentry_t *e = (jsassetentry_t *)scriptProtoGetValue(
|
||||
&MODULE_ASSET_ENTRY_PROTO, args[0]
|
||||
);
|
||||
if(!e || !e->entry) {
|
||||
return moduleBaseThrow("Asset.requireLoaded: expected AssetEntry");
|
||||
}
|
||||
errorret_t err = assetRequireLoaded(e->entry);
|
||||
if(errorIsNotOk(err)) return moduleBaseThrowError(err);
|
||||
return jerry_value_copy(args[0]);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetUnlock) {
|
||||
moduleBaseRequireArgs(1);
|
||||
moduleBaseRequireString(0);
|
||||
char_t buf[256];
|
||||
moduleBaseToString(args[0], buf, sizeof(buf));
|
||||
assetUnlock(buf);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
void moduleAssetInit(void) {
|
||||
moduleAssetEntryInit();
|
||||
moduleAssetBatchInit();
|
||||
scriptProtoInit(&MODULE_ASSET_PROTO, "Asset", sizeof(uint8_t), NULL);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_ASSET_PROTO, "exists", moduleAssetExists
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_ASSET_PROTO, "lock", moduleAssetLock
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_ASSET_PROTO, "unlock", moduleAssetUnlock
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_ASSET_PROTO, "requireLoaded", moduleAssetRequireLoaded
|
||||
);
|
||||
|
||||
jerry_value_t global = MODULE_ASSET_PROTO.prototype;
|
||||
|
||||
struct { const char_t *name; int val; } types[] = {
|
||||
{ "TYPE_MESH", ASSET_LOADER_TYPE_MESH },
|
||||
{ "TYPE_TEXTURE", ASSET_LOADER_TYPE_TEXTURE },
|
||||
{ "TYPE_TILESET", ASSET_LOADER_TYPE_TILESET },
|
||||
{ "TYPE_LOCALE", ASSET_LOADER_TYPE_LOCALE },
|
||||
{ "TYPE_JSON", ASSET_LOADER_TYPE_JSON },
|
||||
{ "TYPE_SCRIPT", ASSET_LOADER_TYPE_SCRIPT },
|
||||
};
|
||||
for(int i = 0; i < 6; i++) {
|
||||
jerry_value_t k = jerry_string_sz(types[i].name);
|
||||
jerry_value_t v = jerry_number((double)types[i].val);
|
||||
jerry_object_set(global, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
|
||||
struct { const char_t *name; int val; } axes[] = {
|
||||
{ "MESH_AXIS_Y_UP", MESH_INPUT_AXIS_Y_UP },
|
||||
{ "MESH_AXIS_Z_UP", MESH_INPUT_AXIS_Z_UP },
|
||||
{ "MESH_AXIS_X_UP", MESH_INPUT_AXIS_X_UP },
|
||||
{ "MESH_AXIS_Y_DOWN", MESH_INPUT_AXIS_Y_DOWN },
|
||||
{ "MESH_AXIS_Z_DOWN", MESH_INPUT_AXIS_Z_DOWN },
|
||||
{ "MESH_AXIS_X_DOWN", MESH_INPUT_AXIS_X_DOWN },
|
||||
};
|
||||
for(int i = 0; i < 6; i++) {
|
||||
jerry_value_t k = jerry_string_sz(axes[i].name);
|
||||
jerry_value_t v = jerry_number((double)axes[i].val);
|
||||
jerry_object_set(global, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
}
|
||||
|
||||
void moduleAssetDispose(void) {
|
||||
scriptProtoDispose(&MODULE_ASSET_PROTO);
|
||||
moduleAssetBatchDispose();
|
||||
moduleAssetEntryDispose();
|
||||
}
|
||||
@@ -14,128 +14,48 @@
|
||||
#include "asset/asset.h"
|
||||
#include "asset/loader/assetloader.h"
|
||||
|
||||
static scriptproto_t MODULE_ASSET_PROTO;
|
||||
extern scriptproto_t MODULE_ASSET_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleAssetExists) {
|
||||
moduleBaseRequireArgs(1);
|
||||
moduleBaseRequireString(0);
|
||||
/**
|
||||
* Asset.exists(path) — returns true if the path exists in the asset archive.
|
||||
* @param args[0] Archive-relative path string.
|
||||
*/
|
||||
moduleBaseFunction(moduleAssetExists);
|
||||
|
||||
char_t buf[256];
|
||||
moduleBaseToString(args[0], buf, sizeof(buf));
|
||||
/**
|
||||
* Asset.lock(path, type, input?) — locks an asset entry and returns an
|
||||
* AssetEntry. The entry begins loading in the background.
|
||||
*
|
||||
* @param args[0] Path string.
|
||||
* @param args[1] Loader type constant (Asset.TYPE_*).
|
||||
* @param args[2] Optional loader input (Texture.FORMAT_* or Asset.MESH_AXIS_*).
|
||||
*/
|
||||
moduleBaseFunction(moduleAssetLock);
|
||||
|
||||
return jerry_boolean(assetFileExists(buf));
|
||||
}
|
||||
/**
|
||||
* Asset.requireLoaded(entry) — blocks until the entry is fully loaded.
|
||||
* @param args[0] An AssetEntry object.
|
||||
* @return The same AssetEntry for chaining.
|
||||
* @throws If the load fails.
|
||||
*/
|
||||
moduleBaseFunction(moduleAssetRequireLoaded);
|
||||
|
||||
moduleBaseFunction(moduleAssetLock) {
|
||||
moduleBaseRequireArgs(2);
|
||||
moduleBaseRequireString(0);
|
||||
moduleBaseRequireNumber(1);
|
||||
/**
|
||||
* Asset.unlock(path) — releases the asset lock for the given path.
|
||||
* Prefer entry.unlock() on the AssetEntry object directly.
|
||||
* @param args[0] Path string originally passed to Asset.lock().
|
||||
*/
|
||||
moduleBaseFunction(moduleAssetUnlock);
|
||||
|
||||
char_t buf[256];
|
||||
moduleBaseToString(args[0], buf, sizeof(buf));
|
||||
assetloadertype_t type = (assetloadertype_t)moduleBaseArgInt(1);
|
||||
/**
|
||||
* Initializes the Asset module. Also calls moduleAssetEntryInit() and
|
||||
* moduleAssetBatchInit(), then registers the global Asset object with
|
||||
* exists/lock/unlock/requireLoaded and all TYPE_* / MESH_AXIS_* constants.
|
||||
*/
|
||||
void moduleAssetInit(void);
|
||||
|
||||
assetloaderinput_t input;
|
||||
assetloaderinput_t *inputPtr = NULL;
|
||||
|
||||
if(argc >= 3 && jerry_value_is_number(args[2])) {
|
||||
int32_t inputVal = moduleBaseArgInt(2);
|
||||
switch(type) {
|
||||
case ASSET_LOADER_TYPE_TEXTURE:
|
||||
input.texture = (textureformat_t)inputVal;
|
||||
inputPtr = &input;
|
||||
break;
|
||||
|
||||
case ASSET_LOADER_TYPE_MESH:
|
||||
input.mesh = (assetmeshinputaxis_t)inputVal;
|
||||
inputPtr = &input;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assetentry_t *entry = assetLock(buf, type, inputPtr);
|
||||
if(!entry) return moduleBaseThrow("Asset.lock: failed to lock asset");
|
||||
jsassetentry_t e = { .entry = entry };
|
||||
|
||||
return scriptProtoCreateValue(&MODULE_ASSET_ENTRY_PROTO, &e);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetRequireLoaded) {
|
||||
moduleBaseRequireArgs(1);
|
||||
|
||||
jsassetentry_t *e = (jsassetentry_t *)scriptProtoGetValue(
|
||||
&MODULE_ASSET_ENTRY_PROTO, args[0]
|
||||
);
|
||||
if(!e || !e->entry) {
|
||||
return moduleBaseThrow("Asset.requireLoaded: expected AssetEntry");
|
||||
}
|
||||
errorret_t err = assetRequireLoaded(e->entry);
|
||||
if(errorIsNotOk(err)) return moduleBaseThrowError(err);
|
||||
jerry_value_t ref = jerry_value_copy(args[0]);
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetUnlock) {
|
||||
moduleBaseRequireArgs(1);
|
||||
moduleBaseRequireString(0);
|
||||
char_t buf[256];
|
||||
moduleBaseToString(args[0], buf, sizeof(buf));
|
||||
assetUnlock(buf);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
static void moduleAssetInit(void) {
|
||||
moduleAssetEntryInit();
|
||||
moduleAssetBatchInit();
|
||||
scriptProtoInit(&MODULE_ASSET_PROTO, "Asset", sizeof(uint8_t), NULL);
|
||||
scriptProtoDefineStaticFunc(&MODULE_ASSET_PROTO, "exists", moduleAssetExists);
|
||||
scriptProtoDefineStaticFunc(&MODULE_ASSET_PROTO, "lock", moduleAssetLock);
|
||||
scriptProtoDefineStaticFunc(&MODULE_ASSET_PROTO, "unlock", moduleAssetUnlock);
|
||||
scriptProtoDefineStaticFunc(&MODULE_ASSET_PROTO, "requireLoaded", moduleAssetRequireLoaded);
|
||||
|
||||
jerry_value_t global = MODULE_ASSET_PROTO.prototype;
|
||||
|
||||
/* Asset.TYPE_* loader type constants */
|
||||
struct { const char_t *name; int val; } types[] = {
|
||||
{ "TYPE_MESH", ASSET_LOADER_TYPE_MESH },
|
||||
{ "TYPE_TEXTURE", ASSET_LOADER_TYPE_TEXTURE },
|
||||
{ "TYPE_TILESET", ASSET_LOADER_TYPE_TILESET },
|
||||
{ "TYPE_LOCALE", ASSET_LOADER_TYPE_LOCALE },
|
||||
{ "TYPE_JSON", ASSET_LOADER_TYPE_JSON },
|
||||
{ "TYPE_SCRIPT", ASSET_LOADER_TYPE_SCRIPT },
|
||||
};
|
||||
for(int i = 0; i < 6; i++) {
|
||||
jerry_value_t k = jerry_string_sz(types[i].name);
|
||||
jerry_value_t v = jerry_number((double)types[i].val);
|
||||
jerry_object_set(global, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
|
||||
/* Asset.MESH_AXIS_* input constants for TYPE_MESH */
|
||||
struct { const char_t *name; int val; } axes[] = {
|
||||
{ "MESH_AXIS_Y_UP", MESH_INPUT_AXIS_Y_UP },
|
||||
{ "MESH_AXIS_Z_UP", MESH_INPUT_AXIS_Z_UP },
|
||||
{ "MESH_AXIS_X_UP", MESH_INPUT_AXIS_X_UP },
|
||||
{ "MESH_AXIS_Y_DOWN", MESH_INPUT_AXIS_Y_DOWN },
|
||||
{ "MESH_AXIS_Z_DOWN", MESH_INPUT_AXIS_Z_DOWN },
|
||||
{ "MESH_AXIS_X_DOWN", MESH_INPUT_AXIS_X_DOWN },
|
||||
};
|
||||
for(int i = 0; i < 6; i++) {
|
||||
jerry_value_t k = jerry_string_sz(axes[i].name);
|
||||
jerry_value_t v = jerry_number((double)axes[i].val);
|
||||
jerry_object_set(global, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
}
|
||||
|
||||
static void moduleAssetDispose(void) {
|
||||
scriptProtoDispose(&MODULE_ASSET_PROTO);
|
||||
moduleAssetBatchDispose();
|
||||
moduleAssetEntryDispose();
|
||||
}
|
||||
/**
|
||||
* Disposes the Asset module and calls moduleAssetBatchDispose() and
|
||||
* moduleAssetEntryDispose().
|
||||
*/
|
||||
void moduleAssetDispose(void);
|
||||
|
||||
@@ -0,0 +1,394 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "moduleassetbatch.h"
|
||||
|
||||
#define ASSET_BATCH_LOADED_MAX 8
|
||||
|
||||
typedef struct {
|
||||
assetbatch_t *batch;
|
||||
jerry_value_t promise;
|
||||
} assetbatchloadedpend_t;
|
||||
|
||||
scriptproto_t MODULE_ASSET_BATCH_PROTO;
|
||||
|
||||
static assetbatchloadedpend_t ASSET_BATCH_LOADED[ASSET_BATCH_LOADED_MAX];
|
||||
static uint32_t ASSET_BATCH_LOADED_COUNT = 0;
|
||||
|
||||
static void assetBatchOnLoadedFire(void *params, void *user);
|
||||
static void assetBatchOnErrorFire(void *params, void *user);
|
||||
|
||||
static void assetBatchOnLoadedFire(void *params, void *user) {
|
||||
assetbatch_t *batch = (assetbatch_t *)user;
|
||||
uint32_t i = 0;
|
||||
while(i < ASSET_BATCH_LOADED_COUNT) {
|
||||
if(ASSET_BATCH_LOADED[i].batch != batch) { i++; continue; }
|
||||
jerry_value_t undef = jerry_undefined();
|
||||
jerry_value_t r = jerry_promise_resolve(
|
||||
ASSET_BATCH_LOADED[i].promise, undef
|
||||
);
|
||||
jerry_value_free(undef);
|
||||
jerry_value_free(r);
|
||||
jerry_value_free(ASSET_BATCH_LOADED[i].promise);
|
||||
ASSET_BATCH_LOADED_COUNT--;
|
||||
if(i < ASSET_BATCH_LOADED_COUNT) {
|
||||
ASSET_BATCH_LOADED[i] =
|
||||
ASSET_BATCH_LOADED[ASSET_BATCH_LOADED_COUNT];
|
||||
}
|
||||
}
|
||||
eventUnsubscribe(&batch->onError, assetBatchOnErrorFire);
|
||||
}
|
||||
|
||||
static void assetBatchOnErrorFire(void *params, void *user) {
|
||||
assetbatch_t *batch = (assetbatch_t *)user;
|
||||
uint32_t i = 0;
|
||||
while(i < ASSET_BATCH_LOADED_COUNT) {
|
||||
if(ASSET_BATCH_LOADED[i].batch != batch) { i++; continue; }
|
||||
jerry_value_t err = jerry_string_sz("Asset batch failed to load");
|
||||
jerry_value_t r = jerry_promise_reject(
|
||||
ASSET_BATCH_LOADED[i].promise, err
|
||||
);
|
||||
jerry_value_free(err);
|
||||
jerry_value_free(r);
|
||||
jerry_value_free(ASSET_BATCH_LOADED[i].promise);
|
||||
ASSET_BATCH_LOADED_COUNT--;
|
||||
if(i < ASSET_BATCH_LOADED_COUNT) {
|
||||
ASSET_BATCH_LOADED[i] =
|
||||
ASSET_BATCH_LOADED[ASSET_BATCH_LOADED_COUNT];
|
||||
}
|
||||
}
|
||||
eventUnsubscribe(&batch->onLoaded, assetBatchOnLoadedFire);
|
||||
}
|
||||
|
||||
void moduleAssetBatchFree(void *ptr, jerry_object_native_info_t *info) {
|
||||
jsassetbatch_t *b = (jsassetbatch_t *)ptr;
|
||||
if(b && b->batch) {
|
||||
assetBatchDispose(b->batch);
|
||||
memoryFree(b->batch);
|
||||
}
|
||||
memoryFree(ptr);
|
||||
}
|
||||
|
||||
jsassetbatch_t *moduleAssetBatchSelf(const jerry_call_info_t *callInfo) {
|
||||
return (jsassetbatch_t *)scriptProtoGetValue(
|
||||
&MODULE_ASSET_BATCH_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetBatchCtor) {
|
||||
if(argc < 1 || !jerry_value_is_array(args[0])) {
|
||||
return moduleBaseThrow("AssetBatch: expected an array of descriptors");
|
||||
}
|
||||
|
||||
uint32_t count = jerry_array_length(args[0]);
|
||||
if(count == 0 || count > (uint32_t)ASSET_BATCH_COUNT_MAX) {
|
||||
return moduleBaseThrow("AssetBatch: descriptor count out of range");
|
||||
}
|
||||
|
||||
assetbatchdesc_t descs[ASSET_BATCH_COUNT_MAX];
|
||||
char_t paths[ASSET_BATCH_COUNT_MAX][ASSET_FILE_NAME_MAX];
|
||||
|
||||
for(uint32_t i = 0; i < count; i++) {
|
||||
jerry_value_t desc = jerry_object_get_index(args[0], i);
|
||||
if(!jerry_value_is_object(desc)) {
|
||||
jerry_value_free(desc);
|
||||
return moduleBaseThrow(
|
||||
"AssetBatch: each descriptor must be an object"
|
||||
);
|
||||
}
|
||||
|
||||
jerry_value_t pathProp = moduleBaseGetProp(desc, "path");
|
||||
if(!jerry_value_is_string(pathProp)) {
|
||||
jerry_value_free(pathProp);
|
||||
jerry_value_free(desc);
|
||||
return moduleBaseThrow(
|
||||
"AssetBatch: descriptor.path must be a string"
|
||||
);
|
||||
}
|
||||
jerry_size_t pathLen = jerry_string_to_buffer(
|
||||
pathProp, JERRY_ENCODING_UTF8,
|
||||
(jerry_char_t *)paths[i], ASSET_FILE_NAME_MAX - 1
|
||||
);
|
||||
paths[i][pathLen] = '\0';
|
||||
jerry_value_free(pathProp);
|
||||
descs[i].path = paths[i];
|
||||
|
||||
jerry_value_t typeProp = moduleBaseGetProp(desc, "type");
|
||||
if(!jerry_value_is_number(typeProp)) {
|
||||
jerry_value_free(typeProp);
|
||||
jerry_value_free(desc);
|
||||
return moduleBaseThrow(
|
||||
"AssetBatch: descriptor.type must be a number"
|
||||
);
|
||||
}
|
||||
descs[i].type = (assetloadertype_t)moduleBaseValueInt(typeProp);
|
||||
jerry_value_free(typeProp);
|
||||
|
||||
memoryZero(&descs[i].input, sizeof(assetloaderinput_t));
|
||||
jerry_value_t inputProp = moduleBaseGetProp(desc, "format");
|
||||
if(jerry_value_is_undefined(inputProp)) {
|
||||
jerry_value_free(inputProp);
|
||||
inputProp = moduleBaseGetProp(desc, "input");
|
||||
}
|
||||
if(jerry_value_is_undefined(inputProp)) {
|
||||
jerry_value_free(inputProp);
|
||||
inputProp = moduleBaseGetProp(desc, "axis");
|
||||
}
|
||||
if(jerry_value_is_number(inputProp)) {
|
||||
int32_t v = moduleBaseValueInt(inputProp);
|
||||
switch(descs[i].type) {
|
||||
case ASSET_LOADER_TYPE_TEXTURE:
|
||||
descs[i].input.texture = (textureformat_t)v;
|
||||
break;
|
||||
case ASSET_LOADER_TYPE_MESH:
|
||||
descs[i].input.mesh = (assetmeshinputaxis_t)v;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
jerry_value_free(inputProp);
|
||||
jerry_value_free(desc);
|
||||
}
|
||||
|
||||
assetbatch_t *batch = (assetbatch_t *)memoryAllocate(sizeof(assetbatch_t));
|
||||
assetBatchInit(batch, (uint16_t)count, descs);
|
||||
|
||||
jsassetbatch_t init = { .batch = batch };
|
||||
return scriptProtoCreateValue(&MODULE_ASSET_BATCH_PROTO, &init);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetBatchGetCount) {
|
||||
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||
if(!b || !b->batch) return jerry_number(0.0);
|
||||
return jerry_number((double)b->batch->count);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetBatchGetIsLoaded) {
|
||||
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||
if(!b || !b->batch) return jerry_boolean(false);
|
||||
return jerry_boolean(assetBatchIsLoaded(b->batch));
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetBatchGetHasError) {
|
||||
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||
if(!b || !b->batch) return jerry_boolean(false);
|
||||
return jerry_boolean(assetBatchHasError(b->batch));
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetBatchRequireLoaded) {
|
||||
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||
if(!b || !b->batch) {
|
||||
return moduleBaseThrow(
|
||||
"AssetBatch.requireLoaded: batch already disposed"
|
||||
);
|
||||
}
|
||||
errorret_t err = assetBatchRequireLoaded(b->batch);
|
||||
if(errorIsNotOk(err)) return moduleBaseThrowError(err);
|
||||
return jerry_value_copy(callInfo->this_value);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetBatchLoaded) {
|
||||
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||
if(!b || !b->batch) {
|
||||
return moduleBaseThrow("AssetBatch.loaded: batch disposed");
|
||||
}
|
||||
|
||||
jerry_value_t promise = jerry_promise();
|
||||
|
||||
if(assetBatchIsLoaded(b->batch)) {
|
||||
jerry_value_t undef = jerry_undefined();
|
||||
jerry_value_t r = jerry_promise_resolve(promise, undef);
|
||||
jerry_value_free(undef);
|
||||
jerry_value_free(r);
|
||||
return promise;
|
||||
}
|
||||
|
||||
if(assetBatchHasError(b->batch)) {
|
||||
jerry_value_t err = jerry_string_sz("Asset batch failed to load");
|
||||
jerry_value_t r = jerry_promise_reject(promise, err);
|
||||
jerry_value_free(err);
|
||||
jerry_value_free(r);
|
||||
return promise;
|
||||
}
|
||||
|
||||
if(ASSET_BATCH_LOADED_COUNT >= ASSET_BATCH_LOADED_MAX) {
|
||||
jerry_value_free(promise);
|
||||
return moduleBaseThrow("AssetBatch.loaded: too many pending");
|
||||
}
|
||||
|
||||
bool_t subscribed = false;
|
||||
for(uint32_t i = 0; i < ASSET_BATCH_LOADED_COUNT; i++) {
|
||||
if(ASSET_BATCH_LOADED[i].batch == b->batch) {
|
||||
subscribed = true; break;
|
||||
}
|
||||
}
|
||||
if(!subscribed) {
|
||||
eventSubscribe(
|
||||
&b->batch->onLoaded, assetBatchOnLoadedFire, b->batch
|
||||
);
|
||||
eventSubscribe(
|
||||
&b->batch->onError, assetBatchOnErrorFire, b->batch
|
||||
);
|
||||
}
|
||||
|
||||
ASSET_BATCH_LOADED[ASSET_BATCH_LOADED_COUNT].batch = b->batch;
|
||||
ASSET_BATCH_LOADED[ASSET_BATCH_LOADED_COUNT].promise =
|
||||
jerry_value_copy(promise);
|
||||
ASSET_BATCH_LOADED_COUNT++;
|
||||
return promise;
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetBatchLock) {
|
||||
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||
if(!b || !b->batch) return jerry_undefined();
|
||||
assetBatchLock(b->batch);
|
||||
return jerry_value_copy(callInfo->this_value);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetBatchUnlock) {
|
||||
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||
if(!b || !b->batch) return jerry_undefined();
|
||||
assetBatchDispose(b->batch);
|
||||
memoryFree(b->batch);
|
||||
b->batch = NULL;
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetBatchEntry) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||
if(!b || !b->batch) return jerry_undefined();
|
||||
uint32_t idx = (uint32_t)moduleBaseArgInt(0);
|
||||
if(idx >= (uint32_t)b->batch->count) return jerry_undefined();
|
||||
assetentry_t *entry = b->batch->entries[idx];
|
||||
if(!entry) return jerry_undefined();
|
||||
assetEntryLock(entry);
|
||||
jsassetentry_t e = { .entry = entry };
|
||||
return scriptProtoCreateValue(&MODULE_ASSET_ENTRY_PROTO, &e);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetBatchGetOnLoaded) {
|
||||
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||
if(!b || !b->batch) return jerry_undefined();
|
||||
return moduleEventGetOrCreate(
|
||||
callInfo, &b->batch->onLoaded, "_onLoaded"
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetBatchGetOnEntryLoaded) {
|
||||
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||
if(!b || !b->batch) return jerry_undefined();
|
||||
return moduleEventGetOrCreate(
|
||||
callInfo, &b->batch->onEntryLoaded, "_onEntryLoaded"
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetBatchGetOnError) {
|
||||
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||
if(!b || !b->batch) return jerry_undefined();
|
||||
return moduleEventGetOrCreate(
|
||||
callInfo, &b->batch->onError, "_onError"
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetBatchGetOnEntryError) {
|
||||
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||
if(!b || !b->batch) return jerry_undefined();
|
||||
return moduleEventGetOrCreate(
|
||||
callInfo, &b->batch->onEntryError, "_onEntryError"
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetBatchToString) {
|
||||
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||
if(!b || !b->batch) return jerry_string_sz("AssetBatch:invalid");
|
||||
char_t buf[32];
|
||||
snprintf(buf, sizeof(buf), "AssetBatch(%u)", (unsigned)b->batch->count);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
void moduleAssetBatchInit(void) {
|
||||
ASSET_BATCH_LOADED_COUNT = 0;
|
||||
scriptProtoInit(
|
||||
&MODULE_ASSET_BATCH_PROTO, "AssetBatch",
|
||||
sizeof(jsassetbatch_t), moduleAssetBatchCtor
|
||||
);
|
||||
MODULE_ASSET_BATCH_PROTO.info.free_cb = moduleAssetBatchFree;
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_BATCH_PROTO, "count",
|
||||
moduleAssetBatchGetCount, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_BATCH_PROTO, "isLoaded",
|
||||
moduleAssetBatchGetIsLoaded, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_BATCH_PROTO, "hasError",
|
||||
moduleAssetBatchGetHasError, NULL
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_ASSET_BATCH_PROTO, "requireLoaded",
|
||||
moduleAssetBatchRequireLoaded
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_ASSET_BATCH_PROTO, "loaded", moduleAssetBatchLoaded
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_ASSET_BATCH_PROTO, "lock", moduleAssetBatchLock
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_ASSET_BATCH_PROTO, "unlock", moduleAssetBatchUnlock
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_ASSET_BATCH_PROTO, "entry", moduleAssetBatchEntry
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_BATCH_PROTO, "onLoaded",
|
||||
moduleAssetBatchGetOnLoaded, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_BATCH_PROTO, "onEntryLoaded",
|
||||
moduleAssetBatchGetOnEntryLoaded, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_BATCH_PROTO, "onError",
|
||||
moduleAssetBatchGetOnError, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_BATCH_PROTO, "onEntryError",
|
||||
moduleAssetBatchGetOnEntryError, NULL
|
||||
);
|
||||
scriptProtoDefineToString(
|
||||
&MODULE_ASSET_BATCH_PROTO, moduleAssetBatchToString
|
||||
);
|
||||
}
|
||||
|
||||
void moduleAssetBatchDispose(void) {
|
||||
for(uint32_t i = 0; i < ASSET_BATCH_LOADED_COUNT; i++) {
|
||||
bool_t seen = false;
|
||||
for(uint32_t j = 0; j < i; j++) {
|
||||
if(ASSET_BATCH_LOADED[j].batch == ASSET_BATCH_LOADED[i].batch) {
|
||||
seen = true; break;
|
||||
}
|
||||
}
|
||||
if(!seen) {
|
||||
eventUnsubscribe(
|
||||
&ASSET_BATCH_LOADED[i].batch->onLoaded,
|
||||
assetBatchOnLoadedFire
|
||||
);
|
||||
eventUnsubscribe(
|
||||
&ASSET_BATCH_LOADED[i].batch->onError,
|
||||
assetBatchOnErrorFire
|
||||
);
|
||||
}
|
||||
jerry_value_free(ASSET_BATCH_LOADED[i].promise);
|
||||
}
|
||||
ASSET_BATCH_LOADED_COUNT = 0;
|
||||
scriptProtoDispose(&MODULE_ASSET_BATCH_PROTO);
|
||||
}
|
||||
@@ -14,280 +14,101 @@
|
||||
#include "asset/loader/assetloader.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
static scriptproto_t MODULE_ASSET_BATCH_PROTO;
|
||||
extern scriptproto_t MODULE_ASSET_BATCH_PROTO;
|
||||
|
||||
/** C struct wrapped by every AssetBatch JS instance. */
|
||||
typedef struct {
|
||||
assetbatch_t *batch;
|
||||
} jsassetbatch_t;
|
||||
|
||||
static void moduleAssetBatchFree(void *ptr, jerry_object_native_info_t *info) {
|
||||
(void)info;
|
||||
jsassetbatch_t *b = (jsassetbatch_t *)ptr;
|
||||
if(b && b->batch) {
|
||||
assetBatchDispose(b->batch);
|
||||
memoryFree(b->batch);
|
||||
}
|
||||
memoryFree(ptr);
|
||||
}
|
||||
|
||||
static inline jsassetbatch_t *moduleAssetBatchSelf(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (jsassetbatch_t *)scriptProtoGetValue(
|
||||
&MODULE_ASSET_BATCH_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
/**
|
||||
* GC free callback — disposes and frees the batch when the JS object is
|
||||
* garbage collected.
|
||||
*
|
||||
* @param ptr Native jsassetbatch_t pointer.
|
||||
* @param info Native info (unused).
|
||||
*/
|
||||
void moduleAssetBatchFree(void *ptr, jerry_object_native_info_t *info);
|
||||
|
||||
/**
|
||||
* AssetBatch(descriptors[])
|
||||
* Returns the jsassetbatch_t pointer from the current this_value.
|
||||
*
|
||||
* Parses an array of {path, type, format?/input?/axis?} descriptor objects,
|
||||
* locks all assets, and returns an AssetBatch JS object. Works with and
|
||||
* without `new`.
|
||||
* @param callInfo The call info.
|
||||
* @return Pointer to the jsassetbatch_t, or NULL if invalid.
|
||||
*/
|
||||
moduleBaseFunction(moduleAssetBatchCtor) {
|
||||
if(argc < 1 || !jerry_value_is_array(args[0])) {
|
||||
return moduleBaseThrow("AssetBatch: expected an array of descriptors");
|
||||
}
|
||||
jsassetbatch_t *moduleAssetBatchSelf(const jerry_call_info_t *callInfo);
|
||||
|
||||
uint32_t count = jerry_array_length(args[0]);
|
||||
if(count == 0 || count > (uint32_t)ASSET_BATCH_COUNT_MAX) {
|
||||
return moduleBaseThrow("AssetBatch: descriptor count out of range");
|
||||
}
|
||||
/**
|
||||
* AssetBatch(descriptors[]) constructor. Parses an array of
|
||||
* {path, type, format?/input?/axis?} descriptor objects, locks all assets,
|
||||
* and returns an AssetBatch JS object. Works with and without `new`.
|
||||
*
|
||||
* @param args[0] Array of AssetBatchDescriptor objects.
|
||||
*/
|
||||
moduleBaseFunction(moduleAssetBatchCtor);
|
||||
|
||||
assetbatchdesc_t descs[ASSET_BATCH_COUNT_MAX];
|
||||
char_t paths[ASSET_BATCH_COUNT_MAX][ASSET_FILE_NAME_MAX];
|
||||
/** @return Number of entries in the batch. */
|
||||
moduleBaseFunction(moduleAssetBatchGetCount);
|
||||
|
||||
for(uint32_t i = 0; i < count; i++) {
|
||||
jerry_value_t desc = jerry_object_get_index(args[0], i);
|
||||
if(!jerry_value_is_object(desc)) {
|
||||
jerry_value_free(desc);
|
||||
return moduleBaseThrow("AssetBatch: each descriptor must be an object");
|
||||
}
|
||||
/** @return True when every entry has reached LOADED. */
|
||||
moduleBaseFunction(moduleAssetBatchGetIsLoaded);
|
||||
|
||||
/* path */
|
||||
jerry_value_t pathProp = moduleBaseGetProp(desc, "path");
|
||||
if(!jerry_value_is_string(pathProp)) {
|
||||
jerry_value_free(pathProp);
|
||||
jerry_value_free(desc);
|
||||
return moduleBaseThrow("AssetBatch: descriptor.path must be a string");
|
||||
}
|
||||
jerry_size_t pathLen = jerry_string_to_buffer(
|
||||
pathProp, JERRY_ENCODING_UTF8,
|
||||
(jerry_char_t *)paths[i], ASSET_FILE_NAME_MAX - 1
|
||||
);
|
||||
paths[i][pathLen] = '\0';
|
||||
jerry_value_free(pathProp);
|
||||
descs[i].path = paths[i];
|
||||
/** @return True if any entry is in an ERROR state. */
|
||||
moduleBaseFunction(moduleAssetBatchGetHasError);
|
||||
|
||||
/* type */
|
||||
jerry_value_t typeProp = moduleBaseGetProp(desc, "type");
|
||||
if(!jerry_value_is_number(typeProp)) {
|
||||
jerry_value_free(typeProp);
|
||||
jerry_value_free(desc);
|
||||
return moduleBaseThrow("AssetBatch: descriptor.type must be a number");
|
||||
}
|
||||
descs[i].type = (assetloadertype_t)moduleBaseValueInt(typeProp);
|
||||
jerry_value_free(typeProp);
|
||||
/**
|
||||
* requireLoaded() — blocks until every entry is loaded.
|
||||
* @return this for chaining.
|
||||
* @throws If any entry fails to load.
|
||||
*/
|
||||
moduleBaseFunction(moduleAssetBatchRequireLoaded);
|
||||
|
||||
/* input: accept format, input, or axis — whichever is present */
|
||||
memoryZero(&descs[i].input, sizeof(assetloaderinput_t));
|
||||
jerry_value_t inputProp = moduleBaseGetProp(desc, "format");
|
||||
if(jerry_value_is_undefined(inputProp)) {
|
||||
jerry_value_free(inputProp);
|
||||
inputProp = moduleBaseGetProp(desc, "input");
|
||||
}
|
||||
if(jerry_value_is_undefined(inputProp)) {
|
||||
jerry_value_free(inputProp);
|
||||
inputProp = moduleBaseGetProp(desc, "axis");
|
||||
}
|
||||
if(jerry_value_is_number(inputProp)) {
|
||||
int32_t v = moduleBaseValueInt(inputProp);
|
||||
switch(descs[i].type) {
|
||||
case ASSET_LOADER_TYPE_TEXTURE:
|
||||
descs[i].input.texture = (textureformat_t)v;
|
||||
break;
|
||||
case ASSET_LOADER_TYPE_MESH:
|
||||
descs[i].input.mesh = (assetmeshinputaxis_t)v;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
jerry_value_free(inputProp);
|
||||
jerry_value_free(desc);
|
||||
}
|
||||
/**
|
||||
* loaded() — returns a Promise that resolves when all entries load, or
|
||||
* rejects if any entry errors. Resolves immediately if already loaded.
|
||||
*/
|
||||
moduleBaseFunction(moduleAssetBatchLoaded);
|
||||
|
||||
assetbatch_t *batch = (assetbatch_t *)memoryAllocate(sizeof(assetbatch_t));
|
||||
assetBatchInit(batch, (uint16_t)count, descs);
|
||||
/**
|
||||
* lock() — acquires one additional lock on every entry.
|
||||
* @return this for chaining.
|
||||
*/
|
||||
moduleBaseFunction(moduleAssetBatchLock);
|
||||
|
||||
jsassetbatch_t init = { .batch = batch };
|
||||
return scriptProtoCreateValue(&MODULE_ASSET_BATCH_PROTO, &init);
|
||||
}
|
||||
/**
|
||||
* unlock() — releases all locks and disposes the batch. The object is
|
||||
* invalid after this call.
|
||||
*/
|
||||
moduleBaseFunction(moduleAssetBatchUnlock);
|
||||
|
||||
/* ---- Properties ---------------------------------------------------------- */
|
||||
/**
|
||||
* entry(index) — returns the AssetEntry at index, adding an independent
|
||||
* lock.
|
||||
* @param args[0] Index (number).
|
||||
* @return AssetEntry, or undefined if out of range.
|
||||
*/
|
||||
moduleBaseFunction(moduleAssetBatchEntry);
|
||||
|
||||
moduleBaseFunction(moduleAssetBatchGetCount) {
|
||||
(void)args; (void)argc;
|
||||
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||
if(!b || !b->batch) return jerry_number(0.0);
|
||||
return jerry_number((double)b->batch->count);
|
||||
}
|
||||
/** @return The onLoaded Event (fires once when all entries load). */
|
||||
moduleBaseFunction(moduleAssetBatchGetOnLoaded);
|
||||
|
||||
moduleBaseFunction(moduleAssetBatchGetIsLoaded) {
|
||||
(void)args; (void)argc;
|
||||
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||
if(!b || !b->batch) return jerry_boolean(false);
|
||||
return jerry_boolean(assetBatchIsLoaded(b->batch));
|
||||
}
|
||||
/** @return The onEntryLoaded Event (fires per entry). */
|
||||
moduleBaseFunction(moduleAssetBatchGetOnEntryLoaded);
|
||||
|
||||
moduleBaseFunction(moduleAssetBatchGetHasError) {
|
||||
(void)args; (void)argc;
|
||||
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||
if(!b || !b->batch) return jerry_boolean(false);
|
||||
return jerry_boolean(assetBatchHasError(b->batch));
|
||||
}
|
||||
/** @return The onError Event (fires once when any entry errors). */
|
||||
moduleBaseFunction(moduleAssetBatchGetOnError);
|
||||
|
||||
/* ---- Methods ------------------------------------------------------------- */
|
||||
/** @return The onEntryError Event (fires per errored entry). */
|
||||
moduleBaseFunction(moduleAssetBatchGetOnEntryError);
|
||||
|
||||
/* Blocks until every entry is loaded. Returns this for chaining. */
|
||||
moduleBaseFunction(moduleAssetBatchRequireLoaded) {
|
||||
(void)args; (void)argc;
|
||||
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||
if(!b || !b->batch) {
|
||||
return moduleBaseThrow("AssetBatch.requireLoaded: batch already disposed");
|
||||
}
|
||||
errorret_t err = assetBatchRequireLoaded(b->batch);
|
||||
if(errorIsNotOk(err)) return moduleBaseThrowError(err);
|
||||
return jerry_value_copy(callInfo->this_value);
|
||||
}
|
||||
/** @return "AssetBatch(n)" string. */
|
||||
moduleBaseFunction(moduleAssetBatchToString);
|
||||
|
||||
/* Acquires an additional lock on every entry. Returns this for chaining. */
|
||||
moduleBaseFunction(moduleAssetBatchLock) {
|
||||
(void)args; (void)argc;
|
||||
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||
if(!b || !b->batch) return jerry_undefined();
|
||||
assetBatchLock(b->batch);
|
||||
return jerry_value_copy(callInfo->this_value);
|
||||
}
|
||||
/**
|
||||
* Initializes the AssetBatch module and registers the global AssetBatch
|
||||
* class.
|
||||
*/
|
||||
void moduleAssetBatchInit(void);
|
||||
|
||||
/* Releases all locks and clears the batch. The object becomes invalid. */
|
||||
moduleBaseFunction(moduleAssetBatchUnlock) {
|
||||
(void)args; (void)argc;
|
||||
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||
if(!b || !b->batch) return jerry_undefined();
|
||||
assetBatchDispose(b->batch);
|
||||
memoryFree(b->batch);
|
||||
b->batch = NULL;
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
/* Returns the AssetEntry at index i, adding an independent lock to it. */
|
||||
moduleBaseFunction(moduleAssetBatchEntry) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||
if(!b || !b->batch) return jerry_undefined();
|
||||
uint32_t idx = (uint32_t)moduleBaseArgInt(0);
|
||||
if(idx >= (uint32_t)b->batch->count) return jerry_undefined();
|
||||
assetentry_t *entry = b->batch->entries[idx];
|
||||
if(!entry) return jerry_undefined();
|
||||
assetEntryLock(entry);
|
||||
jsassetentry_t e = { .entry = entry };
|
||||
return scriptProtoCreateValue(&MODULE_ASSET_ENTRY_PROTO, &e);
|
||||
}
|
||||
|
||||
/* ---- Event proxies ------------------------------------------------------- */
|
||||
|
||||
moduleBaseFunction(moduleAssetBatchGetOnLoaded) {
|
||||
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||
if(!b || !b->batch) return jerry_undefined();
|
||||
return moduleEventProxyGetOrCreate(callInfo, &b->batch->onLoaded, "_onLoaded");
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetBatchGetOnEntryLoaded) {
|
||||
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||
if(!b || !b->batch) return jerry_undefined();
|
||||
return moduleEventProxyGetOrCreate(callInfo, &b->batch->onEntryLoaded, "_onEntryLoaded");
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetBatchGetOnError) {
|
||||
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||
if(!b || !b->batch) return jerry_undefined();
|
||||
return moduleEventProxyGetOrCreate(callInfo, &b->batch->onError, "_onError");
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetBatchGetOnEntryError) {
|
||||
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||
if(!b || !b->batch) return jerry_undefined();
|
||||
return moduleEventProxyGetOrCreate(callInfo, &b->batch->onEntryError, "_onEntryError");
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetBatchToString) {
|
||||
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||
if(!b || !b->batch) return jerry_string_sz("AssetBatch:invalid");
|
||||
char_t buf[32];
|
||||
snprintf(buf, sizeof(buf), "AssetBatch(%u)", (unsigned)b->batch->count);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
/* ---- Init / Dispose ------------------------------------------------------ */
|
||||
|
||||
static void moduleAssetBatchInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_ASSET_BATCH_PROTO, "AssetBatch",
|
||||
sizeof(jsassetbatch_t), moduleAssetBatchCtor
|
||||
);
|
||||
MODULE_ASSET_BATCH_PROTO.info.free_cb = moduleAssetBatchFree;
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_BATCH_PROTO, "count",
|
||||
moduleAssetBatchGetCount, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_BATCH_PROTO, "isLoaded",
|
||||
moduleAssetBatchGetIsLoaded, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_BATCH_PROTO, "hasError",
|
||||
moduleAssetBatchGetHasError, NULL
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_ASSET_BATCH_PROTO, "requireLoaded",
|
||||
moduleAssetBatchRequireLoaded
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_ASSET_BATCH_PROTO, "lock",
|
||||
moduleAssetBatchLock
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_ASSET_BATCH_PROTO, "unlock",
|
||||
moduleAssetBatchUnlock
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_ASSET_BATCH_PROTO, "entry",
|
||||
moduleAssetBatchEntry
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_BATCH_PROTO, "onLoaded",
|
||||
moduleAssetBatchGetOnLoaded, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_BATCH_PROTO, "onEntryLoaded",
|
||||
moduleAssetBatchGetOnEntryLoaded, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_BATCH_PROTO, "onError",
|
||||
moduleAssetBatchGetOnError, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_BATCH_PROTO, "onEntryError",
|
||||
moduleAssetBatchGetOnEntryError, NULL
|
||||
);
|
||||
scriptProtoDefineToString(
|
||||
&MODULE_ASSET_BATCH_PROTO, moduleAssetBatchToString
|
||||
);
|
||||
}
|
||||
|
||||
static void moduleAssetBatchDispose(void) {
|
||||
scriptProtoDispose(&MODULE_ASSET_BATCH_PROTO);
|
||||
}
|
||||
/** Disposes the AssetBatch module. */
|
||||
void moduleAssetBatchDispose(void);
|
||||
|
||||
@@ -0,0 +1,311 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "moduleassetentry.h"
|
||||
|
||||
#define ASSET_ENTRY_LOADED_MAX 16
|
||||
|
||||
typedef struct {
|
||||
assetentry_t *entry;
|
||||
jerry_value_t promise;
|
||||
} assetentryloadedpend_t;
|
||||
|
||||
scriptproto_t MODULE_ASSET_ENTRY_PROTO;
|
||||
|
||||
static assetentryloadedpend_t ASSET_ENTRY_LOADED[ASSET_ENTRY_LOADED_MAX];
|
||||
static uint32_t ASSET_ENTRY_LOADED_COUNT = 0;
|
||||
|
||||
static void assetEntryOnLoadedFire(void *params, void *user);
|
||||
static void assetEntryOnErrorFire(void *params, void *user);
|
||||
|
||||
static void assetEntryOnLoadedFire(void *params, void *user) {
|
||||
assetentry_t *entry = (assetentry_t *)user;
|
||||
uint32_t i = 0;
|
||||
while(i < ASSET_ENTRY_LOADED_COUNT) {
|
||||
if(ASSET_ENTRY_LOADED[i].entry != entry) { i++; continue; }
|
||||
jerry_value_t undef = jerry_undefined();
|
||||
jerry_value_t r = jerry_promise_resolve(
|
||||
ASSET_ENTRY_LOADED[i].promise, undef
|
||||
);
|
||||
jerry_value_free(undef);
|
||||
jerry_value_free(r);
|
||||
jerry_value_free(ASSET_ENTRY_LOADED[i].promise);
|
||||
ASSET_ENTRY_LOADED_COUNT--;
|
||||
if(i < ASSET_ENTRY_LOADED_COUNT) {
|
||||
ASSET_ENTRY_LOADED[i] =
|
||||
ASSET_ENTRY_LOADED[ASSET_ENTRY_LOADED_COUNT];
|
||||
}
|
||||
}
|
||||
eventUnsubscribe(&entry->onError, assetEntryOnErrorFire);
|
||||
}
|
||||
|
||||
static void assetEntryOnErrorFire(void *params, void *user) {
|
||||
assetentry_t *entry = (assetentry_t *)user;
|
||||
uint32_t i = 0;
|
||||
while(i < ASSET_ENTRY_LOADED_COUNT) {
|
||||
if(ASSET_ENTRY_LOADED[i].entry != entry) { i++; continue; }
|
||||
jerry_value_t err = jerry_string_sz("Asset failed to load");
|
||||
jerry_value_t r = jerry_promise_reject(
|
||||
ASSET_ENTRY_LOADED[i].promise, err
|
||||
);
|
||||
jerry_value_free(err);
|
||||
jerry_value_free(r);
|
||||
jerry_value_free(ASSET_ENTRY_LOADED[i].promise);
|
||||
ASSET_ENTRY_LOADED_COUNT--;
|
||||
if(i < ASSET_ENTRY_LOADED_COUNT) {
|
||||
ASSET_ENTRY_LOADED[i] =
|
||||
ASSET_ENTRY_LOADED[ASSET_ENTRY_LOADED_COUNT];
|
||||
}
|
||||
}
|
||||
eventUnsubscribe(&entry->onLoaded, assetEntryOnLoadedFire);
|
||||
}
|
||||
|
||||
void moduleAssetEntryFree(void *ptr, jerry_object_native_info_t *info) {
|
||||
jsassetentry_t *e = (jsassetentry_t *)ptr;
|
||||
if(e && e->entry) {
|
||||
assetUnlockEntry(e->entry);
|
||||
e->entry = NULL;
|
||||
}
|
||||
memoryFree(ptr);
|
||||
}
|
||||
|
||||
jsassetentry_t *moduleAssetEntrySelf(const jerry_call_info_t *callInfo) {
|
||||
return (jsassetentry_t *)scriptProtoGetValue(
|
||||
&MODULE_ASSET_ENTRY_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryCtor) {
|
||||
return moduleBaseThrow("AssetEntry cannot be instantiated with new");
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryGetName) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return jerry_undefined();
|
||||
return jerry_string_sz(e->entry->name);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryGetState) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return jerry_undefined();
|
||||
return jerry_number((double)e->entry->state);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryGetType) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return jerry_undefined();
|
||||
return jerry_number((double)e->entry->type);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryGetIsLoaded) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return jerry_boolean(false);
|
||||
return jerry_boolean(e->entry->state == ASSET_ENTRY_STATE_LOADED);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryGetTexture) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return jerry_undefined();
|
||||
if(e->entry->type != ASSET_LOADER_TYPE_TEXTURE) return jerry_undefined();
|
||||
if(e->entry->state != ASSET_ENTRY_STATE_LOADED) return jerry_undefined();
|
||||
assetEntryLock(e->entry);
|
||||
jstexture_t tex = { .entry = e->entry };
|
||||
return scriptProtoCreateValue(&MODULE_TEXTURE_PROTO, &tex);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryRequireLoaded) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) {
|
||||
return moduleBaseThrow("AssetEntry.requireLoaded: invalid entry");
|
||||
}
|
||||
errorret_t err = assetRequireLoaded(e->entry);
|
||||
if(errorIsNotOk(err)) return moduleBaseThrowError(err);
|
||||
return jerry_value_copy(callInfo->this_value);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryUnlock) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return jerry_undefined();
|
||||
assetUnlockEntry(e->entry);
|
||||
e->entry = NULL;
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryGetOnLoaded) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return jerry_undefined();
|
||||
return moduleEventGetOrCreate(
|
||||
callInfo, &e->entry->onLoaded, "_onLoaded"
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryGetOnUnloaded) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return jerry_undefined();
|
||||
return moduleEventGetOrCreate(
|
||||
callInfo, &e->entry->onUnloaded, "_onUnloaded"
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryGetOnError) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return jerry_undefined();
|
||||
return moduleEventGetOrCreate(
|
||||
callInfo, &e->entry->onError, "_onError"
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryLoaded) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) {
|
||||
return moduleBaseThrow("AssetEntry.loaded: invalid entry");
|
||||
}
|
||||
|
||||
jerry_value_t promise = jerry_promise();
|
||||
|
||||
if(e->entry->state == ASSET_ENTRY_STATE_LOADED) {
|
||||
jerry_value_t undef = jerry_undefined();
|
||||
jerry_value_t r = jerry_promise_resolve(promise, undef);
|
||||
jerry_value_free(undef);
|
||||
jerry_value_free(r);
|
||||
return promise;
|
||||
}
|
||||
|
||||
if(e->entry->state == ASSET_ENTRY_STATE_ERROR) {
|
||||
jerry_value_t err = jerry_string_sz("Asset failed to load");
|
||||
jerry_value_t r = jerry_promise_reject(promise, err);
|
||||
jerry_value_free(err);
|
||||
jerry_value_free(r);
|
||||
return promise;
|
||||
}
|
||||
|
||||
if(ASSET_ENTRY_LOADED_COUNT >= ASSET_ENTRY_LOADED_MAX) {
|
||||
jerry_value_free(promise);
|
||||
return moduleBaseThrow("AssetEntry.loaded: too many pending");
|
||||
}
|
||||
|
||||
bool_t subscribed = false;
|
||||
for(uint32_t i = 0; i < ASSET_ENTRY_LOADED_COUNT; i++) {
|
||||
if(ASSET_ENTRY_LOADED[i].entry == e->entry) {
|
||||
subscribed = true; break;
|
||||
}
|
||||
}
|
||||
if(!subscribed) {
|
||||
eventSubscribe(
|
||||
&e->entry->onLoaded, assetEntryOnLoadedFire, e->entry
|
||||
);
|
||||
eventSubscribe(
|
||||
&e->entry->onError, assetEntryOnErrorFire, e->entry
|
||||
);
|
||||
}
|
||||
|
||||
ASSET_ENTRY_LOADED[ASSET_ENTRY_LOADED_COUNT].entry = e->entry;
|
||||
ASSET_ENTRY_LOADED[ASSET_ENTRY_LOADED_COUNT].promise =
|
||||
jerry_value_copy(promise);
|
||||
ASSET_ENTRY_LOADED_COUNT++;
|
||||
return promise;
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryToString) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return jerry_string_sz("AssetEntry:invalid");
|
||||
char_t buf[64];
|
||||
snprintf(buf, sizeof(buf), "AssetEntry(%s)", e->entry->name);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
void moduleAssetEntryInit(void) {
|
||||
ASSET_ENTRY_LOADED_COUNT = 0;
|
||||
scriptProtoInit(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "AssetEntry",
|
||||
sizeof(jsassetentry_t), moduleAssetEntryCtor
|
||||
);
|
||||
MODULE_ASSET_ENTRY_PROTO.info.free_cb = moduleAssetEntryFree;
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "name", moduleAssetEntryGetName, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "state", moduleAssetEntryGetState, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "type", moduleAssetEntryGetType, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "isLoaded",
|
||||
moduleAssetEntryGetIsLoaded, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "texture",
|
||||
moduleAssetEntryGetTexture, NULL
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "requireLoaded",
|
||||
moduleAssetEntryRequireLoaded
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "unlock", moduleAssetEntryUnlock
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "onLoaded",
|
||||
moduleAssetEntryGetOnLoaded, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "onUnloaded",
|
||||
moduleAssetEntryGetOnUnloaded, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "onError",
|
||||
moduleAssetEntryGetOnError, NULL
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "loaded", moduleAssetEntryLoaded
|
||||
);
|
||||
scriptProtoDefineToString(
|
||||
&MODULE_ASSET_ENTRY_PROTO, moduleAssetEntryToString
|
||||
);
|
||||
|
||||
jerry_value_t ctor = MODULE_ASSET_ENTRY_PROTO.constructor;
|
||||
struct { const char_t *name; int val; } states[] = {
|
||||
{ "NOT_STARTED", ASSET_ENTRY_STATE_NOT_STARTED },
|
||||
{ "PENDING", ASSET_ENTRY_STATE_PENDING_ASYNC },
|
||||
{ "LOADING", ASSET_ENTRY_STATE_LOADING_ASYNC },
|
||||
{ "LOADED", ASSET_ENTRY_STATE_LOADED },
|
||||
{ "ERROR", ASSET_ENTRY_STATE_ERROR },
|
||||
};
|
||||
for(int i = 0; i < 5; i++) {
|
||||
jerry_value_t k = jerry_string_sz(states[i].name);
|
||||
jerry_value_t v = jerry_number((double)states[i].val);
|
||||
jerry_object_set(ctor, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
}
|
||||
|
||||
void moduleAssetEntryDispose(void) {
|
||||
for(uint32_t i = 0; i < ASSET_ENTRY_LOADED_COUNT; i++) {
|
||||
bool_t seen = false;
|
||||
for(uint32_t j = 0; j < i; j++) {
|
||||
if(ASSET_ENTRY_LOADED[j].entry == ASSET_ENTRY_LOADED[i].entry) {
|
||||
seen = true; break;
|
||||
}
|
||||
}
|
||||
if(!seen) {
|
||||
eventUnsubscribe(
|
||||
&ASSET_ENTRY_LOADED[i].entry->onLoaded,
|
||||
assetEntryOnLoadedFire
|
||||
);
|
||||
eventUnsubscribe(
|
||||
&ASSET_ENTRY_LOADED[i].entry->onError,
|
||||
assetEntryOnErrorFire
|
||||
);
|
||||
}
|
||||
jerry_value_free(ASSET_ENTRY_LOADED[i].promise);
|
||||
}
|
||||
ASSET_ENTRY_LOADED_COUNT = 0;
|
||||
scriptProtoDispose(&MODULE_ASSET_ENTRY_PROTO);
|
||||
}
|
||||
@@ -9,196 +9,88 @@
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "script/module/display/moduletexture.h"
|
||||
#include "script/module/asset/moduleeventproxy.h"
|
||||
#include "script/module/event/moduleevent.h"
|
||||
#include "asset/asset.h"
|
||||
#include "asset/loader/assetloader.h"
|
||||
#include "asset/loader/assetentry.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
static scriptproto_t MODULE_ASSET_ENTRY_PROTO;
|
||||
extern scriptproto_t MODULE_ASSET_ENTRY_PROTO;
|
||||
|
||||
/** C struct wrapped by every AssetEntry JS instance. */
|
||||
typedef struct {
|
||||
assetentry_t *entry;
|
||||
} jsassetentry_t;
|
||||
|
||||
/** Releases the asset lock when the JS object is GC'd. */
|
||||
static void moduleAssetEntryFree(
|
||||
void *ptr,
|
||||
jerry_object_native_info_t *info
|
||||
) {
|
||||
(void)info;
|
||||
jsassetentry_t *e = (jsassetentry_t *)ptr;
|
||||
if(e && e->entry) {
|
||||
assetUnlockEntry(e->entry);
|
||||
e->entry = NULL;
|
||||
}
|
||||
memoryFree(ptr);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("AssetEntry cannot be instantiated with new");
|
||||
}
|
||||
|
||||
static inline jsassetentry_t *moduleAssetEntrySelf(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (jsassetentry_t *)scriptProtoGetValue(
|
||||
&MODULE_ASSET_ENTRY_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryGetName) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return jerry_undefined();
|
||||
return jerry_string_sz(e->entry->name);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryGetState) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return jerry_undefined();
|
||||
return jerry_number((double)e->entry->state);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryGetType) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return jerry_undefined();
|
||||
return jerry_number((double)e->entry->type);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryGetIsLoaded) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return jerry_boolean(false);
|
||||
return jerry_boolean(e->entry->state == ASSET_ENTRY_STATE_LOADED);
|
||||
}
|
||||
|
||||
/* requireLoaded() — blocks until fully loaded, returns this for chaining. */
|
||||
moduleBaseFunction(moduleAssetEntryRequireLoaded) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return moduleBaseThrow("AssetEntry.requireLoaded: invalid entry");
|
||||
errorret_t err = assetRequireLoaded(e->entry);
|
||||
if(errorIsNotOk(err)) return moduleBaseThrowError(err);
|
||||
jerry_value_t self = jerry_value_copy(callInfo->this_value);
|
||||
return self;
|
||||
}
|
||||
|
||||
/*
|
||||
* texture — returns a Texture wrapping this entry's loaded texture data.
|
||||
* Returns undefined if the entry is not a texture or not yet loaded.
|
||||
* Locks the entry a second time so the Texture holds its own independent
|
||||
* reference; the lock is released when the Texture is GC'd.
|
||||
/**
|
||||
* GC free callback — releases the asset lock when the AssetEntry JS object
|
||||
* is garbage collected.
|
||||
*
|
||||
* @param ptr Native jsassetentry_t pointer.
|
||||
* @param info Native info (unused).
|
||||
*/
|
||||
moduleBaseFunction(moduleAssetEntryGetTexture) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return jerry_undefined();
|
||||
if(e->entry->type != ASSET_LOADER_TYPE_TEXTURE) return jerry_undefined();
|
||||
if(e->entry->state != ASSET_ENTRY_STATE_LOADED) return jerry_undefined();
|
||||
assetEntryLock(e->entry);
|
||||
jstexture_t tex = { .entry = e->entry };
|
||||
return scriptProtoCreateValue(&MODULE_TEXTURE_PROTO, &tex);
|
||||
}
|
||||
void moduleAssetEntryFree(void *ptr, jerry_object_native_info_t *info);
|
||||
|
||||
/* unlock() — releases the lock early; subsequent access is undefined. */
|
||||
moduleBaseFunction(moduleAssetEntryUnlock) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return jerry_undefined();
|
||||
assetUnlockEntry(e->entry);
|
||||
e->entry = NULL;
|
||||
return jerry_undefined();
|
||||
}
|
||||
/**
|
||||
* Returns the jsassetentry_t pointer from the current this_value.
|
||||
*
|
||||
* @param callInfo The call info.
|
||||
* @return Pointer to the jsassetentry_t, or NULL if invalid.
|
||||
*/
|
||||
jsassetentry_t *moduleAssetEntrySelf(const jerry_call_info_t *callInfo);
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryGetOnLoaded) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return jerry_undefined();
|
||||
return moduleEventProxyGetOrCreate(callInfo, &e->entry->onLoaded, "_onLoaded");
|
||||
}
|
||||
/** AssetEntry() constructor — always throws; not directly instantiable. */
|
||||
moduleBaseFunction(moduleAssetEntryCtor);
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryGetOnUnloaded) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return jerry_undefined();
|
||||
return moduleEventProxyGetOrCreate(callInfo, &e->entry->onUnloaded, "_onUnloaded");
|
||||
}
|
||||
/** @return Archive-relative path used as the cache key. */
|
||||
moduleBaseFunction(moduleAssetEntryGetName);
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryGetOnError) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return jerry_undefined();
|
||||
return moduleEventProxyGetOrCreate(callInfo, &e->entry->onError, "_onError");
|
||||
}
|
||||
/** @return Current loading state as a number (AssetEntry.* constants). */
|
||||
moduleBaseFunction(moduleAssetEntryGetState);
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryToString) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return jerry_string_sz("AssetEntry:invalid");
|
||||
char_t buf[64];
|
||||
snprintf(buf, sizeof(buf), "AssetEntry(%s)", e->entry->name);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
/** @return Loader type constant. */
|
||||
moduleBaseFunction(moduleAssetEntryGetType);
|
||||
|
||||
static void moduleAssetEntryInit(void) {
|
||||
moduleEventProxyInit();
|
||||
scriptProtoInit(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "AssetEntry",
|
||||
sizeof(jsassetentry_t), moduleAssetEntryCtor
|
||||
);
|
||||
MODULE_ASSET_ENTRY_PROTO.info.free_cb = moduleAssetEntryFree;
|
||||
/** @return True when the entry has fully loaded. */
|
||||
moduleBaseFunction(moduleAssetEntryGetIsLoaded);
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "name", moduleAssetEntryGetName, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "state", moduleAssetEntryGetState, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "type", moduleAssetEntryGetType, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "isLoaded", moduleAssetEntryGetIsLoaded, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "texture", moduleAssetEntryGetTexture, NULL
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "requireLoaded", moduleAssetEntryRequireLoaded
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "unlock", moduleAssetEntryUnlock
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "onLoaded",
|
||||
moduleAssetEntryGetOnLoaded, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "onUnloaded",
|
||||
moduleAssetEntryGetOnUnloaded, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "onError",
|
||||
moduleAssetEntryGetOnError, NULL
|
||||
);
|
||||
scriptProtoDefineToString(
|
||||
&MODULE_ASSET_ENTRY_PROTO, moduleAssetEntryToString
|
||||
);
|
||||
/**
|
||||
* Returns a Texture wrapping this entry's texture data. The Texture holds
|
||||
* its own asset lock independently of this AssetEntry.
|
||||
* @return A Texture JS object, or undefined if not a loaded texture.
|
||||
*/
|
||||
moduleBaseFunction(moduleAssetEntryGetTexture);
|
||||
|
||||
/* State constants */
|
||||
jerry_value_t ctor = MODULE_ASSET_ENTRY_PROTO.constructor;
|
||||
struct { const char_t *name; int val; } states[] = {
|
||||
{ "NOT_STARTED", ASSET_ENTRY_STATE_NOT_STARTED },
|
||||
{ "PENDING", ASSET_ENTRY_STATE_PENDING_ASYNC },
|
||||
{ "LOADING", ASSET_ENTRY_STATE_LOADING_ASYNC },
|
||||
{ "LOADED", ASSET_ENTRY_STATE_LOADED },
|
||||
{ "ERROR", ASSET_ENTRY_STATE_ERROR },
|
||||
};
|
||||
for(int i = 0; i < 5; i++) {
|
||||
jerry_value_t k = jerry_string_sz(states[i].name);
|
||||
jerry_value_t v = jerry_number((double)states[i].val);
|
||||
jerry_object_set(ctor, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
/**
|
||||
* requireLoaded() — blocks until the entry is LOADED or ERROR.
|
||||
* @return this for chaining.
|
||||
* @throws If the load fails.
|
||||
*/
|
||||
moduleBaseFunction(moduleAssetEntryRequireLoaded);
|
||||
|
||||
/** unlock() — releases the asset lock immediately. */
|
||||
moduleBaseFunction(moduleAssetEntryUnlock);
|
||||
|
||||
}
|
||||
/** @return The onLoaded Event for this entry. */
|
||||
moduleBaseFunction(moduleAssetEntryGetOnLoaded);
|
||||
|
||||
static void moduleAssetEntryDispose(void) {
|
||||
scriptProtoDispose(&MODULE_ASSET_ENTRY_PROTO);
|
||||
moduleEventProxyDispose();
|
||||
}
|
||||
/** @return The onUnloaded Event for this entry. */
|
||||
moduleBaseFunction(moduleAssetEntryGetOnUnloaded);
|
||||
|
||||
/** @return The onError Event for this entry. */
|
||||
moduleBaseFunction(moduleAssetEntryGetOnError);
|
||||
|
||||
/**
|
||||
* loaded() — returns a Promise that resolves when the entry loads, or
|
||||
* rejects on error. Resolves immediately if already loaded.
|
||||
*/
|
||||
moduleBaseFunction(moduleAssetEntryLoaded);
|
||||
|
||||
/** @return "AssetEntry(name)" string. */
|
||||
moduleBaseFunction(moduleAssetEntryToString);
|
||||
|
||||
/** Initializes the AssetEntry module. */
|
||||
void moduleAssetEntryInit(void);
|
||||
|
||||
/** Disposes the AssetEntry module. */
|
||||
void moduleAssetEntryDispose(void);
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "moduleeventproxy.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
scriptproto_t MODULE_EVENT_PROXY_PROTO;
|
||||
|
||||
void moduleEventProxyTrampoline0(void *params, void *user) {
|
||||
jerry_value_t fn = (jerry_value_t)(uintptr_t)user;
|
||||
jerry_value_t ret = jerry_call(fn, jerry_undefined(), NULL, 0);
|
||||
jerry_value_free(ret);
|
||||
}
|
||||
|
||||
void moduleEventProxyTrampoline1(void *params, void *user) {
|
||||
jerry_value_t fn = (jerry_value_t)(uintptr_t)user;
|
||||
jerry_value_t ret = jerry_call(fn, jerry_undefined(), NULL, 0);
|
||||
jerry_value_free(ret);
|
||||
}
|
||||
|
||||
void moduleEventProxyTrampoline2(void *params, void *user) {
|
||||
jerry_value_t fn = (jerry_value_t)(uintptr_t)user;
|
||||
jerry_value_t ret = jerry_call(fn, jerry_undefined(), NULL, 0);
|
||||
jerry_value_free(ret);
|
||||
}
|
||||
|
||||
void moduleEventProxyTrampoline3(void *params, void *user) {
|
||||
jerry_value_t fn = (jerry_value_t)(uintptr_t)user;
|
||||
jerry_value_t ret = jerry_call(fn, jerry_undefined(), NULL, 0);
|
||||
jerry_value_free(ret);
|
||||
}
|
||||
|
||||
eventcallback_t MODULE_EVENT_PROXY_TRAMPOLINES[MODULE_EVENT_PROXY_MAX_SLOTS] = {
|
||||
moduleEventProxyTrampoline0,
|
||||
moduleEventProxyTrampoline1,
|
||||
moduleEventProxyTrampoline2,
|
||||
moduleEventProxyTrampoline3,
|
||||
};
|
||||
|
||||
void moduleEventProxyFree(void *ptr, jerry_object_native_info_t *info) {
|
||||
jseventproxy_t *ep = (jseventproxy_t *)ptr;
|
||||
if(ep) {
|
||||
for(uint32_t i = 0; i < MODULE_EVENT_PROXY_MAX_SLOTS; i++) {
|
||||
if(jerry_value_is_function(ep->fns[i])) {
|
||||
if(ep->event) {
|
||||
eventUnsubscribe(ep->event, MODULE_EVENT_PROXY_TRAMPOLINES[i]);
|
||||
}
|
||||
jerry_value_free(ep->fns[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
memoryFree(ptr);
|
||||
}
|
||||
|
||||
jseventproxy_t *moduleEventProxySelf(const jerry_call_info_t *callInfo) {
|
||||
return (jseventproxy_t *)scriptProtoGetValue(
|
||||
&MODULE_EVENT_PROXY_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
static jerry_value_t moduleEventProxyGetSlot(
|
||||
const jerry_call_info_t *callInfo,
|
||||
const uint32_t slot
|
||||
) {
|
||||
jseventproxy_t *ep = moduleEventProxySelf(callInfo);
|
||||
if(!ep || !ep->event || slot >= ep->event->size) return jerry_null();
|
||||
return jerry_value_is_function(ep->fns[slot])
|
||||
? jerry_value_copy(ep->fns[slot])
|
||||
: jerry_null();
|
||||
}
|
||||
|
||||
static jerry_value_t moduleEventProxySetSlot(
|
||||
const jerry_call_info_t *callInfo,
|
||||
const jerry_value_t args[],
|
||||
const jerry_length_t argc,
|
||||
const uint32_t slot
|
||||
) {
|
||||
jseventproxy_t *ep = moduleEventProxySelf(callInfo);
|
||||
if(!ep || !ep->event || slot >= ep->event->size) return jerry_undefined();
|
||||
|
||||
if(jerry_value_is_function(ep->fns[slot])) {
|
||||
eventUnsubscribe(ep->event, MODULE_EVENT_PROXY_TRAMPOLINES[slot]);
|
||||
jerry_value_free(ep->fns[slot]);
|
||||
ep->fns[slot] = jerry_undefined();
|
||||
}
|
||||
|
||||
jerry_value_t val = (argc > 0) ? args[0] : jerry_undefined();
|
||||
if(jerry_value_is_function(val)) {
|
||||
ep->fns[slot] = jerry_value_copy(val);
|
||||
eventSubscribe(
|
||||
ep->event,
|
||||
MODULE_EVENT_PROXY_TRAMPOLINES[slot],
|
||||
(void *)(uintptr_t)ep->fns[slot]
|
||||
);
|
||||
}
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleEventProxyGet0) {
|
||||
return moduleEventProxyGetSlot(callInfo, 0);
|
||||
}
|
||||
moduleBaseFunction(moduleEventProxySet0) {
|
||||
return moduleEventProxySetSlot(callInfo, args, argc, 0);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleEventProxyGet1) {
|
||||
return moduleEventProxyGetSlot(callInfo, 1);
|
||||
}
|
||||
moduleBaseFunction(moduleEventProxySet1) {
|
||||
return moduleEventProxySetSlot(callInfo, args, argc, 1);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleEventProxyGet2) {
|
||||
return moduleEventProxyGetSlot(callInfo, 2);
|
||||
}
|
||||
moduleBaseFunction(moduleEventProxySet2) {
|
||||
return moduleEventProxySetSlot(callInfo, args, argc, 2);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleEventProxyGet3) {
|
||||
return moduleEventProxyGetSlot(callInfo, 3);
|
||||
}
|
||||
moduleBaseFunction(moduleEventProxySet3) {
|
||||
return moduleEventProxySetSlot(callInfo, args, argc, 3);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleEventProxyGetLength) {
|
||||
jseventproxy_t *ep = moduleEventProxySelf(callInfo);
|
||||
if(!ep || !ep->event) return jerry_number(0.0);
|
||||
return jerry_number((double)ep->event->size);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleEventProxyToString) {
|
||||
return jerry_string_sz("EventProxy");
|
||||
}
|
||||
|
||||
jerry_value_t moduleEventProxyGetOrCreate(
|
||||
const jerry_call_info_t *callInfo,
|
||||
event_t *event,
|
||||
const char_t *pinKey
|
||||
) {
|
||||
jerry_value_t keyStr = jerry_string_sz(pinKey);
|
||||
jerry_value_t existing = jerry_object_get(callInfo->this_value, keyStr);
|
||||
if(!jerry_value_is_undefined(existing)) {
|
||||
jerry_value_free(keyStr);
|
||||
return existing;
|
||||
}
|
||||
jerry_value_free(existing);
|
||||
|
||||
jseventproxy_t ep;
|
||||
ep.event = event;
|
||||
for(uint32_t i = 0; i < MODULE_EVENT_PROXY_MAX_SLOTS; i++) {
|
||||
ep.fns[i] = jerry_undefined();
|
||||
}
|
||||
|
||||
jerry_value_t proxy = scriptProtoCreateValue(
|
||||
&MODULE_EVENT_PROXY_PROTO, &ep
|
||||
);
|
||||
jerry_object_set(callInfo->this_value, keyStr, proxy);
|
||||
jerry_value_free(keyStr);
|
||||
return proxy;
|
||||
}
|
||||
|
||||
void moduleEventProxyInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_EVENT_PROXY_PROTO, NULL,
|
||||
sizeof(jseventproxy_t), NULL
|
||||
);
|
||||
MODULE_EVENT_PROXY_PROTO.info.free_cb = moduleEventProxyFree;
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_EVENT_PROXY_PROTO, "0",
|
||||
moduleEventProxyGet0, moduleEventProxySet0
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_EVENT_PROXY_PROTO, "1",
|
||||
moduleEventProxyGet1, moduleEventProxySet1
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_EVENT_PROXY_PROTO, "2",
|
||||
moduleEventProxyGet2, moduleEventProxySet2
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_EVENT_PROXY_PROTO, "3",
|
||||
moduleEventProxyGet3, moduleEventProxySet3
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_EVENT_PROXY_PROTO, "length",
|
||||
moduleEventProxyGetLength, NULL
|
||||
);
|
||||
scriptProtoDefineToString(
|
||||
&MODULE_EVENT_PROXY_PROTO, moduleEventProxyToString
|
||||
);
|
||||
}
|
||||
|
||||
void moduleEventProxyDispose(void) {
|
||||
scriptProtoDispose(&MODULE_EVENT_PROXY_PROTO);
|
||||
}
|
||||
@@ -5,241 +5,6 @@
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* Merged into script/module/event/moduleevent.h */
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "event/event.h"
|
||||
|
||||
/**
|
||||
* Maximum number of JS subscriber slots per proxy. Must be >= the largest
|
||||
* event capacity used (ASSET_ENTRY_EVENT_MAX, ASSET_BATCH_EVENT_MAX, etc.).
|
||||
*/
|
||||
#define MODULE_EVENT_PROXY_MAX_SLOTS 4
|
||||
|
||||
static scriptproto_t MODULE_EVENT_PROXY_PROTO;
|
||||
|
||||
/** Native data stored on each EventProxy JS object. */
|
||||
typedef struct {
|
||||
event_t *event;
|
||||
jerry_value_t fns[MODULE_EVENT_PROXY_MAX_SLOTS];
|
||||
} jseventproxy_t;
|
||||
|
||||
/* ---- C trampolines (one per slot index) ---------------------------------- */
|
||||
|
||||
static void moduleEventProxyTrampoline0(void *params, void *user) {
|
||||
(void)params;
|
||||
jerry_value_t fn = (jerry_value_t)(uintptr_t)user;
|
||||
jerry_value_t ret = jerry_call(fn, jerry_undefined(), NULL, 0);
|
||||
jerry_value_free(ret);
|
||||
}
|
||||
|
||||
static void moduleEventProxyTrampoline1(void *params, void *user) {
|
||||
(void)params;
|
||||
jerry_value_t fn = (jerry_value_t)(uintptr_t)user;
|
||||
jerry_value_t ret = jerry_call(fn, jerry_undefined(), NULL, 0);
|
||||
jerry_value_free(ret);
|
||||
}
|
||||
|
||||
static void moduleEventProxyTrampoline2(void *params, void *user) {
|
||||
(void)params;
|
||||
jerry_value_t fn = (jerry_value_t)(uintptr_t)user;
|
||||
jerry_value_t ret = jerry_call(fn, jerry_undefined(), NULL, 0);
|
||||
jerry_value_free(ret);
|
||||
}
|
||||
|
||||
static void moduleEventProxyTrampoline3(void *params, void *user) {
|
||||
(void)params;
|
||||
jerry_value_t fn = (jerry_value_t)(uintptr_t)user;
|
||||
jerry_value_t ret = jerry_call(fn, jerry_undefined(), NULL, 0);
|
||||
jerry_value_free(ret);
|
||||
}
|
||||
|
||||
static eventcallback_t MODULE_EVENT_PROXY_TRAMPOLINES[MODULE_EVENT_PROXY_MAX_SLOTS] = {
|
||||
moduleEventProxyTrampoline0,
|
||||
moduleEventProxyTrampoline1,
|
||||
moduleEventProxyTrampoline2,
|
||||
moduleEventProxyTrampoline3,
|
||||
};
|
||||
|
||||
/* ---- GC free callback ---------------------------------------------------- */
|
||||
|
||||
static void moduleEventProxyFree(void *ptr, jerry_object_native_info_t *info) {
|
||||
(void)info;
|
||||
jseventproxy_t *ep = (jseventproxy_t *)ptr;
|
||||
if(ep) {
|
||||
for(uint32_t i = 0; i < MODULE_EVENT_PROXY_MAX_SLOTS; i++) {
|
||||
if(jerry_value_is_function(ep->fns[i])) {
|
||||
if(ep->event) eventUnsubscribe(ep->event, MODULE_EVENT_PROXY_TRAMPOLINES[i]);
|
||||
jerry_value_free(ep->fns[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
memoryFree(ptr);
|
||||
}
|
||||
|
||||
/* ---- Self helper --------------------------------------------------------- */
|
||||
|
||||
static inline jseventproxy_t *moduleEventProxySelf(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (jseventproxy_t *)scriptProtoGetValue(
|
||||
&MODULE_EVENT_PROXY_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
/* ---- Slot get/set helpers ------------------------------------------------ */
|
||||
|
||||
static inline jerry_value_t moduleEventProxyGetSlot(
|
||||
const jerry_call_info_t *callInfo,
|
||||
const uint32_t slot
|
||||
) {
|
||||
jseventproxy_t *ep = moduleEventProxySelf(callInfo);
|
||||
if(!ep || !ep->event || slot >= ep->event->size) return jerry_null();
|
||||
return jerry_value_is_function(ep->fns[slot])
|
||||
? jerry_value_copy(ep->fns[slot])
|
||||
: jerry_null();
|
||||
}
|
||||
|
||||
static inline jerry_value_t moduleEventProxySetSlot(
|
||||
const jerry_call_info_t *callInfo,
|
||||
const jerry_value_t args[],
|
||||
const jerry_length_t argc,
|
||||
const uint32_t slot
|
||||
) {
|
||||
jseventproxy_t *ep = moduleEventProxySelf(callInfo);
|
||||
if(!ep || !ep->event || slot >= ep->event->size) return jerry_undefined();
|
||||
|
||||
if(jerry_value_is_function(ep->fns[slot])) {
|
||||
eventUnsubscribe(ep->event, MODULE_EVENT_PROXY_TRAMPOLINES[slot]);
|
||||
jerry_value_free(ep->fns[slot]);
|
||||
ep->fns[slot] = jerry_undefined();
|
||||
}
|
||||
|
||||
jerry_value_t val = (argc > 0) ? args[0] : jerry_undefined();
|
||||
if(jerry_value_is_function(val)) {
|
||||
ep->fns[slot] = jerry_value_copy(val);
|
||||
eventSubscribe(
|
||||
ep->event,
|
||||
MODULE_EVENT_PROXY_TRAMPOLINES[slot],
|
||||
(void *)(uintptr_t)ep->fns[slot]
|
||||
);
|
||||
}
|
||||
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
/* ---- Per-slot getter/setter pairs ---------------------------------------- */
|
||||
|
||||
moduleBaseFunction(moduleEventProxyGet0) {
|
||||
(void)args; (void)argc;
|
||||
return moduleEventProxyGetSlot(callInfo, 0);
|
||||
}
|
||||
moduleBaseFunction(moduleEventProxySet0) {
|
||||
return moduleEventProxySetSlot(callInfo, args, argc, 0);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleEventProxyGet1) {
|
||||
(void)args; (void)argc;
|
||||
return moduleEventProxyGetSlot(callInfo, 1);
|
||||
}
|
||||
moduleBaseFunction(moduleEventProxySet1) {
|
||||
return moduleEventProxySetSlot(callInfo, args, argc, 1);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleEventProxyGet2) {
|
||||
(void)args; (void)argc;
|
||||
return moduleEventProxyGetSlot(callInfo, 2);
|
||||
}
|
||||
moduleBaseFunction(moduleEventProxySet2) {
|
||||
return moduleEventProxySetSlot(callInfo, args, argc, 2);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleEventProxyGet3) {
|
||||
(void)args; (void)argc;
|
||||
return moduleEventProxyGetSlot(callInfo, 3);
|
||||
}
|
||||
moduleBaseFunction(moduleEventProxySet3) {
|
||||
return moduleEventProxySetSlot(callInfo, args, argc, 3);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleEventProxyGetLength) {
|
||||
(void)args; (void)argc;
|
||||
jseventproxy_t *ep = moduleEventProxySelf(callInfo);
|
||||
if(!ep || !ep->event) return jerry_number(0.0);
|
||||
return jerry_number((double)ep->event->size);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleEventProxyToString) {
|
||||
(void)args; (void)argc;
|
||||
return jerry_string_sz("EventProxy");
|
||||
}
|
||||
|
||||
/* ---- Lazy-create helper (shared by all parent types) --------------------- */
|
||||
|
||||
/**
|
||||
* Returns the event proxy pinned at pinKey on callInfo->this_value.
|
||||
* Creates and pins it on first access. event must remain valid for the
|
||||
* lifetime of the parent JS object (it is stored by pointer, not copied).
|
||||
*/
|
||||
static inline jerry_value_t moduleEventProxyGetOrCreate(
|
||||
const jerry_call_info_t *callInfo,
|
||||
event_t *event,
|
||||
const char_t *pinKey
|
||||
) {
|
||||
jerry_value_t keyStr = jerry_string_sz(pinKey);
|
||||
jerry_value_t existing = jerry_object_get(callInfo->this_value, keyStr);
|
||||
if(!jerry_value_is_undefined(existing)) {
|
||||
jerry_value_free(keyStr);
|
||||
return existing;
|
||||
}
|
||||
jerry_value_free(existing);
|
||||
|
||||
jseventproxy_t ep;
|
||||
ep.event = event;
|
||||
for(uint32_t i = 0; i < MODULE_EVENT_PROXY_MAX_SLOTS; i++) {
|
||||
ep.fns[i] = jerry_undefined();
|
||||
}
|
||||
|
||||
jerry_value_t proxy = scriptProtoCreateValue(&MODULE_EVENT_PROXY_PROTO, &ep);
|
||||
jerry_object_set(callInfo->this_value, keyStr, proxy);
|
||||
jerry_value_free(keyStr);
|
||||
return proxy;
|
||||
}
|
||||
|
||||
/* ---- Init / Dispose ------------------------------------------------------ */
|
||||
|
||||
static void moduleEventProxyInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_EVENT_PROXY_PROTO, NULL,
|
||||
sizeof(jseventproxy_t), NULL
|
||||
);
|
||||
MODULE_EVENT_PROXY_PROTO.info.free_cb = moduleEventProxyFree;
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_EVENT_PROXY_PROTO, "0",
|
||||
moduleEventProxyGet0, moduleEventProxySet0
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_EVENT_PROXY_PROTO, "1",
|
||||
moduleEventProxyGet1, moduleEventProxySet1
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_EVENT_PROXY_PROTO, "2",
|
||||
moduleEventProxyGet2, moduleEventProxySet2
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_EVENT_PROXY_PROTO, "3",
|
||||
moduleEventProxyGet3, moduleEventProxySet3
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_EVENT_PROXY_PROTO, "length",
|
||||
moduleEventProxyGetLength, NULL
|
||||
);
|
||||
scriptProtoDefineToString(
|
||||
&MODULE_EVENT_PROXY_PROTO, moduleEventProxyToString
|
||||
);
|
||||
}
|
||||
|
||||
static void moduleEventProxyDispose(void) {
|
||||
scriptProtoDispose(&MODULE_EVENT_PROXY_PROTO);
|
||||
}
|
||||
#include "script/module/event/moduleevent.h"
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
moduleconsole.c
|
||||
)
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "moduleconsole.h"
|
||||
#include "util/string.h"
|
||||
#include <string.h>
|
||||
|
||||
scriptproto_t MODULE_CONSOLE_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleConsolePrint) {
|
||||
char_t buf[512];
|
||||
char_t msg[4096];
|
||||
size_t msgLen = 0;
|
||||
|
||||
for(jerry_length_t i = 0; i < argc; ++i) {
|
||||
jerry_value_t strVal = jerry_value_to_string(args[i]);
|
||||
moduleBaseToString(strVal, buf, sizeof(buf));
|
||||
jerry_value_free(strVal);
|
||||
|
||||
size_t partLen = strlen(buf);
|
||||
if(msgLen + partLen + 1 < sizeof(msg)) {
|
||||
stringCopy(msg + msgLen, buf, sizeof(msg) - msgLen);
|
||||
msgLen += partLen;
|
||||
}
|
||||
|
||||
if(i + 1 < argc && msgLen + 1 < sizeof(msg)) {
|
||||
msg[msgLen++] = '\t';
|
||||
msg[msgLen] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
consolePrint("%s", msg);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleConsoleGetVisible) {
|
||||
return jerry_boolean(CONSOLE.visible);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleConsoleSetVisible) {
|
||||
moduleBaseRequireArgs(1);
|
||||
CONSOLE.visible = moduleBaseArgBool(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
void moduleConsoleInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_CONSOLE_PROTO, "Console",
|
||||
sizeof(uint8_t), NULL
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_CONSOLE_PROTO, "print", moduleConsolePrint
|
||||
);
|
||||
scriptProtoDefineStaticProp(
|
||||
&MODULE_CONSOLE_PROTO, "visible",
|
||||
moduleConsoleGetVisible, moduleConsoleSetVisible
|
||||
);
|
||||
}
|
||||
|
||||
void moduleConsoleDispose(void) {
|
||||
scriptProtoDispose(&MODULE_CONSOLE_PROTO);
|
||||
}
|
||||
@@ -10,59 +10,27 @@
|
||||
#include "script/scriptproto.h"
|
||||
#include "console/console.h"
|
||||
|
||||
static scriptproto_t MODULE_CONSOLE_PROTO;
|
||||
extern scriptproto_t MODULE_CONSOLE_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleConsolePrint) {
|
||||
char_t buf[512];
|
||||
char_t msg[4096];
|
||||
size_t msgLen = 0;
|
||||
/**
|
||||
* Console.print(...args) — concatenates all arguments tab-separated and prints
|
||||
* to the engine console.
|
||||
*/
|
||||
moduleBaseFunction(moduleConsolePrint);
|
||||
|
||||
for(jerry_length_t i = 0; i < argc; ++i) {
|
||||
jerry_value_t strVal = jerry_value_to_string(args[i]);
|
||||
moduleBaseToString(strVal, buf, sizeof(buf));
|
||||
jerry_value_free(strVal);
|
||||
/** @return Whether the console overlay is currently visible. */
|
||||
moduleBaseFunction(moduleConsoleGetVisible);
|
||||
|
||||
size_t partLen = strlen(buf);
|
||||
if(msgLen + partLen + 1 < sizeof(msg)) {
|
||||
stringCopy(msg + msgLen, buf, sizeof(msg) - msgLen);
|
||||
msgLen += partLen;
|
||||
}
|
||||
/** Sets console visibility. @param args[0] Boolean visible state. */
|
||||
moduleBaseFunction(moduleConsoleSetVisible);
|
||||
|
||||
if(i + 1 < argc && msgLen + 1 < sizeof(msg)) {
|
||||
msg[msgLen++] = '\t';
|
||||
msg[msgLen] = '\0';
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Initializes the Console module and registers the global Console object with
|
||||
* print() and the visible property.
|
||||
*/
|
||||
void moduleConsoleInit(void);
|
||||
|
||||
consolePrint("%s", msg);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleConsoleGetVisible) {
|
||||
return jerry_boolean(CONSOLE.visible);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleConsoleSetVisible) {
|
||||
moduleBaseRequireArgs(1);
|
||||
CONSOLE.visible = moduleBaseArgBool(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
static void moduleConsoleInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_CONSOLE_PROTO, "Console",
|
||||
sizeof(uint8_t), NULL
|
||||
);
|
||||
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_CONSOLE_PROTO, "print", moduleConsolePrint
|
||||
);
|
||||
scriptProtoDefineStaticProp(
|
||||
&MODULE_CONSOLE_PROTO, "visible",
|
||||
moduleConsoleGetVisible, moduleConsoleSetVisible
|
||||
);
|
||||
}
|
||||
|
||||
static void moduleConsoleDispose(void) {
|
||||
scriptProtoDispose(&MODULE_CONSOLE_PROTO);
|
||||
}
|
||||
/**
|
||||
* Disposes the Console module.
|
||||
*/
|
||||
void moduleConsoleDispose(void);
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
modulecolor.c
|
||||
modulescreen.c
|
||||
moduletexture.c
|
||||
)
|
||||
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "modulecolor.h"
|
||||
|
||||
scriptproto_t MODULE_COLOR_PROTO;
|
||||
|
||||
color_t *moduleColorFrom(const jerry_value_t val) {
|
||||
return (color_t *)scriptProtoGetValue(&MODULE_COLOR_PROTO, val);
|
||||
}
|
||||
|
||||
jerry_value_t moduleColorPush(const color_t c) {
|
||||
return scriptProtoCreateValue(&MODULE_COLOR_PROTO, &c);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleColorConstructor) {
|
||||
color_t *ptr = (color_t *)memoryAllocate(sizeof(color_t));
|
||||
ptr->r = (uint8_t)moduleBaseOptInt(0, 0);
|
||||
ptr->g = (uint8_t)moduleBaseOptInt(1, 0);
|
||||
ptr->b = (uint8_t)moduleBaseOptInt(2, 0);
|
||||
ptr->a = (uint8_t)moduleBaseOptInt(3, 255);
|
||||
jerry_object_set_native_ptr(
|
||||
callInfo->this_value, &MODULE_COLOR_PROTO.info, ptr
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleColorGetR) {
|
||||
color_t *c = moduleColorFrom(callInfo->this_value);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->r);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleColorSetR) {
|
||||
moduleBaseRequireArgs(1);
|
||||
color_t *c = moduleColorFrom(callInfo->this_value);
|
||||
if(!c) return jerry_undefined();
|
||||
c->r = (uint8_t)moduleBaseArgInt(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleColorGetG) {
|
||||
color_t *c = moduleColorFrom(callInfo->this_value);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->g);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleColorSetG) {
|
||||
moduleBaseRequireArgs(1);
|
||||
color_t *c = moduleColorFrom(callInfo->this_value);
|
||||
if(!c) return jerry_undefined();
|
||||
c->g = (uint8_t)moduleBaseArgInt(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleColorGetB) {
|
||||
color_t *c = moduleColorFrom(callInfo->this_value);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->b);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleColorSetB) {
|
||||
moduleBaseRequireArgs(1);
|
||||
color_t *c = moduleColorFrom(callInfo->this_value);
|
||||
if(!c) return jerry_undefined();
|
||||
c->b = (uint8_t)moduleBaseArgInt(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleColorGetA) {
|
||||
color_t *c = moduleColorFrom(callInfo->this_value);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->a);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleColorSetA) {
|
||||
moduleBaseRequireArgs(1);
|
||||
color_t *c = moduleColorFrom(callInfo->this_value);
|
||||
if(!c) return jerry_undefined();
|
||||
c->a = (uint8_t)moduleBaseArgInt(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleColorToString) {
|
||||
color_t *c = moduleColorFrom(callInfo->this_value);
|
||||
if(!c) return jerry_string_sz("Color:invalid");
|
||||
char_t buf[32];
|
||||
snprintf(buf, sizeof(buf), "Color(%u,%u,%u,%u)",
|
||||
(unsigned)c->r, (unsigned)c->g,
|
||||
(unsigned)c->b, (unsigned)c->a
|
||||
);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
void moduleColorInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_COLOR_PROTO, "Color",
|
||||
sizeof(color_t), moduleColorConstructor
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_COLOR_PROTO, "r", moduleColorGetR, moduleColorSetR
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_COLOR_PROTO, "g", moduleColorGetG, moduleColorSetG
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_COLOR_PROTO, "b", moduleColorGetB, moduleColorSetB
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_COLOR_PROTO, "a", moduleColorGetA, moduleColorSetA
|
||||
);
|
||||
scriptProtoDefineToString(&MODULE_COLOR_PROTO, moduleColorToString);
|
||||
|
||||
struct { const char_t *name; color_t val; } constants[] = {
|
||||
{ "WHITE", COLOR_WHITE },
|
||||
{ "BLACK", COLOR_BLACK },
|
||||
{ "RED", COLOR_RED },
|
||||
{ "GREEN", COLOR_GREEN },
|
||||
{ "BLUE", COLOR_BLUE },
|
||||
{ "YELLOW", COLOR_YELLOW },
|
||||
{ "CYAN", COLOR_CYAN },
|
||||
{ "MAGENTA", COLOR_MAGENTA },
|
||||
{ "TRANSPARENT", COLOR_TRANSPARENT },
|
||||
{ "GRAY", COLOR_GRAY },
|
||||
{ "LIGHT_GRAY", COLOR_LIGHT_GRAY },
|
||||
{ "DARK_GRAY", COLOR_DARK_GRAY },
|
||||
{ "ORANGE", COLOR_ORANGE },
|
||||
{ "PURPLE", COLOR_PURPLE },
|
||||
{ "PINK", COLOR_PINK },
|
||||
{ "TEAL", COLOR_TEAL },
|
||||
{ "CORNFLOWER_BLUE", COLOR_CORNFLOWER_BLUE },
|
||||
};
|
||||
jerry_value_t ctor = MODULE_COLOR_PROTO.constructor;
|
||||
for(int i = 0; i < (int)(sizeof(constants)/sizeof(constants[0])); i++) {
|
||||
jerry_value_t k = jerry_string_sz(constants[i].name);
|
||||
jerry_value_t v = moduleColorPush(constants[i].val);
|
||||
jerry_object_set(ctor, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
}
|
||||
|
||||
void moduleColorDispose(void) {
|
||||
scriptProtoDispose(&MODULE_COLOR_PROTO);
|
||||
}
|
||||
@@ -11,144 +11,57 @@
|
||||
#include "util/memory.h"
|
||||
#include "display/color.h"
|
||||
|
||||
static scriptproto_t MODULE_COLOR_PROTO;
|
||||
extern scriptproto_t MODULE_COLOR_PROTO;
|
||||
|
||||
/**
|
||||
* Returns the native color_t pointer from a Color JS instance.
|
||||
* Returns NULL if the value is not a Color.
|
||||
* Returns the native color_t pointer from a Color JS value.
|
||||
*
|
||||
* @param val The JS value to extract from.
|
||||
* @return Pointer to the color data, or NULL if not a Color.
|
||||
*/
|
||||
static inline color_t *moduleColorFrom(const jerry_value_t val) {
|
||||
return (color_t *)scriptProtoGetValue(&MODULE_COLOR_PROTO, val);
|
||||
}
|
||||
color_t *moduleColorFrom(const jerry_value_t val);
|
||||
|
||||
/**
|
||||
* Creates a Color JS object from a C color_t value.
|
||||
* Creates a Color JS object wrapping a copy of a C color_t.
|
||||
*
|
||||
* @param c The source color.
|
||||
* @return A new Color JS object.
|
||||
*/
|
||||
static inline jerry_value_t moduleColorPush(const color_t c) {
|
||||
return scriptProtoCreateValue(&MODULE_COLOR_PROTO, &c);
|
||||
}
|
||||
jerry_value_t moduleColorPush(const color_t c);
|
||||
|
||||
moduleBaseFunction(moduleColorConstructor) {
|
||||
color_t *ptr = (color_t *)memoryAllocate(sizeof(color_t));
|
||||
ptr->r = (uint8_t)moduleBaseOptInt(0, 0);
|
||||
ptr->g = (uint8_t)moduleBaseOptInt(1, 0);
|
||||
ptr->b = (uint8_t)moduleBaseOptInt(2, 0);
|
||||
ptr->a = (uint8_t)moduleBaseOptInt(3, 255);
|
||||
jerry_object_set_native_ptr(
|
||||
callInfo->this_value, &MODULE_COLOR_PROTO.info, ptr
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/** Color(r?, g?, b?, a?) constructor. */
|
||||
moduleBaseFunction(moduleColorConstructor);
|
||||
|
||||
moduleBaseFunction(moduleColorGetR) {
|
||||
color_t *c = moduleColorFrom(callInfo->this_value);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->r);
|
||||
}
|
||||
/** @return The red channel as a number. */
|
||||
moduleBaseFunction(moduleColorGetR);
|
||||
/** Sets the red channel. @param args[0] New r value (0-255). */
|
||||
moduleBaseFunction(moduleColorSetR);
|
||||
|
||||
moduleBaseFunction(moduleColorSetR) {
|
||||
moduleBaseRequireArgs(1);
|
||||
color_t *c = moduleColorFrom(callInfo->this_value);
|
||||
if(!c) return jerry_undefined();
|
||||
c->r = (uint8_t)moduleBaseArgInt(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/** @return The green channel as a number. */
|
||||
moduleBaseFunction(moduleColorGetG);
|
||||
/** Sets the green channel. @param args[0] New g value (0-255). */
|
||||
moduleBaseFunction(moduleColorSetG);
|
||||
|
||||
moduleBaseFunction(moduleColorGetG) {
|
||||
color_t *c = moduleColorFrom(callInfo->this_value);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->g);
|
||||
}
|
||||
/** @return The blue channel as a number. */
|
||||
moduleBaseFunction(moduleColorGetB);
|
||||
/** Sets the blue channel. @param args[0] New b value (0-255). */
|
||||
moduleBaseFunction(moduleColorSetB);
|
||||
|
||||
moduleBaseFunction(moduleColorSetG) {
|
||||
moduleBaseRequireArgs(1);
|
||||
color_t *c = moduleColorFrom(callInfo->this_value);
|
||||
if(!c) return jerry_undefined();
|
||||
c->g = (uint8_t)moduleBaseArgInt(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/** @return The alpha channel as a number. */
|
||||
moduleBaseFunction(moduleColorGetA);
|
||||
/** Sets the alpha channel. @param args[0] New a value (0-255). */
|
||||
moduleBaseFunction(moduleColorSetA);
|
||||
|
||||
moduleBaseFunction(moduleColorGetB) {
|
||||
color_t *c = moduleColorFrom(callInfo->this_value);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->b);
|
||||
}
|
||||
/** @return "Color(r,g,b,a)" string. */
|
||||
moduleBaseFunction(moduleColorToString);
|
||||
|
||||
moduleBaseFunction(moduleColorSetB) {
|
||||
moduleBaseRequireArgs(1);
|
||||
color_t *c = moduleColorFrom(callInfo->this_value);
|
||||
if(!c) return jerry_undefined();
|
||||
c->b = (uint8_t)moduleBaseArgInt(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/**
|
||||
* Initializes the Color module and registers the global Color class with named
|
||||
* color constants (Color.WHITE, Color.RED, etc.).
|
||||
*/
|
||||
void moduleColorInit(void);
|
||||
|
||||
moduleBaseFunction(moduleColorGetA) {
|
||||
color_t *c = moduleColorFrom(callInfo->this_value);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->a);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleColorSetA) {
|
||||
moduleBaseRequireArgs(1);
|
||||
color_t *c = moduleColorFrom(callInfo->this_value);
|
||||
if(!c) return jerry_undefined();
|
||||
c->a = (uint8_t)moduleBaseArgInt(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleColorToString) {
|
||||
color_t *c = moduleColorFrom(callInfo->this_value);
|
||||
if(!c) return jerry_string_sz("Color:invalid");
|
||||
char_t buf[32];
|
||||
snprintf(buf, sizeof(buf), "Color(%u,%u,%u,%u)",
|
||||
(unsigned)c->r, (unsigned)c->g,
|
||||
(unsigned)c->b, (unsigned)c->a
|
||||
);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
static void moduleColorInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_COLOR_PROTO, "Color",
|
||||
sizeof(color_t), moduleColorConstructor
|
||||
);
|
||||
|
||||
scriptProtoDefineProp(&MODULE_COLOR_PROTO, "r", moduleColorGetR, moduleColorSetR);
|
||||
scriptProtoDefineProp(&MODULE_COLOR_PROTO, "g", moduleColorGetG, moduleColorSetG);
|
||||
scriptProtoDefineProp(&MODULE_COLOR_PROTO, "b", moduleColorGetB, moduleColorSetB);
|
||||
scriptProtoDefineProp(&MODULE_COLOR_PROTO, "a", moduleColorGetA, moduleColorSetA);
|
||||
scriptProtoDefineToString(&MODULE_COLOR_PROTO, moduleColorToString);
|
||||
|
||||
/* Static named color constants on the constructor. */
|
||||
struct { const char_t *name; color_t val; } constants[] = {
|
||||
{ "WHITE", COLOR_WHITE },
|
||||
{ "BLACK", COLOR_BLACK },
|
||||
{ "RED", COLOR_RED },
|
||||
{ "GREEN", COLOR_GREEN },
|
||||
{ "BLUE", COLOR_BLUE },
|
||||
{ "YELLOW", COLOR_YELLOW },
|
||||
{ "CYAN", COLOR_CYAN },
|
||||
{ "MAGENTA", COLOR_MAGENTA },
|
||||
{ "TRANSPARENT", COLOR_TRANSPARENT },
|
||||
{ "GRAY", COLOR_GRAY },
|
||||
{ "LIGHT_GRAY", COLOR_LIGHT_GRAY },
|
||||
{ "DARK_GRAY", COLOR_DARK_GRAY },
|
||||
{ "ORANGE", COLOR_ORANGE },
|
||||
{ "PURPLE", COLOR_PURPLE },
|
||||
{ "PINK", COLOR_PINK },
|
||||
{ "TEAL", COLOR_TEAL },
|
||||
{ "CORNFLOWER_BLUE", COLOR_CORNFLOWER_BLUE },
|
||||
};
|
||||
jerry_value_t ctor = MODULE_COLOR_PROTO.constructor;
|
||||
for(int i = 0; i < (int)(sizeof(constants)/sizeof(constants[0])); i++) {
|
||||
jerry_value_t k = jerry_string_sz(constants[i].name);
|
||||
jerry_value_t v = moduleColorPush(constants[i].val);
|
||||
jerry_object_set(ctor, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
}
|
||||
|
||||
static void moduleColorDispose(void) {
|
||||
scriptProtoDispose(&MODULE_COLOR_PROTO);
|
||||
}
|
||||
/**
|
||||
* Disposes the Color module.
|
||||
*/
|
||||
void moduleColorDispose(void);
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "modulescreen.h"
|
||||
|
||||
scriptproto_t MODULE_SCREEN_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleScreenGetWidth) {
|
||||
return jerry_number((double)SCREEN.width);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleScreenGetHeight) {
|
||||
return jerry_number((double)SCREEN.height);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleScreenGetAspect) {
|
||||
return jerry_number((double)SCREEN.aspect);
|
||||
}
|
||||
|
||||
void moduleScreenInit(void) {
|
||||
scriptProtoInit(&MODULE_SCREEN_PROTO, "Screen", sizeof(uint8_t), NULL);
|
||||
scriptProtoDefineStaticProp(
|
||||
&MODULE_SCREEN_PROTO, "width", moduleScreenGetWidth, NULL
|
||||
);
|
||||
scriptProtoDefineStaticProp(
|
||||
&MODULE_SCREEN_PROTO, "height", moduleScreenGetHeight, NULL
|
||||
);
|
||||
scriptProtoDefineStaticProp(
|
||||
&MODULE_SCREEN_PROTO, "aspect", moduleScreenGetAspect, NULL
|
||||
);
|
||||
}
|
||||
|
||||
void moduleScreenDispose(void) {
|
||||
scriptProtoDispose(&MODULE_SCREEN_PROTO);
|
||||
}
|
||||
@@ -10,37 +10,24 @@
|
||||
#include "script/scriptproto.h"
|
||||
#include "display/screen/screen.h"
|
||||
|
||||
static scriptproto_t MODULE_SCREEN_PROTO;
|
||||
extern scriptproto_t MODULE_SCREEN_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleScreenGetWidth) {
|
||||
return jerry_number((double)SCREEN.width);
|
||||
}
|
||||
/** @return Current screen width in pixels. */
|
||||
moduleBaseFunction(moduleScreenGetWidth);
|
||||
|
||||
moduleBaseFunction(moduleScreenGetHeight) {
|
||||
return jerry_number((double)SCREEN.height);
|
||||
}
|
||||
/** @return Current screen height in pixels. */
|
||||
moduleBaseFunction(moduleScreenGetHeight);
|
||||
|
||||
moduleBaseFunction(moduleScreenGetAspect) {
|
||||
return jerry_number((double)SCREEN.aspect);
|
||||
}
|
||||
/** @return Current screen aspect ratio (width / height). */
|
||||
moduleBaseFunction(moduleScreenGetAspect);
|
||||
|
||||
static void moduleScreenInit(void) {
|
||||
scriptProtoInit(&MODULE_SCREEN_PROTO, "Screen", sizeof(uint8_t), NULL);
|
||||
/**
|
||||
* Initializes the Screen module and registers read-only width/height/aspect
|
||||
* properties on the global Screen object.
|
||||
*/
|
||||
void moduleScreenInit(void);
|
||||
|
||||
scriptProtoDefineStaticProp(
|
||||
&MODULE_SCREEN_PROTO, "width",
|
||||
moduleScreenGetWidth, NULL
|
||||
);
|
||||
scriptProtoDefineStaticProp(
|
||||
&MODULE_SCREEN_PROTO, "height",
|
||||
moduleScreenGetHeight, NULL
|
||||
);
|
||||
scriptProtoDefineStaticProp(
|
||||
&MODULE_SCREEN_PROTO, "aspect",
|
||||
moduleScreenGetAspect, NULL
|
||||
);
|
||||
}
|
||||
|
||||
static void moduleScreenDispose(void) {
|
||||
scriptProtoDispose(&MODULE_SCREEN_PROTO);
|
||||
}
|
||||
/**
|
||||
* Disposes the Screen module.
|
||||
*/
|
||||
void moduleScreenDispose(void);
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "moduletexture.h"
|
||||
|
||||
scriptproto_t MODULE_TEXTURE_PROTO;
|
||||
|
||||
void moduleTextureFree(void *ptr, jerry_object_native_info_t *info) {
|
||||
jstexture_t *tex = (jstexture_t *)ptr;
|
||||
if(tex && tex->entry) {
|
||||
assetUnlockEntry(tex->entry);
|
||||
tex->entry = NULL;
|
||||
}
|
||||
memoryFree(ptr);
|
||||
}
|
||||
|
||||
jstexture_t *moduleTextureSelf(const jerry_call_info_t *callInfo) {
|
||||
return (jstexture_t *)scriptProtoGetValue(
|
||||
&MODULE_TEXTURE_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTextureCtor) {
|
||||
return moduleBaseThrow("Texture cannot be instantiated with new");
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTextureGetWidth) {
|
||||
jstexture_t *t = moduleTextureSelf(callInfo);
|
||||
if(!t || !t->entry) return jerry_undefined();
|
||||
return jerry_number((double)t->entry->data.texture.width);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTextureGetHeight) {
|
||||
jstexture_t *t = moduleTextureSelf(callInfo);
|
||||
if(!t || !t->entry) return jerry_undefined();
|
||||
return jerry_number((double)t->entry->data.texture.height);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTextureToString) {
|
||||
jstexture_t *t = moduleTextureSelf(callInfo);
|
||||
if(!t || !t->entry) return jerry_string_sz("Texture:invalid");
|
||||
char_t buf[64];
|
||||
snprintf(buf, sizeof(buf), "Texture(%dx%d)",
|
||||
t->entry->data.texture.width,
|
||||
t->entry->data.texture.height
|
||||
);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
void moduleTextureInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_TEXTURE_PROTO, "Texture",
|
||||
sizeof(jstexture_t), moduleTextureCtor
|
||||
);
|
||||
MODULE_TEXTURE_PROTO.info.free_cb = moduleTextureFree;
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_TEXTURE_PROTO, "width", moduleTextureGetWidth, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_TEXTURE_PROTO, "height", moduleTextureGetHeight, NULL
|
||||
);
|
||||
scriptProtoDefineToString(&MODULE_TEXTURE_PROTO, moduleTextureToString);
|
||||
|
||||
jerry_value_t ctor = MODULE_TEXTURE_PROTO.constructor;
|
||||
struct { const char_t *name; int val; } formats[] = {
|
||||
{ "FORMAT_RGBA", TEXTURE_FORMAT_RGBA },
|
||||
{ "FORMAT_PALETTE", TEXTURE_FORMAT_PALETTE },
|
||||
};
|
||||
for(int i = 0; i < 2; i++) {
|
||||
jerry_value_t k = jerry_string_sz(formats[i].name);
|
||||
jerry_value_t v = jerry_number((double)formats[i].val);
|
||||
jerry_object_set(ctor, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
}
|
||||
|
||||
void moduleTextureDispose(void) {
|
||||
scriptProtoDispose(&MODULE_TEXTURE_PROTO);
|
||||
}
|
||||
@@ -13,96 +13,49 @@
|
||||
#include "display/texture/texture.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
static scriptproto_t MODULE_TEXTURE_PROTO;
|
||||
extern scriptproto_t MODULE_TEXTURE_PROTO;
|
||||
|
||||
/** C struct wrapped by every Texture JS instance. */
|
||||
typedef struct {
|
||||
assetentry_t *entry;
|
||||
} jstexture_t;
|
||||
|
||||
/**
|
||||
* Custom free callback — unlocks the asset entry so it can be reclaimed
|
||||
* once the JS Texture object is garbage collected.
|
||||
* GC free callback — unlocks the asset entry when the Texture JS object is
|
||||
* garbage collected.
|
||||
*
|
||||
* @param ptr Native jstexture_t pointer.
|
||||
* @param info Native info (unused).
|
||||
*/
|
||||
static void moduleTextureFree(
|
||||
void *ptr,
|
||||
jerry_object_native_info_t *info
|
||||
) {
|
||||
(void)info;
|
||||
jstexture_t *tex = (jstexture_t *)ptr;
|
||||
if(tex && tex->entry) {
|
||||
assetUnlockEntry(tex->entry);
|
||||
tex->entry = NULL;
|
||||
}
|
||||
memoryFree(ptr);
|
||||
}
|
||||
void moduleTextureFree(void *ptr, jerry_object_native_info_t *info);
|
||||
|
||||
moduleBaseFunction(moduleTextureCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("Texture cannot be instantiated with new");
|
||||
}
|
||||
/**
|
||||
* Returns the jstexture_t pointer from the current this_value.
|
||||
*
|
||||
* @param callInfo The call info.
|
||||
* @return Pointer to the jstexture_t, or NULL if invalid.
|
||||
*/
|
||||
jstexture_t *moduleTextureSelf(const jerry_call_info_t *callInfo);
|
||||
|
||||
static inline jstexture_t *moduleTextureSelf(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (jstexture_t *)scriptProtoGetValue(
|
||||
&MODULE_TEXTURE_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
/** Texture() constructor — always throws; not directly instantiable. */
|
||||
moduleBaseFunction(moduleTextureCtor);
|
||||
|
||||
moduleBaseFunction(moduleTextureGetWidth) {
|
||||
jstexture_t *t = moduleTextureSelf(callInfo);
|
||||
if(!t || !t->entry) return jerry_undefined();
|
||||
return jerry_number((double)t->entry->data.texture.width);
|
||||
}
|
||||
/** @return Texture width in pixels, or undefined if not loaded. */
|
||||
moduleBaseFunction(moduleTextureGetWidth);
|
||||
|
||||
moduleBaseFunction(moduleTextureGetHeight) {
|
||||
jstexture_t *t = moduleTextureSelf(callInfo);
|
||||
if(!t || !t->entry) return jerry_undefined();
|
||||
return jerry_number((double)t->entry->data.texture.height);
|
||||
}
|
||||
/** @return Texture height in pixels, or undefined if not loaded. */
|
||||
moduleBaseFunction(moduleTextureGetHeight);
|
||||
|
||||
moduleBaseFunction(moduleTextureToString) {
|
||||
jstexture_t *t = moduleTextureSelf(callInfo);
|
||||
if(!t || !t->entry) return jerry_string_sz("Texture:invalid");
|
||||
char_t buf[64];
|
||||
snprintf(buf, sizeof(buf), "Texture(%dx%d)",
|
||||
t->entry->data.texture.width,
|
||||
t->entry->data.texture.height
|
||||
);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
/** @return "Texture(WxH)" string. */
|
||||
moduleBaseFunction(moduleTextureToString);
|
||||
|
||||
static void moduleTextureInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_TEXTURE_PROTO, "Texture",
|
||||
sizeof(jstexture_t), moduleTextureCtor
|
||||
);
|
||||
/* Override the default free callback so the asset lock is released on GC. */
|
||||
MODULE_TEXTURE_PROTO.info.free_cb = moduleTextureFree;
|
||||
/**
|
||||
* Initializes the Texture module and registers the global Texture class with
|
||||
* FORMAT_RGBA and FORMAT_PALETTE constants.
|
||||
*/
|
||||
void moduleTextureInit(void);
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_TEXTURE_PROTO, "width", moduleTextureGetWidth, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_TEXTURE_PROTO, "height", moduleTextureGetHeight, NULL
|
||||
);
|
||||
scriptProtoDefineToString(&MODULE_TEXTURE_PROTO, moduleTextureToString);
|
||||
|
||||
/* Texture.FORMAT_* constants */
|
||||
jerry_value_t ctor = MODULE_TEXTURE_PROTO.constructor;
|
||||
struct { const char_t *name; int val; } formats[] = {
|
||||
{ "FORMAT_RGBA", TEXTURE_FORMAT_RGBA },
|
||||
{ "FORMAT_PALETTE", TEXTURE_FORMAT_PALETTE },
|
||||
};
|
||||
for(int i = 0; i < 2; i++) {
|
||||
jerry_value_t k = jerry_string_sz(formats[i].name);
|
||||
jerry_value_t v = jerry_number((double)formats[i].val);
|
||||
jerry_object_set(ctor, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
}
|
||||
|
||||
static void moduleTextureDispose(void) {
|
||||
scriptProtoDispose(&MODULE_TEXTURE_PROTO);
|
||||
}
|
||||
/**
|
||||
* Disposes the Texture module.
|
||||
*/
|
||||
void moduleTextureDispose(void);
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
moduleengine.c
|
||||
moduleframe.c
|
||||
moduletimeout.c
|
||||
)
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "moduleengine.h"
|
||||
|
||||
scriptproto_t MODULE_ENGINE_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleEngineGetRunning) {
|
||||
return jerry_boolean(ENGINE.running);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleEngineExit) {
|
||||
ENGINE.running = false;
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
void moduleEngineInit(void) {
|
||||
scriptProtoInit(&MODULE_ENGINE_PROTO, "Engine", sizeof(uint8_t), NULL);
|
||||
scriptProtoDefineStaticProp(
|
||||
&MODULE_ENGINE_PROTO, "running",
|
||||
moduleEngineGetRunning, NULL
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_ENGINE_PROTO, "exit", moduleEngineExit
|
||||
);
|
||||
}
|
||||
|
||||
void moduleEngineDispose(void) {
|
||||
scriptProtoDispose(&MODULE_ENGINE_PROTO);
|
||||
}
|
||||
@@ -10,29 +10,21 @@
|
||||
#include "script/scriptproto.h"
|
||||
#include "engine/engine.h"
|
||||
|
||||
static scriptproto_t MODULE_ENGINE_PROTO;
|
||||
extern scriptproto_t MODULE_ENGINE_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleEngineGetRunning) {
|
||||
return jerry_boolean(ENGINE.running);
|
||||
}
|
||||
/** @return True if the engine main loop is still running. */
|
||||
moduleBaseFunction(moduleEngineGetRunning);
|
||||
|
||||
moduleBaseFunction(moduleEngineExit) {
|
||||
ENGINE.running = false;
|
||||
return jerry_undefined();
|
||||
}
|
||||
/** Signals the engine to stop on the next frame. */
|
||||
moduleBaseFunction(moduleEngineExit);
|
||||
|
||||
static void moduleEngineInit(void) {
|
||||
scriptProtoInit(&MODULE_ENGINE_PROTO, "Engine", sizeof(uint8_t), NULL);
|
||||
/**
|
||||
* Initializes the Engine module and registers the global Engine object with the
|
||||
* running property and exit() method.
|
||||
*/
|
||||
void moduleEngineInit(void);
|
||||
|
||||
scriptProtoDefineStaticProp(
|
||||
&MODULE_ENGINE_PROTO, "running",
|
||||
moduleEngineGetRunning, NULL
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_ENGINE_PROTO, "exit", moduleEngineExit
|
||||
);
|
||||
}
|
||||
|
||||
static void moduleEngineDispose(void) {
|
||||
scriptProtoDispose(&MODULE_ENGINE_PROTO);
|
||||
}
|
||||
/**
|
||||
* Disposes the Engine module.
|
||||
*/
|
||||
void moduleEngineDispose(void);
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "moduleframe.h"
|
||||
|
||||
jerry_value_t MODULE_FRAME_PENDING[MODULE_FRAME_PENDING_MAX];
|
||||
uint32_t MODULE_FRAME_PENDING_COUNT = 0;
|
||||
|
||||
moduleBaseFunction(moduleFrameFrame) {
|
||||
if(MODULE_FRAME_PENDING_COUNT >= MODULE_FRAME_PENDING_MAX) {
|
||||
return moduleBaseThrow("Too many pending frame() calls");
|
||||
}
|
||||
jerry_value_t promise = jerry_promise();
|
||||
MODULE_FRAME_PENDING[MODULE_FRAME_PENDING_COUNT++] =
|
||||
jerry_value_copy(promise);
|
||||
return promise;
|
||||
}
|
||||
|
||||
void moduleFrameFlush(void) {
|
||||
uint32_t count = MODULE_FRAME_PENDING_COUNT;
|
||||
MODULE_FRAME_PENDING_COUNT = 0;
|
||||
for(uint32_t i = 0; i < count; i++) {
|
||||
jerry_value_t ret = jerry_promise_resolve(
|
||||
MODULE_FRAME_PENDING[i], jerry_undefined()
|
||||
);
|
||||
jerry_value_free(ret);
|
||||
jerry_value_free(MODULE_FRAME_PENDING[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void moduleFrameInit(void) {
|
||||
MODULE_FRAME_PENDING_COUNT = 0;
|
||||
moduleBaseDefineGlobalMethod("frame", moduleFrameFrame);
|
||||
}
|
||||
|
||||
void moduleFrameDispose(void) {
|
||||
for(uint32_t i = 0; i < MODULE_FRAME_PENDING_COUNT; i++) {
|
||||
jerry_value_free(MODULE_FRAME_PENDING[i]);
|
||||
}
|
||||
MODULE_FRAME_PENDING_COUNT = 0;
|
||||
}
|
||||
@@ -8,38 +8,30 @@
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
|
||||
/** Maximum number of concurrent frame() awaits. */
|
||||
#define MODULE_FRAME_PENDING_MAX 64
|
||||
|
||||
static jerry_value_t MODULE_FRAME_PENDING[MODULE_FRAME_PENDING_MAX];
|
||||
static uint32_t MODULE_FRAME_PENDING_COUNT = 0;
|
||||
extern jerry_value_t MODULE_FRAME_PENDING[MODULE_FRAME_PENDING_MAX];
|
||||
extern uint32_t MODULE_FRAME_PENDING_COUNT;
|
||||
|
||||
moduleBaseFunction(moduleFrameFrame) {
|
||||
if(MODULE_FRAME_PENDING_COUNT >= MODULE_FRAME_PENDING_MAX) {
|
||||
return moduleBaseThrow("Too many pending frame() calls");
|
||||
}
|
||||
jerry_value_t promise = jerry_promise();
|
||||
MODULE_FRAME_PENDING[MODULE_FRAME_PENDING_COUNT++] = jerry_value_copy(promise);
|
||||
return promise;
|
||||
}
|
||||
/**
|
||||
* frame() — returns a Promise that resolves at the start of the next frame.
|
||||
* Used as `await frame()` inside an async script loop.
|
||||
*/
|
||||
moduleBaseFunction(moduleFrameFrame);
|
||||
|
||||
static void moduleFrameFlush(void) {
|
||||
uint32_t count = MODULE_FRAME_PENDING_COUNT;
|
||||
MODULE_FRAME_PENDING_COUNT = 0;
|
||||
for(uint32_t i = 0; i < count; i++) {
|
||||
jerry_value_t ret = jerry_promise_resolve(MODULE_FRAME_PENDING[i], jerry_undefined());
|
||||
jerry_value_free(ret);
|
||||
jerry_value_free(MODULE_FRAME_PENDING[i]);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Resolves all pending frame() promises. Must be called once per frame before
|
||||
* jerry_run_jobs() so that awaiting scripts resume in the same tick.
|
||||
*/
|
||||
void moduleFrameFlush(void);
|
||||
|
||||
static void moduleFrameInit(void) {
|
||||
MODULE_FRAME_PENDING_COUNT = 0;
|
||||
moduleBaseDefineGlobalMethod("frame", moduleFrameFrame);
|
||||
}
|
||||
/**
|
||||
* Initializes the frame module and registers the global frame() function.
|
||||
*/
|
||||
void moduleFrameInit(void);
|
||||
|
||||
static void moduleFrameDispose(void) {
|
||||
for(uint32_t i = 0; i < MODULE_FRAME_PENDING_COUNT; i++) {
|
||||
jerry_value_free(MODULE_FRAME_PENDING[i]);
|
||||
}
|
||||
MODULE_FRAME_PENDING_COUNT = 0;
|
||||
}
|
||||
/**
|
||||
* Disposes the frame module, releasing any unresolved pending promises.
|
||||
*/
|
||||
void moduleFrameDispose(void);
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "moduletimeout.h"
|
||||
|
||||
moduletimeoutentry_t MODULE_TIMEOUT_PENDING[MODULE_TIMEOUT_PENDING_MAX];
|
||||
uint32_t MODULE_TIMEOUT_PENDING_COUNT = 0;
|
||||
|
||||
moduleBaseFunction(moduleTimeoutTimeout) {
|
||||
moduleBaseRequireArgs(1);
|
||||
moduleBaseRequireNumber(0);
|
||||
|
||||
if(MODULE_TIMEOUT_PENDING_COUNT >= MODULE_TIMEOUT_PENDING_MAX) {
|
||||
return moduleBaseThrow("Too many pending timeout() calls");
|
||||
}
|
||||
|
||||
float_t ms = moduleBaseArgFloat(0);
|
||||
jerry_value_t promise = jerry_promise();
|
||||
MODULE_TIMEOUT_PENDING[MODULE_TIMEOUT_PENDING_COUNT].promise =
|
||||
jerry_value_copy(promise);
|
||||
MODULE_TIMEOUT_PENDING[MODULE_TIMEOUT_PENDING_COUNT].targetTime =
|
||||
TIME.time + ms / 1000.0f;
|
||||
MODULE_TIMEOUT_PENDING_COUNT++;
|
||||
return promise;
|
||||
}
|
||||
|
||||
void moduleTimeoutFlush(void) {
|
||||
uint32_t i = 0;
|
||||
while(i < MODULE_TIMEOUT_PENDING_COUNT) {
|
||||
if(TIME.time >= MODULE_TIMEOUT_PENDING[i].targetTime) {
|
||||
jerry_value_t ret = jerry_promise_resolve(
|
||||
MODULE_TIMEOUT_PENDING[i].promise, jerry_undefined()
|
||||
);
|
||||
jerry_value_free(ret);
|
||||
jerry_value_free(MODULE_TIMEOUT_PENDING[i].promise);
|
||||
MODULE_TIMEOUT_PENDING_COUNT--;
|
||||
if(i < MODULE_TIMEOUT_PENDING_COUNT) {
|
||||
MODULE_TIMEOUT_PENDING[i] =
|
||||
MODULE_TIMEOUT_PENDING[MODULE_TIMEOUT_PENDING_COUNT];
|
||||
}
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void moduleTimeoutInit(void) {
|
||||
MODULE_TIMEOUT_PENDING_COUNT = 0;
|
||||
moduleBaseDefineGlobalMethod("timeout", moduleTimeoutTimeout);
|
||||
}
|
||||
|
||||
void moduleTimeoutDispose(void) {
|
||||
for(uint32_t i = 0; i < MODULE_TIMEOUT_PENDING_COUNT; i++) {
|
||||
jerry_value_free(MODULE_TIMEOUT_PENDING[i].promise);
|
||||
}
|
||||
MODULE_TIMEOUT_PENDING_COUNT = 0;
|
||||
}
|
||||
@@ -9,59 +9,38 @@
|
||||
#include "script/module/modulebase.h"
|
||||
#include "time/time.h"
|
||||
|
||||
/** Maximum number of concurrent timeout() awaits. */
|
||||
#define MODULE_TIMEOUT_PENDING_MAX 64
|
||||
|
||||
/** Entry tracking one pending timeout() promise. */
|
||||
typedef struct {
|
||||
jerry_value_t promise;
|
||||
float_t targetTime;
|
||||
} moduletimeoutentry_t;
|
||||
|
||||
static moduletimeoutentry_t MODULE_TIMEOUT_PENDING[MODULE_TIMEOUT_PENDING_MAX];
|
||||
static uint32_t MODULE_TIMEOUT_PENDING_COUNT = 0;
|
||||
extern moduletimeoutentry_t MODULE_TIMEOUT_PENDING[MODULE_TIMEOUT_PENDING_MAX];
|
||||
extern uint32_t MODULE_TIMEOUT_PENDING_COUNT;
|
||||
|
||||
moduleBaseFunction(moduleTimeoutTimeout) {
|
||||
moduleBaseRequireArgs(1);
|
||||
moduleBaseRequireNumber(0);
|
||||
/**
|
||||
* timeout(ms) — returns a Promise that resolves after at least `ms`
|
||||
* milliseconds have elapsed. Used as `await timeout(500)`.
|
||||
*
|
||||
* @param args[0] Delay in milliseconds (number).
|
||||
*/
|
||||
moduleBaseFunction(moduleTimeoutTimeout);
|
||||
|
||||
if(MODULE_TIMEOUT_PENDING_COUNT >= MODULE_TIMEOUT_PENDING_MAX) {
|
||||
return moduleBaseThrow("Too many pending timeout() calls");
|
||||
}
|
||||
/**
|
||||
* Resolves any pending timeout() promises whose target time has passed.
|
||||
* Must be called once per frame before jerry_run_jobs().
|
||||
*/
|
||||
void moduleTimeoutFlush(void);
|
||||
|
||||
float_t ms = moduleBaseArgFloat(0);
|
||||
jerry_value_t promise = jerry_promise();
|
||||
MODULE_TIMEOUT_PENDING[MODULE_TIMEOUT_PENDING_COUNT].promise = jerry_value_copy(promise);
|
||||
MODULE_TIMEOUT_PENDING[MODULE_TIMEOUT_PENDING_COUNT].targetTime = TIME.time + ms / 1000.0f;
|
||||
MODULE_TIMEOUT_PENDING_COUNT++;
|
||||
return promise;
|
||||
}
|
||||
/**
|
||||
* Initializes the timeout module and registers the global timeout() function.
|
||||
*/
|
||||
void moduleTimeoutInit(void);
|
||||
|
||||
static void moduleTimeoutFlush(void) {
|
||||
uint32_t i = 0;
|
||||
while(i < MODULE_TIMEOUT_PENDING_COUNT) {
|
||||
if(TIME.time >= MODULE_TIMEOUT_PENDING[i].targetTime) {
|
||||
jerry_value_t ret = jerry_promise_resolve(
|
||||
MODULE_TIMEOUT_PENDING[i].promise, jerry_undefined()
|
||||
);
|
||||
jerry_value_free(ret);
|
||||
jerry_value_free(MODULE_TIMEOUT_PENDING[i].promise);
|
||||
MODULE_TIMEOUT_PENDING_COUNT--;
|
||||
if(i < MODULE_TIMEOUT_PENDING_COUNT) {
|
||||
MODULE_TIMEOUT_PENDING[i] = MODULE_TIMEOUT_PENDING[MODULE_TIMEOUT_PENDING_COUNT];
|
||||
}
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void moduleTimeoutInit(void) {
|
||||
MODULE_TIMEOUT_PENDING_COUNT = 0;
|
||||
moduleBaseDefineGlobalMethod("timeout", moduleTimeoutTimeout);
|
||||
}
|
||||
|
||||
static void moduleTimeoutDispose(void) {
|
||||
for(uint32_t i = 0; i < MODULE_TIMEOUT_PENDING_COUNT; i++) {
|
||||
jerry_value_free(MODULE_TIMEOUT_PENDING[i].promise);
|
||||
}
|
||||
MODULE_TIMEOUT_PENDING_COUNT = 0;
|
||||
}
|
||||
/**
|
||||
* Disposes the timeout module, releasing any unresolved pending promises.
|
||||
*/
|
||||
void moduleTimeoutDispose(void);
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
modulecomponent.c
|
||||
moduleentity.c
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(component)
|
||||
@@ -0,0 +1,14 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
modulecomponentlist.c
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(display)
|
||||
add_subdirectory(physics)
|
||||
add_subdirectory(trigger)
|
||||
@@ -0,0 +1,11 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
modulecamera.c
|
||||
moduleposition.c
|
||||
modulerenderable.c
|
||||
)
|
||||
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "modulecamera.h"
|
||||
|
||||
scriptproto_t MODULE_CAMERA_PROTO;
|
||||
|
||||
jscomponent_t *moduleCameraSelf(const jerry_call_info_t *callInfo) {
|
||||
return (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_CAMERA_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
entitycamera_t *moduleCameraData(const jscomponent_t *c) {
|
||||
return (entitycamera_t *)componentGetData(
|
||||
c->entityId, c->componentId, COMPONENT_TYPE_CAMERA
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleCameraCtor) {
|
||||
return moduleBaseThrow("Camera cannot be instantiated with new");
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleCameraGetEntity) {
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->entityId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleCameraGetId) {
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->componentId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleCameraGetFov) {
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitycamera_t *cam = moduleCameraData(c);
|
||||
if(!cam) return jerry_undefined();
|
||||
return jerry_number((double)cam->perspective.fov);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleCameraSetFov) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitycamera_t *cam = moduleCameraData(c);
|
||||
if(!cam) return jerry_undefined();
|
||||
cam->perspective.fov = moduleBaseArgFloat(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleCameraGetNearClip) {
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitycamera_t *cam = moduleCameraData(c);
|
||||
if(!cam) return jerry_undefined();
|
||||
return jerry_number((double)cam->nearClip);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleCameraSetNearClip) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitycamera_t *cam = moduleCameraData(c);
|
||||
if(!cam) return jerry_undefined();
|
||||
cam->nearClip = moduleBaseArgFloat(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleCameraGetFarClip) {
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitycamera_t *cam = moduleCameraData(c);
|
||||
if(!cam) return jerry_undefined();
|
||||
return jerry_number((double)cam->farClip);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleCameraSetFarClip) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitycamera_t *cam = moduleCameraData(c);
|
||||
if(!cam) return jerry_undefined();
|
||||
cam->farClip = moduleBaseArgFloat(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleCameraGetProjType) {
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitycamera_t *cam = moduleCameraData(c);
|
||||
if(!cam) return jerry_undefined();
|
||||
return jerry_number((double)cam->projType);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleCameraSetProjType) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitycamera_t *cam = moduleCameraData(c);
|
||||
if(!cam) return jerry_undefined();
|
||||
cam->projType = (entitycameraprojectiontype_t)moduleBaseArgInt(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleCameraToString) {
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_string_sz("Camera:invalid");
|
||||
char_t buf[32];
|
||||
snprintf(buf, sizeof(buf), "Camera(%u)", (unsigned)c->componentId);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
void moduleCameraInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_CAMERA_PROTO, "Camera",
|
||||
sizeof(jscomponent_t), moduleCameraCtor
|
||||
);
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_CAMERA_PROTO, "entity", moduleCameraGetEntity, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_CAMERA_PROTO, "id", moduleCameraGetId, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_CAMERA_PROTO, "fov", moduleCameraGetFov, moduleCameraSetFov
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_CAMERA_PROTO, "nearClip",
|
||||
moduleCameraGetNearClip, moduleCameraSetNearClip
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_CAMERA_PROTO, "farClip",
|
||||
moduleCameraGetFarClip, moduleCameraSetFarClip
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_CAMERA_PROTO, "projType",
|
||||
moduleCameraGetProjType, moduleCameraSetProjType
|
||||
);
|
||||
scriptProtoDefineToString(&MODULE_CAMERA_PROTO, moduleCameraToString);
|
||||
|
||||
jerry_value_t ctor = MODULE_CAMERA_PROTO.constructor;
|
||||
struct { const char_t *name; int val; } projtypes[] = {
|
||||
{ "PERSPECTIVE", ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE },
|
||||
{
|
||||
"PERSPECTIVE_FLIPPED",
|
||||
ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED
|
||||
},
|
||||
{ "ORTHOGRAPHIC", ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC },
|
||||
};
|
||||
for(int i = 0; i < 3; i++) {
|
||||
jerry_value_t k = jerry_string_sz(projtypes[i].name);
|
||||
jerry_value_t v = jerry_number((double)projtypes[i].val);
|
||||
jerry_object_set(ctor, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
}
|
||||
|
||||
void moduleCameraDispose(void) {
|
||||
scriptProtoDispose(&MODULE_CAMERA_PROTO);
|
||||
}
|
||||
@@ -11,164 +11,52 @@
|
||||
#include "script/module/entity/modulecomponent.h"
|
||||
#include "entity/component/display/entitycamera.h"
|
||||
|
||||
static scriptproto_t MODULE_CAMERA_PROTO;
|
||||
extern scriptproto_t MODULE_CAMERA_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleCameraCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("Camera cannot be instantiated with new");
|
||||
}
|
||||
/** Camera() constructor — always throws; not directly instantiable. */
|
||||
moduleBaseFunction(moduleCameraCtor);
|
||||
|
||||
static inline jscomponent_t *moduleCameraSelf(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_CAMERA_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
/** @return Entity ID that owns this camera component. */
|
||||
moduleBaseFunction(moduleCameraGetEntity);
|
||||
|
||||
static inline entitycamera_t *moduleCameraData(const jscomponent_t *c) {
|
||||
return (entitycamera_t *)componentGetData(
|
||||
c->entityId, c->componentId, COMPONENT_TYPE_CAMERA
|
||||
);
|
||||
}
|
||||
/** @return This component's ID. */
|
||||
moduleBaseFunction(moduleCameraGetId);
|
||||
|
||||
moduleBaseFunction(moduleCameraGetEntity) {
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->entityId);
|
||||
}
|
||||
/** @return Field of view in degrees. */
|
||||
moduleBaseFunction(moduleCameraGetFov);
|
||||
|
||||
moduleBaseFunction(moduleCameraGetId) {
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->componentId);
|
||||
}
|
||||
/** Sets field of view. @param args[0] FOV in degrees. */
|
||||
moduleBaseFunction(moduleCameraSetFov);
|
||||
|
||||
moduleBaseFunction(moduleCameraGetFov) {
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitycamera_t *cam = moduleCameraData(c);
|
||||
if(!cam) return jerry_undefined();
|
||||
return jerry_number((double)cam->perspective.fov);
|
||||
}
|
||||
/** @return Near clip plane distance. */
|
||||
moduleBaseFunction(moduleCameraGetNearClip);
|
||||
|
||||
moduleBaseFunction(moduleCameraSetFov) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitycamera_t *cam = moduleCameraData(c);
|
||||
if(!cam) return jerry_undefined();
|
||||
cam->perspective.fov = moduleBaseArgFloat(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/** Sets near clip plane. @param args[0] Near clip distance. */
|
||||
moduleBaseFunction(moduleCameraSetNearClip);
|
||||
|
||||
moduleBaseFunction(moduleCameraGetNearClip) {
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitycamera_t *cam = moduleCameraData(c);
|
||||
if(!cam) return jerry_undefined();
|
||||
return jerry_number((double)cam->nearClip);
|
||||
}
|
||||
/** @return Far clip plane distance. */
|
||||
moduleBaseFunction(moduleCameraGetFarClip);
|
||||
|
||||
moduleBaseFunction(moduleCameraSetNearClip) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitycamera_t *cam = moduleCameraData(c);
|
||||
if(!cam) return jerry_undefined();
|
||||
cam->nearClip = moduleBaseArgFloat(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/** Sets far clip plane. @param args[0] Far clip distance. */
|
||||
moduleBaseFunction(moduleCameraSetFarClip);
|
||||
|
||||
moduleBaseFunction(moduleCameraGetFarClip) {
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitycamera_t *cam = moduleCameraData(c);
|
||||
if(!cam) return jerry_undefined();
|
||||
return jerry_number((double)cam->farClip);
|
||||
}
|
||||
/** @return Projection type constant (Camera.PERSPECTIVE etc.). */
|
||||
moduleBaseFunction(moduleCameraGetProjType);
|
||||
|
||||
moduleBaseFunction(moduleCameraSetFarClip) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitycamera_t *cam = moduleCameraData(c);
|
||||
if(!cam) return jerry_undefined();
|
||||
cam->farClip = moduleBaseArgFloat(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/** Sets projection type. @param args[0] entitycameraprojectiontype_t value. */
|
||||
moduleBaseFunction(moduleCameraSetProjType);
|
||||
|
||||
moduleBaseFunction(moduleCameraGetProjType) {
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitycamera_t *cam = moduleCameraData(c);
|
||||
if(!cam) return jerry_undefined();
|
||||
return jerry_number((double)cam->projType);
|
||||
}
|
||||
/** @return "Camera(id)" string. */
|
||||
moduleBaseFunction(moduleCameraToString);
|
||||
|
||||
moduleBaseFunction(moduleCameraSetProjType) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitycamera_t *cam = moduleCameraData(c);
|
||||
if(!cam) return jerry_undefined();
|
||||
cam->projType = (entitycameraprojectiontype_t)moduleBaseArgInt(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/**
|
||||
* Initializes the Camera module and registers the global Camera class with
|
||||
* fov/nearClip/farClip/projType properties and PERSPECTIVE/ORTHOGRAPHIC
|
||||
* constants.
|
||||
*/
|
||||
void moduleCameraInit(void);
|
||||
|
||||
moduleBaseFunction(moduleCameraToString) {
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_string_sz("Camera:invalid");
|
||||
char_t buf[32];
|
||||
snprintf(buf, sizeof(buf), "Camera(%u)", (unsigned)c->componentId);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
static void moduleCameraInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_CAMERA_PROTO, "Camera",
|
||||
sizeof(jscomponent_t), moduleCameraCtor
|
||||
);
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_CAMERA_PROTO, "entity", moduleCameraGetEntity, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_CAMERA_PROTO, "id", moduleCameraGetId, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_CAMERA_PROTO, "fov", moduleCameraGetFov, moduleCameraSetFov
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_CAMERA_PROTO, "nearClip",
|
||||
moduleCameraGetNearClip, moduleCameraSetNearClip
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_CAMERA_PROTO, "farClip",
|
||||
moduleCameraGetFarClip, moduleCameraSetFarClip
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_CAMERA_PROTO, "projType",
|
||||
moduleCameraGetProjType, moduleCameraSetProjType
|
||||
);
|
||||
scriptProtoDefineToString(&MODULE_CAMERA_PROTO, moduleCameraToString);
|
||||
|
||||
/* Camera.PERSPECTIVE, Camera.PERSPECTIVE_FLIPPED, Camera.ORTHOGRAPHIC */
|
||||
jerry_value_t ctor = MODULE_CAMERA_PROTO.constructor;
|
||||
struct { const char_t *name; int val; } projtypes[] = {
|
||||
{ "PERSPECTIVE", ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE },
|
||||
{ "PERSPECTIVE_FLIPPED", ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED },
|
||||
{ "ORTHOGRAPHIC", ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC },
|
||||
};
|
||||
for(int i = 0; i < 3; i++) {
|
||||
jerry_value_t k = jerry_string_sz(projtypes[i].name);
|
||||
jerry_value_t v = jerry_number((double)projtypes[i].val);
|
||||
jerry_object_set(ctor, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
}
|
||||
|
||||
static void moduleCameraDispose(void) {
|
||||
scriptProtoDispose(&MODULE_CAMERA_PROTO);
|
||||
}
|
||||
/**
|
||||
* Disposes the Camera module.
|
||||
*/
|
||||
void moduleCameraDispose(void);
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "moduleposition.h"
|
||||
|
||||
scriptproto_t MODULE_POSITION_PROTO;
|
||||
|
||||
jscomponent_t *modulePositionSelf(const jerry_call_info_t *callInfo) {
|
||||
return (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_POSITION_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionCtor) {
|
||||
return moduleBaseThrow("Position cannot be instantiated with new");
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionGetEntity) {
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->entityId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionGetId) {
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->componentId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionGetLocalPos) {
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
vec3 v;
|
||||
entityPositionGetLocalPosition(c->entityId, c->componentId, v);
|
||||
return moduleVec3Push(v);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionSetLocalPos) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("Position.localPosition: expected Vec3");
|
||||
entityPositionSetLocalPosition(c->entityId, c->componentId, v);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionGetWorldPos) {
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
vec3 v;
|
||||
entityPositionGetWorldPosition(c->entityId, c->componentId, v);
|
||||
return moduleVec3Push(v);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionSetWorldPos) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("Position.worldPosition: expected Vec3");
|
||||
entityPositionSetWorldPosition(c->entityId, c->componentId, v);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionGetLocalRot) {
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
vec3 v;
|
||||
entityPositionGetLocalRotation(c->entityId, c->componentId, v);
|
||||
return moduleVec3Push(v);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionSetLocalRot) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("Position.localRotation: expected Vec3");
|
||||
entityPositionSetLocalRotation(c->entityId, c->componentId, v);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionGetWorldRot) {
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
vec3 v;
|
||||
entityPositionGetWorldRotation(c->entityId, c->componentId, v);
|
||||
return moduleVec3Push(v);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionSetWorldRot) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("Position.worldRotation: expected Vec3");
|
||||
entityPositionSetWorldRotation(c->entityId, c->componentId, v);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionGetLocalScale) {
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
vec3 v;
|
||||
entityPositionGetLocalScale(c->entityId, c->componentId, v);
|
||||
return moduleVec3Push(v);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionSetLocalScale) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("Position.localScale: expected Vec3");
|
||||
entityPositionSetLocalScale(c->entityId, c->componentId, v);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionGetWorldScale) {
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
vec3 v;
|
||||
entityPositionGetWorldScale(c->entityId, c->componentId, v);
|
||||
return moduleVec3Push(v);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionSetWorldScale) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("Position.worldScale: expected Vec3");
|
||||
entityPositionSetWorldScale(c->entityId, c->componentId, v);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionLookAt) {
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
moduleBaseRequireArgs(1);
|
||||
float_t *target = moduleVec3From(args[0]);
|
||||
if(!target) return moduleBaseThrow("Position.lookAt: expected Vec3 target");
|
||||
|
||||
vec3 eye;
|
||||
entityPositionGetLocalPosition(c->entityId, c->componentId, eye);
|
||||
|
||||
vec3 up = { 0.0f, 1.0f, 0.0f };
|
||||
if(argc >= 2) {
|
||||
float_t *upArg = moduleVec3From(args[1]);
|
||||
if(upArg) glm_vec3_copy(upArg, up);
|
||||
}
|
||||
|
||||
entityPositionLookAt(c->entityId, c->componentId, eye, target, up);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionSetParent) {
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
if(argc == 0 ||
|
||||
jerry_value_is_null(args[0]) ||
|
||||
jerry_value_is_undefined(args[0])) {
|
||||
entityPositionSetParent(
|
||||
c->entityId, c->componentId,
|
||||
ENTITY_ID_INVALID, COMPONENT_ID_INVALID
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
jscomponent_t *parent = (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_POSITION_PROTO, args[0]
|
||||
);
|
||||
if(!parent) {
|
||||
return moduleBaseThrow(
|
||||
"Position.setParent: expected Position or null"
|
||||
);
|
||||
}
|
||||
entityPositionSetParent(
|
||||
c->entityId, c->componentId,
|
||||
parent->entityId, parent->componentId
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionToString) {
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_string_sz("Position:invalid");
|
||||
char_t buf[32];
|
||||
snprintf(buf, sizeof(buf), "Position(%u)", (unsigned)c->componentId);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
void modulePositionInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_POSITION_PROTO, "Position",
|
||||
sizeof(jscomponent_t), modulePositionCtor
|
||||
);
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_POSITION_PROTO, "entity", modulePositionGetEntity, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_POSITION_PROTO, "id", modulePositionGetId, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_POSITION_PROTO, "localPosition",
|
||||
modulePositionGetLocalPos, modulePositionSetLocalPos
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_POSITION_PROTO, "worldPosition",
|
||||
modulePositionGetWorldPos, modulePositionSetWorldPos
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_POSITION_PROTO, "localRotation",
|
||||
modulePositionGetLocalRot, modulePositionSetLocalRot
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_POSITION_PROTO, "worldRotation",
|
||||
modulePositionGetWorldRot, modulePositionSetWorldRot
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_POSITION_PROTO, "localScale",
|
||||
modulePositionGetLocalScale, modulePositionSetLocalScale
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_POSITION_PROTO, "worldScale",
|
||||
modulePositionGetWorldScale, modulePositionSetWorldScale
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_POSITION_PROTO, "lookAt", modulePositionLookAt
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_POSITION_PROTO, "setParent", modulePositionSetParent
|
||||
);
|
||||
scriptProtoDefineToString(&MODULE_POSITION_PROTO, modulePositionToString);
|
||||
}
|
||||
|
||||
void modulePositionDispose(void) {
|
||||
scriptProtoDispose(&MODULE_POSITION_PROTO);
|
||||
}
|
||||
@@ -12,237 +12,78 @@
|
||||
#include "script/module/entity/modulecomponent.h"
|
||||
#include "entity/component/display/entityposition.h"
|
||||
|
||||
static scriptproto_t MODULE_POSITION_PROTO;
|
||||
extern scriptproto_t MODULE_POSITION_PROTO;
|
||||
|
||||
moduleBaseFunction(modulePositionCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("Position cannot be instantiated with new");
|
||||
}
|
||||
/** Position() constructor — always throws; not directly instantiable. */
|
||||
moduleBaseFunction(modulePositionCtor);
|
||||
|
||||
static inline jscomponent_t *modulePositionSelf(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_POSITION_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
/** @return Entity ID that owns this position component. */
|
||||
moduleBaseFunction(modulePositionGetEntity);
|
||||
|
||||
moduleBaseFunction(modulePositionGetEntity) {
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->entityId);
|
||||
}
|
||||
/** @return This component's ID. */
|
||||
moduleBaseFunction(modulePositionGetId);
|
||||
|
||||
moduleBaseFunction(modulePositionGetId) {
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->componentId);
|
||||
}
|
||||
/** @return Local position as a Vec3. */
|
||||
moduleBaseFunction(modulePositionGetLocalPos);
|
||||
|
||||
moduleBaseFunction(modulePositionGetLocalPos) {
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
vec3 v;
|
||||
entityPositionGetLocalPosition(c->entityId, c->componentId, v);
|
||||
return moduleVec3Push(v);
|
||||
}
|
||||
/** Sets local position. @param args[0] Vec3. */
|
||||
moduleBaseFunction(modulePositionSetLocalPos);
|
||||
|
||||
moduleBaseFunction(modulePositionSetLocalPos) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("Position.localPosition: expected Vec3");
|
||||
entityPositionSetLocalPosition(c->entityId, c->componentId, v);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/** @return World position as a Vec3. */
|
||||
moduleBaseFunction(modulePositionGetWorldPos);
|
||||
|
||||
moduleBaseFunction(modulePositionGetWorldPos) {
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
vec3 v;
|
||||
entityPositionGetWorldPosition(c->entityId, c->componentId, v);
|
||||
return moduleVec3Push(v);
|
||||
}
|
||||
/** Sets world position. @param args[0] Vec3. */
|
||||
moduleBaseFunction(modulePositionSetWorldPos);
|
||||
|
||||
moduleBaseFunction(modulePositionSetWorldPos) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("Position.worldPosition: expected Vec3");
|
||||
entityPositionSetWorldPosition(c->entityId, c->componentId, v);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/** @return Local rotation as a Vec3 (Euler angles). */
|
||||
moduleBaseFunction(modulePositionGetLocalRot);
|
||||
|
||||
moduleBaseFunction(modulePositionGetLocalRot) {
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
vec3 v;
|
||||
entityPositionGetLocalRotation(c->entityId, c->componentId, v);
|
||||
return moduleVec3Push(v);
|
||||
}
|
||||
/** Sets local rotation. @param args[0] Vec3. */
|
||||
moduleBaseFunction(modulePositionSetLocalRot);
|
||||
|
||||
moduleBaseFunction(modulePositionSetLocalRot) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("Position.localRotation: expected Vec3");
|
||||
entityPositionSetLocalRotation(c->entityId, c->componentId, v);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/** @return World rotation as a Vec3 (Euler angles). */
|
||||
moduleBaseFunction(modulePositionGetWorldRot);
|
||||
|
||||
moduleBaseFunction(modulePositionGetWorldRot) {
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
vec3 v;
|
||||
entityPositionGetWorldRotation(c->entityId, c->componentId, v);
|
||||
return moduleVec3Push(v);
|
||||
}
|
||||
/** Sets world rotation. @param args[0] Vec3. */
|
||||
moduleBaseFunction(modulePositionSetWorldRot);
|
||||
|
||||
moduleBaseFunction(modulePositionSetWorldRot) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("Position.worldRotation: expected Vec3");
|
||||
entityPositionSetWorldRotation(c->entityId, c->componentId, v);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/** @return Local scale as a Vec3. */
|
||||
moduleBaseFunction(modulePositionGetLocalScale);
|
||||
|
||||
moduleBaseFunction(modulePositionGetLocalScale) {
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
vec3 v;
|
||||
entityPositionGetLocalScale(c->entityId, c->componentId, v);
|
||||
return moduleVec3Push(v);
|
||||
}
|
||||
/** Sets local scale. @param args[0] Vec3. */
|
||||
moduleBaseFunction(modulePositionSetLocalScale);
|
||||
|
||||
moduleBaseFunction(modulePositionSetLocalScale) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("Position.localScale: expected Vec3");
|
||||
entityPositionSetLocalScale(c->entityId, c->componentId, v);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/** @return World scale as a Vec3. */
|
||||
moduleBaseFunction(modulePositionGetWorldScale);
|
||||
|
||||
moduleBaseFunction(modulePositionGetWorldScale) {
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
vec3 v;
|
||||
entityPositionGetWorldScale(c->entityId, c->componentId, v);
|
||||
return moduleVec3Push(v);
|
||||
}
|
||||
/** Sets world scale. @param args[0] Vec3. */
|
||||
moduleBaseFunction(modulePositionSetWorldScale);
|
||||
|
||||
moduleBaseFunction(modulePositionSetWorldScale) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("Position.worldScale: expected Vec3");
|
||||
entityPositionSetWorldScale(c->entityId, c->componentId, v);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/**
|
||||
* lookAt(target, up?) — orients the component toward a target point.
|
||||
* @param args[0] Vec3 target position.
|
||||
* @param args[1] Optional Vec3 up vector (defaults to world up).
|
||||
*/
|
||||
moduleBaseFunction(modulePositionLookAt);
|
||||
|
||||
moduleBaseFunction(modulePositionLookAt) {
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
moduleBaseRequireArgs(1);
|
||||
float_t *target = moduleVec3From(args[0]);
|
||||
if(!target) return moduleBaseThrow("Position.lookAt: expected Vec3 target");
|
||||
/**
|
||||
* setParent(position?) — parents this component to another Position, or
|
||||
* unparents when called with null/undefined.
|
||||
* @param args[0] Position component or null/undefined.
|
||||
*/
|
||||
moduleBaseFunction(modulePositionSetParent);
|
||||
|
||||
vec3 eye;
|
||||
entityPositionGetLocalPosition(c->entityId, c->componentId, eye);
|
||||
/** @return "Position(id)" string. */
|
||||
moduleBaseFunction(modulePositionToString);
|
||||
|
||||
vec3 up = { 0.0f, 1.0f, 0.0f };
|
||||
if(argc >= 2) {
|
||||
float_t *upArg = moduleVec3From(args[1]);
|
||||
if(upArg) glm_vec3_copy(upArg, up);
|
||||
}
|
||||
/**
|
||||
* Initializes the Position module and registers the global Position class with
|
||||
* localPosition/worldPosition/localRotation/worldRotation/localScale/worldScale
|
||||
* properties and lookAt/setParent methods.
|
||||
*/
|
||||
void modulePositionInit(void);
|
||||
|
||||
entityPositionLookAt(c->entityId, c->componentId, eye, target, up);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionSetParent) {
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
if(argc == 0 ||
|
||||
jerry_value_is_null(args[0]) ||
|
||||
jerry_value_is_undefined(args[0])) {
|
||||
entityPositionSetParent(
|
||||
c->entityId, c->componentId,
|
||||
ENTITY_ID_INVALID, COMPONENT_ID_INVALID
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
jscomponent_t *parent = (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_POSITION_PROTO, args[0]
|
||||
);
|
||||
if(!parent) return moduleBaseThrow("Position.setParent: expected Position or null");
|
||||
entityPositionSetParent(
|
||||
c->entityId, c->componentId,
|
||||
parent->entityId, parent->componentId
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionToString) {
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_string_sz("Position:invalid");
|
||||
char_t buf[32];
|
||||
snprintf(buf, sizeof(buf), "Position(%u)", (unsigned)c->componentId);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
static void modulePositionInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_POSITION_PROTO, "Position",
|
||||
sizeof(jscomponent_t), modulePositionCtor
|
||||
);
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_POSITION_PROTO, "entity", modulePositionGetEntity, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_POSITION_PROTO, "id", modulePositionGetId, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_POSITION_PROTO, "localPosition",
|
||||
modulePositionGetLocalPos, modulePositionSetLocalPos
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_POSITION_PROTO, "worldPosition",
|
||||
modulePositionGetWorldPos, modulePositionSetWorldPos
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_POSITION_PROTO, "localRotation",
|
||||
modulePositionGetLocalRot, modulePositionSetLocalRot
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_POSITION_PROTO, "worldRotation",
|
||||
modulePositionGetWorldRot, modulePositionSetWorldRot
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_POSITION_PROTO, "localScale",
|
||||
modulePositionGetLocalScale, modulePositionSetLocalScale
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_POSITION_PROTO, "worldScale",
|
||||
modulePositionGetWorldScale, modulePositionSetWorldScale
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_POSITION_PROTO, "lookAt", modulePositionLookAt
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_POSITION_PROTO, "setParent", modulePositionSetParent
|
||||
);
|
||||
scriptProtoDefineToString(&MODULE_POSITION_PROTO, modulePositionToString);
|
||||
}
|
||||
|
||||
static void modulePositionDispose(void) {
|
||||
scriptProtoDispose(&MODULE_POSITION_PROTO);
|
||||
}
|
||||
/**
|
||||
* Disposes the Position module.
|
||||
*/
|
||||
void modulePositionDispose(void);
|
||||
|
||||
@@ -0,0 +1,278 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "modulerenderable.h"
|
||||
|
||||
scriptproto_t MODULE_RENDERABLE_PROTO;
|
||||
|
||||
jscomponent_t *moduleRenderableSelf(const jerry_call_info_t *callInfo) {
|
||||
return (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_RENDERABLE_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
entityrenderable_t *moduleRenderableData(const jscomponent_t *c) {
|
||||
return (entityrenderable_t *)componentGetData(
|
||||
c->entityId, c->componentId, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
}
|
||||
|
||||
float_t moduleRenderableArrayFloat(
|
||||
const jerry_value_t arr,
|
||||
const uint32_t idx,
|
||||
const float_t def
|
||||
) {
|
||||
if(idx >= jerry_array_length(arr)) return def;
|
||||
jerry_value_t v = jerry_object_get_index(arr, idx);
|
||||
float_t f = jerry_value_is_number(v)
|
||||
? (float_t)jerry_value_as_number(v) : def;
|
||||
jerry_value_free(v);
|
||||
return f;
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableCtor) {
|
||||
return moduleBaseThrow("Renderable cannot be instantiated with new");
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableGetEntity) {
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->entityId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableGetId) {
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->componentId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableGetType) {
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityrenderable_t *r = moduleRenderableData(c);
|
||||
if(!r) return jerry_undefined();
|
||||
return jerry_number((double)r->type);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableSetType) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityRenderableSetType(
|
||||
c->entityId, c->componentId,
|
||||
(entityrenderabletype_t)moduleBaseArgInt(0)
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableGetPriority) {
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityrenderable_t *r = moduleRenderableData(c);
|
||||
if(!r) return jerry_undefined();
|
||||
return jerry_number((double)r->priority);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableSetPriority) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityRenderableSetPriority(
|
||||
c->entityId, c->componentId,
|
||||
(int8_t)moduleBaseArgInt(0)
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableGetColor) {
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityrenderable_t *r = moduleRenderableData(c);
|
||||
if(!r) return jerry_undefined();
|
||||
return moduleColorPush(r->data.material.material.unlit.color);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableSetColor) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityrenderable_t *r = moduleRenderableData(c);
|
||||
if(!r) return jerry_undefined();
|
||||
color_t *col = moduleColorFrom(args[0]);
|
||||
if(!col) return moduleBaseThrow("Renderable.color: expected Color");
|
||||
r->data.material.material.unlit.color = *col;
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableGetTexture) {
|
||||
jerry_value_t key = jerry_string_sz("_tex");
|
||||
jerry_value_t val = jerry_object_get(callInfo->this_value, key);
|
||||
jerry_value_free(key);
|
||||
return val;
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableSetTexture) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityrenderable_t *r = moduleRenderableData(c);
|
||||
if(!r) return jerry_undefined();
|
||||
jstexture_t *tex = (jstexture_t *)scriptProtoGetValue(
|
||||
&MODULE_TEXTURE_PROTO, args[0]
|
||||
);
|
||||
if(!tex || !tex->entry) {
|
||||
return moduleBaseThrow("Renderable.texture: expected Texture");
|
||||
}
|
||||
r->type = ENTITY_RENDERABLE_TYPE_SPRITEBATCH;
|
||||
r->data.spritebatch.texture = &tex->entry->data.texture;
|
||||
jerry_value_t pinKey = jerry_string_sz("_tex");
|
||||
jerry_object_set(callInfo->this_value, pinKey, args[0]);
|
||||
jerry_value_free(pinKey);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableGetSprites) {
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityrenderable_t *r = moduleRenderableData(c);
|
||||
if(!r) return jerry_undefined();
|
||||
const entityrenderablespritebatch_t *sb = &r->data.spritebatch;
|
||||
|
||||
jerry_value_t arr = jerry_array((uint32_t)sb->spriteCount);
|
||||
for(uint32_t i = 0; i < (uint32_t)sb->spriteCount; i++) {
|
||||
const spritebatchsprite_t *s = &sb->sprites[i];
|
||||
float_t vals[10] = {
|
||||
s->min[0], s->min[1], s->min[2],
|
||||
s->max[0], s->max[1], s->max[2],
|
||||
s->uvMin[0], s->uvMin[1],
|
||||
s->uvMax[0], s->uvMax[1],
|
||||
};
|
||||
jerry_value_t sprite = jerry_array(10);
|
||||
for(uint32_t j = 0; j < 10; j++) {
|
||||
jerry_value_t num = jerry_number((double)vals[j]);
|
||||
jerry_object_set_index(sprite, j, num);
|
||||
jerry_value_free(num);
|
||||
}
|
||||
jerry_object_set_index(arr, i, sprite);
|
||||
jerry_value_free(sprite);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableSetSprites) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityrenderable_t *r = moduleRenderableData(c);
|
||||
if(!r) return jerry_undefined();
|
||||
if(!jerry_value_is_array(args[0])) {
|
||||
return moduleBaseThrow("Renderable.sprites: expected Array");
|
||||
}
|
||||
entityrenderablespritebatch_t *sb = &r->data.spritebatch;
|
||||
uint32_t count = jerry_array_length(args[0]);
|
||||
if(count > ENTITY_RENDERABLE_SPRITEBATCH_SPRITES_MAX) {
|
||||
return moduleBaseThrow("Renderable.sprites: exceeds sprite capacity");
|
||||
}
|
||||
sb->spriteCount = 0;
|
||||
for(uint32_t i = 0; i < count; i++) {
|
||||
jerry_value_t elem = jerry_object_get_index(args[0], i);
|
||||
if(!jerry_value_is_array(elem)) {
|
||||
jerry_value_free(elem);
|
||||
return moduleBaseThrow(
|
||||
"Renderable.sprites: each element must be an Array"
|
||||
);
|
||||
}
|
||||
spritebatchsprite_t s;
|
||||
if(jerry_array_length(elem) >= 10) {
|
||||
s.min[0] = moduleRenderableArrayFloat(elem, 0, 0.0f);
|
||||
s.min[1] = moduleRenderableArrayFloat(elem, 1, 0.0f);
|
||||
s.min[2] = moduleRenderableArrayFloat(elem, 2, 0.0f);
|
||||
s.max[0] = moduleRenderableArrayFloat(elem, 3, 0.0f);
|
||||
s.max[1] = moduleRenderableArrayFloat(elem, 4, 0.0f);
|
||||
s.max[2] = moduleRenderableArrayFloat(elem, 5, 0.0f);
|
||||
s.uvMin[0] = moduleRenderableArrayFloat(elem, 6, 0.0f);
|
||||
s.uvMin[1] = moduleRenderableArrayFloat(elem, 7, 0.0f);
|
||||
s.uvMax[0] = moduleRenderableArrayFloat(elem, 8, 1.0f);
|
||||
s.uvMax[1] = moduleRenderableArrayFloat(elem, 9, 1.0f);
|
||||
} else {
|
||||
s.min[0] = moduleRenderableArrayFloat(elem, 0, 0.0f);
|
||||
s.min[1] = moduleRenderableArrayFloat(elem, 1, 0.0f);
|
||||
s.min[2] = 0.0f;
|
||||
s.max[0] = moduleRenderableArrayFloat(elem, 2, 0.0f);
|
||||
s.max[1] = moduleRenderableArrayFloat(elem, 3, 0.0f);
|
||||
s.max[2] = 0.0f;
|
||||
s.uvMin[0] = moduleRenderableArrayFloat(elem, 4, 0.0f);
|
||||
s.uvMin[1] = moduleRenderableArrayFloat(elem, 5, 0.0f);
|
||||
s.uvMax[0] = moduleRenderableArrayFloat(elem, 6, 1.0f);
|
||||
s.uvMax[1] = moduleRenderableArrayFloat(elem, 7, 1.0f);
|
||||
}
|
||||
jerry_value_free(elem);
|
||||
sb->sprites[sb->spriteCount++] = s;
|
||||
}
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableToString) {
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_string_sz("Renderable:invalid");
|
||||
char_t buf[32];
|
||||
snprintf(buf, sizeof(buf), "Renderable(%u)", (unsigned)c->componentId);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
void moduleRenderableInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_RENDERABLE_PROTO, "Renderable",
|
||||
sizeof(jscomponent_t), moduleRenderableCtor
|
||||
);
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_RENDERABLE_PROTO, "entity", moduleRenderableGetEntity, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_RENDERABLE_PROTO, "id", moduleRenderableGetId, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_RENDERABLE_PROTO, "type",
|
||||
moduleRenderableGetType, moduleRenderableSetType
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_RENDERABLE_PROTO, "priority",
|
||||
moduleRenderableGetPriority, moduleRenderableSetPriority
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_RENDERABLE_PROTO, "color",
|
||||
moduleRenderableGetColor, moduleRenderableSetColor
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_RENDERABLE_PROTO, "texture",
|
||||
moduleRenderableGetTexture, moduleRenderableSetTexture
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_RENDERABLE_PROTO, "sprites",
|
||||
moduleRenderableGetSprites, moduleRenderableSetSprites
|
||||
);
|
||||
scriptProtoDefineToString(&MODULE_RENDERABLE_PROTO, moduleRenderableToString);
|
||||
|
||||
jerry_value_t ctor = MODULE_RENDERABLE_PROTO.constructor;
|
||||
struct { const char_t *name; int val; } types[] = {
|
||||
{ "SHADER_MATERIAL", ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL },
|
||||
{ "SPRITEBATCH", ENTITY_RENDERABLE_TYPE_SPRITEBATCH },
|
||||
{ "CUSTOM", ENTITY_RENDERABLE_TYPE_CUSTOM },
|
||||
};
|
||||
for(int i = 0; i < 3; i++) {
|
||||
jerry_value_t k = jerry_string_sz(types[i].name);
|
||||
jerry_value_t v = jerry_number((double)types[i].val);
|
||||
jerry_object_set(ctor, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
}
|
||||
|
||||
void moduleRenderableDispose(void) {
|
||||
scriptProtoDispose(&MODULE_RENDERABLE_PROTO);
|
||||
}
|
||||
@@ -13,291 +13,69 @@
|
||||
#include "script/scriptproto.h"
|
||||
#include "entity/component/display/entityrenderable.h"
|
||||
|
||||
static scriptproto_t MODULE_RENDERABLE_PROTO;
|
||||
extern scriptproto_t MODULE_RENDERABLE_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleRenderableCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("Renderable cannot be instantiated with new");
|
||||
}
|
||||
/** Renderable() constructor — always throws; not directly instantiable. */
|
||||
moduleBaseFunction(moduleRenderableCtor);
|
||||
|
||||
static inline jscomponent_t *moduleRenderableSelf(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_RENDERABLE_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
/** @return Entity ID that owns this renderable component. */
|
||||
moduleBaseFunction(moduleRenderableGetEntity);
|
||||
|
||||
static inline entityrenderable_t *moduleRenderableData(const jscomponent_t *c) {
|
||||
return (entityrenderable_t *)componentGetData(
|
||||
c->entityId, c->componentId, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
}
|
||||
/** @return This component's ID. */
|
||||
moduleBaseFunction(moduleRenderableGetId);
|
||||
|
||||
/** Read a float from a JS array at index, returning def if out of range. */
|
||||
static inline float_t moduleRenderableArrayFloat(
|
||||
const jerry_value_t arr,
|
||||
const uint32_t idx,
|
||||
const float_t def
|
||||
) {
|
||||
if(idx >= jerry_array_length(arr)) return def;
|
||||
jerry_value_t v = jerry_object_get_index(arr, idx);
|
||||
float_t f = jerry_value_is_number(v) ? (float_t)jerry_value_as_number(v) : def;
|
||||
jerry_value_free(v);
|
||||
return f;
|
||||
}
|
||||
/** @return Render type constant (Renderable.SPRITEBATCH etc.). */
|
||||
moduleBaseFunction(moduleRenderableGetType);
|
||||
|
||||
moduleBaseFunction(moduleRenderableGetEntity) {
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->entityId);
|
||||
}
|
||||
/** Sets render type. @param args[0] entityrenderabletype_t value. */
|
||||
moduleBaseFunction(moduleRenderableSetType);
|
||||
|
||||
moduleBaseFunction(moduleRenderableGetId) {
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->componentId);
|
||||
}
|
||||
/** @return Render priority (signed integer). */
|
||||
moduleBaseFunction(moduleRenderableGetPriority);
|
||||
|
||||
moduleBaseFunction(moduleRenderableGetType) {
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityrenderable_t *r = moduleRenderableData(c);
|
||||
if(!r) return jerry_undefined();
|
||||
return jerry_number((double)r->type);
|
||||
}
|
||||
/** Sets render priority. @param args[0] Priority integer. */
|
||||
moduleBaseFunction(moduleRenderableSetPriority);
|
||||
|
||||
moduleBaseFunction(moduleRenderableSetType) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityRenderableSetType(
|
||||
c->entityId, c->componentId,
|
||||
(entityrenderabletype_t)moduleBaseArgInt(0)
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/** @return Material color as a Color object. */
|
||||
moduleBaseFunction(moduleRenderableGetColor);
|
||||
|
||||
moduleBaseFunction(moduleRenderableGetPriority) {
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityrenderable_t *r = moduleRenderableData(c);
|
||||
if(!r) return jerry_undefined();
|
||||
return jerry_number((double)r->priority);
|
||||
}
|
||||
/** Sets material color. @param args[0] Color object. */
|
||||
moduleBaseFunction(moduleRenderableSetColor);
|
||||
|
||||
moduleBaseFunction(moduleRenderableSetPriority) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityRenderableSetPriority(
|
||||
c->entityId, c->componentId,
|
||||
(int8_t)moduleBaseArgInt(0)
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/** @return The pinned Texture JS instance, or undefined if none set. */
|
||||
moduleBaseFunction(moduleRenderableGetTexture);
|
||||
|
||||
moduleBaseFunction(moduleRenderableGetColor) {
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityrenderable_t *r = moduleRenderableData(c);
|
||||
if(!r) return jerry_undefined();
|
||||
return moduleColorPush(r->data.material.material.unlit.color);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableSetColor) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityrenderable_t *r = moduleRenderableData(c);
|
||||
if(!r) return jerry_undefined();
|
||||
color_t *col = moduleColorFrom(args[0]);
|
||||
if(!col) return moduleBaseThrow("Renderable.color: expected Color");
|
||||
r->data.material.material.unlit.color = *col;
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
/*
|
||||
* texture getter — returns the pinned Texture instance, or undefined if none.
|
||||
/**
|
||||
* Sets the texture for SPRITEBATCH rendering. Also switches the render type to
|
||||
* SPRITEBATCH and pins the JS Texture object to prevent GC.
|
||||
* @param args[0] Texture JS object.
|
||||
*/
|
||||
moduleBaseFunction(moduleRenderableGetTexture) {
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
jerry_value_t key = jerry_string_sz("_tex");
|
||||
jerry_value_t val = jerry_object_get(callInfo->this_value, key);
|
||||
jerry_value_free(key);
|
||||
return val;
|
||||
}
|
||||
moduleBaseFunction(moduleRenderableSetTexture);
|
||||
|
||||
/*
|
||||
* texture setter — switches to SPRITEBATCH, binds the texture, and pins the
|
||||
* Texture JS object so GC won't free the asset while the pointer is live.
|
||||
/**
|
||||
* @return JS array of sprite sub-arrays, each with 10 numbers:
|
||||
* [x1,y1,z1, x2,y2,z2, u1,v1, u2,v2].
|
||||
*/
|
||||
moduleBaseFunction(moduleRenderableSetTexture) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityrenderable_t *r = moduleRenderableData(c);
|
||||
if(!r) return jerry_undefined();
|
||||
jstexture_t *tex = (jstexture_t *)scriptProtoGetValue(
|
||||
&MODULE_TEXTURE_PROTO, args[0]
|
||||
);
|
||||
if(!tex || !tex->entry) {
|
||||
return moduleBaseThrow("Renderable.texture: expected Texture");
|
||||
}
|
||||
r->type = ENTITY_RENDERABLE_TYPE_SPRITEBATCH;
|
||||
r->data.spritebatch.texture = &tex->entry->data.texture;
|
||||
jerry_value_t pinKey = jerry_string_sz("_tex");
|
||||
jerry_object_set(callInfo->this_value, pinKey, args[0]);
|
||||
jerry_value_free(pinKey);
|
||||
return jerry_undefined();
|
||||
}
|
||||
moduleBaseFunction(moduleRenderableGetSprites);
|
||||
|
||||
/*
|
||||
* sprites getter — returns a JS array of sprite sub-arrays.
|
||||
* Each element is [x1,y1,z1, x2,y2,z2, u1,v1, u2,v2] (10 numbers).
|
||||
/**
|
||||
* Sets sprite data. Accepts an array of sub-arrays — 10 elements (3D) or
|
||||
* 8 elements (2D, z defaults to 0).
|
||||
* @param args[0] Array of sprite sub-arrays.
|
||||
*/
|
||||
moduleBaseFunction(moduleRenderableGetSprites) {
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityrenderable_t *r = moduleRenderableData(c);
|
||||
if(!r) return jerry_undefined();
|
||||
const entityrenderablespritebatch_t *sb = &r->data.spritebatch;
|
||||
moduleBaseFunction(moduleRenderableSetSprites);
|
||||
|
||||
jerry_value_t arr = jerry_array((uint32_t)sb->spriteCount);
|
||||
for(uint32_t i = 0; i < (uint32_t)sb->spriteCount; i++) {
|
||||
const spritebatchsprite_t *s = &sb->sprites[i];
|
||||
float_t vals[10] = {
|
||||
s->min[0], s->min[1], s->min[2],
|
||||
s->max[0], s->max[1], s->max[2],
|
||||
s->uvMin[0], s->uvMin[1],
|
||||
s->uvMax[0], s->uvMax[1],
|
||||
};
|
||||
jerry_value_t sprite = jerry_array(10);
|
||||
for(uint32_t j = 0; j < 10; j++) {
|
||||
jerry_value_t num = jerry_number((double)vals[j]);
|
||||
jerry_object_set_index(sprite, j, num);
|
||||
jerry_value_free(num);
|
||||
}
|
||||
jerry_object_set_index(arr, i, sprite);
|
||||
jerry_value_free(sprite);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
/** @return "Renderable(id)" string. */
|
||||
moduleBaseFunction(moduleRenderableToString);
|
||||
|
||||
/*
|
||||
* sprites setter — accepts an array of sub-arrays.
|
||||
* Each element: 10 numbers (3D) or 8 numbers (2D, z defaults to 0).
|
||||
/**
|
||||
* Initializes the Renderable module and registers the global Renderable class
|
||||
* with type/priority/color/texture/sprites properties and SPRITEBATCH/
|
||||
* SHADER_MATERIAL/CUSTOM constants.
|
||||
*/
|
||||
moduleBaseFunction(moduleRenderableSetSprites) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityrenderable_t *r = moduleRenderableData(c);
|
||||
if(!r) return jerry_undefined();
|
||||
if(!jerry_value_is_array(args[0])) {
|
||||
return moduleBaseThrow("Renderable.sprites: expected Array");
|
||||
}
|
||||
entityrenderablespritebatch_t *sb = &r->data.spritebatch;
|
||||
uint32_t count = jerry_array_length(args[0]);
|
||||
if(count > ENTITY_RENDERABLE_SPRITEBATCH_SPRITES_MAX) {
|
||||
return moduleBaseThrow("Renderable.sprites: exceeds sprite capacity");
|
||||
}
|
||||
sb->spriteCount = 0;
|
||||
for(uint32_t i = 0; i < count; i++) {
|
||||
jerry_value_t elem = jerry_object_get_index(args[0], i);
|
||||
if(!jerry_value_is_array(elem)) {
|
||||
jerry_value_free(elem);
|
||||
return moduleBaseThrow("Renderable.sprites: each element must be an Array");
|
||||
}
|
||||
spritebatchsprite_t s;
|
||||
if(jerry_array_length(elem) >= 10) {
|
||||
s.min[0] = moduleRenderableArrayFloat(elem, 0, 0.0f);
|
||||
s.min[1] = moduleRenderableArrayFloat(elem, 1, 0.0f);
|
||||
s.min[2] = moduleRenderableArrayFloat(elem, 2, 0.0f);
|
||||
s.max[0] = moduleRenderableArrayFloat(elem, 3, 0.0f);
|
||||
s.max[1] = moduleRenderableArrayFloat(elem, 4, 0.0f);
|
||||
s.max[2] = moduleRenderableArrayFloat(elem, 5, 0.0f);
|
||||
s.uvMin[0] = moduleRenderableArrayFloat(elem, 6, 0.0f);
|
||||
s.uvMin[1] = moduleRenderableArrayFloat(elem, 7, 0.0f);
|
||||
s.uvMax[0] = moduleRenderableArrayFloat(elem, 8, 1.0f);
|
||||
s.uvMax[1] = moduleRenderableArrayFloat(elem, 9, 1.0f);
|
||||
} else {
|
||||
s.min[0] = moduleRenderableArrayFloat(elem, 0, 0.0f);
|
||||
s.min[1] = moduleRenderableArrayFloat(elem, 1, 0.0f);
|
||||
s.min[2] = 0.0f;
|
||||
s.max[0] = moduleRenderableArrayFloat(elem, 2, 0.0f);
|
||||
s.max[1] = moduleRenderableArrayFloat(elem, 3, 0.0f);
|
||||
s.max[2] = 0.0f;
|
||||
s.uvMin[0] = moduleRenderableArrayFloat(elem, 4, 0.0f);
|
||||
s.uvMin[1] = moduleRenderableArrayFloat(elem, 5, 0.0f);
|
||||
s.uvMax[0] = moduleRenderableArrayFloat(elem, 6, 1.0f);
|
||||
s.uvMax[1] = moduleRenderableArrayFloat(elem, 7, 1.0f);
|
||||
}
|
||||
jerry_value_free(elem);
|
||||
sb->sprites[sb->spriteCount++] = s;
|
||||
}
|
||||
return jerry_undefined();
|
||||
}
|
||||
void moduleRenderableInit(void);
|
||||
|
||||
moduleBaseFunction(moduleRenderableToString) {
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_string_sz("Renderable:invalid");
|
||||
char_t buf[32];
|
||||
snprintf(buf, sizeof(buf), "Renderable(%u)", (unsigned)c->componentId);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
static void moduleRenderableInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_RENDERABLE_PROTO, "Renderable",
|
||||
sizeof(jscomponent_t), moduleRenderableCtor
|
||||
);
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_RENDERABLE_PROTO, "entity", moduleRenderableGetEntity, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_RENDERABLE_PROTO, "id", moduleRenderableGetId, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_RENDERABLE_PROTO, "type",
|
||||
moduleRenderableGetType, moduleRenderableSetType
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_RENDERABLE_PROTO, "priority",
|
||||
moduleRenderableGetPriority, moduleRenderableSetPriority
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_RENDERABLE_PROTO, "color",
|
||||
moduleRenderableGetColor, moduleRenderableSetColor
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_RENDERABLE_PROTO, "texture",
|
||||
moduleRenderableGetTexture, moduleRenderableSetTexture
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_RENDERABLE_PROTO, "sprites",
|
||||
moduleRenderableGetSprites, moduleRenderableSetSprites
|
||||
);
|
||||
scriptProtoDefineToString(&MODULE_RENDERABLE_PROTO, moduleRenderableToString);
|
||||
|
||||
/* Renderable.SHADER_MATERIAL, .SPRITEBATCH, .CUSTOM */
|
||||
jerry_value_t ctor = MODULE_RENDERABLE_PROTO.constructor;
|
||||
struct { const char_t *name; int val; } types[] = {
|
||||
{ "SHADER_MATERIAL", ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL },
|
||||
{ "SPRITEBATCH", ENTITY_RENDERABLE_TYPE_SPRITEBATCH },
|
||||
{ "CUSTOM", ENTITY_RENDERABLE_TYPE_CUSTOM },
|
||||
};
|
||||
for(int i = 0; i < 3; i++) {
|
||||
jerry_value_t k = jerry_string_sz(types[i].name);
|
||||
jerry_value_t v = jerry_number((double)types[i].val);
|
||||
jerry_object_set(ctor, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
}
|
||||
|
||||
static void moduleRenderableDispose(void) {
|
||||
scriptProtoDispose(&MODULE_RENDERABLE_PROTO);
|
||||
}
|
||||
/**
|
||||
* Disposes the Renderable module.
|
||||
*/
|
||||
void moduleRenderableDispose(void);
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "modulecomponentlist.h"
|
||||
|
||||
jerry_value_t moduleComponentListCreateInstance(
|
||||
const componenttype_t type,
|
||||
const jscomponent_t *comp
|
||||
) {
|
||||
switch(type) {
|
||||
case COMPONENT_TYPE_CAMERA:
|
||||
return scriptProtoCreateValue(&MODULE_CAMERA_PROTO, comp);
|
||||
case COMPONENT_TYPE_PHYSICS:
|
||||
return scriptProtoCreateValue(&MODULE_PHYSICS_PROTO, comp);
|
||||
case COMPONENT_TYPE_POSITION:
|
||||
return scriptProtoCreateValue(&MODULE_POSITION_PROTO, comp);
|
||||
case COMPONENT_TYPE_RENDERABLE:
|
||||
return scriptProtoCreateValue(&MODULE_RENDERABLE_PROTO, comp);
|
||||
case COMPONENT_TYPE_TRIGGER:
|
||||
return scriptProtoCreateValue(&MODULE_TRIGGER_PROTO, comp);
|
||||
default:
|
||||
return scriptProtoCreateValue(&MODULE_COMPONENT_PROTO, comp);
|
||||
}
|
||||
}
|
||||
|
||||
void moduleComponentListInit(void) {
|
||||
moduleCameraInit();
|
||||
modulePhysicsInit();
|
||||
modulePositionInit();
|
||||
moduleRenderableInit();
|
||||
moduleTriggerInit();
|
||||
}
|
||||
|
||||
void moduleComponentListDispose(void) {
|
||||
moduleTriggerDispose();
|
||||
moduleRenderableDispose();
|
||||
modulePositionDispose();
|
||||
modulePhysicsDispose();
|
||||
moduleCameraDispose();
|
||||
}
|
||||
@@ -16,39 +16,23 @@
|
||||
/**
|
||||
* Returns a typed JS instance for a newly-added component. Falls back to the
|
||||
* generic Component proto for types that have no specific module yet.
|
||||
*
|
||||
* @param type Component type constant.
|
||||
* @param comp Initialized jscomponent_t with entityId and componentId.
|
||||
* @return A jerry_value_t JS object of the appropriate subtype.
|
||||
*/
|
||||
static jerry_value_t moduleComponentListCreateInstance(
|
||||
jerry_value_t moduleComponentListCreateInstance(
|
||||
const componenttype_t type,
|
||||
const jscomponent_t *comp
|
||||
) {
|
||||
switch(type) {
|
||||
case COMPONENT_TYPE_CAMERA:
|
||||
return scriptProtoCreateValue(&MODULE_CAMERA_PROTO, comp);
|
||||
case COMPONENT_TYPE_PHYSICS:
|
||||
return scriptProtoCreateValue(&MODULE_PHYSICS_PROTO, comp);
|
||||
case COMPONENT_TYPE_POSITION:
|
||||
return scriptProtoCreateValue(&MODULE_POSITION_PROTO, comp);
|
||||
case COMPONENT_TYPE_RENDERABLE:
|
||||
return scriptProtoCreateValue(&MODULE_RENDERABLE_PROTO, comp);
|
||||
case COMPONENT_TYPE_TRIGGER:
|
||||
return scriptProtoCreateValue(&MODULE_TRIGGER_PROTO, comp);
|
||||
default:
|
||||
return scriptProtoCreateValue(&MODULE_COMPONENT_PROTO, comp);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
static void moduleComponentListInit(void) {
|
||||
moduleCameraInit();
|
||||
modulePhysicsInit();
|
||||
modulePositionInit();
|
||||
moduleRenderableInit();
|
||||
moduleTriggerInit();
|
||||
}
|
||||
/**
|
||||
* Initializes all component sub-modules (camera, physics, position, renderable,
|
||||
* trigger).
|
||||
*/
|
||||
void moduleComponentListInit(void);
|
||||
|
||||
static void moduleComponentListDispose(void) {
|
||||
moduleTriggerDispose();
|
||||
moduleRenderableDispose();
|
||||
modulePositionDispose();
|
||||
modulePhysicsDispose();
|
||||
moduleCameraDispose();
|
||||
}
|
||||
/**
|
||||
* Disposes all component sub-modules in reverse init order.
|
||||
*/
|
||||
void moduleComponentListDispose(void);
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
modulephysics.c
|
||||
)
|
||||
@@ -0,0 +1,200 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "modulephysics.h"
|
||||
|
||||
scriptproto_t MODULE_PHYSICS_PROTO;
|
||||
|
||||
jscomponent_t *modulePhysicsSelf(const jerry_call_info_t *callInfo) {
|
||||
return (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_PHYSICS_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsCtor) {
|
||||
return moduleBaseThrow("Physics cannot be instantiated with new");
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsGetEntity) {
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->entityId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsGetId) {
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->componentId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsGetBodyType) {
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number(
|
||||
(double)entityPhysicsGetBodyType(c->entityId, c->componentId)
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsSetBodyType) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityPhysicsSetBodyType(
|
||||
c->entityId, c->componentId,
|
||||
(physicsbodytype_t)moduleBaseArgInt(0)
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsGetShape) {
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number(
|
||||
(double)entityPhysicsGetShape(
|
||||
c->entityId, c->componentId
|
||||
).type
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsSetShape) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
physicsshape_t shape = entityPhysicsGetShape(c->entityId, c->componentId);
|
||||
shape.type = (physicshapetype_t)moduleBaseArgInt(0);
|
||||
entityPhysicsSetShape(c->entityId, c->componentId, shape);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsGetVelocity) {
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
vec3 v;
|
||||
entityPhysicsGetVelocity(c->entityId, c->componentId, v);
|
||||
return moduleVec3Push(v);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsSetVelocity) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("Physics.velocity: expected Vec3");
|
||||
entityPhysicsSetVelocity(c->entityId, c->componentId, v);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsGetGravityScale) {
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityphysics_t *p = entityPhysicsGet(c->entityId, c->componentId);
|
||||
if(!p) return jerry_undefined();
|
||||
return jerry_number((double)p->gravityScale);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsSetGravityScale) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityphysics_t *p = entityPhysicsGet(c->entityId, c->componentId);
|
||||
if(!p) return jerry_undefined();
|
||||
p->gravityScale = moduleBaseArgFloat(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsGetOnGround) {
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_boolean(entityPhysicsIsOnGround(c->entityId, c->componentId));
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsApplyImpulse) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("Physics.applyImpulse: expected Vec3");
|
||||
entityPhysicsApplyImpulse(c->entityId, c->componentId, v);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsToString) {
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_string_sz("Physics:invalid");
|
||||
char_t buf[32];
|
||||
snprintf(buf, sizeof(buf), "Physics(%u)", (unsigned)c->componentId);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
void modulePhysicsInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_PHYSICS_PROTO, "Physics",
|
||||
sizeof(jscomponent_t), modulePhysicsCtor
|
||||
);
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_PHYSICS_PROTO, "entity", modulePhysicsGetEntity, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_PHYSICS_PROTO, "id", modulePhysicsGetId, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_PHYSICS_PROTO, "bodyType",
|
||||
modulePhysicsGetBodyType, modulePhysicsSetBodyType
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_PHYSICS_PROTO, "shape",
|
||||
modulePhysicsGetShape, modulePhysicsSetShape
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_PHYSICS_PROTO, "velocity",
|
||||
modulePhysicsGetVelocity, modulePhysicsSetVelocity
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_PHYSICS_PROTO, "gravityScale",
|
||||
modulePhysicsGetGravityScale, modulePhysicsSetGravityScale
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_PHYSICS_PROTO, "onGround", modulePhysicsGetOnGround, NULL
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_PHYSICS_PROTO, "applyImpulse", modulePhysicsApplyImpulse
|
||||
);
|
||||
scriptProtoDefineToString(&MODULE_PHYSICS_PROTO, modulePhysicsToString);
|
||||
|
||||
jerry_value_t ctor = MODULE_PHYSICS_PROTO.constructor;
|
||||
struct { const char_t *name; int val; } bodyTypes[] = {
|
||||
{ "STATIC", PHYSICS_BODY_STATIC },
|
||||
{ "DYNAMIC", PHYSICS_BODY_DYNAMIC },
|
||||
{ "KINEMATIC", PHYSICS_BODY_KINEMATIC },
|
||||
};
|
||||
for(int i = 0; i < 3; i++) {
|
||||
jerry_value_t k = jerry_string_sz(bodyTypes[i].name);
|
||||
jerry_value_t v = jerry_number((double)bodyTypes[i].val);
|
||||
jerry_object_set(ctor, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
|
||||
struct { const char_t *name; int val; } shapes[] = {
|
||||
{ "SHAPE_CUBE", PHYSICS_SHAPE_CUBE },
|
||||
{ "SHAPE_SPHERE", PHYSICS_SHAPE_SPHERE },
|
||||
{ "SHAPE_CAPSULE", PHYSICS_SHAPE_CAPSULE },
|
||||
{ "SHAPE_PLANE", PHYSICS_SHAPE_PLANE },
|
||||
};
|
||||
for(int i = 0; i < 4; i++) {
|
||||
jerry_value_t k = jerry_string_sz(shapes[i].name);
|
||||
jerry_value_t v = jerry_number((double)shapes[i].val);
|
||||
jerry_object_set(ctor, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
}
|
||||
|
||||
void modulePhysicsDispose(void) {
|
||||
scriptProtoDispose(&MODULE_PHYSICS_PROTO);
|
||||
}
|
||||
@@ -12,193 +12,61 @@
|
||||
#include "script/module/entity/modulecomponent.h"
|
||||
#include "entity/component/physics/entityphysics.h"
|
||||
|
||||
static scriptproto_t MODULE_PHYSICS_PROTO;
|
||||
extern scriptproto_t MODULE_PHYSICS_PROTO;
|
||||
|
||||
moduleBaseFunction(modulePhysicsCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("Physics cannot be instantiated with new");
|
||||
}
|
||||
/** Physics() constructor — always throws; not directly instantiable. */
|
||||
moduleBaseFunction(modulePhysicsCtor);
|
||||
|
||||
static inline jscomponent_t *modulePhysicsSelf(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_PHYSICS_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
/** @return Entity ID that owns this physics component. */
|
||||
moduleBaseFunction(modulePhysicsGetEntity);
|
||||
|
||||
moduleBaseFunction(modulePhysicsGetEntity) {
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->entityId);
|
||||
}
|
||||
/** @return This component's ID. */
|
||||
moduleBaseFunction(modulePhysicsGetId);
|
||||
|
||||
moduleBaseFunction(modulePhysicsGetId) {
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->componentId);
|
||||
}
|
||||
/** @return Body type constant (Physics.STATIC, .DYNAMIC, .KINEMATIC). */
|
||||
moduleBaseFunction(modulePhysicsGetBodyType);
|
||||
|
||||
moduleBaseFunction(modulePhysicsGetBodyType) {
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)entityPhysicsGetBodyType(c->entityId, c->componentId));
|
||||
}
|
||||
/** Sets body type. @param args[0] physicsbodytype_t value. */
|
||||
moduleBaseFunction(modulePhysicsSetBodyType);
|
||||
|
||||
moduleBaseFunction(modulePhysicsSetBodyType) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityPhysicsSetBodyType(
|
||||
c->entityId, c->componentId,
|
||||
(physicsbodytype_t)moduleBaseArgInt(0)
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/** @return Collision shape type constant (Physics.SHAPE_*). */
|
||||
moduleBaseFunction(modulePhysicsGetShape);
|
||||
|
||||
moduleBaseFunction(modulePhysicsGetShape) {
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)entityPhysicsGetShape(c->entityId, c->componentId).type);
|
||||
}
|
||||
/** Sets collision shape type. @param args[0] physicshapetype_t value. */
|
||||
moduleBaseFunction(modulePhysicsSetShape);
|
||||
|
||||
moduleBaseFunction(modulePhysicsSetShape) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
physicsshape_t shape = entityPhysicsGetShape(c->entityId, c->componentId);
|
||||
shape.type = (physicshapetype_t)moduleBaseArgInt(0);
|
||||
entityPhysicsSetShape(c->entityId, c->componentId, shape);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/** @return Linear velocity as a Vec3. */
|
||||
moduleBaseFunction(modulePhysicsGetVelocity);
|
||||
|
||||
moduleBaseFunction(modulePhysicsGetVelocity) {
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
vec3 v;
|
||||
entityPhysicsGetVelocity(c->entityId, c->componentId, v);
|
||||
return moduleVec3Push(v);
|
||||
}
|
||||
/** Sets linear velocity. @param args[0] Vec3. */
|
||||
moduleBaseFunction(modulePhysicsSetVelocity);
|
||||
|
||||
moduleBaseFunction(modulePhysicsSetVelocity) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("Physics.velocity: expected Vec3");
|
||||
entityPhysicsSetVelocity(c->entityId, c->componentId, v);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/** @return Gravity scale multiplier (float). */
|
||||
moduleBaseFunction(modulePhysicsGetGravityScale);
|
||||
|
||||
moduleBaseFunction(modulePhysicsGetGravityScale) {
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityphysics_t *p = entityPhysicsGet(c->entityId, c->componentId);
|
||||
if(!p) return jerry_undefined();
|
||||
return jerry_number((double)p->gravityScale);
|
||||
}
|
||||
/** Sets gravity scale. @param args[0] Float multiplier. */
|
||||
moduleBaseFunction(modulePhysicsSetGravityScale);
|
||||
|
||||
moduleBaseFunction(modulePhysicsSetGravityScale) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityphysics_t *p = entityPhysicsGet(c->entityId, c->componentId);
|
||||
if(!p) return jerry_undefined();
|
||||
p->gravityScale = moduleBaseArgFloat(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/** @return True when the body is resting on a surface. */
|
||||
moduleBaseFunction(modulePhysicsGetOnGround);
|
||||
|
||||
moduleBaseFunction(modulePhysicsGetOnGround) {
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_boolean(entityPhysicsIsOnGround(c->entityId, c->componentId));
|
||||
}
|
||||
/**
|
||||
* applyImpulse(impulse) — applies an instantaneous force to the body.
|
||||
* @param args[0] Vec3 impulse vector.
|
||||
*/
|
||||
moduleBaseFunction(modulePhysicsApplyImpulse);
|
||||
|
||||
moduleBaseFunction(modulePhysicsApplyImpulse) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("Physics.applyImpulse: expected Vec3");
|
||||
entityPhysicsApplyImpulse(c->entityId, c->componentId, v);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/** @return "Physics(id)" string. */
|
||||
moduleBaseFunction(modulePhysicsToString);
|
||||
|
||||
moduleBaseFunction(modulePhysicsToString) {
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_string_sz("Physics:invalid");
|
||||
char_t buf[32];
|
||||
snprintf(buf, sizeof(buf), "Physics(%u)", (unsigned)c->componentId);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
/**
|
||||
* Initializes the Physics module and registers the global Physics class with
|
||||
* bodyType/shape/velocity/gravityScale/onGround properties, applyImpulse
|
||||
* method, and STATIC/DYNAMIC/KINEMATIC and SHAPE_* constants.
|
||||
*/
|
||||
void modulePhysicsInit(void);
|
||||
|
||||
static void modulePhysicsInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_PHYSICS_PROTO, "Physics",
|
||||
sizeof(jscomponent_t), modulePhysicsCtor
|
||||
);
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_PHYSICS_PROTO, "entity", modulePhysicsGetEntity, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_PHYSICS_PROTO, "id", modulePhysicsGetId, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_PHYSICS_PROTO, "bodyType",
|
||||
modulePhysicsGetBodyType, modulePhysicsSetBodyType
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_PHYSICS_PROTO, "shape",
|
||||
modulePhysicsGetShape, modulePhysicsSetShape
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_PHYSICS_PROTO, "velocity",
|
||||
modulePhysicsGetVelocity, modulePhysicsSetVelocity
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_PHYSICS_PROTO, "gravityScale",
|
||||
modulePhysicsGetGravityScale, modulePhysicsSetGravityScale
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_PHYSICS_PROTO, "onGround", modulePhysicsGetOnGround, NULL
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_PHYSICS_PROTO, "applyImpulse", modulePhysicsApplyImpulse
|
||||
);
|
||||
scriptProtoDefineToString(&MODULE_PHYSICS_PROTO, modulePhysicsToString);
|
||||
|
||||
/* Body type constants */
|
||||
jerry_value_t ctor = MODULE_PHYSICS_PROTO.constructor;
|
||||
struct { const char_t *name; int val; } bodyTypes[] = {
|
||||
{ "STATIC", PHYSICS_BODY_STATIC },
|
||||
{ "DYNAMIC", PHYSICS_BODY_DYNAMIC },
|
||||
{ "KINEMATIC", PHYSICS_BODY_KINEMATIC },
|
||||
};
|
||||
for(int i = 0; i < 3; i++) {
|
||||
jerry_value_t k = jerry_string_sz(bodyTypes[i].name);
|
||||
jerry_value_t v = jerry_number((double)bodyTypes[i].val);
|
||||
jerry_object_set(ctor, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
|
||||
/* Shape type constants */
|
||||
struct { const char_t *name; int val; } shapes[] = {
|
||||
{ "SHAPE_CUBE", PHYSICS_SHAPE_CUBE },
|
||||
{ "SHAPE_SPHERE", PHYSICS_SHAPE_SPHERE },
|
||||
{ "SHAPE_CAPSULE", PHYSICS_SHAPE_CAPSULE },
|
||||
{ "SHAPE_PLANE", PHYSICS_SHAPE_PLANE },
|
||||
};
|
||||
for(int i = 0; i < 4; i++) {
|
||||
jerry_value_t k = jerry_string_sz(shapes[i].name);
|
||||
jerry_value_t v = jerry_number((double)shapes[i].val);
|
||||
jerry_object_set(ctor, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
}
|
||||
|
||||
static void modulePhysicsDispose(void) {
|
||||
scriptProtoDispose(&MODULE_PHYSICS_PROTO);
|
||||
}
|
||||
/**
|
||||
* Disposes the Physics module.
|
||||
*/
|
||||
void modulePhysicsDispose(void);
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
moduletrigger.c
|
||||
)
|
||||
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "moduletrigger.h"
|
||||
|
||||
scriptproto_t MODULE_TRIGGER_PROTO;
|
||||
|
||||
jscomponent_t *moduleTriggerSelf(const jerry_call_info_t *callInfo) {
|
||||
return (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_TRIGGER_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTriggerCtor) {
|
||||
return moduleBaseThrow("Trigger cannot be instantiated with new");
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTriggerGetEntity) {
|
||||
jscomponent_t *c = moduleTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->entityId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTriggerGetId) {
|
||||
jscomponent_t *c = moduleTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->componentId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTriggerGetMin) {
|
||||
jscomponent_t *c = moduleTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitytrigger_t *t = entityTriggerGet(c->entityId, c->componentId);
|
||||
if(!t) return jerry_undefined();
|
||||
return moduleVec3Push(t->min);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTriggerSetMin) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("Trigger.min: expected Vec3");
|
||||
entitytrigger_t *t = entityTriggerGet(c->entityId, c->componentId);
|
||||
if(!t) return jerry_undefined();
|
||||
glm_vec3_copy(v, t->min);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTriggerGetMax) {
|
||||
jscomponent_t *c = moduleTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitytrigger_t *t = entityTriggerGet(c->entityId, c->componentId);
|
||||
if(!t) return jerry_undefined();
|
||||
return moduleVec3Push(t->max);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTriggerSetMax) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("Trigger.max: expected Vec3");
|
||||
entitytrigger_t *t = entityTriggerGet(c->entityId, c->componentId);
|
||||
if(!t) return jerry_undefined();
|
||||
glm_vec3_copy(v, t->max);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTriggerSetBounds) {
|
||||
moduleBaseRequireArgs(2);
|
||||
jscomponent_t *c = moduleTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *minV = moduleVec3From(args[0]);
|
||||
float_t *maxV = moduleVec3From(args[1]);
|
||||
if(!minV) return moduleBaseThrow("Trigger.setBounds: expected Vec3 for min");
|
||||
if(!maxV) return moduleBaseThrow("Trigger.setBounds: expected Vec3 for max");
|
||||
entityTriggerSetBounds(c->entityId, c->componentId, minV, maxV);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTriggerContains) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("Trigger.contains: expected Vec3");
|
||||
return jerry_boolean(entityTriggerContains(c->entityId, c->componentId, v));
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTriggerToString) {
|
||||
jscomponent_t *c = moduleTriggerSelf(callInfo);
|
||||
if(!c) return jerry_string_sz("Trigger:invalid");
|
||||
char_t buf[32];
|
||||
snprintf(buf, sizeof(buf), "Trigger(%u)", (unsigned)c->componentId);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
void moduleTriggerInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_TRIGGER_PROTO, "Trigger",
|
||||
sizeof(jscomponent_t), moduleTriggerCtor
|
||||
);
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_TRIGGER_PROTO, "entity", moduleTriggerGetEntity, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_TRIGGER_PROTO, "id", moduleTriggerGetId, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_TRIGGER_PROTO, "min", moduleTriggerGetMin, moduleTriggerSetMin
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_TRIGGER_PROTO, "max", moduleTriggerGetMax, moduleTriggerSetMax
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_TRIGGER_PROTO, "setBounds", moduleTriggerSetBounds
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_TRIGGER_PROTO, "contains", moduleTriggerContains
|
||||
);
|
||||
scriptProtoDefineToString(&MODULE_TRIGGER_PROTO, moduleTriggerToString);
|
||||
}
|
||||
|
||||
void moduleTriggerDispose(void) {
|
||||
scriptProtoDispose(&MODULE_TRIGGER_PROTO);
|
||||
}
|
||||
@@ -12,129 +12,53 @@
|
||||
#include "script/module/entity/modulecomponent.h"
|
||||
#include "entity/component/trigger/entitytrigger.h"
|
||||
|
||||
static scriptproto_t MODULE_TRIGGER_PROTO;
|
||||
extern scriptproto_t MODULE_TRIGGER_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleTriggerCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("Trigger cannot be instantiated with new");
|
||||
}
|
||||
/** Trigger() constructor — always throws; not directly instantiable. */
|
||||
moduleBaseFunction(moduleTriggerCtor);
|
||||
|
||||
static inline jscomponent_t *moduleTriggerSelf(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_TRIGGER_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
/** @return Entity ID that owns this trigger component. */
|
||||
moduleBaseFunction(moduleTriggerGetEntity);
|
||||
|
||||
moduleBaseFunction(moduleTriggerGetEntity) {
|
||||
jscomponent_t *c = moduleTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->entityId);
|
||||
}
|
||||
/** @return This component's ID. */
|
||||
moduleBaseFunction(moduleTriggerGetId);
|
||||
|
||||
moduleBaseFunction(moduleTriggerGetId) {
|
||||
jscomponent_t *c = moduleTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->componentId);
|
||||
}
|
||||
/** @return AABB minimum corner as a Vec3. */
|
||||
moduleBaseFunction(moduleTriggerGetMin);
|
||||
|
||||
moduleBaseFunction(moduleTriggerGetMin) {
|
||||
jscomponent_t *c = moduleTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitytrigger_t *t = entityTriggerGet(c->entityId, c->componentId);
|
||||
if(!t) return jerry_undefined();
|
||||
return moduleVec3Push(t->min);
|
||||
}
|
||||
/** Sets AABB minimum corner. @param args[0] Vec3. */
|
||||
moduleBaseFunction(moduleTriggerSetMin);
|
||||
|
||||
moduleBaseFunction(moduleTriggerSetMin) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("Trigger.min: expected Vec3");
|
||||
entitytrigger_t *t = entityTriggerGet(c->entityId, c->componentId);
|
||||
if(!t) return jerry_undefined();
|
||||
glm_vec3_copy(v, t->min);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/** @return AABB maximum corner as a Vec3. */
|
||||
moduleBaseFunction(moduleTriggerGetMax);
|
||||
|
||||
moduleBaseFunction(moduleTriggerGetMax) {
|
||||
jscomponent_t *c = moduleTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitytrigger_t *t = entityTriggerGet(c->entityId, c->componentId);
|
||||
if(!t) return jerry_undefined();
|
||||
return moduleVec3Push(t->max);
|
||||
}
|
||||
/** Sets AABB maximum corner. @param args[0] Vec3. */
|
||||
moduleBaseFunction(moduleTriggerSetMax);
|
||||
|
||||
moduleBaseFunction(moduleTriggerSetMax) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("Trigger.max: expected Vec3");
|
||||
entitytrigger_t *t = entityTriggerGet(c->entityId, c->componentId);
|
||||
if(!t) return jerry_undefined();
|
||||
glm_vec3_copy(v, t->max);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/**
|
||||
* setBounds(min, max) — sets both AABB corners at once.
|
||||
* @param args[0] Vec3 minimum corner.
|
||||
* @param args[1] Vec3 maximum corner.
|
||||
*/
|
||||
moduleBaseFunction(moduleTriggerSetBounds);
|
||||
|
||||
moduleBaseFunction(moduleTriggerSetBounds) {
|
||||
moduleBaseRequireArgs(2);
|
||||
jscomponent_t *c = moduleTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *minV = moduleVec3From(args[0]);
|
||||
float_t *maxV = moduleVec3From(args[1]);
|
||||
if(!minV) return moduleBaseThrow("Trigger.setBounds: expected Vec3 for min");
|
||||
if(!maxV) return moduleBaseThrow("Trigger.setBounds: expected Vec3 for max");
|
||||
entityTriggerSetBounds(c->entityId, c->componentId, minV, maxV);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/**
|
||||
* contains(point) — tests whether a world-space point is inside the AABB.
|
||||
* @param args[0] Vec3 point.
|
||||
* @return true if the point is inside the trigger volume.
|
||||
*/
|
||||
moduleBaseFunction(moduleTriggerContains);
|
||||
|
||||
moduleBaseFunction(moduleTriggerContains) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("Trigger.contains: expected Vec3");
|
||||
return jerry_boolean(entityTriggerContains(c->entityId, c->componentId, v));
|
||||
}
|
||||
/** @return "Trigger(id)" string. */
|
||||
moduleBaseFunction(moduleTriggerToString);
|
||||
|
||||
moduleBaseFunction(moduleTriggerToString) {
|
||||
jscomponent_t *c = moduleTriggerSelf(callInfo);
|
||||
if(!c) return jerry_string_sz("Trigger:invalid");
|
||||
char_t buf[32];
|
||||
snprintf(buf, sizeof(buf), "Trigger(%u)", (unsigned)c->componentId);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
/**
|
||||
* Initializes the Trigger module and registers the global Trigger class with
|
||||
* min/max properties and setBounds/contains methods.
|
||||
*/
|
||||
void moduleTriggerInit(void);
|
||||
|
||||
static void moduleTriggerInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_TRIGGER_PROTO, "Trigger",
|
||||
sizeof(jscomponent_t), moduleTriggerCtor
|
||||
);
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_TRIGGER_PROTO, "entity", moduleTriggerGetEntity, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_TRIGGER_PROTO, "id", moduleTriggerGetId, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_TRIGGER_PROTO, "min", moduleTriggerGetMin, moduleTriggerSetMin
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_TRIGGER_PROTO, "max", moduleTriggerGetMax, moduleTriggerSetMax
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_TRIGGER_PROTO, "setBounds", moduleTriggerSetBounds
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_TRIGGER_PROTO, "contains", moduleTriggerContains
|
||||
);
|
||||
scriptProtoDefineToString(&MODULE_TRIGGER_PROTO, moduleTriggerToString);
|
||||
}
|
||||
|
||||
static void moduleTriggerDispose(void) {
|
||||
scriptProtoDispose(&MODULE_TRIGGER_PROTO);
|
||||
}
|
||||
/**
|
||||
* Disposes the Trigger module.
|
||||
*/
|
||||
void moduleTriggerDispose(void);
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "modulecomponent.h"
|
||||
|
||||
scriptproto_t MODULE_COMPONENT_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleComponentCtor) {
|
||||
return moduleBaseThrow("Component cannot be instantiated with new");
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleComponentGetEntity) {
|
||||
jscomponent_t *c = (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_COMPONENT_PROTO, callInfo->this_value
|
||||
);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->entityId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleComponentGetId) {
|
||||
jscomponent_t *c = (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_COMPONENT_PROTO, callInfo->this_value
|
||||
);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->componentId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleComponentToString) {
|
||||
jscomponent_t *c = (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_COMPONENT_PROTO, callInfo->this_value
|
||||
);
|
||||
if(!c) return jerry_string_sz("Component:invalid");
|
||||
char_t buf[32];
|
||||
snprintf(buf, sizeof(buf), "Component(%u)", (unsigned)c->componentId);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
void moduleComponentInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_COMPONENT_PROTO, "Component",
|
||||
sizeof(jscomponent_t), moduleComponentCtor
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_COMPONENT_PROTO, "entity", moduleComponentGetEntity, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_COMPONENT_PROTO, "id", moduleComponentGetId, NULL
|
||||
);
|
||||
scriptProtoDefineToString(&MODULE_COMPONENT_PROTO, moduleComponentToString);
|
||||
|
||||
jerry_value_t ctor = MODULE_COMPONENT_PROTO.constructor;
|
||||
#define X(enumName, type, field, init, dispose, render) { \
|
||||
jerry_value_t _k = jerry_string_sz(#enumName); \
|
||||
jerry_value_t _v = jerry_number((double)COMPONENT_TYPE_##enumName); \
|
||||
jerry_object_set(ctor, _k, _v); \
|
||||
jerry_value_free(_v); \
|
||||
jerry_value_free(_k); \
|
||||
}
|
||||
#include "entity/componentlist.h"
|
||||
#undef X
|
||||
}
|
||||
|
||||
void moduleComponentDispose(void) {
|
||||
scriptProtoDispose(&MODULE_COMPONENT_PROTO);
|
||||
}
|
||||
@@ -10,84 +10,33 @@
|
||||
#include "script/scriptproto.h"
|
||||
#include "entity/component.h"
|
||||
|
||||
extern scriptproto_t MODULE_COMPONENT_PROTO;
|
||||
|
||||
/** C struct wrapped by every Component JS instance. */
|
||||
typedef struct {
|
||||
entityid_t entityId;
|
||||
componentid_t componentId;
|
||||
} jscomponent_t;
|
||||
|
||||
static scriptproto_t MODULE_COMPONENT_PROTO;
|
||||
/** Component() constructor — always throws; not directly instantiable. */
|
||||
moduleBaseFunction(moduleComponentCtor);
|
||||
|
||||
moduleBaseFunction(moduleComponentCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("Component cannot be instantiated with new");
|
||||
}
|
||||
/** @return The entity ID that owns this component. */
|
||||
moduleBaseFunction(moduleComponentGetEntity);
|
||||
|
||||
moduleBaseFunction(moduleComponentGetEntity) {
|
||||
jscomponent_t *comp = scriptProtoGetValue(
|
||||
&MODULE_COMPONENT_PROTO, callInfo->this_value
|
||||
);
|
||||
if(!comp) return jerry_undefined();
|
||||
return jerry_number((double)comp->entityId);
|
||||
}
|
||||
/** @return This component's ID. */
|
||||
moduleBaseFunction(moduleComponentGetId);
|
||||
|
||||
moduleBaseFunction(moduleComponentGetId) {
|
||||
jscomponent_t *comp = scriptProtoGetValue(
|
||||
&MODULE_COMPONENT_PROTO, callInfo->this_value
|
||||
);
|
||||
if(!comp) return jerry_undefined();
|
||||
return jerry_number((double)comp->componentId);
|
||||
}
|
||||
/** @return Component ID as a string. */
|
||||
moduleBaseFunction(moduleComponentToString);
|
||||
|
||||
moduleBaseFunction(moduleComponentToString) {
|
||||
jscomponent_t *comp = scriptProtoGetValue(
|
||||
&MODULE_COMPONENT_PROTO, callInfo->this_value
|
||||
);
|
||||
if(!comp) return jerry_string_sz("Component:invalid");
|
||||
jerry_value_t num = jerry_number((double)comp->componentId);
|
||||
jerry_value_t str = jerry_value_to_string(num);
|
||||
jerry_value_free(num);
|
||||
return str;
|
||||
}
|
||||
/**
|
||||
* Initializes the Component module, registers the global Component class with
|
||||
* entity/id properties and TYPE_* / INVALID constants.
|
||||
*/
|
||||
void moduleComponentInit(void);
|
||||
|
||||
static void moduleComponentInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_COMPONENT_PROTO, "Component",
|
||||
sizeof(jscomponent_t), moduleComponentCtor
|
||||
);
|
||||
|
||||
/* Instance properties */
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_COMPONENT_PROTO, "entity",
|
||||
moduleComponentGetEntity, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_COMPONENT_PROTO, "id",
|
||||
moduleComponentGetId, NULL
|
||||
);
|
||||
scriptProtoDefineToString(&MODULE_COMPONENT_PROTO, moduleComponentToString);
|
||||
|
||||
/* Component.POSITION, Component.CAMERA, etc. from componentlist.h */
|
||||
jerry_value_t ctor = MODULE_COMPONENT_PROTO.constructor;
|
||||
#define X(enumName, type, field, init, dispose, render) \
|
||||
do { \
|
||||
jerry_value_t _key = jerry_string_sz(#enumName); \
|
||||
jerry_value_t _val = jerry_number((double)COMPONENT_TYPE_##enumName); \
|
||||
jerry_object_set(ctor, _key, _val); \
|
||||
jerry_value_free(_val); \
|
||||
jerry_value_free(_key); \
|
||||
} while(0);
|
||||
#include "entity/componentlist.h"
|
||||
#undef X
|
||||
|
||||
/* Component.INVALID */
|
||||
jerry_value_t _key = jerry_string_sz("INVALID");
|
||||
jerry_value_t _val = jerry_number((double)COMPONENT_ID_INVALID);
|
||||
jerry_object_set(ctor, _key, _val);
|
||||
jerry_value_free(_val);
|
||||
jerry_value_free(_key);
|
||||
}
|
||||
|
||||
static void moduleComponentDispose(void) {
|
||||
scriptProtoDispose(&MODULE_COMPONENT_PROTO);
|
||||
}
|
||||
/**
|
||||
* Disposes the Component module.
|
||||
*/
|
||||
void moduleComponentDispose(void);
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "moduleentity.h"
|
||||
|
||||
scriptproto_t MODULE_ENTITY_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleEntityCtor) {
|
||||
return moduleBaseThrow("Entity cannot be instantiated with new");
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleEntityCreate) {
|
||||
entityid_t id = entityManagerAdd();
|
||||
if(id == ENTITY_ID_INVALID) {
|
||||
return moduleBaseThrow("Entity.create: no entity slots available");
|
||||
}
|
||||
jsentity_t ent = { .id = id };
|
||||
return scriptProtoCreateValue(&MODULE_ENTITY_PROTO, &ent);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleEntityDisposeEntity) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jsentity_t *ent = scriptProtoGetValue(&MODULE_ENTITY_PROTO, args[0]);
|
||||
if(!ent) return moduleBaseThrow("Entity.dispose: expected Entity object");
|
||||
entityDispose(ent->id);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleEntityAdd) {
|
||||
jsentity_t *ent = scriptProtoGetValue(
|
||||
&MODULE_ENTITY_PROTO, callInfo->this_value
|
||||
);
|
||||
if(!ent) return moduleBaseThrow("Entity.add: invalid this");
|
||||
moduleBaseRequireArgs(1);
|
||||
moduleBaseRequireNumber(0);
|
||||
|
||||
const componenttype_t type = (componenttype_t)moduleBaseArgInt(0);
|
||||
if(type <= COMPONENT_TYPE_NULL || type >= COMPONENT_TYPE_COUNT) {
|
||||
return moduleBaseThrow("Entity.add: invalid component type");
|
||||
}
|
||||
|
||||
componentid_t cid = entityAddComponent(ent->id, type);
|
||||
if(cid == COMPONENT_ID_INVALID) {
|
||||
return moduleBaseThrow("Entity.add: failed to add component");
|
||||
}
|
||||
|
||||
jscomponent_t comp = { .entityId = ent->id, .componentId = cid };
|
||||
return moduleComponentListCreateInstance(type, &comp);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleEntityToString) {
|
||||
jsentity_t *ent = scriptProtoGetValue(
|
||||
&MODULE_ENTITY_PROTO, callInfo->this_value
|
||||
);
|
||||
if(!ent) return jerry_string_sz("Entity:invalid");
|
||||
jerry_value_t num = jerry_number((double)ent->id);
|
||||
jerry_value_t str = jerry_value_to_string(num);
|
||||
jerry_value_free(num);
|
||||
return str;
|
||||
}
|
||||
|
||||
void moduleEntityInit(void) {
|
||||
moduleComponentInit();
|
||||
moduleComponentListInit();
|
||||
|
||||
scriptProtoInit(
|
||||
&MODULE_ENTITY_PROTO, "Entity",
|
||||
sizeof(jsentity_t), moduleEntityCtor
|
||||
);
|
||||
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_ENTITY_PROTO, "create", moduleEntityCreate
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_ENTITY_PROTO, "dispose", moduleEntityDisposeEntity
|
||||
);
|
||||
|
||||
jerry_value_t ctor = MODULE_ENTITY_PROTO.constructor;
|
||||
jerry_value_t _key = jerry_string_sz("INVALID");
|
||||
jerry_value_t _val = jerry_number((double)ENTITY_ID_INVALID);
|
||||
jerry_object_set(ctor, _key, _val);
|
||||
jerry_value_free(_val);
|
||||
jerry_value_free(_key);
|
||||
|
||||
scriptProtoDefineFunc(&MODULE_ENTITY_PROTO, "add", moduleEntityAdd);
|
||||
scriptProtoDefineToString(&MODULE_ENTITY_PROTO, moduleEntityToString);
|
||||
}
|
||||
|
||||
void moduleEntityDispose(void) {
|
||||
scriptProtoDispose(&MODULE_ENTITY_PROTO);
|
||||
moduleComponentListDispose();
|
||||
moduleComponentDispose();
|
||||
}
|
||||
@@ -12,95 +12,50 @@
|
||||
#include "script/module/entity/component/modulecomponentlist.h"
|
||||
#include "entity/entitymanager.h"
|
||||
|
||||
extern scriptproto_t MODULE_ENTITY_PROTO;
|
||||
|
||||
/** C struct wrapped by every Entity JS instance. */
|
||||
typedef struct {
|
||||
entityid_t id;
|
||||
} jsentity_t;
|
||||
|
||||
static scriptproto_t MODULE_ENTITY_PROTO;
|
||||
/** Entity() constructor — always throws; use Entity.create() instead. */
|
||||
moduleBaseFunction(moduleEntityCtor);
|
||||
|
||||
moduleBaseFunction(moduleEntityCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("Entity cannot be instantiated with new");
|
||||
}
|
||||
/**
|
||||
* Entity.create() — allocates a new entity slot and returns an
|
||||
* Entity JS object.
|
||||
* @return Entity JS object.
|
||||
* @throws If no entity slots are available.
|
||||
*/
|
||||
moduleBaseFunction(moduleEntityCreate);
|
||||
|
||||
moduleBaseFunction(moduleEntityCreate) {
|
||||
entityid_t id = entityManagerAdd();
|
||||
if(id == ENTITY_ID_INVALID) {
|
||||
return moduleBaseThrow("Entity.create: no entity slots available");
|
||||
}
|
||||
jsentity_t ent = { .id = id };
|
||||
return scriptProtoCreateValue(&MODULE_ENTITY_PROTO, &ent);
|
||||
}
|
||||
/**
|
||||
* Entity.dispose(entity) — disposes an entity and all its components.
|
||||
* @param args[0] Entity JS object.
|
||||
*/
|
||||
moduleBaseFunction(moduleEntityDisposeEntity);
|
||||
|
||||
moduleBaseFunction(moduleEntityDisposeEntity) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jsentity_t *ent = scriptProtoGetValue(&MODULE_ENTITY_PROTO, args[0]);
|
||||
if(!ent) return moduleBaseThrow("Entity.dispose: expected Entity object");
|
||||
entityDispose(ent->id);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/**
|
||||
* entity.add(type) — adds a component of the given type to this entity.
|
||||
* @param args[0] Component type constant (e.g. COMPONENT_TYPE_POSITION).
|
||||
* @return Typed component JS object (Position, Camera, etc.).
|
||||
* @throws If the type is invalid or no component slots are available.
|
||||
*/
|
||||
moduleBaseFunction(moduleEntityAdd);
|
||||
|
||||
moduleBaseFunction(moduleEntityAdd) {
|
||||
jsentity_t *ent = scriptProtoGetValue(
|
||||
&MODULE_ENTITY_PROTO, callInfo->this_value
|
||||
);
|
||||
if(!ent) return moduleBaseThrow("Entity.add: invalid this");
|
||||
moduleBaseRequireArgs(1);
|
||||
moduleBaseRequireNumber(0);
|
||||
/** @return Entity ID as a string. */
|
||||
moduleBaseFunction(moduleEntityToString);
|
||||
|
||||
const componenttype_t type = (componenttype_t)moduleBaseArgInt(0);
|
||||
if(type <= COMPONENT_TYPE_NULL || type >= COMPONENT_TYPE_COUNT) {
|
||||
return moduleBaseThrow("Entity.add: invalid component type");
|
||||
}
|
||||
/**
|
||||
* Initializes the Entity module and registers the global Entity class with
|
||||
* create/dispose static methods, add instance method, and INVALID constant.
|
||||
* Also calls moduleComponentInit() and moduleComponentListInit().
|
||||
*/
|
||||
void moduleEntityInit(void);
|
||||
|
||||
componentid_t cid = entityAddComponent(ent->id, type);
|
||||
if(cid == COMPONENT_ID_INVALID) {
|
||||
return moduleBaseThrow("Entity.add: failed to add component");
|
||||
}
|
||||
|
||||
jscomponent_t comp = { .entityId = ent->id, .componentId = cid };
|
||||
return moduleComponentListCreateInstance(type, &comp);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleEntityToString) {
|
||||
jsentity_t *ent = scriptProtoGetValue(
|
||||
&MODULE_ENTITY_PROTO, callInfo->this_value
|
||||
);
|
||||
if(!ent) return jerry_string_sz("Entity:invalid");
|
||||
jerry_value_t num = jerry_number((double)ent->id);
|
||||
jerry_value_t str = jerry_value_to_string(num);
|
||||
jerry_value_free(num);
|
||||
return str;
|
||||
}
|
||||
|
||||
static void moduleEntityInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_ENTITY_PROTO, "Entity",
|
||||
sizeof(jsentity_t), moduleEntityCtor
|
||||
);
|
||||
|
||||
/* Static methods */
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_ENTITY_PROTO, "create", moduleEntityCreate
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_ENTITY_PROTO, "dispose", moduleEntityDisposeEntity
|
||||
);
|
||||
|
||||
/* Entity.INVALID */
|
||||
jerry_value_t ctor = MODULE_ENTITY_PROTO.constructor;
|
||||
jerry_value_t _key = jerry_string_sz("INVALID");
|
||||
jerry_value_t _val = jerry_number((double)ENTITY_ID_INVALID);
|
||||
jerry_object_set(ctor, _key, _val);
|
||||
jerry_value_free(_val);
|
||||
jerry_value_free(_key);
|
||||
|
||||
/* Instance methods */
|
||||
scriptProtoDefineFunc(&MODULE_ENTITY_PROTO, "add", moduleEntityAdd);
|
||||
scriptProtoDefineToString(&MODULE_ENTITY_PROTO, moduleEntityToString);
|
||||
}
|
||||
|
||||
static void moduleEntityDispose(void) {
|
||||
scriptProtoDispose(&MODULE_ENTITY_PROTO);
|
||||
}
|
||||
/**
|
||||
* Disposes the Entity module and calls moduleComponentListDispose() and
|
||||
* moduleComponentDispose().
|
||||
*/
|
||||
void moduleEntityDispose(void);
|
||||
|
||||
@@ -21,80 +21,201 @@ scriptproto_t MODULE_EVENT_PROTO;
|
||||
static moduleeventpending_t MODULE_EVENT_PENDING[MODULE_EVENT_PENDING_MAX];
|
||||
static uint32_t MODULE_EVENT_PENDING_COUNT = 0;
|
||||
|
||||
/**
|
||||
* Single shared C callback subscribed to any event that has JS awaits.
|
||||
* Resolves all pending promises for the fired event, then unsubscribes.
|
||||
* The user pointer is the event_t * so we can look up and unsubscribe.
|
||||
*/
|
||||
static void moduleEventFireCallback(void *params, void *user) {
|
||||
(void)params;
|
||||
void moduleEventTrampoline0(void *params, void *user) {
|
||||
jerry_value_t fn = (jerry_value_t)(uintptr_t)user;
|
||||
jerry_value_t ret = jerry_call(fn, jerry_undefined(), NULL, 0);
|
||||
jerry_value_free(ret);
|
||||
}
|
||||
|
||||
void moduleEventTrampoline1(void *params, void *user) {
|
||||
jerry_value_t fn = (jerry_value_t)(uintptr_t)user;
|
||||
jerry_value_t ret = jerry_call(fn, jerry_undefined(), NULL, 0);
|
||||
jerry_value_free(ret);
|
||||
}
|
||||
|
||||
void moduleEventTrampoline2(void *params, void *user) {
|
||||
jerry_value_t fn = (jerry_value_t)(uintptr_t)user;
|
||||
jerry_value_t ret = jerry_call(fn, jerry_undefined(), NULL, 0);
|
||||
jerry_value_free(ret);
|
||||
}
|
||||
|
||||
void moduleEventTrampoline3(void *params, void *user) {
|
||||
jerry_value_t fn = (jerry_value_t)(uintptr_t)user;
|
||||
jerry_value_t ret = jerry_call(fn, jerry_undefined(), NULL, 0);
|
||||
jerry_value_free(ret);
|
||||
}
|
||||
|
||||
eventcallback_t MODULE_EVENT_TRAMPOLINES[MODULE_EVENT_MAX_SLOTS] = {
|
||||
moduleEventTrampoline0,
|
||||
moduleEventTrampoline1,
|
||||
moduleEventTrampoline2,
|
||||
moduleEventTrampoline3,
|
||||
};
|
||||
|
||||
void moduleEventFree(void *ptr, jerry_object_native_info_t *info) {
|
||||
jsevent_t *ev = (jsevent_t *)ptr;
|
||||
if(ev) {
|
||||
for(uint32_t i = 0; i < MODULE_EVENT_MAX_SLOTS; i++) {
|
||||
if(jerry_value_is_function(ev->fns[i])) {
|
||||
if(ev->event) {
|
||||
eventUnsubscribe(ev->event, MODULE_EVENT_TRAMPOLINES[i]);
|
||||
}
|
||||
jerry_value_free(ev->fns[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
memoryFree(ptr);
|
||||
}
|
||||
|
||||
static void moduleEventWaitFire(void *params, void *user) {
|
||||
event_t *event = (event_t *)user;
|
||||
|
||||
uint32_t i = 0;
|
||||
while(i < MODULE_EVENT_PENDING_COUNT) {
|
||||
if(MODULE_EVENT_PENDING[i].event != event) { i++; continue; }
|
||||
jerry_value_t ret = jerry_promise_resolve(
|
||||
MODULE_EVENT_PENDING[i].promise, jerry_undefined()
|
||||
jerry_value_t undef = jerry_undefined();
|
||||
jerry_value_t r = jerry_promise_resolve(
|
||||
MODULE_EVENT_PENDING[i].promise, undef
|
||||
);
|
||||
jerry_value_free(ret);
|
||||
jerry_value_free(undef);
|
||||
jerry_value_free(r);
|
||||
jerry_value_free(MODULE_EVENT_PENDING[i].promise);
|
||||
MODULE_EVENT_PENDING_COUNT--;
|
||||
if(i < MODULE_EVENT_PENDING_COUNT) {
|
||||
MODULE_EVENT_PENDING[i] = MODULE_EVENT_PENDING[MODULE_EVENT_PENDING_COUNT];
|
||||
MODULE_EVENT_PENDING[i] =
|
||||
MODULE_EVENT_PENDING[MODULE_EVENT_PENDING_COUNT];
|
||||
}
|
||||
}
|
||||
|
||||
eventUnsubscribe(event, moduleEventFireCallback);
|
||||
eventUnsubscribe(event, moduleEventWaitFire);
|
||||
}
|
||||
|
||||
static jerry_value_t moduleEventWait(
|
||||
const jerry_call_info_t *callInfo,
|
||||
const jerry_value_t args[],
|
||||
const jerry_length_t argc
|
||||
) {
|
||||
(void)args; (void)argc;
|
||||
moduleBaseFunction(moduleEventOn) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jsevent_t *ev = (jsevent_t *)scriptProtoGetValue(
|
||||
&MODULE_EVENT_PROTO, callInfo->this_value
|
||||
);
|
||||
if(!ev || !ev->event) {
|
||||
return moduleBaseThrow("Event.on: invalid event");
|
||||
}
|
||||
if(!jerry_value_is_function(args[0])) {
|
||||
return moduleBaseThrow("Event.on: expected function");
|
||||
}
|
||||
for(uint32_t i = 0; i < MODULE_EVENT_MAX_SLOTS; i++) {
|
||||
if(!jerry_value_is_function(ev->fns[i])) {
|
||||
ev->fns[i] = jerry_value_copy(args[0]);
|
||||
eventSubscribe(
|
||||
ev->event,
|
||||
MODULE_EVENT_TRAMPOLINES[i],
|
||||
(void *)(uintptr_t)ev->fns[i]
|
||||
);
|
||||
return jerry_value_copy(callInfo->this_value);
|
||||
}
|
||||
}
|
||||
return moduleBaseThrow("Event.on: no available subscriber slots");
|
||||
}
|
||||
|
||||
jsevent_t *ev = scriptProtoGetValue(&MODULE_EVENT_PROTO, callInfo->this_value);
|
||||
if(!ev) return moduleBaseThrow("Event.wait: invalid this");
|
||||
moduleBaseFunction(moduleEventOff) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jsevent_t *ev = (jsevent_t *)scriptProtoGetValue(
|
||||
&MODULE_EVENT_PROTO, callInfo->this_value
|
||||
);
|
||||
if(!ev || !ev->event) return jerry_value_copy(callInfo->this_value);
|
||||
for(uint32_t i = 0; i < MODULE_EVENT_MAX_SLOTS; i++) {
|
||||
if(!jerry_value_is_function(ev->fns[i])) continue;
|
||||
jerry_value_t eq = jerry_binary_op(
|
||||
JERRY_BIN_OP_STRICT_EQUAL, ev->fns[i], args[0]
|
||||
);
|
||||
bool_t match = jerry_value_is_true(eq);
|
||||
jerry_value_free(eq);
|
||||
if(match) {
|
||||
eventUnsubscribe(ev->event, MODULE_EVENT_TRAMPOLINES[i]);
|
||||
jerry_value_free(ev->fns[i]);
|
||||
ev->fns[i] = jerry_undefined();
|
||||
return jerry_value_copy(callInfo->this_value);
|
||||
}
|
||||
}
|
||||
return jerry_value_copy(callInfo->this_value);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleEventWait) {
|
||||
jsevent_t *ev = (jsevent_t *)scriptProtoGetValue(
|
||||
&MODULE_EVENT_PROTO, callInfo->this_value
|
||||
);
|
||||
if(!ev || !ev->event) {
|
||||
return moduleBaseThrow("Event.wait: invalid event");
|
||||
}
|
||||
|
||||
if(MODULE_EVENT_PENDING_COUNT >= MODULE_EVENT_PENDING_MAX) {
|
||||
return moduleBaseThrow("Event.wait: too many pending awaits");
|
||||
}
|
||||
|
||||
// Only subscribe once per event — check if we already have a pending await
|
||||
bool_t subscribed = false;
|
||||
for(uint32_t i = 0; i < MODULE_EVENT_PENDING_COUNT; i++) {
|
||||
if(MODULE_EVENT_PENDING[i].event == ev->event) { subscribed = true; break; }
|
||||
if(MODULE_EVENT_PENDING[i].event == ev->event) {
|
||||
subscribed = true; break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!subscribed) {
|
||||
if(ev->event->count >= ev->event->size) {
|
||||
return moduleBaseThrow("Event.wait: event subscriber capacity exceeded");
|
||||
return moduleBaseThrow(
|
||||
"Event.wait: event subscriber capacity exceeded"
|
||||
);
|
||||
}
|
||||
eventSubscribe(ev->event, moduleEventFireCallback, (void *)ev->event);
|
||||
eventSubscribe(ev->event, moduleEventWaitFire, (void *)ev->event);
|
||||
}
|
||||
|
||||
jerry_value_t promise = jerry_promise();
|
||||
MODULE_EVENT_PENDING[MODULE_EVENT_PENDING_COUNT].event = ev->event;
|
||||
MODULE_EVENT_PENDING[MODULE_EVENT_PENDING_COUNT].promise = jerry_value_copy(promise);
|
||||
MODULE_EVENT_PENDING[MODULE_EVENT_PENDING_COUNT].promise =
|
||||
jerry_value_copy(promise);
|
||||
MODULE_EVENT_PENDING_COUNT++;
|
||||
return promise;
|
||||
}
|
||||
|
||||
jerry_value_t moduleEventCreate(event_t *event) {
|
||||
assertNotNull(event, "moduleEventCreate: event must not be NULL");
|
||||
jsevent_t ev = { .event = event };
|
||||
jsevent_t ev;
|
||||
ev.event = event;
|
||||
for(uint32_t i = 0; i < MODULE_EVENT_MAX_SLOTS; i++) {
|
||||
ev.fns[i] = jerry_undefined();
|
||||
}
|
||||
return scriptProtoCreateValue(&MODULE_EVENT_PROTO, &ev);
|
||||
}
|
||||
|
||||
jerry_value_t moduleEventGetOrCreate(
|
||||
const jerry_call_info_t *callInfo,
|
||||
event_t *event,
|
||||
const char_t *pinKey
|
||||
) {
|
||||
jerry_value_t keyStr = jerry_string_sz(pinKey);
|
||||
jerry_value_t existing = jerry_object_get(
|
||||
callInfo->this_value, keyStr
|
||||
);
|
||||
if(!jerry_value_is_undefined(existing)) {
|
||||
jerry_value_free(keyStr);
|
||||
return existing;
|
||||
}
|
||||
jerry_value_free(existing);
|
||||
jerry_value_t ev = moduleEventCreate(event);
|
||||
jerry_object_set(callInfo->this_value, keyStr, ev);
|
||||
jerry_value_free(keyStr);
|
||||
return ev;
|
||||
}
|
||||
|
||||
void moduleEventInit(void) {
|
||||
MODULE_EVENT_PENDING_COUNT = 0;
|
||||
scriptProtoInit(&MODULE_EVENT_PROTO, NULL, sizeof(jsevent_t), NULL);
|
||||
scriptProtoInit(
|
||||
&MODULE_EVENT_PROTO, NULL,
|
||||
sizeof(jsevent_t), NULL
|
||||
);
|
||||
MODULE_EVENT_PROTO.info.free_cb = moduleEventFree;
|
||||
scriptProtoDefineFunc(&MODULE_EVENT_PROTO, "on", moduleEventOn);
|
||||
scriptProtoDefineFunc(&MODULE_EVENT_PROTO, "off", moduleEventOff);
|
||||
scriptProtoDefineFunc(&MODULE_EVENT_PROTO, "wait", moduleEventWait);
|
||||
}
|
||||
|
||||
void moduleEventDispose(void) {
|
||||
// Unsubscribe from each distinct event still in the pending list
|
||||
for(uint32_t i = 0; i < MODULE_EVENT_PENDING_COUNT; i++) {
|
||||
bool_t alreadyUnsub = false;
|
||||
for(uint32_t j = 0; j < i; j++) {
|
||||
@@ -103,7 +224,9 @@ void moduleEventDispose(void) {
|
||||
}
|
||||
}
|
||||
if(!alreadyUnsub) {
|
||||
eventUnsubscribe(MODULE_EVENT_PENDING[i].event, moduleEventFireCallback);
|
||||
eventUnsubscribe(
|
||||
MODULE_EVENT_PENDING[i].event, moduleEventWaitFire
|
||||
);
|
||||
}
|
||||
jerry_value_free(MODULE_EVENT_PENDING[i].promise);
|
||||
}
|
||||
|
||||
@@ -10,15 +10,51 @@
|
||||
#include "script/scriptproto.h"
|
||||
#include "event/event.h"
|
||||
|
||||
/** C struct wrapped by every Event JS instance. */
|
||||
typedef struct {
|
||||
event_t *event;
|
||||
} jsevent_t;
|
||||
/** Maximum number of on() subscriber slots per Event. */
|
||||
#define MODULE_EVENT_MAX_SLOTS 4
|
||||
|
||||
extern scriptproto_t MODULE_EVENT_PROTO;
|
||||
|
||||
/**
|
||||
* Wraps a C event_t pointer in a JS Event object.
|
||||
* Array of C trampolines for on() subscriptions.
|
||||
* Slot i uses MODULE_EVENT_TRAMPOLINES[i].
|
||||
*/
|
||||
extern eventcallback_t MODULE_EVENT_TRAMPOLINES[MODULE_EVENT_MAX_SLOTS];
|
||||
|
||||
/** Native data stored on each Event JS object. */
|
||||
typedef struct {
|
||||
event_t *event;
|
||||
jerry_value_t fns[MODULE_EVENT_MAX_SLOTS];
|
||||
} jsevent_t;
|
||||
|
||||
/**
|
||||
* GC free callback — unsubscribes all on() slots and releases JS function
|
||||
* refs when the Event object is garbage collected.
|
||||
*
|
||||
* @param ptr Native jsevent_t pointer.
|
||||
* @param info Native info (unused).
|
||||
*/
|
||||
void moduleEventFree(void *ptr, jerry_object_native_info_t *info);
|
||||
|
||||
/**
|
||||
* on(fn) — subscribes fn to the event. Returns this for chaining.
|
||||
* @param args[0] Function to call when the event fires.
|
||||
*/
|
||||
moduleBaseFunction(moduleEventOn);
|
||||
|
||||
/**
|
||||
* off(fn) — removes a previously subscribed fn. Returns this for chaining.
|
||||
* @param args[0] The same function reference passed to on().
|
||||
*/
|
||||
moduleBaseFunction(moduleEventOff);
|
||||
|
||||
/**
|
||||
* wait() — returns a Promise that resolves the next time the event fires.
|
||||
*/
|
||||
moduleBaseFunction(moduleEventWait);
|
||||
|
||||
/**
|
||||
* Wraps a C event_t pointer in a new JS Event object.
|
||||
*
|
||||
* @param event The event to wrap. Must outlive the returned JS value.
|
||||
* @return A new JS Event instance.
|
||||
@@ -26,11 +62,25 @@ extern scriptproto_t MODULE_EVENT_PROTO;
|
||||
jerry_value_t moduleEventCreate(event_t *event);
|
||||
|
||||
/**
|
||||
* Initializes the Event module and registers the global Event prototype.
|
||||
* Returns the Event object pinned at pinKey on the parent JS object,
|
||||
* creating and pinning a new one on first access.
|
||||
*
|
||||
* @param callInfo The call info — this_value is the parent object.
|
||||
* @param event The C event_t to wrap. Must outlive the parent object.
|
||||
* @param pinKey Property name used to cache the Event on the parent.
|
||||
* @return A JS Event value (caller must free).
|
||||
*/
|
||||
jerry_value_t moduleEventGetOrCreate(
|
||||
const jerry_call_info_t *callInfo,
|
||||
event_t *event,
|
||||
const char_t *pinKey
|
||||
);
|
||||
|
||||
/** Initializes the Event module and registers the global Event prototype. */
|
||||
void moduleEventInit(void);
|
||||
|
||||
/**
|
||||
* Disposes the Event module, rejecting any pending awaits and cleaning up.
|
||||
* Disposes the Event module, rejecting any pending wait() promises and
|
||||
* cleaning up.
|
||||
*/
|
||||
void moduleEventDispose(void);
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
moduleinput.c
|
||||
)
|
||||
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "moduleinput.h"
|
||||
#include <string.h>
|
||||
|
||||
scriptproto_t MODULE_INPUT_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleInputIsDown) {
|
||||
moduleInputRequireAction(0, "Input.isDown");
|
||||
return jerry_boolean(inputIsDown((inputaction_t)moduleBaseArgInt(0)));
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleInputWasDown) {
|
||||
moduleInputRequireAction(0, "Input.wasDown");
|
||||
return jerry_boolean(inputWasDown((inputaction_t)moduleBaseArgInt(0)));
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleInputPressed) {
|
||||
moduleInputRequireAction(0, "Input.pressed");
|
||||
return jerry_boolean(inputPressed((inputaction_t)moduleBaseArgInt(0)));
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleInputReleased) {
|
||||
moduleInputRequireAction(0, "Input.released");
|
||||
return jerry_boolean(inputReleased((inputaction_t)moduleBaseArgInt(0)));
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleInputGetValue) {
|
||||
moduleInputRequireAction(0, "Input.getValue");
|
||||
return jerry_number(
|
||||
inputGetCurrentValue((inputaction_t)moduleBaseArgInt(0))
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleInputAxis) {
|
||||
moduleInputRequireAction(0, "Input.axis");
|
||||
moduleInputRequireAction(1, "Input.axis");
|
||||
return jerry_number(inputAxis(
|
||||
(inputaction_t)moduleBaseArgInt(0),
|
||||
(inputaction_t)moduleBaseArgInt(1)
|
||||
));
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleInputBind) {
|
||||
moduleBaseRequireArgs(2);
|
||||
moduleBaseRequireString(0);
|
||||
if(!jerry_value_is_number(args[1])) {
|
||||
return moduleBaseThrow("Input.bind: action must be a number");
|
||||
}
|
||||
const inputaction_t action = (inputaction_t)moduleBaseArgInt(1);
|
||||
if(action <= INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) {
|
||||
return moduleBaseThrow("Input.bind: invalid action");
|
||||
}
|
||||
|
||||
char_t name[128];
|
||||
moduleBaseToString(args[0], name, sizeof(name));
|
||||
if(name[0] == '\0') {
|
||||
return moduleBaseThrow("Input.bind: button name cannot be empty");
|
||||
}
|
||||
|
||||
inputbutton_t btn = inputButtonGetByName(name);
|
||||
if(btn.type == INPUT_BUTTON_TYPE_NONE) {
|
||||
return moduleBaseThrow("Input.bind: unknown button name");
|
||||
}
|
||||
|
||||
inputBind(btn, action);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
void moduleInputInit(void) {
|
||||
scriptProtoInit(&MODULE_INPUT_PROTO, "Input", sizeof(uint8_t), NULL);
|
||||
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_INPUT_PROTO, "isDown", moduleInputIsDown
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_INPUT_PROTO, "wasDown", moduleInputWasDown
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_INPUT_PROTO, "pressed", moduleInputPressed
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_INPUT_PROTO, "released", moduleInputReleased
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_INPUT_PROTO, "getValue", moduleInputGetValue
|
||||
);
|
||||
scriptProtoDefineStaticFunc(&MODULE_INPUT_PROTO, "axis", moduleInputAxis);
|
||||
scriptProtoDefineStaticFunc(&MODULE_INPUT_PROTO, "bind", moduleInputBind);
|
||||
|
||||
jerry_value_t result = jerry_eval(
|
||||
(const jerry_char_t *)INPUT_ACTION_SCRIPT,
|
||||
strlen(INPUT_ACTION_SCRIPT),
|
||||
JERRY_PARSE_NO_OPTS
|
||||
);
|
||||
jerry_value_free(result);
|
||||
}
|
||||
|
||||
void moduleInputDispose(void) {
|
||||
scriptProtoDispose(&MODULE_INPUT_PROTO);
|
||||
}
|
||||
@@ -11,12 +11,12 @@
|
||||
#include "input/input.h"
|
||||
#include "input/inputbutton.h"
|
||||
|
||||
static scriptproto_t MODULE_INPUT_PROTO;
|
||||
extern scriptproto_t MODULE_INPUT_PROTO;
|
||||
|
||||
/**
|
||||
* Validates an inputaction_t argument and returns a type error if bad.
|
||||
*
|
||||
* @param i Argument index.
|
||||
* Validates an inputaction_t argument and returns a type error if invalid.
|
||||
*
|
||||
* @param i Argument index.
|
||||
* @param ctx Context string for error messages.
|
||||
*/
|
||||
#define moduleInputRequireAction(i, ctx) do { \
|
||||
@@ -29,110 +29,58 @@ static scriptproto_t MODULE_INPUT_PROTO;
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
moduleBaseFunction(moduleInputIsDown) {
|
||||
moduleInputRequireAction(0, "Input.isDown");
|
||||
return jerry_boolean(
|
||||
inputIsDown((inputaction_t)moduleBaseArgInt(0))
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Input.isDown(action) — true while the action is held this frame.
|
||||
* @param args[0] Input action constant.
|
||||
*/
|
||||
moduleBaseFunction(moduleInputIsDown);
|
||||
|
||||
moduleBaseFunction(moduleInputWasDown) {
|
||||
moduleInputRequireAction(0, "Input.wasDown");
|
||||
return jerry_boolean(
|
||||
inputWasDown((inputaction_t)moduleBaseArgInt(0))
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Input.wasDown(action) — true if the action was held last frame.
|
||||
* @param args[0] Input action constant.
|
||||
*/
|
||||
moduleBaseFunction(moduleInputWasDown);
|
||||
|
||||
moduleBaseFunction(moduleInputPressed) {
|
||||
moduleInputRequireAction(0, "Input.pressed");
|
||||
return jerry_boolean(
|
||||
inputPressed((inputaction_t)moduleBaseArgInt(0))
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Input.pressed(action) — true on the first frame the action is held.
|
||||
* @param args[0] Input action constant.
|
||||
*/
|
||||
moduleBaseFunction(moduleInputPressed);
|
||||
|
||||
moduleBaseFunction(moduleInputReleased) {
|
||||
moduleInputRequireAction(0, "Input.released");
|
||||
return jerry_boolean(
|
||||
inputReleased((inputaction_t)moduleBaseArgInt(0))
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Input.released(action) — true on the first frame the action is released.
|
||||
* @param args[0] Input action constant.
|
||||
*/
|
||||
moduleBaseFunction(moduleInputReleased);
|
||||
|
||||
moduleBaseFunction(moduleInputGetValue) {
|
||||
moduleInputRequireAction(0, "Input.getValue");
|
||||
return jerry_number(
|
||||
inputGetCurrentValue((inputaction_t)moduleBaseArgInt(0))
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Input.getValue(action) — returns the analog value (0–1) of the action.
|
||||
* @param args[0] Input action constant.
|
||||
*/
|
||||
moduleBaseFunction(moduleInputGetValue);
|
||||
|
||||
moduleBaseFunction(moduleInputAxis) {
|
||||
moduleInputRequireAction(0, "Input.axis");
|
||||
moduleInputRequireAction(1, "Input.axis");
|
||||
return jerry_number(inputAxis(
|
||||
(inputaction_t)moduleBaseArgInt(0),
|
||||
(inputaction_t)moduleBaseArgInt(1)
|
||||
));
|
||||
}
|
||||
/**
|
||||
* Input.axis(negative, positive) — returns a signed axis value in [-1, 1].
|
||||
* @param args[0] Negative action constant.
|
||||
* @param args[1] Positive action constant.
|
||||
*/
|
||||
moduleBaseFunction(moduleInputAxis);
|
||||
|
||||
moduleBaseFunction(moduleInputBind) {
|
||||
moduleBaseRequireArgs(2);
|
||||
moduleBaseRequireString(0);
|
||||
if(!jerry_value_is_number(args[1])) {
|
||||
return moduleBaseThrow("Input.bind: action must be a number");
|
||||
}
|
||||
const inputaction_t action = (inputaction_t)moduleBaseArgInt(1);
|
||||
if(action <= INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) {
|
||||
return moduleBaseThrow("Input.bind: invalid action");
|
||||
}
|
||||
/**
|
||||
* Input.bind(buttonName, action) — binds a named button to an action.
|
||||
* @param args[0] Button name string.
|
||||
* @param args[1] Input action constant.
|
||||
*/
|
||||
moduleBaseFunction(moduleInputBind);
|
||||
|
||||
char_t name[128];
|
||||
moduleBaseToString(args[0], name, sizeof(name));
|
||||
if(name[0] == '\0') {
|
||||
return moduleBaseThrow("Input.bind: button name cannot be empty");
|
||||
}
|
||||
/**
|
||||
* Initializes the Input module, registers Input.isDown/wasDown/pressed/
|
||||
* released/getValue/axis/bind, and evaluates INPUT_ACTION_SCRIPT to populate
|
||||
* action constants in the global scope.
|
||||
*/
|
||||
void moduleInputInit(void);
|
||||
|
||||
inputbutton_t btn = inputButtonGetByName(name);
|
||||
if(btn.type == INPUT_BUTTON_TYPE_NONE) {
|
||||
return moduleBaseThrow("Input.bind: unknown button name");
|
||||
}
|
||||
|
||||
inputBind(btn, action);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
static void moduleInputInit(void) {
|
||||
scriptProtoInit(&MODULE_INPUT_PROTO, "Input", sizeof(uint8_t), NULL);
|
||||
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_INPUT_PROTO, "isDown", moduleInputIsDown
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_INPUT_PROTO, "wasDown", moduleInputWasDown
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_INPUT_PROTO, "pressed", moduleInputPressed
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_INPUT_PROTO, "released", moduleInputReleased
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_INPUT_PROTO, "getValue", moduleInputGetValue
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_INPUT_PROTO, "axis", moduleInputAxis
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_INPUT_PROTO, "bind", moduleInputBind
|
||||
);
|
||||
|
||||
/* Register INPUT_ACTION_* integer constants into the global scope. */
|
||||
jerry_value_t result = jerry_eval(
|
||||
(const jerry_char_t *)INPUT_ACTION_SCRIPT,
|
||||
strlen(INPUT_ACTION_SCRIPT),
|
||||
JERRY_PARSE_NO_OPTS
|
||||
);
|
||||
jerry_value_free(result);
|
||||
}
|
||||
|
||||
static void moduleInputDispose(void) {
|
||||
scriptProtoDispose(&MODULE_INPUT_PROTO);
|
||||
}
|
||||
/**
|
||||
* Disposes the Input module.
|
||||
*/
|
||||
void moduleInputDispose(void);
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
modulevec3.c
|
||||
)
|
||||
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "modulevec3.h"
|
||||
|
||||
scriptproto_t MODULE_VEC3_PROTO;
|
||||
|
||||
float_t *moduleVec3Get(const jerry_call_info_t *callInfo) {
|
||||
return (float_t *)scriptProtoGetValue(
|
||||
&MODULE_VEC3_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
float_t *moduleVec3From(const jerry_value_t val) {
|
||||
return (float_t *)scriptProtoGetValue(&MODULE_VEC3_PROTO, val);
|
||||
}
|
||||
|
||||
jerry_value_t moduleVec3Push(const vec3 v) {
|
||||
return scriptProtoCreateValue(&MODULE_VEC3_PROTO, v);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleVec3Constructor) {
|
||||
float_t *ptr = (float_t *)memoryAllocate(sizeof(vec3));
|
||||
ptr[0] = moduleBaseOptFloat(0, 0.0f);
|
||||
ptr[1] = moduleBaseOptFloat(1, 0.0f);
|
||||
ptr[2] = moduleBaseOptFloat(2, 0.0f);
|
||||
jerry_object_set_native_ptr(
|
||||
callInfo->this_value, &MODULE_VEC3_PROTO.info, ptr
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleVec3GetX) {
|
||||
float_t *v = moduleVec3Get(callInfo);
|
||||
if(!v) return jerry_undefined();
|
||||
return jerry_number((double)v[0]);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleVec3SetX) {
|
||||
moduleBaseRequireArgs(1);
|
||||
float_t *v = moduleVec3Get(callInfo);
|
||||
if(!v) return jerry_undefined();
|
||||
v[0] = moduleBaseArgFloat(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleVec3GetY) {
|
||||
float_t *v = moduleVec3Get(callInfo);
|
||||
if(!v) return jerry_undefined();
|
||||
return jerry_number((double)v[1]);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleVec3SetY) {
|
||||
moduleBaseRequireArgs(1);
|
||||
float_t *v = moduleVec3Get(callInfo);
|
||||
if(!v) return jerry_undefined();
|
||||
v[1] = moduleBaseArgFloat(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleVec3GetZ) {
|
||||
float_t *v = moduleVec3Get(callInfo);
|
||||
if(!v) return jerry_undefined();
|
||||
return jerry_number((double)v[2]);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleVec3SetZ) {
|
||||
moduleBaseRequireArgs(1);
|
||||
float_t *v = moduleVec3Get(callInfo);
|
||||
if(!v) return jerry_undefined();
|
||||
v[2] = moduleBaseArgFloat(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleVec3ToString) {
|
||||
float_t *v = moduleVec3Get(callInfo);
|
||||
if(!v) return jerry_string_sz("Vec3:invalid");
|
||||
char_t buf[64];
|
||||
snprintf(buf, sizeof(buf), "Vec3(%g, %g, %g)",
|
||||
(double)v[0], (double)v[1], (double)v[2]
|
||||
);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
void moduleVec3Init(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_VEC3_PROTO, "Vec3",
|
||||
sizeof(vec3), moduleVec3Constructor
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_VEC3_PROTO, "x", moduleVec3GetX, moduleVec3SetX
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_VEC3_PROTO, "y", moduleVec3GetY, moduleVec3SetY
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_VEC3_PROTO, "z", moduleVec3GetZ, moduleVec3SetZ
|
||||
);
|
||||
scriptProtoDefineToString(&MODULE_VEC3_PROTO, moduleVec3ToString);
|
||||
}
|
||||
|
||||
void moduleVec3Dispose(void) {
|
||||
scriptProtoDispose(&MODULE_VEC3_PROTO);
|
||||
}
|
||||
@@ -11,103 +11,59 @@
|
||||
#include "util/memory.h"
|
||||
#include "cglm/cglm.h"
|
||||
|
||||
static scriptproto_t MODULE_VEC3_PROTO;
|
||||
extern scriptproto_t MODULE_VEC3_PROTO;
|
||||
|
||||
float_t * moduleVec3Get(const jerry_call_info_t *callInfo) {
|
||||
return (float_t *)scriptProtoGetValue(
|
||||
&MODULE_VEC3_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Returns the raw float[3] pointer from a Vec3 JS instance.
|
||||
*
|
||||
* @param callInfo Call info whose this_value is the Vec3 instance.
|
||||
* @return Pointer to the vec3 data, or NULL if not a Vec3.
|
||||
*/
|
||||
float_t *moduleVec3Get(const jerry_call_info_t *callInfo);
|
||||
|
||||
float_t * moduleVec3From(const jerry_value_t val) {
|
||||
return (float_t *)scriptProtoGetValue(&MODULE_VEC3_PROTO, val);
|
||||
}
|
||||
/**
|
||||
* Returns the raw float[3] pointer from an arbitrary Vec3 JS value.
|
||||
*
|
||||
* @param val The JS value to extract from.
|
||||
* @return Pointer to the vec3 data, or NULL if not a Vec3.
|
||||
*/
|
||||
float_t *moduleVec3From(const jerry_value_t val);
|
||||
|
||||
jerry_value_t moduleVec3Push(const vec3 v) {
|
||||
return scriptProtoCreateValue(&MODULE_VEC3_PROTO, v);
|
||||
}
|
||||
/**
|
||||
* Creates a Vec3 JS object wrapping a copy of a C vec3.
|
||||
*
|
||||
* @param v The source vec3.
|
||||
* @return A new Vec3 JS object.
|
||||
*/
|
||||
jerry_value_t moduleVec3Push(const vec3 v);
|
||||
|
||||
moduleBaseFunction(moduleVec3Constructor) {
|
||||
float_t *ptr = (float_t *)memoryAllocate(sizeof(vec3));
|
||||
ptr[0] = moduleBaseOptFloat(0, 0.0f);
|
||||
ptr[1] = moduleBaseOptFloat(1, 0.0f);
|
||||
ptr[2] = moduleBaseOptFloat(2, 0.0f);
|
||||
jerry_object_set_native_ptr(
|
||||
callInfo->this_value, &MODULE_VEC3_PROTO.info, ptr
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/** Vec3(x?, y?, z?) constructor. */
|
||||
moduleBaseFunction(moduleVec3Constructor);
|
||||
|
||||
moduleBaseFunction(moduleVec3GetX) {
|
||||
float_t *v = moduleVec3Get(callInfo);
|
||||
if(!v) return jerry_undefined();
|
||||
return jerry_number((double)v[0]);
|
||||
}
|
||||
/** @return The x component as a number. */
|
||||
moduleBaseFunction(moduleVec3GetX);
|
||||
/** Sets the x component. @param args[0] New x value. */
|
||||
moduleBaseFunction(moduleVec3SetX);
|
||||
|
||||
moduleBaseFunction(moduleVec3SetX) {
|
||||
moduleBaseRequireArgs(1);
|
||||
float_t *v = moduleVec3Get(callInfo);
|
||||
if(!v) return jerry_undefined();
|
||||
v[0] = moduleBaseArgFloat(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/** @return The y component as a number. */
|
||||
moduleBaseFunction(moduleVec3GetY);
|
||||
/** Sets the y component. @param args[0] New y value. */
|
||||
moduleBaseFunction(moduleVec3SetY);
|
||||
|
||||
moduleBaseFunction(moduleVec3GetY) {
|
||||
float_t *v = moduleVec3Get(callInfo);
|
||||
if(!v) return jerry_undefined();
|
||||
return jerry_number((double)v[1]);
|
||||
}
|
||||
/** @return The z component as a number. */
|
||||
moduleBaseFunction(moduleVec3GetZ);
|
||||
/** Sets the z component. @param args[0] New z value. */
|
||||
moduleBaseFunction(moduleVec3SetZ);
|
||||
|
||||
moduleBaseFunction(moduleVec3SetY) {
|
||||
moduleBaseRequireArgs(1);
|
||||
float_t *v = moduleVec3Get(callInfo);
|
||||
if(!v) return jerry_undefined();
|
||||
v[1] = moduleBaseArgFloat(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
/** @return "Vec3(x, y, z)" string. */
|
||||
moduleBaseFunction(moduleVec3ToString);
|
||||
|
||||
moduleBaseFunction(moduleVec3GetZ) {
|
||||
float_t *v = moduleVec3Get(callInfo);
|
||||
if(!v) return jerry_undefined();
|
||||
return jerry_number((double)v[2]);
|
||||
}
|
||||
/**
|
||||
* Initializes the Vec3 module and registers the global Vec3 class.
|
||||
*/
|
||||
void moduleVec3Init(void);
|
||||
|
||||
moduleBaseFunction(moduleVec3SetZ) {
|
||||
moduleBaseRequireArgs(1);
|
||||
float_t *v = moduleVec3Get(callInfo);
|
||||
if(!v) return jerry_undefined();
|
||||
v[2] = moduleBaseArgFloat(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleVec3ToString) {
|
||||
float_t *v = moduleVec3Get(callInfo);
|
||||
if(!v) return jerry_string_sz("Vec3:invalid");
|
||||
char_t buf[64];
|
||||
snprintf(buf, sizeof(buf), "Vec3(%g, %g, %g)",
|
||||
(double)v[0], (double)v[1], (double)v[2]
|
||||
);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
static void moduleVec3Init(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_VEC3_PROTO, "Vec3",
|
||||
sizeof(vec3), moduleVec3Constructor
|
||||
);
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_VEC3_PROTO, "x", moduleVec3GetX, moduleVec3SetX
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_VEC3_PROTO, "y", moduleVec3GetY, moduleVec3SetY
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_VEC3_PROTO, "z", moduleVec3GetZ, moduleVec3SetZ
|
||||
);
|
||||
scriptProtoDefineToString(&MODULE_VEC3_PROTO, moduleVec3ToString);
|
||||
}
|
||||
|
||||
static void moduleVec3Dispose(void) {
|
||||
scriptProtoDispose(&MODULE_VEC3_PROTO);
|
||||
}
|
||||
/**
|
||||
* Disposes the Vec3 module.
|
||||
*/
|
||||
void moduleVec3Dispose(void);
|
||||
|
||||
@@ -154,7 +154,7 @@ void moduleBaseSetNumber(const char_t *name, double value);
|
||||
void moduleBaseSetInt(const char_t *name, int32_t value);
|
||||
|
||||
#define moduleBaseFunction(name) \
|
||||
static jerry_value_t name( \
|
||||
jerry_value_t name( \
|
||||
const jerry_call_info_t *callInfo, \
|
||||
const jerry_value_t args[], \
|
||||
const jerry_length_t argc)
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
#include "script/module/engine/moduleframe.h"
|
||||
#include "script/module/event/moduleevent.h"
|
||||
#include "script/module/engine/moduletimeout.h"
|
||||
#include "script/module/entity/component/modulecomponentlist.h"
|
||||
#include "script/module/entity/modulecomponent.h"
|
||||
#include "script/module/entity/moduleentity.h"
|
||||
#include "script/module/input/moduleinput.h"
|
||||
#include "script/module/math/modulevec3.h"
|
||||
@@ -35,9 +33,7 @@ void moduleListInit(void) {
|
||||
moduleFrameInit();
|
||||
moduleTimeoutInit();
|
||||
moduleVec3Init();
|
||||
moduleComponentInit();
|
||||
moduleEntityInit();
|
||||
moduleComponentListInit();
|
||||
moduleInputInit();
|
||||
moduleRequireInit();
|
||||
moduleSceneInit();
|
||||
@@ -54,9 +50,7 @@ void moduleListDispose(void) {
|
||||
moduleSceneDispose();
|
||||
moduleRequireDispose();
|
||||
moduleInputDispose();
|
||||
moduleComponentListDispose();
|
||||
moduleEntityDispose();
|
||||
moduleComponentDispose();
|
||||
moduleVec3Dispose();
|
||||
moduleTimeoutDispose();
|
||||
moduleFrameDispose();
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
modulescene.c
|
||||
)
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "modulescene.h"
|
||||
|
||||
scriptproto_t MODULE_SCENE_PROTO;
|
||||
|
||||
void moduleSceneInit(void) {
|
||||
scriptProtoInit(&MODULE_SCENE_PROTO, "Scene", sizeof(uint8_t), NULL);
|
||||
}
|
||||
|
||||
void moduleSceneDispose(void) {
|
||||
scriptProtoDispose(&MODULE_SCENE_PROTO);
|
||||
}
|
||||
@@ -14,12 +14,14 @@
|
||||
#include "asset/loader/assetloader.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
static scriptproto_t MODULE_SCENE_PROTO;
|
||||
extern scriptproto_t MODULE_SCENE_PROTO;
|
||||
|
||||
static void moduleSceneInit(void) {
|
||||
scriptProtoInit(&MODULE_SCENE_PROTO, "Scene", sizeof(uint8_t), NULL);
|
||||
}
|
||||
/**
|
||||
* Initializes the Scene module and registers the global Scene object.
|
||||
*/
|
||||
void moduleSceneInit(void);
|
||||
|
||||
static void moduleSceneDispose(void) {
|
||||
scriptProtoDispose(&MODULE_SCENE_PROTO);
|
||||
}
|
||||
/**
|
||||
* Disposes the Scene module.
|
||||
*/
|
||||
void moduleSceneDispose(void);
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
modulesystem.c
|
||||
)
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "modulesystem.h"
|
||||
|
||||
scriptproto_t MODULE_SYSTEM_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleSystemGetPlatform) {
|
||||
return jerry_number((double)systemGetPlatform());
|
||||
}
|
||||
|
||||
void moduleSystemInit(void) {
|
||||
scriptProtoInit(&MODULE_SYSTEM_PROTO, "System", sizeof(uint8_t), NULL);
|
||||
|
||||
scriptProtoDefineStaticProp(
|
||||
&MODULE_SYSTEM_PROTO, "platform",
|
||||
moduleSystemGetPlatform, NULL
|
||||
);
|
||||
|
||||
jerry_value_t target = MODULE_SYSTEM_PROTO.prototype;
|
||||
#define SYSTEM_PLATFORM(name, value) \
|
||||
do { \
|
||||
jerry_value_t key = jerry_string_sz("PLATFORM_" #name); \
|
||||
jerry_value_t val = jerry_number((double)(value)); \
|
||||
jerry_object_set(target, key, val); \
|
||||
jerry_value_free(val); \
|
||||
jerry_value_free(key); \
|
||||
} while(0);
|
||||
SYSTEM_PLATFORM_LIST
|
||||
#undef SYSTEM_PLATFORM
|
||||
}
|
||||
|
||||
void moduleSystemDispose(void) {
|
||||
scriptProtoDispose(&MODULE_SYSTEM_PROTO);
|
||||
}
|
||||
@@ -10,35 +10,20 @@
|
||||
#include "script/scriptproto.h"
|
||||
#include "system/system.h"
|
||||
|
||||
static scriptproto_t MODULE_SYSTEM_PROTO;
|
||||
extern scriptproto_t MODULE_SYSTEM_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleSystemGetPlatform) {
|
||||
return jerry_number((double)systemGetPlatform());
|
||||
}
|
||||
/**
|
||||
* @return Current platform as a System.PLATFORM_* constant.
|
||||
*/
|
||||
moduleBaseFunction(moduleSystemGetPlatform);
|
||||
|
||||
static void moduleSystemInit(void) {
|
||||
scriptProtoInit(&MODULE_SYSTEM_PROTO, "System", sizeof(uint8_t), NULL);
|
||||
/**
|
||||
* Initializes the System module, registers the global System object with the
|
||||
* platform property and all PLATFORM_* constants.
|
||||
*/
|
||||
void moduleSystemInit(void);
|
||||
|
||||
scriptProtoDefineStaticProp(
|
||||
&MODULE_SYSTEM_PROTO, "platform",
|
||||
moduleSystemGetPlatform, NULL
|
||||
);
|
||||
|
||||
/* Register PLATFORM_* integer constants on the System global. */
|
||||
jerry_value_t target = MODULE_SYSTEM_PROTO.prototype;
|
||||
|
||||
#define SYSTEM_PLATFORM(name, value) \
|
||||
do { \
|
||||
jerry_value_t key = jerry_string_sz("PLATFORM_" #name); \
|
||||
jerry_value_t val = jerry_number((double)(value)); \
|
||||
jerry_object_set(target, key, val); \
|
||||
jerry_value_free(val); \
|
||||
jerry_value_free(key); \
|
||||
} while(0);
|
||||
SYSTEM_PLATFORM_LIST
|
||||
#undef SYSTEM_PLATFORM
|
||||
}
|
||||
|
||||
static void moduleSystemDispose(void) {
|
||||
scriptProtoDispose(&MODULE_SYSTEM_PROTO);
|
||||
}
|
||||
/**
|
||||
* Disposes the System module.
|
||||
*/
|
||||
void moduleSystemDispose(void);
|
||||
|
||||
Vendored
-18
@@ -5,24 +5,6 @@
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* An array-like proxy over one of an asset entry's events.
|
||||
* Assign a function to a numbered slot to subscribe; assign `null` to
|
||||
* unsubscribe that slot.
|
||||
*
|
||||
* @example
|
||||
* entry.onLoaded[0] = () => Console.print('loaded!');
|
||||
* entry.onLoaded[0] = null; // unsubscribe
|
||||
*/
|
||||
interface AssetEventProxy {
|
||||
readonly length: number;
|
||||
0: (() => void) | null;
|
||||
1: (() => void) | null;
|
||||
2: (() => void) | null;
|
||||
3: (() => void) | null;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A live reference to an entry in the asset cache.
|
||||
* Holds a lock that keeps the entry alive; the lock is released automatically
|
||||
|
||||
Reference in New Issue
Block a user