Add asset reaping
This commit is contained in:
@@ -96,6 +96,34 @@ errorret_t assetRequireLoaded(assetentry_t *entry) {
|
||||
errorOk();
|
||||
}
|
||||
|
||||
assetentry_t * assetLock(
|
||||
const char_t *name,
|
||||
const assetloadertype_t type,
|
||||
assetloaderinput_t *input
|
||||
) {
|
||||
assetentry_t *entry = assetGetEntry(name, type, input);
|
||||
assetEntryLock(entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
void assetUnlock(const char_t *name) {
|
||||
assertNotNull(name, "Name cannot be NULL.");
|
||||
assetentry_t *entry = ASSET.entries;
|
||||
do {
|
||||
if(entry->type != ASSET_LOADER_TYPE_NULL && stringEquals(entry->name, name)) {
|
||||
assetEntryUnlock(entry);
|
||||
return;
|
||||
}
|
||||
entry++;
|
||||
} while(entry < ASSET.entries + ASSET_ENTRY_COUNT_MAX);
|
||||
assertUnreachable("Asset entry not found for unlock.");
|
||||
}
|
||||
|
||||
void assetUnlockEntry(assetentry_t *entry) {
|
||||
assertNotNull(entry, "Entry cannot be NULL.");
|
||||
assetEntryUnlock(entry);
|
||||
}
|
||||
|
||||
errorret_t assetUpdate(void) {
|
||||
// Determine how many available loading slots we have.
|
||||
assetloading_t *availableLoading[ASSET_LOADING_COUNT_MAX];
|
||||
@@ -216,6 +244,33 @@ errorret_t assetUpdate(void) {
|
||||
continue;
|
||||
}
|
||||
} while(loading < ASSET.loading + ASSET_LOADING_COUNT_MAX);
|
||||
|
||||
|
||||
// Reap entries that have no external locks (refs.count == 1 means only the
|
||||
// system hold remains). Only safe to reap LOADED and NOT_STARTED states —
|
||||
// mid-load entries are left for the next cycle.
|
||||
entry = ASSET.entries;
|
||||
do {
|
||||
if(entry->state != ASSET_ENTRY_STATE_LOADED) {
|
||||
entry++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(entry->type == ASSET_LOADER_TYPE_NULL) {
|
||||
entry++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(entry->refs.count > 0) {
|
||||
entry++;
|
||||
continue;
|
||||
}
|
||||
|
||||
consolePrint("Reaping asset %s", entry->name);
|
||||
errorChain(assetEntryDispose(entry));
|
||||
entry++;
|
||||
} while(entry < ASSET.entries + ASSET_ENTRY_COUNT_MAX);
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
|
||||
+35
-3
@@ -56,11 +56,11 @@ errorret_t assetInit(void);
|
||||
bool_t assetFileExists(const char_t *filename);
|
||||
|
||||
/**
|
||||
* Gets, or creates, a new asset entry. You will need to lock the asset soon
|
||||
* after creating or else it will be freed up on the next update cycle.
|
||||
*
|
||||
* Gets, or creates, a new asset entry. Internal — prefer assetLock.
|
||||
*
|
||||
* @param name Filename of the asset.
|
||||
* @param type Type of the asset.
|
||||
* @param input Loader-specific parameters.
|
||||
*/
|
||||
assetentry_t * assetGetEntry(
|
||||
const char_t *name,
|
||||
@@ -68,6 +68,38 @@ assetentry_t * assetGetEntry(
|
||||
assetloaderinput_t *input
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets, creates, and locks an asset entry. The asset will begin loading on
|
||||
* the next assetUpdate. Call assetUnlock when done to allow the entry to be
|
||||
* reclaimed.
|
||||
*
|
||||
* @param name Filename of the asset.
|
||||
* @param type Type of the asset.
|
||||
* @param input Loader-specific parameters.
|
||||
* @return The locked asset entry.
|
||||
*/
|
||||
assetentry_t * assetLock(
|
||||
const char_t *name,
|
||||
const assetloadertype_t type,
|
||||
assetloaderinput_t *input
|
||||
);
|
||||
|
||||
/**
|
||||
* Releases a lock on an asset entry by name. When all locks are released the
|
||||
* entry will be reclaimed at the start of the next assetUpdate.
|
||||
*
|
||||
* @param name Filename of the asset to unlock.
|
||||
*/
|
||||
void assetUnlock(const char_t *name);
|
||||
|
||||
/**
|
||||
* Releases a lock on an asset entry by pointer. When all locks are released
|
||||
* the entry will be reclaimed at the start of the next assetUpdate.
|
||||
*
|
||||
* @param entry The asset entry to unlock.
|
||||
*/
|
||||
void assetUnlockEntry(assetentry_t *entry);
|
||||
|
||||
/**
|
||||
* Requires an asset entry to be loaded. This will block until the asset entry
|
||||
* is fully loaded.
|
||||
|
||||
@@ -20,35 +20,25 @@ errorret_t textInit(void) {
|
||||
assetloaderinput_t input = {
|
||||
.texture = TEXTURE_FORMAT_RGBA
|
||||
};
|
||||
assetentry_t *entryTexture = assetGetEntry(
|
||||
assetentry_t *entryTexture = assetLock(
|
||||
"ui/minogram.png", ASSET_LOADER_TYPE_TEXTURE, &input
|
||||
);
|
||||
assetentry_t *entryTileset = assetGetEntry(
|
||||
assetentry_t *entryTileset = assetLock(
|
||||
"ui/minogram.dtf", ASSET_LOADER_TYPE_TILESET, NULL
|
||||
// "ui/minogram.dtx", ASSET_LOADER_TYPE_TILESET, NULL
|
||||
);
|
||||
errorChain(assetRequireLoaded(entryTexture));
|
||||
errorChain(assetRequireLoaded(entryTileset));
|
||||
|
||||
FONT_DEFAULT.texture = &entryTexture->data.texture;
|
||||
FONT_DEFAULT.tileset = &entryTileset->data.tileset;
|
||||
|
||||
// assetentry_t *entryTileset = assetGetEntry(
|
||||
// "ui/minogram.dtf", ASSET_LOADER_TYPE_TILESET
|
||||
// );
|
||||
|
||||
// assetbatch_t batch;
|
||||
// assetBatchInit(&batch, NULL, NULL, NULL);
|
||||
// assetBatchTexture(&batch, "ui/minogram.png", TEXTURE_FORMAT_RGBA, &FONT_DEFAULT.texture);
|
||||
// assetBatchTileset(&batch, "ui/minogram.dtf", &FONT_DEFAULT.tileset);
|
||||
// errorChain(assetBatchLoad(&batch));
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t textDispose(void) {
|
||||
// assetCacheRelease(&ASSET.cache, "ui/minogram.png");
|
||||
// assetCacheRelease(&ASSET.cache, "ui/minogram.dtf");
|
||||
FONT_DEFAULT.texture = NULL;
|
||||
FONT_DEFAULT.tileset = NULL;
|
||||
assetUnlock("ui/minogram.png");
|
||||
assetUnlock("ui/minogram.dtf");
|
||||
errorOk();
|
||||
}
|
||||
|
||||
|
||||
@@ -20,14 +20,24 @@ errorret_t localeManagerInit() {
|
||||
errorret_t localeManagerSetLocale(const localeinfo_t *locale) {
|
||||
assertNotNull(locale, "Locale cannot be NULL");
|
||||
|
||||
if(LOCALE.entry != NULL) {
|
||||
assetEntryUnlock(LOCALE.entry);
|
||||
LOCALE.entry = NULL;
|
||||
}
|
||||
|
||||
LOCALE.locale = locale;
|
||||
LOCALE.entry = assetGetEntry(locale->file, ASSET_LOADER_TYPE_LOCALE, NULL);
|
||||
assetEntryLock(LOCALE.entry);
|
||||
errorChain(assetRequireLoaded(LOCALE.entry));
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void localeManagerDispose() {
|
||||
LOCALE.entry = NULL;
|
||||
if(LOCALE.entry != NULL) {
|
||||
assetEntryUnlock(LOCALE.entry);
|
||||
LOCALE.entry = NULL;
|
||||
}
|
||||
|
||||
LOCALE.locale = NULL;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* 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 "display/screen/screen.h"
|
||||
|
||||
static scriptproto_t MODULE_SCREEN_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleScreenGetWidth) {
|
||||
return jerry_number((double)SCREEN.width);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleScreenGetHeight) {
|
||||
return jerry_number((double)SCREEN.height);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleScreenGetAspect) {
|
||||
return jerry_number((double)SCREEN.aspect);
|
||||
}
|
||||
|
||||
static void moduleScreenInit(void) {
|
||||
scriptProtoInit(&MODULE_SCREEN_PROTO, "Screen", sizeof(uint8_t), NULL);
|
||||
|
||||
scriptProtoDefineStaticProp(
|
||||
&MODULE_SCREEN_PROTO, "width",
|
||||
moduleScreenGetWidth, NULL
|
||||
);
|
||||
scriptProtoDefineStaticProp(
|
||||
&MODULE_SCREEN_PROTO, "height",
|
||||
moduleScreenGetHeight, NULL
|
||||
);
|
||||
scriptProtoDefineStaticProp(
|
||||
&MODULE_SCREEN_PROTO, "aspect",
|
||||
moduleScreenGetAspect, NULL
|
||||
);
|
||||
}
|
||||
|
||||
static void moduleScreenDispose(void) {
|
||||
scriptProtoDispose(&MODULE_SCREEN_PROTO);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/* Include component modules here as they are added. */
|
||||
|
||||
static void moduleComponentListInit(void) {
|
||||
}
|
||||
|
||||
static void moduleComponentListDispose(void) {
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* 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 "entity/component.h"
|
||||
|
||||
/** C struct wrapped by every Component JS instance. */
|
||||
typedef struct {
|
||||
entityid_t entityId;
|
||||
componentid_t componentId;
|
||||
} jscomponent_t;
|
||||
|
||||
static scriptproto_t MODULE_COMPONENT_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleComponentCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("Component cannot be instantiated with new");
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleComponentGetEntity) {
|
||||
jscomponent_t *comp = scriptProtoGetValue(
|
||||
&MODULE_COMPONENT_PROTO, callInfo->this_value
|
||||
);
|
||||
if(!comp) return jerry_undefined();
|
||||
return jerry_number((double)comp->entityId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleComponentGetId) {
|
||||
jscomponent_t *comp = scriptProtoGetValue(
|
||||
&MODULE_COMPONENT_PROTO, callInfo->this_value
|
||||
);
|
||||
if(!comp) return jerry_undefined();
|
||||
return jerry_number((double)comp->componentId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleComponentToString) {
|
||||
jscomponent_t *comp = scriptProtoGetValue(
|
||||
&MODULE_COMPONENT_PROTO, callInfo->this_value
|
||||
);
|
||||
if(!comp) return jerry_string_sz("Component:invalid");
|
||||
jerry_value_t num = jerry_number((double)comp->componentId);
|
||||
jerry_value_t str = jerry_value_to_string(num);
|
||||
jerry_value_free(num);
|
||||
return str;
|
||||
}
|
||||
|
||||
static void moduleComponentInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_COMPONENT_PROTO, "Component",
|
||||
sizeof(jscomponent_t), moduleComponentCtor
|
||||
);
|
||||
|
||||
/* Instance properties */
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_COMPONENT_PROTO, "entity",
|
||||
moduleComponentGetEntity, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_COMPONENT_PROTO, "id",
|
||||
moduleComponentGetId, NULL
|
||||
);
|
||||
scriptProtoDefineToString(&MODULE_COMPONENT_PROTO, moduleComponentToString);
|
||||
|
||||
/* Component.POSITION, Component.CAMERA, etc. from componentlist.h */
|
||||
jerry_value_t ctor = MODULE_COMPONENT_PROTO.constructor;
|
||||
#define X(enumName, type, field, init, dispose, render) \
|
||||
do { \
|
||||
jerry_value_t _key = jerry_string_sz(#enumName); \
|
||||
jerry_value_t _val = jerry_number((double)COMPONENT_TYPE_##enumName); \
|
||||
jerry_object_set(ctor, _key, _val); \
|
||||
jerry_value_free(_val); \
|
||||
jerry_value_free(_key); \
|
||||
} while(0);
|
||||
#include "entity/componentlist.h"
|
||||
#undef X
|
||||
|
||||
/* Component.INVALID */
|
||||
jerry_value_t _key = jerry_string_sz("INVALID");
|
||||
jerry_value_t _val = jerry_number((double)COMPONENT_ID_INVALID);
|
||||
jerry_object_set(ctor, _key, _val);
|
||||
jerry_value_free(_val);
|
||||
jerry_value_free(_key);
|
||||
}
|
||||
|
||||
static void moduleComponentDispose(void) {
|
||||
scriptProtoDispose(&MODULE_COMPONENT_PROTO);
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* 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/entitymanager.h"
|
||||
|
||||
/** C struct wrapped by every Entity JS instance. */
|
||||
typedef struct {
|
||||
entityid_t id;
|
||||
} jsentity_t;
|
||||
|
||||
static scriptproto_t MODULE_ENTITY_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleEntityCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("Entity cannot be instantiated with new");
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleEntityCreate) {
|
||||
entityid_t id = entityManagerAdd();
|
||||
if(id == ENTITY_ID_INVALID) {
|
||||
return moduleBaseThrow("Entity.create: no entity slots available");
|
||||
}
|
||||
jsentity_t ent = { .id = id };
|
||||
return scriptProtoCreateValue(&MODULE_ENTITY_PROTO, &ent);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleEntityDisposeEntity) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jsentity_t *ent = scriptProtoGetValue(&MODULE_ENTITY_PROTO, args[0]);
|
||||
if(!ent) return moduleBaseThrow("Entity.dispose: expected Entity object");
|
||||
entityDispose(ent->id);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleEntityAdd) {
|
||||
jsentity_t *ent = scriptProtoGetValue(
|
||||
&MODULE_ENTITY_PROTO, callInfo->this_value
|
||||
);
|
||||
if(!ent) return moduleBaseThrow("Entity.add: invalid this");
|
||||
moduleBaseRequireArgs(1);
|
||||
moduleBaseRequireNumber(0);
|
||||
|
||||
const componenttype_t type = (componenttype_t)moduleBaseArgInt(0);
|
||||
if(type <= COMPONENT_TYPE_NULL || type >= COMPONENT_TYPE_COUNT) {
|
||||
return moduleBaseThrow("Entity.add: invalid component type");
|
||||
}
|
||||
|
||||
componentid_t cid = entityAddComponent(ent->id, type);
|
||||
if(cid == COMPONENT_ID_INVALID) {
|
||||
return moduleBaseThrow("Entity.add: failed to add component");
|
||||
}
|
||||
|
||||
jscomponent_t comp = { .entityId = ent->id, .componentId = cid };
|
||||
return scriptProtoCreateValue(&MODULE_COMPONENT_PROTO, &comp);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleEntityToString) {
|
||||
jsentity_t *ent = scriptProtoGetValue(
|
||||
&MODULE_ENTITY_PROTO, callInfo->this_value
|
||||
);
|
||||
if(!ent) return jerry_string_sz("Entity:invalid");
|
||||
jerry_value_t num = jerry_number((double)ent->id);
|
||||
jerry_value_t str = jerry_value_to_string(num);
|
||||
jerry_value_free(num);
|
||||
return str;
|
||||
}
|
||||
|
||||
static void moduleEntityInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_ENTITY_PROTO, "Entity",
|
||||
sizeof(jsentity_t), moduleEntityCtor
|
||||
);
|
||||
|
||||
/* Static methods */
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_ENTITY_PROTO, "create", moduleEntityCreate
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_ENTITY_PROTO, "dispose", moduleEntityDisposeEntity
|
||||
);
|
||||
|
||||
/* Entity.INVALID */
|
||||
jerry_value_t ctor = MODULE_ENTITY_PROTO.constructor;
|
||||
jerry_value_t _key = jerry_string_sz("INVALID");
|
||||
jerry_value_t _val = jerry_number((double)ENTITY_ID_INVALID);
|
||||
jerry_object_set(ctor, _key, _val);
|
||||
jerry_value_free(_val);
|
||||
jerry_value_free(_key);
|
||||
|
||||
/* Instance methods */
|
||||
scriptProtoDefineFunc(&MODULE_ENTITY_PROTO, "add", moduleEntityAdd);
|
||||
scriptProtoDefineToString(&MODULE_ENTITY_PROTO, moduleEntityToString);
|
||||
}
|
||||
|
||||
static void moduleEntityDispose(void) {
|
||||
scriptProtoDispose(&MODULE_ENTITY_PROTO);
|
||||
}
|
||||
@@ -13,7 +13,12 @@
|
||||
|
||||
static scriptproto_t MODULE_INPUT_PROTO;
|
||||
|
||||
/** Validates an inputaction_t argument and returns a type error if bad. */
|
||||
/**
|
||||
* Validates an inputaction_t argument and returns a type error if bad.
|
||||
*
|
||||
* @param i Argument index.
|
||||
* @param ctx Context string for error messages.
|
||||
*/
|
||||
#define moduleInputRequireAction(i, ctx) do { \
|
||||
if(!jerry_value_is_number(args[(i)])) { \
|
||||
return moduleBaseThrow(ctx ": action must be a number"); \
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* 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 "cglm/cglm.h"
|
||||
|
||||
static scriptproto_t MODULE_VEC3_PROTO;
|
||||
|
||||
/**
|
||||
* Returns the native float[3] pointer from the Vec3 instance that owns
|
||||
* the current call (this_value). Returns NULL if not a Vec3.
|
||||
*/
|
||||
static inline float_t *moduleVec3Get(const jerry_call_info_t *callInfo) {
|
||||
return (float_t *)scriptProtoGetValue(
|
||||
&MODULE_VEC3_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the native float[3] pointer from any jerry value.
|
||||
* Returns NULL if the value is not a Vec3 instance.
|
||||
*/
|
||||
static inline float_t *moduleVec3From(const jerry_value_t val) {
|
||||
return (float_t *)scriptProtoGetValue(&MODULE_VEC3_PROTO, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Vec3 JS object from a C vec3 array.
|
||||
*
|
||||
* @param v Source vec3 to copy.
|
||||
* @return A new Vec3 JS instance owning a copy of the data.
|
||||
*/
|
||||
static inline jerry_value_t moduleVec3Push(const vec3 v) {
|
||||
return scriptProtoCreateValue(&MODULE_VEC3_PROTO, v);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleVec3Constructor) {
|
||||
float_t *ptr = (float_t *)memoryAllocate(sizeof(vec3));
|
||||
ptr[0] = moduleBaseOptFloat(0, 0.0f);
|
||||
ptr[1] = moduleBaseOptFloat(1, 0.0f);
|
||||
ptr[2] = moduleBaseOptFloat(2, 0.0f);
|
||||
jerry_object_set_native_ptr(
|
||||
callInfo->this_value, &MODULE_VEC3_PROTO.info, ptr
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleVec3GetX) {
|
||||
float_t *v = moduleVec3Get(callInfo);
|
||||
if(!v) return jerry_undefined();
|
||||
return jerry_number((double)v[0]);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleVec3SetX) {
|
||||
moduleBaseRequireArgs(1);
|
||||
float_t *v = moduleVec3Get(callInfo);
|
||||
if(!v) return jerry_undefined();
|
||||
v[0] = moduleBaseArgFloat(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleVec3GetY) {
|
||||
float_t *v = moduleVec3Get(callInfo);
|
||||
if(!v) return jerry_undefined();
|
||||
return jerry_number((double)v[1]);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleVec3SetY) {
|
||||
moduleBaseRequireArgs(1);
|
||||
float_t *v = moduleVec3Get(callInfo);
|
||||
if(!v) return jerry_undefined();
|
||||
v[1] = moduleBaseArgFloat(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleVec3GetZ) {
|
||||
float_t *v = moduleVec3Get(callInfo);
|
||||
if(!v) return jerry_undefined();
|
||||
return jerry_number((double)v[2]);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleVec3SetZ) {
|
||||
moduleBaseRequireArgs(1);
|
||||
float_t *v = moduleVec3Get(callInfo);
|
||||
if(!v) return jerry_undefined();
|
||||
v[2] = moduleBaseArgFloat(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleVec3ToString) {
|
||||
float_t *v = moduleVec3Get(callInfo);
|
||||
if(!v) return jerry_string_sz("Vec3:invalid");
|
||||
char_t buf[64];
|
||||
snprintf(buf, sizeof(buf), "Vec3(%g, %g, %g)",
|
||||
(double)v[0], (double)v[1], (double)v[2]
|
||||
);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
static void moduleVec3Init(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_VEC3_PROTO, "Vec3",
|
||||
sizeof(vec3), moduleVec3Constructor
|
||||
);
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_VEC3_PROTO, "x", moduleVec3GetX, moduleVec3SetX
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_VEC3_PROTO, "y", moduleVec3GetY, moduleVec3SetY
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_VEC3_PROTO, "z", moduleVec3GetZ, moduleVec3SetZ
|
||||
);
|
||||
scriptProtoDefineToString(&MODULE_VEC3_PROTO, moduleVec3ToString);
|
||||
}
|
||||
|
||||
static void moduleVec3Dispose(void) {
|
||||
scriptProtoDispose(&MODULE_VEC3_PROTO);
|
||||
}
|
||||
@@ -7,20 +7,38 @@
|
||||
|
||||
#pragma once
|
||||
#include "script/module/console/moduleconsole.h"
|
||||
#include "script/module/display/modulescreen.h"
|
||||
#include "script/module/engine/moduleengine.h"
|
||||
#include "script/module/entity/component/modulecomponentlist.h"
|
||||
#include "script/module/entity/modulecomponent.h"
|
||||
#include "script/module/entity/moduleentity.h"
|
||||
#include "script/module/input/moduleinput.h"
|
||||
#include "script/module/math/modulevec3.h"
|
||||
#include "script/module/scene/modulescene.h"
|
||||
#include "script/module/system/modulesystem.h"
|
||||
|
||||
static void moduleListInit(void) {
|
||||
moduleConsoleInit();
|
||||
moduleScreenInit();
|
||||
moduleEngineInit();
|
||||
moduleVec3Init();
|
||||
moduleComponentInit();
|
||||
moduleEntityInit();
|
||||
moduleComponentListInit();
|
||||
moduleInputInit();
|
||||
moduleSceneInit();
|
||||
moduleSystemInit();
|
||||
}
|
||||
|
||||
static void moduleListDispose(void) {
|
||||
moduleSystemDispose();
|
||||
moduleSceneDispose();
|
||||
moduleInputDispose();
|
||||
moduleComponentListDispose();
|
||||
moduleEntityDispose();
|
||||
moduleComponentDispose();
|
||||
moduleVec3Dispose();
|
||||
moduleEngineDispose();
|
||||
moduleScreenDispose();
|
||||
moduleConsoleDispose();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* 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 "scene/scene.h"
|
||||
|
||||
static scriptproto_t MODULE_SCENE_PROTO;
|
||||
|
||||
static void moduleSceneInit(void) {
|
||||
scriptProtoInit(&MODULE_SCENE_PROTO, "Scene", sizeof(uint8_t), NULL);
|
||||
}
|
||||
|
||||
static void moduleSceneDispose(void) {
|
||||
scriptProtoDispose(&MODULE_SCENE_PROTO);
|
||||
}
|
||||
@@ -59,9 +59,11 @@ errorret_t scriptExecFile(const char_t *path) {
|
||||
assertNotNull(path, "Path cannot be NULL");
|
||||
assertTrue(SCRIPT.initialized, "Script system not initialized");
|
||||
|
||||
assetentry_t *entry = assetGetEntry(path, ASSET_LOADER_TYPE_SCRIPT, NULL);
|
||||
assetentry_t *entry = assetLock(path, ASSET_LOADER_TYPE_SCRIPT, NULL);
|
||||
assertNotNull(entry, "Failed to get asset entry for script");
|
||||
errorChain(assetRequireLoaded(entry));
|
||||
assetUnlockEntry(entry);
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -18,7 +18,7 @@ void refInit(
|
||||
) {
|
||||
assertNotNull(ref, "Ref cannot be NULL.");
|
||||
memoryZero(ref, sizeof(ref_t));
|
||||
ref->count = 1;
|
||||
ref->count = 0;
|
||||
ref->data = data;
|
||||
ref->onLock = onLock;
|
||||
ref->onUnlock = onUnlock;
|
||||
@@ -27,14 +27,14 @@ void refInit(
|
||||
|
||||
void refLock(ref_t *ref) {
|
||||
assertNotNull(ref, "Ref cannot be NULL.");
|
||||
assertTrue(ref->count > 0, "Cannot lock a ref with zero count.");
|
||||
assertTrue(ref->count >= 0, "Cannot lock a ref with negative count.");
|
||||
ref->count++;
|
||||
if(ref->onLock != NULL) ref->onLock(ref);
|
||||
}
|
||||
|
||||
bool_t refUnlock(ref_t *ref) {
|
||||
assertNotNull(ref, "Ref cannot be NULL.");
|
||||
assertTrue(ref->count > 0, "Cannot unlock a ref with zero count.");
|
||||
assertTrue(ref->count >= 0, "Cannot unlock a ref with negative count.");
|
||||
|
||||
ref->count--;
|
||||
|
||||
|
||||
Vendored
+34
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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);
|
||||
*/
|
||||
print(...args: unknown[]): void;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/** In-game developer console. */
|
||||
declare var Console: ConsoleNamespace;
|
||||
Vendored
+33
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* Controls over the engine main loop.
|
||||
*/
|
||||
interface EngineNamespace {
|
||||
/**
|
||||
* Whether the engine main loop is still running (read-only).
|
||||
* 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();
|
||||
*/
|
||||
exit(): void;
|
||||
}
|
||||
|
||||
/** Engine lifecycle controls. */
|
||||
declare var Engine: EngineNamespace;
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*
|
||||
* Root type declarations for the Dusk engine built-in JavaScript modules.
|
||||
* These globals are injected by the native JerryScript runtime — they are not
|
||||
* ES modules and cannot be imported.
|
||||
*
|
||||
* Reference this file from a jsconfig.json or tsconfig.json to get
|
||||
* IntelliSense across all game scripts:
|
||||
*
|
||||
* { "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" />
|
||||
Vendored
+115
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* 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
+28
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 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;
|
||||
Vendored
+38
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* Runtime platform detection and system-level information.
|
||||
*/
|
||||
interface SystemNamespace {
|
||||
/**
|
||||
* Numeric identifier for the platform the engine is running on (read-only).
|
||||
* Compare against the `System.PLATFORM_*` constants.
|
||||
*
|
||||
* @example
|
||||
* if (System.platform === System.PLATFORM_PSP) { useLowResAssets(); }
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/** Platform detection and system-level information. */
|
||||
declare var System: SystemNamespace;
|
||||
Reference in New Issue
Block a user