Test sprite from script
This commit is contained in:
+10
-8
@@ -197,8 +197,12 @@ errorret_t assetUpdate(void) {
|
||||
switch(loading->entry->state) {
|
||||
// This thing is pending synchronous loading.
|
||||
case ASSET_ENTRY_STATE_PENDING_SYNC:
|
||||
// Perform sync load.
|
||||
loading->entry->state = ASSET_ENTRY_STATE_LOADING_SYNC;
|
||||
// Unlock before calling loadSync. The sync loader may re-enter
|
||||
// assetUpdate (e.g. a script loading another asset), and the async
|
||||
// thread never touches LOADING_SYNC entries, so this is safe.
|
||||
threadMutexUnlock(&loading->mutex);
|
||||
|
||||
errorret_t ret = (
|
||||
ASSET_LOADER_CALLBACKS[loading->type].loadSync(loading)
|
||||
);
|
||||
@@ -212,8 +216,6 @@ errorret_t assetUpdate(void) {
|
||||
"Loader did not set entry state to loaded or error on finished load."
|
||||
);
|
||||
|
||||
// If an error occured these things need to be true, basically just
|
||||
// ensuring the sync loader is setting the error correctly.
|
||||
if(errorIsNotOk(ret)) {
|
||||
errorCatch(errorPrint(ret));
|
||||
assertTrue(
|
||||
@@ -222,15 +224,15 @@ errorret_t assetUpdate(void) {
|
||||
);
|
||||
}
|
||||
|
||||
threadMutexUnlock(&loading->mutex);
|
||||
loading++;
|
||||
break;
|
||||
|
||||
case ASSET_ENTRY_STATE_LOADING_SYNC:
|
||||
assertUnreachable(
|
||||
"Entry is in a pending sync state still?"
|
||||
);
|
||||
break;
|
||||
// A re-entrant assetUpdate call (e.g. from a script loading another
|
||||
// asset) will see this entry mid-sync-load. Skip it.
|
||||
threadMutexUnlock(&loading->mutex);
|
||||
loading++;
|
||||
continue;
|
||||
|
||||
// Done loading, we can just free it up.
|
||||
case ASSET_ENTRY_STATE_LOADED:
|
||||
|
||||
@@ -25,8 +25,11 @@ void assetEntryInit(
|
||||
memoryZero(entry, sizeof(assetentry_t));
|
||||
stringCopy(entry->name, name, ASSET_FILE_NAME_MAX);
|
||||
entry->type = type;
|
||||
entry->input = input;
|
||||
entry->state = ASSET_ENTRY_STATE_NOT_STARTED;
|
||||
if(input) {
|
||||
entry->inputData = *input;
|
||||
entry->input = &entry->inputData;
|
||||
}
|
||||
refInit(&entry->refs, entry, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,9 @@ typedef struct assetentry_s {
|
||||
// zero). Entries that nobody has ever locked are left alone so raw-pointer
|
||||
// callers (tests, requireLoaded before locking) are not surprised.
|
||||
bool_t wasLocked;
|
||||
// Data that will be passed to the loader about how it should load.
|
||||
// Owned copy of the loader input. input points here when non-NULL.
|
||||
assetloaderinput_t inputData;
|
||||
// Pointer to inputData, or NULL if no input was provided.
|
||||
assetloaderinput_t *input;
|
||||
} assetentry_t;
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@ void entityRenderableDispose(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
void entityRenderableSetType(
|
||||
@@ -80,6 +79,49 @@ void entityRenderableSetDraw(
|
||||
r->data.custom.drawUser = user;
|
||||
}
|
||||
|
||||
static errorret_t entityRenderableDrawSpritebatch(
|
||||
const entityrenderablespritebatch_t *sb
|
||||
) {
|
||||
if(sb->spriteCount == 0) errorOk();
|
||||
|
||||
errorChain(displaySetState((displaystate_t){
|
||||
.flags = DISPLAY_STATE_FLAG_BLEND
|
||||
}));
|
||||
|
||||
spriteBatchClear();
|
||||
shadermaterial_t mat;
|
||||
memoryZero(&mat, sizeof(shadermaterial_t));
|
||||
mat.unlit.texture = sb->texture;
|
||||
mat.unlit.color = COLOR_WHITE;
|
||||
errorChain(spriteBatchBuffer(
|
||||
sb->sprites, sb->spriteCount,
|
||||
SHADER_LIST_DEFS[SHADER_LIST_SHADER_UNLIT].shader, mat
|
||||
));
|
||||
return spriteBatchFlush();
|
||||
}
|
||||
|
||||
static errorret_t entityRenderableDrawMaterial(
|
||||
const entityrenderablematerial_t *m
|
||||
) {
|
||||
errorChain(displaySetState(m->state));
|
||||
shader_t *shader = SHADER_LIST_DEFS[m->shaderType].shader;
|
||||
assertNotNull(shader, "Shader cannot be null for material type");
|
||||
errorChain(shaderBind(shader));
|
||||
errorChain(shaderSetMaterial(shader, &m->material));
|
||||
for(uint8_t i = 0; i < m->meshCount; i++) {
|
||||
errorChain(meshDraw(m->meshes[i], m->meshOffsets[i], m->meshCounts[i]));
|
||||
}
|
||||
errorOk();
|
||||
}
|
||||
|
||||
static errorret_t entityRenderableDrawCustom(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const entityrenderablecustom_t *custom
|
||||
) {
|
||||
return custom->draw(entityId, componentId, custom->drawUser);
|
||||
}
|
||||
|
||||
errorret_t entityRenderableDraw(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
@@ -87,41 +129,13 @@ errorret_t entityRenderableDraw(
|
||||
entityrenderable_t *r = componentGetData(
|
||||
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
|
||||
switch(r->type) {
|
||||
case ENTITY_RENDERABLE_TYPE_SPRITEBATCH: {
|
||||
const entityrenderablespritebatch_t *sb = &r->data.spritebatch;
|
||||
errorChain(displaySetState((displaystate_t){
|
||||
.flags = DISPLAY_STATE_FLAG_BLEND
|
||||
}));
|
||||
spriteBatchClear();
|
||||
shadermaterial_t mat;
|
||||
memoryZero(&mat, sizeof(shadermaterial_t));
|
||||
mat.unlit.texture = sb->texture;
|
||||
mat.unlit.color = COLOR_WHITE;
|
||||
errorChain(spriteBatchBuffer(
|
||||
sb->sprites, sb->spriteCount,
|
||||
SHADER_LIST_DEFS[SHADER_LIST_SHADER_UNLIT].shader, mat
|
||||
));
|
||||
return spriteBatchFlush();
|
||||
}
|
||||
|
||||
case ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL: {
|
||||
const entityrenderablematerial_t *m = &r->data.material;
|
||||
errorChain(displaySetState(m->state));
|
||||
shader_t *shader = SHADER_LIST_DEFS[m->shaderType].shader;
|
||||
assertNotNull(shader, "Shader cannot be null for material type");
|
||||
errorChain(shaderBind(shader));
|
||||
errorChain(shaderSetMaterial(shader, &m->material));
|
||||
for(uint8_t i = 0; i < m->meshCount; i++) {
|
||||
errorChain(meshDraw(m->meshes[i], m->meshOffsets[i], m->meshCounts[i]));
|
||||
}
|
||||
errorOk();
|
||||
}
|
||||
|
||||
case ENTITY_RENDERABLE_TYPE_SPRITEBATCH:
|
||||
return entityRenderableDrawSpritebatch(&r->data.spritebatch);
|
||||
case ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL:
|
||||
return entityRenderableDrawMaterial(&r->data.material);
|
||||
case ENTITY_RENDERABLE_TYPE_CUSTOM:
|
||||
return r->data.custom.draw(entityId, componentId, r->data.custom.drawUser);
|
||||
|
||||
return entityRenderableDrawCustom(entityId, componentId, &r->data.custom);
|
||||
default:
|
||||
assertUnreachable("Invalid renderable type");
|
||||
}
|
||||
|
||||
@@ -16,13 +16,6 @@
|
||||
|
||||
void initialSceneInit(void) {
|
||||
consolePrint("Initial scene initialized");
|
||||
|
||||
// Cube entity — RENDERABLE init defaults to a white unit cube at origin
|
||||
entityid_t cubeId = entityManagerAdd();
|
||||
SCENE.data.initial.cubeEntityId = cubeId;
|
||||
entityAddComponent(cubeId, COMPONENT_TYPE_POSITION);
|
||||
entityAddComponent(cubeId, COMPONENT_TYPE_RENDERABLE);
|
||||
|
||||
errorCatch(errorPrint(scriptExecFile("testentity.js")));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "script/module/display/moduletexture.h"
|
||||
#include "script/module/asset/moduleassetentry.h"
|
||||
#include "asset/asset.h"
|
||||
#include "asset/loader/assetloader.h"
|
||||
|
||||
static scriptproto_t MODULE_ASSET_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleAssetExists) {
|
||||
moduleBaseRequireArgs(1);
|
||||
moduleBaseRequireString(0);
|
||||
|
||||
char_t buf[256];
|
||||
moduleBaseToString(args[0], buf, sizeof(buf));
|
||||
|
||||
return jerry_boolean(assetFileExists(buf));
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetLock) {
|
||||
moduleBaseRequireArgs(2);
|
||||
moduleBaseRequireString(0);
|
||||
moduleBaseRequireNumber(1);
|
||||
|
||||
char_t buf[256];
|
||||
moduleBaseToString(args[0], buf, sizeof(buf));
|
||||
assetloadertype_t type = (assetloadertype_t)moduleBaseArgInt(1);
|
||||
|
||||
assetloaderinput_t input;
|
||||
assetloaderinput_t *inputPtr = NULL;
|
||||
|
||||
if(argc >= 3 && jerry_value_is_number(args[2])) {
|
||||
int32_t inputVal = moduleBaseArgInt(2);
|
||||
switch(type) {
|
||||
case ASSET_LOADER_TYPE_TEXTURE:
|
||||
input.texture = (textureformat_t)inputVal;
|
||||
inputPtr = &input;
|
||||
break;
|
||||
|
||||
case ASSET_LOADER_TYPE_MESH:
|
||||
input.mesh = (assetmeshinputaxis_t)inputVal;
|
||||
inputPtr = &input;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assetentry_t *entry = assetLock(buf, type, inputPtr);
|
||||
if(!entry) return moduleBaseThrow("Asset.lock: failed to lock asset");
|
||||
jsassetentry_t e = { .entry = entry };
|
||||
|
||||
return scriptProtoCreateValue(&MODULE_ASSET_ENTRY_PROTO, &e);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetRequireLoaded) {
|
||||
moduleBaseRequireArgs(1);
|
||||
|
||||
jsassetentry_t *e = (jsassetentry_t *)scriptProtoGetValue(
|
||||
&MODULE_ASSET_ENTRY_PROTO, args[0]
|
||||
);
|
||||
if(!e || !e->entry) {
|
||||
return moduleBaseThrow("Asset.requireLoaded: expected AssetEntry");
|
||||
}
|
||||
errorret_t err = assetRequireLoaded(e->entry);
|
||||
if(errorIsNotOk(err)) return moduleBaseThrowError(err);
|
||||
jerry_value_t ref = jerry_value_copy(args[0]);
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetUnlock) {
|
||||
moduleBaseRequireArgs(1);
|
||||
moduleBaseRequireString(0);
|
||||
char_t buf[256];
|
||||
moduleBaseToString(args[0], buf, sizeof(buf));
|
||||
assetUnlock(buf);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
static void moduleAssetInit(void) {
|
||||
moduleAssetEntryInit();
|
||||
scriptProtoInit(&MODULE_ASSET_PROTO, "Asset", sizeof(uint8_t), NULL);
|
||||
scriptProtoDefineStaticFunc(&MODULE_ASSET_PROTO, "exists", moduleAssetExists);
|
||||
scriptProtoDefineStaticFunc(&MODULE_ASSET_PROTO, "lock", moduleAssetLock);
|
||||
scriptProtoDefineStaticFunc(&MODULE_ASSET_PROTO, "unlock", moduleAssetUnlock);
|
||||
scriptProtoDefineStaticFunc(&MODULE_ASSET_PROTO, "requireLoaded", moduleAssetRequireLoaded);
|
||||
|
||||
jerry_value_t global = MODULE_ASSET_PROTO.prototype;
|
||||
|
||||
/* Asset.TYPE_* loader type constants */
|
||||
struct { const char_t *name; int val; } types[] = {
|
||||
{ "TYPE_MESH", ASSET_LOADER_TYPE_MESH },
|
||||
{ "TYPE_TEXTURE", ASSET_LOADER_TYPE_TEXTURE },
|
||||
{ "TYPE_TILESET", ASSET_LOADER_TYPE_TILESET },
|
||||
{ "TYPE_LOCALE", ASSET_LOADER_TYPE_LOCALE },
|
||||
{ "TYPE_JSON", ASSET_LOADER_TYPE_JSON },
|
||||
{ "TYPE_SCRIPT", ASSET_LOADER_TYPE_SCRIPT },
|
||||
};
|
||||
for(int i = 0; i < 6; i++) {
|
||||
jerry_value_t k = jerry_string_sz(types[i].name);
|
||||
jerry_value_t v = jerry_number((double)types[i].val);
|
||||
jerry_object_set(global, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
|
||||
/* Asset.MESH_AXIS_* input constants for TYPE_MESH */
|
||||
struct { const char_t *name; int val; } axes[] = {
|
||||
{ "MESH_AXIS_Y_UP", MESH_INPUT_AXIS_Y_UP },
|
||||
{ "MESH_AXIS_Z_UP", MESH_INPUT_AXIS_Z_UP },
|
||||
{ "MESH_AXIS_X_UP", MESH_INPUT_AXIS_X_UP },
|
||||
{ "MESH_AXIS_Y_DOWN", MESH_INPUT_AXIS_Y_DOWN },
|
||||
{ "MESH_AXIS_Z_DOWN", MESH_INPUT_AXIS_Z_DOWN },
|
||||
{ "MESH_AXIS_X_DOWN", MESH_INPUT_AXIS_X_DOWN },
|
||||
};
|
||||
for(int i = 0; i < 6; i++) {
|
||||
jerry_value_t k = jerry_string_sz(axes[i].name);
|
||||
jerry_value_t v = jerry_number((double)axes[i].val);
|
||||
jerry_object_set(global, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
}
|
||||
|
||||
static void moduleAssetDispose(void) {
|
||||
scriptProtoDispose(&MODULE_ASSET_PROTO);
|
||||
moduleAssetEntryDispose();
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "script/module/display/moduletexture.h"
|
||||
#include "asset/asset.h"
|
||||
#include "asset/loader/assetloader.h"
|
||||
#include "asset/loader/assetentry.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
static scriptproto_t MODULE_ASSET_ENTRY_PROTO;
|
||||
|
||||
typedef struct {
|
||||
assetentry_t *entry;
|
||||
} jsassetentry_t;
|
||||
|
||||
/** Releases the asset lock when the JS object is GC'd. */
|
||||
static void moduleAssetEntryFree(
|
||||
void *ptr,
|
||||
jerry_object_native_info_t *info
|
||||
) {
|
||||
(void)info;
|
||||
jsassetentry_t *e = (jsassetentry_t *)ptr;
|
||||
if(e && e->entry) {
|
||||
assetUnlockEntry(e->entry);
|
||||
e->entry = NULL;
|
||||
}
|
||||
memoryFree(ptr);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("AssetEntry cannot be instantiated with new");
|
||||
}
|
||||
|
||||
static inline jsassetentry_t *moduleAssetEntrySelf(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (jsassetentry_t *)scriptProtoGetValue(
|
||||
&MODULE_ASSET_ENTRY_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryGetName) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return jerry_undefined();
|
||||
return jerry_string_sz(e->entry->name);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryGetState) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return jerry_undefined();
|
||||
return jerry_number((double)e->entry->state);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryGetType) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return jerry_undefined();
|
||||
return jerry_number((double)e->entry->type);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryGetIsLoaded) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return jerry_boolean(false);
|
||||
return jerry_boolean(e->entry->state == ASSET_ENTRY_STATE_LOADED);
|
||||
}
|
||||
|
||||
/* requireLoaded() — blocks until fully loaded, returns this for chaining. */
|
||||
moduleBaseFunction(moduleAssetEntryRequireLoaded) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return moduleBaseThrow("AssetEntry.requireLoaded: invalid entry");
|
||||
errorret_t err = assetRequireLoaded(e->entry);
|
||||
if(errorIsNotOk(err)) return moduleBaseThrowError(err);
|
||||
jerry_value_t self = jerry_value_copy(callInfo->this_value);
|
||||
return self;
|
||||
}
|
||||
|
||||
/*
|
||||
* texture — returns a Texture wrapping this entry's loaded texture data.
|
||||
* Returns undefined if the entry is not a texture or not yet loaded.
|
||||
* Locks the entry a second time so the Texture holds its own independent
|
||||
* reference; the lock is released when the Texture is GC'd.
|
||||
*/
|
||||
moduleBaseFunction(moduleAssetEntryGetTexture) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return jerry_undefined();
|
||||
if(e->entry->type != ASSET_LOADER_TYPE_TEXTURE) return jerry_undefined();
|
||||
if(e->entry->state != ASSET_ENTRY_STATE_LOADED) return jerry_undefined();
|
||||
assetEntryLock(e->entry);
|
||||
jstexture_t tex = { .entry = e->entry };
|
||||
return scriptProtoCreateValue(&MODULE_TEXTURE_PROTO, &tex);
|
||||
}
|
||||
|
||||
/* unlock() — releases the lock early; subsequent access is undefined. */
|
||||
moduleBaseFunction(moduleAssetEntryUnlock) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return jerry_undefined();
|
||||
assetUnlockEntry(e->entry);
|
||||
e->entry = NULL;
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleAssetEntryToString) {
|
||||
jsassetentry_t *e = moduleAssetEntrySelf(callInfo);
|
||||
if(!e || !e->entry) return jerry_string_sz("AssetEntry:invalid");
|
||||
char_t buf[64];
|
||||
snprintf(buf, sizeof(buf), "AssetEntry(%s)", e->entry->name);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
static void moduleAssetEntryInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "AssetEntry",
|
||||
sizeof(jsassetentry_t), moduleAssetEntryCtor
|
||||
);
|
||||
MODULE_ASSET_ENTRY_PROTO.info.free_cb = moduleAssetEntryFree;
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "name", moduleAssetEntryGetName, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "state", moduleAssetEntryGetState, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "type", moduleAssetEntryGetType, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "isLoaded", moduleAssetEntryGetIsLoaded, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "texture", moduleAssetEntryGetTexture, NULL
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "requireLoaded", moduleAssetEntryRequireLoaded
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_ASSET_ENTRY_PROTO, "unlock", moduleAssetEntryUnlock
|
||||
);
|
||||
scriptProtoDefineToString(
|
||||
&MODULE_ASSET_ENTRY_PROTO, moduleAssetEntryToString
|
||||
);
|
||||
|
||||
/* State constants */
|
||||
jerry_value_t ctor = MODULE_ASSET_ENTRY_PROTO.constructor;
|
||||
struct { const char_t *name; int val; } states[] = {
|
||||
{ "NOT_STARTED", ASSET_ENTRY_STATE_NOT_STARTED },
|
||||
{ "PENDING", ASSET_ENTRY_STATE_PENDING_ASYNC },
|
||||
{ "LOADING", ASSET_ENTRY_STATE_LOADING_ASYNC },
|
||||
{ "LOADED", ASSET_ENTRY_STATE_LOADED },
|
||||
{ "ERROR", ASSET_ENTRY_STATE_ERROR },
|
||||
};
|
||||
for(int i = 0; i < 5; i++) {
|
||||
jerry_value_t k = jerry_string_sz(states[i].name);
|
||||
jerry_value_t v = jerry_number((double)states[i].val);
|
||||
jerry_object_set(ctor, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void moduleAssetEntryDispose(void) {
|
||||
scriptProtoDispose(&MODULE_ASSET_ENTRY_PROTO);
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "util/memory.h"
|
||||
#include "display/color.h"
|
||||
|
||||
static scriptproto_t MODULE_COLOR_PROTO;
|
||||
|
||||
/**
|
||||
* Returns the native color_t pointer from a Color JS instance.
|
||||
* Returns NULL if the value is not a Color.
|
||||
*/
|
||||
static inline color_t *moduleColorFrom(const jerry_value_t val) {
|
||||
return (color_t *)scriptProtoGetValue(&MODULE_COLOR_PROTO, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Color JS object from a C color_t value.
|
||||
*/
|
||||
static inline jerry_value_t moduleColorPush(const color_t c) {
|
||||
return scriptProtoCreateValue(&MODULE_COLOR_PROTO, &c);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleColorConstructor) {
|
||||
color_t *ptr = (color_t *)memoryAllocate(sizeof(color_t));
|
||||
ptr->r = (uint8_t)moduleBaseOptInt(0, 0);
|
||||
ptr->g = (uint8_t)moduleBaseOptInt(1, 0);
|
||||
ptr->b = (uint8_t)moduleBaseOptInt(2, 0);
|
||||
ptr->a = (uint8_t)moduleBaseOptInt(3, 255);
|
||||
jerry_object_set_native_ptr(
|
||||
callInfo->this_value, &MODULE_COLOR_PROTO.info, ptr
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleColorGetR) {
|
||||
color_t *c = moduleColorFrom(callInfo->this_value);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->r);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleColorSetR) {
|
||||
moduleBaseRequireArgs(1);
|
||||
color_t *c = moduleColorFrom(callInfo->this_value);
|
||||
if(!c) return jerry_undefined();
|
||||
c->r = (uint8_t)moduleBaseArgInt(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleColorGetG) {
|
||||
color_t *c = moduleColorFrom(callInfo->this_value);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->g);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleColorSetG) {
|
||||
moduleBaseRequireArgs(1);
|
||||
color_t *c = moduleColorFrom(callInfo->this_value);
|
||||
if(!c) return jerry_undefined();
|
||||
c->g = (uint8_t)moduleBaseArgInt(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleColorGetB) {
|
||||
color_t *c = moduleColorFrom(callInfo->this_value);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->b);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleColorSetB) {
|
||||
moduleBaseRequireArgs(1);
|
||||
color_t *c = moduleColorFrom(callInfo->this_value);
|
||||
if(!c) return jerry_undefined();
|
||||
c->b = (uint8_t)moduleBaseArgInt(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleColorGetA) {
|
||||
color_t *c = moduleColorFrom(callInfo->this_value);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->a);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleColorSetA) {
|
||||
moduleBaseRequireArgs(1);
|
||||
color_t *c = moduleColorFrom(callInfo->this_value);
|
||||
if(!c) return jerry_undefined();
|
||||
c->a = (uint8_t)moduleBaseArgInt(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleColorToString) {
|
||||
color_t *c = moduleColorFrom(callInfo->this_value);
|
||||
if(!c) return jerry_string_sz("Color:invalid");
|
||||
char_t buf[32];
|
||||
snprintf(buf, sizeof(buf), "Color(%u,%u,%u,%u)",
|
||||
(unsigned)c->r, (unsigned)c->g,
|
||||
(unsigned)c->b, (unsigned)c->a
|
||||
);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
static void moduleColorInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_COLOR_PROTO, "Color",
|
||||
sizeof(color_t), moduleColorConstructor
|
||||
);
|
||||
|
||||
scriptProtoDefineProp(&MODULE_COLOR_PROTO, "r", moduleColorGetR, moduleColorSetR);
|
||||
scriptProtoDefineProp(&MODULE_COLOR_PROTO, "g", moduleColorGetG, moduleColorSetG);
|
||||
scriptProtoDefineProp(&MODULE_COLOR_PROTO, "b", moduleColorGetB, moduleColorSetB);
|
||||
scriptProtoDefineProp(&MODULE_COLOR_PROTO, "a", moduleColorGetA, moduleColorSetA);
|
||||
scriptProtoDefineToString(&MODULE_COLOR_PROTO, moduleColorToString);
|
||||
|
||||
/* Static named color constants on the constructor. */
|
||||
struct { const char_t *name; color_t val; } constants[] = {
|
||||
{ "WHITE", COLOR_WHITE },
|
||||
{ "BLACK", COLOR_BLACK },
|
||||
{ "RED", COLOR_RED },
|
||||
{ "GREEN", COLOR_GREEN },
|
||||
{ "BLUE", COLOR_BLUE },
|
||||
{ "YELLOW", COLOR_YELLOW },
|
||||
{ "CYAN", COLOR_CYAN },
|
||||
{ "MAGENTA", COLOR_MAGENTA },
|
||||
{ "TRANSPARENT", COLOR_TRANSPARENT },
|
||||
{ "GRAY", COLOR_GRAY },
|
||||
{ "LIGHT_GRAY", COLOR_LIGHT_GRAY },
|
||||
{ "DARK_GRAY", COLOR_DARK_GRAY },
|
||||
{ "ORANGE", COLOR_ORANGE },
|
||||
{ "PURPLE", COLOR_PURPLE },
|
||||
{ "PINK", COLOR_PINK },
|
||||
{ "TEAL", COLOR_TEAL },
|
||||
{ "CORNFLOWER_BLUE", COLOR_CORNFLOWER_BLUE },
|
||||
};
|
||||
jerry_value_t ctor = MODULE_COLOR_PROTO.constructor;
|
||||
for(int i = 0; i < (int)(sizeof(constants)/sizeof(constants[0])); i++) {
|
||||
jerry_value_t k = jerry_string_sz(constants[i].name);
|
||||
jerry_value_t v = moduleColorPush(constants[i].val);
|
||||
jerry_object_set(ctor, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
}
|
||||
|
||||
static void moduleColorDispose(void) {
|
||||
scriptProtoDispose(&MODULE_COLOR_PROTO);
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "asset/asset.h"
|
||||
#include "asset/loader/assetloader.h"
|
||||
#include "display/texture/texture.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
static scriptproto_t MODULE_TEXTURE_PROTO;
|
||||
|
||||
typedef struct {
|
||||
assetentry_t *entry;
|
||||
} jstexture_t;
|
||||
|
||||
/**
|
||||
* Custom free callback — unlocks the asset entry so it can be reclaimed
|
||||
* once the JS Texture object is garbage collected.
|
||||
*/
|
||||
static void moduleTextureFree(
|
||||
void *ptr,
|
||||
jerry_object_native_info_t *info
|
||||
) {
|
||||
(void)info;
|
||||
jstexture_t *tex = (jstexture_t *)ptr;
|
||||
if(tex && tex->entry) {
|
||||
assetUnlockEntry(tex->entry);
|
||||
tex->entry = NULL;
|
||||
}
|
||||
memoryFree(ptr);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTextureCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("Texture cannot be instantiated with new");
|
||||
}
|
||||
|
||||
static inline jstexture_t *moduleTextureSelf(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (jstexture_t *)scriptProtoGetValue(
|
||||
&MODULE_TEXTURE_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTextureGetWidth) {
|
||||
jstexture_t *t = moduleTextureSelf(callInfo);
|
||||
if(!t || !t->entry) return jerry_undefined();
|
||||
return jerry_number((double)t->entry->data.texture.width);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTextureGetHeight) {
|
||||
jstexture_t *t = moduleTextureSelf(callInfo);
|
||||
if(!t || !t->entry) return jerry_undefined();
|
||||
return jerry_number((double)t->entry->data.texture.height);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTextureToString) {
|
||||
jstexture_t *t = moduleTextureSelf(callInfo);
|
||||
if(!t || !t->entry) return jerry_string_sz("Texture:invalid");
|
||||
char_t buf[64];
|
||||
snprintf(buf, sizeof(buf), "Texture(%dx%d)",
|
||||
t->entry->data.texture.width,
|
||||
t->entry->data.texture.height
|
||||
);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
static void moduleTextureInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_TEXTURE_PROTO, "Texture",
|
||||
sizeof(jstexture_t), moduleTextureCtor
|
||||
);
|
||||
/* Override the default free callback so the asset lock is released on GC. */
|
||||
MODULE_TEXTURE_PROTO.info.free_cb = moduleTextureFree;
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_TEXTURE_PROTO, "width", moduleTextureGetWidth, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_TEXTURE_PROTO, "height", moduleTextureGetHeight, NULL
|
||||
);
|
||||
scriptProtoDefineToString(&MODULE_TEXTURE_PROTO, moduleTextureToString);
|
||||
|
||||
/* Texture.FORMAT_* constants */
|
||||
jerry_value_t ctor = MODULE_TEXTURE_PROTO.constructor;
|
||||
struct { const char_t *name; int val; } formats[] = {
|
||||
{ "FORMAT_RGBA", TEXTURE_FORMAT_RGBA },
|
||||
{ "FORMAT_PALETTE", TEXTURE_FORMAT_PALETTE },
|
||||
};
|
||||
for(int i = 0; i < 2; i++) {
|
||||
jerry_value_t k = jerry_string_sz(formats[i].name);
|
||||
jerry_value_t v = jerry_number((double)formats[i].val);
|
||||
jerry_object_set(ctor, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
}
|
||||
|
||||
static void moduleTextureDispose(void) {
|
||||
scriptProtoDispose(&MODULE_TEXTURE_PROTO);
|
||||
}
|
||||
@@ -8,7 +8,10 @@
|
||||
#pragma once
|
||||
#include "script/module/entity/modulecomponent.h"
|
||||
#include "camera/modulecamera.h"
|
||||
#include "physics/modulephysics.h"
|
||||
#include "position/moduleposition.h"
|
||||
#include "renderable/modulerenderable.h"
|
||||
#include "trigger/moduletrigger.h"
|
||||
|
||||
/**
|
||||
* Returns a typed JS instance for a newly-added component. Falls back to the
|
||||
@@ -19,21 +22,33 @@ static jerry_value_t moduleComponentListCreateInstance(
|
||||
const jscomponent_t *comp
|
||||
) {
|
||||
switch(type) {
|
||||
case COMPONENT_TYPE_POSITION:
|
||||
return scriptProtoCreateValue(&MODULE_POSITION_PROTO, comp);
|
||||
case COMPONENT_TYPE_CAMERA:
|
||||
return scriptProtoCreateValue(&MODULE_CAMERA_PROTO, comp);
|
||||
case COMPONENT_TYPE_PHYSICS:
|
||||
return scriptProtoCreateValue(&MODULE_PHYSICS_PROTO, comp);
|
||||
case COMPONENT_TYPE_POSITION:
|
||||
return scriptProtoCreateValue(&MODULE_POSITION_PROTO, comp);
|
||||
case COMPONENT_TYPE_RENDERABLE:
|
||||
return scriptProtoCreateValue(&MODULE_RENDERABLE_PROTO, comp);
|
||||
case COMPONENT_TYPE_TRIGGER:
|
||||
return scriptProtoCreateValue(&MODULE_TRIGGER_PROTO, comp);
|
||||
default:
|
||||
return scriptProtoCreateValue(&MODULE_COMPONENT_PROTO, comp);
|
||||
}
|
||||
}
|
||||
|
||||
static void moduleComponentListInit(void) {
|
||||
modulePositionInit();
|
||||
moduleCameraInit();
|
||||
modulePhysicsInit();
|
||||
modulePositionInit();
|
||||
moduleRenderableInit();
|
||||
moduleTriggerInit();
|
||||
}
|
||||
|
||||
static void moduleComponentListDispose(void) {
|
||||
moduleCameraDispose();
|
||||
moduleTriggerDispose();
|
||||
moduleRenderableDispose();
|
||||
modulePositionDispose();
|
||||
modulePhysicsDispose();
|
||||
moduleCameraDispose();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "script/module/math/modulevec3.h"
|
||||
#include "script/module/entity/modulecomponent.h"
|
||||
#include "entity/component/physics/entityphysics.h"
|
||||
|
||||
static scriptproto_t MODULE_PHYSICS_PROTO;
|
||||
|
||||
moduleBaseFunction(modulePhysicsCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("Physics cannot be instantiated with new");
|
||||
}
|
||||
|
||||
static inline jscomponent_t *modulePhysicsSelf(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_PHYSICS_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsGetEntity) {
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->entityId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsGetId) {
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->componentId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsGetBodyType) {
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)entityPhysicsGetBodyType(c->entityId, c->componentId));
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsSetBodyType) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityPhysicsSetBodyType(
|
||||
c->entityId, c->componentId,
|
||||
(physicsbodytype_t)moduleBaseArgInt(0)
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsGetShape) {
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)entityPhysicsGetShape(c->entityId, c->componentId).type);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsSetShape) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
physicsshape_t shape = entityPhysicsGetShape(c->entityId, c->componentId);
|
||||
shape.type = (physicshapetype_t)moduleBaseArgInt(0);
|
||||
entityPhysicsSetShape(c->entityId, c->componentId, shape);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsGetVelocity) {
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
vec3 v;
|
||||
entityPhysicsGetVelocity(c->entityId, c->componentId, v);
|
||||
return moduleVec3Push(v);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsSetVelocity) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("Physics.velocity: expected Vec3");
|
||||
entityPhysicsSetVelocity(c->entityId, c->componentId, v);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsGetGravityScale) {
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityphysics_t *p = entityPhysicsGet(c->entityId, c->componentId);
|
||||
if(!p) return jerry_undefined();
|
||||
return jerry_number((double)p->gravityScale);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsSetGravityScale) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityphysics_t *p = entityPhysicsGet(c->entityId, c->componentId);
|
||||
if(!p) return jerry_undefined();
|
||||
p->gravityScale = moduleBaseArgFloat(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsGetOnGround) {
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_boolean(entityPhysicsIsOnGround(c->entityId, c->componentId));
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsApplyImpulse) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("Physics.applyImpulse: expected Vec3");
|
||||
entityPhysicsApplyImpulse(c->entityId, c->componentId, v);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsToString) {
|
||||
jscomponent_t *c = modulePhysicsSelf(callInfo);
|
||||
if(!c) return jerry_string_sz("Physics:invalid");
|
||||
char_t buf[32];
|
||||
snprintf(buf, sizeof(buf), "Physics(%u)", (unsigned)c->componentId);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
static void modulePhysicsInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_PHYSICS_PROTO, "Physics",
|
||||
sizeof(jscomponent_t), modulePhysicsCtor
|
||||
);
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_PHYSICS_PROTO, "entity", modulePhysicsGetEntity, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_PHYSICS_PROTO, "id", modulePhysicsGetId, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_PHYSICS_PROTO, "bodyType",
|
||||
modulePhysicsGetBodyType, modulePhysicsSetBodyType
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_PHYSICS_PROTO, "shape",
|
||||
modulePhysicsGetShape, modulePhysicsSetShape
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_PHYSICS_PROTO, "velocity",
|
||||
modulePhysicsGetVelocity, modulePhysicsSetVelocity
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_PHYSICS_PROTO, "gravityScale",
|
||||
modulePhysicsGetGravityScale, modulePhysicsSetGravityScale
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_PHYSICS_PROTO, "onGround", modulePhysicsGetOnGround, NULL
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_PHYSICS_PROTO, "applyImpulse", modulePhysicsApplyImpulse
|
||||
);
|
||||
scriptProtoDefineToString(&MODULE_PHYSICS_PROTO, modulePhysicsToString);
|
||||
|
||||
/* Body type constants */
|
||||
jerry_value_t ctor = MODULE_PHYSICS_PROTO.constructor;
|
||||
struct { const char_t *name; int val; } bodyTypes[] = {
|
||||
{ "STATIC", PHYSICS_BODY_STATIC },
|
||||
{ "DYNAMIC", PHYSICS_BODY_DYNAMIC },
|
||||
{ "KINEMATIC", PHYSICS_BODY_KINEMATIC },
|
||||
};
|
||||
for(int i = 0; i < 3; i++) {
|
||||
jerry_value_t k = jerry_string_sz(bodyTypes[i].name);
|
||||
jerry_value_t v = jerry_number((double)bodyTypes[i].val);
|
||||
jerry_object_set(ctor, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
|
||||
/* Shape type constants */
|
||||
struct { const char_t *name; int val; } shapes[] = {
|
||||
{ "SHAPE_CUBE", PHYSICS_SHAPE_CUBE },
|
||||
{ "SHAPE_SPHERE", PHYSICS_SHAPE_SPHERE },
|
||||
{ "SHAPE_CAPSULE", PHYSICS_SHAPE_CAPSULE },
|
||||
{ "SHAPE_PLANE", PHYSICS_SHAPE_PLANE },
|
||||
};
|
||||
for(int i = 0; i < 4; i++) {
|
||||
jerry_value_t k = jerry_string_sz(shapes[i].name);
|
||||
jerry_value_t v = jerry_number((double)shapes[i].val);
|
||||
jerry_object_set(ctor, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
}
|
||||
|
||||
static void modulePhysicsDispose(void) {
|
||||
scriptProtoDispose(&MODULE_PHYSICS_PROTO);
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/module/display/modulecolor.h"
|
||||
#include "script/module/display/moduletexture.h"
|
||||
#include "script/module/entity/modulecomponent.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "entity/component/display/entityrenderable.h"
|
||||
|
||||
static scriptproto_t MODULE_RENDERABLE_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleRenderableCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("Renderable cannot be instantiated with new");
|
||||
}
|
||||
|
||||
static inline jscomponent_t *moduleRenderableSelf(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_RENDERABLE_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
static inline entityrenderable_t *moduleRenderableData(const jscomponent_t *c) {
|
||||
return (entityrenderable_t *)componentGetData(
|
||||
c->entityId, c->componentId, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableGetEntity) {
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->entityId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableGetId) {
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->componentId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableGetType) {
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityrenderable_t *r = moduleRenderableData(c);
|
||||
if(!r) return jerry_undefined();
|
||||
return jerry_number((double)r->type);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableSetType) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityRenderableSetType(
|
||||
c->entityId, c->componentId,
|
||||
(entityrenderabletype_t)moduleBaseArgInt(0)
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableGetPriority) {
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityrenderable_t *r = moduleRenderableData(c);
|
||||
if(!r) return jerry_undefined();
|
||||
return jerry_number((double)r->priority);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableSetPriority) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityRenderableSetPriority(
|
||||
c->entityId, c->componentId,
|
||||
(int8_t)moduleBaseArgInt(0)
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableGetColor) {
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityrenderable_t *r = moduleRenderableData(c);
|
||||
if(!r) return jerry_undefined();
|
||||
return moduleColorPush(r->data.material.material.unlit.color);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableSetColor) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityrenderable_t *r = moduleRenderableData(c);
|
||||
if(!r) return jerry_undefined();
|
||||
color_t *col = moduleColorFrom(args[0]);
|
||||
if(!col) return moduleBaseThrow("Renderable.color: expected Color");
|
||||
r->data.material.material.unlit.color = *col;
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
/* setTexture(tex: Texture) — switches to SPRITEBATCH and stores the texture. */
|
||||
moduleBaseFunction(moduleRenderableSetTexture) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityrenderable_t *r = moduleRenderableData(c);
|
||||
if(!r) return jerry_undefined();
|
||||
jstexture_t *tex = (jstexture_t *)scriptProtoGetValue(
|
||||
&MODULE_TEXTURE_PROTO, args[0]
|
||||
);
|
||||
if(!tex || !tex->entry) {
|
||||
return moduleBaseThrow("Renderable.setTexture: expected Texture");
|
||||
}
|
||||
r->type = ENTITY_RENDERABLE_TYPE_SPRITEBATCH;
|
||||
r->data.spritebatch.texture = &tex->entry->data.texture;
|
||||
/* Pin the Texture object so GC won't free the asset while we hold a pointer. */
|
||||
jerry_value_t pinKey = jerry_string_sz("_tex");
|
||||
jerry_object_set(callInfo->this_value, pinKey, args[0]);
|
||||
jerry_value_free(pinKey);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
/*
|
||||
* addSprite(x1,y1,z1, x2,y2,z2, u1,v1, u2,v2)
|
||||
* addSprite(x1,y1, x2,y2, u1,v1, u2,v2) — z defaults to 0
|
||||
*/
|
||||
moduleBaseFunction(moduleRenderableAddSprite) {
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityrenderable_t *r = moduleRenderableData(c);
|
||||
if(!r) return jerry_undefined();
|
||||
entityrenderablespritebatch_t *sb = &r->data.spritebatch;
|
||||
if(sb->spriteCount >= ENTITY_RENDERABLE_SPRITEBATCH_SPRITES_MAX) {
|
||||
return moduleBaseThrow("Renderable.addSprite: sprite capacity reached");
|
||||
}
|
||||
spritebatchsprite_t s;
|
||||
if(argc >= 10) {
|
||||
moduleBaseRequireArgs(10);
|
||||
s.min[0] = moduleBaseArgFloat(0);
|
||||
s.min[1] = moduleBaseArgFloat(1);
|
||||
s.min[2] = moduleBaseArgFloat(2);
|
||||
s.max[0] = moduleBaseArgFloat(3);
|
||||
s.max[1] = moduleBaseArgFloat(4);
|
||||
s.max[2] = moduleBaseArgFloat(5);
|
||||
s.uvMin[0] = moduleBaseArgFloat(6);
|
||||
s.uvMin[1] = moduleBaseArgFloat(7);
|
||||
s.uvMax[0] = moduleBaseArgFloat(8);
|
||||
s.uvMax[1] = moduleBaseArgFloat(9);
|
||||
} else {
|
||||
moduleBaseRequireArgs(8);
|
||||
s.min[0] = moduleBaseArgFloat(0);
|
||||
s.min[1] = moduleBaseArgFloat(1);
|
||||
s.min[2] = 0.0f;
|
||||
s.max[0] = moduleBaseArgFloat(2);
|
||||
s.max[1] = moduleBaseArgFloat(3);
|
||||
s.max[2] = 0.0f;
|
||||
s.uvMin[0] = moduleBaseArgFloat(4);
|
||||
s.uvMin[1] = moduleBaseArgFloat(5);
|
||||
s.uvMax[0] = moduleBaseArgFloat(6);
|
||||
s.uvMax[1] = moduleBaseArgFloat(7);
|
||||
}
|
||||
sb->sprites[sb->spriteCount++] = s;
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
/* clearSprites() — resets the sprite count to 0. */
|
||||
moduleBaseFunction(moduleRenderableClearSprites) {
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entityrenderable_t *r = moduleRenderableData(c);
|
||||
if(!r) return jerry_undefined();
|
||||
r->data.spritebatch.spriteCount = 0;
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableToString) {
|
||||
jscomponent_t *c = moduleRenderableSelf(callInfo);
|
||||
if(!c) return jerry_string_sz("Renderable:invalid");
|
||||
char_t buf[32];
|
||||
snprintf(buf, sizeof(buf), "Renderable(%u)", (unsigned)c->componentId);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
static void moduleRenderableInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_RENDERABLE_PROTO, "Renderable",
|
||||
sizeof(jscomponent_t), moduleRenderableCtor
|
||||
);
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_RENDERABLE_PROTO, "entity", moduleRenderableGetEntity, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_RENDERABLE_PROTO, "id", moduleRenderableGetId, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_RENDERABLE_PROTO, "type",
|
||||
moduleRenderableGetType, moduleRenderableSetType
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_RENDERABLE_PROTO, "priority",
|
||||
moduleRenderableGetPriority, moduleRenderableSetPriority
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_RENDERABLE_PROTO, "color",
|
||||
moduleRenderableGetColor, moduleRenderableSetColor
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_RENDERABLE_PROTO, "setTexture", moduleRenderableSetTexture
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_RENDERABLE_PROTO, "addSprite", moduleRenderableAddSprite
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_RENDERABLE_PROTO, "clearSprites", moduleRenderableClearSprites
|
||||
);
|
||||
scriptProtoDefineToString(&MODULE_RENDERABLE_PROTO, moduleRenderableToString);
|
||||
|
||||
/* Renderable.SHADER_MATERIAL, .SPRITEBATCH, .CUSTOM */
|
||||
jerry_value_t ctor = MODULE_RENDERABLE_PROTO.constructor;
|
||||
struct { const char_t *name; int val; } types[] = {
|
||||
{ "SHADER_MATERIAL", ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL },
|
||||
{ "SPRITEBATCH", ENTITY_RENDERABLE_TYPE_SPRITEBATCH },
|
||||
{ "CUSTOM", ENTITY_RENDERABLE_TYPE_CUSTOM },
|
||||
};
|
||||
for(int i = 0; i < 3; i++) {
|
||||
jerry_value_t k = jerry_string_sz(types[i].name);
|
||||
jerry_value_t v = jerry_number((double)types[i].val);
|
||||
jerry_object_set(ctor, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
}
|
||||
|
||||
static void moduleRenderableDispose(void) {
|
||||
scriptProtoDispose(&MODULE_RENDERABLE_PROTO);
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "script/module/math/modulevec3.h"
|
||||
#include "script/module/entity/modulecomponent.h"
|
||||
#include "entity/component/trigger/entitytrigger.h"
|
||||
|
||||
static scriptproto_t MODULE_TRIGGER_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleTriggerCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("Trigger cannot be instantiated with new");
|
||||
}
|
||||
|
||||
static inline jscomponent_t *moduleTriggerSelf(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_TRIGGER_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTriggerGetEntity) {
|
||||
jscomponent_t *c = moduleTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->entityId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTriggerGetId) {
|
||||
jscomponent_t *c = moduleTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->componentId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTriggerGetMin) {
|
||||
jscomponent_t *c = moduleTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitytrigger_t *t = entityTriggerGet(c->entityId, c->componentId);
|
||||
if(!t) return jerry_undefined();
|
||||
return moduleVec3Push(t->min);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTriggerSetMin) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("Trigger.min: expected Vec3");
|
||||
entitytrigger_t *t = entityTriggerGet(c->entityId, c->componentId);
|
||||
if(!t) return jerry_undefined();
|
||||
glm_vec3_copy(v, t->min);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTriggerGetMax) {
|
||||
jscomponent_t *c = moduleTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitytrigger_t *t = entityTriggerGet(c->entityId, c->componentId);
|
||||
if(!t) return jerry_undefined();
|
||||
return moduleVec3Push(t->max);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTriggerSetMax) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("Trigger.max: expected Vec3");
|
||||
entitytrigger_t *t = entityTriggerGet(c->entityId, c->componentId);
|
||||
if(!t) return jerry_undefined();
|
||||
glm_vec3_copy(v, t->max);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTriggerSetBounds) {
|
||||
moduleBaseRequireArgs(2);
|
||||
jscomponent_t *c = moduleTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *minV = moduleVec3From(args[0]);
|
||||
float_t *maxV = moduleVec3From(args[1]);
|
||||
if(!minV) return moduleBaseThrow("Trigger.setBounds: expected Vec3 for min");
|
||||
if(!maxV) return moduleBaseThrow("Trigger.setBounds: expected Vec3 for max");
|
||||
entityTriggerSetBounds(c->entityId, c->componentId, minV, maxV);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTriggerContains) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleTriggerSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
float_t *v = moduleVec3From(args[0]);
|
||||
if(!v) return moduleBaseThrow("Trigger.contains: expected Vec3");
|
||||
return jerry_boolean(entityTriggerContains(c->entityId, c->componentId, v));
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTriggerToString) {
|
||||
jscomponent_t *c = moduleTriggerSelf(callInfo);
|
||||
if(!c) return jerry_string_sz("Trigger:invalid");
|
||||
char_t buf[32];
|
||||
snprintf(buf, sizeof(buf), "Trigger(%u)", (unsigned)c->componentId);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
static void moduleTriggerInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_TRIGGER_PROTO, "Trigger",
|
||||
sizeof(jscomponent_t), moduleTriggerCtor
|
||||
);
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_TRIGGER_PROTO, "entity", moduleTriggerGetEntity, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_TRIGGER_PROTO, "id", moduleTriggerGetId, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_TRIGGER_PROTO, "min", moduleTriggerGetMin, moduleTriggerSetMin
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_TRIGGER_PROTO, "max", moduleTriggerGetMax, moduleTriggerSetMax
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_TRIGGER_PROTO, "setBounds", moduleTriggerSetBounds
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_TRIGGER_PROTO, "contains", moduleTriggerContains
|
||||
);
|
||||
scriptProtoDefineToString(&MODULE_TRIGGER_PROTO, moduleTriggerToString);
|
||||
}
|
||||
|
||||
static void moduleTriggerDispose(void) {
|
||||
scriptProtoDispose(&MODULE_TRIGGER_PROTO);
|
||||
}
|
||||
@@ -6,7 +6,9 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/asset/moduleasset.h"
|
||||
#include "script/module/console/moduleconsole.h"
|
||||
#include "script/module/display/modulecolor.h"
|
||||
#include "script/module/display/modulescreen.h"
|
||||
#include "script/module/engine/moduleengine.h"
|
||||
#include "script/module/entity/component/modulecomponentlist.h"
|
||||
@@ -18,6 +20,9 @@
|
||||
#include "script/module/system/modulesystem.h"
|
||||
|
||||
static void moduleListInit(void) {
|
||||
moduleTextureInit();
|
||||
moduleColorInit();
|
||||
moduleAssetInit();
|
||||
moduleConsoleInit();
|
||||
moduleScreenInit();
|
||||
moduleEngineInit();
|
||||
@@ -41,4 +46,7 @@ static void moduleListDispose(void) {
|
||||
moduleEngineDispose();
|
||||
moduleScreenDispose();
|
||||
moduleConsoleDispose();
|
||||
moduleAssetDispose();
|
||||
moduleColorDispose();
|
||||
moduleTextureDispose();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user