Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 82c300b077 | |||
| 0f8b629e20 | |||
| 36f6ac65f2 | |||
| a25871a849 | |||
| 57766a9104 | |||
| d73edb403f | |||
| b14196ff0d |
@@ -144,7 +144,7 @@ jobs:
|
||||
- name: Copy output files.
|
||||
run: |
|
||||
mkdir -p ./git-artifcats/Dusk/apps/Dusk
|
||||
cp build-wii/Dusk.dol ./git-artifcats/Dusk/apps/Dusk/boot.dol
|
||||
cp build-wii/boot.dol ./git-artifcats/Dusk/apps/Dusk/boot.dol
|
||||
cp build-wii/dusk.dsk ./git-artifcats/Dusk/apps/Dusk/dusk.dsk
|
||||
cp build-wii/meta.xml ./git-artifcats/Dusk/apps/Dusk/meta.xml
|
||||
- name: Upload Wii binary
|
||||
|
||||
@@ -106,3 +106,4 @@ yarn.lock
|
||||
/build*
|
||||
/assets/test
|
||||
/tools_old
|
||||
/assets/test.png
|
||||
@@ -0,0 +1,24 @@
|
||||
// Load rosa.
|
||||
Console.print('Asset time');
|
||||
const entry = Asset.lock('test.png', Asset.TYPE_TEXTURE, Texture.FORMAT_RGBA);
|
||||
Asset.requireLoaded(entry);
|
||||
Console.print('Asset loaded');
|
||||
|
||||
// Camera at (3,3,3) looking at origin
|
||||
const cam = Entity.create();
|
||||
const camPos = cam.add(Component.POSITION);
|
||||
cam.add(Component.CAMERA);
|
||||
camPos.localPosition = new Vec3(3, 3, 3);
|
||||
camPos.lookAt(new Vec3(0, 0, 0));
|
||||
|
||||
// Test entity at origin
|
||||
const testEntity = Entity.create();
|
||||
const testPos = testEntity.add(Component.POSITION);
|
||||
|
||||
/** @type {RenderableSpritebatch} */
|
||||
const testRenderable = testEntity.add(Component.RENDERABLE);
|
||||
testRenderable.texture = entry.texture;
|
||||
testRenderable.sprites = [
|
||||
[0, 0, 1, 1, 0, 1, 1, 0]
|
||||
];
|
||||
testPos.localPosition = new Vec3(0, 0, 0);
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/bash
|
||||
docker build -t dusk-dolphin -f docker/dolphin/Dockerfile .
|
||||
docker run --rm -v $(pwd):/workdir dusk-dolphin /bin/bash -c "./scripts/build-gamecube.sh"
|
||||
docker run --rm -v "$(pwd):/workdir" dusk-dolphin /bin/bash -c "./scripts/build-gamecube.sh"
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/bash
|
||||
docker build -t dusk-dolphin -f docker/dolphin/Dockerfile .
|
||||
docker run --rm -v $(pwd):/workdir dusk-dolphin /bin/bash -c "./scripts/build-gamecube-iso.sh"
|
||||
docker run --rm -v "$(pwd):/workdir" dusk-dolphin /bin/bash -c "./scripts/build-gamecube-iso.sh"
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/bash
|
||||
docker build -t dusk-knulli -f docker/knulli/Dockerfile .
|
||||
docker run --rm -v $(pwd):/workdir dusk-knulli /bin/bash -c "./scripts/build-knulli.sh"
|
||||
docker run --rm -v "$(pwd):/workdir" dusk-knulli /bin/bash -c "./scripts/build-knulli.sh"
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/bash
|
||||
docker build -t dusk-linux -f docker/linux/Dockerfile .
|
||||
docker run --rm -v $(pwd):/workdir dusk-linux /bin/bash -c "./scripts/build-linux.sh"
|
||||
docker run --rm -v "$(pwd):/workdir" dusk-linux /bin/bash -c "./scripts/build-linux.sh"
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/bash
|
||||
docker build -t dusk-psp -f docker/psp/Dockerfile .
|
||||
docker run --rm -v $(pwd):/workdir dusk-psp /bin/bash -c "./scripts/build-psp.sh"
|
||||
docker run --rm -v "$(pwd):/workdir" dusk-psp /bin/bash -c "./scripts/build-psp.sh"
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/bash
|
||||
docker build -t dusk-vita -f docker/vita/Dockerfile .
|
||||
docker run --rm -v $(pwd):/workdir dusk-vita /bin/bash -c "./scripts/build-vita.sh"
|
||||
docker run --rm -v "$(pwd):/workdir" dusk-vita /bin/bash -c "./scripts/build-vita.sh"
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/bash
|
||||
docker build -t dusk-dolphin -f docker/dolphin/Dockerfile .
|
||||
docker run --rm -v $(pwd):/workdir dusk-dolphin /bin/bash -c "./scripts/build-wii.sh"
|
||||
docker run --rm -v "$(pwd):/workdir" dusk-dolphin /bin/bash -c "./scripts/build-wii.sh"
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/bash
|
||||
docker build -t dusk-dolphin -f docker/dolphin/Dockerfile .
|
||||
docker run --rm -v $(pwd):/workdir dusk-dolphin /bin/bash -c "./scripts/build-wii-iso.sh"
|
||||
docker run --rm -v "$(pwd):/workdir" dusk-dolphin /bin/bash -c "./scripts/build-wii-iso.sh"
|
||||
|
||||
@@ -8,3 +8,4 @@ mkdir -p build-wii
|
||||
cmake -S. -Bbuild-wii -DDUSK_TARGET_SYSTEM=wii -DCMAKE_TOOLCHAIN_FILE="$DEVKITPRO/cmake/Wii.cmake"
|
||||
cd build-wii
|
||||
make -j$(nproc) VERBOSE=1
|
||||
mv Dusk.dol boot.dol
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/bash
|
||||
docker build -t dusk-linux -f docker/linux/Dockerfile .
|
||||
docker run --rm -v $(pwd):/workdir dusk-linux /bin/bash -c "./scripts/test-linux.sh"
|
||||
docker run --rm -v "$(pwd):/workdir" dusk-linux /bin/bash -c "./scripts/test-linux.sh"
|
||||
+10
-8
@@ -197,8 +197,12 @@ errorret_t assetUpdate(void) {
|
||||
switch(loading->entry->state) {
|
||||
// This thing is pending synchronous loading.
|
||||
case ASSET_ENTRY_STATE_PENDING_SYNC:
|
||||
// Perform sync load.
|
||||
loading->entry->state = ASSET_ENTRY_STATE_LOADING_SYNC;
|
||||
// Unlock before calling loadSync. The sync loader may re-enter
|
||||
// assetUpdate (e.g. a script loading another asset), and the async
|
||||
// thread never touches LOADING_SYNC entries, so this is safe.
|
||||
threadMutexUnlock(&loading->mutex);
|
||||
|
||||
errorret_t ret = (
|
||||
ASSET_LOADER_CALLBACKS[loading->type].loadSync(loading)
|
||||
);
|
||||
@@ -212,8 +216,6 @@ errorret_t assetUpdate(void) {
|
||||
"Loader did not set entry state to loaded or error on finished load."
|
||||
);
|
||||
|
||||
// If an error occured these things need to be true, basically just
|
||||
// ensuring the sync loader is setting the error correctly.
|
||||
if(errorIsNotOk(ret)) {
|
||||
errorCatch(errorPrint(ret));
|
||||
assertTrue(
|
||||
@@ -222,15 +224,15 @@ errorret_t assetUpdate(void) {
|
||||
);
|
||||
}
|
||||
|
||||
threadMutexUnlock(&loading->mutex);
|
||||
loading++;
|
||||
break;
|
||||
|
||||
case ASSET_ENTRY_STATE_LOADING_SYNC:
|
||||
assertUnreachable(
|
||||
"Entry is in a pending sync state still?"
|
||||
);
|
||||
break;
|
||||
// A re-entrant assetUpdate call (e.g. from a script loading another
|
||||
// asset) will see this entry mid-sync-load. Skip it.
|
||||
threadMutexUnlock(&loading->mutex);
|
||||
loading++;
|
||||
continue;
|
||||
|
||||
// Done loading, we can just free it up.
|
||||
case ASSET_ENTRY_STATE_LOADED:
|
||||
|
||||
@@ -25,8 +25,11 @@ void assetEntryInit(
|
||||
memoryZero(entry, sizeof(assetentry_t));
|
||||
stringCopy(entry->name, name, ASSET_FILE_NAME_MAX);
|
||||
entry->type = type;
|
||||
entry->input = input;
|
||||
entry->state = ASSET_ENTRY_STATE_NOT_STARTED;
|
||||
if(input) {
|
||||
entry->inputData = *input;
|
||||
entry->input = &entry->inputData;
|
||||
}
|
||||
refInit(&entry->refs, entry, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,9 @@ typedef struct assetentry_s {
|
||||
// zero). Entries that nobody has ever locked are left alone so raw-pointer
|
||||
// callers (tests, requireLoaded before locking) are not surprised.
|
||||
bool_t wasLocked;
|
||||
// Data that will be passed to the loader about how it should load.
|
||||
// Owned copy of the loader input. input points here when non-NULL.
|
||||
assetloaderinput_t inputData;
|
||||
// Pointer to inputData, or NULL if no input was provided.
|
||||
assetloaderinput_t *input;
|
||||
} assetentry_t;
|
||||
|
||||
|
||||
@@ -47,19 +47,19 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
|
||||
errorChain(displayInit());
|
||||
errorChain(uiInit());
|
||||
errorChain(uiTextboxInit());
|
||||
|
||||
errorChain(cutsceneInit());
|
||||
errorChain(sceneInit());
|
||||
entityManagerInit();
|
||||
backpackInit();
|
||||
physicsManagerInit();
|
||||
errorChain(networkInit());
|
||||
|
||||
errorChain(scriptInit());
|
||||
errorChain(scriptExecFile("init.js"));
|
||||
|
||||
consolePrint("Engine initialized");
|
||||
|
||||
errorChain(scriptExecFile("init.js"));
|
||||
sceneSet(SCENE_TYPE_INITIAL);
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@ void entityRenderableDispose(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
void entityRenderableSetType(
|
||||
@@ -80,20 +79,15 @@ void entityRenderableSetDraw(
|
||||
r->data.custom.drawUser = user;
|
||||
}
|
||||
|
||||
errorret_t entityRenderableDraw(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
static errorret_t entityRenderableDrawSpritebatch(
|
||||
const entityrenderablespritebatch_t *sb
|
||||
) {
|
||||
entityrenderable_t *r = componentGetData(
|
||||
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
if(sb->spriteCount == 0) errorOk();
|
||||
|
||||
switch(r->type) {
|
||||
case ENTITY_RENDERABLE_TYPE_SPRITEBATCH: {
|
||||
const entityrenderablespritebatch_t *sb = &r->data.spritebatch;
|
||||
errorChain(displaySetState((displaystate_t){
|
||||
.flags = DISPLAY_STATE_FLAG_BLEND
|
||||
}));
|
||||
|
||||
spriteBatchClear();
|
||||
shadermaterial_t mat;
|
||||
memoryZero(&mat, sizeof(shadermaterial_t));
|
||||
@@ -106,8 +100,9 @@ errorret_t entityRenderableDraw(
|
||||
return spriteBatchFlush();
|
||||
}
|
||||
|
||||
case ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL: {
|
||||
const entityrenderablematerial_t *m = &r->data.material;
|
||||
static errorret_t entityRenderableDrawMaterial(
|
||||
const entityrenderablematerial_t *m
|
||||
) {
|
||||
errorChain(displaySetState(m->state));
|
||||
shader_t *shader = SHADER_LIST_DEFS[m->shaderType].shader;
|
||||
assertNotNull(shader, "Shader cannot be null for material type");
|
||||
@@ -119,9 +114,28 @@ errorret_t entityRenderableDraw(
|
||||
errorOk();
|
||||
}
|
||||
|
||||
case ENTITY_RENDERABLE_TYPE_CUSTOM:
|
||||
return r->data.custom.draw(entityId, componentId, r->data.custom.drawUser);
|
||||
static errorret_t entityRenderableDrawCustom(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const entityrenderablecustom_t *custom
|
||||
) {
|
||||
return custom->draw(entityId, componentId, custom->drawUser);
|
||||
}
|
||||
|
||||
errorret_t entityRenderableDraw(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entityrenderable_t *r = componentGetData(
|
||||
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
switch(r->type) {
|
||||
case ENTITY_RENDERABLE_TYPE_SPRITEBATCH:
|
||||
return entityRenderableDrawSpritebatch(&r->data.spritebatch);
|
||||
case ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL:
|
||||
return entityRenderableDrawMaterial(&r->data.material);
|
||||
case ENTITY_RENDERABLE_TYPE_CUSTOM:
|
||||
return entityRenderableDrawCustom(entityId, componentId, &r->data.custom);
|
||||
default:
|
||||
assertUnreachable("Invalid renderable type");
|
||||
}
|
||||
|
||||
@@ -8,28 +8,21 @@
|
||||
#include "initialscene.h"
|
||||
#include "console/console.h"
|
||||
#include "scene/scene.h"
|
||||
#include "time/time.h"
|
||||
#include "ui/uiloading.h"
|
||||
#include "script/script.h"
|
||||
#include "entity/entitymanager.h"
|
||||
#include "entity/entity.h"
|
||||
#include "entity/component/display/entityposition.h"
|
||||
#include "entity/component/display/entityrenderable.h"
|
||||
|
||||
void initialSceneInit(void) {
|
||||
consolePrint("Initial scene initialized");
|
||||
SCENE.data.initial.timer = 0.0f;
|
||||
SCENE.data.initial.hiding = false;
|
||||
uiLoadingShow(NULL, NULL);
|
||||
errorCatch(errorPrint(scriptExecFile("testentity.js")));
|
||||
}
|
||||
|
||||
errorret_t initialSceneUpdate(void) {
|
||||
initialscene_t *scene = &SCENE.data.initial;
|
||||
if(scene->hiding) errorOk();
|
||||
|
||||
scene->timer += TIME.delta;
|
||||
if(scene->timer >= INITIAL_SCENE_WAIT) {
|
||||
scene->hiding = true;
|
||||
uiLoadingHide(NULL, NULL);
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void initialSceneDispose(void) {
|
||||
entityDispose(SCENE.data.initial.cubeEntityId);
|
||||
}
|
||||
|
||||
@@ -7,12 +7,10 @@
|
||||
|
||||
#pragma once
|
||||
#include "error/error.h"
|
||||
|
||||
#define INITIAL_SCENE_WAIT 2.0f
|
||||
#include "entity/entitybase.h"
|
||||
|
||||
typedef struct {
|
||||
float_t timer;
|
||||
bool_t hiding;
|
||||
entityid_t cubeEntityId;
|
||||
} initialscene_t;
|
||||
|
||||
void initialSceneInit(void);
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "script/module/display/moduletexture.h"
|
||||
#include "script/module/asset/moduleassetentry.h"
|
||||
#include "asset/asset.h"
|
||||
#include "asset/loader/assetloader.h"
|
||||
|
||||
static 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);
|
||||
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();
|
||||
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);
|
||||
moduleAssetEntryDispose();
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "script/module/display/moduletexture.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;
|
||||
|
||||
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.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void moduleAssetEntryInit(void) {
|
||||
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
|
||||
);
|
||||
scriptProtoDefineToString(
|
||||
&MODULE_ASSET_ENTRY_PROTO, moduleAssetEntryToString
|
||||
);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void moduleAssetEntryDispose(void) {
|
||||
scriptProtoDispose(&MODULE_ASSET_ENTRY_PROTO);
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "util/memory.h"
|
||||
#include "display/color.h"
|
||||
|
||||
static 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.
|
||||
*/
|
||||
static inline color_t *moduleColorFrom(const jerry_value_t val) {
|
||||
return (color_t *)scriptProtoGetValue(&MODULE_COLOR_PROTO, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Color JS object from a C color_t value.
|
||||
*/
|
||||
static inline 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "asset/asset.h"
|
||||
#include "asset/loader/assetloader.h"
|
||||
#include "display/texture/texture.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
static scriptproto_t MODULE_TEXTURE_PROTO;
|
||||
|
||||
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.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTextureCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("Texture cannot be instantiated with new");
|
||||
}
|
||||
|
||||
static inline jstexture_t *moduleTextureSelf(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (jstexture_t *)scriptProtoGetValue(
|
||||
&MODULE_TEXTURE_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "script/module/entity/modulecomponent.h"
|
||||
#include "entity/component/display/entitycamera.h"
|
||||
|
||||
static scriptproto_t MODULE_CAMERA_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleCameraCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("Camera cannot be instantiated with new");
|
||||
}
|
||||
|
||||
static inline jscomponent_t *moduleCameraSelf(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_CAMERA_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
static inline entitycamera_t *moduleCameraData(const jscomponent_t *c) {
|
||||
return (entitycamera_t *)componentGetData(
|
||||
c->entityId, c->componentId, COMPONENT_TYPE_CAMERA
|
||||
);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "script/module/entity/modulecomponent.h"
|
||||
#include "entity/component/overworld/entityinteractable.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
static scriptproto_t MODULE_INTERACTABLE_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleInteractableCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("Interactable cannot be instantiated with new");
|
||||
}
|
||||
|
||||
static inline jscomponent_t *moduleInteractableSelf(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_INTERACTABLE_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
static void moduleInteractableCb(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
void *user
|
||||
) {
|
||||
(void)entityId; (void)componentId;
|
||||
jerry_value_t fn = *((jerry_value_t *)user);
|
||||
jerry_value_t ret = jerry_call(fn, jerry_undefined(), NULL, 0);
|
||||
jerry_value_free(ret);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleInteractableGetEntity) {
|
||||
jscomponent_t *c = moduleInteractableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->entityId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleInteractableGetId) {
|
||||
jscomponent_t *c = moduleInteractableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->componentId);
|
||||
}
|
||||
|
||||
/*
|
||||
* onInteract getter — reads back the pinned JS function stored on this._cb.
|
||||
*/
|
||||
moduleBaseFunction(moduleInteractableGetOnInteract) {
|
||||
(void)args; (void)argc;
|
||||
jerry_value_t key = jerry_string_sz("_cb");
|
||||
jerry_value_t val = jerry_object_get(callInfo->this_value, key);
|
||||
jerry_value_free(key);
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* onInteract setter — pins the JS function on this._cb for GC safety, and
|
||||
* registers a C trampoline that calls it when the player interacts.
|
||||
* Passing null/undefined clears the callback.
|
||||
*/
|
||||
moduleBaseFunction(moduleInteractableSetOnInteract) {
|
||||
jscomponent_t *c = moduleInteractableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityinteractable_t *d = entityInteractableGet(c->entityId, c->componentId);
|
||||
if(!d) return jerry_undefined();
|
||||
|
||||
/* Free previously stored JS reference */
|
||||
if(d->user) {
|
||||
jerry_value_free(*((jerry_value_t *)d->user));
|
||||
free(d->user);
|
||||
d->user = NULL;
|
||||
}
|
||||
|
||||
jerry_value_t pin = (argc > 0) ? args[0] : jerry_undefined();
|
||||
jerry_value_t pinKey = jerry_string_sz("_cb");
|
||||
|
||||
if(jerry_value_is_function(pin)) {
|
||||
jerry_value_t *stored = (jerry_value_t *)malloc(sizeof(jerry_value_t));
|
||||
*stored = jerry_value_copy(pin);
|
||||
entityInteractableSetCallback(
|
||||
c->entityId, c->componentId, moduleInteractableCb, stored
|
||||
);
|
||||
jerry_object_set(callInfo->this_value, pinKey, pin);
|
||||
} else {
|
||||
entityInteractableSetCallback(c->entityId, c->componentId, NULL, NULL);
|
||||
jerry_value_t undef = jerry_undefined();
|
||||
jerry_object_set(callInfo->this_value, pinKey, undef);
|
||||
jerry_value_free(undef);
|
||||
}
|
||||
|
||||
jerry_value_free(pinKey);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleInteractableTrigger) {
|
||||
(void)args; (void)argc;
|
||||
jscomponent_t *c = moduleInteractableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityInteractableTrigger(c->entityId, c->componentId);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleInteractableToString) {
|
||||
jscomponent_t *c = moduleInteractableSelf(callInfo);
|
||||
if(!c) return jerry_string_sz("Interactable:invalid");
|
||||
char_t buf[32];
|
||||
snprintf(buf, sizeof(buf), "Interactable(%u)", (unsigned)c->componentId);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
static void moduleInteractableInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_INTERACTABLE_PROTO, "Interactable",
|
||||
sizeof(jscomponent_t), moduleInteractableCtor
|
||||
);
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_INTERACTABLE_PROTO, "entity", moduleInteractableGetEntity, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_INTERACTABLE_PROTO, "id", moduleInteractableGetId, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_INTERACTABLE_PROTO, "onInteract",
|
||||
moduleInteractableGetOnInteract, moduleInteractableSetOnInteract
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_INTERACTABLE_PROTO, "trigger", moduleInteractableTrigger
|
||||
);
|
||||
scriptProtoDefineToString(
|
||||
&MODULE_INTERACTABLE_PROTO, moduleInteractableToString
|
||||
);
|
||||
}
|
||||
|
||||
static void moduleInteractableDispose(void) {
|
||||
scriptProtoDispose(&MODULE_INTERACTABLE_PROTO);
|
||||
}
|
||||
@@ -6,11 +6,74 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/entity/modulecomponent.h"
|
||||
#include "camera/modulecamera.h"
|
||||
#include "interactable/moduleinteractable.h"
|
||||
#include "overworld/moduleoverworld.h"
|
||||
#include "overworldcamera/moduleoverworldcamera.h"
|
||||
#include "overworldtrigger/moduleoverworldtrigger.h"
|
||||
#include "physics/modulephysics.h"
|
||||
#include "player/moduleplayer.h"
|
||||
#include "position/moduleposition.h"
|
||||
#include "renderable/modulerenderable.h"
|
||||
#include "trigger/moduletrigger.h"
|
||||
|
||||
/* Include component modules here as they are added. */
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
static 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_INTERACTABLE:
|
||||
return scriptProtoCreateValue(&MODULE_INTERACTABLE_PROTO, comp);
|
||||
case COMPONENT_TYPE_OVERWORLD:
|
||||
return scriptProtoCreateValue(&MODULE_OVERWORLD_PROTO, comp);
|
||||
case COMPONENT_TYPE_OVERWORLD_CAMERA:
|
||||
return scriptProtoCreateValue(&MODULE_OVERWORLD_CAMERA_PROTO, comp);
|
||||
case COMPONENT_TYPE_OVERWORLD_TRIGGER:
|
||||
return scriptProtoCreateValue(&MODULE_OVERWORLD_TRIGGER_PROTO, comp);
|
||||
case COMPONENT_TYPE_PHYSICS:
|
||||
return scriptProtoCreateValue(&MODULE_PHYSICS_PROTO, comp);
|
||||
case COMPONENT_TYPE_PLAYER:
|
||||
return scriptProtoCreateValue(&MODULE_PLAYER_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();
|
||||
moduleInteractableInit();
|
||||
moduleOverworldInit();
|
||||
moduleOverworldCameraInit();
|
||||
moduleOverworldTriggerInit();
|
||||
modulePhysicsInit();
|
||||
modulePlayerInit();
|
||||
modulePositionInit();
|
||||
moduleRenderableInit();
|
||||
moduleTriggerInit();
|
||||
}
|
||||
|
||||
static void moduleComponentListDispose(void) {
|
||||
moduleTriggerDispose();
|
||||
moduleRenderableDispose();
|
||||
modulePositionDispose();
|
||||
modulePlayerDispose();
|
||||
modulePhysicsDispose();
|
||||
moduleOverworldTriggerDispose();
|
||||
moduleOverworldCameraDispose();
|
||||
moduleOverworldDispose();
|
||||
moduleInteractableDispose();
|
||||
moduleCameraDispose();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "script/module/entity/modulecomponent.h"
|
||||
#include "entity/component/overworld/entityoverworld.h"
|
||||
#include "overworld/facingdir.h"
|
||||
|
||||
static scriptproto_t MODULE_OVERWORLD_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleOverworldCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("Overworld cannot be instantiated with new");
|
||||
}
|
||||
|
||||
static inline jscomponent_t *moduleOverworldSelf(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_OVERWORLD_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldGetEntity) {
|
||||
jscomponent_t *c = moduleOverworldSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->entityId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldGetId) {
|
||||
jscomponent_t *c = moduleOverworldSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->componentId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldGetType) {
|
||||
jscomponent_t *c = moduleOverworldSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityoverworld_t *o = entityOverworldGet(c->entityId, c->componentId);
|
||||
if(!o) return jerry_undefined();
|
||||
return jerry_number((double)o->type);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldSetType) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleOverworldSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityOverworldSetType(
|
||||
c->entityId, c->componentId,
|
||||
(entityoverworldtype_t)moduleBaseArgInt(0)
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldGetFacing) {
|
||||
jscomponent_t *c = moduleOverworldSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityoverworld_t *o = entityOverworldGet(c->entityId, c->componentId);
|
||||
if(!o) return jerry_undefined();
|
||||
return jerry_number((double)o->facing);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldSetFacing) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleOverworldSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityoverworld_t *o = entityOverworldGet(c->entityId, c->componentId);
|
||||
if(!o) return jerry_undefined();
|
||||
o->facing = (facingdir_t)moduleBaseArgInt(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldGetRenderCompId) {
|
||||
jscomponent_t *c = moduleOverworldSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityoverworld_t *o = entityOverworldGet(c->entityId, c->componentId);
|
||||
if(!o) return jerry_undefined();
|
||||
return jerry_number((double)o->renderCompId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldGetPhysCompId) {
|
||||
jscomponent_t *c = moduleOverworldSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityoverworld_t *o = entityOverworldGet(c->entityId, c->componentId);
|
||||
if(!o) return jerry_undefined();
|
||||
return jerry_number((double)o->physCompId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldToString) {
|
||||
jscomponent_t *c = moduleOverworldSelf(callInfo);
|
||||
if(!c) return jerry_string_sz("Overworld:invalid");
|
||||
char_t buf[32];
|
||||
snprintf(buf, sizeof(buf), "Overworld(%u)", (unsigned)c->componentId);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
static void moduleOverworldInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_OVERWORLD_PROTO, "Overworld",
|
||||
sizeof(jscomponent_t), moduleOverworldCtor
|
||||
);
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_OVERWORLD_PROTO, "entity", moduleOverworldGetEntity, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_OVERWORLD_PROTO, "id", moduleOverworldGetId, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_OVERWORLD_PROTO, "type",
|
||||
moduleOverworldGetType, moduleOverworldSetType
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_OVERWORLD_PROTO, "facing",
|
||||
moduleOverworldGetFacing, moduleOverworldSetFacing
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_OVERWORLD_PROTO, "renderComponentId",
|
||||
moduleOverworldGetRenderCompId, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_OVERWORLD_PROTO, "physicsComponentId",
|
||||
moduleOverworldGetPhysCompId, NULL
|
||||
);
|
||||
scriptProtoDefineToString(&MODULE_OVERWORLD_PROTO, moduleOverworldToString);
|
||||
|
||||
jerry_value_t ctor = MODULE_OVERWORLD_PROTO.constructor;
|
||||
|
||||
struct { const char_t *name; int val; } types[] = {
|
||||
{ "PLAYER", OVERWORLD_ENTITY_TYPE_PLAYER },
|
||||
{ "NPC", OVERWORLD_ENTITY_TYPE_NPC },
|
||||
};
|
||||
for(int i = 0; i < 2; 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);
|
||||
}
|
||||
|
||||
struct { const char_t *name; int val; } dirs[] = {
|
||||
{ "FACING_DOWN", FACING_DIR_DOWN },
|
||||
{ "FACING_UP", FACING_DIR_UP },
|
||||
{ "FACING_LEFT", FACING_DIR_LEFT },
|
||||
{ "FACING_RIGHT", FACING_DIR_RIGHT },
|
||||
{ "FACING_SOUTH", FACING_DIR_SOUTH },
|
||||
{ "FACING_NORTH", FACING_DIR_NORTH },
|
||||
{ "FACING_WEST", FACING_DIR_WEST },
|
||||
{ "FACING_EAST", FACING_DIR_EAST },
|
||||
};
|
||||
for(int i = 0; i < 8; i++) {
|
||||
jerry_value_t k = jerry_string_sz(dirs[i].name);
|
||||
jerry_value_t v = jerry_number((double)dirs[i].val);
|
||||
jerry_object_set(ctor, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
}
|
||||
|
||||
static void moduleOverworldDispose(void) {
|
||||
scriptProtoDispose(&MODULE_OVERWORLD_PROTO);
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "script/module/math/modulevec3.h"
|
||||
#include "script/module/entity/modulecomponent.h"
|
||||
#include "entity/component/overworld/entityoverworldcamera.h"
|
||||
|
||||
static scriptproto_t MODULE_OVERWORLD_CAMERA_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleOverworldCameraCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("OverworldCamera cannot be instantiated with new");
|
||||
}
|
||||
|
||||
static inline jscomponent_t *moduleOverworldCameraSelf(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_OVERWORLD_CAMERA_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldCameraGetEntity) {
|
||||
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->entityId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldCameraGetId) {
|
||||
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->componentId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldCameraGetTargetEntity) {
|
||||
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityoverworldcamera_t *cam = entityOverworldCameraGet(c->entityId, c->componentId);
|
||||
if(!cam) return jerry_undefined();
|
||||
return jerry_number((double)cam->targetEntityId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldCameraSetTargetEntity) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityoverworldcamera_t *cam = entityOverworldCameraGet(c->entityId, c->componentId);
|
||||
if(!cam) return jerry_undefined();
|
||||
cam->targetEntityId = (entityid_t)moduleBaseArgInt(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldCameraGetTargetPosComp) {
|
||||
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityoverworldcamera_t *cam = entityOverworldCameraGet(c->entityId, c->componentId);
|
||||
if(!cam) return jerry_undefined();
|
||||
return jerry_number((double)cam->targetPosCompId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldCameraSetTargetPosComp) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityoverworldcamera_t *cam = entityOverworldCameraGet(c->entityId, c->componentId);
|
||||
if(!cam) return jerry_undefined();
|
||||
cam->targetPosCompId = (componentid_t)moduleBaseArgInt(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldCameraGetTargetOffset) {
|
||||
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityoverworldcamera_t *cam = entityOverworldCameraGet(c->entityId, c->componentId);
|
||||
if(!cam) return jerry_undefined();
|
||||
return moduleVec3Push(cam->targetOffset);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldCameraSetTargetOffset) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("OverworldCamera.targetOffset: expected Vec3");
|
||||
entityoverworldcamera_t *cam = entityOverworldCameraGet(c->entityId, c->componentId);
|
||||
if(!cam) return jerry_undefined();
|
||||
glm_vec3_copy(v, cam->targetOffset);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldCameraGetEyeOffset) {
|
||||
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityoverworldcamera_t *cam = entityOverworldCameraGet(c->entityId, c->componentId);
|
||||
if(!cam) return jerry_undefined();
|
||||
return moduleVec3Push(cam->eyeOffset);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldCameraSetEyeOffset) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("OverworldCamera.eyeOffset: expected Vec3");
|
||||
entityoverworldcamera_t *cam = entityOverworldCameraGet(c->entityId, c->componentId);
|
||||
if(!cam) return jerry_undefined();
|
||||
glm_vec3_copy(v, cam->eyeOffset);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldCameraGetScale) {
|
||||
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityoverworldcamera_t *cam = entityOverworldCameraGet(c->entityId, c->componentId);
|
||||
if(!cam) return jerry_undefined();
|
||||
return jerry_number((double)cam->scale);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldCameraSetScale) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityoverworldcamera_t *cam = entityOverworldCameraGet(c->entityId, c->componentId);
|
||||
if(!cam) return jerry_undefined();
|
||||
cam->scale = moduleBaseArgFloat(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldCameraSetTarget) {
|
||||
moduleBaseRequireArgs(2);
|
||||
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityOverworldCameraSetTarget(
|
||||
c->entityId, c->componentId,
|
||||
(entityid_t)moduleBaseArgInt(0),
|
||||
(componentid_t)moduleBaseArgInt(1)
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldCameraToString) {
|
||||
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
|
||||
if(!c) return jerry_string_sz("OverworldCamera:invalid");
|
||||
char_t buf[32];
|
||||
snprintf(buf, sizeof(buf), "OverworldCamera(%u)", (unsigned)c->componentId);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
static void moduleOverworldCameraInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_OVERWORLD_CAMERA_PROTO, "OverworldCamera",
|
||||
sizeof(jscomponent_t), moduleOverworldCameraCtor
|
||||
);
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_OVERWORLD_CAMERA_PROTO, "entity",
|
||||
moduleOverworldCameraGetEntity, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_OVERWORLD_CAMERA_PROTO, "id",
|
||||
moduleOverworldCameraGetId, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_OVERWORLD_CAMERA_PROTO, "targetEntity",
|
||||
moduleOverworldCameraGetTargetEntity, moduleOverworldCameraSetTargetEntity
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_OVERWORLD_CAMERA_PROTO, "targetPositionComponent",
|
||||
moduleOverworldCameraGetTargetPosComp, moduleOverworldCameraSetTargetPosComp
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_OVERWORLD_CAMERA_PROTO, "targetOffset",
|
||||
moduleOverworldCameraGetTargetOffset, moduleOverworldCameraSetTargetOffset
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_OVERWORLD_CAMERA_PROTO, "eyeOffset",
|
||||
moduleOverworldCameraGetEyeOffset, moduleOverworldCameraSetEyeOffset
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_OVERWORLD_CAMERA_PROTO, "scale",
|
||||
moduleOverworldCameraGetScale, moduleOverworldCameraSetScale
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_OVERWORLD_CAMERA_PROTO, "setTarget",
|
||||
moduleOverworldCameraSetTarget
|
||||
);
|
||||
scriptProtoDefineToString(
|
||||
&MODULE_OVERWORLD_CAMERA_PROTO, moduleOverworldCameraToString
|
||||
);
|
||||
}
|
||||
|
||||
static void moduleOverworldCameraDispose(void) {
|
||||
scriptProtoDispose(&MODULE_OVERWORLD_CAMERA_PROTO);
|
||||
}
|
||||
@@ -0,0 +1,374 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "script/module/math/modulevec3.h"
|
||||
#include "script/module/entity/modulecomponent.h"
|
||||
#include "entity/component/overworld/entityoverworldtrigger.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
static scriptproto_t MODULE_OVERWORLD_TRIGGER_PROTO;
|
||||
|
||||
/**
|
||||
* Heap-allocated struct stored in entityoverworldtrigger_t.user.
|
||||
* Holds jerry_value_t copies of the four JS callback functions.
|
||||
*/
|
||||
typedef struct {
|
||||
jerry_value_t onEnter;
|
||||
jerry_value_t onExit;
|
||||
jerry_value_t onStay;
|
||||
jerry_value_t onOutside;
|
||||
} jsoverworldtriggercbs_t;
|
||||
|
||||
moduleBaseFunction(moduleOverworldTriggerCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("OverworldTrigger cannot be instantiated with new");
|
||||
}
|
||||
|
||||
static inline jscomponent_t *moduleOverworldTriggerSelf(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_OVERWORLD_TRIGGER_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
/** Lazily allocates the callback struct and stores it in the trigger's user. */
|
||||
static jsoverworldtriggercbs_t *moduleOverworldTriggerGetCbs(
|
||||
entityoverworldtrigger_t *t
|
||||
) {
|
||||
if(t->user) return (jsoverworldtriggercbs_t *)t->user;
|
||||
jsoverworldtriggercbs_t *cbs = (jsoverworldtriggercbs_t *)malloc(
|
||||
sizeof(jsoverworldtriggercbs_t)
|
||||
);
|
||||
cbs->onEnter = jerry_undefined();
|
||||
cbs->onExit = jerry_undefined();
|
||||
cbs->onStay = jerry_undefined();
|
||||
cbs->onOutside = jerry_undefined();
|
||||
t->user = (void *)cbs;
|
||||
return cbs;
|
||||
}
|
||||
|
||||
static void moduleOverworldTriggerOnEnterCb(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
void *user
|
||||
) {
|
||||
(void)entityId; (void)componentId;
|
||||
jsoverworldtriggercbs_t *cbs = (jsoverworldtriggercbs_t *)user;
|
||||
if(!jerry_value_is_function(cbs->onEnter)) return;
|
||||
jerry_value_t ret = jerry_call(cbs->onEnter, jerry_undefined(), NULL, 0);
|
||||
jerry_value_free(ret);
|
||||
}
|
||||
|
||||
static void moduleOverworldTriggerOnExitCb(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
void *user
|
||||
) {
|
||||
(void)entityId; (void)componentId;
|
||||
jsoverworldtriggercbs_t *cbs = (jsoverworldtriggercbs_t *)user;
|
||||
if(!jerry_value_is_function(cbs->onExit)) return;
|
||||
jerry_value_t ret = jerry_call(cbs->onExit, jerry_undefined(), NULL, 0);
|
||||
jerry_value_free(ret);
|
||||
}
|
||||
|
||||
static void moduleOverworldTriggerOnStayCb(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
void *user
|
||||
) {
|
||||
(void)entityId; (void)componentId;
|
||||
jsoverworldtriggercbs_t *cbs = (jsoverworldtriggercbs_t *)user;
|
||||
if(!jerry_value_is_function(cbs->onStay)) return;
|
||||
jerry_value_t ret = jerry_call(cbs->onStay, jerry_undefined(), NULL, 0);
|
||||
jerry_value_free(ret);
|
||||
}
|
||||
|
||||
static void moduleOverworldTriggerOnOutsideCb(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
void *user
|
||||
) {
|
||||
(void)entityId; (void)componentId;
|
||||
jsoverworldtriggercbs_t *cbs = (jsoverworldtriggercbs_t *)user;
|
||||
if(!jerry_value_is_function(cbs->onOutside)) return;
|
||||
jerry_value_t ret = jerry_call(cbs->onOutside, jerry_undefined(), NULL, 0);
|
||||
jerry_value_free(ret);
|
||||
}
|
||||
|
||||
// ---- entity / id ----
|
||||
|
||||
moduleBaseFunction(moduleOverworldTriggerGetEntity) {
|
||||
jscomponent_t *c = moduleOverworldTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->entityId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldTriggerGetId) {
|
||||
jscomponent_t *c = moduleOverworldTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->componentId);
|
||||
}
|
||||
|
||||
// ---- min / max ----
|
||||
|
||||
moduleBaseFunction(moduleOverworldTriggerGetMin) {
|
||||
jscomponent_t *c = moduleOverworldTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityoverworldtrigger_t *t = entityOverworldTriggerGet(c->entityId, c->componentId);
|
||||
if(!t) return jerry_undefined();
|
||||
return moduleVec3Push(t->min);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldTriggerSetMin) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleOverworldTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("OverworldTrigger.min: expected Vec3");
|
||||
entityoverworldtrigger_t *t = entityOverworldTriggerGet(c->entityId, c->componentId);
|
||||
if(!t) return jerry_undefined();
|
||||
glm_vec3_copy(v, t->min);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldTriggerGetMax) {
|
||||
jscomponent_t *c = moduleOverworldTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityoverworldtrigger_t *t = entityOverworldTriggerGet(c->entityId, c->componentId);
|
||||
if(!t) return jerry_undefined();
|
||||
return moduleVec3Push(t->max);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldTriggerSetMax) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleOverworldTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("OverworldTrigger.max: expected Vec3");
|
||||
entityoverworldtrigger_t *t = entityOverworldTriggerGet(c->entityId, c->componentId);
|
||||
if(!t) return jerry_undefined();
|
||||
glm_vec3_copy(v, t->max);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
// ---- playerInside ----
|
||||
|
||||
moduleBaseFunction(moduleOverworldTriggerGetPlayerInside) {
|
||||
jscomponent_t *c = moduleOverworldTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityoverworldtrigger_t *t = entityOverworldTriggerGet(c->entityId, c->componentId);
|
||||
if(!t) return jerry_undefined();
|
||||
return jerry_boolean(t->playerInside);
|
||||
}
|
||||
|
||||
// ---- setBounds ----
|
||||
|
||||
moduleBaseFunction(moduleOverworldTriggerSetBounds) {
|
||||
moduleBaseRequireArgs(2);
|
||||
jscomponent_t *c = moduleOverworldTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *minV = moduleVec3From(args[0]);
|
||||
float_t *maxV = moduleVec3From(args[1]);
|
||||
if(!minV) return moduleBaseThrow("OverworldTrigger.setBounds: expected Vec3 for min");
|
||||
if(!maxV) return moduleBaseThrow("OverworldTrigger.setBounds: expected Vec3 for max");
|
||||
entityOverworldTriggerSetBounds(c->entityId, c->componentId, minV, maxV);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
// ---- callback helpers ----
|
||||
|
||||
/*
|
||||
* Pins the JS function on this._onXxx for GC safety, stores a copied
|
||||
* jerry_value_t reference in the cbs struct for the C trampoline, and
|
||||
* wires up the C callback pointer. Passing null/undefined clears it.
|
||||
*/
|
||||
static void moduleOverworldTriggerSetCb(
|
||||
const jerry_call_info_t *callInfo,
|
||||
const jerry_value_t *newArgs,
|
||||
const jerry_length_t newArgc,
|
||||
jerry_value_t *slot,
|
||||
entityoverworldtriggercallback_t *cslot,
|
||||
entityoverworldtriggercallback_t trampolineFn,
|
||||
const char_t *pinKey
|
||||
) {
|
||||
jerry_value_free(*slot);
|
||||
jerry_value_t pin = (newArgc > 0) ? newArgs[0] : jerry_undefined();
|
||||
jerry_value_t keyVal = jerry_string_sz(pinKey);
|
||||
if(jerry_value_is_function(pin)) {
|
||||
*slot = jerry_value_copy(pin);
|
||||
*cslot = trampolineFn;
|
||||
jerry_object_set(callInfo->this_value, keyVal, pin);
|
||||
} else {
|
||||
*slot = jerry_undefined();
|
||||
*cslot = NULL;
|
||||
jerry_value_t undef = jerry_undefined();
|
||||
jerry_object_set(callInfo->this_value, keyVal, undef);
|
||||
jerry_value_free(undef);
|
||||
}
|
||||
jerry_value_free(keyVal);
|
||||
}
|
||||
|
||||
static jerry_value_t moduleOverworldTriggerGetPinnedCb(
|
||||
const jerry_call_info_t *callInfo,
|
||||
const char_t *pinKey
|
||||
) {
|
||||
jerry_value_t key = jerry_string_sz(pinKey);
|
||||
jerry_value_t val = jerry_object_get(callInfo->this_value, key);
|
||||
jerry_value_free(key);
|
||||
return val;
|
||||
}
|
||||
|
||||
// ---- onEnter ----
|
||||
|
||||
moduleBaseFunction(moduleOverworldTriggerGetOnEnter) {
|
||||
(void)args; (void)argc;
|
||||
return moduleOverworldTriggerGetPinnedCb(callInfo, "_onEnter");
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldTriggerSetOnEnter) {
|
||||
jscomponent_t *c = moduleOverworldTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityoverworldtrigger_t *t = entityOverworldTriggerGet(c->entityId, c->componentId);
|
||||
if(!t) return jerry_undefined();
|
||||
jsoverworldtriggercbs_t *cbs = moduleOverworldTriggerGetCbs(t);
|
||||
moduleOverworldTriggerSetCb(
|
||||
callInfo, args, argc,
|
||||
&cbs->onEnter, &t->onEnter,
|
||||
moduleOverworldTriggerOnEnterCb, "_onEnter"
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
// ---- onExit ----
|
||||
|
||||
moduleBaseFunction(moduleOverworldTriggerGetOnExit) {
|
||||
(void)args; (void)argc;
|
||||
return moduleOverworldTriggerGetPinnedCb(callInfo, "_onExit");
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldTriggerSetOnExit) {
|
||||
jscomponent_t *c = moduleOverworldTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityoverworldtrigger_t *t = entityOverworldTriggerGet(c->entityId, c->componentId);
|
||||
if(!t) return jerry_undefined();
|
||||
jsoverworldtriggercbs_t *cbs = moduleOverworldTriggerGetCbs(t);
|
||||
moduleOverworldTriggerSetCb(
|
||||
callInfo, args, argc,
|
||||
&cbs->onExit, &t->onExit,
|
||||
moduleOverworldTriggerOnExitCb, "_onExit"
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
// ---- onStay ----
|
||||
|
||||
moduleBaseFunction(moduleOverworldTriggerGetOnStay) {
|
||||
(void)args; (void)argc;
|
||||
return moduleOverworldTriggerGetPinnedCb(callInfo, "_onStay");
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldTriggerSetOnStay) {
|
||||
jscomponent_t *c = moduleOverworldTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityoverworldtrigger_t *t = entityOverworldTriggerGet(c->entityId, c->componentId);
|
||||
if(!t) return jerry_undefined();
|
||||
jsoverworldtriggercbs_t *cbs = moduleOverworldTriggerGetCbs(t);
|
||||
moduleOverworldTriggerSetCb(
|
||||
callInfo, args, argc,
|
||||
&cbs->onStay, &t->onStay,
|
||||
moduleOverworldTriggerOnStayCb, "_onStay"
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
// ---- onOutside ----
|
||||
|
||||
moduleBaseFunction(moduleOverworldTriggerGetOnOutside) {
|
||||
(void)args; (void)argc;
|
||||
return moduleOverworldTriggerGetPinnedCb(callInfo, "_onOutside");
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldTriggerSetOnOutside) {
|
||||
jscomponent_t *c = moduleOverworldTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityoverworldtrigger_t *t = entityOverworldTriggerGet(c->entityId, c->componentId);
|
||||
if(!t) return jerry_undefined();
|
||||
jsoverworldtriggercbs_t *cbs = moduleOverworldTriggerGetCbs(t);
|
||||
moduleOverworldTriggerSetCb(
|
||||
callInfo, args, argc,
|
||||
&cbs->onOutside, &t->onOutside,
|
||||
moduleOverworldTriggerOnOutsideCb, "_onOutside"
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleOverworldTriggerToString) {
|
||||
jscomponent_t *c = moduleOverworldTriggerSelf(callInfo);
|
||||
if(!c) return jerry_string_sz("OverworldTrigger:invalid");
|
||||
char_t buf[32];
|
||||
snprintf(buf, sizeof(buf), "OverworldTrigger(%u)", (unsigned)c->componentId);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
static void moduleOverworldTriggerInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_OVERWORLD_TRIGGER_PROTO, "OverworldTrigger",
|
||||
sizeof(jscomponent_t), moduleOverworldTriggerCtor
|
||||
);
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_OVERWORLD_TRIGGER_PROTO, "entity",
|
||||
moduleOverworldTriggerGetEntity, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_OVERWORLD_TRIGGER_PROTO, "id",
|
||||
moduleOverworldTriggerGetId, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_OVERWORLD_TRIGGER_PROTO, "min",
|
||||
moduleOverworldTriggerGetMin, moduleOverworldTriggerSetMin
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_OVERWORLD_TRIGGER_PROTO, "max",
|
||||
moduleOverworldTriggerGetMax, moduleOverworldTriggerSetMax
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_OVERWORLD_TRIGGER_PROTO, "playerInside",
|
||||
moduleOverworldTriggerGetPlayerInside, NULL
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_OVERWORLD_TRIGGER_PROTO, "setBounds",
|
||||
moduleOverworldTriggerSetBounds
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_OVERWORLD_TRIGGER_PROTO, "onEnter",
|
||||
moduleOverworldTriggerGetOnEnter, moduleOverworldTriggerSetOnEnter
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_OVERWORLD_TRIGGER_PROTO, "onExit",
|
||||
moduleOverworldTriggerGetOnExit, moduleOverworldTriggerSetOnExit
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_OVERWORLD_TRIGGER_PROTO, "onStay",
|
||||
moduleOverworldTriggerGetOnStay, moduleOverworldTriggerSetOnStay
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_OVERWORLD_TRIGGER_PROTO, "onOutside",
|
||||
moduleOverworldTriggerGetOnOutside, moduleOverworldTriggerSetOnOutside
|
||||
);
|
||||
scriptProtoDefineToString(
|
||||
&MODULE_OVERWORLD_TRIGGER_PROTO, moduleOverworldTriggerToString
|
||||
);
|
||||
}
|
||||
|
||||
static void moduleOverworldTriggerDispose(void) {
|
||||
scriptProtoDispose(&MODULE_OVERWORLD_TRIGGER_PROTO);
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "script/module/math/modulevec3.h"
|
||||
#include "script/module/entity/modulecomponent.h"
|
||||
#include "entity/component/physics/entityphysics.h"
|
||||
|
||||
static scriptproto_t MODULE_PHYSICS_PROTO;
|
||||
|
||||
moduleBaseFunction(modulePhysicsCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("Physics cannot be instantiated with new");
|
||||
}
|
||||
|
||||
static inline jscomponent_t *modulePhysicsSelf(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_PHYSICS_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "script/module/entity/modulecomponent.h"
|
||||
#include "entity/component/overworld/entityplayer.h"
|
||||
|
||||
static scriptproto_t MODULE_PLAYER_PROTO;
|
||||
|
||||
moduleBaseFunction(modulePlayerCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("Player cannot be instantiated with new");
|
||||
}
|
||||
|
||||
static inline jscomponent_t *modulePlayerSelf(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_PLAYER_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePlayerGetEntity) {
|
||||
jscomponent_t *c = modulePlayerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->entityId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePlayerGetId) {
|
||||
jscomponent_t *c = modulePlayerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->componentId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePlayerGetSpeed) {
|
||||
jscomponent_t *c = modulePlayerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityplayer_t *p = entityPlayerGet(c->entityId, c->componentId);
|
||||
if(!p) return jerry_undefined();
|
||||
return jerry_number((double)p->speed);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePlayerSetSpeed) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePlayerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityplayer_t *p = entityPlayerGet(c->entityId, c->componentId);
|
||||
if(!p) return jerry_undefined();
|
||||
p->speed = moduleBaseArgFloat(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePlayerGetRunSpeed) {
|
||||
jscomponent_t *c = modulePlayerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityplayer_t *p = entityPlayerGet(c->entityId, c->componentId);
|
||||
if(!p) return jerry_undefined();
|
||||
return jerry_number((double)p->runSpeed);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePlayerSetRunSpeed) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePlayerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityplayer_t *p = entityPlayerGet(c->entityId, c->componentId);
|
||||
if(!p) return jerry_undefined();
|
||||
p->runSpeed = moduleBaseArgFloat(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePlayerToString) {
|
||||
jscomponent_t *c = modulePlayerSelf(callInfo);
|
||||
if(!c) return jerry_string_sz("Player:invalid");
|
||||
char_t buf[32];
|
||||
snprintf(buf, sizeof(buf), "Player(%u)", (unsigned)c->componentId);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
static void modulePlayerInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_PLAYER_PROTO, "Player",
|
||||
sizeof(jscomponent_t), modulePlayerCtor
|
||||
);
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_PLAYER_PROTO, "entity", modulePlayerGetEntity, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_PLAYER_PROTO, "id", modulePlayerGetId, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_PLAYER_PROTO, "speed",
|
||||
modulePlayerGetSpeed, modulePlayerSetSpeed
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_PLAYER_PROTO, "runSpeed",
|
||||
modulePlayerGetRunSpeed, modulePlayerSetRunSpeed
|
||||
);
|
||||
scriptProtoDefineToString(&MODULE_PLAYER_PROTO, modulePlayerToString);
|
||||
}
|
||||
|
||||
static void modulePlayerDispose(void) {
|
||||
scriptProtoDispose(&MODULE_PLAYER_PROTO);
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "script/module/math/modulevec3.h"
|
||||
#include "script/module/entity/modulecomponent.h"
|
||||
#include "entity/component/display/entityposition.h"
|
||||
|
||||
static scriptproto_t MODULE_POSITION_PROTO;
|
||||
|
||||
moduleBaseFunction(modulePositionCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("Position cannot be instantiated with new");
|
||||
}
|
||||
|
||||
static inline jscomponent_t *modulePositionSelf(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_POSITION_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,303 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/module/display/modulecolor.h"
|
||||
#include "script/module/display/moduletexture.h"
|
||||
#include "script/module/entity/modulecomponent.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "entity/component/display/entityrenderable.h"
|
||||
|
||||
static scriptproto_t MODULE_RENDERABLE_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleRenderableCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("Renderable cannot be instantiated with new");
|
||||
}
|
||||
|
||||
static inline jscomponent_t *moduleRenderableSelf(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_RENDERABLE_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
static inline entityrenderable_t *moduleRenderableData(const jscomponent_t *c) {
|
||||
return (entityrenderable_t *)componentGetData(
|
||||
c->entityId, c->componentId, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
}
|
||||
|
||||
/** 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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
/*
|
||||
* texture getter — returns the pinned Texture instance, or undefined if none.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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).
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* sprites setter — accepts an array of sub-arrays.
|
||||
* Each element: 10 numbers (3D) or 8 numbers (2D, z defaults to 0).
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "script/module/math/modulevec3.h"
|
||||
#include "script/module/entity/modulecomponent.h"
|
||||
#include "entity/component/trigger/entitytrigger.h"
|
||||
|
||||
static scriptproto_t MODULE_TRIGGER_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleTriggerCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("Trigger cannot be instantiated with new");
|
||||
}
|
||||
|
||||
static inline jscomponent_t *moduleTriggerSelf(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_TRIGGER_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "script/module/entity/modulecomponent.h"
|
||||
#include "script/module/entity/component/modulecomponentlist.h"
|
||||
#include "entity/entitymanager.h"
|
||||
|
||||
/** C struct wrapped by every Entity JS instance. */
|
||||
@@ -59,7 +60,7 @@ moduleBaseFunction(moduleEntityAdd) {
|
||||
}
|
||||
|
||||
jscomponent_t comp = { .entityId = ent->id, .componentId = cid };
|
||||
return scriptProtoCreateValue(&MODULE_COMPONENT_PROTO, &comp);
|
||||
return moduleComponentListCreateInstance(type, &comp);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleEntityToString) {
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/asset/moduleasset.h"
|
||||
#include "script/module/console/moduleconsole.h"
|
||||
#include "script/module/display/modulecolor.h"
|
||||
#include "script/module/display/modulescreen.h"
|
||||
#include "script/module/engine/moduleengine.h"
|
||||
#include "script/module/entity/component/modulecomponentlist.h"
|
||||
@@ -18,6 +20,9 @@
|
||||
#include "script/module/system/modulesystem.h"
|
||||
|
||||
static void moduleListInit(void) {
|
||||
moduleTextureInit();
|
||||
moduleColorInit();
|
||||
moduleAssetInit();
|
||||
moduleConsoleInit();
|
||||
moduleScreenInit();
|
||||
moduleEngineInit();
|
||||
@@ -41,4 +46,7 @@ static void moduleListDispose(void) {
|
||||
moduleEngineDispose();
|
||||
moduleScreenDispose();
|
||||
moduleConsoleDispose();
|
||||
moduleAssetDispose();
|
||||
moduleColorDispose();
|
||||
moduleTextureDispose();
|
||||
}
|
||||
|
||||
@@ -12,8 +12,43 @@
|
||||
|
||||
static scriptproto_t MODULE_SCENE_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleSceneGetCurrent) {
|
||||
return jerry_number((double)SCENE.type);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleSceneSet) {
|
||||
moduleBaseRequireArgs(1);
|
||||
moduleBaseRequireNumber(0);
|
||||
const scenetype_t type = (scenetype_t)moduleBaseArgInt(0);
|
||||
if(type <= SCENE_TYPE_NULL || type >= SCENE_TYPE_COUNT) {
|
||||
return moduleBaseThrow("Scene.set: invalid scene type");
|
||||
}
|
||||
sceneSet(type);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
static void moduleSceneInit(void) {
|
||||
scriptProtoInit(&MODULE_SCENE_PROTO, "Scene", sizeof(uint8_t), NULL);
|
||||
|
||||
scriptProtoDefineStaticProp(
|
||||
&MODULE_SCENE_PROTO, "current", moduleSceneGetCurrent, NULL
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_SCENE_PROTO, "set", moduleSceneSet
|
||||
);
|
||||
|
||||
/* Scene.INITIAL, Scene.TEST, Scene.OVERWORLD, ... */
|
||||
jerry_value_t global = MODULE_SCENE_PROTO.prototype;
|
||||
#define X(structName, varName, varNameUpper, initFunc, updateFunc, disposeFunc) \
|
||||
do { \
|
||||
jerry_value_t _key = jerry_string_sz(#varNameUpper); \
|
||||
jerry_value_t _val = jerry_number((double)SCENE_TYPE_##varNameUpper); \
|
||||
jerry_object_set(global, _key, _val); \
|
||||
jerry_value_free(_val); \
|
||||
jerry_value_free(_key); \
|
||||
} while(0);
|
||||
#include "scene/scenelist.h"
|
||||
#undef X
|
||||
}
|
||||
|
||||
static void moduleSceneDispose(void) {
|
||||
|
||||
@@ -8,19 +8,66 @@
|
||||
#include "log/log.h"
|
||||
#include "display/display.h"
|
||||
#include <debug.h>
|
||||
#include <fat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define LOG_DEBUG_PATH "/apps/Dusk/debug.log"
|
||||
#define LOG_ERROR_PATH "/apps/Dusk/error.log"
|
||||
|
||||
static bool_t fatTried = false;
|
||||
static bool_t fatReady = false;
|
||||
|
||||
static void logInitFAT(void) {
|
||||
if(fatTried) return;
|
||||
fatTried = true;
|
||||
fatReady = fatInitDefault();
|
||||
}
|
||||
|
||||
void logDebug(const char_t *message, ...) {
|
||||
// Print to stdout
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
vfprintf(stdout, message, args);
|
||||
va_end(args);
|
||||
|
||||
// Print to stdout
|
||||
va_list copy;
|
||||
va_copy(copy, args);
|
||||
vfprintf(stdout, message, copy);
|
||||
va_end(copy);
|
||||
fflush(stdout);
|
||||
|
||||
// Print to file
|
||||
logInitFAT();
|
||||
if(fatReady) {
|
||||
FILE *file = fopen(LOG_DEBUG_PATH, "a");
|
||||
if(file) {
|
||||
va_copy(copy, args);
|
||||
vfprintf(file, message, copy);
|
||||
va_end(copy);
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void logError(const char_t *message, ...) {
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
|
||||
// Write to file before displaying on screen
|
||||
logInitFAT();
|
||||
if(fatReady) {
|
||||
FILE *file = fopen(LOG_ERROR_PATH, "a");
|
||||
if(file) {
|
||||
va_list copy;
|
||||
va_copy(copy, args);
|
||||
vfprintf(file, message, copy);
|
||||
va_end(copy);
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
|
||||
// Either create graphics, or hijack the displays' graphics.
|
||||
void *xfb = NULL;
|
||||
GXRModeObj *rmode = NULL;
|
||||
void *framebuffer;
|
||||
|
||||
@@ -54,12 +101,24 @@ void logError(const char_t *message, ...) {
|
||||
}
|
||||
|
||||
// Printf
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
vprintf(message, args);
|
||||
va_list copy;
|
||||
va_copy(copy, args);
|
||||
vprintf(message, copy);
|
||||
va_end(copy);
|
||||
va_end(args);
|
||||
|
||||
// PAD_Init is idempotent — safe to call even if inputInit already called it,
|
||||
// and handles the case where the error occurred before inputInit ran.
|
||||
PAD_Init();
|
||||
while(SYS_MainLoop()) {
|
||||
PAD_ScanPads();
|
||||
// START button matches the RAGEQUIT bind — allows exit on GC controller
|
||||
// when there is no Wiimote HOME button available.
|
||||
if(PAD_ButtonsDown(0) & PAD_BUTTON_START) break;
|
||||
VIDEO_WaitVSync();
|
||||
}
|
||||
|
||||
// Exit cleanly to HBC regardless of engine state. engineDispose() is not
|
||||
// called here because the engine may be partially initialized.
|
||||
exit(0);
|
||||
}
|
||||
@@ -267,6 +267,73 @@ static void test_update_error_slot_stays_occupied(void **state) {
|
||||
assert_int_equal(memoryGetAllocatedCount(), 0);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// assetEntryInit — input copy
|
||||
// ============================================================
|
||||
|
||||
static void test_getEntry_null_input_stays_null(void **state) {
|
||||
assetentry_t *entry = assetGetEntry("test.locale", ASSET_LOADER_TYPE_LOCALE, NULL);
|
||||
|
||||
assert_null(entry->input);
|
||||
assert_int_equal(memoryGetAllocatedCount(), 0);
|
||||
}
|
||||
|
||||
static void test_getEntry_input_copied_into_entry(void **state) {
|
||||
assetloaderinput_t input;
|
||||
memoryZero(&input, sizeof(input));
|
||||
input.texture = (textureformat_t)42;
|
||||
|
||||
assetentry_t *entry = assetGetEntry("test.texture", ASSET_LOADER_TYPE_TEXTURE, &input);
|
||||
|
||||
// input must have been copied — entry->input must point inside the entry.
|
||||
assert_non_null(entry->input);
|
||||
assert_ptr_equal(entry->input, &entry->inputData);
|
||||
assert_int_equal((int)entry->input->texture, 42);
|
||||
|
||||
assert_int_equal(memoryGetAllocatedCount(), 0);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// assetUpdate — re-entrant sync loader
|
||||
// ============================================================
|
||||
|
||||
static assetentry_t *reentrant_inner_entry = NULL;
|
||||
static bool_t reentrant_inner_loaded = false;
|
||||
|
||||
static errorret_t reentrant_stub_load(assetloading_t *loading) {
|
||||
if(reentrant_inner_entry == NULL) {
|
||||
// Simulate a script loading another asset from within its own sync step.
|
||||
reentrant_inner_entry = assetGetEntry(
|
||||
"inner.json", ASSET_LOADER_TYPE_JSON, NULL
|
||||
);
|
||||
errorret_t inner_ret = assetRequireLoaded(reentrant_inner_entry);
|
||||
reentrant_inner_loaded = errorIsOk(inner_ret);
|
||||
if(errorIsNotOk(inner_ret)) errorChain(inner_ret);
|
||||
}
|
||||
loading->entry->state = ASSET_ENTRY_STATE_LOADED;
|
||||
errorOk();
|
||||
}
|
||||
|
||||
static void test_update_reentrant_sync_loader(void **state) {
|
||||
reentrant_inner_entry = NULL;
|
||||
reentrant_inner_loaded = false;
|
||||
// LOCALE uses the re-entrant loader; JSON keeps the default stub_load_success.
|
||||
ASSET_LOADER_CALLBACKS[ASSET_LOADER_TYPE_LOCALE].loadSync = reentrant_stub_load;
|
||||
|
||||
assetentry_t *outer = assetGetEntry("outer.locale", ASSET_LOADER_TYPE_LOCALE, NULL);
|
||||
|
||||
errorret_t ret = assetRequireLoaded(outer);
|
||||
assert_true(errorIsOk(ret));
|
||||
assert_int_equal(outer->state, ASSET_ENTRY_STATE_LOADED);
|
||||
// Verify the re-entrant load ran and completed successfully.
|
||||
// (The inner entry may have been reaped by the time we check here,
|
||||
// so we capture the result inside the callback rather than reading state.)
|
||||
assert_non_null(reentrant_inner_entry);
|
||||
assert_true(reentrant_inner_loaded);
|
||||
|
||||
assert_int_equal(memoryGetAllocatedCount(), 0);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// assetGetEntry — dedup against non-NOT_STARTED entries
|
||||
// ============================================================
|
||||
@@ -377,6 +444,8 @@ int main(void) {
|
||||
cmocka_unit_test_setup_teardown(test_getEntry_dedup, asset_setup, asset_teardown),
|
||||
cmocka_unit_test_setup_teardown(test_getEntry_distinct_names, asset_setup, asset_teardown),
|
||||
cmocka_unit_test_setup_teardown(test_getEntry_returns_loaded_entry, asset_setup, asset_teardown),
|
||||
cmocka_unit_test_setup_teardown(test_getEntry_null_input_stays_null, asset_setup, asset_teardown),
|
||||
cmocka_unit_test_setup_teardown(test_getEntry_input_copied_into_entry, asset_setup, asset_teardown),
|
||||
|
||||
// assetUpdate — state machine
|
||||
cmocka_unit_test_setup_teardown(test_update_noop_on_empty_table, asset_setup, asset_teardown),
|
||||
@@ -388,6 +457,7 @@ int main(void) {
|
||||
cmocka_unit_test_setup_teardown(test_update_overflow_queues_entries, asset_setup, asset_teardown),
|
||||
cmocka_unit_test_setup_teardown(test_update_error_state, asset_setup, asset_teardown),
|
||||
cmocka_unit_test_setup_teardown(test_update_error_slot_stays_occupied, asset_setup, asset_teardown),
|
||||
cmocka_unit_test_setup_teardown(test_update_reentrant_sync_loader, asset_setup, asset_teardown),
|
||||
|
||||
// assetEntryDispose
|
||||
cmocka_unit_test_setup_teardown(test_entry_dispose_clears_entry, asset_setup, asset_teardown),
|
||||
|
||||
Vendored
+72
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/** Asset archive queries and cache management. */
|
||||
interface AssetNamespace {
|
||||
// Loader type constants
|
||||
readonly TYPE_MESH: number;
|
||||
readonly TYPE_TEXTURE: number;
|
||||
readonly TYPE_TILESET: number;
|
||||
readonly TYPE_LOCALE: number;
|
||||
readonly TYPE_JSON: number;
|
||||
readonly TYPE_SCRIPT: number;
|
||||
|
||||
// Mesh axis input constants (pass as `input` to lock with TYPE_MESH)
|
||||
readonly MESH_AXIS_Y_UP: number;
|
||||
readonly MESH_AXIS_Z_UP: number;
|
||||
readonly MESH_AXIS_X_UP: number;
|
||||
readonly MESH_AXIS_Y_DOWN: number;
|
||||
readonly MESH_AXIS_Z_DOWN: number;
|
||||
readonly MESH_AXIS_X_DOWN: number;
|
||||
|
||||
/**
|
||||
* Returns `true` if the given path exists in the asset archive (`dusk.dsk`).
|
||||
*
|
||||
* @param path - Archive-relative path, e.g. `"init.js"` or `"ui/hud.png"`.
|
||||
*/
|
||||
exists(path: string): boolean;
|
||||
|
||||
/**
|
||||
* Locks an entry in the asset cache and returns an `AssetEntry`.
|
||||
* The entry begins loading in the background. Call `entry.requireLoaded()`
|
||||
* to block until it is ready.
|
||||
*
|
||||
* The lock is released when the `AssetEntry` is GC'd or `entry.unlock()`
|
||||
* is called explicitly.
|
||||
*
|
||||
* @param path - Archive-relative path.
|
||||
* @param type - Loader type constant (`Asset.TYPE_*`).
|
||||
* @param input - Optional loader-specific input constant.
|
||||
* `TYPE_TEXTURE` → `Texture.FORMAT_*`
|
||||
* `TYPE_MESH` → `Asset.MESH_AXIS_*`
|
||||
*
|
||||
* @example
|
||||
* const entry = Asset.lock('data/map.json');
|
||||
* entry.requireLoaded();
|
||||
*/
|
||||
lock(path: string, type: number, input?: number): AssetEntry;
|
||||
|
||||
/**
|
||||
* Blocks until the given entry is fully loaded.
|
||||
* Returns the entry for chaining.
|
||||
* @throws If the load fails.
|
||||
*
|
||||
* @example
|
||||
* const entry = Asset.requireLoaded(Asset.lock('map.json', Asset.TYPE_JSON));
|
||||
*/
|
||||
requireLoaded(entry: AssetEntry): AssetEntry;
|
||||
|
||||
/**
|
||||
* Releases the lock on an asset by path.
|
||||
* Prefer calling `entry.unlock()` on the `AssetEntry` object directly.
|
||||
*
|
||||
* @param path - The path originally passed to `lock`.
|
||||
*/
|
||||
unlock(path: string): void;
|
||||
}
|
||||
|
||||
declare var Asset: AssetNamespace;
|
||||
Vendored
+54
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* A live reference to an entry in the asset cache.
|
||||
* Holds a lock that keeps the entry alive; the lock is released automatically
|
||||
* when the object is garbage collected, or immediately via `unlock()`.
|
||||
*/
|
||||
interface AssetEntry {
|
||||
/** Archive-relative path used as the cache key. */
|
||||
readonly name: string;
|
||||
/** Current loading state — compare against `AssetEntry.*` state constants. */
|
||||
readonly state: number;
|
||||
/** Loader type — one of the `AssetEntry.TYPE_*` constants. */
|
||||
readonly type: number;
|
||||
/** `true` when the entry has fully loaded (`state === AssetEntry.LOADED`). */
|
||||
readonly isLoaded: boolean;
|
||||
/**
|
||||
* Returns a `Texture` for this entry when it is a loaded texture asset.
|
||||
* The `Texture` holds its own asset lock — independent of this `AssetEntry`.
|
||||
* Returns `undefined` if the entry is not of type `Asset.TYPE_TEXTURE` or
|
||||
* is not yet loaded.
|
||||
*/
|
||||
readonly texture: Texture | undefined;
|
||||
/**
|
||||
* Blocks until the entry reaches `LOADED` (or `ERROR`).
|
||||
* Returns `this` for chaining.
|
||||
* @throws If the load fails.
|
||||
*/
|
||||
requireLoaded(): this;
|
||||
/**
|
||||
* Releases the lock immediately.
|
||||
* After this call the object is invalid — do not use it again.
|
||||
*/
|
||||
unlock(): void;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
interface AssetEntryConstructor {
|
||||
// Loading state constants
|
||||
readonly NOT_STARTED: number;
|
||||
readonly PENDING: number;
|
||||
readonly LOADING: number;
|
||||
readonly LOADED: number;
|
||||
readonly ERROR: number;
|
||||
|
||||
new(): never;
|
||||
}
|
||||
|
||||
declare var AssetEntry: AssetEntryConstructor;
|
||||
+1
-8
@@ -5,16 +5,12 @@
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* Interface for the in-game developer console.
|
||||
*/
|
||||
/** Interface for the in-game developer console. */
|
||||
interface ConsoleNamespace {
|
||||
/**
|
||||
* Prints one or more values to the in-game console, separated by tabs.
|
||||
* Each argument is coerced to a string before printing.
|
||||
*
|
||||
* @param args - Values to print.
|
||||
*
|
||||
* @example
|
||||
* Console.print("x =", player.x, "y =", player.y);
|
||||
*/
|
||||
@@ -23,9 +19,6 @@ interface ConsoleNamespace {
|
||||
/**
|
||||
* Whether the in-game console overlay is currently visible.
|
||||
* Set to `true` to show the console, `false` to hide it.
|
||||
*
|
||||
* @example
|
||||
* Console.visible = true;
|
||||
*/
|
||||
visible: boolean;
|
||||
}
|
||||
Vendored
+41
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/** An RGBA color with channels in the range 0–255. */
|
||||
declare class Color {
|
||||
/** @param r Red 0–255 (default 0) */
|
||||
/** @param g Green 0–255 (default 0) */
|
||||
/** @param b Blue 0–255 (default 0) */
|
||||
/** @param a Alpha 0–255 (default 255) */
|
||||
constructor(r?: number, g?: number, b?: number, a?: number);
|
||||
|
||||
r: number;
|
||||
g: number;
|
||||
b: number;
|
||||
a: number;
|
||||
|
||||
toString(): string;
|
||||
|
||||
// Named color constants
|
||||
static readonly WHITE: Color;
|
||||
static readonly BLACK: Color;
|
||||
static readonly RED: Color;
|
||||
static readonly GREEN: Color;
|
||||
static readonly BLUE: Color;
|
||||
static readonly YELLOW: Color;
|
||||
static readonly CYAN: Color;
|
||||
static readonly MAGENTA: Color;
|
||||
static readonly TRANSPARENT: Color;
|
||||
static readonly GRAY: Color;
|
||||
static readonly LIGHT_GRAY: Color;
|
||||
static readonly DARK_GRAY: Color;
|
||||
static readonly ORANGE: Color;
|
||||
static readonly PURPLE: Color;
|
||||
static readonly PINK: Color;
|
||||
static readonly TEAL: Color;
|
||||
static readonly CORNFLOWER_BLUE: Color;
|
||||
}
|
||||
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/** Read-only information about the current display surface. */
|
||||
interface ScreenNamespace {
|
||||
/** Current render-target width in pixels. */
|
||||
readonly width: number;
|
||||
/** Current render-target height in pixels. */
|
||||
readonly height: number;
|
||||
/** Aspect ratio: `width / height`. */
|
||||
readonly aspect: number;
|
||||
}
|
||||
|
||||
/** Current display / render-target dimensions. */
|
||||
declare var Screen: ScreenNamespace;
|
||||
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* A loaded texture asset. Holds a lock on the underlying asset entry —
|
||||
* the lock is released automatically when the object is garbage collected.
|
||||
*/
|
||||
interface Texture {
|
||||
/** Pixel width of the texture. */
|
||||
readonly width: number;
|
||||
/** Pixel height of the texture. */
|
||||
readonly height: number;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
interface TextureConstructor {
|
||||
/** RGBA 32-bit format (4 channels × 8 bits). */
|
||||
readonly FORMAT_RGBA: number;
|
||||
/** Paletted format. */
|
||||
readonly FORMAT_PALETTE: number;
|
||||
new(): never;
|
||||
}
|
||||
|
||||
declare var Texture: TextureConstructor;
|
||||
+4
-13
@@ -5,26 +5,17 @@
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* Controls over the engine main loop.
|
||||
*/
|
||||
/** Controls over the engine main loop. */
|
||||
interface EngineNamespace {
|
||||
/**
|
||||
* Whether the engine main loop is still running (read-only).
|
||||
* Whether the engine main loop is still running.
|
||||
* Becomes `false` after `Engine.exit()` is called.
|
||||
*
|
||||
* @example
|
||||
* while (Engine.running) { ... }
|
||||
*/
|
||||
readonly running: boolean;
|
||||
|
||||
/**
|
||||
* Requests an orderly shutdown of the engine.
|
||||
* Sets the internal running flag to `false`; the main loop exits at the end
|
||||
* of the current tick.
|
||||
*
|
||||
* @example
|
||||
* Engine.exit();
|
||||
* Requests an orderly shutdown. Sets `running` to `false`; the main loop
|
||||
* exits at the end of the current tick.
|
||||
*/
|
||||
exit(): void;
|
||||
}
|
||||
Vendored
+39
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base type for all components. `entity.add()` returns a subtype when the
|
||||
* component type has a dedicated module; cast with `as Position` etc. when
|
||||
* you need the specific API.
|
||||
*/
|
||||
interface Component {
|
||||
/** Entity ID this component belongs to. */
|
||||
readonly entity: number;
|
||||
/** Component slot index. */
|
||||
readonly id: number;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
interface ComponentConstructor {
|
||||
/** Sentinel for an invalid component ID. */
|
||||
readonly INVALID: number;
|
||||
|
||||
readonly POSITION: number;
|
||||
readonly CAMERA: number;
|
||||
readonly RENDERABLE: number;
|
||||
readonly PHYSICS: number;
|
||||
readonly TRIGGER: number;
|
||||
readonly OVERWORLD: number;
|
||||
readonly PLAYER: number;
|
||||
readonly INTERACTABLE: number;
|
||||
readonly OVERWORLD_CAMERA: number;
|
||||
readonly OVERWORLD_TRIGGER: number;
|
||||
|
||||
new(): never;
|
||||
}
|
||||
|
||||
declare var Component: ComponentConstructor;
|
||||
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/** Camera projection component. Only one camera is active at a time. */
|
||||
interface Camera extends Component {
|
||||
/** Field of view in radians (perspective only). */
|
||||
fov: number;
|
||||
/** Near clip plane distance. */
|
||||
nearClip: number;
|
||||
/** Far clip plane distance. */
|
||||
farClip: number;
|
||||
/** One of `Camera.PERSPECTIVE`, `Camera.PERSPECTIVE_FLIPPED`, or `Camera.ORTHOGRAPHIC`. */
|
||||
projType: number;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
interface CameraConstructor {
|
||||
readonly PERSPECTIVE: number;
|
||||
readonly PERSPECTIVE_FLIPPED: number;
|
||||
readonly ORTHOGRAPHIC: number;
|
||||
new(): never;
|
||||
}
|
||||
|
||||
declare var Camera: CameraConstructor;
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* Interactable component. Fires a callback when the player activates it.
|
||||
*
|
||||
* Assign a JS function to `onInteract` to handle the event from script.
|
||||
* Call `trigger()` to fire the callback imperatively from C or JS.
|
||||
*/
|
||||
interface Interactable extends Component {
|
||||
/** Called when the player interacts with this entity. Set to null to clear. */
|
||||
onInteract: (() => void) | null;
|
||||
/** Fires the registered callback immediately (no-op if none is set). */
|
||||
trigger(): void;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
interface InteractableConstructor {
|
||||
new(): never;
|
||||
}
|
||||
|
||||
declare var Interactable: InteractableConstructor;
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/** Overworld character component (player or NPC). */
|
||||
interface Overworld extends Component {
|
||||
/**
|
||||
* Entity type — `Overworld.PLAYER` or `Overworld.NPC`.
|
||||
*/
|
||||
type: number;
|
||||
/**
|
||||
* Facing direction — one of the `Overworld.FACING_*` constants.
|
||||
*/
|
||||
facing: number;
|
||||
/** Component ID of the linked Renderable, or INVALID if none. */
|
||||
readonly renderComponentId: number;
|
||||
/** Component ID of the linked Physics body, or INVALID if none. */
|
||||
readonly physicsComponentId: number;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
interface OverworldConstructor {
|
||||
readonly PLAYER: number;
|
||||
readonly NPC: number;
|
||||
|
||||
readonly FACING_DOWN: number;
|
||||
readonly FACING_UP: number;
|
||||
readonly FACING_LEFT: number;
|
||||
readonly FACING_RIGHT: number;
|
||||
readonly FACING_SOUTH: number;
|
||||
readonly FACING_NORTH: number;
|
||||
readonly FACING_WEST: number;
|
||||
readonly FACING_EAST: number;
|
||||
|
||||
new(): never;
|
||||
}
|
||||
|
||||
declare var Overworld: OverworldConstructor;
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* Overworld follow-camera component.
|
||||
* Smoothly tracks a target entity's Position each frame.
|
||||
*/
|
||||
interface OverworldCamera extends Component {
|
||||
/** Entity ID to follow. */
|
||||
targetEntity: number;
|
||||
/** Position component ID on the target entity. */
|
||||
targetPositionComponent: number;
|
||||
/** World-space offset added to the target's position before placing the camera. */
|
||||
targetOffset: Vec3;
|
||||
/** Eye-space offset applied on top of targetOffset. */
|
||||
eyeOffset: Vec3;
|
||||
/** Orthographic scale factor (larger = wider view). */
|
||||
scale: number;
|
||||
/**
|
||||
* Convenience setter — equivalent to assigning `targetEntity` and
|
||||
* `targetPositionComponent` individually.
|
||||
*/
|
||||
setTarget(targetEntityId: number, targetPositionComponentId: number): void;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
interface OverworldCameraConstructor {
|
||||
new(): never;
|
||||
}
|
||||
|
||||
declare var OverworldCamera: OverworldCameraConstructor;
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* Overworld AABB trigger. Fires callbacks as the player enters, stays inside,
|
||||
* exits, or remains outside the defined bounding box each frame.
|
||||
*/
|
||||
interface OverworldTrigger extends Component {
|
||||
/** Minimum corner of the trigger AABB. */
|
||||
min: Vec3;
|
||||
/** Maximum corner of the trigger AABB. */
|
||||
max: Vec3;
|
||||
/** `true` while the player is inside the trigger bounds. */
|
||||
readonly playerInside: boolean;
|
||||
|
||||
/** Fired once when the player first enters the bounds. */
|
||||
onEnter: (() => void) | null;
|
||||
/** Fired once when the player leaves the bounds. */
|
||||
onExit: (() => void) | null;
|
||||
/** Fired every frame while the player remains inside the bounds. */
|
||||
onStay: (() => void) | null;
|
||||
/** Fired every frame while the player remains outside the bounds. */
|
||||
onOutside: (() => void) | null;
|
||||
|
||||
/** Convenience setter for both corners at once. */
|
||||
setBounds(min: Vec3, max: Vec3): void;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
interface OverworldTriggerConstructor {
|
||||
new(): never;
|
||||
}
|
||||
|
||||
declare var OverworldTrigger: OverworldTriggerConstructor;
|
||||
Vendored
+39
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/** Physics body component. */
|
||||
interface Physics extends Component {
|
||||
/** Body simulation type — `Physics.STATIC`, `DYNAMIC`, or `KINEMATIC`. */
|
||||
bodyType: number;
|
||||
/**
|
||||
* Collision shape type — one of the `Physics.SHAPE_*` constants.
|
||||
* Changing the type preserves existing velocity and ground state.
|
||||
*/
|
||||
shape: number;
|
||||
/** Current linear velocity (Vec3). */
|
||||
velocity: Vec3;
|
||||
/** Gravity multiplier. 0 = no gravity, 1 = full, negative = inverted. */
|
||||
gravityScale: number;
|
||||
/** `true` if the body rested on a surface during the last simulation step. */
|
||||
readonly onGround: boolean;
|
||||
/** Applies an instantaneous velocity change. No-op on STATIC bodies. */
|
||||
applyImpulse(impulse: Vec3): void;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
interface PhysicsConstructor {
|
||||
readonly STATIC: number;
|
||||
readonly DYNAMIC: number;
|
||||
readonly KINEMATIC: number;
|
||||
readonly SHAPE_CUBE: number;
|
||||
readonly SHAPE_SPHERE: number;
|
||||
readonly SHAPE_CAPSULE: number;
|
||||
readonly SHAPE_PLANE: number;
|
||||
new(): never;
|
||||
}
|
||||
|
||||
declare var Physics: PhysicsConstructor;
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/** Player movement component. Controls walk and run speeds. */
|
||||
interface Player extends Component {
|
||||
/** Walk speed in world units per second. */
|
||||
speed: number;
|
||||
/** Run speed in world units per second. */
|
||||
runSpeed: number;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
interface PlayerConstructor {
|
||||
new(): never;
|
||||
}
|
||||
|
||||
declare var Player: PlayerConstructor;
|
||||
Vendored
+41
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/** Transform component — local/world PRS with an optional parent hierarchy. */
|
||||
interface Position extends Component {
|
||||
/**
|
||||
* Local-space position. Reading returns a Vec3 copy; assigning a Vec3
|
||||
* writes through to the C transform and marks descendants dirty.
|
||||
*/
|
||||
localPosition: Vec3;
|
||||
/** World-space position (full parent-chain applied). */
|
||||
worldPosition: Vec3;
|
||||
/** Local euler rotation in radians (XYZ order). */
|
||||
localRotation: Vec3;
|
||||
/** World euler rotation in radians. */
|
||||
worldRotation: Vec3;
|
||||
/** Local scale. */
|
||||
localScale: Vec3;
|
||||
/** World scale (extracted from parent-chain matrix). */
|
||||
worldScale: Vec3;
|
||||
/**
|
||||
* Orients the transform so it faces `target`. Uses the current local
|
||||
* position as the eye. `up` defaults to world Y-up.
|
||||
*/
|
||||
lookAt(target: Vec3, up?: Vec3): void;
|
||||
/**
|
||||
* Attaches this transform to a parent. Pass `null` / `undefined` to detach.
|
||||
*/
|
||||
setParent(parent: Position | null | undefined): void;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
interface PositionConstructor {
|
||||
new(): never;
|
||||
}
|
||||
|
||||
declare var Position: PositionConstructor;
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/** Fields shared by every renderable type. */
|
||||
interface Renderable extends Component {
|
||||
/** Current render type — one of the `Renderable.*` type constants. */
|
||||
type: number;
|
||||
/** Render priority. 0 = auto. Higher = drawn later. */
|
||||
priority: number;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renderable in `SHADER_MATERIAL` mode (default after `entity.add`).
|
||||
* Renders a mesh with the unlit shader.
|
||||
*/
|
||||
interface RenderableMaterial extends Renderable {
|
||||
/**
|
||||
* Unlit material color. Reading returns a fresh `Color` copy; assigning
|
||||
* a `Color` instance writes through to the C material.
|
||||
*
|
||||
* @example
|
||||
* r.color = Color.RED;
|
||||
* r.color = new Color(255, 128, 0);
|
||||
*/
|
||||
color: Color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renderable in `SPRITEBATCH` mode.
|
||||
*
|
||||
* Set `texture` to activate spritebatch rendering (also switches `type`
|
||||
* to `Renderable.SPRITEBATCH` automatically).
|
||||
*/
|
||||
interface RenderableSpritebatch extends Renderable {
|
||||
/**
|
||||
* The bound texture. Assigning a `Texture` switches the renderable to
|
||||
* `SPRITEBATCH` mode and pins the object against GC. Reading returns the
|
||||
* same `Texture` instance that was assigned, or `undefined` if none.
|
||||
*/
|
||||
texture: Texture | undefined;
|
||||
|
||||
/**
|
||||
* Sprite list. Reading returns a JS array of 10-element sub-arrays
|
||||
* `[x1,y1,z1, x2,y2,z2, u1,v1, u2,v2]` — one per sprite.
|
||||
*
|
||||
* Assigning an array replaces all sprites. Each element may be:
|
||||
* - 10 numbers (3D): `[x1,y1,z1, x2,y2,z2, u1,v1, u2,v2]`
|
||||
* - 8 numbers (2D, z defaults to 0): `[x1,y1, x2,y2, u1,v1, u2,v2]`
|
||||
*
|
||||
* @example
|
||||
* r.sprites = [[-0.5, 0, 0.5, 1, 0, 0, 1, 1]];
|
||||
* r.sprites = []; // clear
|
||||
*/
|
||||
sprites: number[][];
|
||||
}
|
||||
|
||||
/**
|
||||
* Renderable in `CUSTOM` mode.
|
||||
* Draw logic is provided by a C callback set via `entityRenderableSetDraw`.
|
||||
*/
|
||||
interface RenderableCustom extends Renderable {}
|
||||
|
||||
interface RenderableConstructor {
|
||||
readonly SHADER_MATERIAL: number;
|
||||
readonly SPRITEBATCH: number;
|
||||
readonly CUSTOM: number;
|
||||
new(): never;
|
||||
}
|
||||
|
||||
declare var Renderable: RenderableConstructor;
|
||||
Vendored
+25
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/** AABB trigger volume. `contains` tests whether a world point is inside. */
|
||||
interface Trigger extends Component {
|
||||
/** Minimum corner of the AABB (Vec3). */
|
||||
min: Vec3;
|
||||
/** Maximum corner of the AABB (Vec3). */
|
||||
max: Vec3;
|
||||
/** Sets both corners at once. */
|
||||
setBounds(min: Vec3, max: Vec3): void;
|
||||
/** Returns `true` if `point` is inside `[min, max]`. */
|
||||
contains(point: Vec3): boolean;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
interface TriggerConstructor {
|
||||
new(): never;
|
||||
}
|
||||
|
||||
declare var Trigger: TriggerConstructor;
|
||||
Vendored
+29
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
interface Entity {
|
||||
/**
|
||||
* Adds a component of the given type and returns it.
|
||||
* Returns a typed subclass when the component has a dedicated module
|
||||
* (`Position`, `Camera`, `Renderable`, `Trigger`, `Physics`); otherwise
|
||||
* returns the base `Component`. Cast with `as Position` etc. when needed.
|
||||
*/
|
||||
add(type: number): Component;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
interface EntityConstructor {
|
||||
/** Sentinel for an invalid entity ID. */
|
||||
readonly INVALID: number;
|
||||
/** Allocates a new entity from the fixed pool (max 64). */
|
||||
create(): Entity;
|
||||
/** Disposes the entity and all of its components. */
|
||||
dispose(entity: Entity): void;
|
||||
new(): never;
|
||||
}
|
||||
|
||||
declare var Entity: EntityConstructor;
|
||||
Vendored
+32
-5
@@ -14,8 +14,35 @@
|
||||
* { "compilerOptions": { "typeRoots": ["./types"] } }
|
||||
*/
|
||||
|
||||
/// <reference path="./console.d.ts" />
|
||||
/// <reference path="./screen.d.ts" />
|
||||
/// <reference path="./engine.d.ts" />
|
||||
/// <reference path="./input.d.ts" />
|
||||
/// <reference path="./system.d.ts" />
|
||||
// math
|
||||
/// <reference path="./math/vec3.d.ts" />
|
||||
|
||||
// display
|
||||
/// <reference path="./display/color.d.ts" />
|
||||
/// <reference path="./display/screen.d.ts" />
|
||||
/// <reference path="./display/texture.d.ts" />
|
||||
|
||||
// asset
|
||||
/// <reference path="./asset/assetentry.d.ts" />
|
||||
/// <reference path="./asset/asset.d.ts" />
|
||||
|
||||
// engine systems
|
||||
/// <reference path="./console/console.d.ts" />
|
||||
/// <reference path="./engine/engine.d.ts" />
|
||||
/// <reference path="./input/input.d.ts" />
|
||||
/// <reference path="./scene/scene.d.ts" />
|
||||
/// <reference path="./system/system.d.ts" />
|
||||
|
||||
// entity / components
|
||||
/// <reference path="./entity/component.d.ts" />
|
||||
/// <reference path="./entity/component/camera.d.ts" />
|
||||
/// <reference path="./entity/component/interactable.d.ts" />
|
||||
/// <reference path="./entity/component/overworld.d.ts" />
|
||||
/// <reference path="./entity/component/overworldcamera.d.ts" />
|
||||
/// <reference path="./entity/component/overworldtrigger.d.ts" />
|
||||
/// <reference path="./entity/component/physics.d.ts" />
|
||||
/// <reference path="./entity/component/player.d.ts" />
|
||||
/// <reference path="./entity/component/position.d.ts" />
|
||||
/// <reference path="./entity/component/renderable.d.ts" />
|
||||
/// <reference path="./entity/component/trigger.d.ts" />
|
||||
/// <reference path="./entity/entity.d.ts" />
|
||||
|
||||
Vendored
-115
@@ -1,115 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* Opaque type alias for input action identifiers.
|
||||
* Use the `INPUT_ACTION_*` constants rather than raw numbers.
|
||||
*/
|
||||
type InputAction = number;
|
||||
|
||||
/**
|
||||
* Polling-based input queries and button rebinding.
|
||||
*/
|
||||
interface InputNamespace {
|
||||
/**
|
||||
* Returns `true` while the given action is held down this frame.
|
||||
*
|
||||
* @param action - An `INPUT_ACTION_*` constant.
|
||||
*
|
||||
* @example
|
||||
* if (Input.isDown(INPUT_ACTION_UP)) { player.moveUp(); }
|
||||
*/
|
||||
isDown(action: InputAction): boolean;
|
||||
|
||||
/**
|
||||
* Returns `true` if the given action was held down in the previous frame.
|
||||
*
|
||||
* @param action - An `INPUT_ACTION_*` constant.
|
||||
*/
|
||||
wasDown(action: InputAction): boolean;
|
||||
|
||||
/**
|
||||
* Returns `true` on the first frame the action transitions from up → down.
|
||||
*
|
||||
* @param action - An `INPUT_ACTION_*` constant.
|
||||
*
|
||||
* @example
|
||||
* if (Input.pressed(INPUT_ACTION_ACCEPT)) { confirmSelection(); }
|
||||
*/
|
||||
pressed(action: InputAction): boolean;
|
||||
|
||||
/**
|
||||
* Returns `true` on the first frame the action transitions from down → up.
|
||||
*
|
||||
* @param action - An `INPUT_ACTION_*` constant.
|
||||
*/
|
||||
released(action: InputAction): boolean;
|
||||
|
||||
/**
|
||||
* Returns the continuous (analog) value of an action in the range `0.0–1.0`.
|
||||
* Digital buttons return either `0` or `1`.
|
||||
*
|
||||
* @param action - An `INPUT_ACTION_*` constant.
|
||||
*
|
||||
* @example
|
||||
* const speed = Input.getValue(INPUT_ACTION_UP) * MAX_SPEED;
|
||||
*/
|
||||
getValue(action: InputAction): number;
|
||||
|
||||
/**
|
||||
* Returns a signed axis value in the range `-1.0–1.0`, derived from two
|
||||
* opposing actions: `getValue(pos) - getValue(neg)`.
|
||||
*
|
||||
* @param neg - Action mapped to the negative direction.
|
||||
* @param pos - Action mapped to the positive direction.
|
||||
*
|
||||
* @example
|
||||
* const moveX = Input.axis(INPUT_ACTION_LEFT, INPUT_ACTION_RIGHT);
|
||||
*/
|
||||
axis(neg: InputAction, pos: InputAction): number;
|
||||
|
||||
/**
|
||||
* Rebinds a physical button (by name) to a logical input action at runtime.
|
||||
* Throws if `buttonName` is unknown or `action` is out of range.
|
||||
*
|
||||
* @param buttonName - Platform-specific button identifier string (e.g. `"A"`, `"START"`).
|
||||
* @param action - Target `INPUT_ACTION_*` constant.
|
||||
*
|
||||
* @example
|
||||
* Input.bind("A", INPUT_ACTION_ACCEPT);
|
||||
*/
|
||||
bind(buttonName: string, action: InputAction): void;
|
||||
}
|
||||
|
||||
/** Polling-based input system. */
|
||||
declare var Input: InputNamespace;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Input action constants.
|
||||
// Injected as plain global variables by the engine at startup.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/** Move / navigate upward. */
|
||||
declare var INPUT_ACTION_UP: InputAction;
|
||||
/** Move / navigate downward. */
|
||||
declare var INPUT_ACTION_DOWN: InputAction;
|
||||
/** Move / navigate left. */
|
||||
declare var INPUT_ACTION_LEFT: InputAction;
|
||||
/** Move / navigate right. */
|
||||
declare var INPUT_ACTION_RIGHT: InputAction;
|
||||
/** Confirm / accept the current selection. */
|
||||
declare var INPUT_ACTION_ACCEPT: InputAction;
|
||||
/** Cancel / go back. */
|
||||
declare var INPUT_ACTION_CANCEL: InputAction;
|
||||
/** Emergency quit (e.g. hold-to-exit on embedded platforms). */
|
||||
declare var INPUT_ACTION_RAGEQUIT: InputAction;
|
||||
/** Toggle the developer console overlay. */
|
||||
declare var INPUT_ACTION_CONSOLE: InputAction;
|
||||
/** Pointer / cursor horizontal position (analog). */
|
||||
declare var INPUT_ACTION_POINTERX: InputAction;
|
||||
/** Pointer / cursor vertical position (analog). */
|
||||
declare var INPUT_ACTION_POINTERY: InputAction;
|
||||
Vendored
+50
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/** Opaque type alias for input action identifiers. */
|
||||
type InputAction = number;
|
||||
|
||||
/** Polling-based input queries and button rebinding. */
|
||||
interface InputNamespace {
|
||||
/** Returns `true` while the given action is held down this frame. */
|
||||
isDown(action: InputAction): boolean;
|
||||
/** Returns `true` if the given action was held down last frame. */
|
||||
wasDown(action: InputAction): boolean;
|
||||
/** Returns `true` on the first frame the action transitions up → down. */
|
||||
pressed(action: InputAction): boolean;
|
||||
/** Returns `true` on the first frame the action transitions down → up. */
|
||||
released(action: InputAction): boolean;
|
||||
/** Continuous (analog) value in `0.0–1.0`. Digital buttons return 0 or 1. */
|
||||
getValue(action: InputAction): number;
|
||||
/**
|
||||
* Signed axis value `-1.0–1.0`: `getValue(pos) - getValue(neg)`.
|
||||
* @param neg - Action mapped to the negative direction.
|
||||
* @param pos - Action mapped to the positive direction.
|
||||
*/
|
||||
axis(neg: InputAction, pos: InputAction): number;
|
||||
/**
|
||||
* Rebinds a physical button to a logical action at runtime.
|
||||
* @param buttonName - Platform-specific button name, e.g. `"A"`, `"START"`.
|
||||
* @param action - Target `INPUT_ACTION_*` constant.
|
||||
*/
|
||||
bind(buttonName: string, action: InputAction): void;
|
||||
}
|
||||
|
||||
/** Polling-based input system. */
|
||||
declare var Input: InputNamespace;
|
||||
|
||||
// Input action constants — injected as globals by the engine at startup.
|
||||
declare var INPUT_ACTION_UP: InputAction;
|
||||
declare var INPUT_ACTION_DOWN: InputAction;
|
||||
declare var INPUT_ACTION_LEFT: InputAction;
|
||||
declare var INPUT_ACTION_RIGHT: InputAction;
|
||||
declare var INPUT_ACTION_ACCEPT: InputAction;
|
||||
declare var INPUT_ACTION_CANCEL: InputAction;
|
||||
declare var INPUT_ACTION_RAGEQUIT: InputAction;
|
||||
declare var INPUT_ACTION_CONSOLE: InputAction;
|
||||
declare var INPUT_ACTION_POINTERX: InputAction;
|
||||
declare var INPUT_ACTION_POINTERY: InputAction;
|
||||
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/** A three-component float vector (x, y, z). */
|
||||
declare class Vec3 {
|
||||
constructor(x?: number, y?: number, z?: number);
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
toString(): string;
|
||||
}
|
||||
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/** Scene management — request scene transitions and query the active scene. */
|
||||
interface SceneNamespace {
|
||||
/** Type constant of the currently active scene, or 0 if none. */
|
||||
readonly current: number;
|
||||
|
||||
/**
|
||||
* Requests a scene transition. The change takes effect at the start of the
|
||||
* next safe update tick (current scene is disposed, new scene is initialized).
|
||||
*
|
||||
* @example
|
||||
* Scene.set(Scene.OVERWORLD);
|
||||
*/
|
||||
set(type: number): void;
|
||||
|
||||
readonly INITIAL: number;
|
||||
readonly TEST: number;
|
||||
readonly OVERWORLD: number;
|
||||
}
|
||||
|
||||
declare var Scene: SceneNamespace;
|
||||
Vendored
-28
@@ -1,28 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* Read-only information about the current display surface.
|
||||
*/
|
||||
interface ScreenNamespace {
|
||||
/** Current render-target width in pixels (read-only). */
|
||||
readonly width: number;
|
||||
|
||||
/** Current render-target height in pixels (read-only). */
|
||||
readonly height: number;
|
||||
|
||||
/**
|
||||
* Aspect ratio of the current render target: `width / height` (read-only).
|
||||
*
|
||||
* @example
|
||||
* if (Screen.aspect > 1) { /* landscape *\/ }
|
||||
*/
|
||||
readonly aspect: number;
|
||||
}
|
||||
|
||||
/** Current display / render-target dimensions. */
|
||||
declare var Screen: ScreenNamespace;
|
||||
+2
-13
@@ -5,12 +5,10 @@
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* Runtime platform detection and system-level information.
|
||||
*/
|
||||
/** Runtime platform detection. */
|
||||
interface SystemNamespace {
|
||||
/**
|
||||
* Numeric identifier for the platform the engine is running on (read-only).
|
||||
* Numeric identifier for the current platform.
|
||||
* Compare against the `System.PLATFORM_*` constants.
|
||||
*
|
||||
* @example
|
||||
@@ -18,19 +16,10 @@ interface SystemNamespace {
|
||||
*/
|
||||
readonly platform: number;
|
||||
|
||||
/** Linux desktop. */
|
||||
readonly PLATFORM_LINUX: number;
|
||||
|
||||
/** Knulli handheld (Linux-based). */
|
||||
readonly PLATFORM_KNULLI: number;
|
||||
|
||||
/** Sony PlayStation Portable. */
|
||||
readonly PLATFORM_PSP: number;
|
||||
|
||||
/** Nintendo GameCube. */
|
||||
readonly PLATFORM_GAMECUBE: number;
|
||||
|
||||
/** Nintendo Wii. */
|
||||
readonly PLATFORM_WII: number;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user