Want to test this in PSP
This commit is contained in:
@@ -1,3 +1,8 @@
|
|||||||
|
// Copyright (c) 2026 Dominic Masters
|
||||||
|
//
|
||||||
|
// This software is released under the MIT License.
|
||||||
|
// https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
const platformNames = {
|
const platformNames = {
|
||||||
[System.PLATFORM_LINUX]: 'Linux',
|
[System.PLATFORM_LINUX]: 'Linux',
|
||||||
[System.PLATFORM_KNULLI]: 'Knulli',
|
[System.PLATFORM_KNULLI]: 'Knulli',
|
||||||
@@ -8,6 +13,8 @@ const platformNames = {
|
|||||||
|
|
||||||
Console.print('Platform: ' + (platformNames[System.platform] || 'Unknown'));
|
Console.print('Platform: ' + (platformNames[System.platform] || 'Unknown'));
|
||||||
|
|
||||||
|
UIFullboxOver.setColor(Color.BLACK);
|
||||||
|
|
||||||
requireAsync('testscene.js').then(Scene.set).catch(err => {
|
requireAsync('testscene.js').then(Scene.set).catch(err => {
|
||||||
Console.print('Error loading scene: ' + err);
|
Console.print('Error loading scene: ' + err);
|
||||||
Engine.exit();
|
Engine.exit();
|
||||||
|
|||||||
+4
-2
@@ -18,7 +18,7 @@ scene.init = async function() {
|
|||||||
var cam = scene.cam.add(Component.CAMERA);
|
var cam = scene.cam.add(Component.CAMERA);
|
||||||
camPos.localPosition = new Vec3(3, 3, 3);
|
camPos.localPosition = new Vec3(3, 3, 3);
|
||||||
camPos.lookAt(new Vec3(0, 0, 0));
|
camPos.lookAt(new Vec3(0, 0, 0));
|
||||||
|
|
||||||
// Floor - large flat slab, no texture needed.
|
// Floor - large flat slab, no texture needed.
|
||||||
scene.floor = Entity.create();
|
scene.floor = Entity.create();
|
||||||
var floorPos = scene.floor.add(Component.POSITION);
|
var floorPos = scene.floor.add(Component.POSITION);
|
||||||
@@ -27,6 +27,8 @@ scene.init = async function() {
|
|||||||
floorR.color = Color.BLUE;
|
floorR.color = Color.BLUE;
|
||||||
// floorPos.localScale = new Vec3(16, 0.2, 16);
|
// floorPos.localScale = new Vec3(16, 0.2, 16);
|
||||||
// floorPos.localPosition = new Vec3(0, -0.1, 0);
|
// floorPos.localPosition = new Vec3(0, -0.1, 0);
|
||||||
|
|
||||||
|
await UIFullboxOver.transition(Color.BLACK, Color.TRANSPARENT, 1.0);
|
||||||
};
|
};
|
||||||
|
|
||||||
scene.update = function() {
|
scene.update = function() {
|
||||||
@@ -37,4 +39,4 @@ scene.dispose = function() {
|
|||||||
Entity.dispose(scene.cam);
|
Entity.dispose(scene.cam);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = scene;
|
module.exports = scene;
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
PUBLIC
|
PUBLIC
|
||||||
script.c
|
script.c
|
||||||
|
scriptpromisepend.c
|
||||||
scriptproto.c
|
scriptproto.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -8,61 +8,35 @@
|
|||||||
#include "moduleassetbatch.h"
|
#include "moduleassetbatch.h"
|
||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
|
|
||||||
#define ASSET_BATCH_LOADED_MAX 8
|
#define ASSET_BATCH_PEND_MAX 8
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
assetbatch_t *batch;
|
|
||||||
jerry_value_t promise;
|
|
||||||
} assetbatchloadedpend_t;
|
|
||||||
|
|
||||||
scriptproto_t MODULE_ASSET_BATCH_PROTO;
|
scriptproto_t MODULE_ASSET_BATCH_PROTO;
|
||||||
|
|
||||||
static assetbatchloadedpend_t ASSET_BATCH_LOADED[ASSET_BATCH_LOADED_MAX];
|
static scriptpromisepend_t ASSET_BATCH_PEND[ASSET_BATCH_PEND_MAX];
|
||||||
static uint32_t ASSET_BATCH_LOADED_COUNT = 0;
|
static uint32_t ASSET_BATCH_PEND_COUNT = 0;
|
||||||
|
|
||||||
static void assetBatchOnLoadedFire(void *params, void *user);
|
void assetBatchOnLoadedFire(void *params, void *user) {
|
||||||
static void assetBatchOnErrorFire(void *params, void *user);
|
|
||||||
|
|
||||||
static void assetBatchOnLoadedFire(void *params, void *user) {
|
|
||||||
assetbatch_t *batch = (assetbatch_t *)user;
|
assetbatch_t *batch = (assetbatch_t *)user;
|
||||||
uint32_t i = 0;
|
jerry_value_t undef = jerry_undefined();
|
||||||
while(i < ASSET_BATCH_LOADED_COUNT) {
|
uint32_t n = scriptPromisePendResolve(
|
||||||
if(ASSET_BATCH_LOADED[i].batch != batch) { i++; continue; }
|
ASSET_BATCH_PEND, &ASSET_BATCH_PEND_COUNT, batch, undef
|
||||||
jerry_value_t undef = jerry_undefined();
|
);
|
||||||
jerry_value_t r = jerry_promise_resolve(
|
jerry_value_free(undef);
|
||||||
ASSET_BATCH_LOADED[i].promise, undef
|
if(!n) return;
|
||||||
);
|
eventUnsubscribe(&batch->onLoaded, assetBatchOnLoadedFire);
|
||||||
jerry_value_free(undef);
|
|
||||||
jerry_value_free(r);
|
|
||||||
jerry_value_free(ASSET_BATCH_LOADED[i].promise);
|
|
||||||
ASSET_BATCH_LOADED_COUNT--;
|
|
||||||
if(i < ASSET_BATCH_LOADED_COUNT) {
|
|
||||||
ASSET_BATCH_LOADED[i] =
|
|
||||||
ASSET_BATCH_LOADED[ASSET_BATCH_LOADED_COUNT];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
eventUnsubscribe(&batch->onError, assetBatchOnErrorFire);
|
eventUnsubscribe(&batch->onError, assetBatchOnErrorFire);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void assetBatchOnErrorFire(void *params, void *user) {
|
void assetBatchOnErrorFire(void *params, void *user) {
|
||||||
assetbatch_t *batch = (assetbatch_t *)user;
|
assetbatch_t *batch = (assetbatch_t *)user;
|
||||||
uint32_t i = 0;
|
jerry_value_t err = jerry_string_sz("Asset batch failed to load");
|
||||||
while(i < ASSET_BATCH_LOADED_COUNT) {
|
uint32_t n = scriptPromisePendReject(
|
||||||
if(ASSET_BATCH_LOADED[i].batch != batch) { i++; continue; }
|
ASSET_BATCH_PEND, &ASSET_BATCH_PEND_COUNT, batch, err
|
||||||
jerry_value_t err = jerry_string_sz("Asset batch failed to load");
|
);
|
||||||
jerry_value_t r = jerry_promise_reject(
|
jerry_value_free(err);
|
||||||
ASSET_BATCH_LOADED[i].promise, err
|
if(!n) return;
|
||||||
);
|
|
||||||
jerry_value_free(err);
|
|
||||||
jerry_value_free(r);
|
|
||||||
jerry_value_free(ASSET_BATCH_LOADED[i].promise);
|
|
||||||
ASSET_BATCH_LOADED_COUNT--;
|
|
||||||
if(i < ASSET_BATCH_LOADED_COUNT) {
|
|
||||||
ASSET_BATCH_LOADED[i] =
|
|
||||||
ASSET_BATCH_LOADED[ASSET_BATCH_LOADED_COUNT];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
eventUnsubscribe(&batch->onLoaded, assetBatchOnLoadedFire);
|
eventUnsubscribe(&batch->onLoaded, assetBatchOnLoadedFire);
|
||||||
|
eventUnsubscribe(&batch->onError, assetBatchOnErrorFire);
|
||||||
}
|
}
|
||||||
|
|
||||||
void moduleAssetBatchFree(void *ptr, jerry_object_native_info_t *info) {
|
void moduleAssetBatchFree(void *ptr, jerry_object_native_info_t *info) {
|
||||||
@@ -217,18 +191,14 @@ moduleBaseFunction(moduleAssetBatchLoaded) {
|
|||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ASSET_BATCH_LOADED_COUNT >= ASSET_BATCH_LOADED_MAX) {
|
if(ASSET_BATCH_PEND_COUNT >= ASSET_BATCH_PEND_MAX) {
|
||||||
jerry_value_free(promise);
|
jerry_value_free(promise);
|
||||||
return moduleBaseThrow("AssetBatch.loaded: too many pending");
|
return moduleBaseThrow("AssetBatch.loaded: too many pending");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool_t subscribed = false;
|
if(!scriptPromisePendHas(
|
||||||
for(uint32_t i = 0; i < ASSET_BATCH_LOADED_COUNT; i++) {
|
ASSET_BATCH_PEND, ASSET_BATCH_PEND_COUNT, b->batch
|
||||||
if(ASSET_BATCH_LOADED[i].batch == b->batch) {
|
)) {
|
||||||
subscribed = true; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!subscribed) {
|
|
||||||
eventSubscribe(
|
eventSubscribe(
|
||||||
&b->batch->onLoaded, assetBatchOnLoadedFire, b->batch
|
&b->batch->onLoaded, assetBatchOnLoadedFire, b->batch
|
||||||
);
|
);
|
||||||
@@ -237,10 +207,10 @@ moduleBaseFunction(moduleAssetBatchLoaded) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSET_BATCH_LOADED[ASSET_BATCH_LOADED_COUNT].batch = b->batch;
|
scriptPromisePendAdd(
|
||||||
ASSET_BATCH_LOADED[ASSET_BATCH_LOADED_COUNT].promise =
|
ASSET_BATCH_PEND, &ASSET_BATCH_PEND_COUNT,
|
||||||
jerry_value_copy(promise);
|
ASSET_BATCH_PEND_MAX, b->batch, promise
|
||||||
ASSET_BATCH_LOADED_COUNT++;
|
);
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,7 +309,7 @@ moduleBaseFunction(moduleAssetBatchToString) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void moduleAssetBatchInit(void) {
|
void moduleAssetBatchInit(void) {
|
||||||
ASSET_BATCH_LOADED_COUNT = 0;
|
ASSET_BATCH_PEND_COUNT = 0;
|
||||||
scriptProtoInit(
|
scriptProtoInit(
|
||||||
&MODULE_ASSET_BATCH_PROTO, "AssetBatch",
|
&MODULE_ASSET_BATCH_PROTO, "AssetBatch",
|
||||||
sizeof(jsassetbatch_t), moduleAssetBatchCtor
|
sizeof(jsassetbatch_t), moduleAssetBatchCtor
|
||||||
@@ -400,25 +370,19 @@ void moduleAssetBatchInit(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void moduleAssetBatchDispose(void) {
|
void moduleAssetBatchDispose(void) {
|
||||||
for(uint32_t i = 0; i < ASSET_BATCH_LOADED_COUNT; i++) {
|
for(uint32_t i = 0; i < ASSET_BATCH_PEND_COUNT; i++) {
|
||||||
bool_t seen = false;
|
bool_t seen = false;
|
||||||
for(uint32_t j = 0; j < i; j++) {
|
for(uint32_t j = 0; j < i; j++) {
|
||||||
if(ASSET_BATCH_LOADED[j].batch == ASSET_BATCH_LOADED[i].batch) {
|
if(ASSET_BATCH_PEND[j].key == ASSET_BATCH_PEND[i].key) {
|
||||||
seen = true; break;
|
seen = true; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!seen) {
|
if(!seen) {
|
||||||
eventUnsubscribe(
|
assetbatch_t *b = (assetbatch_t *)ASSET_BATCH_PEND[i].key;
|
||||||
&ASSET_BATCH_LOADED[i].batch->onLoaded,
|
eventUnsubscribe(&b->onLoaded, assetBatchOnLoadedFire);
|
||||||
assetBatchOnLoadedFire
|
eventUnsubscribe(&b->onError, assetBatchOnErrorFire);
|
||||||
);
|
|
||||||
eventUnsubscribe(
|
|
||||||
&ASSET_BATCH_LOADED[i].batch->onError,
|
|
||||||
assetBatchOnErrorFire
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
jerry_value_free(ASSET_BATCH_LOADED[i].promise);
|
|
||||||
}
|
}
|
||||||
ASSET_BATCH_LOADED_COUNT = 0;
|
scriptPromisePendFreeAll(ASSET_BATCH_PEND, &ASSET_BATCH_PEND_COUNT);
|
||||||
scriptProtoDispose(&MODULE_ASSET_BATCH_PROTO);
|
scriptProtoDispose(&MODULE_ASSET_BATCH_PROTO);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "script/module/modulebase.h"
|
#include "script/module/modulebase.h"
|
||||||
#include "script/scriptproto.h"
|
#include "script/scriptproto.h"
|
||||||
|
#include "script/scriptpromisepend.h"
|
||||||
#include "script/module/asset/moduleassetentry.h"
|
#include "script/module/asset/moduleassetentry.h"
|
||||||
#include "asset/assetbatch.h"
|
#include "asset/assetbatch.h"
|
||||||
#include "asset/asset.h"
|
#include "asset/asset.h"
|
||||||
@@ -21,6 +22,24 @@ typedef struct {
|
|||||||
assetbatch_t *batch;
|
assetbatch_t *batch;
|
||||||
} jsassetbatch_t;
|
} jsassetbatch_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves all pending loaded() promises for this batch, then
|
||||||
|
* unsubscribes from both onLoaded and onError.
|
||||||
|
*
|
||||||
|
* @param params Unused.
|
||||||
|
* @param user The assetbatch_t pointer that finished loading.
|
||||||
|
*/
|
||||||
|
void assetBatchOnLoadedFire(void *params, void *user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rejects all pending loaded() promises for this batch, then
|
||||||
|
* unsubscribes from both onLoaded and onError.
|
||||||
|
*
|
||||||
|
* @param params Unused.
|
||||||
|
* @param user The assetbatch_t pointer that errored.
|
||||||
|
*/
|
||||||
|
void assetBatchOnErrorFire(void *params, void *user);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GC free callback - disposes and frees the batch when the JS object is
|
* GC free callback - disposes and frees the batch when the JS object is
|
||||||
* garbage collected.
|
* garbage collected.
|
||||||
|
|||||||
@@ -7,61 +7,35 @@
|
|||||||
|
|
||||||
#include "moduleassetentry.h"
|
#include "moduleassetentry.h"
|
||||||
|
|
||||||
#define ASSET_ENTRY_LOADED_MAX 16
|
#define ASSET_ENTRY_PEND_MAX 16
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
assetentry_t *entry;
|
|
||||||
jerry_value_t promise;
|
|
||||||
} assetentryloadedpend_t;
|
|
||||||
|
|
||||||
scriptproto_t MODULE_ASSET_ENTRY_PROTO;
|
scriptproto_t MODULE_ASSET_ENTRY_PROTO;
|
||||||
|
|
||||||
static assetentryloadedpend_t ASSET_ENTRY_LOADED[ASSET_ENTRY_LOADED_MAX];
|
static scriptpromisepend_t ASSET_ENTRY_PEND[ASSET_ENTRY_PEND_MAX];
|
||||||
static uint32_t ASSET_ENTRY_LOADED_COUNT = 0;
|
static uint32_t ASSET_ENTRY_PEND_COUNT = 0;
|
||||||
|
|
||||||
static void assetEntryOnLoadedFire(void *params, void *user);
|
void assetEntryOnLoadedFire(void *params, void *user) {
|
||||||
static void assetEntryOnErrorFire(void *params, void *user);
|
|
||||||
|
|
||||||
static void assetEntryOnLoadedFire(void *params, void *user) {
|
|
||||||
assetentry_t *entry = (assetentry_t *)user;
|
assetentry_t *entry = (assetentry_t *)user;
|
||||||
uint32_t i = 0;
|
jerry_value_t undef = jerry_undefined();
|
||||||
while(i < ASSET_ENTRY_LOADED_COUNT) {
|
uint32_t n = scriptPromisePendResolve(
|
||||||
if(ASSET_ENTRY_LOADED[i].entry != entry) { i++; continue; }
|
ASSET_ENTRY_PEND, &ASSET_ENTRY_PEND_COUNT, entry, undef
|
||||||
jerry_value_t undef = jerry_undefined();
|
);
|
||||||
jerry_value_t r = jerry_promise_resolve(
|
jerry_value_free(undef);
|
||||||
ASSET_ENTRY_LOADED[i].promise, undef
|
if(!n) return;
|
||||||
);
|
eventUnsubscribe(&entry->onLoaded, assetEntryOnLoadedFire);
|
||||||
jerry_value_free(undef);
|
|
||||||
jerry_value_free(r);
|
|
||||||
jerry_value_free(ASSET_ENTRY_LOADED[i].promise);
|
|
||||||
ASSET_ENTRY_LOADED_COUNT--;
|
|
||||||
if(i < ASSET_ENTRY_LOADED_COUNT) {
|
|
||||||
ASSET_ENTRY_LOADED[i] =
|
|
||||||
ASSET_ENTRY_LOADED[ASSET_ENTRY_LOADED_COUNT];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
eventUnsubscribe(&entry->onError, assetEntryOnErrorFire);
|
eventUnsubscribe(&entry->onError, assetEntryOnErrorFire);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void assetEntryOnErrorFire(void *params, void *user) {
|
void assetEntryOnErrorFire(void *params, void *user) {
|
||||||
assetentry_t *entry = (assetentry_t *)user;
|
assetentry_t *entry = (assetentry_t *)user;
|
||||||
uint32_t i = 0;
|
jerry_value_t err = jerry_string_sz("Asset failed to load");
|
||||||
while(i < ASSET_ENTRY_LOADED_COUNT) {
|
uint32_t n = scriptPromisePendReject(
|
||||||
if(ASSET_ENTRY_LOADED[i].entry != entry) { i++; continue; }
|
ASSET_ENTRY_PEND, &ASSET_ENTRY_PEND_COUNT, entry, err
|
||||||
jerry_value_t err = jerry_string_sz("Asset failed to load");
|
);
|
||||||
jerry_value_t r = jerry_promise_reject(
|
jerry_value_free(err);
|
||||||
ASSET_ENTRY_LOADED[i].promise, err
|
if(!n) return;
|
||||||
);
|
|
||||||
jerry_value_free(err);
|
|
||||||
jerry_value_free(r);
|
|
||||||
jerry_value_free(ASSET_ENTRY_LOADED[i].promise);
|
|
||||||
ASSET_ENTRY_LOADED_COUNT--;
|
|
||||||
if(i < ASSET_ENTRY_LOADED_COUNT) {
|
|
||||||
ASSET_ENTRY_LOADED[i] =
|
|
||||||
ASSET_ENTRY_LOADED[ASSET_ENTRY_LOADED_COUNT];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
eventUnsubscribe(&entry->onLoaded, assetEntryOnLoadedFire);
|
eventUnsubscribe(&entry->onLoaded, assetEntryOnLoadedFire);
|
||||||
|
eventUnsubscribe(&entry->onError, assetEntryOnErrorFire);
|
||||||
}
|
}
|
||||||
|
|
||||||
void moduleAssetEntryFree(void *ptr, jerry_object_native_info_t *info) {
|
void moduleAssetEntryFree(void *ptr, jerry_object_native_info_t *info) {
|
||||||
@@ -164,9 +138,7 @@ moduleBaseFunction(moduleAssetEntryLoaded) {
|
|||||||
if(!e || !e->entry) {
|
if(!e || !e->entry) {
|
||||||
return moduleBaseThrow("AssetEntry.loaded: invalid entry");
|
return moduleBaseThrow("AssetEntry.loaded: invalid entry");
|
||||||
}
|
}
|
||||||
|
|
||||||
jerry_value_t promise = jerry_promise();
|
jerry_value_t promise = jerry_promise();
|
||||||
|
|
||||||
if(e->entry->state == ASSET_ENTRY_STATE_LOADED) {
|
if(e->entry->state == ASSET_ENTRY_STATE_LOADED) {
|
||||||
jerry_value_t undef = jerry_undefined();
|
jerry_value_t undef = jerry_undefined();
|
||||||
jerry_value_t r = jerry_promise_resolve(promise, undef);
|
jerry_value_t r = jerry_promise_resolve(promise, undef);
|
||||||
@@ -174,7 +146,6 @@ moduleBaseFunction(moduleAssetEntryLoaded) {
|
|||||||
jerry_value_free(r);
|
jerry_value_free(r);
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(e->entry->state == ASSET_ENTRY_STATE_ERROR) {
|
if(e->entry->state == ASSET_ENTRY_STATE_ERROR) {
|
||||||
jerry_value_t err = jerry_string_sz("Asset failed to load");
|
jerry_value_t err = jerry_string_sz("Asset failed to load");
|
||||||
jerry_value_t r = jerry_promise_reject(promise, err);
|
jerry_value_t r = jerry_promise_reject(promise, err);
|
||||||
@@ -182,19 +153,13 @@ moduleBaseFunction(moduleAssetEntryLoaded) {
|
|||||||
jerry_value_free(r);
|
jerry_value_free(r);
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
if(ASSET_ENTRY_PEND_COUNT >= ASSET_ENTRY_PEND_MAX) {
|
||||||
if(ASSET_ENTRY_LOADED_COUNT >= ASSET_ENTRY_LOADED_MAX) {
|
|
||||||
jerry_value_free(promise);
|
jerry_value_free(promise);
|
||||||
return moduleBaseThrow("AssetEntry.loaded: too many pending");
|
return moduleBaseThrow("AssetEntry.loaded: too many pending");
|
||||||
}
|
}
|
||||||
|
if(!scriptPromisePendHas(
|
||||||
bool_t subscribed = false;
|
ASSET_ENTRY_PEND, ASSET_ENTRY_PEND_COUNT, e->entry
|
||||||
for(uint32_t i = 0; i < ASSET_ENTRY_LOADED_COUNT; i++) {
|
)) {
|
||||||
if(ASSET_ENTRY_LOADED[i].entry == e->entry) {
|
|
||||||
subscribed = true; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!subscribed) {
|
|
||||||
eventSubscribe(
|
eventSubscribe(
|
||||||
&e->entry->onLoaded, assetEntryOnLoadedFire, e->entry
|
&e->entry->onLoaded, assetEntryOnLoadedFire, e->entry
|
||||||
);
|
);
|
||||||
@@ -202,11 +167,10 @@ moduleBaseFunction(moduleAssetEntryLoaded) {
|
|||||||
&e->entry->onError, assetEntryOnErrorFire, e->entry
|
&e->entry->onError, assetEntryOnErrorFire, e->entry
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
scriptPromisePendAdd(
|
||||||
ASSET_ENTRY_LOADED[ASSET_ENTRY_LOADED_COUNT].entry = e->entry;
|
ASSET_ENTRY_PEND, &ASSET_ENTRY_PEND_COUNT,
|
||||||
ASSET_ENTRY_LOADED[ASSET_ENTRY_LOADED_COUNT].promise =
|
ASSET_ENTRY_PEND_MAX, e->entry, promise
|
||||||
jerry_value_copy(promise);
|
);
|
||||||
ASSET_ENTRY_LOADED_COUNT++;
|
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,7 +183,7 @@ moduleBaseFunction(moduleAssetEntryToString) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void moduleAssetEntryInit(void) {
|
void moduleAssetEntryInit(void) {
|
||||||
ASSET_ENTRY_LOADED_COUNT = 0;
|
ASSET_ENTRY_PEND_COUNT = 0;
|
||||||
scriptProtoInit(
|
scriptProtoInit(
|
||||||
&MODULE_ASSET_ENTRY_PROTO, "AssetEntry",
|
&MODULE_ASSET_ENTRY_PROTO, "AssetEntry",
|
||||||
sizeof(jsassetentry_t), moduleAssetEntryCtor
|
sizeof(jsassetentry_t), moduleAssetEntryCtor
|
||||||
@@ -287,25 +251,19 @@ void moduleAssetEntryInit(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void moduleAssetEntryDispose(void) {
|
void moduleAssetEntryDispose(void) {
|
||||||
for(uint32_t i = 0; i < ASSET_ENTRY_LOADED_COUNT; i++) {
|
for(uint32_t i = 0; i < ASSET_ENTRY_PEND_COUNT; i++) {
|
||||||
bool_t seen = false;
|
bool_t seen = false;
|
||||||
for(uint32_t j = 0; j < i; j++) {
|
for(uint32_t j = 0; j < i; j++) {
|
||||||
if(ASSET_ENTRY_LOADED[j].entry == ASSET_ENTRY_LOADED[i].entry) {
|
if(ASSET_ENTRY_PEND[j].key == ASSET_ENTRY_PEND[i].key) {
|
||||||
seen = true; break;
|
seen = true; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!seen) {
|
if(!seen) {
|
||||||
eventUnsubscribe(
|
assetentry_t *e = (assetentry_t *)ASSET_ENTRY_PEND[i].key;
|
||||||
&ASSET_ENTRY_LOADED[i].entry->onLoaded,
|
eventUnsubscribe(&e->onLoaded, assetEntryOnLoadedFire);
|
||||||
assetEntryOnLoadedFire
|
eventUnsubscribe(&e->onError, assetEntryOnErrorFire);
|
||||||
);
|
|
||||||
eventUnsubscribe(
|
|
||||||
&ASSET_ENTRY_LOADED[i].entry->onError,
|
|
||||||
assetEntryOnErrorFire
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
jerry_value_free(ASSET_ENTRY_LOADED[i].promise);
|
|
||||||
}
|
}
|
||||||
ASSET_ENTRY_LOADED_COUNT = 0;
|
scriptPromisePendFreeAll(ASSET_ENTRY_PEND, &ASSET_ENTRY_PEND_COUNT);
|
||||||
scriptProtoDispose(&MODULE_ASSET_ENTRY_PROTO);
|
scriptProtoDispose(&MODULE_ASSET_ENTRY_PROTO);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "script/module/modulebase.h"
|
#include "script/module/modulebase.h"
|
||||||
#include "script/scriptproto.h"
|
#include "script/scriptproto.h"
|
||||||
|
#include "script/scriptpromisepend.h"
|
||||||
#include "script/module/display/moduletexture.h"
|
#include "script/module/display/moduletexture.h"
|
||||||
#include "script/module/event/moduleevent.h"
|
#include "script/module/event/moduleevent.h"
|
||||||
#include "asset/asset.h"
|
#include "asset/asset.h"
|
||||||
@@ -22,6 +23,24 @@ typedef struct {
|
|||||||
assetentry_t *entry;
|
assetentry_t *entry;
|
||||||
} jsassetentry_t;
|
} jsassetentry_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves all pending loaded() promises for this entry, then
|
||||||
|
* unsubscribes from both onLoaded and onError.
|
||||||
|
*
|
||||||
|
* @param params Unused.
|
||||||
|
* @param user The assetentry_t pointer that finished loading.
|
||||||
|
*/
|
||||||
|
void assetEntryOnLoadedFire(void *params, void *user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rejects all pending loaded() promises for this entry, then
|
||||||
|
* unsubscribes from both onLoaded and onError.
|
||||||
|
*
|
||||||
|
* @param params Unused.
|
||||||
|
* @param user The assetentry_t pointer that errored.
|
||||||
|
*/
|
||||||
|
void assetEntryOnErrorFire(void *params, void *user);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GC free callback - releases the asset lock when the AssetEntry JS object
|
* GC free callback - releases the asset lock when the AssetEntry JS object
|
||||||
* is garbage collected.
|
* is garbage collected.
|
||||||
|
|||||||
@@ -11,14 +11,9 @@
|
|||||||
|
|
||||||
#define MODULE_EVENT_PENDING_MAX 32
|
#define MODULE_EVENT_PENDING_MAX 32
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
event_t *event;
|
|
||||||
jerry_value_t promise;
|
|
||||||
} moduleeventpending_t;
|
|
||||||
|
|
||||||
scriptproto_t MODULE_EVENT_PROTO;
|
scriptproto_t MODULE_EVENT_PROTO;
|
||||||
|
|
||||||
static moduleeventpending_t MODULE_EVENT_PENDING[MODULE_EVENT_PENDING_MAX];
|
static scriptpromisepend_t MODULE_EVENT_PENDING[MODULE_EVENT_PENDING_MAX];
|
||||||
static uint32_t MODULE_EVENT_PENDING_COUNT = 0;
|
static uint32_t MODULE_EVENT_PENDING_COUNT = 0;
|
||||||
|
|
||||||
void moduleEventTrampoline0(void *params, void *user) {
|
void moduleEventTrampoline0(void *params, void *user) {
|
||||||
@@ -67,29 +62,6 @@ void moduleEventFree(void *ptr, jerry_object_native_info_t *info) {
|
|||||||
memoryFree(ptr);
|
memoryFree(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void moduleEventWaitFire(void *params, void *user) {
|
|
||||||
event_t *event = (event_t *)user;
|
|
||||||
|
|
||||||
uint32_t i = 0;
|
|
||||||
while(i < MODULE_EVENT_PENDING_COUNT) {
|
|
||||||
if(MODULE_EVENT_PENDING[i].event != event) { i++; continue; }
|
|
||||||
jerry_value_t undef = jerry_undefined();
|
|
||||||
jerry_value_t r = jerry_promise_resolve(
|
|
||||||
MODULE_EVENT_PENDING[i].promise, undef
|
|
||||||
);
|
|
||||||
jerry_value_free(undef);
|
|
||||||
jerry_value_free(r);
|
|
||||||
jerry_value_free(MODULE_EVENT_PENDING[i].promise);
|
|
||||||
MODULE_EVENT_PENDING_COUNT--;
|
|
||||||
if(i < MODULE_EVENT_PENDING_COUNT) {
|
|
||||||
MODULE_EVENT_PENDING[i] =
|
|
||||||
MODULE_EVENT_PENDING[MODULE_EVENT_PENDING_COUNT];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eventUnsubscribe(event, moduleEventWaitFire);
|
|
||||||
}
|
|
||||||
|
|
||||||
moduleBaseFunction(moduleEventOn) {
|
moduleBaseFunction(moduleEventOn) {
|
||||||
moduleBaseRequireArgs(1);
|
moduleBaseRequireArgs(1);
|
||||||
jsevent_t *ev = (jsevent_t *)scriptProtoGetValue(
|
jsevent_t *ev = (jsevent_t *)scriptProtoGetValue(
|
||||||
@@ -145,31 +117,24 @@ moduleBaseFunction(moduleEventWait) {
|
|||||||
if(!ev || !ev->event) {
|
if(!ev || !ev->event) {
|
||||||
return moduleBaseThrow("Event.wait: invalid event");
|
return moduleBaseThrow("Event.wait: invalid event");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(MODULE_EVENT_PENDING_COUNT >= MODULE_EVENT_PENDING_MAX) {
|
if(MODULE_EVENT_PENDING_COUNT >= MODULE_EVENT_PENDING_MAX) {
|
||||||
return moduleBaseThrow("Event.wait: too many pending awaits");
|
return moduleBaseThrow("Event.wait: too many pending awaits");
|
||||||
}
|
}
|
||||||
|
if(!scriptPromisePendHas(
|
||||||
bool_t subscribed = false;
|
MODULE_EVENT_PENDING, MODULE_EVENT_PENDING_COUNT, ev->event
|
||||||
for(uint32_t i = 0; i < MODULE_EVENT_PENDING_COUNT; i++) {
|
)) {
|
||||||
if(MODULE_EVENT_PENDING[i].event == ev->event) {
|
|
||||||
subscribed = true; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!subscribed) {
|
|
||||||
if(ev->event->count >= ev->event->size) {
|
if(ev->event->count >= ev->event->size) {
|
||||||
return moduleBaseThrow(
|
return moduleBaseThrow(
|
||||||
"Event.wait: event subscriber capacity exceeded"
|
"Event.wait: event subscriber capacity exceeded"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
eventSubscribe(ev->event, moduleEventWaitFire, (void *)ev->event);
|
eventSubscribe(ev->event, moduleEventWaitFire, ev->event);
|
||||||
}
|
}
|
||||||
|
|
||||||
jerry_value_t promise = jerry_promise();
|
jerry_value_t promise = jerry_promise();
|
||||||
MODULE_EVENT_PENDING[MODULE_EVENT_PENDING_COUNT].event = ev->event;
|
scriptPromisePendAdd(
|
||||||
MODULE_EVENT_PENDING[MODULE_EVENT_PENDING_COUNT].promise =
|
MODULE_EVENT_PENDING, &MODULE_EVENT_PENDING_COUNT,
|
||||||
jerry_value_copy(promise);
|
MODULE_EVENT_PENDING_MAX, ev->event, promise
|
||||||
MODULE_EVENT_PENDING_COUNT++;
|
);
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,6 +168,17 @@ jerry_value_t moduleEventGetOrCreate(
|
|||||||
return ev;
|
return ev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void moduleEventWaitFire(void *params, void *user) {
|
||||||
|
event_t *event = (event_t *)user;
|
||||||
|
jerry_value_t undef = jerry_undefined();
|
||||||
|
uint32_t n = scriptPromisePendResolve(
|
||||||
|
MODULE_EVENT_PENDING, &MODULE_EVENT_PENDING_COUNT, event, undef
|
||||||
|
);
|
||||||
|
jerry_value_free(undef);
|
||||||
|
if(!n) return;
|
||||||
|
eventUnsubscribe(event, moduleEventWaitFire);
|
||||||
|
}
|
||||||
|
|
||||||
void moduleEventInit(void) {
|
void moduleEventInit(void) {
|
||||||
MODULE_EVENT_PENDING_COUNT = 0;
|
MODULE_EVENT_PENDING_COUNT = 0;
|
||||||
scriptProtoInit(
|
scriptProtoInit(
|
||||||
@@ -217,19 +193,20 @@ void moduleEventInit(void) {
|
|||||||
|
|
||||||
void moduleEventDispose(void) {
|
void moduleEventDispose(void) {
|
||||||
for(uint32_t i = 0; i < MODULE_EVENT_PENDING_COUNT; i++) {
|
for(uint32_t i = 0; i < MODULE_EVENT_PENDING_COUNT; i++) {
|
||||||
bool_t alreadyUnsub = false;
|
bool_t seen = false;
|
||||||
for(uint32_t j = 0; j < i; j++) {
|
for(uint32_t j = 0; j < i; j++) {
|
||||||
if(MODULE_EVENT_PENDING[j].event == MODULE_EVENT_PENDING[i].event) {
|
if(MODULE_EVENT_PENDING[j].key == MODULE_EVENT_PENDING[i].key) {
|
||||||
alreadyUnsub = true; break;
|
seen = true; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!alreadyUnsub) {
|
if(!seen) {
|
||||||
eventUnsubscribe(
|
eventUnsubscribe(
|
||||||
MODULE_EVENT_PENDING[i].event, moduleEventWaitFire
|
(event_t *)MODULE_EVENT_PENDING[i].key, moduleEventWaitFire
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
jerry_value_free(MODULE_EVENT_PENDING[i].promise);
|
|
||||||
}
|
}
|
||||||
MODULE_EVENT_PENDING_COUNT = 0;
|
scriptPromisePendFreeAll(
|
||||||
|
MODULE_EVENT_PENDING, &MODULE_EVENT_PENDING_COUNT
|
||||||
|
);
|
||||||
scriptProtoDispose(&MODULE_EVENT_PROTO);
|
scriptProtoDispose(&MODULE_EVENT_PROTO);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "script/module/modulebase.h"
|
#include "script/module/modulebase.h"
|
||||||
#include "script/scriptproto.h"
|
#include "script/scriptproto.h"
|
||||||
|
#include "script/scriptpromisepend.h"
|
||||||
#include "event/event.h"
|
#include "event/event.h"
|
||||||
|
|
||||||
/** Maximum number of on() subscriber slots per Event. */
|
/** Maximum number of on() subscriber slots per Event. */
|
||||||
@@ -27,6 +28,15 @@ typedef struct {
|
|||||||
jerry_value_t fns[MODULE_EVENT_MAX_SLOTS];
|
jerry_value_t fns[MODULE_EVENT_MAX_SLOTS];
|
||||||
} jsevent_t;
|
} jsevent_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event trampoline used by wait(). Resolves all pending wait() promises
|
||||||
|
* for the fired event and unsubscribes itself.
|
||||||
|
*
|
||||||
|
* @param params Unused.
|
||||||
|
* @param user The event_t pointer that fired.
|
||||||
|
*/
|
||||||
|
void moduleEventWaitFire(void *params, void *user);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GC free callback - unsubscribes all on() slots and releases JS function
|
* GC free callback - unsubscribes all on() slots and releases JS function
|
||||||
* refs when the Event object is garbage collected.
|
* refs when the Event object is garbage collected.
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#include "script/module/scene/modulescene.h"
|
#include "script/module/scene/modulescene.h"
|
||||||
#include "script/module/story/modulestory.h"
|
#include "script/module/story/modulestory.h"
|
||||||
#include "script/module/system/modulesystem.h"
|
#include "script/module/system/modulesystem.h"
|
||||||
|
#include "script/module/ui/modulefullbox.h"
|
||||||
#include "script/module/ui/moduletextbox.h"
|
#include "script/module/ui/moduletextbox.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -55,6 +56,7 @@ void moduleListInit(void) {
|
|||||||
moduleSceneInit();
|
moduleSceneInit();
|
||||||
moduleStoryInit();
|
moduleStoryInit();
|
||||||
moduleSystemInit();
|
moduleSystemInit();
|
||||||
|
moduleFullboxInit();
|
||||||
moduleTextboxInit();
|
moduleTextboxInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,6 +66,7 @@ void moduleListUpdate(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void moduleListDispose(void) {
|
void moduleListDispose(void) {
|
||||||
|
moduleFullboxDispose();
|
||||||
moduleTextboxDispose();
|
moduleTextboxDispose();
|
||||||
moduleSystemDispose();
|
moduleSystemDispose();
|
||||||
moduleOverworldDispose();
|
moduleOverworldDispose();
|
||||||
|
|||||||
@@ -6,18 +6,18 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "modulerequire.h"
|
#include "modulerequire.h"
|
||||||
|
#include "script/scriptpromisepend.h"
|
||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
|
|
||||||
modulerequireasyncpending_t MODULE_REQUIRE_ASYNC_PENDING[
|
#define MODULE_REQUIRE_ASYNC_MAX 16
|
||||||
MODULE_REQUIRE_ASYNC_MAX
|
|
||||||
];
|
static scriptpromisepend_t MODULE_REQUIRE_ASYNC_PEND[MODULE_REQUIRE_ASYNC_MAX];
|
||||||
uint32_t MODULE_REQUIRE_ASYNC_PENDING_COUNT = 0;
|
static uint32_t MODULE_REQUIRE_ASYNC_PEND_COUNT = 0;
|
||||||
|
|
||||||
void moduleRequireAsyncOnLoaded(void *params, void *user) {
|
void moduleRequireAsyncOnLoaded(void *params, void *user) {
|
||||||
assetentry_t *entry = (assetentry_t *)params;
|
assetentry_t *entry = (assetentry_t *)user;
|
||||||
|
|
||||||
eventUnsubscribe(&entry->onLoaded, moduleRequireAsyncOnLoaded);
|
eventUnsubscribe(&entry->onLoaded, moduleRequireAsyncOnLoaded);
|
||||||
eventUnsubscribe(&entry->onError, moduleRequireAsyncOnError);
|
eventUnsubscribe(&entry->onError, moduleRequireAsyncOnError);
|
||||||
|
|
||||||
@@ -26,66 +26,26 @@ void moduleRequireAsyncOnLoaded(void *params, void *user) {
|
|||||||
jerry_undefined() :
|
jerry_undefined() :
|
||||||
jerry_value_copy(entry->data.script.exports)
|
jerry_value_copy(entry->data.script.exports)
|
||||||
);
|
);
|
||||||
|
uint32_t n = scriptPromisePendResolve(
|
||||||
uint32_t i = 0;
|
MODULE_REQUIRE_ASYNC_PEND, &MODULE_REQUIRE_ASYNC_PEND_COUNT,
|
||||||
while(i < MODULE_REQUIRE_ASYNC_PENDING_COUNT) {
|
entry, exports
|
||||||
if(MODULE_REQUIRE_ASYNC_PENDING[i].entry != entry) {
|
);
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
assetUnlockEntry(entry);
|
|
||||||
|
|
||||||
jerry_value_t copy = jerry_value_copy(exports);
|
|
||||||
jerry_value_t ret = jerry_promise_resolve(
|
|
||||||
MODULE_REQUIRE_ASYNC_PENDING[i].promise, copy
|
|
||||||
);
|
|
||||||
jerry_value_free(ret);
|
|
||||||
jerry_value_free(copy);
|
|
||||||
jerry_value_free(MODULE_REQUIRE_ASYNC_PENDING[i].promise);
|
|
||||||
|
|
||||||
MODULE_REQUIRE_ASYNC_PENDING_COUNT--;
|
|
||||||
|
|
||||||
if(i < MODULE_REQUIRE_ASYNC_PENDING_COUNT) {
|
|
||||||
MODULE_REQUIRE_ASYNC_PENDING[i] = (
|
|
||||||
MODULE_REQUIRE_ASYNC_PENDING[MODULE_REQUIRE_ASYNC_PENDING_COUNT]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
jerry_value_free(exports);
|
jerry_value_free(exports);
|
||||||
|
for(uint32_t i = 0; i < n; i++) assetUnlockEntry(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
void moduleRequireAsyncOnError(void *params, void *user) {
|
void moduleRequireAsyncOnError(void *params, void *user) {
|
||||||
assetentry_t *entry = (assetentry_t *)params;
|
assetentry_t *entry = (assetentry_t *)user;
|
||||||
|
|
||||||
eventUnsubscribe(&entry->onLoaded, moduleRequireAsyncOnLoaded);
|
eventUnsubscribe(&entry->onLoaded, moduleRequireAsyncOnLoaded);
|
||||||
eventUnsubscribe(&entry->onError, moduleRequireAsyncOnError);
|
eventUnsubscribe(&entry->onError, moduleRequireAsyncOnError);
|
||||||
|
|
||||||
jerry_value_t errStr = jerry_string_sz("Module load failed");
|
jerry_value_t errStr = jerry_string_sz("Module load failed");
|
||||||
|
uint32_t n = scriptPromisePendReject(
|
||||||
uint32_t i = 0;
|
MODULE_REQUIRE_ASYNC_PEND, &MODULE_REQUIRE_ASYNC_PEND_COUNT,
|
||||||
while(i < MODULE_REQUIRE_ASYNC_PENDING_COUNT) {
|
entry, errStr
|
||||||
if(MODULE_REQUIRE_ASYNC_PENDING[i].entry != entry) { i++; continue; }
|
);
|
||||||
assetUnlockEntry(entry);
|
|
||||||
|
|
||||||
jerry_value_t copy = jerry_value_copy(errStr);
|
|
||||||
jerry_value_t ret = jerry_promise_reject(
|
|
||||||
MODULE_REQUIRE_ASYNC_PENDING[i].promise, copy
|
|
||||||
);
|
|
||||||
jerry_value_free(ret);
|
|
||||||
jerry_value_free(copy);
|
|
||||||
jerry_value_free(MODULE_REQUIRE_ASYNC_PENDING[i].promise);
|
|
||||||
MODULE_REQUIRE_ASYNC_PENDING_COUNT--;
|
|
||||||
|
|
||||||
if(i < MODULE_REQUIRE_ASYNC_PENDING_COUNT) {
|
|
||||||
MODULE_REQUIRE_ASYNC_PENDING[i] = (
|
|
||||||
MODULE_REQUIRE_ASYNC_PENDING[MODULE_REQUIRE_ASYNC_PENDING_COUNT]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
jerry_value_free(errStr);
|
jerry_value_free(errStr);
|
||||||
|
for(uint32_t i = 0; i < n; i++) assetUnlockEntry(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
jerry_value_t moduleRequireFunc(
|
jerry_value_t moduleRequireFunc(
|
||||||
@@ -108,7 +68,9 @@ jerry_value_t moduleRequireFunc(
|
|||||||
|
|
||||||
assetloaderinput_t input;
|
assetloaderinput_t input;
|
||||||
input.script.nothing = NULL;
|
input.script.nothing = NULL;
|
||||||
assetentry_t *entry = assetLock(moduleName, ASSET_LOADER_TYPE_SCRIPT, &input);
|
assetentry_t *entry = assetLock(
|
||||||
|
moduleName, ASSET_LOADER_TYPE_SCRIPT, &input
|
||||||
|
);
|
||||||
|
|
||||||
errorret_t err = assetRequireLoaded(entry);
|
errorret_t err = assetRequireLoaded(entry);
|
||||||
if(errorIsNotOk(err)) {
|
if(errorIsNotOk(err)) {
|
||||||
@@ -137,10 +99,12 @@ jerry_value_t moduleRequireAsyncFunc(
|
|||||||
if(argc < 1 || !jerry_value_is_string(args[0])) {
|
if(argc < 1 || !jerry_value_is_string(args[0])) {
|
||||||
return moduleBaseThrow("requireAsync expects a filename string.");
|
return moduleBaseThrow("requireAsync expects a filename string.");
|
||||||
}
|
}
|
||||||
if(jerry_string_size(args[0], JERRY_ENCODING_UTF8) >= ASSET_FILE_NAME_MAX) {
|
if(
|
||||||
|
jerry_string_size(args[0], JERRY_ENCODING_UTF8) >= ASSET_FILE_NAME_MAX
|
||||||
|
) {
|
||||||
return moduleBaseThrow("Module name too long.");
|
return moduleBaseThrow("Module name too long.");
|
||||||
}
|
}
|
||||||
if(MODULE_REQUIRE_ASYNC_PENDING_COUNT >= MODULE_REQUIRE_ASYNC_MAX) {
|
if(MODULE_REQUIRE_ASYNC_PEND_COUNT >= MODULE_REQUIRE_ASYNC_MAX) {
|
||||||
return moduleBaseThrow("Too many pending requireAsync calls.");
|
return moduleBaseThrow("Too many pending requireAsync calls.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,11 +113,12 @@ jerry_value_t moduleRequireAsyncFunc(
|
|||||||
|
|
||||||
assetloaderinput_t input;
|
assetloaderinput_t input;
|
||||||
input.script.nothing = NULL;
|
input.script.nothing = NULL;
|
||||||
assetentry_t *entry = assetLock(moduleName, ASSET_LOADER_TYPE_SCRIPT, &input);
|
assetentry_t *entry = assetLock(
|
||||||
|
moduleName, ASSET_LOADER_TYPE_SCRIPT, &input
|
||||||
|
);
|
||||||
|
|
||||||
jerry_value_t promise = jerry_promise();
|
jerry_value_t promise = jerry_promise();
|
||||||
|
|
||||||
// Already loaded - resolve immediately.
|
|
||||||
if(entry->state == ASSET_ENTRY_STATE_LOADED) {
|
if(entry->state == ASSET_ENTRY_STATE_LOADED) {
|
||||||
jerry_value_t exports = (
|
jerry_value_t exports = (
|
||||||
jerry_value_is_undefined(entry->data.script.exports) ?
|
jerry_value_is_undefined(entry->data.script.exports) ?
|
||||||
@@ -167,7 +132,6 @@ jerry_value_t moduleRequireAsyncFunc(
|
|||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Already errored - reject immediately.
|
|
||||||
if(entry->state == ASSET_ENTRY_STATE_ERROR) {
|
if(entry->state == ASSET_ENTRY_STATE_ERROR) {
|
||||||
assetUnlockEntry(entry);
|
assetUnlockEntry(entry);
|
||||||
jerry_value_t errStr = jerry_string_sz("Module load failed");
|
jerry_value_t errStr = jerry_string_sz("Module load failed");
|
||||||
@@ -177,62 +141,56 @@ jerry_value_t moduleRequireAsyncFunc(
|
|||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subscribe to entry events only if this is the first pending await for it.
|
if(!scriptPromisePendHas(
|
||||||
bool_t subscribed = false;
|
MODULE_REQUIRE_ASYNC_PEND, MODULE_REQUIRE_ASYNC_PEND_COUNT, entry
|
||||||
for(uint32_t i = 0; i < MODULE_REQUIRE_ASYNC_PENDING_COUNT; i++) {
|
)) {
|
||||||
if(MODULE_REQUIRE_ASYNC_PENDING[i].entry == entry) {
|
|
||||||
subscribed = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!subscribed) {
|
|
||||||
if(entry->onLoaded.count >= entry->onLoaded.size) {
|
if(entry->onLoaded.count >= entry->onLoaded.size) {
|
||||||
assetUnlockEntry(entry);
|
assetUnlockEntry(entry);
|
||||||
jerry_value_free(promise);
|
jerry_value_free(promise);
|
||||||
return moduleBaseThrow("requireAsync: onLoaded event capacity exceeded.");
|
return moduleBaseThrow(
|
||||||
|
"requireAsync: onLoaded event capacity exceeded."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if(entry->onError.count >= entry->onError.size) {
|
if(entry->onError.count >= entry->onError.size) {
|
||||||
assetUnlockEntry(entry);
|
assetUnlockEntry(entry);
|
||||||
jerry_value_free(promise);
|
jerry_value_free(promise);
|
||||||
return moduleBaseThrow("requireAsync: onError event capacity exceeded.");
|
return moduleBaseThrow(
|
||||||
|
"requireAsync: onError event capacity exceeded."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
eventSubscribe(&entry->onLoaded, moduleRequireAsyncOnLoaded, NULL);
|
eventSubscribe(&entry->onLoaded, moduleRequireAsyncOnLoaded, entry);
|
||||||
eventSubscribe(&entry->onError, moduleRequireAsyncOnError, NULL);
|
eventSubscribe(&entry->onError, moduleRequireAsyncOnError, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
MODULE_REQUIRE_ASYNC_PENDING[MODULE_REQUIRE_ASYNC_PENDING_COUNT].entry = (
|
scriptPromisePendAdd(
|
||||||
entry
|
MODULE_REQUIRE_ASYNC_PEND, &MODULE_REQUIRE_ASYNC_PEND_COUNT,
|
||||||
|
MODULE_REQUIRE_ASYNC_MAX, entry, promise
|
||||||
);
|
);
|
||||||
MODULE_REQUIRE_ASYNC_PENDING[MODULE_REQUIRE_ASYNC_PENDING_COUNT].promise = (
|
|
||||||
jerry_value_copy(promise)
|
|
||||||
);
|
|
||||||
MODULE_REQUIRE_ASYNC_PENDING_COUNT++;
|
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
void moduleRequireInit(void) {
|
void moduleRequireInit(void) {
|
||||||
MODULE_REQUIRE_ASYNC_PENDING_COUNT = 0;
|
MODULE_REQUIRE_ASYNC_PEND_COUNT = 0;
|
||||||
moduleBaseDefineGlobalMethod("require", moduleRequireFunc);
|
moduleBaseDefineGlobalMethod("require", moduleRequireFunc);
|
||||||
moduleBaseDefineGlobalMethod("requireAsync", moduleRequireAsyncFunc);
|
moduleBaseDefineGlobalMethod("requireAsync", moduleRequireAsyncFunc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void moduleRequireDispose(void) {
|
void moduleRequireDispose(void) {
|
||||||
for(uint32_t i = 0; i < MODULE_REQUIRE_ASYNC_PENDING_COUNT; i++) {
|
for(uint32_t i = 0; i < MODULE_REQUIRE_ASYNC_PEND_COUNT; i++) {
|
||||||
assetentry_t *entry = MODULE_REQUIRE_ASYNC_PENDING[i].entry;
|
assetentry_t *e = (assetentry_t *)MODULE_REQUIRE_ASYNC_PEND[i].key;
|
||||||
bool_t alreadyUnsub = false;
|
bool_t seen = false;
|
||||||
for(uint32_t j = 0; j < i; j++) {
|
for(uint32_t j = 0; j < i; j++) {
|
||||||
if(MODULE_REQUIRE_ASYNC_PENDING[j].entry == entry) {
|
if(MODULE_REQUIRE_ASYNC_PEND[j].key == e) {
|
||||||
alreadyUnsub = true;
|
seen = true; break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!alreadyUnsub) {
|
if(!seen) {
|
||||||
eventUnsubscribe(&entry->onLoaded, moduleRequireAsyncOnLoaded);
|
eventUnsubscribe(&e->onLoaded, moduleRequireAsyncOnLoaded);
|
||||||
eventUnsubscribe(&entry->onError, moduleRequireAsyncOnError);
|
eventUnsubscribe(&e->onError, moduleRequireAsyncOnError);
|
||||||
}
|
}
|
||||||
assetUnlockEntry(entry);
|
assetUnlockEntry(e);
|
||||||
jerry_value_free(MODULE_REQUIRE_ASYNC_PENDING[i].promise);
|
|
||||||
}
|
}
|
||||||
MODULE_REQUIRE_ASYNC_PENDING_COUNT = 0;
|
scriptPromisePendFreeAll(
|
||||||
|
MODULE_REQUIRE_ASYNC_PEND, &MODULE_REQUIRE_ASYNC_PEND_COUNT
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,19 +9,6 @@
|
|||||||
#include "script/module/modulebase.h"
|
#include "script/module/modulebase.h"
|
||||||
#include "asset/asset.h"
|
#include "asset/asset.h"
|
||||||
|
|
||||||
#define MODULE_REQUIRE_ASYNC_MAX 16
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
assetentry_t *entry;
|
|
||||||
jerry_value_t promise;
|
|
||||||
} modulerequireasyncpending_t;
|
|
||||||
|
|
||||||
extern modulerequireasyncpending_t MODULE_REQUIRE_ASYNC_PENDING[
|
|
||||||
MODULE_REQUIRE_ASYNC_MAX
|
|
||||||
];
|
|
||||||
|
|
||||||
extern uint32_t MODULE_REQUIRE_ASYNC_PENDING_COUNT;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Success loaded callback for async module loading.
|
* Success loaded callback for async module loading.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -5,5 +5,6 @@
|
|||||||
|
|
||||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
PUBLIC
|
PUBLIC
|
||||||
|
modulefullbox.c
|
||||||
moduletextbox.c
|
moduletextbox.c
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,150 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "modulefullbox.h"
|
||||||
|
#include "script/scriptpromisepend.h"
|
||||||
|
#include "script/module/display/modulecolor.h"
|
||||||
|
#include "animation/easing.h"
|
||||||
|
|
||||||
|
#define MODULE_FULLBOX_PEND_MAX 8
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uifullbox_t *fullbox;
|
||||||
|
} jsuifullbox_t;
|
||||||
|
|
||||||
|
scriptproto_t MODULE_FULLBOX_PROTO;
|
||||||
|
|
||||||
|
static scriptpromisepend_t MODULE_FULLBOX_PEND[MODULE_FULLBOX_PEND_MAX];
|
||||||
|
static uint32_t MODULE_FULLBOX_PEND_COUNT = 0;
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleFullboxSetColor) {
|
||||||
|
moduleBaseRequireArgs(1);
|
||||||
|
jsuifullbox_t *d = (jsuifullbox_t *)scriptProtoGetValue(
|
||||||
|
&MODULE_FULLBOX_PROTO, callInfo->this_value
|
||||||
|
);
|
||||||
|
if(!d || !d->fullbox) return jerry_undefined();
|
||||||
|
color_t *c = moduleColorFrom(args[0]);
|
||||||
|
if(!c) return jerry_undefined();
|
||||||
|
moduleFullboxTransitionFire(NULL, d->fullbox);
|
||||||
|
uiFullboxTransition(d->fullbox, *c, *c, 0.0f, EASING_LINEAR);
|
||||||
|
jerry_value_t promise = jerry_promise();
|
||||||
|
jerry_value_t undef = jerry_undefined();
|
||||||
|
jerry_value_t r = jerry_promise_resolve(promise, undef);
|
||||||
|
jerry_value_free(undef);
|
||||||
|
jerry_value_free(r);
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleFullboxTransition) {
|
||||||
|
moduleBaseRequireArgs(3);
|
||||||
|
jsuifullbox_t *d = (jsuifullbox_t *)scriptProtoGetValue(
|
||||||
|
&MODULE_FULLBOX_PROTO, callInfo->this_value
|
||||||
|
);
|
||||||
|
if(!d || !d->fullbox) return jerry_undefined();
|
||||||
|
color_t *from = moduleColorFrom(args[0]);
|
||||||
|
color_t *to = moduleColorFrom(args[1]);
|
||||||
|
if(!from || !to) return jerry_undefined();
|
||||||
|
float_t duration = moduleBaseArgFloat(2);
|
||||||
|
easingtype_t easing = (easingtype_t)moduleBaseOptInt(
|
||||||
|
3, (int32_t)EASING_LINEAR
|
||||||
|
);
|
||||||
|
moduleFullboxTransitionFire(NULL, d->fullbox);
|
||||||
|
uiFullboxTransition(d->fullbox, *from, *to, duration, easing);
|
||||||
|
jerry_value_t promise = jerry_promise();
|
||||||
|
if(duration <= 0.0f) {
|
||||||
|
jerry_value_t undef = jerry_undefined();
|
||||||
|
jerry_value_t r = jerry_promise_resolve(promise, undef);
|
||||||
|
jerry_value_free(undef);
|
||||||
|
jerry_value_free(r);
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
if(MODULE_FULLBOX_PEND_COUNT >= MODULE_FULLBOX_PEND_MAX) {
|
||||||
|
jerry_value_t errStr = jerry_string_sz(
|
||||||
|
"UIFullbox.transition: too many pending"
|
||||||
|
);
|
||||||
|
jerry_value_t r = jerry_promise_reject(promise, errStr);
|
||||||
|
jerry_value_free(errStr);
|
||||||
|
jerry_value_free(r);
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
if(!scriptPromisePendHas(
|
||||||
|
MODULE_FULLBOX_PEND, MODULE_FULLBOX_PEND_COUNT, d->fullbox
|
||||||
|
)) {
|
||||||
|
eventSubscribe(
|
||||||
|
&d->fullbox->onTransitionEnd,
|
||||||
|
moduleFullboxTransitionFire,
|
||||||
|
d->fullbox
|
||||||
|
);
|
||||||
|
}
|
||||||
|
scriptPromisePendAdd(
|
||||||
|
MODULE_FULLBOX_PEND, &MODULE_FULLBOX_PEND_COUNT,
|
||||||
|
MODULE_FULLBOX_PEND_MAX, d->fullbox, promise
|
||||||
|
);
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
void moduleFullboxTransitionFire(void *params, void *user) {
|
||||||
|
uifullbox_t *fullbox = (uifullbox_t *)user;
|
||||||
|
jerry_value_t undef = jerry_undefined();
|
||||||
|
uint32_t n = scriptPromisePendResolve(
|
||||||
|
MODULE_FULLBOX_PEND, &MODULE_FULLBOX_PEND_COUNT, fullbox, undef
|
||||||
|
);
|
||||||
|
jerry_value_free(undef);
|
||||||
|
if(!n) return;
|
||||||
|
eventUnsubscribe(
|
||||||
|
&fullbox->onTransitionEnd, moduleFullboxTransitionFire
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void moduleFullboxInit(void) {
|
||||||
|
MODULE_FULLBOX_PEND_COUNT = 0;
|
||||||
|
scriptProtoInit(
|
||||||
|
&MODULE_FULLBOX_PROTO, NULL, sizeof(jsuifullbox_t), NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
scriptProtoDefineFunc(
|
||||||
|
&MODULE_FULLBOX_PROTO, "setColor", moduleFullboxSetColor
|
||||||
|
);
|
||||||
|
scriptProtoDefineFunc(
|
||||||
|
&MODULE_FULLBOX_PROTO, "transition", moduleFullboxTransition
|
||||||
|
);
|
||||||
|
|
||||||
|
jsuifullbox_t over = { .fullbox = &UI_FULLBOX_OVER };
|
||||||
|
jerry_value_t overVal = scriptProtoCreateValue(
|
||||||
|
&MODULE_FULLBOX_PROTO, &over
|
||||||
|
);
|
||||||
|
moduleBaseSetValue("UIFullboxOver", overVal);
|
||||||
|
jerry_value_free(overVal);
|
||||||
|
|
||||||
|
jsuifullbox_t under = { .fullbox = &UI_FULLBOX_UNDER };
|
||||||
|
jerry_value_t underVal = scriptProtoCreateValue(
|
||||||
|
&MODULE_FULLBOX_PROTO, &under
|
||||||
|
);
|
||||||
|
moduleBaseSetValue("UIFullboxUnder", underVal);
|
||||||
|
jerry_value_free(underVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
void moduleFullboxDispose(void) {
|
||||||
|
for(uint32_t i = 0; i < MODULE_FULLBOX_PEND_COUNT; i++) {
|
||||||
|
bool_t seen = false;
|
||||||
|
for(uint32_t j = 0; j < i; j++) {
|
||||||
|
if(MODULE_FULLBOX_PEND[j].key == MODULE_FULLBOX_PEND[i].key) {
|
||||||
|
seen = true; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!seen) {
|
||||||
|
uifullbox_t *fb = (uifullbox_t *)MODULE_FULLBOX_PEND[i].key;
|
||||||
|
eventUnsubscribe(
|
||||||
|
&fb->onTransitionEnd, moduleFullboxTransitionFire
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scriptPromisePendFreeAll(
|
||||||
|
MODULE_FULLBOX_PEND, &MODULE_FULLBOX_PEND_COUNT
|
||||||
|
);
|
||||||
|
scriptProtoDispose(&MODULE_FULLBOX_PROTO);
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
|
#include "script/scriptproto.h"
|
||||||
|
#include "ui/uifullbox.h"
|
||||||
|
|
||||||
|
extern scriptproto_t MODULE_FULLBOX_PROTO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event trampoline that resolves all pending transition promises for a
|
||||||
|
* fullbox and unsubscribes from onTransitionEnd. Also called directly
|
||||||
|
* to flush promises when a new transition interrupts a running one.
|
||||||
|
*
|
||||||
|
* @param params Unused (receives the uifullbox_t from eventInvoke).
|
||||||
|
* @param user The uifullbox_t pointer whose transition completed.
|
||||||
|
*/
|
||||||
|
void moduleFullboxTransitionFire(void *params, void *user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setColor(color) - instantly sets the fullbox to a solid color.
|
||||||
|
* Returns a Promise that resolves immediately.
|
||||||
|
*
|
||||||
|
* @param args[0] Color instance.
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleFullboxSetColor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* transition(from, to, duration, easing?) - animates the fullbox from
|
||||||
|
* one color to another. Returns a Promise that resolves when the
|
||||||
|
* transition completes.
|
||||||
|
*
|
||||||
|
* @param args[0] Starting Color.
|
||||||
|
* @param args[1] Ending Color.
|
||||||
|
* @param args[2] Duration in seconds.
|
||||||
|
* @param args[3] Optional EASING_* constant (default: EASING_LINEAR).
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleFullboxTransition);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the UIFullbox module, registering UIFullboxOver and
|
||||||
|
* UIFullboxUnder as global singleton objects.
|
||||||
|
*/
|
||||||
|
void moduleFullboxInit(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disposes the UIFullbox module.
|
||||||
|
*/
|
||||||
|
void moduleFullboxDispose(void);
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "scriptpromisepend.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
|
||||||
|
uint32_t scriptPromisePendResolve(
|
||||||
|
scriptpromisepend_t *pend,
|
||||||
|
uint32_t *count,
|
||||||
|
const void *key,
|
||||||
|
jerry_value_t value
|
||||||
|
) {
|
||||||
|
uint32_t resolved = 0;
|
||||||
|
uint32_t i = 0;
|
||||||
|
while(i < *count) {
|
||||||
|
if(pend[i].key != key) { i++; continue; }
|
||||||
|
jerry_value_t r = jerry_promise_resolve(pend[i].promise, value);
|
||||||
|
jerry_value_free(r);
|
||||||
|
jerry_value_free(pend[i].promise);
|
||||||
|
(*count)--;
|
||||||
|
if(i < *count) pend[i] = pend[*count];
|
||||||
|
resolved++;
|
||||||
|
}
|
||||||
|
return resolved;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t scriptPromisePendReject(
|
||||||
|
scriptpromisepend_t *pend,
|
||||||
|
uint32_t *count,
|
||||||
|
const void *key,
|
||||||
|
jerry_value_t error
|
||||||
|
) {
|
||||||
|
uint32_t rejected = 0;
|
||||||
|
uint32_t i = 0;
|
||||||
|
while(i < *count) {
|
||||||
|
if(pend[i].key != key) { i++; continue; }
|
||||||
|
jerry_value_t r = jerry_promise_reject(pend[i].promise, error);
|
||||||
|
jerry_value_free(r);
|
||||||
|
jerry_value_free(pend[i].promise);
|
||||||
|
(*count)--;
|
||||||
|
if(i < *count) pend[i] = pend[*count];
|
||||||
|
rejected++;
|
||||||
|
}
|
||||||
|
return rejected;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool_t scriptPromisePendHas(
|
||||||
|
const scriptpromisepend_t *pend,
|
||||||
|
uint32_t count,
|
||||||
|
const void *key
|
||||||
|
) {
|
||||||
|
for(uint32_t i = 0; i < count; i++) {
|
||||||
|
if(pend[i].key == key) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scriptPromisePendAdd(
|
||||||
|
scriptpromisepend_t *pend,
|
||||||
|
uint32_t *count,
|
||||||
|
uint32_t max,
|
||||||
|
const void *key,
|
||||||
|
jerry_value_t promise
|
||||||
|
) {
|
||||||
|
assertTrue(*count < max, "scriptPromisePendAdd: capacity exceeded");
|
||||||
|
pend[*count].key = (void *)key;
|
||||||
|
pend[*count].promise = jerry_value_copy(promise);
|
||||||
|
(*count)++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scriptPromisePendFreeAll(
|
||||||
|
scriptpromisepend_t *pend,
|
||||||
|
uint32_t *count
|
||||||
|
) {
|
||||||
|
for(uint32_t i = 0; i < *count; i++) {
|
||||||
|
jerry_value_free(pend[i].promise);
|
||||||
|
}
|
||||||
|
*count = 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "dusk.h"
|
||||||
|
#include <jerryscript.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* One pending promise keyed to a pointer.
|
||||||
|
* Declare a static array of these in each script module that needs to
|
||||||
|
* wait on a C event before resolving a JS promise.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
void *key;
|
||||||
|
jerry_value_t promise;
|
||||||
|
} scriptpromisepend_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves all entries whose key matches and swap-removes them.
|
||||||
|
* Returns the number of promises resolved.
|
||||||
|
*
|
||||||
|
* @param pend The pending array.
|
||||||
|
* @param count Current count (updated in place).
|
||||||
|
* @param key Key to match.
|
||||||
|
* @param value Value passed to jerry_promise_resolve.
|
||||||
|
* @return Number of promises resolved.
|
||||||
|
*/
|
||||||
|
uint32_t scriptPromisePendResolve(
|
||||||
|
scriptpromisepend_t *pend,
|
||||||
|
uint32_t *count,
|
||||||
|
const void *key,
|
||||||
|
jerry_value_t value
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rejects all entries whose key matches and swap-removes them.
|
||||||
|
* Returns the number of promises rejected.
|
||||||
|
*
|
||||||
|
* @param pend The pending array.
|
||||||
|
* @param count Current count (updated in place).
|
||||||
|
* @param key Key to match.
|
||||||
|
* @param error Reason passed to jerry_promise_reject.
|
||||||
|
* @return Number of promises rejected.
|
||||||
|
*/
|
||||||
|
uint32_t scriptPromisePendReject(
|
||||||
|
scriptpromisepend_t *pend,
|
||||||
|
uint32_t *count,
|
||||||
|
const void *key,
|
||||||
|
jerry_value_t error
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if any entry has key equal to key.
|
||||||
|
*
|
||||||
|
* @param pend The pending array.
|
||||||
|
* @param count Current count.
|
||||||
|
* @param key Key to search for.
|
||||||
|
* @return true if found.
|
||||||
|
*/
|
||||||
|
bool_t scriptPromisePendHas(
|
||||||
|
const scriptpromisepend_t *pend,
|
||||||
|
uint32_t count,
|
||||||
|
const void *key
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends a new entry. Stores a copy of the promise; the caller keeps
|
||||||
|
* the original to return to script. Asserts that count < max.
|
||||||
|
*
|
||||||
|
* @param pend The pending array.
|
||||||
|
* @param count Current count (incremented in place).
|
||||||
|
* @param max Capacity of the array.
|
||||||
|
* @param key Key to associate with the promise.
|
||||||
|
* @param promise Promise to copy into the array.
|
||||||
|
*/
|
||||||
|
void scriptPromisePendAdd(
|
||||||
|
scriptpromisepend_t *pend,
|
||||||
|
uint32_t *count,
|
||||||
|
uint32_t max,
|
||||||
|
const void *key,
|
||||||
|
jerry_value_t promise
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees all stored promise references without resolving them, then
|
||||||
|
* zeros count. Call during module dispose before cleaning up events.
|
||||||
|
*
|
||||||
|
* @param pend The pending array.
|
||||||
|
* @param count Current count (set to 0).
|
||||||
|
*/
|
||||||
|
void scriptPromisePendFreeAll(
|
||||||
|
scriptpromisepend_t *pend,
|
||||||
|
uint32_t *count
|
||||||
|
);
|
||||||
@@ -20,6 +20,8 @@ ui_t UI;
|
|||||||
|
|
||||||
errorret_t uiInit(void) {
|
errorret_t uiInit(void) {
|
||||||
memoryZero(&UI, sizeof(ui_t));
|
memoryZero(&UI, sizeof(ui_t));
|
||||||
|
uiFullboxInit(&UI_FULLBOX_UNDER);
|
||||||
|
uiFullboxInit(&UI_FULLBOX_OVER);
|
||||||
uiLoadingInit();
|
uiLoadingInit();
|
||||||
|
|
||||||
uielement_t *element = &UI_ELEMENTS[0];
|
uielement_t *element = &UI_ELEMENTS[0];
|
||||||
|
|||||||
@@ -20,14 +20,17 @@ uielement_t UI_ELEMENTS[] = {
|
|||||||
|
|
||||||
// { .type = UI_ELEMENT_TYPE_SCRIPT, .script = { .script = "ui/test.js" } },
|
// { .type = UI_ELEMENT_TYPE_SCRIPT, .script = { .script = "ui/test.js" } },
|
||||||
|
|
||||||
{ .type = UI_ELEMENT_TYPE_NATIVE, .draw = consoleDraw },
|
|
||||||
{ .type = UI_ELEMENT_TYPE_NATIVE, .draw = uiTextboxDraw },
|
{ .type = UI_ELEMENT_TYPE_NATIVE, .draw = uiTextboxDraw },
|
||||||
// Fullbox over: above absolutely everything.
|
// Fullbox over: above absolutely everything.
|
||||||
{ .type = UI_ELEMENT_TYPE_NATIVE, .draw = uiFullboxOverDraw },
|
{ .type = UI_ELEMENT_TYPE_NATIVE, .draw = uiFullboxOverDraw },
|
||||||
|
|
||||||
|
|
||||||
// These render above the fullbox overlay.
|
// These render above the fullbox overlay.
|
||||||
|
{ .type = UI_ELEMENT_TYPE_NATIVE, .draw = consoleDraw },
|
||||||
{ .type = UI_ELEMENT_TYPE_NATIVE, .draw = uiFPSDraw },
|
{ .type = UI_ELEMENT_TYPE_NATIVE, .draw = uiFPSDraw },
|
||||||
{ .type = UI_ELEMENT_TYPE_NATIVE, .draw = uiLoadingDraw },
|
{ .type = UI_ELEMENT_TYPE_NATIVE, .draw = uiLoadingDraw },
|
||||||
|
|
||||||
|
|
||||||
{ .type = UI_ELEMENT_TYPE_NULL },
|
{ .type = UI_ELEMENT_TYPE_NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
@@ -51,6 +51,7 @@
|
|||||||
/// <reference path="./save/save.d.ts" />
|
/// <reference path="./save/save.d.ts" />
|
||||||
|
|
||||||
// ui
|
// ui
|
||||||
|
/// <reference path="./ui/fullbox.d.ts" />
|
||||||
/// <reference path="./ui/textbox.d.ts" />
|
/// <reference path="./ui/textbox.d.ts" />
|
||||||
|
|
||||||
// engine systems
|
// engine systems
|
||||||
|
|||||||
Vendored
+39
@@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** A full-screen color overlay. */
|
||||||
|
interface UIFullboxInstance {
|
||||||
|
/**
|
||||||
|
* Sets the overlay to a solid color with no animation.
|
||||||
|
* Returns a Promise that resolves immediately.
|
||||||
|
* @param color - The color to apply.
|
||||||
|
*/
|
||||||
|
setColor(color: Color): Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animates the overlay from one color to another.
|
||||||
|
* Returns a Promise that resolves when the transition completes.
|
||||||
|
* Starting a new transition while one is in progress resolves the
|
||||||
|
* old Promise immediately before beginning the new one.
|
||||||
|
* @param from - Starting color.
|
||||||
|
* @param to - Ending color.
|
||||||
|
* @param duration - Duration in seconds.
|
||||||
|
* @param easing - Optional EASING_* constant (default: EASING_LINEAR).
|
||||||
|
*/
|
||||||
|
transition(
|
||||||
|
from: Color,
|
||||||
|
to: Color,
|
||||||
|
duration: number,
|
||||||
|
easing?: number
|
||||||
|
): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Full-screen overlay drawn on top of all UI elements. */
|
||||||
|
declare var UIFullboxOver: UIFullboxInstance;
|
||||||
|
|
||||||
|
/** Full-screen overlay drawn below all UI elements. */
|
||||||
|
declare var UIFullboxUnder: UIFullboxInstance;
|
||||||
Reference in New Issue
Block a user