2 Commits

Author SHA1 Message Date
YourWishes 88903fee94 No need for asset batching on text.c 2026-06-01 22:36:02 -05:00
YourWishes 1e8311fc04 Add asset batch 2026-06-01 22:34:44 -05:00
17 changed files with 204 additions and 691 deletions
-8
View File
@@ -1,8 +0,0 @@
const cam = Entity.create();
const pos = cam.add(Component.POSITION);
cam.add(Component.CAMERA);
pos.localPosition = new Vec3(3, 3, 3);
pos.lookAt(new Vec3(0, 0, 0));
Console.print('Camera entity ID: ' + cam.toString());
+1
View File
@@ -7,6 +7,7 @@
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
asset.c
assetbatch.c
assetfile.c
)
+94
View File
@@ -0,0 +1,94 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "assetbatch.h"
#include "asset.h"
#include "assert/assert.h"
#include "util/memory.h"
#include <unistd.h>
void assetBatchInit(
assetbatch_t *batch,
const uint16_t count,
const assetbatchdesc_t *descs
) {
assertNotNull(batch, "Batch cannot be NULL.");
assertNotNull(descs, "Descs cannot be NULL.");
assertTrue(count > 0, "Count must be greater than 0.");
assertTrue(count <= ASSET_BATCH_COUNT_MAX, "Count exceeds ASSET_BATCH_COUNT_MAX.");
memoryZero(batch, sizeof(assetbatch_t));
batch->count = count;
for(uint16_t i = 0; i < count; i++) {
// Copy input into batch-owned storage so the descriptor need not persist.
batch->inputs[i] = descs[i].input;
batch->entries[i] = assetLock(descs[i].path, descs[i].type, &batch->inputs[i]);
}
}
void assetBatchLock(assetbatch_t *batch) {
assertNotNull(batch, "Batch cannot be NULL.");
for(uint16_t i = 0; i < batch->count; i++) {
assetEntryLock(batch->entries[i]);
}
}
void assetBatchUnlock(assetbatch_t *batch) {
assertNotNull(batch, "Batch cannot be NULL.");
for(uint16_t i = 0; i < batch->count; i++) {
assetEntryUnlock(batch->entries[i]);
}
}
bool_t assetBatchIsLoaded(const assetbatch_t *batch) {
assertNotNull(batch, "Batch cannot be NULL.");
for(uint16_t i = 0; i < batch->count; i++) {
if(batch->entries[i]->state != ASSET_ENTRY_STATE_LOADED) return false;
}
return true;
}
bool_t assetBatchHasError(const assetbatch_t *batch) {
assertNotNull(batch, "Batch cannot be NULL.");
for(uint16_t i = 0; i < batch->count; i++) {
if(batch->entries[i]->state == ASSET_ENTRY_STATE_ERROR) return true;
}
return false;
}
errorret_t assetBatchRequireLoaded(assetbatch_t *batch) {
assertNotNull(batch, "Batch cannot be NULL.");
bool_t allDone;
do {
allDone = true;
for(uint16_t i = 0; i < batch->count; i++) {
const assetentrystate_t state = batch->entries[i]->state;
if(state == ASSET_ENTRY_STATE_ERROR) {
errorThrow("Asset '%s' failed to load.", batch->entries[i]->name);
}
if(state != ASSET_ENTRY_STATE_LOADED) {
allDone = false;
}
}
if(!allDone) {
usleep(1000);
errorChain(assetUpdate());
}
} while(!allDone);
errorOk();
}
void assetBatchDispose(assetbatch_t *batch) {
assertNotNull(batch, "Batch cannot be NULL.");
for(uint16_t i = 0; i < batch->count; i++) {
assetUnlockEntry(batch->entries[i]);
}
memoryZero(batch, sizeof(assetbatch_t));
}
+82
View File
@@ -0,0 +1,82 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "asset/loader/assetentry.h"
#include "asset/loader/assetloader.h"
#define ASSET_BATCH_COUNT_MAX 64
typedef struct {
const char_t *path;
assetloadertype_t type;
assetloaderinput_t input;
} assetbatchdesc_t;
typedef struct {
assetentry_t *entries[ASSET_BATCH_COUNT_MAX];
assetloaderinput_t inputs[ASSET_BATCH_COUNT_MAX];
uint16_t count;
} assetbatch_t;
/**
* Initialises the batch from an array of descriptors. Each entry is locked
* and queued for loading immediately.
*
* @param batch Batch to initialise.
* @param descs Array of entry descriptors (need not outlive this call).
* @param count Number of descriptors (must be <= ASSET_BATCH_COUNT_MAX).
*/
void assetBatchInit(
assetbatch_t *batch,
uint16_t count,
const assetbatchdesc_t *descs
);
/**
* Acquires one additional lock on every entry in the batch.
*
* @param batch Batch to lock.
*/
void assetBatchLock(assetbatch_t *batch);
/**
* Releases one lock from every entry in the batch. When an entry's lock
* count reaches zero it will be reaped on the next assetUpdate.
*
* @param batch Batch to unlock.
*/
void assetBatchUnlock(assetbatch_t *batch);
/**
* Returns true if every entry in the batch has finished loading.
*
* @param batch Batch to query.
*/
bool_t assetBatchIsLoaded(const assetbatch_t *batch);
/**
* Returns true if any entry in the batch is in an error state.
*
* @param batch Batch to query.
*/
bool_t assetBatchHasError(const assetbatch_t *batch);
/**
* Blocks until every entry is loaded. Returns an error if any entry fails.
*
* @param batch Batch to wait on.
*/
errorret_t assetBatchRequireLoaded(assetbatch_t *batch);
/**
* Releases the batch's lock on every entry and clears the batch. After this
* call the batch struct may be reused with assetBatchInit.
*
* @param batch Batch to dispose.
*/
void assetBatchDispose(assetbatch_t *batch);
+4 -4
View File
@@ -17,9 +17,7 @@
font_t FONT_DEFAULT;
errorret_t textInit(void) {
assetloaderinput_t input = {
.texture = TEXTURE_FORMAT_RGBA
};
assetloaderinput_t input = { .texture = TEXTURE_FORMAT_RGBA };
assetentry_t *entryTexture = assetLock(
"ui/minogram.png", ASSET_LOADER_TYPE_TEXTURE, &input
);
@@ -95,7 +93,9 @@ errorret_t textDraw(
float_t posX = x;
float_t posY = y;
errorChain(shaderSetTexture(&SHADER_UNLIT, SHADER_UNLIT_TEXTURE, font->texture));
errorChain(shaderSetTexture(
&SHADER_UNLIT, SHADER_UNLIT_TEXTURE, font->texture
));
#if MESH_ENABLE_COLOR
#else
+3 -3
View File
@@ -47,18 +47,18 @@ 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();
}
+14 -14
View File
@@ -8,28 +8,28 @@
#include "initialscene.h"
#include "console/console.h"
#include "scene/scene.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"
#include "time/time.h"
#include "ui/uiloading.h"
void initialSceneInit(void) {
consolePrint("Initial scene initialized");
// Cube entity — RENDERABLE init defaults to a white unit cube at origin
entityid_t cubeId = entityManagerAdd();
SCENE.data.initial.cubeEntityId = cubeId;
entityAddComponent(cubeId, COMPONENT_TYPE_POSITION);
entityAddComponent(cubeId, COMPONENT_TYPE_RENDERABLE);
errorCatch(errorPrint(scriptExecFile("testentity.js")));
SCENE.data.initial.timer = 0.0f;
SCENE.data.initial.hiding = false;
uiLoadingShow(NULL, NULL);
}
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);
}
+4 -2
View File
@@ -7,10 +7,12 @@
#pragma once
#include "error/error.h"
#include "entity/entitybase.h"
#define INITIAL_SCENE_WAIT 2.0f
typedef struct {
entityid_t cubeEntityId;
float_t timer;
bool_t hiding;
} initialscene_t;
void initialSceneInit(void);
@@ -1,174 +0,0 @@
/**
* 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);
}
@@ -6,34 +6,11 @@
*/
#pragma once
#include "script/module/entity/modulecomponent.h"
#include "camera/modulecamera.h"
#include "position/moduleposition.h"
/**
* 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_POSITION:
return scriptProtoCreateValue(&MODULE_POSITION_PROTO, comp);
case COMPONENT_TYPE_CAMERA:
return scriptProtoCreateValue(&MODULE_CAMERA_PROTO, comp);
default:
return scriptProtoCreateValue(&MODULE_COMPONENT_PROTO, comp);
}
}
/* Include component modules here as they are added. */
static void moduleComponentListInit(void) {
modulePositionInit();
moduleCameraInit();
}
static void moduleComponentListDispose(void) {
moduleCameraDispose();
modulePositionDispose();
}
@@ -1,248 +0,0 @@
/**
* 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);
}
+1 -2
View File
@@ -9,7 +9,6 @@
#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. */
@@ -60,7 +59,7 @@ moduleBaseFunction(moduleEntityAdd) {
}
jscomponent_t comp = { .entityId = ent->id, .componentId = cid };
return moduleComponentListCreateInstance(type, &comp);
return scriptProtoCreateValue(&MODULE_COMPONENT_PROTO, &comp);
}
moduleBaseFunction(moduleEntityToString) {
@@ -12,43 +12,8 @@
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) {
-129
View File
@@ -1,129 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
// ---------------------------------------------------------------------------
// Component (generic base returned by entity.add() for untyped components)
// ---------------------------------------------------------------------------
/** Base component returned by entity.add() for component types without a specific module. */
interface Component {
/** Entity ID this component belongs to. */
readonly entity: number;
/** Component slot ID. */
readonly id: number;
toString(): string;
}
interface ComponentConstructor {
/** Sentinel value for an invalid component ID. */
readonly INVALID: number;
// Component type constants (generated from componentlist.h)
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;
// ---------------------------------------------------------------------------
// Position
// ---------------------------------------------------------------------------
/** Position/rotation/scale transform component with optional parent hierarchy. */
interface Position extends Component {
/**
* Local-space position. Assigning a Vec3 writes to the C transform and
* marks the world transform dirty. Reading returns a fresh Vec3 copy.
*/
localPosition: Vec3;
/** World-space position (accounts for all parent transforms). */
worldPosition: Vec3;
/** Local-space euler rotation in radians (XYZ). */
localRotation: Vec3;
/** World-space euler rotation in radians. */
worldRotation: Vec3;
/** Local-space scale. */
localScale: Vec3;
/** World-space scale. */
worldScale: Vec3;
/**
* Orients the transform to look at a world-space target point.
* Uses the current local position as the eye. Optionally specify an up
* vector (defaults to Y-up).
*/
lookAt(target: Vec3, up?: Vec3): void;
/**
* Sets this component's parent in the transform hierarchy.
* Pass `null` or `undefined` to detach.
*/
setParent(parent: Position | null | undefined): void;
toString(): string;
}
interface PositionConstructor {
new(): never;
}
declare var Position: PositionConstructor;
// ---------------------------------------------------------------------------
// Camera
// ---------------------------------------------------------------------------
/** Camera projection component. */
interface Camera extends Component {
/** Field of view in radians (perspective projections only). */
fov: number;
/** Near clip plane distance. */
nearClip: number;
/** Far clip plane distance. */
farClip: number;
/** Projection type — one of the Camera.PERSPECTIVE / Camera.ORTHOGRAPHIC constants. */
projType: number;
toString(): string;
}
interface CameraConstructor {
readonly PERSPECTIVE: number;
readonly PERSPECTIVE_FLIPPED: number;
readonly ORTHOGRAPHIC: number;
new(): never;
}
declare var Camera: CameraConstructor;
// ---------------------------------------------------------------------------
// Entity
// ---------------------------------------------------------------------------
interface Entity {
/** Add a component of the given type and return a typed instance. */
add(type: CameraConstructor["PERSPECTIVE"] | number): Component;
toString(): string;
}
interface EntityConstructor {
/** Sentinel value for an invalid entity ID. */
readonly INVALID: number;
/** Creates a new entity and returns it. Returns Entity.INVALID slot if the pool is full. */
create(): Entity;
/** Disposes the entity and all its components. */
dispose(entity: Entity): void;
new(): never;
}
declare var Entity: EntityConstructor;
-3
View File
@@ -19,6 +19,3 @@
/// <reference path="./engine.d.ts" />
/// <reference path="./input.d.ts" />
/// <reference path="./system.d.ts" />
/// <reference path="./vec3.d.ts" />
/// <reference path="./entity.d.ts" />
/// <reference path="./scene.d.ts" />
-30
View File
@@ -1,30 +0,0 @@
/**
* 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 {
/** The 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).
*
* @param type - A `Scene.*` scene type constant.
*
* @example
* Scene.set(Scene.OVERWORLD);
*/
set(type: number): void;
// Scene type constants (generated from scenelist.h)
readonly INITIAL: number;
readonly TEST: number;
readonly OVERWORLD: number;
}
declare var Scene: SceneNamespace;
-15
View File
@@ -1,15 +0,0 @@
/**
* 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;
}