ABout to try scene and script merger
This commit is contained in:
+3
-4
@@ -1,5 +1,3 @@
|
|||||||
Console.print('This is called from JavaScript');
|
|
||||||
|
|
||||||
const platformNames = {
|
const platformNames = {
|
||||||
[System.PLATFORM_LINUX]: 'Linux',
|
[System.PLATFORM_LINUX]: 'Linux',
|
||||||
[System.PLATFORM_KNULLI]: 'Knulli',
|
[System.PLATFORM_KNULLI]: 'Knulli',
|
||||||
@@ -8,5 +6,6 @@ const platformNames = {
|
|||||||
[System.PLATFORM_WII]: 'Wii',
|
[System.PLATFORM_WII]: 'Wii',
|
||||||
};
|
};
|
||||||
|
|
||||||
const platformName = platformNames[System.platform] || 'Unknown';
|
Console.print('Platform: ' + (platformNames[System.platform] || 'Unknown'));
|
||||||
Console.print('Platform: ' + platformName);
|
|
||||||
|
// Scene.set('testscene.js');
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
// 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);
|
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
var scene = {};
|
||||||
|
|
||||||
|
scene.batch = AssetBatch([
|
||||||
|
{ path: 'test.png', type: Asset.TYPE_TEXTURE, format: Texture.FORMAT_RGBA }
|
||||||
|
]);
|
||||||
|
|
||||||
|
var cam;
|
||||||
|
var camPos;
|
||||||
|
var testEntity;
|
||||||
|
var testPos;
|
||||||
|
var testRenderable;
|
||||||
|
var texEntry;
|
||||||
|
|
||||||
|
scene.load = function() {
|
||||||
|
return scene.batch;
|
||||||
|
};
|
||||||
|
|
||||||
|
scene.init = function() {
|
||||||
|
texEntry = scene.batch.entry(0);
|
||||||
|
|
||||||
|
// Camera at (3, 3, 3) looking at origin
|
||||||
|
cam = Entity.create();
|
||||||
|
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 with textured quad at origin
|
||||||
|
testEntity = Entity.create();
|
||||||
|
testPos = testEntity.add(Component.POSITION);
|
||||||
|
testRenderable = testEntity.add(Component.RENDERABLE);
|
||||||
|
|
||||||
|
testRenderable.texture = texEntry.texture;
|
||||||
|
testRenderable.sprites = [
|
||||||
|
[0, 0, 1, 1, 0, 1, 1, 0]
|
||||||
|
];
|
||||||
|
testPos.localPosition = new Vec3(0, 0, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
scene.dispose = function() {
|
||||||
|
Entity.dispose(cam);
|
||||||
|
Entity.dispose(testEntity);
|
||||||
|
|
||||||
|
texEntry.unlock();
|
||||||
|
scene.batch.unlock();
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = scene;
|
||||||
@@ -222,6 +222,8 @@ errorret_t assetUpdate(void) {
|
|||||||
loading->entry->state == ASSET_ENTRY_STATE_ERROR,
|
loading->entry->state == ASSET_ENTRY_STATE_ERROR,
|
||||||
"Loader did not set entry state to error on failed load."
|
"Loader did not set entry state to error on failed load."
|
||||||
);
|
);
|
||||||
|
} else if(loading->entry->state == ASSET_ENTRY_STATE_LOADED) {
|
||||||
|
eventInvoke(&loading->entry->onLoaded, loading->entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
loading++;
|
loading++;
|
||||||
@@ -241,10 +243,14 @@ errorret_t assetUpdate(void) {
|
|||||||
loading++;
|
loading++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ASSET_ENTRY_STATE_ERROR:
|
case ASSET_ENTRY_STATE_ERROR: {
|
||||||
|
assetentry_t *errEntry = loading->entry;
|
||||||
|
loading->entry = NULL;
|
||||||
threadMutexUnlock(&loading->mutex);
|
threadMutexUnlock(&loading->mutex);
|
||||||
|
eventInvoke(&errEntry->onError, errEntry);
|
||||||
errorThrow("Failed to load asset asynchronously.");
|
errorThrow("Failed to load asset asynchronously.");
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
threadMutexUnlock(&loading->mutex);
|
threadMutexUnlock(&loading->mutex);
|
||||||
|
|||||||
@@ -11,6 +11,38 @@
|
|||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
/* ---- Per-entry event trampolines ----------------------------------------- */
|
||||||
|
|
||||||
|
static void assetBatchEntryOnLoadedCb(void *params, void *user) {
|
||||||
|
assetentry_t *entry = (assetentry_t *)params;
|
||||||
|
assetbatch_t *batch = (assetbatch_t *)user;
|
||||||
|
|
||||||
|
batch->loadedCount++;
|
||||||
|
eventInvoke(&batch->onEntryLoaded, entry);
|
||||||
|
|
||||||
|
if((uint16_t)(batch->loadedCount + batch->errorCount) >= batch->count) {
|
||||||
|
if(batch->errorCount == 0) {
|
||||||
|
eventInvoke(&batch->onLoaded, batch);
|
||||||
|
} else {
|
||||||
|
eventInvoke(&batch->onError, batch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assetBatchEntryOnErrorCb(void *params, void *user) {
|
||||||
|
assetentry_t *entry = (assetentry_t *)params;
|
||||||
|
assetbatch_t *batch = (assetbatch_t *)user;
|
||||||
|
|
||||||
|
batch->errorCount++;
|
||||||
|
eventInvoke(&batch->onEntryError, entry);
|
||||||
|
|
||||||
|
if((uint16_t)(batch->loadedCount + batch->errorCount) >= batch->count) {
|
||||||
|
eventInvoke(&batch->onError, batch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- Public API ---------------------------------------------------------- */
|
||||||
|
|
||||||
void assetBatchInit(
|
void assetBatchInit(
|
||||||
assetbatch_t *batch,
|
assetbatch_t *batch,
|
||||||
const uint16_t count,
|
const uint16_t count,
|
||||||
@@ -24,10 +56,40 @@ void assetBatchInit(
|
|||||||
memoryZero(batch, sizeof(assetbatch_t));
|
memoryZero(batch, sizeof(assetbatch_t));
|
||||||
batch->count = count;
|
batch->count = count;
|
||||||
|
|
||||||
|
eventInit(
|
||||||
|
&batch->onLoaded,
|
||||||
|
batch->onLoadedCallbacks, batch->onLoadedUsers, ASSET_BATCH_EVENT_MAX
|
||||||
|
);
|
||||||
|
eventInit(
|
||||||
|
&batch->onEntryLoaded,
|
||||||
|
batch->onEntryLoadedCallbacks, batch->onEntryLoadedUsers, ASSET_BATCH_EVENT_MAX
|
||||||
|
);
|
||||||
|
eventInit(
|
||||||
|
&batch->onError,
|
||||||
|
batch->onErrorCallbacks, batch->onErrorUsers, ASSET_BATCH_EVENT_MAX
|
||||||
|
);
|
||||||
|
eventInit(
|
||||||
|
&batch->onEntryError,
|
||||||
|
batch->onEntryErrorCallbacks, batch->onEntryErrorUsers, ASSET_BATCH_EVENT_MAX
|
||||||
|
);
|
||||||
|
|
||||||
for(uint16_t i = 0; i < count; i++) {
|
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->inputs[i] = descs[i].input;
|
||||||
batch->entries[i] = assetLock(descs[i].path, descs[i].type, &batch->inputs[i]);
|
batch->entries[i] = assetLock(descs[i].path, descs[i].type, &batch->inputs[i]);
|
||||||
|
|
||||||
|
if(batch->entries[i]->state == ASSET_ENTRY_STATE_LOADED) {
|
||||||
|
/* Already loaded (cached) — count it now, no subscription needed. */
|
||||||
|
batch->loadedCount++;
|
||||||
|
} else if(batch->entries[i]->state == ASSET_ENTRY_STATE_ERROR) {
|
||||||
|
batch->errorCount++;
|
||||||
|
} else {
|
||||||
|
eventSubscribe(
|
||||||
|
&batch->entries[i]->onLoaded, assetBatchEntryOnLoadedCb, batch
|
||||||
|
);
|
||||||
|
eventSubscribe(
|
||||||
|
&batch->entries[i]->onError, assetBatchEntryOnErrorCb, batch
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +150,12 @@ errorret_t assetBatchRequireLoaded(assetbatch_t *batch) {
|
|||||||
void assetBatchDispose(assetbatch_t *batch) {
|
void assetBatchDispose(assetbatch_t *batch) {
|
||||||
assertNotNull(batch, "Batch cannot be NULL.");
|
assertNotNull(batch, "Batch cannot be NULL.");
|
||||||
for(uint16_t i = 0; i < batch->count; i++) {
|
for(uint16_t i = 0; i < batch->count; i++) {
|
||||||
assetUnlockEntry(batch->entries[i]);
|
if(batch->entries[i]) {
|
||||||
|
/* Unsubscribe while we still hold a lock so the entry is guaranteed live. */
|
||||||
|
eventUnsubscribe(&batch->entries[i]->onLoaded, assetBatchEntryOnLoadedCb);
|
||||||
|
eventUnsubscribe(&batch->entries[i]->onError, assetBatchEntryOnErrorCb);
|
||||||
|
assetUnlockEntry(batch->entries[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
memoryZero(batch, sizeof(assetbatch_t));
|
memoryZero(batch, sizeof(assetbatch_t));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "asset/loader/assetentry.h"
|
#include "asset/loader/assetentry.h"
|
||||||
#include "asset/loader/assetloader.h"
|
#include "asset/loader/assetloader.h"
|
||||||
|
#include "event/event.h"
|
||||||
|
|
||||||
#define ASSET_BATCH_COUNT_MAX 64
|
#define ASSET_BATCH_COUNT_MAX 64
|
||||||
|
#define ASSET_BATCH_EVENT_MAX 4
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char_t *path;
|
const char_t *path;
|
||||||
@@ -21,6 +23,28 @@ typedef struct {
|
|||||||
assetentry_t *entries[ASSET_BATCH_COUNT_MAX];
|
assetentry_t *entries[ASSET_BATCH_COUNT_MAX];
|
||||||
assetloaderinput_t inputs[ASSET_BATCH_COUNT_MAX];
|
assetloaderinput_t inputs[ASSET_BATCH_COUNT_MAX];
|
||||||
uint16_t count;
|
uint16_t count;
|
||||||
|
uint16_t loadedCount;
|
||||||
|
uint16_t errorCount;
|
||||||
|
|
||||||
|
/** Fires once when every entry has loaded successfully. params = assetbatch_t * */
|
||||||
|
event_t onLoaded;
|
||||||
|
eventcallback_t onLoadedCallbacks[ASSET_BATCH_EVENT_MAX];
|
||||||
|
void *onLoadedUsers[ASSET_BATCH_EVENT_MAX];
|
||||||
|
|
||||||
|
/** Fires each time a single entry finishes loading. params = assetentry_t * */
|
||||||
|
event_t onEntryLoaded;
|
||||||
|
eventcallback_t onEntryLoadedCallbacks[ASSET_BATCH_EVENT_MAX];
|
||||||
|
void *onEntryLoadedUsers[ASSET_BATCH_EVENT_MAX];
|
||||||
|
|
||||||
|
/** Fires once when all entries have finished (any with errors). params = assetbatch_t * */
|
||||||
|
event_t onError;
|
||||||
|
eventcallback_t onErrorCallbacks[ASSET_BATCH_EVENT_MAX];
|
||||||
|
void *onErrorUsers[ASSET_BATCH_EVENT_MAX];
|
||||||
|
|
||||||
|
/** Fires each time a single entry errors. params = assetentry_t * */
|
||||||
|
event_t onEntryError;
|
||||||
|
eventcallback_t onEntryErrorCallbacks[ASSET_BATCH_EVENT_MAX];
|
||||||
|
void *onEntryErrorUsers[ASSET_BATCH_EVENT_MAX];
|
||||||
} assetbatch_t;
|
} assetbatch_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -31,6 +31,22 @@ void assetEntryInit(
|
|||||||
entry->input = &entry->inputData;
|
entry->input = &entry->inputData;
|
||||||
}
|
}
|
||||||
refInit(&entry->refs, entry, NULL, NULL, NULL);
|
refInit(&entry->refs, entry, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
eventInit(
|
||||||
|
&entry->onLoaded,
|
||||||
|
entry->onLoadedCallbacks, entry->onLoadedUsers,
|
||||||
|
ASSET_ENTRY_EVENT_MAX
|
||||||
|
);
|
||||||
|
eventInit(
|
||||||
|
&entry->onUnloaded,
|
||||||
|
entry->onUnloadedCallbacks, entry->onUnloadedUsers,
|
||||||
|
ASSET_ENTRY_EVENT_MAX
|
||||||
|
);
|
||||||
|
eventInit(
|
||||||
|
&entry->onError,
|
||||||
|
entry->onErrorCallbacks, entry->onErrorUsers,
|
||||||
|
ASSET_ENTRY_EVENT_MAX
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void assetEntryLock(assetentry_t *entry) {
|
void assetEntryLock(assetentry_t *entry) {
|
||||||
@@ -67,10 +83,10 @@ void assetEntryStartLoading(
|
|||||||
|
|
||||||
errorret_t assetEntryDispose(assetentry_t *entry) {
|
errorret_t assetEntryDispose(assetentry_t *entry) {
|
||||||
assertNotNull(entry, "Entry cannot be NULL");
|
assertNotNull(entry, "Entry cannot be NULL");
|
||||||
|
|
||||||
assertTrue(entry->type != ASSET_LOADER_TYPE_NULL, "Invalid loader type.");
|
assertTrue(entry->type != ASSET_LOADER_TYPE_NULL, "Invalid loader type.");
|
||||||
assertTrue(entry->type < ASSET_LOADER_TYPE_COUNT, "Invalid loader type.");
|
assertTrue(entry->type < ASSET_LOADER_TYPE_COUNT, "Invalid loader type.");
|
||||||
|
|
||||||
|
eventInvoke(&entry->onUnloaded, entry);
|
||||||
errorChain(ASSET_LOADER_CALLBACKS[entry->type].dispose(entry));
|
errorChain(ASSET_LOADER_CALLBACKS[entry->type].dispose(entry));
|
||||||
memoryZero(entry, sizeof(assetentry_t));
|
memoryZero(entry, sizeof(assetentry_t));
|
||||||
errorOk();
|
errorOk();
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "asset/loader/assetloading.h"
|
#include "asset/loader/assetloading.h"
|
||||||
|
#include "event/event.h"
|
||||||
#include "util/ref.h"
|
#include "util/ref.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -19,7 +20,12 @@ typedef enum {
|
|||||||
ASSET_ENTRY_STATE_ERROR
|
ASSET_ENTRY_STATE_ERROR
|
||||||
} assetentrystate_t;
|
} assetentrystate_t;
|
||||||
|
|
||||||
typedef struct assetentry_s {
|
/** Maximum number of subscribers for each per-entry event. */
|
||||||
|
#define ASSET_ENTRY_EVENT_MAX 2
|
||||||
|
|
||||||
|
typedef struct assetentry_s assetentry_t;
|
||||||
|
|
||||||
|
struct assetentry_s {
|
||||||
// Filename and cache key
|
// Filename and cache key
|
||||||
char_t name[ASSET_FILE_NAME_MAX];
|
char_t name[ASSET_FILE_NAME_MAX];
|
||||||
// What type of asset is this?
|
// What type of asset is this?
|
||||||
@@ -39,7 +45,32 @@ typedef struct assetentry_s {
|
|||||||
assetloaderinput_t inputData;
|
assetloaderinput_t inputData;
|
||||||
// Pointer to inputData, or NULL if no input was provided.
|
// Pointer to inputData, or NULL if no input was provided.
|
||||||
assetloaderinput_t *input;
|
assetloaderinput_t *input;
|
||||||
} assetentry_t;
|
|
||||||
|
/**
|
||||||
|
* Fired once when loading completes successfully (params = assetentry_t *).
|
||||||
|
* Always invoked on the main thread.
|
||||||
|
*/
|
||||||
|
event_t onLoaded;
|
||||||
|
eventcallback_t onLoadedCallbacks[ASSET_ENTRY_EVENT_MAX];
|
||||||
|
void *onLoadedUsers[ASSET_ENTRY_EVENT_MAX];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fired once when the entry is disposed/reaped (params = assetentry_t *).
|
||||||
|
* The asset data is still accessible when the callback runs.
|
||||||
|
* Always invoked on the main thread.
|
||||||
|
*/
|
||||||
|
event_t onUnloaded;
|
||||||
|
eventcallback_t onUnloadedCallbacks[ASSET_ENTRY_EVENT_MAX];
|
||||||
|
void *onUnloadedUsers[ASSET_ENTRY_EVENT_MAX];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fired once when loading fails (params = assetentry_t *).
|
||||||
|
* Always invoked on the main thread.
|
||||||
|
*/
|
||||||
|
event_t onError;
|
||||||
|
eventcallback_t onErrorCallbacks[ASSET_ENTRY_EVENT_MAX];
|
||||||
|
void *onErrorUsers[ASSET_ENTRY_EVENT_MAX];
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes an asset entry with the given name and type. This does not load
|
* Initializes an asset entry with the given name and type. This does not load
|
||||||
@@ -86,6 +117,7 @@ void assetEntryStartLoading(assetentry_t *entry, assetloading_t *loading);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Disposes an asset entry, freeing any resources it holds.
|
* Disposes an asset entry, freeing any resources it holds.
|
||||||
|
* Fires the onUnloaded event before releasing asset data.
|
||||||
*
|
*
|
||||||
* @param entry The asset entry to dispose.
|
* @param entry The asset entry to dispose.
|
||||||
* @return Any error that occurs during disposal.
|
* @return Any error that occurs during disposal.
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "asset/loader/assetloading.h"
|
#include "asset/loader/assetloading.h"
|
||||||
#include "asset/loader/assetentry.h"
|
#include "asset/loader/assetentry.h"
|
||||||
#include "asset/loader/assetloader.h"
|
#include "asset/loader/assetloader.h"
|
||||||
|
#include "script/module/require/modulerequire.h"
|
||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
#include <jerryscript.h>
|
#include <jerryscript.h>
|
||||||
|
|||||||
@@ -13,7 +13,12 @@
|
|||||||
typedef struct assetloading_s assetloading_t;
|
typedef struct assetloading_s assetloading_t;
|
||||||
typedef struct assetentry_s assetentry_t;
|
typedef struct assetentry_s assetentry_t;
|
||||||
|
|
||||||
typedef struct { void *nothing; } assetscriptloaderinput_t;
|
/**
|
||||||
|
* Pass isModule = true to evaluate in isolated module scope.
|
||||||
|
* The loaded result (entry->data.script) will be module.exports rather than
|
||||||
|
* the script's return value.
|
||||||
|
*/
|
||||||
|
typedef struct { bool_t isModule; } assetscriptloaderinput_t;
|
||||||
typedef uint32_t assetscriptoutput_t;
|
typedef uint32_t assetscriptoutput_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
|
|||||||
consolePrint("Engine initialized");
|
consolePrint("Engine initialized");
|
||||||
|
|
||||||
errorChain(scriptExecFile("init.js"));
|
errorChain(scriptExecFile("init.js"));
|
||||||
sceneSet(SCENE_TYPE_INITIAL);
|
|
||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,10 @@
|
|||||||
# Copyright (c) 2025 Dominic Masters
|
# Copyright (c) 2026 Dominic Masters
|
||||||
#
|
#
|
||||||
# This software is released under the MIT License.
|
# This software is released under the MIT License.
|
||||||
# https://opensource.org/licenses/MIT
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
# Sources
|
|
||||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
PUBLIC
|
PUBLIC
|
||||||
scene.c
|
scene.c
|
||||||
scenerenderpipeline.c
|
scenerenderpipeline.c
|
||||||
)
|
)
|
||||||
|
|
||||||
# Subdirectories
|
|
||||||
add_subdirectory(initial)
|
|
||||||
add_subdirectory(test)
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
# Copyright (c) 2026 Dominic Masters
|
|
||||||
#
|
|
||||||
# This software is released under the MIT License.
|
|
||||||
# https://opensource.org/licenses/MIT
|
|
||||||
|
|
||||||
# Sources
|
|
||||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
|
||||||
PUBLIC
|
|
||||||
initialscene.c
|
|
||||||
)
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2026 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#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"
|
|
||||||
|
|
||||||
void initialSceneInit(void) {
|
|
||||||
consolePrint("Initial scene initialized");
|
|
||||||
errorCatch(errorPrint(scriptExecFile("testentity.js")));
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t initialSceneUpdate(void) {
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
void initialSceneDispose(void) {
|
|
||||||
entityDispose(SCENE.data.initial.cubeEntityId);
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2026 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "error/error.h"
|
|
||||||
#include "entity/entitybase.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
entityid_t cubeEntityId;
|
|
||||||
} initialscene_t;
|
|
||||||
|
|
||||||
void initialSceneInit(void);
|
|
||||||
errorret_t initialSceneUpdate(void);
|
|
||||||
void initialSceneDispose(void);
|
|
||||||
+6
-55
@@ -6,26 +6,15 @@
|
|||||||
#include "scene.h"
|
#include "scene.h"
|
||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
#include "log/log.h"
|
|
||||||
#include "time/time.h"
|
#include "time/time.h"
|
||||||
#include "display/screen/screen.h"
|
#include "display/screen/screen.h"
|
||||||
#include "entity/entitymanager.h"
|
#include "entity/entitymanager.h"
|
||||||
#include "display/shader/shaderunlit.h"
|
#include "display/shader/shaderunlit.h"
|
||||||
#include "display/display.h"
|
#include "display/display.h"
|
||||||
#include "console/console.h"
|
|
||||||
#include "util/string.h"
|
|
||||||
#include "ui/ui.h"
|
#include "ui/ui.h"
|
||||||
#include "scene/scenerenderpipeline.h"
|
#include "scene/scenerenderpipeline.h"
|
||||||
#include "entity/component.h"
|
#include "entity/component.h"
|
||||||
|
|
||||||
scenefuncs_t SCENE_FUNCTIONS[SCENE_TYPE_COUNT] = {
|
|
||||||
{ 0 },
|
|
||||||
#define X(structName, varName, varNameUpper, initFunc, updateFunc, disposeFunc) \
|
|
||||||
{ initFunc, updateFunc, disposeFunc },
|
|
||||||
#include "scene/scenelist.h"
|
|
||||||
#undef X
|
|
||||||
};
|
|
||||||
|
|
||||||
scene_t SCENE;
|
scene_t SCENE;
|
||||||
|
|
||||||
errorret_t sceneInit(void) {
|
errorret_t sceneInit(void) {
|
||||||
@@ -34,37 +23,6 @@ errorret_t sceneInit(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
errorret_t sceneUpdate(void) {
|
errorret_t sceneUpdate(void) {
|
||||||
// Handle scene change
|
|
||||||
if(SCENE.nextType != SCENE_TYPE_NULL) {
|
|
||||||
// Dispose current scene.
|
|
||||||
if(SCENE.type != SCENE_TYPE_NULL) {
|
|
||||||
if(SCENE_FUNCTIONS[SCENE.type].dispose) {
|
|
||||||
SCENE_FUNCTIONS[SCENE.type].dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init new scene
|
|
||||||
SCENE.type = SCENE.nextType;
|
|
||||||
SCENE.nextType = SCENE_TYPE_NULL;
|
|
||||||
|
|
||||||
if(SCENE.type != SCENE_TYPE_NULL) {
|
|
||||||
if(SCENE_FUNCTIONS[SCENE.type].init) {
|
|
||||||
SCENE_FUNCTIONS[SCENE.type].init();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update scene
|
|
||||||
#ifdef DUSK_TIME_DYNAMIC
|
|
||||||
if(TIME.dynamicUpdate) {
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(SCENE.type != SCENE_TYPE_NULL && SCENE_FUNCTIONS[SCENE.type].update) {
|
|
||||||
errorChain(SCENE_FUNCTIONS[SCENE.type].update());
|
|
||||||
}
|
|
||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,21 +61,14 @@ errorret_t sceneRender(void) {
|
|||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
void sceneSet(const scenetype_t type) {
|
void sceneSet(void) {
|
||||||
assertTrue(
|
|
||||||
type > SCENE_TYPE_NULL && type < SCENE_TYPE_COUNT,
|
|
||||||
"Invalid scene type"
|
|
||||||
);
|
|
||||||
SCENE.nextType = type;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
errorret_t sceneDispose(void) {
|
errorret_t sceneDispose(void) {
|
||||||
if(SCENE.type != SCENE_TYPE_NULL) {
|
// if(SCENE.active) {
|
||||||
if(SCENE_FUNCTIONS[SCENE.type].dispose) {
|
// scriptSceneDispose();
|
||||||
SCENE_FUNCTIONS[SCENE.type].dispose();
|
// SCENE.active = false;
|
||||||
}
|
// }
|
||||||
}
|
// SCENE.transitioning = false;
|
||||||
SCENE.type = SCENE_TYPE_NULL;
|
|
||||||
SCENE.nextType = SCENE_TYPE_NULL;
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-47
@@ -6,74 +6,38 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "asset/assetfile.h"
|
#include "error/error.h"
|
||||||
#include "scene/initial/initialscene.h"
|
|
||||||
#include "scene/test/testscene.h"
|
|
||||||
|
|
||||||
#define SCENE_EVENT_UPDATE_MAX 16
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
SCENE_TYPE_NULL,
|
|
||||||
#define X(structName, varName, varNameUpper, initFunc, updateFunc, disposeFunc) \
|
|
||||||
SCENE_TYPE_##varNameUpper,
|
|
||||||
#include "scene/scenelist.h"
|
|
||||||
#undef X
|
|
||||||
SCENE_TYPE_COUNT
|
|
||||||
} scenetype_t;
|
|
||||||
|
|
||||||
typedef union {
|
|
||||||
#define X(structName, varName, varNameUpper, initFunc, updateFunc, disposeFunc) \
|
|
||||||
structName varName;
|
|
||||||
#include "scene/scenelist.h"
|
|
||||||
#undef X
|
|
||||||
} scenedata_t;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
void (*init)(void);
|
void *nothing;
|
||||||
errorret_t (*update)(void);
|
|
||||||
void (*dispose)(void);
|
|
||||||
} scenefuncs_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
scenedata_t data;
|
|
||||||
scenetype_t type;
|
|
||||||
scenetype_t nextType;
|
|
||||||
} scene_t;
|
} scene_t;
|
||||||
|
|
||||||
extern scenefuncs_t SCENE_FUNCTIONS[SCENE_TYPE_COUNT];
|
|
||||||
extern scene_t SCENE;
|
extern scene_t SCENE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the scene manager.
|
* Initialises the scene manager.
|
||||||
*
|
|
||||||
* @return Any error state that happened.
|
|
||||||
*/
|
*/
|
||||||
errorret_t sceneInit(void);
|
errorret_t sceneInit(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ticks the scene manager; may call the scene's update method.
|
* Ticks the scene manager. Processes any pending scene transition, then
|
||||||
*
|
* calls scriptSceneUpdate on the active scene.
|
||||||
* @return Any error state that happened.
|
|
||||||
*/
|
*/
|
||||||
errorret_t sceneUpdate(void);
|
errorret_t sceneUpdate(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the scene.
|
* Renders the current scene (entities, render pipeline, UI).
|
||||||
*
|
|
||||||
* @return Any error state that happened.
|
|
||||||
*/
|
*/
|
||||||
errorret_t sceneRender(void);
|
errorret_t sceneRender(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requests a scene change on the next safe opportunity.
|
* Requests a scene transition. The pending script scene (set via
|
||||||
*
|
* scriptSceneSetPending) will be activated at the start of the next
|
||||||
* @param type The type of scene to change to.
|
* sceneUpdate call.
|
||||||
*/
|
*/
|
||||||
void sceneSet(const scenetype_t type);
|
// void sceneSet(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disposes of the current scene.
|
* Disposes the active scene immediately.
|
||||||
*
|
|
||||||
* @return Any error state that happened.
|
|
||||||
*/
|
*/
|
||||||
errorret_t sceneDispose(void);
|
errorret_t sceneDispose(void);
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2026 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef X
|
|
||||||
#define X(structName, varName, varNameUpper, initFunc, updateFunc, disposeFunc) \
|
|
||||||
((void))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
X(initialscene_t, initial, INITIAL, initialSceneInit, initialSceneUpdate, initialSceneDispose)
|
|
||||||
X(testscene_t, test, TEST, testSceneInit, testSceneUpdate, testSceneDispose)
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2026 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "testscene.h"
|
|
||||||
#include "console/console.h"
|
|
||||||
#include "entity/entitymanager.h"
|
|
||||||
#include "input/input.h"
|
|
||||||
|
|
||||||
#define TEST_SCENE_ENTITY_MAX (ENTITY_COUNT_MAX - 1)
|
|
||||||
|
|
||||||
static entityid_t cameraEntityId;
|
|
||||||
static componentid_t cameraCompId;
|
|
||||||
static entityid_t testEntities[TEST_SCENE_ENTITY_MAX];
|
|
||||||
static uint8_t testEntityCount = 0;
|
|
||||||
|
|
||||||
static void testSceneSpawnTestEntity(void) {
|
|
||||||
if(testEntityCount >= TEST_SCENE_ENTITY_MAX) return;
|
|
||||||
|
|
||||||
entityid_t entity = entityManagerAdd();
|
|
||||||
componentid_t posComp = entityAddComponent(entity, COMPONENT_TYPE_POSITION);
|
|
||||||
entityAddComponent(entity, COMPONENT_TYPE_RENDERABLE);
|
|
||||||
|
|
||||||
const int32_t cols = 20;
|
|
||||||
const float_t spacing = 1.5f;
|
|
||||||
int32_t col = testEntityCount % cols;
|
|
||||||
int32_t row = testEntityCount / cols;
|
|
||||||
vec3 pos = {
|
|
||||||
((float_t)col - (cols - 1) * 0.5f) * spacing,
|
|
||||||
0.0f,
|
|
||||||
(float_t)row * spacing
|
|
||||||
};
|
|
||||||
entityPositionSetLocalPosition(entity, posComp, pos);
|
|
||||||
|
|
||||||
testEntities[testEntityCount++] = entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void testSceneUpdateCamera(void) {
|
|
||||||
if(testEntityCount == 0) return;
|
|
||||||
|
|
||||||
float_t minX = FLT_MAX, maxX = -FLT_MAX;
|
|
||||||
float_t minZ = FLT_MAX, maxZ = -FLT_MAX;
|
|
||||||
|
|
||||||
for(entityid_t i = 0; i < testEntityCount; i++) {
|
|
||||||
componentid_t posComp = entityGetComponent(
|
|
||||||
testEntities[i], COMPONENT_TYPE_POSITION
|
|
||||||
);
|
|
||||||
if(posComp == COMPONENT_ID_INVALID) continue;
|
|
||||||
vec3 pos;
|
|
||||||
entityPositionGetLocalPosition(testEntities[i], posComp, pos);
|
|
||||||
if(pos[0] < minX) minX = pos[0];
|
|
||||||
if(pos[0] > maxX) maxX = pos[0];
|
|
||||||
if(pos[2] < minZ) minZ = pos[2];
|
|
||||||
if(pos[2] > maxZ) maxZ = pos[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
float_t centerX = (minX + maxX) * 0.5f;
|
|
||||||
float_t centerZ = (minZ + maxZ) * 0.5f;
|
|
||||||
float_t extentX = (maxX - minX) * 0.5f + 0.5f;
|
|
||||||
float_t extentZ = (maxZ - minZ) * 0.5f + 0.5f;
|
|
||||||
float_t extent = extentX > extentZ ? extentX : extentZ;
|
|
||||||
float_t dist = extent * 1.5f + 2.0f;
|
|
||||||
|
|
||||||
vec3 target = { centerX, 0.0f, centerZ };
|
|
||||||
vec3 eye = { centerX + dist, dist, centerZ + dist };
|
|
||||||
vec3 up = { 0.0f, 1.0f, 0.0f };
|
|
||||||
entityPositionLookAt(cameraEntityId, cameraCompId, eye, target, up);
|
|
||||||
}
|
|
||||||
|
|
||||||
void testSceneInit(void) {
|
|
||||||
consolePrint("Test scene initialized");
|
|
||||||
testEntityCount = 0;
|
|
||||||
|
|
||||||
cameraEntityId = entityManagerAdd();
|
|
||||||
cameraCompId = entityAddComponent(cameraEntityId, COMPONENT_TYPE_POSITION);
|
|
||||||
entityAddComponent(cameraEntityId, COMPONENT_TYPE_CAMERA);
|
|
||||||
|
|
||||||
vec3 eye, target, up;
|
|
||||||
glm_vec3_zero(target);
|
|
||||||
glm_vec3_copy((vec3){ 3.0f, 3.0f, 3.0f }, eye);
|
|
||||||
glm_vec3_copy((vec3){ 0.0f, 1.0f, 0.0f }, up);
|
|
||||||
entityPositionLookAt(cameraEntityId, cameraCompId, eye, target, up);
|
|
||||||
|
|
||||||
for(int i = 0; i < 5; i++) testSceneSpawnTestEntity();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t testSceneUpdate(void) {
|
|
||||||
if(inputPressed(INPUT_ACTION_ACCEPT)) {
|
|
||||||
for(int i = 0; i < 5; i++) testSceneSpawnTestEntity();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(inputPressed(INPUT_ACTION_CANCEL)) {
|
|
||||||
for(int i = 0; i < 5 && testEntityCount > 0; i++) {
|
|
||||||
entityDispose(testEntities[--testEntityCount]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
testSceneUpdateCamera();
|
|
||||||
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
void testSceneDispose(void) {
|
|
||||||
testEntityCount = 0;
|
|
||||||
cameraEntityId = ENTITY_ID_INVALID;
|
|
||||||
cameraCompId = COMPONENT_ID_INVALID;
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2026 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "error/error.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
void *nothing;
|
|
||||||
} testscene_t;
|
|
||||||
|
|
||||||
void testSceneInit(void);
|
|
||||||
errorret_t testSceneUpdate(void);
|
|
||||||
void testSceneDispose(void);
|
|
||||||
@@ -7,3 +7,6 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
|||||||
PUBLIC
|
PUBLIC
|
||||||
modulebase.c
|
modulebase.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Subdirs
|
||||||
|
add_subdirectory(require)
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "script/scriptproto.h"
|
#include "script/scriptproto.h"
|
||||||
#include "script/module/display/moduletexture.h"
|
#include "script/module/display/moduletexture.h"
|
||||||
#include "script/module/asset/moduleassetentry.h"
|
#include "script/module/asset/moduleassetentry.h"
|
||||||
|
#include "script/module/asset/moduleassetbatch.h"
|
||||||
#include "asset/asset.h"
|
#include "asset/asset.h"
|
||||||
#include "asset/loader/assetloader.h"
|
#include "asset/loader/assetloader.h"
|
||||||
|
|
||||||
@@ -89,6 +90,7 @@ moduleBaseFunction(moduleAssetUnlock) {
|
|||||||
|
|
||||||
static void moduleAssetInit(void) {
|
static void moduleAssetInit(void) {
|
||||||
moduleAssetEntryInit();
|
moduleAssetEntryInit();
|
||||||
|
moduleAssetBatchInit();
|
||||||
scriptProtoInit(&MODULE_ASSET_PROTO, "Asset", sizeof(uint8_t), NULL);
|
scriptProtoInit(&MODULE_ASSET_PROTO, "Asset", sizeof(uint8_t), NULL);
|
||||||
scriptProtoDefineStaticFunc(&MODULE_ASSET_PROTO, "exists", moduleAssetExists);
|
scriptProtoDefineStaticFunc(&MODULE_ASSET_PROTO, "exists", moduleAssetExists);
|
||||||
scriptProtoDefineStaticFunc(&MODULE_ASSET_PROTO, "lock", moduleAssetLock);
|
scriptProtoDefineStaticFunc(&MODULE_ASSET_PROTO, "lock", moduleAssetLock);
|
||||||
@@ -134,5 +136,6 @@ static void moduleAssetInit(void) {
|
|||||||
|
|
||||||
static void moduleAssetDispose(void) {
|
static void moduleAssetDispose(void) {
|
||||||
scriptProtoDispose(&MODULE_ASSET_PROTO);
|
scriptProtoDispose(&MODULE_ASSET_PROTO);
|
||||||
|
moduleAssetBatchDispose();
|
||||||
moduleAssetEntryDispose();
|
moduleAssetEntryDispose();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,293 @@
|
|||||||
|
/**
|
||||||
|
* 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/asset/moduleassetentry.h"
|
||||||
|
#include "asset/assetbatch.h"
|
||||||
|
#include "asset/asset.h"
|
||||||
|
#include "asset/loader/assetloader.h"
|
||||||
|
#include "util/memory.h"
|
||||||
|
|
||||||
|
static scriptproto_t MODULE_ASSET_BATCH_PROTO;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
assetbatch_t *batch;
|
||||||
|
} jsassetbatch_t;
|
||||||
|
|
||||||
|
static void moduleAssetBatchFree(void *ptr, jerry_object_native_info_t *info) {
|
||||||
|
(void)info;
|
||||||
|
jsassetbatch_t *b = (jsassetbatch_t *)ptr;
|
||||||
|
if(b && b->batch) {
|
||||||
|
assetBatchDispose(b->batch);
|
||||||
|
memoryFree(b->batch);
|
||||||
|
}
|
||||||
|
memoryFree(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline jsassetbatch_t *moduleAssetBatchSelf(
|
||||||
|
const jerry_call_info_t *callInfo
|
||||||
|
) {
|
||||||
|
return (jsassetbatch_t *)scriptProtoGetValue(
|
||||||
|
&MODULE_ASSET_BATCH_PROTO, callInfo->this_value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AssetBatch(descriptors[])
|
||||||
|
*
|
||||||
|
* Parses an array of {path, type, format?/input?/axis?} descriptor objects,
|
||||||
|
* locks all assets, and returns an AssetBatch JS object. Works with and
|
||||||
|
* without `new`.
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleAssetBatchCtor) {
|
||||||
|
if(argc < 1 || !jerry_value_is_array(args[0])) {
|
||||||
|
return moduleBaseThrow("AssetBatch: expected an array of descriptors");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count = jerry_array_length(args[0]);
|
||||||
|
if(count == 0 || count > (uint32_t)ASSET_BATCH_COUNT_MAX) {
|
||||||
|
return moduleBaseThrow("AssetBatch: descriptor count out of range");
|
||||||
|
}
|
||||||
|
|
||||||
|
assetbatchdesc_t descs[ASSET_BATCH_COUNT_MAX];
|
||||||
|
char_t paths[ASSET_BATCH_COUNT_MAX][ASSET_FILE_NAME_MAX];
|
||||||
|
|
||||||
|
for(uint32_t i = 0; i < count; i++) {
|
||||||
|
jerry_value_t desc = jerry_object_get_index(args[0], i);
|
||||||
|
if(!jerry_value_is_object(desc)) {
|
||||||
|
jerry_value_free(desc);
|
||||||
|
return moduleBaseThrow("AssetBatch: each descriptor must be an object");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* path */
|
||||||
|
jerry_value_t pathProp = moduleBaseGetProp(desc, "path");
|
||||||
|
if(!jerry_value_is_string(pathProp)) {
|
||||||
|
jerry_value_free(pathProp);
|
||||||
|
jerry_value_free(desc);
|
||||||
|
return moduleBaseThrow("AssetBatch: descriptor.path must be a string");
|
||||||
|
}
|
||||||
|
jerry_size_t pathLen = jerry_string_to_buffer(
|
||||||
|
pathProp, JERRY_ENCODING_UTF8,
|
||||||
|
(jerry_char_t *)paths[i], ASSET_FILE_NAME_MAX - 1
|
||||||
|
);
|
||||||
|
paths[i][pathLen] = '\0';
|
||||||
|
jerry_value_free(pathProp);
|
||||||
|
descs[i].path = paths[i];
|
||||||
|
|
||||||
|
/* type */
|
||||||
|
jerry_value_t typeProp = moduleBaseGetProp(desc, "type");
|
||||||
|
if(!jerry_value_is_number(typeProp)) {
|
||||||
|
jerry_value_free(typeProp);
|
||||||
|
jerry_value_free(desc);
|
||||||
|
return moduleBaseThrow("AssetBatch: descriptor.type must be a number");
|
||||||
|
}
|
||||||
|
descs[i].type = (assetloadertype_t)moduleBaseValueInt(typeProp);
|
||||||
|
jerry_value_free(typeProp);
|
||||||
|
|
||||||
|
/* input: accept format, input, or axis — whichever is present */
|
||||||
|
memoryZero(&descs[i].input, sizeof(assetloaderinput_t));
|
||||||
|
jerry_value_t inputProp = moduleBaseGetProp(desc, "format");
|
||||||
|
if(jerry_value_is_undefined(inputProp)) {
|
||||||
|
jerry_value_free(inputProp);
|
||||||
|
inputProp = moduleBaseGetProp(desc, "input");
|
||||||
|
}
|
||||||
|
if(jerry_value_is_undefined(inputProp)) {
|
||||||
|
jerry_value_free(inputProp);
|
||||||
|
inputProp = moduleBaseGetProp(desc, "axis");
|
||||||
|
}
|
||||||
|
if(jerry_value_is_number(inputProp)) {
|
||||||
|
int32_t v = moduleBaseValueInt(inputProp);
|
||||||
|
switch(descs[i].type) {
|
||||||
|
case ASSET_LOADER_TYPE_TEXTURE:
|
||||||
|
descs[i].input.texture = (textureformat_t)v;
|
||||||
|
break;
|
||||||
|
case ASSET_LOADER_TYPE_MESH:
|
||||||
|
descs[i].input.mesh = (assetmeshinputaxis_t)v;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jerry_value_free(inputProp);
|
||||||
|
jerry_value_free(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
assetbatch_t *batch = (assetbatch_t *)memoryAllocate(sizeof(assetbatch_t));
|
||||||
|
assetBatchInit(batch, (uint16_t)count, descs);
|
||||||
|
|
||||||
|
jsassetbatch_t init = { .batch = batch };
|
||||||
|
return scriptProtoCreateValue(&MODULE_ASSET_BATCH_PROTO, &init);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- Properties ---------------------------------------------------------- */
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleAssetBatchGetCount) {
|
||||||
|
(void)args; (void)argc;
|
||||||
|
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||||
|
if(!b || !b->batch) return jerry_number(0.0);
|
||||||
|
return jerry_number((double)b->batch->count);
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleAssetBatchGetIsLoaded) {
|
||||||
|
(void)args; (void)argc;
|
||||||
|
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||||
|
if(!b || !b->batch) return jerry_boolean(false);
|
||||||
|
return jerry_boolean(assetBatchIsLoaded(b->batch));
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleAssetBatchGetHasError) {
|
||||||
|
(void)args; (void)argc;
|
||||||
|
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||||
|
if(!b || !b->batch) return jerry_boolean(false);
|
||||||
|
return jerry_boolean(assetBatchHasError(b->batch));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- Methods ------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* Blocks until every entry is loaded. Returns this for chaining. */
|
||||||
|
moduleBaseFunction(moduleAssetBatchRequireLoaded) {
|
||||||
|
(void)args; (void)argc;
|
||||||
|
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||||
|
if(!b || !b->batch) {
|
||||||
|
return moduleBaseThrow("AssetBatch.requireLoaded: batch already disposed");
|
||||||
|
}
|
||||||
|
errorret_t err = assetBatchRequireLoaded(b->batch);
|
||||||
|
if(errorIsNotOk(err)) return moduleBaseThrowError(err);
|
||||||
|
return jerry_value_copy(callInfo->this_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Acquires an additional lock on every entry. Returns this for chaining. */
|
||||||
|
moduleBaseFunction(moduleAssetBatchLock) {
|
||||||
|
(void)args; (void)argc;
|
||||||
|
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||||
|
if(!b || !b->batch) return jerry_undefined();
|
||||||
|
assetBatchLock(b->batch);
|
||||||
|
return jerry_value_copy(callInfo->this_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Releases all locks and clears the batch. The object becomes invalid. */
|
||||||
|
moduleBaseFunction(moduleAssetBatchUnlock) {
|
||||||
|
(void)args; (void)argc;
|
||||||
|
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||||
|
if(!b || !b->batch) return jerry_undefined();
|
||||||
|
assetBatchDispose(b->batch);
|
||||||
|
memoryFree(b->batch);
|
||||||
|
b->batch = NULL;
|
||||||
|
return jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the AssetEntry at index i, adding an independent lock to it. */
|
||||||
|
moduleBaseFunction(moduleAssetBatchEntry) {
|
||||||
|
moduleBaseRequireArgs(1);
|
||||||
|
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||||
|
if(!b || !b->batch) return jerry_undefined();
|
||||||
|
uint32_t idx = (uint32_t)moduleBaseArgInt(0);
|
||||||
|
if(idx >= (uint32_t)b->batch->count) return jerry_undefined();
|
||||||
|
assetentry_t *entry = b->batch->entries[idx];
|
||||||
|
if(!entry) return jerry_undefined();
|
||||||
|
assetEntryLock(entry);
|
||||||
|
jsassetentry_t e = { .entry = entry };
|
||||||
|
return scriptProtoCreateValue(&MODULE_ASSET_ENTRY_PROTO, &e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- Event proxies ------------------------------------------------------- */
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleAssetBatchGetOnLoaded) {
|
||||||
|
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||||
|
if(!b || !b->batch) return jerry_undefined();
|
||||||
|
return moduleEventProxyGetOrCreate(callInfo, &b->batch->onLoaded, "_onLoaded");
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleAssetBatchGetOnEntryLoaded) {
|
||||||
|
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||||
|
if(!b || !b->batch) return jerry_undefined();
|
||||||
|
return moduleEventProxyGetOrCreate(callInfo, &b->batch->onEntryLoaded, "_onEntryLoaded");
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleAssetBatchGetOnError) {
|
||||||
|
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||||
|
if(!b || !b->batch) return jerry_undefined();
|
||||||
|
return moduleEventProxyGetOrCreate(callInfo, &b->batch->onError, "_onError");
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleAssetBatchGetOnEntryError) {
|
||||||
|
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||||
|
if(!b || !b->batch) return jerry_undefined();
|
||||||
|
return moduleEventProxyGetOrCreate(callInfo, &b->batch->onEntryError, "_onEntryError");
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleAssetBatchToString) {
|
||||||
|
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||||
|
if(!b || !b->batch) return jerry_string_sz("AssetBatch:invalid");
|
||||||
|
char_t buf[32];
|
||||||
|
snprintf(buf, sizeof(buf), "AssetBatch(%u)", (unsigned)b->batch->count);
|
||||||
|
return jerry_string_sz(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- Init / Dispose ------------------------------------------------------ */
|
||||||
|
|
||||||
|
static void moduleAssetBatchInit(void) {
|
||||||
|
scriptProtoInit(
|
||||||
|
&MODULE_ASSET_BATCH_PROTO, "AssetBatch",
|
||||||
|
sizeof(jsassetbatch_t), moduleAssetBatchCtor
|
||||||
|
);
|
||||||
|
MODULE_ASSET_BATCH_PROTO.info.free_cb = moduleAssetBatchFree;
|
||||||
|
|
||||||
|
scriptProtoDefineProp(
|
||||||
|
&MODULE_ASSET_BATCH_PROTO, "count",
|
||||||
|
moduleAssetBatchGetCount, NULL
|
||||||
|
);
|
||||||
|
scriptProtoDefineProp(
|
||||||
|
&MODULE_ASSET_BATCH_PROTO, "isLoaded",
|
||||||
|
moduleAssetBatchGetIsLoaded, NULL
|
||||||
|
);
|
||||||
|
scriptProtoDefineProp(
|
||||||
|
&MODULE_ASSET_BATCH_PROTO, "hasError",
|
||||||
|
moduleAssetBatchGetHasError, NULL
|
||||||
|
);
|
||||||
|
scriptProtoDefineFunc(
|
||||||
|
&MODULE_ASSET_BATCH_PROTO, "requireLoaded",
|
||||||
|
moduleAssetBatchRequireLoaded
|
||||||
|
);
|
||||||
|
scriptProtoDefineFunc(
|
||||||
|
&MODULE_ASSET_BATCH_PROTO, "lock",
|
||||||
|
moduleAssetBatchLock
|
||||||
|
);
|
||||||
|
scriptProtoDefineFunc(
|
||||||
|
&MODULE_ASSET_BATCH_PROTO, "unlock",
|
||||||
|
moduleAssetBatchUnlock
|
||||||
|
);
|
||||||
|
scriptProtoDefineFunc(
|
||||||
|
&MODULE_ASSET_BATCH_PROTO, "entry",
|
||||||
|
moduleAssetBatchEntry
|
||||||
|
);
|
||||||
|
scriptProtoDefineProp(
|
||||||
|
&MODULE_ASSET_BATCH_PROTO, "onLoaded",
|
||||||
|
moduleAssetBatchGetOnLoaded, NULL
|
||||||
|
);
|
||||||
|
scriptProtoDefineProp(
|
||||||
|
&MODULE_ASSET_BATCH_PROTO, "onEntryLoaded",
|
||||||
|
moduleAssetBatchGetOnEntryLoaded, NULL
|
||||||
|
);
|
||||||
|
scriptProtoDefineProp(
|
||||||
|
&MODULE_ASSET_BATCH_PROTO, "onError",
|
||||||
|
moduleAssetBatchGetOnError, NULL
|
||||||
|
);
|
||||||
|
scriptProtoDefineProp(
|
||||||
|
&MODULE_ASSET_BATCH_PROTO, "onEntryError",
|
||||||
|
moduleAssetBatchGetOnEntryError, NULL
|
||||||
|
);
|
||||||
|
scriptProtoDefineToString(
|
||||||
|
&MODULE_ASSET_BATCH_PROTO, moduleAssetBatchToString
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void moduleAssetBatchDispose(void) {
|
||||||
|
scriptProtoDispose(&MODULE_ASSET_BATCH_PROTO);
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "script/module/modulebase.h"
|
#include "script/module/modulebase.h"
|
||||||
#include "script/scriptproto.h"
|
#include "script/scriptproto.h"
|
||||||
#include "script/module/display/moduletexture.h"
|
#include "script/module/display/moduletexture.h"
|
||||||
|
#include "script/module/asset/moduleeventproxy.h"
|
||||||
#include "asset/asset.h"
|
#include "asset/asset.h"
|
||||||
#include "asset/loader/assetloader.h"
|
#include "asset/loader/assetloader.h"
|
||||||
#include "asset/loader/assetentry.h"
|
#include "asset/loader/assetentry.h"
|
||||||
@@ -106,6 +107,24 @@ moduleBaseFunction(moduleAssetEntryUnlock) {
|
|||||||
return jerry_undefined();
|
return jerry_undefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleAssetEntryGetOnLoaded) {
|
||||||
|
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||||
|
if(!e || !e->entry) return jerry_undefined();
|
||||||
|
return moduleEventProxyGetOrCreate(callInfo, &e->entry->onLoaded, "_onLoaded");
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleAssetEntryGetOnUnloaded) {
|
||||||
|
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||||
|
if(!e || !e->entry) return jerry_undefined();
|
||||||
|
return moduleEventProxyGetOrCreate(callInfo, &e->entry->onUnloaded, "_onUnloaded");
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleAssetEntryGetOnError) {
|
||||||
|
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||||
|
if(!e || !e->entry) return jerry_undefined();
|
||||||
|
return moduleEventProxyGetOrCreate(callInfo, &e->entry->onError, "_onError");
|
||||||
|
}
|
||||||
|
|
||||||
moduleBaseFunction(moduleAssetEntryToString) {
|
moduleBaseFunction(moduleAssetEntryToString) {
|
||||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||||
if(!e || !e->entry) return jerry_string_sz("AssetEntry:invalid");
|
if(!e || !e->entry) return jerry_string_sz("AssetEntry:invalid");
|
||||||
@@ -115,6 +134,7 @@ moduleBaseFunction(moduleAssetEntryToString) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void moduleAssetEntryInit(void) {
|
static void moduleAssetEntryInit(void) {
|
||||||
|
moduleEventProxyInit();
|
||||||
scriptProtoInit(
|
scriptProtoInit(
|
||||||
&MODULE_ASSET_ENTRY_PROTO, "AssetEntry",
|
&MODULE_ASSET_ENTRY_PROTO, "AssetEntry",
|
||||||
sizeof(jsassetentry_t), moduleAssetEntryCtor
|
sizeof(jsassetentry_t), moduleAssetEntryCtor
|
||||||
@@ -142,6 +162,18 @@ static void moduleAssetEntryInit(void) {
|
|||||||
scriptProtoDefineFunc(
|
scriptProtoDefineFunc(
|
||||||
&MODULE_ASSET_ENTRY_PROTO, "unlock", moduleAssetEntryUnlock
|
&MODULE_ASSET_ENTRY_PROTO, "unlock", moduleAssetEntryUnlock
|
||||||
);
|
);
|
||||||
|
scriptProtoDefineProp(
|
||||||
|
&MODULE_ASSET_ENTRY_PROTO, "onLoaded",
|
||||||
|
moduleAssetEntryGetOnLoaded, NULL
|
||||||
|
);
|
||||||
|
scriptProtoDefineProp(
|
||||||
|
&MODULE_ASSET_ENTRY_PROTO, "onUnloaded",
|
||||||
|
moduleAssetEntryGetOnUnloaded, NULL
|
||||||
|
);
|
||||||
|
scriptProtoDefineProp(
|
||||||
|
&MODULE_ASSET_ENTRY_PROTO, "onError",
|
||||||
|
moduleAssetEntryGetOnError, NULL
|
||||||
|
);
|
||||||
scriptProtoDefineToString(
|
scriptProtoDefineToString(
|
||||||
&MODULE_ASSET_ENTRY_PROTO, moduleAssetEntryToString
|
&MODULE_ASSET_ENTRY_PROTO, moduleAssetEntryToString
|
||||||
);
|
);
|
||||||
@@ -168,4 +200,5 @@ static void moduleAssetEntryInit(void) {
|
|||||||
|
|
||||||
static void moduleAssetEntryDispose(void) {
|
static void moduleAssetEntryDispose(void) {
|
||||||
scriptProtoDispose(&MODULE_ASSET_ENTRY_PROTO);
|
scriptProtoDispose(&MODULE_ASSET_ENTRY_PROTO);
|
||||||
|
moduleEventProxyDispose();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,245 @@
|
|||||||
|
/**
|
||||||
|
* 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 "event/event.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum number of JS subscriber slots per proxy. Must be >= the largest
|
||||||
|
* event capacity used (ASSET_ENTRY_EVENT_MAX, ASSET_BATCH_EVENT_MAX, etc.).
|
||||||
|
*/
|
||||||
|
#define MODULE_EVENT_PROXY_MAX_SLOTS 4
|
||||||
|
|
||||||
|
static scriptproto_t MODULE_EVENT_PROXY_PROTO;
|
||||||
|
|
||||||
|
/** Native data stored on each EventProxy JS object. */
|
||||||
|
typedef struct {
|
||||||
|
event_t *event;
|
||||||
|
jerry_value_t fns[MODULE_EVENT_PROXY_MAX_SLOTS];
|
||||||
|
} jseventproxy_t;
|
||||||
|
|
||||||
|
/* ---- C trampolines (one per slot index) ---------------------------------- */
|
||||||
|
|
||||||
|
static void moduleEventProxyTrampoline0(void *params, void *user) {
|
||||||
|
(void)params;
|
||||||
|
jerry_value_t fn = (jerry_value_t)(uintptr_t)user;
|
||||||
|
jerry_value_t ret = jerry_call(fn, jerry_undefined(), NULL, 0);
|
||||||
|
jerry_value_free(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void moduleEventProxyTrampoline1(void *params, void *user) {
|
||||||
|
(void)params;
|
||||||
|
jerry_value_t fn = (jerry_value_t)(uintptr_t)user;
|
||||||
|
jerry_value_t ret = jerry_call(fn, jerry_undefined(), NULL, 0);
|
||||||
|
jerry_value_free(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void moduleEventProxyTrampoline2(void *params, void *user) {
|
||||||
|
(void)params;
|
||||||
|
jerry_value_t fn = (jerry_value_t)(uintptr_t)user;
|
||||||
|
jerry_value_t ret = jerry_call(fn, jerry_undefined(), NULL, 0);
|
||||||
|
jerry_value_free(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void moduleEventProxyTrampoline3(void *params, void *user) {
|
||||||
|
(void)params;
|
||||||
|
jerry_value_t fn = (jerry_value_t)(uintptr_t)user;
|
||||||
|
jerry_value_t ret = jerry_call(fn, jerry_undefined(), NULL, 0);
|
||||||
|
jerry_value_free(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static eventcallback_t MODULE_EVENT_PROXY_TRAMPOLINES[MODULE_EVENT_PROXY_MAX_SLOTS] = {
|
||||||
|
moduleEventProxyTrampoline0,
|
||||||
|
moduleEventProxyTrampoline1,
|
||||||
|
moduleEventProxyTrampoline2,
|
||||||
|
moduleEventProxyTrampoline3,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ---- GC free callback ---------------------------------------------------- */
|
||||||
|
|
||||||
|
static void moduleEventProxyFree(void *ptr, jerry_object_native_info_t *info) {
|
||||||
|
(void)info;
|
||||||
|
jseventproxy_t *ep = (jseventproxy_t *)ptr;
|
||||||
|
if(ep) {
|
||||||
|
for(uint32_t i = 0; i < MODULE_EVENT_PROXY_MAX_SLOTS; i++) {
|
||||||
|
if(jerry_value_is_function(ep->fns[i])) {
|
||||||
|
if(ep->event) eventUnsubscribe(ep->event, MODULE_EVENT_PROXY_TRAMPOLINES[i]);
|
||||||
|
jerry_value_free(ep->fns[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memoryFree(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- Self helper --------------------------------------------------------- */
|
||||||
|
|
||||||
|
static inline jseventproxy_t *moduleEventProxySelf(
|
||||||
|
const jerry_call_info_t *callInfo
|
||||||
|
) {
|
||||||
|
return (jseventproxy_t *)scriptProtoGetValue(
|
||||||
|
&MODULE_EVENT_PROXY_PROTO, callInfo->this_value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- Slot get/set helpers ------------------------------------------------ */
|
||||||
|
|
||||||
|
static inline jerry_value_t moduleEventProxyGetSlot(
|
||||||
|
const jerry_call_info_t *callInfo,
|
||||||
|
const uint32_t slot
|
||||||
|
) {
|
||||||
|
jseventproxy_t *ep = moduleEventProxySelf(callInfo);
|
||||||
|
if(!ep || !ep->event || slot >= ep->event->size) return jerry_null();
|
||||||
|
return jerry_value_is_function(ep->fns[slot])
|
||||||
|
? jerry_value_copy(ep->fns[slot])
|
||||||
|
: jerry_null();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline jerry_value_t moduleEventProxySetSlot(
|
||||||
|
const jerry_call_info_t *callInfo,
|
||||||
|
const jerry_value_t args[],
|
||||||
|
const jerry_length_t argc,
|
||||||
|
const uint32_t slot
|
||||||
|
) {
|
||||||
|
jseventproxy_t *ep = moduleEventProxySelf(callInfo);
|
||||||
|
if(!ep || !ep->event || slot >= ep->event->size) return jerry_undefined();
|
||||||
|
|
||||||
|
if(jerry_value_is_function(ep->fns[slot])) {
|
||||||
|
eventUnsubscribe(ep->event, MODULE_EVENT_PROXY_TRAMPOLINES[slot]);
|
||||||
|
jerry_value_free(ep->fns[slot]);
|
||||||
|
ep->fns[slot] = jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
jerry_value_t val = (argc > 0) ? args[0] : jerry_undefined();
|
||||||
|
if(jerry_value_is_function(val)) {
|
||||||
|
ep->fns[slot] = jerry_value_copy(val);
|
||||||
|
eventSubscribe(
|
||||||
|
ep->event,
|
||||||
|
MODULE_EVENT_PROXY_TRAMPOLINES[slot],
|
||||||
|
(void *)(uintptr_t)ep->fns[slot]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- Per-slot getter/setter pairs ---------------------------------------- */
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleEventProxyGet0) {
|
||||||
|
(void)args; (void)argc;
|
||||||
|
return moduleEventProxyGetSlot(callInfo, 0);
|
||||||
|
}
|
||||||
|
moduleBaseFunction(moduleEventProxySet0) {
|
||||||
|
return moduleEventProxySetSlot(callInfo, args, argc, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleEventProxyGet1) {
|
||||||
|
(void)args; (void)argc;
|
||||||
|
return moduleEventProxyGetSlot(callInfo, 1);
|
||||||
|
}
|
||||||
|
moduleBaseFunction(moduleEventProxySet1) {
|
||||||
|
return moduleEventProxySetSlot(callInfo, args, argc, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleEventProxyGet2) {
|
||||||
|
(void)args; (void)argc;
|
||||||
|
return moduleEventProxyGetSlot(callInfo, 2);
|
||||||
|
}
|
||||||
|
moduleBaseFunction(moduleEventProxySet2) {
|
||||||
|
return moduleEventProxySetSlot(callInfo, args, argc, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleEventProxyGet3) {
|
||||||
|
(void)args; (void)argc;
|
||||||
|
return moduleEventProxyGetSlot(callInfo, 3);
|
||||||
|
}
|
||||||
|
moduleBaseFunction(moduleEventProxySet3) {
|
||||||
|
return moduleEventProxySetSlot(callInfo, args, argc, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleEventProxyGetLength) {
|
||||||
|
(void)args; (void)argc;
|
||||||
|
jseventproxy_t *ep = moduleEventProxySelf(callInfo);
|
||||||
|
if(!ep || !ep->event) return jerry_number(0.0);
|
||||||
|
return jerry_number((double)ep->event->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleEventProxyToString) {
|
||||||
|
(void)args; (void)argc;
|
||||||
|
return jerry_string_sz("EventProxy");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- Lazy-create helper (shared by all parent types) --------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the event proxy pinned at pinKey on callInfo->this_value.
|
||||||
|
* Creates and pins it on first access. event must remain valid for the
|
||||||
|
* lifetime of the parent JS object (it is stored by pointer, not copied).
|
||||||
|
*/
|
||||||
|
static inline jerry_value_t moduleEventProxyGetOrCreate(
|
||||||
|
const jerry_call_info_t *callInfo,
|
||||||
|
event_t *event,
|
||||||
|
const char_t *pinKey
|
||||||
|
) {
|
||||||
|
jerry_value_t keyStr = jerry_string_sz(pinKey);
|
||||||
|
jerry_value_t existing = jerry_object_get(callInfo->this_value, keyStr);
|
||||||
|
if(!jerry_value_is_undefined(existing)) {
|
||||||
|
jerry_value_free(keyStr);
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
jerry_value_free(existing);
|
||||||
|
|
||||||
|
jseventproxy_t ep;
|
||||||
|
ep.event = event;
|
||||||
|
for(uint32_t i = 0; i < MODULE_EVENT_PROXY_MAX_SLOTS; i++) {
|
||||||
|
ep.fns[i] = jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
jerry_value_t proxy = scriptProtoCreateValue(&MODULE_EVENT_PROXY_PROTO, &ep);
|
||||||
|
jerry_object_set(callInfo->this_value, keyStr, proxy);
|
||||||
|
jerry_value_free(keyStr);
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- Init / Dispose ------------------------------------------------------ */
|
||||||
|
|
||||||
|
static void moduleEventProxyInit(void) {
|
||||||
|
scriptProtoInit(
|
||||||
|
&MODULE_EVENT_PROXY_PROTO, NULL,
|
||||||
|
sizeof(jseventproxy_t), NULL
|
||||||
|
);
|
||||||
|
MODULE_EVENT_PROXY_PROTO.info.free_cb = moduleEventProxyFree;
|
||||||
|
|
||||||
|
scriptProtoDefineProp(
|
||||||
|
&MODULE_EVENT_PROXY_PROTO, "0",
|
||||||
|
moduleEventProxyGet0, moduleEventProxySet0
|
||||||
|
);
|
||||||
|
scriptProtoDefineProp(
|
||||||
|
&MODULE_EVENT_PROXY_PROTO, "1",
|
||||||
|
moduleEventProxyGet1, moduleEventProxySet1
|
||||||
|
);
|
||||||
|
scriptProtoDefineProp(
|
||||||
|
&MODULE_EVENT_PROXY_PROTO, "2",
|
||||||
|
moduleEventProxyGet2, moduleEventProxySet2
|
||||||
|
);
|
||||||
|
scriptProtoDefineProp(
|
||||||
|
&MODULE_EVENT_PROXY_PROTO, "3",
|
||||||
|
moduleEventProxyGet3, moduleEventProxySet3
|
||||||
|
);
|
||||||
|
scriptProtoDefineProp(
|
||||||
|
&MODULE_EVENT_PROXY_PROTO, "length",
|
||||||
|
moduleEventProxyGetLength, NULL
|
||||||
|
);
|
||||||
|
scriptProtoDefineToString(
|
||||||
|
&MODULE_EVENT_PROXY_PROTO, moduleEventProxyToString
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void moduleEventProxyDispose(void) {
|
||||||
|
scriptProtoDispose(&MODULE_EVENT_PROXY_PROTO);
|
||||||
|
}
|
||||||
@@ -13,31 +13,17 @@
|
|||||||
|
|
||||||
static scriptproto_t MODULE_VEC3_PROTO;
|
static scriptproto_t MODULE_VEC3_PROTO;
|
||||||
|
|
||||||
/**
|
float_t * moduleVec3Get(const jerry_call_info_t *callInfo) {
|
||||||
* 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(
|
return (float_t *)scriptProtoGetValue(
|
||||||
&MODULE_VEC3_PROTO, callInfo->this_value
|
&MODULE_VEC3_PROTO, callInfo->this_value
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
float_t * moduleVec3From(const jerry_value_t val) {
|
||||||
* 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);
|
return (float_t *)scriptProtoGetValue(&MODULE_VEC3_PROTO, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
jerry_value_t moduleVec3Push(const vec3 v) {
|
||||||
* 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);
|
return scriptProtoCreateValue(&MODULE_VEC3_PROTO, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include "script/module/entity/moduleentity.h"
|
#include "script/module/entity/moduleentity.h"
|
||||||
#include "script/module/input/moduleinput.h"
|
#include "script/module/input/moduleinput.h"
|
||||||
#include "script/module/math/modulevec3.h"
|
#include "script/module/math/modulevec3.h"
|
||||||
|
#include "script/module/require/modulerequire.h"
|
||||||
#include "script/module/scene/modulescene.h"
|
#include "script/module/scene/modulescene.h"
|
||||||
#include "script/module/system/modulesystem.h"
|
#include "script/module/system/modulesystem.h"
|
||||||
|
|
||||||
@@ -31,6 +32,7 @@ static void moduleListInit(void) {
|
|||||||
moduleEntityInit();
|
moduleEntityInit();
|
||||||
moduleComponentListInit();
|
moduleComponentListInit();
|
||||||
moduleInputInit();
|
moduleInputInit();
|
||||||
|
moduleRequireInit();
|
||||||
moduleSceneInit();
|
moduleSceneInit();
|
||||||
moduleSystemInit();
|
moduleSystemInit();
|
||||||
}
|
}
|
||||||
@@ -38,6 +40,7 @@ static void moduleListInit(void) {
|
|||||||
static void moduleListDispose(void) {
|
static void moduleListDispose(void) {
|
||||||
moduleSystemDispose();
|
moduleSystemDispose();
|
||||||
moduleSceneDispose();
|
moduleSceneDispose();
|
||||||
|
moduleRequireDispose();
|
||||||
moduleInputDispose();
|
moduleInputDispose();
|
||||||
moduleComponentListDispose();
|
moduleComponentListDispose();
|
||||||
moduleEntityDispose();
|
moduleEntityDispose();
|
||||||
|
|||||||
@@ -5,5 +5,5 @@
|
|||||||
|
|
||||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
PUBLIC
|
PUBLIC
|
||||||
testscene.c
|
modulerequire.c
|
||||||
)
|
)
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "modulerequire.h"
|
||||||
|
#include "asset/asset.h"
|
||||||
|
#include "asset/assetfile.h"
|
||||||
|
|
||||||
|
jerry_value_t moduleRequireFunc(
|
||||||
|
const jerry_call_info_t *callInfo,
|
||||||
|
const jerry_value_t args[],
|
||||||
|
const jerry_length_t argc
|
||||||
|
) {
|
||||||
|
return jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
jerry_value_t moduleRequireAsyncFunc(
|
||||||
|
const jerry_call_info_t *callInfo,
|
||||||
|
const jerry_value_t args[],
|
||||||
|
const jerry_length_t argc
|
||||||
|
) {
|
||||||
|
return jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
void moduleRequireInit(void) {
|
||||||
|
moduleBaseDefineGlobalMethod("require", moduleRequireFunc);
|
||||||
|
moduleBaseDefineGlobalMethod("requireAsync", moduleRequireAsyncFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void moduleRequireDispose(void) {
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/**
|
||||||
|
* 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"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the require() module system: creates the module cache and
|
||||||
|
* registers the global require() and requireAsync() functions.
|
||||||
|
*/
|
||||||
|
void moduleRequireInit(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disposes of the require() module system, releasing the module cache.
|
||||||
|
*/
|
||||||
|
void moduleRequireDispose(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Records the directory of the script about to be evaluated so that relative
|
||||||
|
* require() paths can be resolved correctly. Call before jerry_eval; pair each
|
||||||
|
* call with moduleRequirePopDir().
|
||||||
|
*
|
||||||
|
* @param filePath Full asset path of the script (e.g. "scripts/Main.js").
|
||||||
|
*/
|
||||||
|
void moduleRequirePushDir(const char_t *filePath);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pops the most recently pushed directory off the resolution stack.
|
||||||
|
*/
|
||||||
|
void moduleRequirePopDir(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates a script source in an isolated module scope.
|
||||||
|
*
|
||||||
|
* Sets up fresh module/exports globals, pushes the directory for nested
|
||||||
|
* require() calls, evaluates the source, then restores everything.
|
||||||
|
*
|
||||||
|
* On success returns module.exports (caller owns the reference).
|
||||||
|
* On eval error returns the exception value (caller must check with
|
||||||
|
* jerry_value_is_exception and free appropriately).
|
||||||
|
*
|
||||||
|
* @param path Full asset path — used only for directory resolution.
|
||||||
|
* @param src Source bytes.
|
||||||
|
* @param size Byte count of src (not including any null terminator).
|
||||||
|
*/
|
||||||
|
jerry_value_t moduleRequireExecModule(
|
||||||
|
const char_t *path,
|
||||||
|
const jerry_char_t *src,
|
||||||
|
const size_t size
|
||||||
|
);
|
||||||
@@ -7,48 +7,17 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "script/module/modulebase.h"
|
#include "script/module/modulebase.h"
|
||||||
|
#include "script/module/asset/moduleassetbatch.h"
|
||||||
#include "script/scriptproto.h"
|
#include "script/scriptproto.h"
|
||||||
#include "scene/scene.h"
|
#include "scene/scene.h"
|
||||||
|
#include "asset/asset.h"
|
||||||
|
#include "asset/loader/assetloader.h"
|
||||||
|
#include "util/memory.h"
|
||||||
|
|
||||||
static scriptproto_t MODULE_SCENE_PROTO;
|
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) {
|
static void moduleSceneInit(void) {
|
||||||
scriptProtoInit(&MODULE_SCENE_PROTO, "Scene", sizeof(uint8_t), NULL);
|
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) {
|
static void moduleSceneDispose(void) {
|
||||||
|
|||||||
Vendored
+86
@@ -0,0 +1,86 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Descriptor for one entry in an `AssetBatch`.
|
||||||
|
*
|
||||||
|
* `format` — texture format constant (`Texture.FORMAT_*`). Alias for `input`
|
||||||
|
* when the type is `Asset.TYPE_TEXTURE`.
|
||||||
|
* `axis` — mesh axis constant (`Asset.MESH_AXIS_*`). Alias for `input`
|
||||||
|
* when the type is `Asset.TYPE_MESH`.
|
||||||
|
* `input` — generic numeric input for all other loader types.
|
||||||
|
*/
|
||||||
|
interface AssetBatchDescriptor {
|
||||||
|
path: string;
|
||||||
|
type: number;
|
||||||
|
format?: number;
|
||||||
|
axis?: number;
|
||||||
|
input?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A group of asset entries locked and queued for loading together. */
|
||||||
|
interface AssetBatch {
|
||||||
|
/** Number of entries in the batch. */
|
||||||
|
readonly count: number;
|
||||||
|
/** `true` when every entry has reached `LOADED`. */
|
||||||
|
readonly isLoaded: boolean;
|
||||||
|
/** `true` if any entry is in an `ERROR` state. */
|
||||||
|
readonly hasError: boolean;
|
||||||
|
/**
|
||||||
|
* Blocks until every entry is loaded.
|
||||||
|
* Returns `this` for chaining.
|
||||||
|
* @throws If any entry fails to load.
|
||||||
|
*/
|
||||||
|
requireLoaded(): this;
|
||||||
|
/**
|
||||||
|
* Acquires one additional lock on every entry.
|
||||||
|
* Returns `this` for chaining.
|
||||||
|
*/
|
||||||
|
lock(): this;
|
||||||
|
/**
|
||||||
|
* Releases all locks and clears the batch.
|
||||||
|
* After this call the object is invalid — do not use it again.
|
||||||
|
*/
|
||||||
|
unlock(): void;
|
||||||
|
/**
|
||||||
|
* Returns the `AssetEntry` at `index`, adding an independent lock.
|
||||||
|
* The returned entry must be unlocked separately when no longer needed.
|
||||||
|
* Returns `undefined` if `index` is out of range or the batch is disposed.
|
||||||
|
*/
|
||||||
|
entry(index: number): AssetEntry | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires once when every entry has loaded successfully.
|
||||||
|
* Subscribe with `onLoaded[0] = () => { ... }`.
|
||||||
|
*/
|
||||||
|
readonly onLoaded: AssetEventProxy;
|
||||||
|
/**
|
||||||
|
* Fires each time a single entry finishes loading.
|
||||||
|
* Subscribe with `onEntryLoaded[0] = () => { ... }`.
|
||||||
|
*/
|
||||||
|
readonly onEntryLoaded: AssetEventProxy;
|
||||||
|
/**
|
||||||
|
* Fires once when all entries have finished but at least one errored.
|
||||||
|
* Subscribe with `onError[0] = () => { ... }`.
|
||||||
|
*/
|
||||||
|
readonly onError: AssetEventProxy;
|
||||||
|
/**
|
||||||
|
* Fires each time a single entry transitions to an error state.
|
||||||
|
* Subscribe with `onEntryError[0] = () => { ... }`.
|
||||||
|
*/
|
||||||
|
readonly onEntryError: AssetEventProxy;
|
||||||
|
|
||||||
|
toString(): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AssetBatchConstructor {
|
||||||
|
/** Creates a batch from an array of descriptors. Works with or without `new`. */
|
||||||
|
(descriptors: AssetBatchDescriptor[]): AssetBatch;
|
||||||
|
new(descriptors: AssetBatchDescriptor[]): AssetBatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare var AssetBatch: AssetBatchConstructor;
|
||||||
Vendored
+24
@@ -5,6 +5,24 @@
|
|||||||
* https://opensource.org/licenses/MIT
|
* https://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array-like proxy over one of an asset entry's events.
|
||||||
|
* Assign a function to a numbered slot to subscribe; assign `null` to
|
||||||
|
* unsubscribe that slot.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* entry.onLoaded[0] = () => Console.print('loaded!');
|
||||||
|
* entry.onLoaded[0] = null; // unsubscribe
|
||||||
|
*/
|
||||||
|
interface AssetEventProxy {
|
||||||
|
readonly length: number;
|
||||||
|
0: (() => void) | null;
|
||||||
|
1: (() => void) | null;
|
||||||
|
2: (() => void) | null;
|
||||||
|
3: (() => void) | null;
|
||||||
|
toString(): string;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A live reference to an entry in the asset cache.
|
* A live reference to an entry in the asset cache.
|
||||||
* Holds a lock that keeps the entry alive; the lock is released automatically
|
* Holds a lock that keeps the entry alive; the lock is released automatically
|
||||||
@@ -26,6 +44,12 @@ interface AssetEntry {
|
|||||||
* is not yet loaded.
|
* is not yet loaded.
|
||||||
*/
|
*/
|
||||||
readonly texture: Texture | undefined;
|
readonly texture: Texture | undefined;
|
||||||
|
/** Event proxy — subscribe up to 4 callbacks for when loading completes. */
|
||||||
|
readonly onLoaded: AssetEventProxy;
|
||||||
|
/** Event proxy — subscribe up to 4 callbacks for when the entry is disposed. */
|
||||||
|
readonly onUnloaded: AssetEventProxy;
|
||||||
|
/** Event proxy — subscribe up to 4 callbacks for when loading fails. */
|
||||||
|
readonly onError: AssetEventProxy;
|
||||||
/**
|
/**
|
||||||
* Blocks until the entry reaches `LOADED` (or `ERROR`).
|
* Blocks until the entry reaches `LOADED` (or `ERROR`).
|
||||||
* Returns `this` for chaining.
|
* Returns `this` for chaining.
|
||||||
|
|||||||
Vendored
+4
@@ -14,6 +14,9 @@
|
|||||||
* { "compilerOptions": { "typeRoots": ["./types"] } }
|
* { "compilerOptions": { "typeRoots": ["./types"] } }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// module system
|
||||||
|
/// <reference path="./require.d.ts" />
|
||||||
|
|
||||||
// math
|
// math
|
||||||
/// <reference path="./math/vec3.d.ts" />
|
/// <reference path="./math/vec3.d.ts" />
|
||||||
|
|
||||||
@@ -24,6 +27,7 @@
|
|||||||
|
|
||||||
// asset
|
// asset
|
||||||
/// <reference path="./asset/assetentry.d.ts" />
|
/// <reference path="./asset/assetentry.d.ts" />
|
||||||
|
/// <reference path="./asset/assetbatch.d.ts" />
|
||||||
/// <reference path="./asset/asset.d.ts" />
|
/// <reference path="./asset/asset.d.ts" />
|
||||||
|
|
||||||
// engine systems
|
// engine systems
|
||||||
|
|||||||
Vendored
+69
@@ -0,0 +1,69 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CommonJS-style module loader. Accepts a single path or an array of paths.
|
||||||
|
*
|
||||||
|
* - Single string → returns that module's `exports`.
|
||||||
|
* - Array of strings → returns an array of `exports` in the same order.
|
||||||
|
*
|
||||||
|
* Modules are cached after their first load. Subsequent calls with the same
|
||||||
|
* resolved path return the cached exports without re-executing the file.
|
||||||
|
*
|
||||||
|
* Path rules: `"./foo"` / `"../foo"` resolve relative to the calling script's
|
||||||
|
* directory; any other string resolves from the archive root. `.js` is
|
||||||
|
* appended automatically when missing.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const NPC = require('./entities/NPC');
|
||||||
|
* const [NPC, Item] = require(['./entities/NPC', './entities/Item']);
|
||||||
|
*/
|
||||||
|
declare function require(path: string): any;
|
||||||
|
declare function require(paths: string[]): any[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asynchronous module loader. Accepts a single path or an array of paths.
|
||||||
|
* The asset file(s) are read in the background; once all are loaded and
|
||||||
|
* evaluated, `callback` is invoked.
|
||||||
|
*
|
||||||
|
* - Single string → `callback(exports)` — first argument is the module's
|
||||||
|
* `exports`, or `null` on load failure.
|
||||||
|
* - Array of strings → `callback(exportsArray)` — first argument is an array
|
||||||
|
* of `exports` values in the same order; failed entries are `null`.
|
||||||
|
*
|
||||||
|
* Cached modules resolve synchronously (callback fires on the same call).
|
||||||
|
* Path rules are identical to `require`.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* requireAsync('./entities/NPC', function(NPC) {
|
||||||
|
* if(NPC) NPC.init();
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* requireAsync(['./entities/NPC', './entities/Item'], function(mods) {
|
||||||
|
* const [NPC, Item] = mods;
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
declare function requireAsync(
|
||||||
|
path: string,
|
||||||
|
callback: (exports: any) => void
|
||||||
|
): void;
|
||||||
|
declare function requireAsync(
|
||||||
|
paths: string[],
|
||||||
|
callback: (exports: any[]) => void
|
||||||
|
): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The module object for the currently executing script.
|
||||||
|
* Assign `module.exports` to control what `require()` returns to callers.
|
||||||
|
*/
|
||||||
|
declare var module: { exports: any };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shorthand for `module.exports`. Direct assignment (`exports = ...`) does
|
||||||
|
* NOT update `module.exports`; use `module.exports = ...` for that.
|
||||||
|
*/
|
||||||
|
declare var exports: any;
|
||||||
Vendored
+37
-11
@@ -5,23 +5,49 @@
|
|||||||
* https://opensource.org/licenses/MIT
|
* https://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** Scene management — request scene transitions and query the active scene. */
|
/**
|
||||||
|
* The object a JS scene module must export.
|
||||||
|
* All methods are optional.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // assets/scenes/game.js
|
||||||
|
* var scene = {};
|
||||||
|
* var batch = AssetBatch([{ path: 'tex/bg.png', type: Asset.TYPE_TEXTURE }]);
|
||||||
|
*
|
||||||
|
* scene.load = function() { return batch; };
|
||||||
|
* scene.init = function() { Console.print('scene started'); };
|
||||||
|
* scene.update = function() { /* per-frame logic *\/ };
|
||||||
|
* scene.dispose = function() { batch.unlock(); };
|
||||||
|
*
|
||||||
|
* module.exports = scene;
|
||||||
|
*/
|
||||||
|
interface SceneObject {
|
||||||
|
/** Return an AssetBatch to preload before init is called. Optional. */
|
||||||
|
load?(): AssetBatch | undefined;
|
||||||
|
/** Called when this scene becomes active. Optional. */
|
||||||
|
init?(): void;
|
||||||
|
/** Called every frame while this scene is active. Optional. */
|
||||||
|
update?(): void;
|
||||||
|
/** Called when the scene is replaced or the engine shuts down. Optional. */
|
||||||
|
dispose?(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Scene management. */
|
||||||
interface SceneNamespace {
|
interface SceneNamespace {
|
||||||
/** Type constant of the currently active scene, or 0 if none. */
|
/** `true` while a JS script scene is running. */
|
||||||
readonly current: number;
|
readonly active: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requests a scene transition. The change takes effect at the start of the
|
* Loads the JS module at `path`, waits for any `AssetBatch` returned by
|
||||||
* next safe update tick (current scene is disposed, new scene is initialized).
|
* `scene.load()`, then activates the scene (calling `scene.init()`).
|
||||||
|
* The previous scene's `dispose()` is called just before `init()`.
|
||||||
|
*
|
||||||
|
* Returns immediately — the transition is asynchronous.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* Scene.set(Scene.OVERWORLD);
|
* Scene.set('assets/scenes/game.js');
|
||||||
*/
|
*/
|
||||||
set(type: number): void;
|
set(path: string): void;
|
||||||
|
|
||||||
readonly INITIAL: number;
|
|
||||||
readonly TEST: number;
|
|
||||||
readonly OVERWORLD: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare var Scene: SceneNamespace;
|
declare var Scene: SceneNamespace;
|
||||||
|
|||||||
Reference in New Issue
Block a user