Compare commits

3 Commits

Author SHA1 Message Date
YourWishes 677768e6ab Map Base 2026-05-19 23:13:41 -05:00
YourWishes ed6c951783 Script improvements 2026-05-17 23:40:42 -05:00
YourWishes 54254348b8 Add parent/child 2026-05-17 21:46:08 -05:00
79 changed files with 2607 additions and 1682 deletions
+4 -5
View File
@@ -3,11 +3,10 @@ var OverworldEntity = include('entities/OverworldEntity.js');
function CubeEntity() { function CubeEntity() {
OverworldEntity.call(this); OverworldEntity.call(this);
this.add(MESH); this.add(RENDERABLE);
this.add(MATERIAL);
this.cubeMesh = Mesh.createCube(); this.cubeMesh = Mesh.createCube();
this.mesh.mesh = this.cubeMesh; this.renderable.mesh = this.cubeMesh;
} }
CubeEntity.prototype = Object.create(OverworldEntity.prototype); CubeEntity.prototype = Object.create(OverworldEntity.prototype);
@@ -15,11 +14,11 @@ CubeEntity.prototype.constructor = CubeEntity;
CubeEntity.prototype.update = function() { CubeEntity.prototype.update = function() {
OverworldEntity.prototype.update.call(this); OverworldEntity.prototype.update.call(this);
var speed = 3.0; var speed = 5.0;
var move = Input.axis2D(INPUT_ACTION_LEFT, INPUT_ACTION_RIGHT, INPUT_ACTION_UP, INPUT_ACTION_DOWN); var move = Input.axis2D(INPUT_ACTION_LEFT, INPUT_ACTION_RIGHT, INPUT_ACTION_UP, INPUT_ACTION_DOWN);
this.position.position.x += move.x * speed * TIME.delta; this.position.position.x += move.x * speed * TIME.delta;
this.position.position.z += move.y * speed * TIME.delta; this.position.position.z += move.y * speed * TIME.delta;
this.material.color = Color.rainbow(); this.renderable.color = Color.rainbow();
}; };
module = CubeEntity; module = CubeEntity;
+1 -1
View File
@@ -15,7 +15,7 @@ OverworldEntity.prototype.update = function() {
} }
OverworldEntity.prototype.dispose = function() { OverworldEntity.prototype.dispose = function() {
// Nothing to dispose Entity.prototype.dispose.call(this);
} }
module = OverworldEntity; module = OverworldEntity;
+15 -15
View File
@@ -76,18 +76,18 @@ if (typeof PSP !== 'undefined') {
Scene.set('scenes/cube.js'); Scene.set('scenes/cube.js');
Console.print("Testing save stuff;"); // Console.print("Testing save stuff;");
Console.print("Save Count: " + Save.count); // Console.print("Save Count: " + Save.count);
Console.print("Save 0 exists? " + Save.exists(0)); // Console.print("Save 0 exists? " + Save.exists(0));
try { // try {
Save.load(0); // Save.load(0);
Console.print("Successfully loaded save 0."); // Console.print("Successfully loaded save 0.");
} catch (e) { // } catch (e) {
Console.print("Error loading save 0: " + e); // Console.print("Error loading save 0: " + e);
Save.delete(0); // Save.delete(0);
} // }
Console.print("Save 0 exists? " + Save.exists(0)); // Console.print("Save 0 exists? " + Save.exists(0));
Console.print("Writing..."); // Console.print("Writing...");
Save.write(0); // Save.write(0);
Console.print("Save 0 exists? " + Save.exists(0)); // Console.print("Save 0 exists? " + Save.exists(0));
Console.print("Save 0 data: " + Save.load(0)); // Console.print("Save 0 data: " + Save.load(0));
+17
View File
@@ -0,0 +1,17 @@
var CubeEntity = include('entities/CubeEntity.js');
function TestChunkN100(x, y, z) {
MapChunk.call(this, x, y, z);
this.cube = new CubeEntity();
this.cube.position.position = new Vec3(-16, 0, 0);
}
TestChunkN100.prototype = Object.create(MapChunk.prototype);
TestChunkN100.prototype.constructor = TestChunkN100;
TestChunkN100.prototype.dispose = function() {
this.cube.dispose();
};
module = TestChunkN100;
+17
View File
@@ -0,0 +1,17 @@
var CubeEntity = include('entities/CubeEntity.js');
function TestChunk000(x, y, z) {
MapChunk.call(this, x, y, z);
this.cube = new CubeEntity();
this.cube.position.position = new Vec3(0, 0, 0);
}
TestChunk000.prototype = Object.create(MapChunk.prototype);
TestChunk000.prototype.constructor = TestChunk000;
TestChunk000.prototype.dispose = function() {
this.cube.dispose();
};
module = TestChunk000;
+17
View File
@@ -0,0 +1,17 @@
var CubeEntity = include('entities/CubeEntity.js');
function TestChunk001(x, y, z) {
MapChunk.call(this, x, y, z);
this.cube = new CubeEntity();
this.cube.position.position = new Vec3(0, 0, 16);
}
TestChunk001.prototype = Object.create(MapChunk.prototype);
TestChunk001.prototype.constructor = TestChunk001;
TestChunk001.prototype.dispose = function() {
this.cube.dispose();
};
module = TestChunk001;
+17
View File
@@ -0,0 +1,17 @@
var CubeEntity = include('entities/CubeEntity.js');
function TestChunk010(x, y, z) {
MapChunk.call(this, x, y, z);
this.cube = new CubeEntity();
this.cube.position.position = new Vec3(0, 16, 0);
}
TestChunk010.prototype = Object.create(MapChunk.prototype);
TestChunk010.prototype.constructor = TestChunk010;
TestChunk010.prototype.dispose = function() {
this.cube.dispose();
};
module = TestChunk010;
+17
View File
@@ -0,0 +1,17 @@
var CubeEntity = include('entities/CubeEntity.js');
function TestChunk100(x, y, z) {
MapChunk.call(this, x, y, z);
this.cube = new CubeEntity();
this.cube.position.position = new Vec3(16, 0, 0);
}
TestChunk100.prototype = Object.create(MapChunk.prototype);
TestChunk100.prototype.constructor = TestChunk100;
TestChunk100.prototype.dispose = function() {
this.cube.dispose();
};
module = TestChunk100;
+17
View File
@@ -0,0 +1,17 @@
var CubeEntity = include('entities/CubeEntity.js');
function TestChunk200(x, y, z) {
MapChunk.call(this, x, y, z);
this.cube = new CubeEntity();
this.cube.position.position = new Vec3(32, 0, 0);
}
TestChunk200.prototype = Object.create(MapChunk.prototype);
TestChunk200.prototype.constructor = TestChunk200;
TestChunk200.prototype.dispose = function() {
this.cube.dispose();
};
module = TestChunk200;
+17
View File
@@ -0,0 +1,17 @@
var CubeEntity = include('entities/CubeEntity.js');
function TestChunk300(x, y, z) {
MapChunk.call(this, x, y, z);
this.cube = new CubeEntity();
this.cube.position.position = new Vec3(48, 0, 0);
}
TestChunk300.prototype = Object.create(MapChunk.prototype);
TestChunk300.prototype.constructor = TestChunk300;
TestChunk300.prototype.dispose = function() {
this.cube.dispose();
};
module = TestChunk300;
+17
View File
@@ -0,0 +1,17 @@
function TestMap() {
Map.call(this);
Map.setChunkSize(16, 16, 16);
Map.setPosition(0, 0, 0);
}
TestMap.prototype = Object.create(Map.prototype);
TestMap.prototype.constructor = TestMap;
TestMap.prototype.update = function() {
};
TestMap.prototype.dispose = function() {
};
module = TestMap;
+13 -30
View File
@@ -1,50 +1,33 @@
var CubeEntity = include('entities/CubeEntity.js'); var CubeEntity = include('entities/CubeEntity.js');
var MoveCubeCutscene = include('cutscenes/MoveCubeCutscene.js');
function CubeScene() { function CubeScene() {
Map.load('test');
this.cam = new Entity(); this.cam = new Entity();
this.cam.add(POSITION); this.cam.add(POSITION);
this.cam.add(CAMERA); this.cam.add(CAMERA);
this.cam.position.position = new Vec3(3, 3, 3); this.player = new CubeEntity();
this.cam.position.lookAt(new Vec3(0, 0, 0)); this.player.position.position = new Vec3(0, 0, 0);
this.cube = new CubeEntity();
this.spriteEnt = new Entity();
this.spriteEnt.add(POSITION);
this.spriteEnt.position.position = new Vec3(16, 16, 0);
this.inputEnabled = false;
var scene = this;
Cutscene.play(new MoveCubeCutscene({ cube: this.cube })).then(function() {
scene.inputEnabled = true;
});
Textbox.setText(
"Hello! This is a visual novel textbox. It automatically " +
"wraps long lines and splits into pages when the content " +
"is too tall to fit. Press advance to continue...\t" +
"This is a second paragraph on a new page."
);
} }
CubeScene.prototype = Object.create(Scene.prototype); CubeScene.prototype = Object.create(Scene.prototype);
CubeScene.prototype.constructor = CubeScene; CubeScene.prototype.constructor = CubeScene;
CubeScene.prototype.update = function() { CubeScene.prototype.update = function() {
if(this.inputEnabled) { this.player.update();
this.cube.update();
} var pos = this.player.position.position;
this.cam.position.position = new Vec3(pos.x, pos.y + 8, pos.z + 8);
this.cam.position.lookAt(pos);
Map.setPosition(Math.floor(pos.x), Math.floor(pos.y), Math.floor(pos.z));
}; };
CubeScene.prototype.dispose = function() { CubeScene.prototype.dispose = function() {
Cutscene.stop();
this.cam.dispose(); this.cam.dispose();
this.cube.dispose(); this.player.dispose();
this.spriteEnt.dispose(); Map.dispose();
}; };
module = CubeScene; module = CubeScene;
+1
View File
@@ -76,6 +76,7 @@ add_subdirectory(system)
add_subdirectory(time) add_subdirectory(time)
add_subdirectory(ui) add_subdirectory(ui)
add_subdirectory(network) add_subdirectory(network)
add_subdirectory(overworld)
add_subdirectory(save) add_subdirectory(save)
add_subdirectory(util) add_subdirectory(util)
add_subdirectory(thread) add_subdirectory(thread)
@@ -175,9 +175,26 @@ errorret_t spriteBatchPush3D(
); );
} }
errorret_t spriteBatchBufferSprite(const spritebatchsprite_t *sprite) {
if(sprite->texture != SPRITEBATCH.currentTexture) {
errorChain(spriteBatchFlush());
SPRITEBATCH.currentTexture = sprite->texture;
}
return spriteBatchPush3D(
sprite->min,
sprite->max,
#if MESH_ENABLE_COLOR
sprite->color,
#endif
sprite->uvMin,
sprite->uvMax
);
}
void spriteBatchClear() { void spriteBatchClear() {
SPRITEBATCH.spriteCount = 0; SPRITEBATCH.spriteCount = 0;
SPRITEBATCH.spriteFlush = 0; SPRITEBATCH.spriteFlush = 0;
SPRITEBATCH.currentTexture = NULL;
} }
errorret_t spriteBatchFlush() { errorret_t spriteBatchFlush() {
@@ -7,6 +7,7 @@
#pragma once #pragma once
#include "display/mesh/quad.h" #include "display/mesh/quad.h"
#include "display/texture/texture.h"
#define SPRITEBATCH_SPRITES_MAX 512 #define SPRITEBATCH_SPRITES_MAX 512
#define SPRITEBATCH_VERTEX_COUNT (SPRITEBATCH_SPRITES_MAX * QUAD_VERTEX_COUNT) #define SPRITEBATCH_VERTEX_COUNT (SPRITEBATCH_SPRITES_MAX * QUAD_VERTEX_COUNT)
@@ -15,10 +16,22 @@
SPRITEBATCH_SPRITES_MAX / SPRITEBATCH_FLUSH_COUNT \ SPRITEBATCH_SPRITES_MAX / SPRITEBATCH_FLUSH_COUNT \
) )
typedef struct {
vec3 min;
vec3 max;
vec2 uvMin;
vec2 uvMax;
texture_t *texture;
#if MESH_ENABLE_COLOR
color_t color;
#endif
} spritebatchsprite_t;
typedef struct { typedef struct {
mesh_t mesh; mesh_t mesh;
int32_t spriteCount; int32_t spriteCount;
int32_t spriteFlush; int32_t spriteFlush;
texture_t *currentTexture;
} spritebatch_t; } spritebatch_t;
// Have to define these seperately because of alignment in certain platforms. // Have to define these seperately because of alignment in certain platforms.
@@ -119,6 +132,15 @@ errorret_t spriteBatchPush3D(
const vec2 uvMax const vec2 uvMax
); );
/**
* Buffers a sprite defined by a spritebatchsprite_t. Automatically flushes
* if the texture changes from the previously buffered sprite.
*
* @param sprite The sprite to buffer.
* @return An error code indicating success or failure.
*/
errorret_t spriteBatchBufferSprite(const spritebatchsprite_t *sprite);
/** /**
* Clears the sprite batch. This will mean calling flush renders nothing. * Clears the sprite batch. This will mean calling flush renders nothing.
*/ */
+1 -1
View File
@@ -87,7 +87,7 @@ entityid_t componentGetEntitiesWithComponent(
componentid_t used = ENTITY_MANAGER.entitiesWithComponent[ componentid_t used = ENTITY_MANAGER.entitiesWithComponent[
type * ENTITY_COUNT_MAX + i type * ENTITY_COUNT_MAX + i
]; ];
if(used == 0xFF) continue; if(used == COMPONENT_ID_INVALID) continue;
assertTrue( assertTrue(
ENTITY_MANAGER.components[componentGetIndex(i, used)].type == type, ENTITY_MANAGER.components[componentGetIndex(i, used)].type == type,
"Component type mismatch in entitiesWithComponent lookup" "Component type mismatch in entitiesWithComponent lookup"
+1
View File
@@ -6,3 +6,4 @@
add_subdirectory(display) add_subdirectory(display)
add_subdirectory(physics) add_subdirectory(physics)
add_subdirectory(script) add_subdirectory(script)
add_subdirectory(trigger)
@@ -8,6 +8,5 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC PUBLIC
entityposition.c entityposition.c
entitycamera.c entitycamera.c
entitymesh.c entityrenderable.c
entitymaterial.c
) )
@@ -75,8 +75,8 @@ void entityCameraGetForward(const entityid_t entityId, vec2 out) {
entityposition_t *pos = entityPositionGet(entityId, posComp); entityposition_t *pos = entityPositionGet(entityId, posComp);
// View matrix column layout: M[col][row], // View matrix column layout: M[col][row],
// forward = {-M[0][2], -M[1][2], -M[2][2]} // forward = {-M[0][2], -M[1][2], -M[2][2]}
float_t fx = -pos->transform[0][2]; float_t fx = -pos->worldTransform[0][2];
float_t fz = -pos->transform[2][2]; float_t fz = -pos->worldTransform[2][2];
float_t len = sqrtf(fx * fx + fz * fz); float_t len = sqrtf(fx * fx + fz * fz);
if(len > 1e-6f) { fx /= len; fz /= len; } if(len > 1e-6f) { fx /= len; fz /= len; }
out[0] = fx; out[0] = fx;
@@ -87,8 +87,8 @@ void entityCameraGetRight(const entityid_t entityId, vec2 out) {
componentid_t posComp = entityGetComponent(entityId, COMPONENT_TYPE_POSITION); componentid_t posComp = entityGetComponent(entityId, COMPONENT_TYPE_POSITION);
entityposition_t *pos = entityPositionGet(entityId, posComp); entityposition_t *pos = entityPositionGet(entityId, posComp);
// View matrix column layout: right = {M[0][0], M[1][0], M[2][0]} // View matrix column layout: right = {M[0][0], M[1][0], M[2][0]}
float_t rx = pos->transform[0][0]; float_t rx = pos->worldTransform[0][0];
float_t rz = pos->transform[2][0]; float_t rz = pos->worldTransform[2][0];
float_t len = sqrtf(rx * rx + rz * rz); float_t len = sqrtf(rx * rx + rz * rz);
if(len > 1e-6f) { rx /= len; rz /= len; } if(len > 1e-6f) { rx /= len; rz /= len; }
out[0] = rx; out[0] = rx;
@@ -1,62 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "entity/entitymanager.h"
#include "display/shader/shaderunlit.h"
void entityMaterialInit(
const entityid_t entityId,
const componentid_t componentId
) {
entitymaterial_t *mat = componentGetData(
entityId, componentId, COMPONENT_TYPE_MATERIAL
);
mat->shader = &SHADER_UNLIT;
mat->material.unlit.color = COLOR_WHITE;
}
shadermaterial_t * entityMaterialGetShaderMaterial(
const entityid_t entityId,
const componentid_t componentId
) {
entitymaterial_t *mat = componentGetData(
entityId, componentId, COMPONENT_TYPE_MATERIAL
);
return &mat->material;
}
shader_t * entityMaterialGetShader(
const entityid_t entityId,
const componentid_t componentId
) {
entitymaterial_t *mat = componentGetData(
entityId, componentId, COMPONENT_TYPE_MATERIAL
);
return mat->shader;
}
void entityMaterialSetShader(
const entityid_t entityId,
const componentid_t componentId,
shader_t *shader
) {
entitymaterial_t *mat = componentGetData(
entityId, componentId, COMPONENT_TYPE_MATERIAL
);
mat->shader = shader;
}
void entityMaterialSetColor(
const entityid_t entityId,
const componentid_t componentId,
const color_t color
) {
entitymaterial_t *mat = componentGetData(
entityId, componentId, COMPONENT_TYPE_MATERIAL
);
mat->material.unlit.color = color;
}
@@ -1,76 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "entity/entitybase.h"
#include "display/shader/shadermaterial.h"
typedef struct {
shader_t *shader;
shadermaterial_t material;
} entitymaterial_t;
/**
* Initializes the entity material component, defaulting to the unlit shader.
*
* @param entityId The entity ID.
* @param componentId The component ID.
*/
void entityMaterialInit(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Gets the shader material for the given entity and component.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @return The shader material for the given entity and component.
*/
shadermaterial_t * entityMaterialGetShaderMaterial(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Gets the shader for the given entity and component.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @return The shader for the given entity and component.
*/
shader_t * entityMaterialGetShader(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Sets the shader for the given entity and component.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param shader The shader to set.
*/
void entityMaterialSetShader(
const entityid_t entityId,
const componentid_t componentId,
shader_t *shader
);
/**
* Sets the unlit color for the given entity and component.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param color The color to set.
*/
void entityMaterialSetColor(
const entityid_t entityId,
const componentid_t componentId,
const color_t color
);
@@ -1,46 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "entitymesh.h"
#include "entity/entitymanager.h"
void entityMeshInit(
const entityid_t entityId,
const componentid_t componentId
) {
entitymesh_t *comp = componentGetData(
entityId, componentId, COMPONENT_TYPE_MESH
);
comp->mesh = NULL;
}
mesh_t * entityMeshGetMesh(
const entityid_t entityId,
const componentid_t componentId
) {
entitymesh_t *comp = componentGetData(
entityId, componentId, COMPONENT_TYPE_MESH
);
return comp->mesh;
}
void entityMeshSetMesh(
const entityid_t entityId,
const componentid_t componentId,
mesh_t *mesh
) {
entitymesh_t *comp = componentGetData(
entityId, componentId, COMPONENT_TYPE_MESH
);
comp->mesh = mesh;
}
void entityMeshDispose(
const entityid_t entityId,
const componentid_t componentId
) {
}
@@ -1,61 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "entity/entitybase.h"
#include "display/mesh/mesh.h"
typedef struct {
mesh_t *mesh;
} entitymesh_t;
/**
* Initializes the entity mesh component.
*
* @param entityId The entity ID.
* @param componentId The component ID.
*/
void entityMeshInit(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Retrieves the mesh associated with the entity mesh component.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @return A pointer to the mesh associated with the entity mesh component.
*/
mesh_t * entityMeshGetMesh(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Sets the mesh associated with the entity mesh component.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param mesh A pointer to the mesh to associate.
*/
void entityMeshSetMesh(
const entityid_t entityId,
const componentid_t componentId,
mesh_t *mesh
);
/**
* Disposes the entity mesh component.
*
* @param entityId The entity ID.
* @param componentId The component ID.
*/
void entityMeshDispose(
const entityid_t entityId,
const componentid_t componentId
);
@@ -7,6 +7,33 @@
#include "entity/entitymanager.h" #include "entity/entitymanager.h"
// Lazily recompute worldTransform from the parent chain.
static void entityPositionUpdateWorld(entityposition_t *pos) {
if(!pos->dirty) return;
if(pos->parentEntityId == ENTITY_ID_INVALID) {
glm_mat4_copy(pos->localTransform, pos->worldTransform);
} else {
entityposition_t *parent = componentGetData(
pos->parentEntityId, pos->parentComponentId, COMPONENT_TYPE_POSITION
);
entityPositionUpdateWorld(parent);
glm_mat4_mul(parent->worldTransform, pos->localTransform, pos->worldTransform);
}
pos->dirty = false;
}
void entityPositionMarkDirty(entityposition_t *pos) {
pos->dirty = true;
for(uint8_t i = 0; i < pos->childCount; i++) {
entityposition_t *child = componentGetData(
pos->childEntityIds[i], pos->childComponentIds[i], COMPONENT_TYPE_POSITION
);
entityPositionMarkDirty(child);
}
}
void entityPositionInit( void entityPositionInit(
const entityid_t entityId, const entityid_t entityId,
const componentid_t componentId const componentid_t componentId
@@ -18,7 +45,12 @@ void entityPositionInit(
glm_vec3_zero(pos->position); glm_vec3_zero(pos->position);
glm_vec3_zero(pos->rotation); glm_vec3_zero(pos->rotation);
glm_vec3_one(pos->scale); glm_vec3_one(pos->scale);
glm_mat4_identity(pos->transform); glm_mat4_identity(pos->localTransform);
glm_mat4_identity(pos->worldTransform);
pos->dirty = false;
pos->parentEntityId = ENTITY_ID_INVALID;
pos->parentComponentId = COMPONENT_ID_INVALID;
pos->childCount = 0;
} }
void entityPositionLookAt( void entityPositionLookAt(
@@ -31,8 +63,9 @@ void entityPositionLookAt(
entityposition_t *pos = componentGetData( entityposition_t *pos = componentGetData(
entityId, componentId, COMPONENT_TYPE_POSITION entityId, componentId, COMPONENT_TYPE_POSITION
); );
glm_lookat(eye, target, up, pos->transform); glm_lookat(eye, target, up, pos->localTransform);
entityPositionDecompose(pos); entityPositionDecompose(pos);
entityPositionMarkDirty(pos);
} }
void entityPositionGetTransform( void entityPositionGetTransform(
@@ -43,7 +76,19 @@ void entityPositionGetTransform(
entityposition_t *pos = componentGetData( entityposition_t *pos = componentGetData(
entityId, componentId, COMPONENT_TYPE_POSITION entityId, componentId, COMPONENT_TYPE_POSITION
); );
glm_mat4_copy(pos->transform, dest); entityPositionUpdateWorld(pos);
glm_mat4_copy(pos->worldTransform, dest);
}
void entityPositionGetLocalTransform(
const entityid_t entityId,
const componentid_t componentId,
mat4 dest
) {
entityposition_t *pos = componentGetData(
entityId, componentId, COMPONENT_TYPE_POSITION
);
glm_mat4_copy(pos->localTransform, dest);
} }
void entityPositionGetPosition( void entityPositionGetPosition(
@@ -115,6 +160,54 @@ void entityPositionSetScale(
entityPositionRebuild(pos); entityPositionRebuild(pos);
} }
void entityPositionSetParent(
const entityid_t entityId,
const componentid_t componentId,
const entityid_t parentEntityId,
const componentid_t parentComponentId
) {
entityposition_t *pos = componentGetData(
entityId, componentId, COMPONENT_TYPE_POSITION
);
// Remove from old parent's child list.
if(pos->parentEntityId != ENTITY_ID_INVALID) {
entityposition_t *oldParent = componentGetData(
pos->parentEntityId, pos->parentComponentId, COMPONENT_TYPE_POSITION
);
for(uint8_t i = 0; i < oldParent->childCount; i++) {
if(
oldParent->childEntityIds[i] == entityId &&
oldParent->childComponentIds[i] == componentId
) {
oldParent->childCount--;
for(uint8_t j = i; j < oldParent->childCount; j++) {
oldParent->childEntityIds[j] = oldParent->childEntityIds[j + 1];
oldParent->childComponentIds[j] = oldParent->childComponentIds[j + 1];
}
break;
}
}
}
pos->parentEntityId = parentEntityId;
pos->parentComponentId = parentComponentId;
// Register with new parent.
if(parentEntityId != ENTITY_ID_INVALID) {
entityposition_t *parent = componentGetData(
parentEntityId, parentComponentId, COMPONENT_TYPE_POSITION
);
if(parent->childCount < ENTITY_POSITION_CHILDREN_MAX) {
parent->childEntityIds[parent->childCount] = entityId;
parent->childComponentIds[parent->childCount] = componentId;
parent->childCount++;
}
}
entityPositionMarkDirty(pos);
}
entityposition_t *entityPositionGet( entityposition_t *entityPositionGet(
const entityid_t entityId, const entityid_t entityId,
const componentid_t componentId const componentid_t componentId
@@ -125,57 +218,87 @@ entityposition_t *entityPositionGet(
} }
void entityPositionRebuild(entityposition_t *pos) { void entityPositionRebuild(entityposition_t *pos) {
glm_mat4_identity(pos->transform); glm_mat4_identity(pos->localTransform);
glm_translate(pos->transform, pos->position); glm_translate(pos->localTransform, pos->position);
glm_rotate_x(pos->transform, pos->rotation[0], pos->transform); glm_rotate_x(pos->localTransform, pos->rotation[0], pos->localTransform);
glm_rotate_y(pos->transform, pos->rotation[1], pos->transform); glm_rotate_y(pos->localTransform, pos->rotation[1], pos->localTransform);
glm_rotate_z(pos->transform, pos->rotation[2], pos->transform); glm_rotate_z(pos->localTransform, pos->rotation[2], pos->localTransform);
glm_scale(pos->transform, pos->scale); glm_scale(pos->localTransform, pos->scale);
entityPositionMarkDirty(pos);
}
void entityPositionDisposeDeep(
const entityid_t entityId,
const componentid_t componentId
) {
entityposition_t *pos = entityPositionGet(entityId, componentId);
// Detach from parent so the parent's child list stays consistent.
if(pos->parentEntityId != ENTITY_ID_INVALID) {
entityPositionSetParent(entityId, componentId, ENTITY_ID_INVALID, COMPONENT_ID_INVALID);
}
// Copy the child list before disposing self (entityDispose invalidates pos).
uint8_t childCount = pos->childCount;
entityid_t childEntityIds[ENTITY_POSITION_CHILDREN_MAX];
componentid_t childComponentIds[ENTITY_POSITION_CHILDREN_MAX];
for(uint8_t i = 0; i < childCount; i++) {
childEntityIds[i] = pos->childEntityIds[i];
childComponentIds[i] = pos->childComponentIds[i];
// Sever the child's parent link so it won't try to modify our disposed data.
entityposition_t *child = entityPositionGet(childEntityIds[i], childComponentIds[i]);
child->parentEntityId = ENTITY_ID_INVALID;
child->parentComponentId = COMPONENT_ID_INVALID;
}
entityDispose(entityId);
for(uint8_t i = 0; i < childCount; i++) {
entityPositionDisposeDeep(childEntityIds[i], childComponentIds[i]);
}
} }
void entityPositionDecompose(entityposition_t *pos) { void entityPositionDecompose(entityposition_t *pos) {
// Translation: column 3 // Translation: column 3
pos->position[0] = pos->transform[3][0]; pos->position[0] = pos->localTransform[3][0];
pos->position[1] = pos->transform[3][1]; pos->position[1] = pos->localTransform[3][1];
pos->position[2] = pos->transform[3][2]; pos->position[2] = pos->localTransform[3][2];
// Scale: length of each basis column (xyz only) // Scale: length of each basis column (xyz only)
pos->scale[0] = sqrtf( pos->scale[0] = sqrtf(
pos->transform[0][0] * pos->transform[0][0] + pos->localTransform[0][0] * pos->localTransform[0][0] +
pos->transform[0][1] * pos->transform[0][1] + pos->localTransform[0][1] * pos->localTransform[0][1] +
pos->transform[0][2] * pos->transform[0][2] pos->localTransform[0][2] * pos->localTransform[0][2]
); );
pos->scale[1] = sqrtf( pos->scale[1] = sqrtf(
pos->transform[1][0] * pos->transform[1][0] + pos->localTransform[1][0] * pos->localTransform[1][0] +
pos->transform[1][1] * pos->transform[1][1] + pos->localTransform[1][1] * pos->localTransform[1][1] +
pos->transform[1][2] * pos->transform[1][2] pos->localTransform[1][2] * pos->localTransform[1][2]
); );
pos->scale[2] = sqrtf( pos->scale[2] = sqrtf(
pos->transform[2][0] * pos->transform[2][0] + pos->localTransform[2][0] * pos->localTransform[2][0] +
pos->transform[2][1] * pos->transform[2][1] + pos->localTransform[2][1] * pos->localTransform[2][1] +
pos->transform[2][2] * pos->transform[2][2] pos->localTransform[2][2] * pos->localTransform[2][2]
); );
// Normalize columns to isolate the rotation matrix // Normalize columns to isolate the rotation matrix.
float invS0 = pos->scale[0] > 0.0f ? 1.0f / pos->scale[0] : 0.0f; float invS0 = pos->scale[0] > 0.0f ? 1.0f / pos->scale[0] : 0.0f;
float invS1 = pos->scale[1] > 0.0f ? 1.0f / pos->scale[1] : 0.0f; float invS1 = pos->scale[1] > 0.0f ? 1.0f / pos->scale[1] : 0.0f;
float invS2 = pos->scale[2] > 0.0f ? 1.0f / pos->scale[2] : 0.0f; float invS2 = pos->scale[2] > 0.0f ? 1.0f / pos->scale[2] : 0.0f;
mat4 r; mat4 r;
glm_mat4_identity(r); glm_mat4_identity(r);
r[0][0] = pos->transform[0][0] * invS0; r[0][0] = pos->localTransform[0][0] * invS0;
r[0][1] = pos->transform[0][1] * invS0; r[0][1] = pos->localTransform[0][1] * invS0;
r[0][2] = pos->transform[0][2] * invS0; r[0][2] = pos->localTransform[0][2] * invS0;
r[1][0] = pos->transform[1][0] * invS1; r[1][0] = pos->localTransform[1][0] * invS1;
r[1][1] = pos->transform[1][1] * invS1; r[1][1] = pos->localTransform[1][1] * invS1;
r[1][2] = pos->transform[1][2] * invS1; r[1][2] = pos->localTransform[1][2] * invS1;
r[2][0] = pos->transform[2][0] * invS2; r[2][0] = pos->localTransform[2][0] * invS2;
r[2][1] = pos->transform[2][1] * invS2; r[2][1] = pos->localTransform[2][1] * invS2;
r[2][2] = pos->transform[2][2] * invS2; r[2][2] = pos->localTransform[2][2] * invS2;
// Extract XYZ euler angles (R = Rx * Ry * Rz, column-major) // Extract XYZ euler angles (R = Rx * Ry * Rz, column-major)
// r[2][0] = sin(Y), r[2][1] = -sin(X)*cos(Y), r[2][2] = cos(X)*cos(Y)
// r[0][0] = cos(Y)*cos(Z), r[1][0] = -cos(Y)*sin(Z)
float sinBeta = glm_clamp(r[2][0], -1.0f, 1.0f); float sinBeta = glm_clamp(r[2][0], -1.0f, 1.0f);
pos->rotation[1] = asinf(sinBeta); pos->rotation[1] = asinf(sinBeta);
float cosBeta = cosf(pos->rotation[1]); float cosBeta = cosf(pos->rotation[1]);
@@ -184,7 +307,7 @@ void entityPositionDecompose(entityposition_t *pos) {
pos->rotation[0] = atan2f(-r[2][1], r[2][2]); pos->rotation[0] = atan2f(-r[2][1], r[2][2]);
pos->rotation[2] = atan2f(-r[1][0], r[0][0]); pos->rotation[2] = atan2f(-r[1][0], r[0][0]);
} else { } else {
// Gimbal lock: pin Z to 0, recover X from the remaining degree of freedom // Gimbal lock: pin Z to 0, recover X.
pos->rotation[2] = 0.0f; pos->rotation[2] = 0.0f;
pos->rotation[0] = (sinBeta > 0.0f) pos->rotation[0] = (sinBeta > 0.0f)
? atan2f(r[0][1], r[1][1]) ? atan2f(r[0][1], r[1][1])
@@ -8,18 +8,24 @@
#pragma once #pragma once
#include "entity/entitybase.h" #include "entity/entitybase.h"
#define ENTITY_POSITION_CHILDREN_MAX 8
typedef struct { typedef struct {
mat4 transform; mat4 localTransform;
mat4 worldTransform;
vec3 position; vec3 position;
vec3 rotation; vec3 rotation;
vec3 scale; vec3 scale;
bool dirty;
entityid_t parentEntityId;
componentid_t parentComponentId;
uint8_t childCount;
entityid_t childEntityIds[ENTITY_POSITION_CHILDREN_MAX];
componentid_t childComponentIds[ENTITY_POSITION_CHILDREN_MAX];
} entityposition_t; } entityposition_t;
/** /**
* Initialize the entity position component. * Initialize the entity position component.
*
* @param entityId The entity ID.
* @param componentId The component ID.
*/ */
void entityPositionInit( void entityPositionInit(
const entityid_t entityId, const entityid_t entityId,
@@ -27,13 +33,13 @@ void entityPositionInit(
); );
/** /**
* Transforms the entity's position to look at a target point. * Transforms the entity's local transform to look at a target point.
* *
* @param entityId The entity ID. * @param entityId The entity ID.
* @param componentId The component ID. * @param componentId The component ID.
* @param target The target point to look at. * @param target The target point to look at.
* @param up The up vector for the look at transformation. * @param up The up vector.
* @param eye The position of the camera/eye for the look at transformation. * @param eye The eye/camera position.
*/ */
void entityPositionLookAt( void entityPositionLookAt(
const entityid_t entityId, const entityid_t entityId,
@@ -44,11 +50,11 @@ void entityPositionLookAt(
); );
/** /**
* Gets the transform matrix of the entity position component. * Gets the world-space transform matrix, recomputing it lazily if dirty.
* *
* @param entityId The entity ID. * @param entityId The entity ID.
* @param componentId The component ID. * @param componentId The component ID.
* @param dest The destination matrix to write the transform to. * @param dest Destination matrix.
*/ */
void entityPositionGetTransform( void entityPositionGetTransform(
const entityid_t entityId, const entityid_t entityId,
@@ -57,11 +63,20 @@ void entityPositionGetTransform(
); );
/** /**
* Gets the cached position of the entity. * Gets the local transform matrix (does not include parent transforms).
* *
* @param entityId The entity ID. * @param entityId The entity ID.
* @param componentId The component ID. * @param componentId The component ID.
* @param dest The destination vec3 to write the position to. * @param dest Destination matrix.
*/
void entityPositionGetLocalTransform(
const entityid_t entityId,
const componentid_t componentId,
mat4 dest
);
/**
* Gets the cached local position.
*/ */
void entityPositionGetPosition( void entityPositionGetPosition(
const entityid_t entityId, const entityid_t entityId,
@@ -70,11 +85,7 @@ void entityPositionGetPosition(
); );
/** /**
* Sets the position of the entity and rebuilds the transform matrix. * Sets the local position and marks the world transform dirty.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param position The new position.
*/ */
void entityPositionSetPosition( void entityPositionSetPosition(
const entityid_t entityId, const entityid_t entityId,
@@ -83,11 +94,7 @@ void entityPositionSetPosition(
); );
/** /**
* Gets the cached euler rotation (XYZ, radians) of the entity. * Gets the cached local euler rotation (XYZ, radians).
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param dest The destination vec3 to write the rotation to.
*/ */
void entityPositionGetRotation( void entityPositionGetRotation(
const entityid_t entityId, const entityid_t entityId,
@@ -96,12 +103,7 @@ void entityPositionGetRotation(
); );
/** /**
* Sets the euler rotation (XYZ, radians) of the entity and rebuilds the * Sets the local euler rotation (XYZ, radians) and marks the world transform dirty.
* transform matrix.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param rotation The new euler rotation in radians.
*/ */
void entityPositionSetRotation( void entityPositionSetRotation(
const entityid_t entityId, const entityid_t entityId,
@@ -110,11 +112,7 @@ void entityPositionSetRotation(
); );
/** /**
* Gets the cached scale of the entity. * Gets the cached local scale.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param dest The destination vec3 to write the scale to.
*/ */
void entityPositionGetScale( void entityPositionGetScale(
const entityid_t entityId, const entityid_t entityId,
@@ -123,11 +121,7 @@ void entityPositionGetScale(
); );
/** /**
* Sets the scale of the entity and rebuilds the transform matrix. * Sets the local scale and marks the world transform dirty.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param scale The new scale.
*/ */
void entityPositionSetScale( void entityPositionSetScale(
const entityid_t entityId, const entityid_t entityId,
@@ -136,13 +130,24 @@ void entityPositionSetScale(
); );
/** /**
* Returns a direct pointer to the entity position component data. * Sets the parent of this entity's position component.
* After modifying position, rotation, or scale directly, call * Pass ENTITY_ID_INVALID / COMPONENT_ID_INVALID to detach from any parent.
* entityPositionRebuild() to update the transform matrix.
* *
* @param entityId The entity ID. * @param entityId The child entity ID.
* @param componentId The component ID. * @param componentId The child component ID.
* @return Pointer to the entity position component data. * @param parentEntityId The parent entity ID.
* @param parentComponentId The parent component ID.
*/
void entityPositionSetParent(
const entityid_t entityId,
const componentid_t componentId,
const entityid_t parentEntityId,
const componentid_t parentComponentId
);
/**
* Returns a direct pointer to the entity position component data.
* After modifying localTransform directly, call entityPositionMarkDirty().
*/ */
entityposition_t *entityPositionGet( entityposition_t *entityPositionGet(
const entityid_t entityId, const entityid_t entityId,
@@ -150,15 +155,30 @@ entityposition_t *entityPositionGet(
); );
/** /**
* Internal function to rebuild the transform matrix of the entity position * Rebuilds the local transform matrix from the cached position/rotation/scale,
* component based on the current position, rotation, and scale. * then marks this node and all descendants dirty.
*/ */
void entityPositionRebuild(entityposition_t *pos); void entityPositionRebuild(entityposition_t *pos);
/** /**
* Decomposes the transform matrix back into the position, rotation (XYZ euler, * Marks this node and all descendants as having a stale world transform.
* radians), and scale cache fields. Call after any direct matrix modification. */
void entityPositionMarkDirty(entityposition_t *pos);
/**
* Disposes this entity and all of its position-component descendants
* recursively. Detaches from any parent before destroying.
* *
* @param pos Pointer to the entity position component data. * @param entityId The root entity ID.
* @param componentId The root position component ID.
*/
void entityPositionDisposeDeep(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Decomposes the local transform matrix back into the position, rotation
* (XYZ euler, radians), and scale cache fields.
*/ */
void entityPositionDecompose(entityposition_t *pos); void entityPositionDecompose(entityposition_t *pos);
@@ -0,0 +1,149 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "entityrenderable.h"
#include "entity/entitymanager.h"
#include "display/shader/shaderunlit.h"
#include "display/mesh/cube.h"
void entityRenderableInit(
const entityid_t entityId,
const componentid_t componentId
) {
entityrenderable_t *r = componentGetData(
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
r->type = ENTITY_RENDERABLE_TYPE_MATERIAL;
r->mesh = &CUBE_MESH_SIMPLE;
r->shader = &SHADER_UNLIT;
r->material.unlit.color = COLOR_WHITE;
}
entityrenderabletype_t entityRenderableGetType(
const entityid_t entityId,
const componentid_t componentId
) {
entityrenderable_t *r = componentGetData(
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
return r->type;
}
void entityRenderableSetType(
const entityid_t entityId,
const componentid_t componentId,
const entityrenderabletype_t type
) {
entityrenderable_t *r = componentGetData(
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
r->type = type;
}
mesh_t * entityRenderableGetMesh(
const entityid_t entityId,
const componentid_t componentId
) {
entityrenderable_t *r = componentGetData(
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
return r->mesh;
}
void entityRenderableSetMesh(
const entityid_t entityId,
const componentid_t componentId,
mesh_t *mesh
) {
entityrenderable_t *r = componentGetData(
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
r->mesh = mesh;
}
shader_t * entityRenderableGetShader(
const entityid_t entityId,
const componentid_t componentId
) {
entityrenderable_t *r = componentGetData(
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
return r->shader;
}
void entityRenderableSetShader(
const entityid_t entityId,
const componentid_t componentId,
shader_t *shader
) {
entityrenderable_t *r = componentGetData(
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
r->shader = shader;
}
shadermaterial_t * entityRenderableGetShaderMaterial(
const entityid_t entityId,
const componentid_t componentId
) {
entityrenderable_t *r = componentGetData(
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
return &r->material;
}
void entityRenderableSetColor(
const entityid_t entityId,
const componentid_t componentId,
const color_t color
) {
entityrenderable_t *r = componentGetData(
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
r->material.unlit.color = color;
}
void entityRenderableSpriteBatchAdd(
const entityid_t entityId,
const componentid_t componentId,
const spritebatchsprite_t *sprite
) {
entityrenderable_t *r = componentGetData(
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
if(r->spritebatch.spriteCount >= ENTITY_RENDERABLE_SPRITEBATCH_SPRITES_MAX) return;
r->spritebatch.sprites[r->spritebatch.spriteCount++] = *sprite;
}
void entityRenderableSpriteBatchClear(
const entityid_t entityId,
const componentid_t componentId
) {
entityrenderable_t *r = componentGetData(
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
r->spritebatch.spriteCount = 0;
}
void entityRenderableDispose(
const entityid_t entityId,
const componentid_t componentId
) {
entityrenderable_t *r = componentGetData(
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
if(
r->type == ENTITY_RENDERABLE_TYPE_CALLBACK &&
r->userFree &&
r->user
) {
r->userFree(r->user);
r->user = NULL;
}
r->mesh = NULL;
r->shader = NULL;
}
@@ -0,0 +1,157 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "entity/entitybase.h"
#include "display/mesh/mesh.h"
#include "display/shader/shadermaterial.h"
#include "display/spritebatch/spritebatch.h"
#define ENTITY_RENDERABLE_SPRITEBATCH_SPRITES_MAX 64
typedef enum {
ENTITY_RENDERABLE_TYPE_MATERIAL = 0,
ENTITY_RENDERABLE_TYPE_SPRITEBATCH,
ENTITY_RENDERABLE_TYPE_CALLBACK,
} entityrenderabletype_t;
typedef errorret_t (*entityrenderablecallback_t)(
const entityid_t entityId,
const componentid_t componentId,
const mat4 view,
const mat4 proj,
const mat4 model,
void *user
);
typedef struct {
spritebatchsprite_t sprites[ENTITY_RENDERABLE_SPRITEBATCH_SPRITES_MAX];
uint16_t spriteCount;
} entityrenderablespritebatch_t;
typedef struct {
entityrenderabletype_t type;
shader_t *shader;
union {
struct {
mesh_t *mesh;
shadermaterial_t material;
};
entityrenderablespritebatch_t spritebatch;
struct {
entityrenderablecallback_t callback;
void (*userFree)(void *user);
void *user;
};
};
} entityrenderable_t;
/**
* Initializes the entity renderable component. Defaults to
* ENTITY_RENDERABLE_TYPE_MATERIAL, the unlit shader, white color, no mesh.
*/
void entityRenderableInit(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Disposes the entity renderable component, freeing any callback user data.
*/
void entityRenderableDispose(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Gets the renderable type.
*/
entityrenderabletype_t entityRenderableGetType(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Sets the renderable type.
*/
void entityRenderableSetType(
const entityid_t entityId,
const componentid_t componentId,
const entityrenderabletype_t type
);
/**
* Gets the mesh pointer (ENTITY_RENDERABLE_TYPE_MATERIAL only).
*/
mesh_t * entityRenderableGetMesh(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Sets the mesh pointer (ENTITY_RENDERABLE_TYPE_MATERIAL only).
*/
void entityRenderableSetMesh(
const entityid_t entityId,
const componentid_t componentId,
mesh_t *mesh
);
/**
* Gets the shader pointer.
*/
shader_t * entityRenderableGetShader(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Sets the shader pointer.
*/
void entityRenderableSetShader(
const entityid_t entityId,
const componentid_t componentId,
shader_t *shader
);
/**
* Gets a pointer to the shader material union
* (ENTITY_RENDERABLE_TYPE_MATERIAL only).
*/
shadermaterial_t * entityRenderableGetShaderMaterial(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Sets the unlit color (ENTITY_RENDERABLE_TYPE_MATERIAL only).
*/
void entityRenderableSetColor(
const entityid_t entityId,
const componentid_t componentId,
const color_t color
);
/**
* Appends a sprite to the spritebatch renderable
* (ENTITY_RENDERABLE_TYPE_SPRITEBATCH only).
* Does nothing if the sprite buffer is full.
*/
void entityRenderableSpriteBatchAdd(
const entityid_t entityId,
const componentid_t componentId,
const spritebatchsprite_t *sprite
);
/**
* Clears all buffered sprites from the spritebatch renderable
* (ENTITY_RENDERABLE_TYPE_SPRITEBATCH only).
*/
void entityRenderableSpriteBatchClear(
const entityid_t entityId,
const componentid_t componentId
);
@@ -0,0 +1,9 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
entitytrigger.c
)
@@ -0,0 +1,54 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "entity/entitymanager.h"
void entityTriggerInit(
const entityid_t entityId,
const componentid_t componentId
) {
entitytrigger_t *t = componentGetData(
entityId, componentId, COMPONENT_TYPE_TRIGGER
);
glm_vec3_zero(t->min);
glm_vec3_zero(t->max);
}
entitytrigger_t * entityTriggerGet(
const entityid_t entityId,
const componentid_t componentId
) {
return componentGetData(entityId, componentId, COMPONENT_TYPE_TRIGGER);
}
bool_t entityTriggerContains(
const entityid_t entityId,
const componentid_t componentId,
const vec3 point
) {
entitytrigger_t *t = componentGetData(
entityId, componentId, COMPONENT_TYPE_TRIGGER
);
return (
point[0] >= t->min[0] && point[0] <= t->max[0] &&
point[1] >= t->min[1] && point[1] <= t->max[1] &&
point[2] >= t->min[2] && point[2] <= t->max[2]
);
}
void entityTriggerSetBounds(
const entityid_t entityId,
const componentid_t componentId,
const vec3 min,
const vec3 max
) {
entitytrigger_t *t = componentGetData(
entityId, componentId, COMPONENT_TYPE_TRIGGER
);
glm_vec3_copy((float_t*)min, t->min);
glm_vec3_copy((float_t*)max, t->max);
}
@@ -0,0 +1,49 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "entity/entitybase.h"
typedef struct {
vec3 min;
vec3 max;
} entitytrigger_t;
/**
* Initializes the trigger component with zeroed bounds.
*/
void entityTriggerInit(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Returns a pointer to the trigger component data.
*/
entitytrigger_t * entityTriggerGet(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Returns true if the given world-space point lies within [min, max].
*/
bool_t entityTriggerContains(
const entityid_t entityId,
const componentid_t componentId,
const vec3 point
);
/**
* Sets both bounds at once.
*/
void entityTriggerSetBounds(
const entityid_t entityId,
const componentid_t componentId,
const vec3 min,
const vec3 max
);
+7 -7
View File
@@ -7,9 +7,9 @@
#include "entity/component/display/entityposition.h" #include "entity/component/display/entityposition.h"
#include "entity/component/display/entitycamera.h" #include "entity/component/display/entitycamera.h"
#include "entity/component/display/entitymesh.h" #include "entity/component/display/entityrenderable.h"
#include "entity/component/display/entitymaterial.h"
#include "entity/component/physics/entityphysics.h" #include "entity/component/physics/entityphysics.h"
#include "entity/component/trigger/entitytrigger.h"
// Name (Uppercase) // Name (Uppercase)
// Structure // Structure
@@ -17,8 +17,8 @@
// Init function (optional) // Init function (optional)
// Dispose function (optional) // Dispose function (optional)
X(POSITION, entityposition_t, position, entityPositionInit, NULL) X(POSITION, entityposition_t, position, entityPositionInit, NULL)
X(CAMERA, entitycamera_t, camera, entityCameraInit, NULL) X(CAMERA, entitycamera_t, camera, entityCameraInit, NULL)
X(MESH, entitymesh_t, mesh, entityMeshInit, entityMeshDispose) X(RENDERABLE, entityrenderable_t, renderable, entityRenderableInit, entityRenderableDispose)
X(MATERIAL, entitymaterial_t, material, entityMaterialInit, NULL) X(PHYSICS, entityphysics_t, physics, entityPhysicsInit, entityPhysicsDispose)
X(PHYSICS, entityphysics_t, physics, entityPhysicsInit, entityPhysicsDispose) X(TRIGGER, entitytrigger_t, trigger, entityTriggerInit, NULL)
+18 -7
View File
@@ -6,6 +6,7 @@
*/ */
#include "entitymanager.h" #include "entitymanager.h"
#include "component/display/entityposition.h"
#include "util/memory.h" #include "util/memory.h"
#include "assert/assert.h" #include "assert/assert.h"
@@ -22,7 +23,7 @@ void entityInit(const entityid_t entityId) {
) { ) {
ENTITY_MANAGER.entitiesWithComponent[ ENTITY_MANAGER.entitiesWithComponent[
compType * ENTITY_COUNT_MAX + entityId compType * ENTITY_COUNT_MAX + entityId
] = 0xFF; ] = COMPONENT_ID_INVALID;
} }
ent->state |= ENTITY_STATE_ACTIVE; ent->state |= ENTITY_STATE_ACTIVE;
@@ -52,7 +53,7 @@ componentid_t entityAddComponent(
} }
assertUnreachable("Entity has no more component slots available"); assertUnreachable("Entity has no more component slots available");
return 0xFF; return COMPONENT_ID_INVALID;
} }
componentid_t entityGetComponent( componentid_t entityGetComponent(
@@ -62,7 +63,7 @@ componentid_t entityGetComponent(
componentid_t compId = ENTITY_MANAGER.entitiesWithComponent[ componentid_t compId = ENTITY_MANAGER.entitiesWithComponent[
type * ENTITY_COUNT_MAX + entityId type * ENTITY_COUNT_MAX + entityId
]; ];
if(compId == 0xFF) return compId; if(compId == COMPONENT_ID_INVALID) return compId;
assertTrue( assertTrue(
ENTITY_MANAGER.components[componentGetIndex(entityId, compId)].type == type, ENTITY_MANAGER.components[componentGetIndex(entityId, compId)].type == type,
"Component type mismatch" "Component type mismatch"
@@ -70,17 +71,27 @@ componentid_t entityGetComponent(
return compId; return compId;
} }
void entityDisposeDeep(const entityid_t entityId) {
componentid_t posComp = entityGetComponent(entityId, COMPONENT_TYPE_POSITION);
if(posComp != COMPONENT_ID_INVALID) {
entityPositionDisposeDeep(entityId, posComp);
} else {
entityDispose(entityId);
}
}
void entityDispose(const entityid_t entityId) { void entityDispose(const entityid_t entityId) {
componentindex_t compInd; componentindex_t compInd;
entity_t *ent = &ENTITY_MANAGER.entities[entityId]; entity_t *ent = &ENTITY_MANAGER.entities[entityId];
for(componentid_t i = 0; i < ENTITY_COMPONENT_COUNT_MAX; i++) { for(componentid_t i = 0; i < ENTITY_COMPONENT_COUNT_MAX; i++) {
compInd = componentGetIndex(entityId, i); compInd = componentGetIndex(entityId, i);
if(ENTITY_MANAGER.components[compInd].type == COMPONENT_TYPE_NULL) continue; componenttype_t type = ENTITY_MANAGER.components[compInd].type;
componentDispose(entityId, i); if(type == COMPONENT_TYPE_NULL) continue;
ENTITY_MANAGER.entitiesWithComponent[ ENTITY_MANAGER.entitiesWithComponent[
ENTITY_MANAGER.components[compInd].type * ENTITY_COUNT_MAX + entityId type * ENTITY_COUNT_MAX + entityId
] = 0xFF; ] = COMPONENT_ID_INVALID;
componentDispose(entityId, i);
} }
ent->state = 0; ent->state = 0;
+10 -1
View File
@@ -35,7 +35,7 @@ componentid_t entityAddComponent(
/** /**
* Gets the ID of the component of the given type on the entity with the given * Gets the ID of the component of the given type on the entity with the given
* ID, or 0xFF if the entity lacks the component. * ID, or COMPONENT_ID_INVALID if the entity lacks the component.
* *
* @param entityId The ID of the entity to get the component from. * @param entityId The ID of the entity to get the component from.
* @param type The type of the component to get. * @param type The type of the component to get.
@@ -52,3 +52,12 @@ componentid_t entityGetComponent(
* @param entityId The ID of the entity to dispose of. * @param entityId The ID of the entity to dispose of.
*/ */
void entityDispose(const entityid_t entityId); void entityDispose(const entityid_t entityId);
/**
* Disposes of an entity and all of its position-component descendants
* recursively. If the entity has no position component, behaves like
* entityDispose.
*
* @param entityId The root entity ID.
*/
void entityDisposeDeep(const entityid_t entityId);
+3
View File
@@ -11,6 +11,9 @@
#define ENTITY_COUNT_MAX 20 #define ENTITY_COUNT_MAX 20
#define ENTITY_COMPONENT_COUNT_MAX 8 #define ENTITY_COMPONENT_COUNT_MAX 8
#define ENTITY_ID_INVALID 0xFF
#define COMPONENT_ID_INVALID 0xFF
typedef uint8_t entityid_t; typedef uint8_t entityid_t;
typedef uint8_t componentid_t; typedef uint8_t componentid_t;
typedef uint16_t componentindex_t; typedef uint16_t componentindex_t;
+2 -2
View File
@@ -15,7 +15,7 @@ entitymanager_t ENTITY_MANAGER;
void entityManagerInit(void) { void entityManagerInit(void) {
memoryZero(&ENTITY_MANAGER, sizeof(entitymanager_t)); memoryZero(&ENTITY_MANAGER, sizeof(entitymanager_t));
memorySet( memorySet(
ENTITY_MANAGER.entitiesWithComponent, 0xFF, ENTITY_MANAGER.entitiesWithComponent, COMPONENT_ID_INVALID,
sizeof(entityid_t) * COMPONENT_TYPE_COUNT * ENTITY_COUNT_MAX sizeof(entityid_t) * COMPONENT_TYPE_COUNT * ENTITY_COUNT_MAX
); );
@@ -33,7 +33,7 @@ entityid_t entityManagerAdd() {
return i; return i;
} }
assertUnreachable("No more entity IDs available"); assertUnreachable("No more entity IDs available");
return 0xFF; return ENTITY_ID_INVALID;
} }
void entityManagerDispose(void) { void entityManagerDispose(void) {
+11
View File
@@ -0,0 +1,11 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
maptypes.c
map.c
mapchunk.c
)
+178
View File
@@ -0,0 +1,178 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "map.h"
#include "assert/assert.h"
#include "asset/assetfile.h"
#include "util/memory.h"
#include "util/string.h"
#include "console/console.h"
#include "script/module/overworld/modulemap.h"
map_t MAP;
chunkindex_t mapChunkRelToIndex(
chunkunit_t rx,
chunkunit_t ry,
chunkunit_t rz
) {
return (chunkindex_t)(
rz * (MAP_CHUNKS_WIDE * MAP_CHUNKS_HIGH) +
ry * MAP_CHUNKS_WIDE +
rx
);
}
void mapInit(void) {
memoryZero(&MAP, sizeof(map_t));
MAP.scriptRef = MAP_SCRIPT_REF_NONE;
}
errorret_t mapLoad(const char_t *handle) {
assertStrLenMin(handle, 1, "Map handle cannot be empty");
assertStrLenMax(handle, MAP_HANDLE_MAX - 1, "Map handle too long");
if(mapIsLoaded()) mapDispose();
memoryZero(&MAP, sizeof(map_t));
MAP.scriptRef = MAP_SCRIPT_REF_NONE;
stringCopy(MAP.handle, handle, MAP_HANDLE_MAX);
char_t path[ASSET_FILE_NAME_MAX];
stringFormat(path, sizeof(path), "maps/%s/init.js", handle);
jerry_value_t mapClass = MAP_SCRIPT_REF_NONE;
errorChain(scriptManagerExecFile(path, &mapClass));
if(!jerry_value_is_function(mapClass)) {
if(mapClass != MAP_SCRIPT_REF_NONE) jerry_value_free(mapClass);
errorThrow("Map '%s' must export a constructor function", handle);
}
jerry_value_t mapObj = jerry_construct(mapClass, NULL, 0);
jerry_value_free(mapClass);
if(jerry_value_is_exception(mapObj)) {
char_t errMsg[512];
moduleBaseExceptionMessage(mapObj, errMsg, sizeof(errMsg));
jerry_value_free(mapObj);
errorThrow("Map '%s' constructor threw: %s", handle, errMsg);
}
MAP.scriptRef = mapObj;
consolePrint("Map loaded: %s", handle);
errorOk();
}
bool_t mapIsLoaded(void) {
return MAP.loaded;
}
errorret_t mapPositionSet(tilepos_t tilePos) {
assertTrue(MAP.chunkTileWidth > 0, "chunkTileWidth not set");
assertTrue(MAP.chunkTileHeight > 0, "chunkTileHeight not set");
assertTrue(MAP.chunkTileDepth > 0, "chunkTileDepth not set");
// Convert tile position to chunk-space window origin.
chunkpos_t newPos = {
.x = (chunkunit_t)(tilePos.x / MAP.chunkTileWidth),
.y = (chunkunit_t)(tilePos.y / MAP.chunkTileHeight),
.z = (chunkunit_t)(tilePos.z / MAP.chunkTileDepth),
};
if(MAP.loaded && chunkPosEqual(MAP.chunkPosition, newPos)) errorOk();
// Categorise existing chunks as remaining or freed.
chunkindex_t remaining[MAP_CHUNKS_COUNT];
chunkindex_t freed[MAP_CHUNKS_COUNT];
chunkindex_t remainingCount = 0;
chunkindex_t freedCount = 0;
for(chunkindex_t i = 0; i < MAP_CHUNKS_COUNT; i++) {
mapchunk_t *chunk = &MAP.chunks[i];
chunkpos_t p = chunk->position;
bool_t stays = MAP.loaded &&
p.x >= newPos.x && p.x < newPos.x + MAP_CHUNKS_WIDE &&
p.y >= newPos.y && p.y < newPos.y + MAP_CHUNKS_HIGH &&
p.z >= newPos.z && p.z < newPos.z + MAP_CHUNKS_DEEP;
if(stays) {
remaining[remainingCount++] = i;
} else {
if(MAP.loaded) mapChunkUnload(chunk);
freed[freedCount++] = i;
}
}
// Build chunkOrder for the new window, loading into freed slots as needed.
chunkindex_t orderIndex = 0;
for(chunkunit_t zOff = 0; zOff < MAP_CHUNKS_DEEP; zOff++) {
for(chunkunit_t yOff = 0; yOff < MAP_CHUNKS_HIGH; yOff++) {
for(chunkunit_t xOff = 0; xOff < MAP_CHUNKS_WIDE; xOff++) {
chunkpos_t target = {
.x = (chunkunit_t)(newPos.x + xOff),
.y = (chunkunit_t)(newPos.y + yOff),
.z = (chunkunit_t)(newPos.z + zOff),
};
// Check if the target chunk is already loaded.
chunkindex_t poolIdx = -1;
for(chunkindex_t r = 0; r < remainingCount; r++) {
if(chunkPosEqual(MAP.chunks[remaining[r]].position, target)) {
poolIdx = remaining[r];
break;
}
}
// Otherwise recycle a freed slot.
if(poolIdx == -1) {
poolIdx = freed[--freedCount];
MAP.chunks[poolIdx].position = target;
errorChain(mapChunkLoad(&MAP.chunks[poolIdx]));
}
MAP.chunkOrder[orderIndex++] = &MAP.chunks[poolIdx];
}}}
MAP.chunkPosition = newPos;
MAP.loaded = true;
errorOk();
}
mapchunk_t *mapGetChunkAt(chunkpos_t pos) {
if(!MAP.loaded) return NULL;
chunkpos_t p = MAP.chunkPosition;
if(
pos.x < p.x || pos.x >= p.x + MAP_CHUNKS_WIDE ||
pos.y < p.y || pos.y >= p.y + MAP_CHUNKS_HIGH ||
pos.z < p.z || pos.z >= p.z + MAP_CHUNKS_DEEP
) return NULL;
chunkindex_t idx = mapChunkRelToIndex(
pos.x - p.x, pos.y - p.y, pos.z - p.z
);
return MAP.chunkOrder[idx];
}
errorret_t mapUpdate(void) {
if(!MAP.loaded) errorOk();
errorChain(moduleMapCall("update"));
errorOk();
}
void mapDispose(void) {
consolePrint("Map disposing: %s", MAP.handle);
if(MAP.scriptRef != MAP_SCRIPT_REF_NONE) {
moduleMapCall("dispose");
moduleMapReset();
}
if(!MAP.loaded) return;
for(chunkindex_t i = 0; i < MAP_CHUNKS_COUNT; i++) {
mapChunkUnload(&MAP.chunks[i]);
}
MAP.loaded = false;
}
+102
View File
@@ -0,0 +1,102 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "mapchunk.h"
#include "error/error.h"
#include "script/scriptmanager.h"
#define MAP_NAME_MAX 64
#define MAP_HANDLE_MAX 32
#define MAP_CHUNKS_WIDE 3
#define MAP_CHUNKS_HIGH 3
#define MAP_CHUNKS_DEEP 2
#define MAP_CHUNKS_COUNT (MAP_CHUNKS_WIDE * MAP_CHUNKS_HIGH * MAP_CHUNKS_DEEP)
typedef struct {
char_t name[MAP_NAME_MAX];
char_t handle[MAP_HANDLE_MAX];
uint16_t chunkTileWidth;
uint16_t chunkTileHeight;
uint16_t chunkTileDepth;
mapchunk_t chunks[MAP_CHUNKS_COUNT];
mapchunk_t *chunkOrder[MAP_CHUNKS_COUNT];
chunkpos_t chunkPosition;
bool_t loaded;
jerry_value_t scriptRef;
} map_t;
/** Sentinel value meaning no map script is loaded. */
#define MAP_SCRIPT_REF_NONE ((jerry_value_t)0)
extern map_t MAP;
/**
* Initializes the map, zeroing all state.
*/
void mapInit(void);
/**
* Prepares the map for use with the given handle. If a map is already loaded
* it is disposed first. Chunk positions are not set until mapPositionSet is
* called.
*
* @param handle Short identifier for this map (max MAP_HANDLE_MAX - 1 chars).
* @return An error code.
*/
errorret_t mapLoad(const char_t *handle);
/**
* Returns true if a map is currently loaded.
*
* @return true if a map is loaded, false otherwise.
*/
bool_t mapIsLoaded(void);
/**
* Converts a chunk position relative to the window origin to its pool index.
*
* @param rx Relative chunk X offset within the window.
* @param ry Relative chunk Y offset within the window.
* @param rz Relative chunk Z offset within the window.
* @return The flat pool index for that relative position.
*/
chunkindex_t mapChunkRelToIndex(
chunkunit_t rx,
chunkunit_t ry,
chunkunit_t rz
);
/**
* Slides the loaded chunk window so its origin is the chunk that contains
* the given tile-space position. Only the delta is loaded/unloaded.
*
* @param tilePos Tile-space position of the new window origin.
* @return An error code.
*/
errorret_t mapPositionSet(tilepos_t tilePos);
/**
* Updates the map each frame.
*
* @return An error code.
*/
errorret_t mapUpdate(void);
/**
* Disposes the map, unloading all chunks.
*/
void mapDispose(void);
/**
* Returns the chunk at the given absolute chunk-space position, or NULL if
* it is outside the currently loaded window.
*
* @param pos Absolute chunk-space position to look up.
* @return Pointer to the chunk, or NULL if not loaded.
*/
mapchunk_t *mapGetChunkAt(chunkpos_t pos);
+96
View File
@@ -0,0 +1,96 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "mapchunk.h"
#include "map.h"
#include "entity/entitymanager.h"
#include "util/memory.h"
#include "util/string.h"
#include "asset/asset.h"
#include "console/console.h"
#include "script/module/overworld/modulemapchunk.h"
errorret_t mapChunkLoad(mapchunk_t *chunk) {
chunk->entityCount = 0;
chunk->scriptRef = MAP_CHUNK_SCRIPT_REF_NONE;
memoryZero(chunk->entities, sizeof(chunk->entities));
if(MAP.handle[0] == '\0') errorOk();
char_t path[ASSET_FILE_NAME_MAX];
stringFormat(
path, sizeof(path),
"maps/%s/chunks/%d_%d_%d.js",
MAP.handle,
(int)chunk->position.x,
(int)chunk->position.y,
(int)chunk->position.z
);
if(!assetFileExists(path)) errorOk();
jerry_value_t chunkClass = MAP_CHUNK_SCRIPT_REF_NONE;
errorChain(scriptManagerExecFile(path, &chunkClass));
if(!jerry_value_is_function(chunkClass)) {
if(chunkClass != MAP_CHUNK_SCRIPT_REF_NONE) jerry_value_free(chunkClass);
errorThrow("Chunk script '%s' must export a constructor", path);
}
jerry_value_t args[3] = {
jerry_number((double)chunk->position.x),
jerry_number((double)chunk->position.y),
jerry_number((double)chunk->position.z),
};
jerry_value_t chunkObj = jerry_construct(chunkClass, args, 3);
jerry_value_free(chunkClass);
jerry_value_free(args[0]);
jerry_value_free(args[1]);
jerry_value_free(args[2]);
if(jerry_value_is_exception(chunkObj)) {
jerry_value_free(chunkObj);
errorThrow("Chunk script '%s' constructor threw", path);
}
chunk->scriptRef = chunkObj;
consolePrint(
"Chunk loaded: %s [%d,%d,%d]",
path,
(int)chunk->position.x,
(int)chunk->position.y,
(int)chunk->position.z
);
errorOk();
}
void mapChunkUnload(mapchunk_t *chunk) {
consolePrint(
"Chunk unloading: [%d,%d,%d]",
(int)chunk->position.x,
(int)chunk->position.y,
(int)chunk->position.z
);
if(chunk->scriptRef != MAP_CHUNK_SCRIPT_REF_NONE) {
jerry_value_t key = jerry_string_sz("dispose");
jerry_value_t fn = jerry_object_get(chunk->scriptRef, key);
jerry_value_free(key);
if(jerry_value_is_function(fn)) {
jerry_value_t result = jerry_call(fn, chunk->scriptRef, NULL, 0);
jerry_value_free(result);
}
jerry_value_free(fn);
jerry_value_free(chunk->scriptRef);
chunk->scriptRef = MAP_CHUNK_SCRIPT_REF_NONE;
}
for(uint8_t i = 0; i < chunk->entityCount; i++) {
entityDispose(chunk->entities[i]);
}
chunk->entityCount = 0;
}
+39
View File
@@ -0,0 +1,39 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "maptypes.h"
#include "entity/entitybase.h"
#include "error/error.h"
#include "script/scriptmanager.h"
#define MAP_CHUNK_ENTITY_COUNT_MAX 64
/** Sentinel value meaning no chunk script is loaded. */
#define MAP_CHUNK_SCRIPT_REF_NONE ((jerry_value_t)0)
typedef struct {
chunkpos_t position;
entityid_t entities[MAP_CHUNK_ENTITY_COUNT_MAX];
uint8_t entityCount;
jerry_value_t scriptRef;
} mapchunk_t;
/**
* Loads content into a chunk at its current position.
*
* @param chunk The chunk to load.
* @return An error code.
*/
errorret_t mapChunkLoad(mapchunk_t *chunk);
/**
* Disposes all entities owned by the chunk and resets its state.
*
* @param chunk The chunk to unload.
*/
void mapChunkUnload(mapchunk_t *chunk);
+12
View File
@@ -0,0 +1,12 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "maptypes.h"
bool_t chunkPosEqual(chunkpos_t a, chunkpos_t b) {
return a.x == b.x && a.y == b.y && a.z == b.z;
}
+30
View File
@@ -0,0 +1,30 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
typedef int16_t chunkunit_t;
typedef int16_t chunkindex_t;
typedef int32_t tileunit_t;
typedef struct {
chunkunit_t x, y, z;
} chunkpos_t;
typedef struct {
tileunit_t x, y, z;
} tilepos_t;
/**
* Checks if two chunk positions are equal.
*
* @param a The first chunk position.
* @param b The second chunk position.
* @return true if the positions are equal, false otherwise.
*/
bool_t chunkPosEqual(chunkpos_t a, chunkpos_t b);
+12
View File
@@ -314,3 +314,15 @@ errorret_t saveStreamWriteDateImpl(
errorOk(); errorOk();
} }
errorret_t saveFileLoad(savestream_t *stream, savefile_t *file) {
saveFileReadHeader(stream, file->header);
saveFileReadVersion(stream, &file->version);
errorOk();
}
errorret_t saveFileWrite(savestream_t *stream, savefile_t *file) {
saveFileWriteHeader(stream, file->header);
saveFileWriteVersion(stream, &file->version);
errorOk();
}
+59 -52
View File
@@ -10,7 +10,9 @@
#include "time/time.h" #include "time/time.h"
#include "display/screen/screen.h" #include "display/screen/screen.h"
#include "entity/entitymanager.h" #include "entity/entitymanager.h"
#include "entity/component/display/entityrenderable.h"
#include "display/shader/shaderunlit.h" #include "display/shader/shaderunlit.h"
#include "display/spritebatch/spritebatch.h"
#include "display/screen/screen.h" #include "display/screen/screen.h"
#include "console/console.h" #include "console/console.h"
#include "util/string.h" #include "util/string.h"
@@ -67,7 +69,7 @@ errorret_t sceneRender(void) {
entityid_t camEnt = camEnts[camIndex]; entityid_t camEnt = camEnts[camIndex];
componentid_t camComp = camComps[camIndex]; componentid_t camComp = camComps[camIndex];
componentid_t camPos = entityGetComponent(camEnt, COMPONENT_TYPE_POSITION); componentid_t camPos = entityGetComponent(camEnt, COMPONENT_TYPE_POSITION);
if(camPos == 0xFF) { if(camPos == COMPONENT_ID_INVALID) {
logError("Camera entity without entity position found\n"); logError("Camera entity without entity position found\n");
continue; continue;
} }
@@ -75,63 +77,68 @@ errorret_t sceneRender(void) {
entityCameraGetProjection(camEnt, camComp, proj); entityCameraGetProjection(camEnt, camComp, proj);
entityPositionGetTransform(camEnt, camPos, view); entityPositionGetTransform(camEnt, camPos, view);
// For each entity (I could iterate only over entities with mesh/material)
// but in future I may have different renderable types.
for(entityid_t entityId = 0; entityId < ENTITY_COUNT_MAX; entityId++) { for(entityid_t entityId = 0; entityId < ENTITY_COUNT_MAX; entityId++) {
// Does this entity have a material? componentid_t renderComp = entityGetComponent(
componentid_t matComp = entityGetComponent( entityId, COMPONENT_TYPE_RENDERABLE
entityId, COMPONENT_TYPE_MATERIAL
); );
if(matComp != 0xFF) { if(renderComp == COMPONENT_ID_INVALID) continue;
// Yes, get the mesh
componentid_t meshComp = entityGetComponent(
entityId, COMPONENT_TYPE_MESH
);
if(meshComp == 0xFF) {
logError("Entity with material but no mesh found\n");
continue;
}
mesh_t *mesh = entityMeshGetMesh(entityId, meshComp);
if(mesh == NULL) {
logError("Entity with material but no mesh found\n");
continue;
}
// Yes, get the material and shader. entityrenderable_t *r = componentGetData(
shadermaterial_t *material = entityMaterialGetShaderMaterial( entityId, renderComp, COMPONENT_TYPE_RENDERABLE
entityId, matComp );
);
shader_t *shader = entityMaterialGetShader(entityId, matComp);
if(shader == NULL) {
logError("Entity with material but no shader found\n");
continue;
}
// Get the transform. componentid_t posComp = entityGetComponent(
componentid_t meshPos = entityGetComponent( entityId, COMPONENT_TYPE_POSITION
entityId, COMPONENT_TYPE_POSITION );
); if(posComp == COMPONENT_ID_INVALID) {
if(meshPos == 0xFF) { glm_mat4_identity(model);
glm_mat4_identity(model); } else {
} else { entityPositionGetTransform(entityId, posComp, model);
entityPositionGetTransform(entityId, meshPos, model);
}
// Render the mesh.
if(shaderCurrent != shader) {
shaderCurrent = shader;
errorChain(shaderBind(shaderCurrent));
errorChain(shaderSetMatrix(shader, SHADER_UNLIT_PROJECTION, proj));
errorChain(shaderSetMatrix(shader, SHADER_UNLIT_VIEW, view));
}
errorChain(shaderSetMatrix(shader, SHADER_UNLIT_MODEL, model));
errorChain(shaderSetMaterial(shader, material));
errorChain(meshDraw(mesh, 0, -1));
continue;
} }
// No, in future there may be other renderable types. switch(r->type) {
case ENTITY_RENDERABLE_TYPE_CALLBACK: {
if(!r->callback) break;
errorChain(r->callback(
entityId, renderComp, view, proj, model, r->user
));
break;
}
case ENTITY_RENDERABLE_TYPE_MATERIAL: {
shader_t *shader = r->shader;
if(!shader) break;
if(!r->mesh) break;
if(shaderCurrent != shader) {
shaderCurrent = shader;
errorChain(shaderBind(shaderCurrent));
errorChain(shaderSetMatrix(shader, SHADER_UNLIT_PROJECTION, proj));
errorChain(shaderSetMatrix(shader, SHADER_UNLIT_VIEW, view));
}
errorChain(shaderSetMatrix(shader, SHADER_UNLIT_MODEL, model));
errorChain(shaderSetMaterial(shader, &r->material));
errorChain(meshDraw(r->mesh, 0, -1));
break;
}
case ENTITY_RENDERABLE_TYPE_SPRITEBATCH: {
if(r->spritebatch.spriteCount == 0) break;
shader_t *shader = r->shader;
if(!shader) break;
if(shaderCurrent != shader) {
shaderCurrent = shader;
errorChain(shaderBind(shaderCurrent));
errorChain(shaderSetMatrix(shader, SHADER_UNLIT_PROJECTION, proj));
errorChain(shaderSetMatrix(shader, SHADER_UNLIT_VIEW, view));
}
errorChain(shaderSetMatrix(shader, SHADER_UNLIT_MODEL, model));
for(uint16_t si = 0; si < r->spritebatch.spriteCount; si++) {
errorChain(spriteBatchBufferSprite(&r->spritebatch.sprites[si]));
}
errorChain(spriteBatchFlush());
break;
}
}
} }
} }
@@ -5,6 +5,7 @@
#pragma once #pragma once
#include "script/module/modulebase.h" #include "script/module/modulebase.h"
#include "script/module/event/moduleEvent.h"
#include "script/scriptproto.h" #include "script/scriptproto.h"
#include "animation/animation.h" #include "animation/animation.h"
#include "util/memory.h" #include "util/memory.h"
@@ -36,24 +37,6 @@ static inline animation_t *moduleAnimationGet(
return (animation_t *)moduleAnimationGetWrapper(callInfo); return (animation_t *)moduleAnimationGetWrapper(callInfo);
} }
static easingtype_t moduleAnimationReadEasing(const jerry_value_t val) {
if(jerry_value_is_number(val)) {
return (easingtype_t)(uint32_t)jerry_value_as_number(val);
}
if(jerry_value_is_object(val) || jerry_value_is_function(val)) {
jerry_value_t key = jerry_string_sz("type");
jerry_value_t typeVal = jerry_object_get(val, key);
jerry_value_free(key);
easingtype_t result = EASING_LINEAR;
if(jerry_value_is_number(typeVal)) {
result = (easingtype_t)(uint32_t)jerry_value_as_number(typeVal);
}
jerry_value_free(typeVal);
return result;
}
return EASING_LINEAR;
}
static void jsAnimationPropertyFree(void *ptr, jerry_object_native_info_t *info) { static void jsAnimationPropertyFree(void *ptr, jerry_object_native_info_t *info) {
(void)info; (void)info;
memoryFree(ptr); memoryFree(ptr);
@@ -98,9 +81,7 @@ static jerry_value_t moduleAnimationFireKeyframes(
float_t prevTime, float_t prevTime,
float_t newTime float_t newTime
) { ) {
jerry_value_t kfKey = jerry_string_sz("_keyframes"); jerry_value_t kfArr = moduleBaseGetProp(propObj, "_keyframes");
jerry_value_t kfArr = jerry_object_get(propObj, kfKey);
jerry_value_free(kfKey);
if(!jerry_value_is_array(kfArr)) { if(!jerry_value_is_array(kfArr)) {
jerry_value_free(kfArr); jerry_value_free(kfArr);
@@ -111,16 +92,12 @@ static jerry_value_t moduleAnimationFireKeyframes(
for(jerry_length_t i = 0; i < len; i++) { for(jerry_length_t i = 0; i < len; i++) {
jerry_value_t kfObj = jerry_object_get_index(kfArr, i); jerry_value_t kfObj = jerry_object_get_index(kfArr, i);
jerry_value_t tKey = jerry_string_sz("time"); jerry_value_t tVal = moduleBaseGetProp(kfObj, "time");
jerry_value_t tVal = jerry_object_get(kfObj, tKey); float_t kfTime = moduleBaseValueFloat(tVal);
jerry_value_free(tKey);
float_t kfTime = (float_t)jerry_value_as_number(tVal);
jerry_value_free(tVal); jerry_value_free(tVal);
if(prevTime < kfTime && newTime >= kfTime) { if(prevTime < kfTime && newTime >= kfTime) {
jerry_value_t cbKey = jerry_string_sz("onReach"); jerry_value_t cb = moduleBaseGetProp(kfObj, "onReach");
jerry_value_t cb = jerry_object_get(kfObj, cbKey);
jerry_value_free(cbKey);
if(jerry_value_is_function(cb)) { if(jerry_value_is_function(cb)) {
jerry_value_t r = jerry_call(cb, propObj, NULL, 0); jerry_value_t r = jerry_call(cb, propObj, NULL, 0);
@@ -187,22 +164,16 @@ moduleBaseFunction(moduleAnimationConstructor) {
for(jerry_length_t i = 0; i < kfLen; i++) { for(jerry_length_t i = 0; i < kfLen; i++) {
jerry_value_t kf = jerry_object_get_index(kfArr, i); jerry_value_t kf = jerry_object_get_index(kfArr, i);
jerry_value_t tKey = jerry_string_sz("time"); jerry_value_t tVal = moduleBaseGetProp(kf, "time");
jerry_value_t tVal = jerry_object_get(kf, tKey); float_t t = moduleBaseValueFloat(tVal);
jerry_value_free(tKey);
float_t t = (float_t)jerry_value_as_number(tVal);
jerry_value_free(tVal); jerry_value_free(tVal);
jerry_value_t vKey = jerry_string_sz("value"); jerry_value_t vVal = moduleBaseGetProp(kf, "value");
jerry_value_t vVal = jerry_object_get(kf, vKey); float_t v = moduleBaseValueFloat(vVal);
jerry_value_free(vKey);
float_t v = (float_t)jerry_value_as_number(vVal);
jerry_value_free(vVal); jerry_value_free(vVal);
jerry_value_t eKey = jerry_string_sz("easing"); jerry_value_t eVal = moduleBaseGetProp(kf, "easing");
jerry_value_t eVal = jerry_object_get(kf, eKey); easingtype_t e = moduleReadEasing(eVal);
jerry_value_free(eKey);
easingtype_t e = moduleAnimationReadEasing(eVal);
jerry_value_free(eVal); jerry_value_free(eVal);
jerry_value_free(kf); jerry_value_free(kf);
@@ -236,16 +207,12 @@ moduleBaseFunction(moduleAnimationConstructor) {
moduleBaseFunction(moduleAnimationUpdate) { moduleBaseFunction(moduleAnimationUpdate) {
jsAnimation_t *janim = moduleAnimationGetWrapper(callInfo); jsAnimation_t *janim = moduleAnimationGetWrapper(callInfo);
if(!janim) return moduleBaseThrow("Invalid Animation instance"); if(!janim) return moduleBaseThrow("Invalid Animation instance");
if(argc < 1 || !jerry_value_is_number(args[0])) { moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
return moduleBaseThrow("update() expects a number delta");
}
float_t prevTime = janim->anim.time; float_t prevTime = janim->anim.time;
animationUpdate(&janim->anim, (float_t)jerry_value_as_number(args[0])); animationUpdate(&janim->anim, moduleBaseArgFloat(0));
jerry_value_t propsKey = jerry_string_sz("properties"); jerry_value_t propsArr = moduleBaseGetProp(callInfo->this_value, "properties");
jerry_value_t propsArr = jerry_object_get(callInfo->this_value, propsKey);
jerry_value_free(propsKey);
if(jerry_value_is_array(propsArr)) { if(jerry_value_is_array(propsArr)) {
jerry_length_t len = jerry_array_length(propsArr); jerry_length_t len = jerry_array_length(propsArr);
for(jerry_length_t p = 0; p < len; p++) { for(jerry_length_t p = 0; p < len; p++) {
@@ -286,8 +253,8 @@ moduleBaseFunction(moduleAnimationGetLoop) {
moduleBaseFunction(moduleAnimationSetLoop) { moduleBaseFunction(moduleAnimationSetLoop) {
animation_t *anim = moduleAnimationGet(callInfo); animation_t *anim = moduleAnimationGet(callInfo);
if(!anim) return moduleBaseThrow("Invalid Animation instance"); if(!anim) return moduleBaseThrow("Invalid Animation instance");
if(argc < 1) return moduleBaseThrow("Expected boolean"); moduleBaseRequireArgs(1);
if(jerry_value_is_true(args[0])) { if(moduleBaseArgBool(0)) {
anim->flags |= ANIMATION_FLAG_LOOP_ENABLED; anim->flags |= ANIMATION_FLAG_LOOP_ENABLED;
} else { } else {
anim->flags &= ~ANIMATION_FLAG_LOOP_ENABLED; anim->flags &= ~ANIMATION_FLAG_LOOP_ENABLED;
@@ -43,11 +43,8 @@ moduleBaseFunction(moduleConsoleGetVisible) {
} }
moduleBaseFunction(moduleConsoleSetVisible) { moduleBaseFunction(moduleConsoleSetVisible) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); moduleBaseRequireArgs(1);
if(!jerry_value_is_boolean(args[0])) { CONSOLE.visible = moduleBaseArgBool(0);
return moduleBaseThrow("Console.visible: expected boolean");
}
CONSOLE.visible = jerry_value_is_true(args[0]);
return jerry_undefined(); return jerry_undefined();
} }
@@ -85,10 +85,7 @@ moduleBaseFunction(moduleCutsceneDefaultDispose) {
* Returns the instance for optional chaining. * Returns the instance for optional chaining.
*/ */
moduleBaseFunction(moduleCutsceneThen) { moduleBaseFunction(moduleCutsceneThen) {
if(argc < 1 || !jerry_value_is_function(args[0])) { moduleBaseRequireArgs(1); moduleBaseRequireFunction(0);
return moduleBaseThrow("then() expects a function argument");
}
jerry_value_t key = jerry_string_sz("_onFinished"); jerry_value_t key = jerry_string_sz("_onFinished");
jerry_object_set(callInfo->this_value, key, args[0]); jerry_object_set(callInfo->this_value, key, args[0]);
jerry_value_free(key); jerry_value_free(key);
@@ -104,10 +101,7 @@ moduleBaseFunction(moduleCutsceneThen) {
* Returns the instance to allow chaining .then() directly. * Returns the instance to allow chaining .then() directly.
*/ */
moduleBaseFunction(moduleCutscenePlay) { moduleBaseFunction(moduleCutscenePlay) {
if(argc < 1 || !jerry_value_is_object(args[0])) { moduleBaseRequireArgs(1); moduleBaseRequireObject(0);
return moduleBaseThrow("play() expects a cutscene instance");
}
if(CUTSCENE.activeRef != CUTSCENE_SCRIPT_REF_NONE) { if(CUTSCENE.activeRef != CUTSCENE_SCRIPT_REF_NONE) {
moduleCutsceneReset(); moduleCutsceneReset();
} }
+31 -69
View File
@@ -22,76 +22,55 @@ static inline color_t * moduleColorGet(
} }
moduleBaseFunction(moduleColorGetR) { moduleBaseFunction(moduleColorGetR) {
color_t *c = moduleColorGet(callInfo); moduleBaseGetOrReturn(color_t, c, moduleColorGet);
return c ? jerry_number(c->r) : jerry_undefined(); return jerry_number(c->r);
} }
moduleBaseFunction(moduleColorGetG) { moduleBaseFunction(moduleColorGetG) {
color_t *c = moduleColorGet(callInfo); moduleBaseGetOrReturn(color_t, c, moduleColorGet);
return c ? jerry_number(c->g) : jerry_undefined(); return jerry_number(c->g);
} }
moduleBaseFunction(moduleColorGetB) { moduleBaseFunction(moduleColorGetB) {
color_t *c = moduleColorGet(callInfo); moduleBaseGetOrReturn(color_t, c, moduleColorGet);
return c ? jerry_number(c->b) : jerry_undefined(); return jerry_number(c->b);
} }
moduleBaseFunction(moduleColorGetA) { moduleBaseFunction(moduleColorGetA) {
color_t *c = moduleColorGet(callInfo); moduleBaseGetOrReturn(color_t, c, moduleColorGet);
return c ? jerry_number(c->a) : jerry_undefined(); return jerry_number(c->a);
} }
moduleBaseFunction(moduleColorSetR) { moduleBaseFunction(moduleColorSetR) {
if(argc < 1) { moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
return moduleBaseThrow("Expected at least 1 argument"); moduleBaseGetOrReturn(color_t, c, moduleColorGet);
} c->r = (colorchannel8_t)moduleBaseArgInt(0);
moduleBaseRequireNumber(0);
color_t *c = moduleColorGet(callInfo);
if(!c) return jerry_undefined();
c->r = (colorchannel8_t)jerry_value_as_number(args[0]);
return args[0]; return args[0];
} }
moduleBaseFunction(moduleColorSetG) { moduleBaseFunction(moduleColorSetG) {
if(argc < 1) { moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
return moduleBaseThrow("Expected at least 1 argument"); moduleBaseGetOrReturn(color_t, c, moduleColorGet);
} c->g = (colorchannel8_t)moduleBaseArgInt(0);
moduleBaseRequireNumber(0);
color_t *c = moduleColorGet(callInfo);
if(!c) return jerry_undefined();
c->g = (colorchannel8_t)jerry_value_as_number(args[0]);
return args[0]; return args[0];
} }
moduleBaseFunction(moduleColorSetB) { moduleBaseFunction(moduleColorSetB) {
if(argc < 1) { moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
return moduleBaseThrow("Expected at least 1 argument"); moduleBaseGetOrReturn(color_t, c, moduleColorGet);
} c->b = (colorchannel8_t)moduleBaseArgInt(0);
moduleBaseRequireNumber(0);
color_t *c = moduleColorGet(callInfo);
if(!c) return jerry_undefined();
c->b = (colorchannel8_t)jerry_value_as_number(args[0]);
return args[0]; return args[0];
} }
moduleBaseFunction(moduleColorSetA) { moduleBaseFunction(moduleColorSetA) {
if(argc < 1) { moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
return moduleBaseThrow("Expected at least 1 argument"); moduleBaseGetOrReturn(color_t, c, moduleColorGet);
} c->a = (colorchannel8_t)moduleBaseArgInt(0);
moduleBaseRequireNumber(0);
color_t *c = moduleColorGet(callInfo);
if(!c) return jerry_undefined();
c->a = (colorchannel8_t)jerry_value_as_number(args[0]);
return args[0]; return args[0];
} }
moduleBaseFunction(moduleColorToString) { moduleBaseFunction(moduleColorToString) {
color_t *c = moduleColorGet(callInfo); moduleBaseGetOrReturn(color_t, c, moduleColorGet);
if(!c) return jerry_undefined();
char_t buf[64]; char_t buf[64];
stringFormat( stringFormat(
buf, sizeof(buf), buf, sizeof(buf),
@@ -107,38 +86,21 @@ static jerry_value_t moduleColorMakeObject(color_t color) {
} }
moduleBaseFunction(moduleColorConstructor) { moduleBaseFunction(moduleColorConstructor) {
if(argc > 0 && !jerry_value_is_number(args[0])) { if(argc > 0 && !jerry_value_is_number(args[0])) return moduleBaseThrow("Color: r must be a number");
return moduleBaseThrow("Color: r must be a number"); if(argc > 1 && !jerry_value_is_number(args[1])) return moduleBaseThrow("Color: g must be a number");
} if(argc > 2 && !jerry_value_is_number(args[2])) return moduleBaseThrow("Color: b must be a number");
if(argc > 1 && !jerry_value_is_number(args[1])) { if(argc > 3 && !jerry_value_is_number(args[3])) return moduleBaseThrow("Color: a must be a number");
return moduleBaseThrow("Color: g must be a number");
}
if(argc > 2 && !jerry_value_is_number(args[2])) {
return moduleBaseThrow("Color: b must be a number");
}
if(argc > 3 && !jerry_value_is_number(args[3])) {
return moduleBaseThrow("Color: a must be a number");
}
color_t c; color_t c;
c.r = argc > 0 ? (colorchannel8_t)jerry_value_as_number(args[0]) : 255; c.r = (colorchannel8_t)moduleBaseOptInt(0, 255);
c.g = argc > 1 ? (colorchannel8_t)jerry_value_as_number(args[1]) : 255; c.g = (colorchannel8_t)moduleBaseOptInt(1, 255);
c.b = argc > 2 ? (colorchannel8_t)jerry_value_as_number(args[2]) : 255; c.b = (colorchannel8_t)moduleBaseOptInt(2, 255);
c.a = argc > 3 ? (colorchannel8_t)jerry_value_as_number(args[3]) : 255; c.a = (colorchannel8_t)moduleBaseOptInt(3, 255);
return moduleColorMakeObject(c); return moduleColorMakeObject(c);
} }
moduleBaseFunction(moduleColorRainbow) { moduleBaseFunction(moduleColorRainbow) {
float_t t; float_t t = moduleBaseOptFloat(0, TIME.time * 4.0f);
if(argc >= 2 && jerry_value_is_number(args[1])) t *= moduleBaseArgFloat(1);
if(argc >= 1 && jerry_value_is_number(args[0])) {
t = (float_t)jerry_value_as_number(args[0]);
} else {
t = TIME.time * 4.0f;
}
if(argc >= 2 && jerry_value_is_number(args[1])) {
t *= (float_t)jerry_value_as_number(args[1]);
}
color_t c; color_t c;
c.r = (colorchannel8_t)((sinf(t) + 1.0f) * 0.5f * 255.0f); c.r = (colorchannel8_t)((sinf(t) + 1.0f) * 0.5f * 255.0f);
+37 -69
View File
@@ -101,20 +101,22 @@ static jerry_value_t moduleMeshFinalize(
// ---- MeshVertex ---- // ---- MeshVertex ----
moduleBaseFunction(moduleMeshVertexGetPosition) { static inline meshvertexscript_t * moduleMeshVertexGet(
meshvertexscript_t *mv = (meshvertexscript_t*)scriptProtoGetValue( const jerry_call_info_t *callInfo
) {
return (meshvertexscript_t*)scriptProtoGetValue(
&MODULE_MESH_VERTEX_PROTO, callInfo->this_value &MODULE_MESH_VERTEX_PROTO, callInfo->this_value
); );
if(!mv) return jerry_undefined(); }
moduleBaseFunction(moduleMeshVertexGetPosition) {
moduleBaseGetOrReturn(meshvertexscript_t, mv, moduleMeshVertexGet);
return moduleVec3RefPush(mv->vertex->pos, NULL, NULL); return moduleVec3RefPush(mv->vertex->pos, NULL, NULL);
} }
moduleBaseFunction(moduleMeshVertexSetPosition) { moduleBaseFunction(moduleMeshVertexSetPosition) {
if(argc < 1) return moduleBaseThrow("Expected position argument"); moduleBaseRequireArgs(1);
meshvertexscript_t *mv = (meshvertexscript_t*)scriptProtoGetValue( moduleBaseGetOrReturn(meshvertexscript_t, mv, moduleMeshVertexGet);
&MODULE_MESH_VERTEX_PROTO, callInfo->this_value
);
if(!mv) return jerry_undefined();
vec3 v; vec3 v;
if(!moduleVec3AnyCheck(args[0], v)) return moduleBaseThrow("Expected Vec3"); if(!moduleVec3AnyCheck(args[0], v)) return moduleBaseThrow("Expected Vec3");
glm_vec3_copy(v, mv->vertex->pos); glm_vec3_copy(v, mv->vertex->pos);
@@ -124,10 +126,9 @@ moduleBaseFunction(moduleMeshVertexSetPosition) {
// ---- Mesh instance ---- // ---- Mesh instance ----
moduleBaseFunction(moduleMeshConstructor) { moduleBaseFunction(moduleMeshConstructor) {
if(argc < 1) return moduleBaseThrow("Expected vertex count"); moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
moduleBaseRequireNumber(0);
int32_t vertexCount = (int32_t)jerry_value_as_number(args[0]); int32_t vertexCount = moduleBaseArgInt(0);
if(vertexCount <= 0) return moduleBaseThrow("Vertex count must be > 0"); if(vertexCount <= 0) return moduleBaseThrow("Vertex count must be > 0");
meshscript_t *ms = moduleMeshAlloc(vertexCount); meshscript_t *ms = moduleMeshAlloc(vertexCount);
@@ -159,14 +160,12 @@ moduleBaseFunction(moduleMeshGetVertices) {
} }
moduleBaseFunction(moduleMeshGetVertexCount) { moduleBaseFunction(moduleMeshGetVertexCount) {
meshscript_t *ms = moduleMeshGet(callInfo); moduleBaseGetOrReturn(meshscript_t, ms, moduleMeshGet);
if(!ms) return jerry_undefined();
return jerry_number((double)ms->vertexCount); return jerry_number((double)ms->vertexCount);
} }
moduleBaseFunction(moduleMeshFlush) { moduleBaseFunction(moduleMeshFlush) {
meshscript_t *ms = moduleMeshGet(callInfo); moduleBaseGetOrReturn(meshscript_t, ms, moduleMeshGet);
if(!ms) return jerry_undefined();
if(!ms->initialized) { if(!ms->initialized) {
(void)meshInit( (void)meshInit(
&ms->mesh, &ms->mesh,
@@ -182,8 +181,7 @@ moduleBaseFunction(moduleMeshFlush) {
} }
moduleBaseFunction(moduleMeshDispose) { moduleBaseFunction(moduleMeshDispose) {
meshscript_t *ms = moduleMeshGet(callInfo); moduleBaseGetOrReturn(meshscript_t, ms, moduleMeshGet);
if(!ms) return jerry_undefined();
if(ms->initialized) { if(ms->initialized) {
(void)meshDispose(&ms->mesh); (void)meshDispose(&ms->mesh);
ms->initialized = false; ms->initialized = false;
@@ -256,10 +254,10 @@ moduleBaseFunction(moduleMeshCreateQuad) {
!jerry_value_is_number(args[2]) || !jerry_value_is_number(args[3])) { !jerry_value_is_number(args[2]) || !jerry_value_is_number(args[3])) {
return moduleBaseThrow("Mesh.createQuad: expected (minX, minY, maxX, maxY)"); return moduleBaseThrow("Mesh.createQuad: expected (minX, minY, maxX, maxY)");
} }
minX = (float_t)jerry_value_as_number(args[0]); minX = moduleBaseArgFloat(0);
minY = (float_t)jerry_value_as_number(args[1]); minY = moduleBaseArgFloat(1);
maxX = (float_t)jerry_value_as_number(args[2]); maxX = moduleBaseArgFloat(2);
maxY = (float_t)jerry_value_as_number(args[3]); maxY = moduleBaseArgFloat(3);
} }
meshscript_t *ms = moduleMeshAlloc(QUAD_VERTEX_COUNT); meshscript_t *ms = moduleMeshAlloc(QUAD_VERTEX_COUNT);
quadBuffer( quadBuffer(
@@ -275,18 +273,9 @@ moduleBaseFunction(moduleMeshCreateQuad) {
// Mesh.createSphere(radius?, stacks?, sectors?) // Mesh.createSphere(radius?, stacks?, sectors?)
moduleBaseFunction(moduleMeshCreateSphere) { moduleBaseFunction(moduleMeshCreateSphere) {
float_t radius = 0.5f; float_t radius = moduleBaseOptFloat(0, 0.5f);
int32_t stacks = SPHERE_STACKS; int32_t stacks = moduleBaseOptInt(1, SPHERE_STACKS);
int32_t sectors = SPHERE_SECTORS; int32_t sectors = moduleBaseOptInt(2, SPHERE_SECTORS);
if(argc >= 1 && jerry_value_is_number(args[0])) {
radius = (float_t)jerry_value_as_number(args[0]);
}
if(argc >= 2 && jerry_value_is_number(args[1])) {
stacks = (int32_t)jerry_value_as_number(args[1]);
}
if(argc >= 3 && jerry_value_is_number(args[2])) {
sectors = (int32_t)jerry_value_as_number(args[2]);
}
int32_t vertexCount = stacks * sectors * 6; int32_t vertexCount = stacks * sectors * 6;
vec3 center = { 0.0f, 0.0f, 0.0f }; vec3 center = { 0.0f, 0.0f, 0.0f };
meshscript_t *ms = moduleMeshAlloc(vertexCount); meshscript_t *ms = moduleMeshAlloc(vertexCount);
@@ -301,13 +290,8 @@ moduleBaseFunction(moduleMeshCreateSphere) {
// Mesh.createPlane(width?, height?) — XZ-aligned, centered at origin // Mesh.createPlane(width?, height?) — XZ-aligned, centered at origin
moduleBaseFunction(moduleMeshCreatePlane) { moduleBaseFunction(moduleMeshCreatePlane) {
float_t width = 1.0f, height = 1.0f; float_t width = moduleBaseOptFloat(0, 1.0f);
if(argc >= 1 && jerry_value_is_number(args[0])) { float_t height = moduleBaseOptFloat(1, 1.0f);
width = (float_t)jerry_value_as_number(args[0]);
}
if(argc >= 2 && jerry_value_is_number(args[1])) {
height = (float_t)jerry_value_as_number(args[1]);
}
vec3 min = { -width * 0.5f, 0.0f, -height * 0.5f }; vec3 min = { -width * 0.5f, 0.0f, -height * 0.5f };
vec3 max = { width * 0.5f, 0.0f, height * 0.5f }; vec3 max = { width * 0.5f, 0.0f, height * 0.5f };
vec2 uvMin = { 0.0f, 0.0f }; vec2 uvMin = { 0.0f, 0.0f };
@@ -325,22 +309,10 @@ moduleBaseFunction(moduleMeshCreatePlane) {
// Mesh.createCapsule(radius?, halfHeight?, capRings?, sectors?) // Mesh.createCapsule(radius?, halfHeight?, capRings?, sectors?)
moduleBaseFunction(moduleMeshCreateCapsule) { moduleBaseFunction(moduleMeshCreateCapsule) {
float_t radius = 0.5f; float_t radius = moduleBaseOptFloat(0, 0.5f);
float_t halfHeight = 0.5f; float_t halfHeight = moduleBaseOptFloat(1, 0.5f);
int32_t capRings = CAPSULE_CAP_RINGS; int32_t capRings = moduleBaseOptInt(2, CAPSULE_CAP_RINGS);
int32_t sectors = CAPSULE_SECTORS; int32_t sectors = moduleBaseOptInt(3, CAPSULE_SECTORS);
if(argc >= 1 && jerry_value_is_number(args[0])) {
radius = (float_t)jerry_value_as_number(args[0]);
}
if(argc >= 2 && jerry_value_is_number(args[1])) {
halfHeight = (float_t)jerry_value_as_number(args[1]);
}
if(argc >= 3 && jerry_value_is_number(args[2])) {
capRings = (int32_t)jerry_value_as_number(args[2]);
}
if(argc >= 4 && jerry_value_is_number(args[3])) {
sectors = (int32_t)jerry_value_as_number(args[3]);
}
int32_t vertexCount = (2 * capRings + 1) * sectors * 6; int32_t vertexCount = (2 * capRings + 1) * sectors * 6;
vec3 center = { 0.0f, 0.0f, 0.0f }; vec3 center = { 0.0f, 0.0f, 0.0f };
meshscript_t *ms = moduleMeshAlloc(vertexCount); meshscript_t *ms = moduleMeshAlloc(vertexCount);
@@ -355,19 +327,15 @@ moduleBaseFunction(moduleMeshCreateCapsule) {
// Mesh.createTriPrism(x0, y0, x1, y1, x2, y2, minZ, maxZ) // Mesh.createTriPrism(x0, y0, x1, y1, x2, y2, minZ, maxZ)
moduleBaseFunction(moduleMeshCreateTriPrism) { moduleBaseFunction(moduleMeshCreateTriPrism) {
if(argc < 8) { moduleBaseRequireArgs(8);
return moduleBaseThrow( float_t x0 = moduleBaseArgFloat(0);
"Mesh.createTriPrism: expected (x0,y0, x1,y1, x2,y2, minZ, maxZ)" float_t y0 = moduleBaseArgFloat(1);
); float_t x1 = moduleBaseArgFloat(2);
} float_t y1 = moduleBaseArgFloat(3);
float_t x0 = (float_t)jerry_value_as_number(args[0]); float_t x2 = moduleBaseArgFloat(4);
float_t y0 = (float_t)jerry_value_as_number(args[1]); float_t y2 = moduleBaseArgFloat(5);
float_t x1 = (float_t)jerry_value_as_number(args[2]); float_t minZ = moduleBaseArgFloat(6);
float_t y1 = (float_t)jerry_value_as_number(args[3]); float_t maxZ = moduleBaseArgFloat(7);
float_t x2 = (float_t)jerry_value_as_number(args[4]);
float_t y2 = (float_t)jerry_value_as_number(args[5]);
float_t minZ = (float_t)jerry_value_as_number(args[6]);
float_t maxZ = (float_t)jerry_value_as_number(args[7]);
meshscript_t *ms = moduleMeshAlloc(TRIPRISM_VERTEX_COUNT); meshscript_t *ms = moduleMeshAlloc(TRIPRISM_VERTEX_COUNT);
triPrismBuffer( triPrismBuffer(
ms->vertices, x0, y0, x1, y1, x2, y2, minZ, maxZ ms->vertices, x0, y0, x1, y1, x2, y2, minZ, maxZ
@@ -28,15 +28,9 @@ moduleBaseFunction(moduleScreenGetBackground) {
} }
moduleBaseFunction(moduleScreenSetBackground) { moduleBaseFunction(moduleScreenSetBackground) {
if(argc < 1 || !jerry_value_is_object(args[0])) { moduleBaseRequireArgs(1); moduleBaseRequireObject(0);
return moduleBaseThrow("Screen background color must be a color object"); color_t *color = (color_t*)scriptProtoGetValue(&MODULE_COLOR_PROTO, args[0]);
} if(!color) return moduleBaseThrow("Background must be a valid color object");
color_t *color = (color_t*)scriptProtoGetValue(
&MODULE_COLOR_PROTO, args[0]
);
if(!color) {
return moduleBaseThrow("Background must be a valid color object");
}
memoryCopy(&SCREEN.background, color, sizeof(color_t)); memoryCopy(&SCREEN.background, color, sizeof(color_t));
return jerry_undefined(); return jerry_undefined();
} }
@@ -21,9 +21,9 @@ moduleBaseFunction(moduleSpriteBatchGetSpriteCount) {
moduleBaseFunction(moduleSpriteBatchPush) { moduleBaseFunction(moduleSpriteBatchPush) {
#if MESH_ENABLE_COLOR #if MESH_ENABLE_COLOR
if(argc < 9) return moduleBaseThrow("expected 9 arguments"); moduleBaseRequireArgs(9);
#else #else
if(argc < 8) return moduleBaseThrow("expected 8 arguments"); moduleBaseRequireArgs(8);
#endif #endif
moduleBaseRequireNumber(0); moduleBaseRequireNumber(0);
@@ -32,27 +32,18 @@ moduleBaseFunction(moduleSpriteBatchPush) {
moduleBaseRequireNumber(3); moduleBaseRequireNumber(3);
#if MESH_ENABLE_COLOR #if MESH_ENABLE_COLOR
if(!jerry_value_is_object(args[4])) {
return moduleBaseThrow("color must be a Color object");
}
color_t *col = (color_t *)scriptProtoGetValue(&MODULE_COLOR_PROTO, args[4]); color_t *col = (color_t *)scriptProtoGetValue(&MODULE_COLOR_PROTO, args[4]);
if(!col) { if(!col) return moduleBaseThrow("color must be a Color object");
return moduleBaseThrow("color must be a Color object");
}
moduleBaseRequireNumber(5); moduleBaseRequireNumber(5);
moduleBaseRequireNumber(6); moduleBaseRequireNumber(6);
moduleBaseRequireNumber(7); moduleBaseRequireNumber(7);
moduleBaseRequireNumber(8); moduleBaseRequireNumber(8);
spriteBatchPush( spriteBatchPush(
(float_t)jerry_value_as_number(args[0]), moduleBaseArgFloat(0), moduleBaseArgFloat(1),
(float_t)jerry_value_as_number(args[1]), moduleBaseArgFloat(2), moduleBaseArgFloat(3),
(float_t)jerry_value_as_number(args[2]),
(float_t)jerry_value_as_number(args[3]),
*col, *col,
(float_t)jerry_value_as_number(args[5]), moduleBaseArgFloat(5), moduleBaseArgFloat(6),
(float_t)jerry_value_as_number(args[6]), moduleBaseArgFloat(7), moduleBaseArgFloat(8)
(float_t)jerry_value_as_number(args[7]),
(float_t)jerry_value_as_number(args[8])
); );
#else #else
moduleBaseRequireNumber(4); moduleBaseRequireNumber(4);
@@ -60,14 +51,10 @@ moduleBaseFunction(moduleSpriteBatchPush) {
moduleBaseRequireNumber(6); moduleBaseRequireNumber(6);
moduleBaseRequireNumber(7); moduleBaseRequireNumber(7);
spriteBatchPush( spriteBatchPush(
(float_t)jerry_value_as_number(args[0]), moduleBaseArgFloat(0), moduleBaseArgFloat(1),
(float_t)jerry_value_as_number(args[1]), moduleBaseArgFloat(2), moduleBaseArgFloat(3),
(float_t)jerry_value_as_number(args[2]), moduleBaseArgFloat(4), moduleBaseArgFloat(5),
(float_t)jerry_value_as_number(args[3]), moduleBaseArgFloat(6), moduleBaseArgFloat(7)
(float_t)jerry_value_as_number(args[4]),
(float_t)jerry_value_as_number(args[5]),
(float_t)jerry_value_as_number(args[6]),
(float_t)jerry_value_as_number(args[7])
); );
#endif #endif
@@ -76,58 +63,29 @@ moduleBaseFunction(moduleSpriteBatchPush) {
moduleBaseFunction(moduleSpriteBatchPush3D) { moduleBaseFunction(moduleSpriteBatchPush3D) {
#if MESH_ENABLE_COLOR #if MESH_ENABLE_COLOR
if(argc < 5) return moduleBaseThrow("expected 5 arguments"); moduleBaseRequireArgs(5);
#else #else
if(argc < 4) return moduleBaseThrow("expected 4 arguments"); moduleBaseRequireArgs(4);
#endif #endif
if(!jerry_value_is_object(args[0])) {
return moduleBaseThrow("min must be a Vec3");
}
float_t *min = moduleVec3From(args[0]); float_t *min = moduleVec3From(args[0]);
if(!min) return moduleBaseThrow("min must be a Vec3"); if(!min) return moduleBaseThrow("min must be a Vec3");
if(!jerry_value_is_object(args[1])) {
return moduleBaseThrow("max must be a Vec3");
}
float_t *max = moduleVec3From(args[1]); float_t *max = moduleVec3From(args[1]);
if(!max) return moduleBaseThrow("max must be a Vec3"); if(!max) return moduleBaseThrow("max must be a Vec3");
#if MESH_ENABLE_COLOR #if MESH_ENABLE_COLOR
if(!jerry_value_is_object(args[2])) {
return moduleBaseThrow("color must be a Color object");
}
color_t *col = (color_t *)scriptProtoGetValue(&MODULE_COLOR_PROTO, args[2]); color_t *col = (color_t *)scriptProtoGetValue(&MODULE_COLOR_PROTO, args[2]);
if(!col) { if(!col) return moduleBaseThrow("color must be a Color object");
return moduleBaseThrow("color must be a Color object");
}
if(!jerry_value_is_object(args[3])) {
return moduleBaseThrow("uvMin must be a Vec2");
}
float_t *uvMin = moduleVec2From(args[3]); float_t *uvMin = moduleVec2From(args[3]);
if(!uvMin) return moduleBaseThrow("uvMin must be a Vec2"); if(!uvMin) return moduleBaseThrow("uvMin must be a Vec2");
if(!jerry_value_is_object(args[4])) {
return moduleBaseThrow("uvMax must be a Vec2");
}
float_t *uvMax = moduleVec2From(args[4]); float_t *uvMax = moduleVec2From(args[4]);
if(!uvMax) return moduleBaseThrow("uvMax must be a Vec2"); if(!uvMax) return moduleBaseThrow("uvMax must be a Vec2");
spriteBatchPush3D(min, max, *col, uvMin, uvMax); spriteBatchPush3D(min, max, *col, uvMin, uvMax);
#else #else
if(!jerry_value_is_object(args[2])) {
return moduleBaseThrow("uvMin must be a Vec2");
}
float_t *uvMin = moduleVec2From(args[2]); float_t *uvMin = moduleVec2From(args[2]);
if(!uvMin) return moduleBaseThrow("uvMin must be a Vec2"); if(!uvMin) return moduleBaseThrow("uvMin must be a Vec2");
if(!jerry_value_is_object(args[3])) {
return moduleBaseThrow("uvMax must be a Vec2");
}
float_t *uvMax = moduleVec2From(args[3]); float_t *uvMax = moduleVec2From(args[3]);
if(!uvMax) return moduleBaseThrow("uvMax must be a Vec2"); if(!uvMax) return moduleBaseThrow("uvMax must be a Vec2");
spriteBatchPush3D(min, max, uvMin, uvMax); spriteBatchPush3D(min, max, uvMin, uvMax);
#endif #endif
+6 -13
View File
@@ -14,21 +14,17 @@
static scriptproto_t MODULE_TEXT_PROTO; static scriptproto_t MODULE_TEXT_PROTO;
moduleBaseFunction(moduleTextDraw) { moduleBaseFunction(moduleTextDraw) {
if(argc < 3) return moduleBaseThrow("expected at least 3 arguments"); moduleBaseRequireArgs(3); moduleBaseRequireNumber(0); moduleBaseRequireNumber(1);
moduleBaseRequireNumber(0); moduleBaseRequireString(2);
moduleBaseRequireNumber(1);
if(!jerry_value_is_string(args[2])) {
return moduleBaseThrow("text must be a string");
}
float_t x = (float_t)jerry_value_as_number(args[0]); float_t x = moduleBaseArgFloat(0);
float_t y = (float_t)jerry_value_as_number(args[1]); float_t y = moduleBaseArgFloat(1);
char_t text[1024]; char_t text[1024];
moduleBaseToString(args[2], text, sizeof(text)); moduleBaseToString(args[2], text, sizeof(text));
color_t col = COLOR_WHITE; color_t col = COLOR_WHITE;
if(argc >= 4 && jerry_value_is_object(args[3])) { if(argc >= 4) {
color_t *c = (color_t *)scriptProtoGetValue(&MODULE_COLOR_PROTO, args[3]); color_t *c = (color_t *)scriptProtoGetValue(&MODULE_COLOR_PROTO, args[3]);
if(c) col = *c; if(c) col = *c;
} }
@@ -45,10 +41,7 @@ moduleBaseFunction(moduleTextDraw) {
} }
moduleBaseFunction(moduleTextMeasure) { moduleBaseFunction(moduleTextMeasure) {
if(argc < 1) return moduleBaseThrow("expected at least 1 argument"); moduleBaseRequireArgs(1); moduleBaseRequireString(0);
if(!jerry_value_is_string(args[0])) {
return moduleBaseThrow("text must be a string");
}
char_t text[1024]; char_t text[1024];
moduleBaseToString(args[0], text, sizeof(text)); moduleBaseToString(args[0], text, sizeof(text));
@@ -21,177 +21,133 @@ static entitycamera_t * moduleEntityCameraGet(
&MODULE_ENTITY_CAMERA_PROTO, callInfo->this_value &MODULE_ENTITY_CAMERA_PROTO, callInfo->this_value
); );
if(!h) return NULL; if(!h) return NULL;
return (entitycamera_t*)componentGetData( return (entitycamera_t*)componentGetData(h->eid, h->cid, COMPONENT_TYPE_CAMERA);
h->eid, h->cid, COMPONENT_TYPE_CAMERA
);
} }
// ---- Getters ----
moduleBaseFunction(moduleEntityCameraGetZNear) { moduleBaseFunction(moduleEntityCameraGetZNear) {
entitycamera_t *cam = moduleEntityCameraGet(callInfo); moduleBaseGetOrReturn(entitycamera_t, cam, moduleEntityCameraGet);
if(!cam) return jerry_undefined();
return jerry_number(cam->nearClip); return jerry_number(cam->nearClip);
} }
moduleBaseFunction(moduleEntityCameraGetZFar) { moduleBaseFunction(moduleEntityCameraGetZFar) {
entitycamera_t *cam = moduleEntityCameraGet(callInfo); moduleBaseGetOrReturn(entitycamera_t, cam, moduleEntityCameraGet);
if(!cam) return jerry_undefined();
return jerry_number(cam->farClip); return jerry_number(cam->farClip);
} }
moduleBaseFunction(moduleEntityCameraGetOrthoTop) {
entitycamera_t *cam = moduleEntityCameraGet(callInfo);
if(!cam || cam->projType != ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) {
return jerry_undefined();
}
return jerry_number(cam->orthographic.top);
}
moduleBaseFunction(moduleEntityCameraGetOrthoBottom) {
entitycamera_t *cam = moduleEntityCameraGet(callInfo);
if(!cam || cam->projType != ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) {
return jerry_undefined();
}
return jerry_number(cam->orthographic.bottom);
}
moduleBaseFunction(moduleEntityCameraGetOrthoLeft) {
entitycamera_t *cam = moduleEntityCameraGet(callInfo);
if(!cam || cam->projType != ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) {
return jerry_undefined();
}
return jerry_number(cam->orthographic.left);
}
moduleBaseFunction(moduleEntityCameraGetOrthoRight) {
entitycamera_t *cam = moduleEntityCameraGet(callInfo);
if(!cam || cam->projType != ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) {
return jerry_undefined();
}
return jerry_number(cam->orthographic.right);
}
moduleBaseFunction(moduleEntityCameraGetFov) { moduleBaseFunction(moduleEntityCameraGetFov) {
entitycamera_t *cam = moduleEntityCameraGet(callInfo); moduleBaseGetOrReturn(entitycamera_t, cam, moduleEntityCameraGet);
if(!cam || ( if(
cam->projType != ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE && cam->projType != ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE &&
cam->projType != ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED cam->projType != ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED
)) { ) return jerry_undefined();
return jerry_undefined();
}
return jerry_number(cam->perspective.fov); return jerry_number(cam->perspective.fov);
} }
moduleBaseFunction(moduleEntityCameraGetProjectionType) { moduleBaseFunction(moduleEntityCameraGetProjectionType) {
entitycamera_t *cam = moduleEntityCameraGet(callInfo); moduleBaseGetOrReturn(entitycamera_t, cam, moduleEntityCameraGet);
if(!cam) return jerry_undefined();
return jerry_number(cam->projType); return jerry_number(cam->projType);
} }
moduleBaseFunction(moduleEntityCameraGetOrthoTop) {
moduleBaseGetOrReturn(entitycamera_t, cam, moduleEntityCameraGet);
if(cam->projType != ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) return jerry_undefined();
return jerry_number(cam->orthographic.top);
}
moduleBaseFunction(moduleEntityCameraGetOrthoBottom) {
moduleBaseGetOrReturn(entitycamera_t, cam, moduleEntityCameraGet);
if(cam->projType != ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) return jerry_undefined();
return jerry_number(cam->orthographic.bottom);
}
moduleBaseFunction(moduleEntityCameraGetOrthoLeft) {
moduleBaseGetOrReturn(entitycamera_t, cam, moduleEntityCameraGet);
if(cam->projType != ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) return jerry_undefined();
return jerry_number(cam->orthographic.left);
}
moduleBaseFunction(moduleEntityCameraGetOrthoRight) {
moduleBaseGetOrReturn(entitycamera_t, cam, moduleEntityCameraGet);
if(cam->projType != ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) return jerry_undefined();
return jerry_number(cam->orthographic.right);
}
// ---- Setters ----
moduleBaseFunction(moduleEntityCameraSetZNear) { moduleBaseFunction(moduleEntityCameraSetZNear) {
if(argc < 1 || !jerry_value_is_number(args[0])) { moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
return moduleBaseThrow("Expected a number"); moduleBaseGetOrReturn(entitycamera_t, cam, moduleEntityCameraGet);
} cam->nearClip = moduleBaseArgFloat(0);
entitycamera_t *cam = moduleEntityCameraGet(callInfo);
if(!cam) return jerry_undefined();
cam->nearClip = (float_t)jerry_value_as_number(args[0]);
return args[0]; return args[0];
} }
moduleBaseFunction(moduleEntityCameraSetZFar) { moduleBaseFunction(moduleEntityCameraSetZFar) {
if(argc < 1 || !jerry_value_is_number(args[0])) { moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
return moduleBaseThrow("Expected a number"); moduleBaseGetOrReturn(entitycamera_t, cam, moduleEntityCameraGet);
} cam->farClip = moduleBaseArgFloat(0);
entitycamera_t *cam = moduleEntityCameraGet(callInfo);
if(!cam) return jerry_undefined();
cam->farClip = (float_t)jerry_value_as_number(args[0]);
return args[0];
}
moduleBaseFunction(moduleEntityCameraSetOrthoTop) {
if(argc < 1 || !jerry_value_is_number(args[0])) {
return moduleBaseThrow("Expected a number");
}
entitycamera_t *cam = moduleEntityCameraGet(callInfo);
if(!cam || cam->projType != ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) {
return jerry_undefined();
}
cam->orthographic.top = (float_t)jerry_value_as_number(args[0]);
return args[0];
}
moduleBaseFunction(moduleEntityCameraSetOrthoBottom) {
if(argc < 1 || !jerry_value_is_number(args[0])) {
return moduleBaseThrow("Expected a number");
}
entitycamera_t *cam = moduleEntityCameraGet(callInfo);
if(!cam || cam->projType != ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) {
return jerry_undefined();
}
cam->orthographic.bottom = (float_t)jerry_value_as_number(args[0]);
return args[0];
}
moduleBaseFunction(moduleEntityCameraSetOrthoLeft) {
if(argc < 1 || !jerry_value_is_number(args[0])) {
return moduleBaseThrow("Expected a number");
}
entitycamera_t *cam = moduleEntityCameraGet(callInfo);
if(!cam || cam->projType != ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) {
return jerry_undefined();
}
cam->orthographic.left = (float_t)jerry_value_as_number(args[0]);
return args[0];
}
moduleBaseFunction(moduleEntityCameraSetOrthoRight) {
if(argc < 1 || !jerry_value_is_number(args[0])) {
return moduleBaseThrow("Expected a number");
}
entitycamera_t *cam = moduleEntityCameraGet(callInfo);
if(!cam || cam->projType != ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) {
return jerry_undefined();
}
cam->orthographic.right = (float_t)jerry_value_as_number(args[0]);
return args[0]; return args[0];
} }
moduleBaseFunction(moduleEntityCameraSetFov) { moduleBaseFunction(moduleEntityCameraSetFov) {
if(argc < 1 || !jerry_value_is_number(args[0])) { moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
return moduleBaseThrow("Expected a number"); moduleBaseGetOrReturn(entitycamera_t, cam, moduleEntityCameraGet);
} if(
entitycamera_t *cam = moduleEntityCameraGet(callInfo);
if(!cam || (
cam->projType != ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE && cam->projType != ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE &&
cam->projType != ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED cam->projType != ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED
)) { ) return jerry_undefined();
return jerry_undefined(); cam->perspective.fov = moduleBaseArgFloat(0);
}
cam->perspective.fov = (float_t)jerry_value_as_number(args[0]);
return args[0]; return args[0];
} }
moduleBaseFunction(moduleEntityCameraSetProjectionType) { moduleBaseFunction(moduleEntityCameraSetProjectionType) {
if(argc < 1 || !jerry_value_is_number(args[0])) { moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
return moduleBaseThrow("Expected a number"); moduleBaseGetOrReturn(entitycamera_t, cam, moduleEntityCameraGet);
} int32_t t = moduleBaseArgInt(0);
entitycamera_t *cam = moduleEntityCameraGet(callInfo);
if(!cam) return jerry_undefined();
int32_t projType = (int32_t)jerry_value_as_number(args[0]);
if( if(
projType < ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE || t < ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE ||
projType > ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC t > ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC
) { ) return moduleBaseThrow("Invalid projection type");
return moduleBaseThrow("Invalid projection type"); cam->projType = (entitycameraprojectiontype_t)t;
} return args[0];
cam->projType = (entitycameraprojectiontype_t)projType; }
moduleBaseFunction(moduleEntityCameraSetOrthoTop) {
moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
moduleBaseGetOrReturn(entitycamera_t, cam, moduleEntityCameraGet);
if(cam->projType != ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) return jerry_undefined();
cam->orthographic.top = moduleBaseArgFloat(0);
return args[0];
}
moduleBaseFunction(moduleEntityCameraSetOrthoBottom) {
moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
moduleBaseGetOrReturn(entitycamera_t, cam, moduleEntityCameraGet);
if(cam->projType != ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) return jerry_undefined();
cam->orthographic.bottom = moduleBaseArgFloat(0);
return args[0];
}
moduleBaseFunction(moduleEntityCameraSetOrthoLeft) {
moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
moduleBaseGetOrReturn(entitycamera_t, cam, moduleEntityCameraGet);
if(cam->projType != ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) return jerry_undefined();
cam->orthographic.left = moduleBaseArgFloat(0);
return args[0];
}
moduleBaseFunction(moduleEntityCameraSetOrthoRight) {
moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
moduleBaseGetOrReturn(entitycamera_t, cam, moduleEntityCameraGet);
if(cam->projType != ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) return jerry_undefined();
cam->orthographic.right = moduleBaseArgFloat(0);
return args[0]; return args[0];
} }
moduleBaseFunction(moduleEntityCameraAdd) { moduleBaseFunction(moduleEntityCameraAdd) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
moduleBaseRequireNumber(0); entityid_t id = (entityid_t)moduleBaseArgInt(0);
entityid_t id = (entityid_t)jerry_value_as_number(args[0]);
componentid_t comp = entityAddComponent(id, COMPONENT_TYPE_CAMERA); componentid_t comp = entityAddComponent(id, COMPONENT_TYPE_CAMERA);
componenthandle_t h = { .eid = id, .cid = comp }; componenthandle_t h = { .eid = id, .cid = comp };
return scriptProtoCreateValue(&MODULE_ENTITY_CAMERA_PROTO, &h); return scriptProtoCreateValue(&MODULE_ENTITY_CAMERA_PROTO, &h);
@@ -202,45 +158,25 @@ static void moduleEntityCAMERA(void) {
&MODULE_ENTITY_CAMERA_PROTO, NULL, sizeof(componenthandle_t), NULL &MODULE_ENTITY_CAMERA_PROTO, NULL, sizeof(componenthandle_t), NULL
); );
scriptProtoDefineProp( scriptProtoDefineProp(&MODULE_ENTITY_CAMERA_PROTO, "zNear",
&MODULE_ENTITY_CAMERA_PROTO, "zNear", moduleEntityCameraGetZNear, moduleEntityCameraSetZNear);
moduleEntityCameraGetZNear, moduleEntityCameraSetZNear scriptProtoDefineProp(&MODULE_ENTITY_CAMERA_PROTO, "zFar",
); moduleEntityCameraGetZFar, moduleEntityCameraSetZFar);
scriptProtoDefineProp( scriptProtoDefineProp(&MODULE_ENTITY_CAMERA_PROTO, "fov",
&MODULE_ENTITY_CAMERA_PROTO, "zFar", moduleEntityCameraGetFov, moduleEntityCameraSetFov);
moduleEntityCameraGetZFar, moduleEntityCameraSetZFar scriptProtoDefineProp(&MODULE_ENTITY_CAMERA_PROTO, "projectionType",
); moduleEntityCameraGetProjectionType, moduleEntityCameraSetProjectionType);
scriptProtoDefineProp( scriptProtoDefineProp(&MODULE_ENTITY_CAMERA_PROTO, "orthoTop",
&MODULE_ENTITY_CAMERA_PROTO, "orthoTop", moduleEntityCameraGetOrthoTop, moduleEntityCameraSetOrthoTop);
moduleEntityCameraGetOrthoTop, moduleEntityCameraSetOrthoTop scriptProtoDefineProp(&MODULE_ENTITY_CAMERA_PROTO, "orthoBottom",
); moduleEntityCameraGetOrthoBottom, moduleEntityCameraSetOrthoBottom);
scriptProtoDefineProp( scriptProtoDefineProp(&MODULE_ENTITY_CAMERA_PROTO, "orthoLeft",
&MODULE_ENTITY_CAMERA_PROTO, "orthoBottom", moduleEntityCameraGetOrthoLeft, moduleEntityCameraSetOrthoLeft);
moduleEntityCameraGetOrthoBottom, moduleEntityCameraSetOrthoBottom scriptProtoDefineProp(&MODULE_ENTITY_CAMERA_PROTO, "orthoRight",
); moduleEntityCameraGetOrthoRight, moduleEntityCameraSetOrthoRight);
scriptProtoDefineProp(
&MODULE_ENTITY_CAMERA_PROTO, "orthoLeft",
moduleEntityCameraGetOrthoLeft, moduleEntityCameraSetOrthoLeft
);
scriptProtoDefineProp(
&MODULE_ENTITY_CAMERA_PROTO, "orthoRight",
moduleEntityCameraGetOrthoRight, moduleEntityCameraSetOrthoRight
);
scriptProtoDefineProp(
&MODULE_ENTITY_CAMERA_PROTO, "fov",
moduleEntityCameraGetFov, moduleEntityCameraSetFov
);
scriptProtoDefineProp(
&MODULE_ENTITY_CAMERA_PROTO, "projectionType",
moduleEntityCameraGetProjectionType, moduleEntityCameraSetProjectionType
);
moduleBaseSetInt( moduleBaseSetInt("CAMERA_TYPE_ORTHOGRAPHIC",
"CAMERA_TYPE_ORTHOGRAPHIC", ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC);
ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC moduleBaseSetInt("CAMERA_TYPE_PERSPECTIVE",
); ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE);
moduleBaseSetInt(
"CAMERA_TYPE_PERSPECTIVE",
ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE
);
} }
@@ -1,72 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "script/module/modulebase.h"
#include "script/module/display/modulecolor.h"
#include "script/scriptproto.h"
#include "entity/entity.h"
#include "entity/component/display/entitymaterial.h"
#include "moduleentityposition.h"
static scriptproto_t MODULE_ENTITY_MATERIAL_PROTO;
static entitymaterial_t * moduleEntityMaterialGet(
const jerry_call_info_t *callInfo
) {
componenthandle_t *h = scriptProtoGetValue(
&MODULE_ENTITY_MATERIAL_PROTO, callInfo->this_value
);
if(!h) return NULL;
return (entitymaterial_t*)componentGetData(
h->eid, h->cid, COMPONENT_TYPE_MATERIAL
);
}
moduleBaseFunction(moduleEntityMaterialGetColor) {
entitymaterial_t *mat = moduleEntityMaterialGet(callInfo);
if(!mat) return jerry_undefined();
return moduleColorMakeObject(mat->material.unlit.color);
}
moduleBaseFunction(moduleEntityMaterialSetColor) {
if(argc < 1 || !jerry_value_is_object(args[0])) {
return moduleBaseThrow("Material.color: expected color object");
}
color_t *color = (color_t*)scriptProtoGetValue(&MODULE_COLOR_PROTO, args[0]);
if(!color) {
return moduleBaseThrow("Material.color: expected valid color object");
}
entitymaterial_t *mat = moduleEntityMaterialGet(callInfo);
if(!mat) return jerry_undefined();
memoryCopy(&mat->material.unlit.color, color, sizeof(color_t));
return jerry_undefined();
}
moduleBaseFunction(moduleEntityMaterialAdd) {
if(argc < 1 || !jerry_value_is_number(args[0])) {
return moduleBaseThrow("Expected at least 1 argument");
}
entityid_t id = (entityid_t)jerry_value_as_number(args[0]);
componentid_t comp = entityAddComponent(id, COMPONENT_TYPE_MATERIAL);
componenthandle_t h = { .eid = id, .cid = comp };
return scriptProtoCreateValue(&MODULE_ENTITY_MATERIAL_PROTO, &h);
}
static void moduleEntityMATERIAL(void) {
scriptProtoInit(
&MODULE_ENTITY_MATERIAL_PROTO,
NULL,
sizeof(componenthandle_t),
NULL
);
scriptProtoDefineProp(
&MODULE_ENTITY_MATERIAL_PROTO, "color",
moduleEntityMaterialGetColor, moduleEntityMaterialSetColor
);
}
@@ -1,63 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "script/module/modulebase.h"
#include "script/scriptproto.h"
#include "script/module/display/modulemesh.h"
#include "entity/entity.h"
#include "entity/component/display/entitymesh.h"
#include "moduleentityposition.h"
static scriptproto_t MODULE_ENTITY_MESH_PROTO;
static entitymesh_t * moduleEntityMeshGet(
const jerry_call_info_t *callInfo
) {
componenthandle_t *h = scriptProtoGetValue(
&MODULE_ENTITY_MESH_PROTO, callInfo->this_value
);
if(!h) return NULL;
return (entitymesh_t*)componentGetData(h->eid, h->cid, COMPONENT_TYPE_MESH);
}
moduleBaseFunction(moduleEntityMeshGetMesh) {
entitymesh_t *comp = moduleEntityMeshGet(callInfo);
if(!comp || !comp->mesh) return jerry_undefined();
return moduleBaseWrapPointer(comp->mesh);
}
moduleBaseFunction(moduleEntityMeshSetMesh) {
if(argc < 1) return moduleBaseThrow("Expected a Mesh argument");
entitymesh_t *comp = moduleEntityMeshGet(callInfo);
if(!comp) return jerry_undefined();
meshscript_t *ms = moduleMeshFrom(args[0]);
if(ms) {
comp->mesh = &ms->mesh;
return jerry_undefined();
}
mesh_t *raw = (mesh_t*)moduleBaseUnwrapPointer(args[0]);
if(raw) {
comp->mesh = raw;
return jerry_undefined();
}
return moduleBaseThrow("Expected a Mesh object or mesh constant");
}
static void moduleEntityMESH(void) {
scriptProtoInit(
&MODULE_ENTITY_MESH_PROTO, NULL,
sizeof(componenthandle_t), NULL
);
scriptProtoDefineProp(
&MODULE_ENTITY_MESH_PROTO, "mesh",
moduleEntityMeshGetMesh, moduleEntityMeshSetMesh
);
}
@@ -26,123 +26,87 @@ static entityphysics_t * moduleEntityPhysicsGet(
} }
moduleBaseFunction(moduleEntityPhysicsGetVelocity) { moduleBaseFunction(moduleEntityPhysicsGetVelocity) {
entityphysics_t *phys = moduleEntityPhysicsGet(callInfo); moduleBaseGetOrReturn(entityphysics_t, phys, moduleEntityPhysicsGet);
if(!phys) return jerry_undefined();
return moduleVec3RefPush(phys->velocity, NULL, NULL); return moduleVec3RefPush(phys->velocity, NULL, NULL);
} }
moduleBaseFunction(moduleEntityPhysicsSetVelocity) { moduleBaseFunction(moduleEntityPhysicsSetVelocity) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); moduleBaseRequireArgs(1);
entityphysics_t *phys = moduleEntityPhysicsGet(callInfo); moduleBaseGetOrReturn(entityphysics_t, phys, moduleEntityPhysicsGet);
if(!phys) return jerry_undefined();
vec3 v; vec3 v;
if(!moduleVec3AnyCheck(args[0], v)) { if(!moduleVec3AnyCheck(args[0], v)) return moduleBaseThrow("Expected Vec3");
return moduleBaseThrow("expected Vec3");
}
glm_vec3_copy(v, phys->velocity); glm_vec3_copy(v, phys->velocity);
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleEntityPhysicsGetOnGround) { moduleBaseFunction(moduleEntityPhysicsGetOnGround) {
entityphysics_t *phys = moduleEntityPhysicsGet(callInfo); moduleBaseGetOrReturn(entityphysics_t, phys, moduleEntityPhysicsGet);
if(!phys) return jerry_undefined();
return jerry_boolean(phys->onGround); return jerry_boolean(phys->onGround);
} }
moduleBaseFunction(moduleEntityPhysicsGetBodyType) { moduleBaseFunction(moduleEntityPhysicsGetBodyType) {
entityphysics_t *phys = moduleEntityPhysicsGet(callInfo); moduleBaseGetOrReturn(entityphysics_t, phys, moduleEntityPhysicsGet);
if(!phys) return jerry_undefined();
return jerry_number(phys->type); return jerry_number(phys->type);
} }
moduleBaseFunction(moduleEntityPhysicsSetBodyType) { moduleBaseFunction(moduleEntityPhysicsSetBodyType) {
if(argc < 1) { moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
return moduleBaseThrow("Expected at least 1 argument"); moduleBaseGetOrReturn(entityphysics_t, phys, moduleEntityPhysicsGet);
} phys->type = (physicsbodytype_t)moduleBaseArgInt(0);
moduleBaseRequireNumber(0);
entityphysics_t *phys = moduleEntityPhysicsGet(callInfo);
if(!phys) return jerry_undefined();
phys->type = (physicsbodytype_t)(int32_t)jerry_value_as_number(args[0]);
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleEntityPhysicsApplyImpulse) { moduleBaseFunction(moduleEntityPhysicsApplyImpulse) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); moduleBaseRequireArgs(1);
entityphysics_t *phys = moduleEntityPhysicsGet(callInfo); moduleBaseGetOrReturn(entityphysics_t, phys, moduleEntityPhysicsGet);
if(!phys) return jerry_undefined();
if(phys->type == PHYSICS_BODY_STATIC) return jerry_undefined(); if(phys->type == PHYSICS_BODY_STATIC) return jerry_undefined();
vec3 impulse; vec3 impulse;
if(!moduleVec3Check(args[0], impulse)) { if(!moduleVec3Check(args[0], impulse)) return moduleBaseThrow("Expected Vec3 impulse");
return moduleBaseThrow("expected Vec3 impulse");
}
glm_vec3_add(phys->velocity, impulse, phys->velocity); glm_vec3_add(phys->velocity, impulse, phys->velocity);
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleEntityPhysicsSetShapeCube) { moduleBaseFunction(moduleEntityPhysicsSetShapeCube) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); moduleBaseRequireArgs(1);
entityphysics_t *phys = moduleEntityPhysicsGet(callInfo); moduleBaseGetOrReturn(entityphysics_t, phys, moduleEntityPhysicsGet);
if(!phys) return jerry_undefined();
vec3 half; vec3 half;
if(!moduleVec3Check(args[0], half)) { if(!moduleVec3Check(args[0], half)) return moduleBaseThrow("Expected Vec3 halfExtents");
return moduleBaseThrow("expected Vec3 halfExtents");
}
phys->shape.type = PHYSICS_SHAPE_CUBE; phys->shape.type = PHYSICS_SHAPE_CUBE;
glm_vec3_copy(half, phys->shape.data.cube.halfExtents); glm_vec3_copy(half, phys->shape.data.cube.halfExtents);
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleEntityPhysicsSetShapeSphere) { moduleBaseFunction(moduleEntityPhysicsSetShapeSphere) {
if(argc < 1) { moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
return moduleBaseThrow("Expected at least 1 argument"); moduleBaseGetOrReturn(entityphysics_t, phys, moduleEntityPhysicsGet);
}
moduleBaseRequireNumber(0);
entityphysics_t *phys = moduleEntityPhysicsGet(callInfo);
if(!phys) return jerry_undefined();
phys->shape.type = PHYSICS_SHAPE_SPHERE; phys->shape.type = PHYSICS_SHAPE_SPHERE;
phys->shape.data.sphere.radius = (float_t)jerry_value_as_number(args[0]); phys->shape.data.sphere.radius = moduleBaseArgFloat(0);
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleEntityPhysicsSetShapeCapsule) { moduleBaseFunction(moduleEntityPhysicsSetShapeCapsule) {
if(argc < 2) return moduleBaseThrow("Expected at least 2 arguments"); moduleBaseRequireArgs(2); moduleBaseRequireNumber(0); moduleBaseRequireNumber(1);
moduleBaseRequireNumber(0); moduleBaseRequireNumber(1); moduleBaseGetOrReturn(entityphysics_t, phys, moduleEntityPhysicsGet);
entityphysics_t *phys = moduleEntityPhysicsGet(callInfo);
if(!phys) return jerry_undefined();
phys->shape.type = PHYSICS_SHAPE_CAPSULE; phys->shape.type = PHYSICS_SHAPE_CAPSULE;
phys->shape.data.capsule.radius = (float_t)jerry_value_as_number(args[0]); phys->shape.data.capsule.radius = moduleBaseArgFloat(0);
phys->shape.data.capsule.halfHeight = phys->shape.data.capsule.halfHeight = moduleBaseArgFloat(1);
(float_t)jerry_value_as_number(args[1]);
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleEntityPhysicsSetShapePlane) { moduleBaseFunction(moduleEntityPhysicsSetShapePlane) {
if(argc < 2) { moduleBaseRequireArgs(2); moduleBaseRequireNumber(1);
return moduleBaseThrow("Expected at least 2 arguments"); moduleBaseGetOrReturn(entityphysics_t, phys, moduleEntityPhysicsGet);
}
moduleBaseRequireNumber(1);
entityphysics_t *phys = moduleEntityPhysicsGet(callInfo);
if(!phys) return jerry_undefined();
vec3 normal; vec3 normal;
if(!moduleVec3Check(args[0], normal)) { if(!moduleVec3Check(args[0], normal)) return moduleBaseThrow("Expected Vec3 normal");
return moduleBaseThrow("expected Vec3 normal");
}
phys->shape.type = PHYSICS_SHAPE_PLANE; phys->shape.type = PHYSICS_SHAPE_PLANE;
glm_vec3_copy(normal, phys->shape.data.plane.normal); glm_vec3_copy(normal, phys->shape.data.plane.normal);
phys->shape.data.plane.distance = (float_t)jerry_value_as_number(args[1]); phys->shape.data.plane.distance = moduleBaseArgFloat(1);
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleEntityPhysicsAdd) { moduleBaseFunction(moduleEntityPhysicsAdd) {
if(argc < 1) { moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
return moduleBaseThrow("Expected at least 1 argument"); entityid_t id = (entityid_t)moduleBaseArgInt(0);
}
moduleBaseRequireNumber(0);
entityid_t id = (entityid_t)jerry_value_as_number(args[0]);
componentid_t comp = entityAddComponent(id, COMPONENT_TYPE_PHYSICS); componentid_t comp = entityAddComponent(id, COMPONENT_TYPE_PHYSICS);
componenthandle_t h = { .eid = id, .cid = comp }; componenthandle_t h = { .eid = id, .cid = comp };
return scriptProtoCreateValue(&MODULE_ENTITY_PHYSICS_PROTO, &h); return scriptProtoCreateValue(&MODULE_ENTITY_PHYSICS_PROTO, &h);
@@ -150,43 +114,26 @@ moduleBaseFunction(moduleEntityPhysicsAdd) {
static void moduleEntityPHYSICS(void) { static void moduleEntityPHYSICS(void) {
scriptProtoInit( scriptProtoInit(
&MODULE_ENTITY_PHYSICS_PROTO, NULL, &MODULE_ENTITY_PHYSICS_PROTO, NULL, sizeof(componenthandle_t), NULL
sizeof(componenthandle_t), NULL
); );
scriptProtoDefineProp( scriptProtoDefineProp(&MODULE_ENTITY_PHYSICS_PROTO, "velocity",
&MODULE_ENTITY_PHYSICS_PROTO, "velocity", moduleEntityPhysicsGetVelocity, moduleEntityPhysicsSetVelocity);
moduleEntityPhysicsGetVelocity, moduleEntityPhysicsSetVelocity scriptProtoDefineProp(&MODULE_ENTITY_PHYSICS_PROTO, "onGround",
); moduleEntityPhysicsGetOnGround, NULL);
scriptProtoDefineProp( scriptProtoDefineProp(&MODULE_ENTITY_PHYSICS_PROTO, "bodyType",
&MODULE_ENTITY_PHYSICS_PROTO, "onGround", moduleEntityPhysicsGetBodyType, moduleEntityPhysicsSetBodyType);
moduleEntityPhysicsGetOnGround, NULL
);
scriptProtoDefineProp(
&MODULE_ENTITY_PHYSICS_PROTO, "bodyType",
moduleEntityPhysicsGetBodyType, moduleEntityPhysicsSetBodyType
);
scriptProtoDefineFunc( scriptProtoDefineFunc(&MODULE_ENTITY_PHYSICS_PROTO, "applyImpulse",
&MODULE_ENTITY_PHYSICS_PROTO, "applyImpulse", moduleEntityPhysicsApplyImpulse);
moduleEntityPhysicsApplyImpulse scriptProtoDefineFunc(&MODULE_ENTITY_PHYSICS_PROTO, "setShapeCube",
); moduleEntityPhysicsSetShapeCube);
scriptProtoDefineFunc( scriptProtoDefineFunc(&MODULE_ENTITY_PHYSICS_PROTO, "setShapeSphere",
&MODULE_ENTITY_PHYSICS_PROTO, "setShapeCube", moduleEntityPhysicsSetShapeSphere);
moduleEntityPhysicsSetShapeCube scriptProtoDefineFunc(&MODULE_ENTITY_PHYSICS_PROTO, "setShapeCapsule",
); moduleEntityPhysicsSetShapeCapsule);
scriptProtoDefineFunc( scriptProtoDefineFunc(&MODULE_ENTITY_PHYSICS_PROTO, "setShapePlane",
&MODULE_ENTITY_PHYSICS_PROTO, "setShapeSphere", moduleEntityPhysicsSetShapePlane);
moduleEntityPhysicsSetShapeSphere
);
scriptProtoDefineFunc(
&MODULE_ENTITY_PHYSICS_PROTO, "setShapeCapsule",
moduleEntityPhysicsSetShapeCapsule
);
scriptProtoDefineFunc(
&MODULE_ENTITY_PHYSICS_PROTO, "setShapePlane",
moduleEntityPhysicsSetShapePlane
);
moduleBaseSetInt("PHYSICS_BODY_STATIC", PHYSICS_BODY_STATIC); moduleBaseSetInt("PHYSICS_BODY_STATIC", PHYSICS_BODY_STATIC);
moduleBaseSetInt("PHYSICS_BODY_DYNAMIC", PHYSICS_BODY_DYNAMIC); moduleBaseSetInt("PHYSICS_BODY_DYNAMIC", PHYSICS_BODY_DYNAMIC);
@@ -33,92 +33,89 @@ static entityposition_t * moduleEntityPositionGet(
} }
moduleBaseFunction(moduleEntityPositionGetPosition) { moduleBaseFunction(moduleEntityPositionGetPosition) {
entityposition_t *pos = moduleEntityPositionGet(callInfo); moduleBaseGetOrReturn(entityposition_t, pos, moduleEntityPositionGet);
if(!pos) return jerry_undefined(); return moduleVec3RefPush(pos->position, (void(*)(void*))entityPositionRebuild, pos);
return moduleVec3RefPush(
pos->position, (void(*)(void*))entityPositionRebuild, pos
);
} }
moduleBaseFunction(moduleEntityPositionSetPosition) { moduleBaseFunction(moduleEntityPositionSetPosition) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); moduleBaseRequireArgs(1);
entityposition_t *pos = moduleEntityPositionGet(callInfo); moduleBaseGetOrReturn(entityposition_t, pos, moduleEntityPositionGet);
if(!pos) return jerry_undefined();
vec3 v; vec3 v;
if(!moduleVec3AnyCheck(args[0], v)) { if(!moduleVec3AnyCheck(args[0], v)) return moduleBaseThrow("Expected Vec3");
return moduleBaseThrow("expected Vec3");
}
glm_vec3_copy(v, pos->position); glm_vec3_copy(v, pos->position);
entityPositionRebuild(pos); entityPositionRebuild(pos);
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleEntityPositionGetRotation) { moduleBaseFunction(moduleEntityPositionGetRotation) {
entityposition_t *pos = moduleEntityPositionGet(callInfo); moduleBaseGetOrReturn(entityposition_t, pos, moduleEntityPositionGet);
if(!pos) return jerry_undefined(); return moduleVec3RefPush(pos->rotation, (void(*)(void*))entityPositionRebuild, pos);
return moduleVec3RefPush(
pos->rotation, (void(*)(void*))entityPositionRebuild, pos
);
} }
moduleBaseFunction(moduleEntityPositionSetRotation) { moduleBaseFunction(moduleEntityPositionSetRotation) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); moduleBaseRequireArgs(1);
entityposition_t *pos = moduleEntityPositionGet(callInfo); moduleBaseGetOrReturn(entityposition_t, pos, moduleEntityPositionGet);
if(!pos) return jerry_undefined();
vec3 v; vec3 v;
if(!moduleVec3AnyCheck(args[0], v)) { if(!moduleVec3AnyCheck(args[0], v)) return moduleBaseThrow("Expected Vec3");
return moduleBaseThrow("expected Vec3");
}
glm_vec3_copy(v, pos->rotation); glm_vec3_copy(v, pos->rotation);
entityPositionRebuild(pos); entityPositionRebuild(pos);
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleEntityPositionGetScale) { moduleBaseFunction(moduleEntityPositionGetScale) {
entityposition_t *pos = moduleEntityPositionGet(callInfo); moduleBaseGetOrReturn(entityposition_t, pos, moduleEntityPositionGet);
if(!pos) return jerry_undefined(); return moduleVec3RefPush(pos->scale, (void(*)(void*))entityPositionRebuild, pos);
return moduleVec3RefPush(
pos->scale, (void(*)(void*))entityPositionRebuild, pos
);
} }
moduleBaseFunction(moduleEntityPositionSetScale) { moduleBaseFunction(moduleEntityPositionSetScale) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); moduleBaseRequireArgs(1);
entityposition_t *pos = moduleEntityPositionGet(callInfo); moduleBaseGetOrReturn(entityposition_t, pos, moduleEntityPositionGet);
if(!pos) return jerry_undefined();
vec3 v; vec3 v;
if(!moduleVec3AnyCheck(args[0], v)) { if(!moduleVec3AnyCheck(args[0], v)) return moduleBaseThrow("Expected Vec3");
return moduleBaseThrow("expected Vec3");
}
glm_vec3_copy(v, pos->scale); glm_vec3_copy(v, pos->scale);
entityPositionRebuild(pos); entityPositionRebuild(pos);
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleEntityPositionLookAt) { moduleBaseFunction(moduleEntityPositionLookAt) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); moduleBaseRequireArgs(1);
entityposition_t *pos = moduleEntityPositionGet(callInfo); moduleBaseGetOrReturn(entityposition_t, pos, moduleEntityPositionGet);
if(!pos) return jerry_undefined();
vec3 target; vec3 target;
if(!moduleVec3AnyCheck(args[0], target)) { if(!moduleVec3AnyCheck(args[0], target)) return moduleBaseThrow("Expected Vec3 target");
return moduleBaseThrow("expected Vec3 target");
}
vec3 up = { 0.0f, 1.0f, 0.0f }; vec3 up = { 0.0f, 1.0f, 0.0f };
if(argc >= 2 && !moduleVec3AnyCheck(args[1], up)) { if(argc >= 2 && !moduleVec3AnyCheck(args[1], up)) return moduleBaseThrow("Expected Vec3 up");
return moduleBaseThrow("expected Vec3 up"); componenthandle_t *h = scriptProtoGetValue(
&MODULE_ENTITY_POSITION_PROTO, callInfo->this_value
);
entityPositionLookAt(h->eid, h->cid, target, up, pos->position);
return jerry_undefined();
}
moduleBaseFunction(moduleEntityPositionGetParent) {
moduleBaseGetOrReturn(entityposition_t, pos, moduleEntityPositionGet);
if(pos->parentEntityId == ENTITY_ID_INVALID) return jerry_null();
componenthandle_t ph = { .eid = pos->parentEntityId, .cid = pos->parentComponentId };
return scriptProtoCreateValue(&MODULE_ENTITY_POSITION_PROTO, &ph);
}
moduleBaseFunction(moduleEntityPositionSetParentProp) {
componenthandle_t *h = scriptProtoGetValue(
&MODULE_ENTITY_POSITION_PROTO, callInfo->this_value
);
if(!h) return jerry_undefined();
if(argc < 1 || jerry_value_is_null(args[0]) || jerry_value_is_undefined(args[0])) {
entityPositionSetParent(h->eid, h->cid, ENTITY_ID_INVALID, COMPONENT_ID_INVALID);
return jerry_undefined();
} }
glm_lookat(pos->position, target, up, pos->transform); componenthandle_t *ph = scriptProtoGetValue(&MODULE_ENTITY_POSITION_PROTO, args[0]);
entityPositionDecompose(pos); if(!ph) return moduleBaseThrow("Expected EntityPosition");
entityPositionSetParent(h->eid, h->cid, ph->eid, ph->cid);
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleEntityPositionAdd) { moduleBaseFunction(moduleEntityPositionAdd) {
if(argc < 1) { moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
return moduleBaseThrow("Expected at least 1 argument"); entityid_t id = (entityid_t)moduleBaseArgInt(0);
}
moduleBaseRequireNumber(0);
entityid_t id = (entityid_t)jerry_value_as_number(args[0]);
componentid_t comp = entityAddComponent(id, COMPONENT_TYPE_POSITION); componentid_t comp = entityAddComponent(id, COMPONENT_TYPE_POSITION);
componenthandle_t h = { .eid = id, .cid = comp }; componenthandle_t h = { .eid = id, .cid = comp };
return scriptProtoCreateValue(&MODULE_ENTITY_POSITION_PROTO, &h); return scriptProtoCreateValue(&MODULE_ENTITY_POSITION_PROTO, &h);
@@ -126,25 +123,16 @@ moduleBaseFunction(moduleEntityPositionAdd) {
static void moduleEntityPOSITION(void) { static void moduleEntityPOSITION(void) {
scriptProtoInit( scriptProtoInit(
&MODULE_ENTITY_POSITION_PROTO, NULL, &MODULE_ENTITY_POSITION_PROTO, NULL, sizeof(componenthandle_t), NULL
sizeof(componenthandle_t), NULL
);
scriptProtoDefineProp(
&MODULE_ENTITY_POSITION_PROTO, "position",
moduleEntityPositionGetPosition, moduleEntityPositionSetPosition
);
scriptProtoDefineProp(
&MODULE_ENTITY_POSITION_PROTO, "rotation",
moduleEntityPositionGetRotation, moduleEntityPositionSetRotation
);
scriptProtoDefineProp(
&MODULE_ENTITY_POSITION_PROTO, "scale",
moduleEntityPositionGetScale, moduleEntityPositionSetScale
);
scriptProtoDefineFunc(
&MODULE_ENTITY_POSITION_PROTO, "lookAt",
moduleEntityPositionLookAt
); );
scriptProtoDefineProp(&MODULE_ENTITY_POSITION_PROTO, "position",
moduleEntityPositionGetPosition, moduleEntityPositionSetPosition);
scriptProtoDefineProp(&MODULE_ENTITY_POSITION_PROTO, "rotation",
moduleEntityPositionGetRotation, moduleEntityPositionSetRotation);
scriptProtoDefineProp(&MODULE_ENTITY_POSITION_PROTO, "scale",
moduleEntityPositionGetScale, moduleEntityPositionSetScale);
scriptProtoDefineProp(&MODULE_ENTITY_POSITION_PROTO, "parent",
moduleEntityPositionGetParent, moduleEntityPositionSetParentProp);
scriptProtoDefineFunc(&MODULE_ENTITY_POSITION_PROTO, "lookAt",
moduleEntityPositionLookAt);
} }
@@ -0,0 +1,201 @@
/**
* 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/modulemesh.h"
#include "script/module/display/modulecolor.h"
#include "script/scriptproto.h"
#include "entity/entity.h"
#include "entity/component/display/entityrenderable.h"
#include "moduleentityposition.h"
static scriptproto_t MODULE_ENTITY_RENDERABLE_PROTO;
static entityrenderable_t * moduleEntityRenderableGet(
const jerry_call_info_t *callInfo
) {
componenthandle_t *h = scriptProtoGetValue(
&MODULE_ENTITY_RENDERABLE_PROTO, callInfo->this_value
);
if(!h) return NULL;
return (entityrenderable_t*)componentGetData(
h->eid, h->cid, COMPONENT_TYPE_RENDERABLE
);
}
moduleBaseFunction(moduleEntityRenderableGetType) {
moduleBaseGetOrReturn(entityrenderable_t, r, moduleEntityRenderableGet);
return jerry_number(r->type);
}
moduleBaseFunction(moduleEntityRenderableSetType) {
moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
moduleBaseGetOrReturn(entityrenderable_t, r, moduleEntityRenderableGet);
r->type = (entityrenderabletype_t)moduleBaseArgInt(0);
return jerry_undefined();
}
moduleBaseFunction(moduleEntityRenderableGetMesh) {
moduleBaseGetOrReturn(entityrenderable_t, r, moduleEntityRenderableGet);
if(!r->mesh) return jerry_undefined();
return moduleBaseWrapPointer(r->mesh);
}
moduleBaseFunction(moduleEntityRenderableSetMesh) {
moduleBaseRequireArgs(1);
moduleBaseGetOrReturn(entityrenderable_t, r, moduleEntityRenderableGet);
meshscript_t *ms = moduleMeshFrom(args[0]);
if(ms) { r->mesh = &ms->mesh; return jerry_undefined(); }
mesh_t *raw = (mesh_t*)moduleBaseUnwrapPointer(args[0]);
if(raw) { r->mesh = raw; return jerry_undefined(); }
return moduleBaseThrow("Expected a Mesh object or mesh constant");
}
moduleBaseFunction(moduleEntityRenderableGetColor) {
moduleBaseGetOrReturn(entityrenderable_t, r, moduleEntityRenderableGet);
return moduleColorMakeObject(r->material.unlit.color);
}
moduleBaseFunction(moduleEntityRenderableSetColor) {
moduleBaseRequireArgs(1); moduleBaseRequireObject(0);
color_t *color = (color_t*)scriptProtoGetValue(&MODULE_COLOR_PROTO, args[0]);
if(!color) return moduleBaseThrow("Renderable.color: expected valid color object");
moduleBaseGetOrReturn(entityrenderable_t, r, moduleEntityRenderableGet);
memoryCopy(&r->material.unlit.color, color, sizeof(color_t));
return jerry_undefined();
}
moduleBaseFunction(moduleEntityRenderableSpriteBatchAdd) {
moduleBaseRequireArgs(1);
componenthandle_t *h = scriptProtoGetValue(
&MODULE_ENTITY_RENDERABLE_PROTO, callInfo->this_value
);
if(!h) return jerry_undefined();
spritebatchsprite_t sprite;
glm_vec3_zero(sprite.min);
glm_vec3_zero(sprite.max);
glm_vec2_zero(sprite.uvMin);
glm_vec2_zero(sprite.uvMax);
sprite.texture = NULL;
#if MESH_ENABLE_COLOR
sprite.color = COLOR_WHITE;
#endif
jerry_value_t obj = args[0];
#define getVecField(name, dst, n) do { \
jerry_value_t _v = jerry_object_get_sz(obj, name); \
if(!jerry_value_is_undefined(_v)) moduleVec##n##AnyCheck(_v, dst); \
jerry_value_free(_v); \
} while(0)
getVecField("min", sprite.min, 3);
getVecField("max", sprite.max, 3);
getVecField("uvMin", sprite.uvMin, 2);
getVecField("uvMax", sprite.uvMax, 2);
#undef getVecField
entityRenderableSpriteBatchAdd(h->eid, h->cid, &sprite);
return jerry_undefined();
}
moduleBaseFunction(moduleEntityRenderableSpriteBatchClear) {
componenthandle_t *h = scriptProtoGetValue(
&MODULE_ENTITY_RENDERABLE_PROTO, callInfo->this_value
);
if(!h) return jerry_undefined();
entityRenderableSpriteBatchClear(h->eid, h->cid);
return jerry_undefined();
}
static void jsRenderCallbackFree(void *user) {
jerry_value_t *cb = (jerry_value_t *)user;
jerry_value_free(*cb);
memoryFree(cb);
}
static errorret_t jsRenderCallbackBridge(
const entityid_t entityId,
const componentid_t componentId,
const mat4 view,
const mat4 proj,
const mat4 model,
void *user
) {
(void)entityId; (void)componentId;
(void)view; (void)proj; (void)model;
jerry_value_t *cb = (jerry_value_t *)user;
jerry_value_t ret = jerry_call(*cb, jerry_undefined(), NULL, 0);
if(jerry_value_is_exception(ret)) {
jerry_value_free(ret);
errorThrow("Renderable callback threw a JS exception");
}
jerry_value_free(ret);
errorOk();
}
moduleBaseFunction(moduleEntityRenderableSetCallback) {
componenthandle_t *h = scriptProtoGetValue(
&MODULE_ENTITY_RENDERABLE_PROTO, callInfo->this_value
);
if(!h) return jerry_undefined();
entityrenderable_t *r = (entityrenderable_t *)componentGetData(
h->eid, h->cid, COMPONENT_TYPE_RENDERABLE
);
if(
r->type == ENTITY_RENDERABLE_TYPE_CALLBACK &&
r->userFree &&
r->user
) {
r->userFree(r->user);
r->user = NULL;
}
if(argc >= 1 && jerry_value_is_function(args[0])) {
jerry_value_t *cb = (jerry_value_t *)memoryAllocate(sizeof(jerry_value_t));
*cb = jerry_value_copy(args[0]);
r->type = ENTITY_RENDERABLE_TYPE_CALLBACK;
r->callback = jsRenderCallbackBridge;
r->userFree = jsRenderCallbackFree;
r->user = cb;
} else {
r->type = ENTITY_RENDERABLE_TYPE_CALLBACK;
r->callback = NULL;
r->userFree = NULL;
r->user = NULL;
}
return jerry_undefined();
}
static void moduleEntityRENDERABLE(void) {
scriptProtoInit(
&MODULE_ENTITY_RENDERABLE_PROTO, NULL, sizeof(componenthandle_t), NULL
);
scriptProtoDefineProp(&MODULE_ENTITY_RENDERABLE_PROTO, "type",
moduleEntityRenderableGetType, moduleEntityRenderableSetType);
scriptProtoDefineProp(&MODULE_ENTITY_RENDERABLE_PROTO, "mesh",
moduleEntityRenderableGetMesh, moduleEntityRenderableSetMesh);
scriptProtoDefineProp(&MODULE_ENTITY_RENDERABLE_PROTO, "color",
moduleEntityRenderableGetColor, moduleEntityRenderableSetColor);
scriptProtoDefineFunc(&MODULE_ENTITY_RENDERABLE_PROTO, "addSprite",
moduleEntityRenderableSpriteBatchAdd);
scriptProtoDefineFunc(&MODULE_ENTITY_RENDERABLE_PROTO, "clearSprites",
moduleEntityRenderableSpriteBatchClear);
scriptProtoDefineFunc(&MODULE_ENTITY_RENDERABLE_PROTO, "setCallback",
moduleEntityRenderableSetCallback);
moduleBaseSetInt("ENTITY_RENDERABLE_TYPE_MATERIAL",
ENTITY_RENDERABLE_TYPE_MATERIAL);
moduleBaseSetInt("ENTITY_RENDERABLE_TYPE_SPRITEBATCH",
ENTITY_RENDERABLE_TYPE_SPRITEBATCH);
moduleBaseSetInt("ENTITY_RENDERABLE_TYPE_CALLBACK",
ENTITY_RENDERABLE_TYPE_CALLBACK);
}
@@ -0,0 +1,92 @@
/**
* 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/math/modulevec3.h"
#include "script/scriptproto.h"
#include "entity/entity.h"
#include "entity/component/trigger/entitytrigger.h"
#include "moduleentityposition.h"
static scriptproto_t MODULE_ENTITY_TRIGGER_PROTO;
static entitytrigger_t * moduleEntityTriggerGet(
const jerry_call_info_t *callInfo
) {
componenthandle_t *h = scriptProtoGetValue(
&MODULE_ENTITY_TRIGGER_PROTO, callInfo->this_value
);
if(!h) return NULL;
return entityTriggerGet(h->eid, h->cid);
}
moduleBaseFunction(moduleEntityTriggerGetMin) {
moduleBaseGetOrReturn(entitytrigger_t, t, moduleEntityTriggerGet);
return moduleVec3Push(t->min);
}
moduleBaseFunction(moduleEntityTriggerSetMin) {
moduleBaseRequireArgs(1);
moduleBaseGetOrReturn(entitytrigger_t, t, moduleEntityTriggerGet);
vec3 v;
if(!moduleVec3AnyCheck(args[0], v)) return moduleBaseThrow("Expected Vec3");
glm_vec3_copy(v, t->min);
return jerry_undefined();
}
moduleBaseFunction(moduleEntityTriggerGetMax) {
moduleBaseGetOrReturn(entitytrigger_t, t, moduleEntityTriggerGet);
return moduleVec3Push(t->max);
}
moduleBaseFunction(moduleEntityTriggerSetMax) {
moduleBaseRequireArgs(1);
moduleBaseGetOrReturn(entitytrigger_t, t, moduleEntityTriggerGet);
vec3 v;
if(!moduleVec3AnyCheck(args[0], v)) return moduleBaseThrow("Expected Vec3");
glm_vec3_copy(v, t->max);
return jerry_undefined();
}
moduleBaseFunction(moduleEntityTriggerSetBounds) {
moduleBaseRequireArgs(2);
componenthandle_t *h = scriptProtoGetValue(
&MODULE_ENTITY_TRIGGER_PROTO, callInfo->this_value
);
if(!h) return jerry_undefined();
vec3 mn, mx;
if(!moduleVec3AnyCheck(args[0], mn)) return moduleBaseThrow("Expected Vec3 min");
if(!moduleVec3AnyCheck(args[1], mx)) return moduleBaseThrow("Expected Vec3 max");
entityTriggerSetBounds(h->eid, h->cid, mn, mx);
return jerry_undefined();
}
moduleBaseFunction(moduleEntityTriggerContains) {
moduleBaseRequireArgs(1);
componenthandle_t *h = scriptProtoGetValue(
&MODULE_ENTITY_TRIGGER_PROTO, callInfo->this_value
);
if(!h) return jerry_boolean(false);
vec3 point;
if(!moduleVec3AnyCheck(args[0], point)) return moduleBaseThrow("Expected Vec3");
return jerry_boolean(entityTriggerContains(h->eid, h->cid, point));
}
static void moduleEntityTRIGGER(void) {
scriptProtoInit(
&MODULE_ENTITY_TRIGGER_PROTO, NULL, sizeof(componenthandle_t), NULL
);
scriptProtoDefineProp(&MODULE_ENTITY_TRIGGER_PROTO, "min",
moduleEntityTriggerGetMin, moduleEntityTriggerSetMin);
scriptProtoDefineProp(&MODULE_ENTITY_TRIGGER_PROTO, "max",
moduleEntityTriggerGetMax, moduleEntityTriggerSetMax);
scriptProtoDefineFunc(&MODULE_ENTITY_TRIGGER_PROTO, "setBounds",
moduleEntityTriggerSetBounds);
scriptProtoDefineFunc(&MODULE_ENTITY_TRIGGER_PROTO, "contains",
moduleEntityTriggerContains);
}
+29 -38
View File
@@ -13,9 +13,9 @@
#include "component/moduleentityposition.h" #include "component/moduleentityposition.h"
#include "component/moduleentitycamera.h" #include "component/moduleentitycamera.h"
#include "component/moduleentitymesh.h" #include "component/moduleentityrenderable.h"
#include "component/moduleentitymaterial.h"
#include "component/moduleentityphysics.h" #include "component/moduleentityphysics.h"
#include "component/moduleentitytrigger.h"
typedef struct { typedef struct {
entityid_t id; entityid_t id;
@@ -23,12 +23,17 @@ typedef struct {
static scriptproto_t MODULE_ENTITY_PROTO; static scriptproto_t MODULE_ENTITY_PROTO;
// Getters static inline entityscript_t * moduleEntityGet(
moduleBaseFunction(moduleEntityGetId) { const jerry_call_info_t *callInfo
entityscript_t *inst = (entityscript_t*)scriptProtoGetValue( ) {
return (entityscript_t*)scriptProtoGetValue(
&MODULE_ENTITY_PROTO, callInfo->this_value &MODULE_ENTITY_PROTO, callInfo->this_value
); );
if(!inst) return jerry_undefined(); }
// Getters
moduleBaseFunction(moduleEntityGetId) {
moduleBaseGetOrReturn(entityscript_t, inst, moduleEntityGet);
return jerry_number(inst->id); return jerry_number(inst->id);
} }
@@ -50,16 +55,13 @@ static jerry_value_t moduleEntityGetComponent(
entityid_t entityId; entityid_t entityId;
componentid_t compId; componentid_t compId;
// Get the entity script data. entityscript_t *inst = moduleEntityGet(callInfo);
entityscript_t *inst = (entityscript_t*)scriptProtoGetValue(
&MODULE_ENTITY_PROTO, callInfo->this_value
);
if(!inst) return jerry_undefined(); if(!inst) return jerry_undefined();
entityId = inst->id; entityId = inst->id;
// Find the component ID of the requested type. // Find the component ID of the requested type.
compId = entityGetComponent(entityId, type); compId = entityGetComponent(entityId, type);
if(compId == 0xFF) { if(compId == COMPONENT_ID_INVALID) {
return jerry_undefined(); return jerry_undefined();
} }
@@ -81,9 +83,7 @@ static jerry_value_t moduleEntityGetComponent(
#undef X #undef X
moduleBaseFunction(moduleEntityToString) { moduleBaseFunction(moduleEntityToString) {
entityscript_t *inst = (entityscript_t*)scriptProtoGetValue( entityscript_t *inst = moduleEntityGet(callInfo);
&MODULE_ENTITY_PROTO, callInfo->this_value
);
if(!inst) return jerry_string_sz("Entity(?)"); if(!inst) return jerry_string_sz("Entity(?)");
char_t components[128]; char_t components[128];
@@ -91,7 +91,7 @@ moduleBaseFunction(moduleEntityToString) {
bool_t first = true; bool_t first = true;
for(componenttype_t t = 1; t < COMPONENT_TYPE_COUNT; t++) { for(componenttype_t t = 1; t < COMPONENT_TYPE_COUNT; t++) {
if(entityGetComponent(inst->id, t) == 0xFF) continue; if(entityGetComponent(inst->id, t) == COMPONENT_ID_INVALID) continue;
if(!first) { if(!first) {
stringCopy(components + clen, ", ", sizeof(components) - clen); stringCopy(components + clen, ", ", sizeof(components) - clen);
clen += 2; clen += 2;
@@ -130,30 +130,29 @@ moduleBaseFunction(moduleEntityConstructor) {
} }
moduleBaseFunction(moduleEntityAddComponent) { moduleBaseFunction(moduleEntityAddComponent) {
if(argc < 1 || !jerry_value_is_number(args[0])) { moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
return moduleBaseThrow("Entity.add: expected a valid component type"); componenttype_t type = (componenttype_t)moduleBaseArgInt(0);
}
componenttype_t type = (componenttype_t)jerry_value_as_number(args[0]);
if(type <= COMPONENT_TYPE_NULL || type >= COMPONENT_TYPE_COUNT) { if(type <= COMPONENT_TYPE_NULL || type >= COMPONENT_TYPE_COUNT) {
return moduleBaseThrow("Entity.add: invalid component type"); return moduleBaseThrow("Entity.add: invalid component type");
} }
// Get the entity script data. entityscript_t *inst = moduleEntityGet(callInfo);
entityscript_t *inst = (entityscript_t*)scriptProtoGetValue(
&MODULE_ENTITY_PROTO, callInfo->this_value
);
if(!inst) return moduleBaseThrow("Entity.add: invalid entity"); if(!inst) return moduleBaseThrow("Entity.add: invalid entity");
componentid_t id = entityAddComponent(inst->id, type); componentid_t id = entityAddComponent(inst->id, type);
return jerry_number(id); componenthandle_t h = { .eid = inst->id, .cid = id };
switch(type) {
#define X(enumName, stype, field, init, dispose) \
case COMPONENT_TYPE_##enumName: \
return scriptProtoCreateValue(&MODULE_ENTITY_##enumName##_PROTO, &h);
#include "entity/componentlist.h"
#undef X
default: return jerry_number(id);
}
} }
moduleBaseFunction(moduleEntityDisposeMethod) { moduleBaseFunction(moduleEntityDisposeMethod) {
entityscript_t *inst = (entityscript_t*)scriptProtoGetValue( moduleBaseGetOrReturn(entityscript_t, inst, moduleEntityGet);
&MODULE_ENTITY_PROTO, callInfo->this_value
);
if(!inst) return jerry_undefined();
entityDispose(inst->id); entityDispose(inst->id);
return jerry_undefined(); return jerry_undefined();
} }
@@ -183,8 +182,6 @@ static void moduleEntity(void) {
); );
// Init component type modules. // Init component type modules.
char_t buffer[64];
#define X(enumName, type, field, iMethod, dMethod) \ #define X(enumName, type, field, iMethod, dMethod) \
moduleEntity##enumName(); \ moduleEntity##enumName(); \
scriptProtoDefineProp( \ scriptProtoDefineProp( \
@@ -193,13 +190,7 @@ static void moduleEntity(void) {
moduleEntityGet##enumName, \ moduleEntityGet##enumName, \
NULL \ NULL \
); \ ); \
snprintf( \ moduleBaseSetInt(#enumName, COMPONENT_TYPE_##enumName);
buffer, sizeof(buffer), \
"%s = %d\n", \
#enumName, \
COMPONENT_TYPE_##enumName \
); \
moduleBaseEval(buffer);
#include "entity/componentlist.h" #include "entity/componentlist.h"
#undef X #undef X
} }
@@ -7,6 +7,7 @@
#include "script/module/modulebase.h" #include "script/module/modulebase.h"
#include "event/event.h" #include "event/event.h"
#include "assert/assert.h" #include "assert/assert.h"
#include "animation/easing.h"
#define MODULE_EVENT_POOL_MAX 32 #define MODULE_EVENT_POOL_MAX 32
@@ -67,3 +68,36 @@ static void moduleEventJsUnsubscribe(event_t *event, jerry_value_t callback) {
return; return;
} }
} }
/**
* Swap a pool-based event callback slot. Unsubscribes and frees the previous
* function (if any), then subscribes fn if it is callable. Pass
* jerry_undefined() as fn to clear without setting a new callback.
*/
static inline void moduleEventSetCallback(
jerry_value_t *slot, event_t *event, jerry_value_t fn
) {
if(*slot) {
moduleEventJsUnsubscribe(event, *slot);
jerry_value_free(*slot);
*slot = 0;
}
if(jerry_value_is_function(fn)) {
*slot = jerry_value_copy(fn);
moduleEventJsSubscribe(event, fn);
}
}
/**
* Read an easing type from a JS value. Accepts either a raw number (easing
* enum) or an easing function object with a .type property. Returns
* EASING_LINEAR for any other input.
*/
static inline easingtype_t moduleReadEasing(jerry_value_t val) {
if(jerry_value_is_number(val)) return (easingtype_t)moduleBaseValueInt(val);
jerry_value_t typeVal = moduleBaseGetProp(val, "type");
easingtype_t type = jerry_value_is_number(typeVal)
? (easingtype_t)moduleBaseValueInt(typeVal) : EASING_LINEAR;
jerry_value_free(typeVal);
return type;
}
+26 -53
View File
@@ -16,9 +16,7 @@ static scriptproto_t MODULE_INPUT_PROTO;
// Static Methods // Static Methods
moduleBaseFunction(moduleInputBind) { moduleBaseFunction(moduleInputBind) {
if(argc < 2) return moduleBaseThrow("Expected at least 2 arguments"); moduleBaseRequireArgs(2); moduleBaseRequireString(0); moduleBaseRequireNumber(1);
moduleBaseRequireString(0);
moduleBaseRequireNumber(1);
char_t strBtn[128]; char_t strBtn[128];
moduleBaseToString(args[0], strBtn, sizeof(strBtn)); moduleBaseToString(args[0], strBtn, sizeof(strBtn));
@@ -26,7 +24,7 @@ moduleBaseFunction(moduleInputBind) {
return moduleBaseThrow("Input.bind: button name cannot be empty"); return moduleBaseThrow("Input.bind: button name cannot be empty");
} }
const inputaction_t action = (inputaction_t)jerry_value_as_number(args[1]); const inputaction_t action = (inputaction_t)moduleBaseArgInt(1);
if(action <= INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) { if(action <= INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) {
return moduleBaseThrow("Input.bind: invalid action"); return moduleBaseThrow("Input.bind: invalid action");
} }
@@ -41,12 +39,8 @@ moduleBaseFunction(moduleInputBind) {
} }
moduleBaseFunction(moduleInputIsDown) { moduleBaseFunction(moduleInputIsDown) {
if(argc < 1) { moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
return moduleBaseThrow("Expected at least 1 argument"); const inputaction_t action = (inputaction_t)moduleBaseArgInt(0);
}
moduleBaseRequireNumber(0);
const inputaction_t action = (inputaction_t)jerry_value_as_number(args[0]);
if(action <= INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) { if(action <= INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) {
return moduleBaseThrow("Input.isDown: invalid action"); return moduleBaseThrow("Input.isDown: invalid action");
} }
@@ -54,12 +48,8 @@ moduleBaseFunction(moduleInputIsDown) {
} }
moduleBaseFunction(moduleInputPressed) { moduleBaseFunction(moduleInputPressed) {
if(argc < 1) { moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
return moduleBaseThrow("Expected at least 1 argument"); const inputaction_t action = (inputaction_t)moduleBaseArgInt(0);
}
moduleBaseRequireNumber(0);
const inputaction_t action = (inputaction_t)jerry_value_as_number(args[0]);
if(action <= INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) { if(action <= INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) {
return moduleBaseThrow("Input.pressed: invalid action"); return moduleBaseThrow("Input.pressed: invalid action");
} }
@@ -67,12 +57,8 @@ moduleBaseFunction(moduleInputPressed) {
} }
moduleBaseFunction(moduleInputReleased) { moduleBaseFunction(moduleInputReleased) {
if(argc < 1) { moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
return moduleBaseThrow("Expected at least 1 argument"); const inputaction_t action = (inputaction_t)moduleBaseArgInt(0);
}
moduleBaseRequireNumber(0);
const inputaction_t action = (inputaction_t)jerry_value_as_number(args[0]);
if(action <= INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) { if(action <= INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) {
return moduleBaseThrow("Input.released: invalid action"); return moduleBaseThrow("Input.released: invalid action");
} }
@@ -80,12 +66,8 @@ moduleBaseFunction(moduleInputReleased) {
} }
moduleBaseFunction(moduleInputGetValue) { moduleBaseFunction(moduleInputGetValue) {
if(argc < 1) { moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
return moduleBaseThrow("Expected at least 1 argument"); const inputaction_t action = (inputaction_t)moduleBaseArgInt(0);
}
moduleBaseRequireNumber(0);
const inputaction_t action = (inputaction_t)jerry_value_as_number(args[0]);
if(action <= INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) { if(action <= INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) {
return moduleBaseThrow("Input.getValue: invalid action"); return moduleBaseThrow("Input.getValue: invalid action");
} }
@@ -93,10 +75,9 @@ moduleBaseFunction(moduleInputGetValue) {
} }
moduleBaseFunction(moduleInputAxis) { moduleBaseFunction(moduleInputAxis) {
if(argc < 2) return moduleBaseThrow("Expected at least 2 arguments"); moduleBaseRequireArgs(2); moduleBaseRequireNumber(0); moduleBaseRequireNumber(1);
moduleBaseRequireNumber(0); moduleBaseRequireNumber(1); const inputaction_t neg = (inputaction_t)moduleBaseArgInt(0);
const inputaction_t neg = (inputaction_t)jerry_value_as_number(args[0]); const inputaction_t pos = (inputaction_t)moduleBaseArgInt(1);
const inputaction_t pos = (inputaction_t)jerry_value_as_number(args[1]);
if(neg <= INPUT_ACTION_NULL || neg >= INPUT_ACTION_COUNT) { if(neg <= INPUT_ACTION_NULL || neg >= INPUT_ACTION_COUNT) {
return moduleBaseThrow("Input.axis: invalid negative action"); return moduleBaseThrow("Input.axis: invalid negative action");
} }
@@ -107,13 +88,13 @@ moduleBaseFunction(moduleInputAxis) {
} }
moduleBaseFunction(moduleInputAxis2D) { moduleBaseFunction(moduleInputAxis2D) {
if(argc < 4) return moduleBaseThrow("Expected at least 4 arguments"); moduleBaseRequireArgs(4);
moduleBaseRequireNumber(0); moduleBaseRequireNumber(1); moduleBaseRequireNumber(0); moduleBaseRequireNumber(1);
moduleBaseRequireNumber(2); moduleBaseRequireNumber(3); moduleBaseRequireNumber(2); moduleBaseRequireNumber(3);
const inputaction_t negX = (inputaction_t)jerry_value_as_number(args[0]); const inputaction_t negX = (inputaction_t)moduleBaseArgInt(0);
const inputaction_t posX = (inputaction_t)jerry_value_as_number(args[1]); const inputaction_t posX = (inputaction_t)moduleBaseArgInt(1);
const inputaction_t negY = (inputaction_t)jerry_value_as_number(args[2]); const inputaction_t negY = (inputaction_t)moduleBaseArgInt(2);
const inputaction_t posY = (inputaction_t)jerry_value_as_number(args[3]); const inputaction_t posY = (inputaction_t)moduleBaseArgInt(3);
if(negX <= INPUT_ACTION_NULL || negX >= INPUT_ACTION_COUNT) { if(negX <= INPUT_ACTION_NULL || negX >= INPUT_ACTION_COUNT) {
return moduleBaseThrow("Input.axis2D: invalid negX action"); return moduleBaseThrow("Input.axis2D: invalid negX action");
} }
@@ -132,10 +113,8 @@ moduleBaseFunction(moduleInputAxis2D) {
} }
moduleBaseFunction(moduleInputOnPressed) { moduleBaseFunction(moduleInputOnPressed) {
if(argc < 2) return moduleBaseThrow("Input.onPressed: expected (action, fn)"); moduleBaseRequireArgs(2); moduleBaseRequireNumber(0); moduleBaseRequireFunction(1);
moduleBaseRequireNumber(0); const inputaction_t action = (inputaction_t)moduleBaseArgInt(0);
moduleBaseRequireFunction(1);
const inputaction_t action = (inputaction_t)jerry_value_as_number(args[0]);
if(action <= INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) { if(action <= INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) {
return moduleBaseThrow("Input.onPressed: invalid action"); return moduleBaseThrow("Input.onPressed: invalid action");
} }
@@ -144,10 +123,8 @@ moduleBaseFunction(moduleInputOnPressed) {
} }
moduleBaseFunction(moduleInputOffPressed) { moduleBaseFunction(moduleInputOffPressed) {
if(argc < 2) return moduleBaseThrow("Input.offPressed: expected (action, fn)"); moduleBaseRequireArgs(2); moduleBaseRequireNumber(0); moduleBaseRequireFunction(1);
moduleBaseRequireNumber(0); const inputaction_t action = (inputaction_t)moduleBaseArgInt(0);
moduleBaseRequireFunction(1);
const inputaction_t action = (inputaction_t)jerry_value_as_number(args[0]);
if(action <= INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) { if(action <= INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) {
return moduleBaseThrow("Input.offPressed: invalid action"); return moduleBaseThrow("Input.offPressed: invalid action");
} }
@@ -156,10 +133,8 @@ moduleBaseFunction(moduleInputOffPressed) {
} }
moduleBaseFunction(moduleInputOnReleased) { moduleBaseFunction(moduleInputOnReleased) {
if(argc < 2) return moduleBaseThrow("Input.onReleased: expected (action, fn)"); moduleBaseRequireArgs(2); moduleBaseRequireNumber(0); moduleBaseRequireFunction(1);
moduleBaseRequireNumber(0); const inputaction_t action = (inputaction_t)moduleBaseArgInt(0);
moduleBaseRequireFunction(1);
const inputaction_t action = (inputaction_t)jerry_value_as_number(args[0]);
if(action <= INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) { if(action <= INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) {
return moduleBaseThrow("Input.onReleased: invalid action"); return moduleBaseThrow("Input.onReleased: invalid action");
} }
@@ -168,10 +143,8 @@ moduleBaseFunction(moduleInputOnReleased) {
} }
moduleBaseFunction(moduleInputOffReleased) { moduleBaseFunction(moduleInputOffReleased) {
if(argc < 2) return moduleBaseThrow("Input.offReleased: expected (action, fn)"); moduleBaseRequireArgs(2); moduleBaseRequireNumber(0); moduleBaseRequireFunction(1);
moduleBaseRequireNumber(0); const inputaction_t action = (inputaction_t)moduleBaseArgInt(0);
moduleBaseRequireFunction(1);
const inputaction_t action = (inputaction_t)jerry_value_as_number(args[0]);
if(action <= INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) { if(action <= INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) {
return moduleBaseThrow("Input.offReleased: invalid action"); return moduleBaseThrow("Input.offReleased: invalid action");
} }
+22 -53
View File
@@ -27,88 +27,57 @@ static inline inventory_t * moduleInventoryGet(
} }
moduleBaseFunction(moduleInventoryAdd) { moduleBaseFunction(moduleInventoryAdd) {
if(argc < 2) return moduleBaseThrow("Expected (itemId, quantity)"); moduleBaseRequireArgs(2); moduleBaseRequireNumber(0); moduleBaseRequireNumber(1);
moduleBaseRequireNumber(0); moduleBaseGetOrReturn(inventory_t, inv, moduleInventoryGet);
moduleBaseRequireNumber(1); inventoryAdd(inv, (itemid_t)moduleBaseArgInt(0), (uint8_t)moduleBaseArgInt(1));
inventory_t *inv = moduleInventoryGet(callInfo);
if(!inv) return jerry_undefined();
inventoryAdd(
inv,
(itemid_t)jerry_value_as_number(args[0]),
(uint8_t)jerry_value_as_number(args[1])
);
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleInventoryRemove) { moduleBaseFunction(moduleInventoryRemove) {
if(argc < 1) return moduleBaseThrow("Expected itemId"); moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
moduleBaseRequireNumber(0); moduleBaseGetOrReturn(inventory_t, inv, moduleInventoryGet);
inventory_t *inv = moduleInventoryGet(callInfo); inventoryRemove(inv, (itemid_t)moduleBaseArgInt(0));
if(!inv) return jerry_undefined();
inventoryRemove(inv, (itemid_t)jerry_value_as_number(args[0]));
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleInventorySet) { moduleBaseFunction(moduleInventorySet) {
if(argc < 2) return moduleBaseThrow("Expected (itemId, quantity)"); moduleBaseRequireArgs(2); moduleBaseRequireNumber(0); moduleBaseRequireNumber(1);
moduleBaseRequireNumber(0); moduleBaseGetOrReturn(inventory_t, inv, moduleInventoryGet);
moduleBaseRequireNumber(1); inventorySet(inv, (itemid_t)moduleBaseArgInt(0), (uint8_t)moduleBaseArgInt(1));
inventory_t *inv = moduleInventoryGet(callInfo);
if(!inv) return jerry_undefined();
inventorySet(
inv,
(itemid_t)jerry_value_as_number(args[0]),
(uint8_t)jerry_value_as_number(args[1])
);
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleInventoryCount) { moduleBaseFunction(moduleInventoryCount) {
if(argc < 1) return moduleBaseThrow("Expected itemId"); moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
moduleBaseRequireNumber(0); moduleBaseGetOrReturn(inventory_t, inv, moduleInventoryGet);
inventory_t *inv = moduleInventoryGet(callInfo); return jerry_number((double)inventoryGetCount(inv, (itemid_t)moduleBaseArgInt(0)));
if(!inv) return jerry_undefined();
return jerry_number(
(double)inventoryGetCount(inv, (itemid_t)jerry_value_as_number(args[0]))
);
} }
moduleBaseFunction(moduleInventoryHas) { moduleBaseFunction(moduleInventoryHas) {
if(argc < 1) return moduleBaseThrow("Expected itemId"); moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
moduleBaseRequireNumber(0); moduleBaseGetOrReturn(inventory_t, inv, moduleInventoryGet);
inventory_t *inv = moduleInventoryGet(callInfo); return jerry_boolean(inventoryItemExists(inv, (itemid_t)moduleBaseArgInt(0)));
if(!inv) return jerry_undefined();
return jerry_boolean(
inventoryItemExists(inv, (itemid_t)jerry_value_as_number(args[0]))
);
} }
moduleBaseFunction(moduleInventoryIsItemFull) { moduleBaseFunction(moduleInventoryIsItemFull) {
if(argc < 1) return moduleBaseThrow("Expected itemId"); moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
moduleBaseRequireNumber(0); moduleBaseGetOrReturn(inventory_t, inv, moduleInventoryGet);
inventory_t *inv = moduleInventoryGet(callInfo); return jerry_boolean(inventoryItemFull(inv, (itemid_t)moduleBaseArgInt(0)));
if(!inv) return jerry_undefined();
return jerry_boolean(
inventoryItemFull(inv, (itemid_t)jerry_value_as_number(args[0]))
);
} }
moduleBaseFunction(moduleInventorySort) { moduleBaseFunction(moduleInventorySort) {
if(argc < 1) return moduleBaseThrow("Expected sortBy"); moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
moduleBaseRequireNumber(0); moduleBaseGetOrReturn(inventory_t, inv, moduleInventoryGet);
inventory_t *inv = moduleInventoryGet(callInfo);
if(!inv) return jerry_undefined();
inventorySort( inventorySort(
inv, inv,
(inventorysort_t)jerry_value_as_number(args[0]), (inventorysort_t)moduleBaseArgInt(0),
(argc >= 2 && jerry_value_is_true(args[1])) (argc >= 2 && jerry_value_is_true(args[1]))
); );
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleInventoryGetFull) { moduleBaseFunction(moduleInventoryGetFull) {
inventory_t *inv = moduleInventoryGet(callInfo); moduleBaseGetOrReturn(inventory_t, inv, moduleInventoryGet);
if(!inv) return jerry_undefined();
return jerry_boolean(inventoryIsFull(inv)); return jerry_boolean(inventoryIsFull(inv));
} }
+10 -13
View File
@@ -28,7 +28,7 @@ moduleBaseFunction(moduleMatConstructor) {
} }
moduleBaseFunction(moduleMatMul) { moduleBaseFunction(moduleMatMul) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); moduleBaseRequireArgs(1);
float_t (*a)[4] = (float_t (*)[4])moduleMatGet(callInfo); float_t (*a)[4] = (float_t (*)[4])moduleMatGet(callInfo);
if(!a) return moduleBaseThrow("Mat4.mul: invalid this"); if(!a) return moduleBaseThrow("Mat4.mul: invalid this");
float_t (*b)[4] = (float_t (*)[4])scriptProtoGetValue( float_t (*b)[4] = (float_t (*)[4])scriptProtoGetValue(
@@ -63,22 +63,21 @@ moduleBaseFunction(moduleMatDeterminant) {
} }
moduleBaseFunction(moduleMatMulVec3) { moduleBaseFunction(moduleMatMulVec3) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); moduleBaseRequireArgs(1);
float_t (*m)[4] = (float_t (*)[4])moduleMatGet(callInfo); float_t (*m)[4] = (float_t (*)[4])moduleMatGet(callInfo);
if(!m) return moduleBaseThrow("Mat4.mulVec3: invalid this"); if(!m) return moduleBaseThrow("Mat4.mulVec3: invalid this");
vec3 vin; vec3 vin;
if(!moduleVec3Check(args[0], vin)) { if(!moduleVec3Check(args[0], vin)) {
return moduleBaseThrow("Mat4.mulVec3: argument must be a Vec3"); return moduleBaseThrow("Mat4.mulVec3: argument must be a Vec3");
} }
float_t w = (argc >= 2 && jerry_value_is_number(args[1])) float_t w = moduleBaseOptFloat(1, 1.0f);
? (float_t)jerry_value_as_number(args[1]) : 1.0f;
vec3 vout; vec3 vout;
glm_mat4_mulv3(m, vin, w, vout); glm_mat4_mulv3(m, vin, w, vout);
return moduleVec3Push(vout); return moduleVec3Push(vout);
} }
moduleBaseFunction(moduleMatMulVec4) { moduleBaseFunction(moduleMatMulVec4) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); moduleBaseRequireArgs(1);
float_t (*m)[4] = (float_t (*)[4])moduleMatGet(callInfo); float_t (*m)[4] = (float_t (*)[4])moduleMatGet(callInfo);
if(!m) return moduleBaseThrow("Mat4.mulVec4: invalid this"); if(!m) return moduleBaseThrow("Mat4.mulVec4: invalid this");
vec4 vin; vec4 vin;
@@ -91,7 +90,7 @@ moduleBaseFunction(moduleMatMulVec4) {
} }
moduleBaseFunction(moduleMatTranslate) { moduleBaseFunction(moduleMatTranslate) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); moduleBaseRequireArgs(1);
float_t (*m)[4] = (float_t (*)[4])moduleMatGet(callInfo); float_t (*m)[4] = (float_t (*)[4])moduleMatGet(callInfo);
if(!m) return moduleBaseThrow("Mat4.translate: invalid this"); if(!m) return moduleBaseThrow("Mat4.translate: invalid this");
vec3 tv; vec3 tv;
@@ -105,7 +104,7 @@ moduleBaseFunction(moduleMatTranslate) {
} }
moduleBaseFunction(moduleMatScale) { moduleBaseFunction(moduleMatScale) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); moduleBaseRequireArgs(1);
float_t (*m)[4] = (float_t (*)[4])moduleMatGet(callInfo); float_t (*m)[4] = (float_t (*)[4])moduleMatGet(callInfo);
if(!m) return moduleBaseThrow("Mat4.scale: invalid this"); if(!m) return moduleBaseThrow("Mat4.scale: invalid this");
vec3 sv; vec3 sv;
@@ -125,22 +124,20 @@ moduleBaseFunction(moduleMatStaticIdentity) {
} }
moduleBaseFunction(moduleMatStaticPerspective) { moduleBaseFunction(moduleMatStaticPerspective) {
if(argc < 4) return moduleBaseThrow("Expected at least 4 arguments"); moduleBaseRequireArgs(4);
moduleBaseRequireNumber(0); moduleBaseRequireNumber(1); moduleBaseRequireNumber(0); moduleBaseRequireNumber(1);
moduleBaseRequireNumber(2); moduleBaseRequireNumber(3); moduleBaseRequireNumber(2); moduleBaseRequireNumber(3);
mat4 r; mat4 r;
glm_perspective( glm_perspective(
(float_t)jerry_value_as_number(args[0]), moduleBaseArgFloat(0), moduleBaseArgFloat(1),
(float_t)jerry_value_as_number(args[1]), moduleBaseArgFloat(2), moduleBaseArgFloat(3),
(float_t)jerry_value_as_number(args[2]),
(float_t)jerry_value_as_number(args[3]),
r r
); );
return scriptProtoCreateValue(&MODULE_MAT4_PROTO, r); return scriptProtoCreateValue(&MODULE_MAT4_PROTO, r);
} }
moduleBaseFunction(moduleMatStaticLookAt) { moduleBaseFunction(moduleMatStaticLookAt) {
if(argc < 3) return moduleBaseThrow("Expected at least 3 arguments"); moduleBaseRequireArgs(3);
vec3 eye, center, up; vec3 eye, center, up;
if(!moduleVec3Check(args[0], eye)) { if(!moduleVec3Check(args[0], eye)) {
return moduleBaseThrow("Mat4.lookAt: eye must be a Vec3"); return moduleBaseThrow("Mat4.lookAt: eye must be a Vec3");
+24 -28
View File
@@ -24,10 +24,8 @@ static inline float_t * moduleVec2From(jerry_value_t val) {
moduleBaseFunction(moduleVec2Constructor) { moduleBaseFunction(moduleVec2Constructor) {
float_t *ptr = (float_t *)memoryAllocate(sizeof(vec2)); float_t *ptr = (float_t *)memoryAllocate(sizeof(vec2));
ptr[0] = (argc >= 1 && jerry_value_is_number(args[0])) ptr[0] = moduleBaseOptFloat(0, 0.0f);
? (float_t)jerry_value_as_number(args[0]) : 0.0f; ptr[1] = moduleBaseOptFloat(1, 0.0f);
ptr[1] = (argc >= 2 && jerry_value_is_number(args[1]))
? (float_t)jerry_value_as_number(args[1]) : 0.0f;
jerry_object_set_native_ptr( jerry_object_set_native_ptr(
callInfo->this_value, &MODULE_VEC2_PROTO.info, ptr callInfo->this_value, &MODULE_VEC2_PROTO.info, ptr
); );
@@ -35,27 +33,29 @@ moduleBaseFunction(moduleVec2Constructor) {
} }
moduleBaseFunction(moduleVec2GetX) { moduleBaseFunction(moduleVec2GetX) {
float_t *v = moduleVec2Get(callInfo); moduleBaseGetOrReturn(float_t, v, moduleVec2Get);
return v ? jerry_number(v[0]) : jerry_undefined(); return jerry_number(v[0]);
} }
moduleBaseFunction(moduleVec2SetX) { moduleBaseFunction(moduleVec2SetX) {
float_t *v = moduleVec2Get(callInfo); moduleBaseRequireArgs(1);
if(v && argc > 0) v[0] = (float_t)jerry_value_as_number(args[0]); moduleBaseGetOrReturn(float_t, v, moduleVec2Get);
v[0] = moduleBaseArgFloat(0);
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleVec2GetY) { moduleBaseFunction(moduleVec2GetY) {
float_t *v = moduleVec2Get(callInfo); moduleBaseGetOrReturn(float_t, v, moduleVec2Get);
return v ? jerry_number(v[1]) : jerry_undefined(); return jerry_number(v[1]);
} }
moduleBaseFunction(moduleVec2SetY) { moduleBaseFunction(moduleVec2SetY) {
float_t *v = moduleVec2Get(callInfo); moduleBaseRequireArgs(1);
if(v && argc > 0) v[1] = (float_t)jerry_value_as_number(args[0]); moduleBaseGetOrReturn(float_t, v, moduleVec2Get);
v[1] = moduleBaseArgFloat(0);
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleVec2Dot) { moduleBaseFunction(moduleVec2Dot) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); moduleBaseRequireArgs(1);
float_t *a = moduleVec2Get(callInfo); float_t *a = moduleVec2Get(callInfo);
if(!a) return moduleBaseThrow("Vec2.dot: invalid this"); if(!a) return moduleBaseThrow("Vec2.dot: invalid this");
float_t *b = moduleVec2From(args[0]); float_t *b = moduleVec2From(args[0]);
@@ -92,7 +92,7 @@ moduleBaseFunction(moduleVec2Negate) {
} }
moduleBaseFunction(moduleVec2Add) { moduleBaseFunction(moduleVec2Add) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); moduleBaseRequireArgs(1);
float_t *a = moduleVec2Get(callInfo); float_t *a = moduleVec2Get(callInfo);
if(!a) return moduleBaseThrow("Vec2.add: invalid this"); if(!a) return moduleBaseThrow("Vec2.add: invalid this");
float_t *b = moduleVec2From(args[0]); float_t *b = moduleVec2From(args[0]);
@@ -103,7 +103,7 @@ moduleBaseFunction(moduleVec2Add) {
} }
moduleBaseFunction(moduleVec2Sub) { moduleBaseFunction(moduleVec2Sub) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); moduleBaseRequireArgs(1);
float_t *a = moduleVec2Get(callInfo); float_t *a = moduleVec2Get(callInfo);
if(!a) return moduleBaseThrow("Vec2.sub: invalid this"); if(!a) return moduleBaseThrow("Vec2.sub: invalid this");
float_t *b = moduleVec2From(args[0]); float_t *b = moduleVec2From(args[0]);
@@ -114,35 +114,27 @@ moduleBaseFunction(moduleVec2Sub) {
} }
moduleBaseFunction(moduleVec2Scale) { moduleBaseFunction(moduleVec2Scale) {
if(argc < 1) { moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
return moduleBaseThrow("Expected at least 1 argument");
}
moduleBaseRequireNumber(0);
float_t *v = moduleVec2Get(callInfo); float_t *v = moduleVec2Get(callInfo);
if(!v) return moduleBaseThrow("Vec2.scale: invalid this"); if(!v) return moduleBaseThrow("Vec2.scale: invalid this");
vec2 r; vec2 r;
glm_vec2_scale(v, (float_t)jerry_value_as_number(args[0]), r); glm_vec2_scale(v, moduleBaseArgFloat(0), r);
return scriptProtoCreateValue(&MODULE_VEC2_PROTO, r); return scriptProtoCreateValue(&MODULE_VEC2_PROTO, r);
} }
moduleBaseFunction(moduleVec2Lerp) { moduleBaseFunction(moduleVec2Lerp) {
if(argc < 2) { moduleBaseRequireArgs(2); moduleBaseRequireNumber(1);
return moduleBaseThrow("Expected at least 2 arguments");
}
moduleBaseRequireNumber(1);
float_t *a = moduleVec2Get(callInfo); float_t *a = moduleVec2Get(callInfo);
if(!a) return moduleBaseThrow("Vec2.lerp: invalid this"); if(!a) return moduleBaseThrow("Vec2.lerp: invalid this");
float_t *b = moduleVec2From(args[0]); float_t *b = moduleVec2From(args[0]);
if(!b) return moduleBaseThrow("Vec2.lerp: first argument must be a Vec2"); if(!b) return moduleBaseThrow("Vec2.lerp: first argument must be a Vec2");
vec2 r; vec2 r;
glm_vec2_lerp(a, b, (float_t)jerry_value_as_number(args[1]), r); glm_vec2_lerp(a, b, moduleBaseArgFloat(1), r);
return scriptProtoCreateValue(&MODULE_VEC2_PROTO, r); return scriptProtoCreateValue(&MODULE_VEC2_PROTO, r);
} }
moduleBaseFunction(moduleVec2Distance) { moduleBaseFunction(moduleVec2Distance) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); moduleBaseRequireArgs(1);
float_t *a = moduleVec2Get(callInfo); float_t *a = moduleVec2Get(callInfo);
if(!a) return moduleBaseThrow("Vec2.distance: invalid this"); if(!a) return moduleBaseThrow("Vec2.distance: invalid this");
float_t *b = moduleVec2From(args[0]); float_t *b = moduleVec2From(args[0]);
@@ -170,6 +162,10 @@ static inline bool_t moduleVec2Check(jerry_value_t val, float_t *out) {
return true; return true;
} }
static inline bool_t moduleVec2AnyCheck(jerry_value_t val, float_t *out) {
return moduleVec2Check(val, out);
}
static void moduleVec2(void) { static void moduleVec2(void) {
scriptProtoInit( scriptProtoInit(
&MODULE_VEC2_PROTO, "Vec2", sizeof(vec2), moduleVec2Constructor &MODULE_VEC2_PROTO, "Vec2", sizeof(vec2), moduleVec2Constructor
+27 -35
View File
@@ -24,12 +24,9 @@ static inline float_t * moduleVec3From(jerry_value_t val) {
moduleBaseFunction(moduleVec3Constructor) { moduleBaseFunction(moduleVec3Constructor) {
float_t *ptr = (float_t *)memoryAllocate(sizeof(vec3)); float_t *ptr = (float_t *)memoryAllocate(sizeof(vec3));
ptr[0] = (argc >= 1 && jerry_value_is_number(args[0])) ptr[0] = moduleBaseOptFloat(0, 0.0f);
? (float_t)jerry_value_as_number(args[0]) : 0.0f; ptr[1] = moduleBaseOptFloat(1, 0.0f);
ptr[1] = (argc >= 2 && jerry_value_is_number(args[1])) ptr[2] = moduleBaseOptFloat(2, 0.0f);
? (float_t)jerry_value_as_number(args[1]) : 0.0f;
ptr[2] = (argc >= 3 && jerry_value_is_number(args[2]))
? (float_t)jerry_value_as_number(args[2]) : 0.0f;
jerry_object_set_native_ptr( jerry_object_set_native_ptr(
callInfo->this_value, &MODULE_VEC3_PROTO.info, ptr callInfo->this_value, &MODULE_VEC3_PROTO.info, ptr
); );
@@ -37,37 +34,40 @@ moduleBaseFunction(moduleVec3Constructor) {
} }
moduleBaseFunction(moduleVec3GetX) { moduleBaseFunction(moduleVec3GetX) {
float_t *v = moduleVec3Get(callInfo); moduleBaseGetOrReturn(float_t, v, moduleVec3Get);
return v ? jerry_number(v[0]) : jerry_undefined(); return jerry_number(v[0]);
} }
moduleBaseFunction(moduleVec3SetX) { moduleBaseFunction(moduleVec3SetX) {
float_t *v = moduleVec3Get(callInfo); moduleBaseRequireArgs(1);
if(v && argc > 0) v[0] = (float_t)jerry_value_as_number(args[0]); moduleBaseGetOrReturn(float_t, v, moduleVec3Get);
v[0] = moduleBaseArgFloat(0);
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleVec3GetY) { moduleBaseFunction(moduleVec3GetY) {
float_t *v = moduleVec3Get(callInfo); moduleBaseGetOrReturn(float_t, v, moduleVec3Get);
return v ? jerry_number(v[1]) : jerry_undefined(); return jerry_number(v[1]);
} }
moduleBaseFunction(moduleVec3SetY) { moduleBaseFunction(moduleVec3SetY) {
float_t *v = moduleVec3Get(callInfo); moduleBaseRequireArgs(1);
if(v && argc > 0) v[1] = (float_t)jerry_value_as_number(args[0]); moduleBaseGetOrReturn(float_t, v, moduleVec3Get);
v[1] = moduleBaseArgFloat(0);
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleVec3GetZ) { moduleBaseFunction(moduleVec3GetZ) {
float_t *v = moduleVec3Get(callInfo); moduleBaseGetOrReturn(float_t, v, moduleVec3Get);
return v ? jerry_number(v[2]) : jerry_undefined(); return jerry_number(v[2]);
} }
moduleBaseFunction(moduleVec3SetZ) { moduleBaseFunction(moduleVec3SetZ) {
float_t *v = moduleVec3Get(callInfo); moduleBaseRequireArgs(1);
if(v && argc > 0) v[2] = (float_t)jerry_value_as_number(args[0]); moduleBaseGetOrReturn(float_t, v, moduleVec3Get);
v[2] = moduleBaseArgFloat(0);
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleVec3Dot) { moduleBaseFunction(moduleVec3Dot) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); moduleBaseRequireArgs(1);
float_t *a = moduleVec3Get(callInfo); float_t *a = moduleVec3Get(callInfo);
if(!a) return moduleBaseThrow("Vec3.dot: invalid this"); if(!a) return moduleBaseThrow("Vec3.dot: invalid this");
float_t *b = moduleVec3From(args[0]); float_t *b = moduleVec3From(args[0]);
@@ -76,7 +76,7 @@ moduleBaseFunction(moduleVec3Dot) {
} }
moduleBaseFunction(moduleVec3Cross) { moduleBaseFunction(moduleVec3Cross) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); moduleBaseRequireArgs(1);
float_t *a = moduleVec3Get(callInfo); float_t *a = moduleVec3Get(callInfo);
if(!a) return moduleBaseThrow("Vec3.cross: invalid this"); if(!a) return moduleBaseThrow("Vec3.cross: invalid this");
float_t *b = moduleVec3From(args[0]); float_t *b = moduleVec3From(args[0]);
@@ -115,7 +115,7 @@ moduleBaseFunction(moduleVec3Negate) {
} }
moduleBaseFunction(moduleVec3Add) { moduleBaseFunction(moduleVec3Add) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); moduleBaseRequireArgs(1);
float_t *a = moduleVec3Get(callInfo); float_t *a = moduleVec3Get(callInfo);
if(!a) return moduleBaseThrow("Vec3.add: invalid this"); if(!a) return moduleBaseThrow("Vec3.add: invalid this");
float_t *b = moduleVec3From(args[0]); float_t *b = moduleVec3From(args[0]);
@@ -126,7 +126,7 @@ moduleBaseFunction(moduleVec3Add) {
} }
moduleBaseFunction(moduleVec3Sub) { moduleBaseFunction(moduleVec3Sub) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); moduleBaseRequireArgs(1);
float_t *a = moduleVec3Get(callInfo); float_t *a = moduleVec3Get(callInfo);
if(!a) return moduleBaseThrow("Vec3.sub: invalid this"); if(!a) return moduleBaseThrow("Vec3.sub: invalid this");
float_t *b = moduleVec3From(args[0]); float_t *b = moduleVec3From(args[0]);
@@ -137,35 +137,27 @@ moduleBaseFunction(moduleVec3Sub) {
} }
moduleBaseFunction(moduleVec3Scale) { moduleBaseFunction(moduleVec3Scale) {
if(argc < 1) { moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
return moduleBaseThrow("Expected at least 1 argument");
}
moduleBaseRequireNumber(0);
float_t *v = moduleVec3Get(callInfo); float_t *v = moduleVec3Get(callInfo);
if(!v) return moduleBaseThrow("Vec3.scale: invalid this"); if(!v) return moduleBaseThrow("Vec3.scale: invalid this");
vec3 r; vec3 r;
glm_vec3_scale(v, (float_t)jerry_value_as_number(args[0]), r); glm_vec3_scale(v, moduleBaseArgFloat(0), r);
return scriptProtoCreateValue(&MODULE_VEC3_PROTO, r); return scriptProtoCreateValue(&MODULE_VEC3_PROTO, r);
} }
moduleBaseFunction(moduleVec3Lerp) { moduleBaseFunction(moduleVec3Lerp) {
if(argc < 2) { moduleBaseRequireArgs(2); moduleBaseRequireNumber(1);
return moduleBaseThrow("Expected at least 2 arguments");
}
moduleBaseRequireNumber(1);
float_t *a = moduleVec3Get(callInfo); float_t *a = moduleVec3Get(callInfo);
if(!a) return moduleBaseThrow("Vec3.lerp: invalid this"); if(!a) return moduleBaseThrow("Vec3.lerp: invalid this");
float_t *b = moduleVec3From(args[0]); float_t *b = moduleVec3From(args[0]);
if(!b) return moduleBaseThrow("Vec3.lerp: first argument must be a Vec3"); if(!b) return moduleBaseThrow("Vec3.lerp: first argument must be a Vec3");
vec3 r; vec3 r;
glm_vec3_lerp(a, b, (float_t)jerry_value_as_number(args[1]), r); glm_vec3_lerp(a, b, moduleBaseArgFloat(1), r);
return scriptProtoCreateValue(&MODULE_VEC3_PROTO, r); return scriptProtoCreateValue(&MODULE_VEC3_PROTO, r);
} }
moduleBaseFunction(moduleVec3Distance) { moduleBaseFunction(moduleVec3Distance) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); moduleBaseRequireArgs(1);
float_t *a = moduleVec3Get(callInfo); float_t *a = moduleVec3Get(callInfo);
if(!a) return moduleBaseThrow("Vec3.distance: invalid this"); if(!a) return moduleBaseThrow("Vec3.distance: invalid this");
float_t *b = moduleVec3From(args[0]); float_t *b = moduleVec3From(args[0]);
+18 -21
View File
@@ -36,41 +36,38 @@ static inline void moduleVec3RefNotify(vec3ref_t *ref) {
} }
moduleBaseFunction(moduleVec3RefGetX) { moduleBaseFunction(moduleVec3RefGetX) {
vec3ref_t *ref = moduleVec3RefGet(callInfo); moduleBaseGetOrReturn(vec3ref_t, ref, moduleVec3RefGet);
return ref ? jerry_number(ref->data[0]) : jerry_undefined(); return jerry_number(ref->data[0]);
} }
moduleBaseFunction(moduleVec3RefSetX) { moduleBaseFunction(moduleVec3RefSetX) {
vec3ref_t *ref = moduleVec3RefGet(callInfo); moduleBaseRequireArgs(1);
if(ref && argc > 0) { moduleBaseGetOrReturn(vec3ref_t, ref, moduleVec3RefGet);
ref->data[0] = (float_t)jerry_value_as_number(args[0]); ref->data[0] = moduleBaseArgFloat(0);
moduleVec3RefNotify(ref); moduleVec3RefNotify(ref);
}
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleVec3RefGetY) { moduleBaseFunction(moduleVec3RefGetY) {
vec3ref_t *ref = moduleVec3RefGet(callInfo); moduleBaseGetOrReturn(vec3ref_t, ref, moduleVec3RefGet);
return ref ? jerry_number(ref->data[1]) : jerry_undefined(); return jerry_number(ref->data[1]);
} }
moduleBaseFunction(moduleVec3RefSetY) { moduleBaseFunction(moduleVec3RefSetY) {
vec3ref_t *ref = moduleVec3RefGet(callInfo); moduleBaseRequireArgs(1);
if(ref && argc > 0) { moduleBaseGetOrReturn(vec3ref_t, ref, moduleVec3RefGet);
ref->data[1] = (float_t)jerry_value_as_number(args[0]); ref->data[1] = moduleBaseArgFloat(0);
moduleVec3RefNotify(ref); moduleVec3RefNotify(ref);
}
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleVec3RefGetZ) { moduleBaseFunction(moduleVec3RefGetZ) {
vec3ref_t *ref = moduleVec3RefGet(callInfo); moduleBaseGetOrReturn(vec3ref_t, ref, moduleVec3RefGet);
return ref ? jerry_number(ref->data[2]) : jerry_undefined(); return jerry_number(ref->data[2]);
} }
moduleBaseFunction(moduleVec3RefSetZ) { moduleBaseFunction(moduleVec3RefSetZ) {
vec3ref_t *ref = moduleVec3RefGet(callInfo); moduleBaseRequireArgs(1);
if(ref && argc > 0) { moduleBaseGetOrReturn(vec3ref_t, ref, moduleVec3RefGet);
ref->data[2] = (float_t)jerry_value_as_number(args[0]); ref->data[2] = moduleBaseArgFloat(0);
moduleVec3RefNotify(ref); moduleVec3RefNotify(ref);
}
return jerry_undefined(); return jerry_undefined();
} }
+35 -63
View File
@@ -24,14 +24,10 @@ static inline float_t * moduleVec4From(jerry_value_t val) {
moduleBaseFunction(moduleVec4Constructor) { moduleBaseFunction(moduleVec4Constructor) {
float_t *ptr = (float_t *)memoryAllocate(sizeof(vec4)); float_t *ptr = (float_t *)memoryAllocate(sizeof(vec4));
ptr[0] = (argc >= 1 && jerry_value_is_number(args[0])) ptr[0] = moduleBaseOptFloat(0, 0.0f);
? (float_t)jerry_value_as_number(args[0]) : 0.0f; ptr[1] = moduleBaseOptFloat(1, 0.0f);
ptr[1] = (argc >= 2 && jerry_value_is_number(args[1])) ptr[2] = moduleBaseOptFloat(2, 0.0f);
? (float_t)jerry_value_as_number(args[1]) : 0.0f; ptr[3] = moduleBaseOptFloat(3, 0.0f);
ptr[2] = (argc >= 3 && jerry_value_is_number(args[2]))
? (float_t)jerry_value_as_number(args[2]) : 0.0f;
ptr[3] = (argc >= 4 && jerry_value_is_number(args[3]))
? (float_t)jerry_value_as_number(args[3]) : 0.0f;
jerry_object_set_native_ptr( jerry_object_set_native_ptr(
callInfo->this_value, &MODULE_VEC4_PROTO.info, ptr callInfo->this_value, &MODULE_VEC4_PROTO.info, ptr
); );
@@ -40,88 +36,72 @@ moduleBaseFunction(moduleVec4Constructor) {
// x/y/z/w // x/y/z/w
moduleBaseFunction(moduleVec4GetX) { moduleBaseFunction(moduleVec4GetX) {
float_t *v = moduleVec4Get(callInfo); moduleBaseGetOrReturn(float_t, v, moduleVec4Get); return jerry_number(v[0]);
return v ? jerry_number(v[0]) : jerry_undefined();
} }
moduleBaseFunction(moduleVec4SetX) { moduleBaseFunction(moduleVec4SetX) {
float_t *v = moduleVec4Get(callInfo); moduleBaseRequireArgs(1); moduleBaseGetOrReturn(float_t, v, moduleVec4Get);
if(v && argc > 0) v[0] = (float_t)jerry_value_as_number(args[0]); v[0] = moduleBaseArgFloat(0); return jerry_undefined();
return jerry_undefined();
} }
moduleBaseFunction(moduleVec4GetY) { moduleBaseFunction(moduleVec4GetY) {
float_t *v = moduleVec4Get(callInfo); moduleBaseGetOrReturn(float_t, v, moduleVec4Get); return jerry_number(v[1]);
return v ? jerry_number(v[1]) : jerry_undefined();
} }
moduleBaseFunction(moduleVec4SetY) { moduleBaseFunction(moduleVec4SetY) {
float_t *v = moduleVec4Get(callInfo); moduleBaseRequireArgs(1); moduleBaseGetOrReturn(float_t, v, moduleVec4Get);
if(v && argc > 0) v[1] = (float_t)jerry_value_as_number(args[0]); v[1] = moduleBaseArgFloat(0); return jerry_undefined();
return jerry_undefined();
} }
moduleBaseFunction(moduleVec4GetZ) { moduleBaseFunction(moduleVec4GetZ) {
float_t *v = moduleVec4Get(callInfo); moduleBaseGetOrReturn(float_t, v, moduleVec4Get); return jerry_number(v[2]);
return v ? jerry_number(v[2]) : jerry_undefined();
} }
moduleBaseFunction(moduleVec4SetZ) { moduleBaseFunction(moduleVec4SetZ) {
float_t *v = moduleVec4Get(callInfo); moduleBaseRequireArgs(1); moduleBaseGetOrReturn(float_t, v, moduleVec4Get);
if(v && argc > 0) v[2] = (float_t)jerry_value_as_number(args[0]); v[2] = moduleBaseArgFloat(0); return jerry_undefined();
return jerry_undefined();
} }
moduleBaseFunction(moduleVec4GetW) { moduleBaseFunction(moduleVec4GetW) {
float_t *v = moduleVec4Get(callInfo); moduleBaseGetOrReturn(float_t, v, moduleVec4Get); return jerry_number(v[3]);
return v ? jerry_number(v[3]) : jerry_undefined();
} }
moduleBaseFunction(moduleVec4SetW) { moduleBaseFunction(moduleVec4SetW) {
float_t *v = moduleVec4Get(callInfo); moduleBaseRequireArgs(1); moduleBaseGetOrReturn(float_t, v, moduleVec4Get);
if(v && argc > 0) v[3] = (float_t)jerry_value_as_number(args[0]); v[3] = moduleBaseArgFloat(0); return jerry_undefined();
return jerry_undefined();
} }
// u0/v0/u1/v1 aliases for UV coordinates // u0/v0/u1/v1 aliases for UV coordinates
moduleBaseFunction(moduleVec4GetU0) { moduleBaseFunction(moduleVec4GetU0) {
float_t *v = moduleVec4Get(callInfo); moduleBaseGetOrReturn(float_t, v, moduleVec4Get); return jerry_number(v[0]);
return v ? jerry_number(v[0]) : jerry_undefined();
} }
moduleBaseFunction(moduleVec4SetU0) { moduleBaseFunction(moduleVec4SetU0) {
float_t *v = moduleVec4Get(callInfo); moduleBaseRequireArgs(1); moduleBaseGetOrReturn(float_t, v, moduleVec4Get);
if(v && argc > 0) v[0] = (float_t)jerry_value_as_number(args[0]); v[0] = moduleBaseArgFloat(0); return jerry_undefined();
return jerry_undefined();
} }
moduleBaseFunction(moduleVec4GetV0) { moduleBaseFunction(moduleVec4GetV0) {
float_t *v = moduleVec4Get(callInfo); moduleBaseGetOrReturn(float_t, v, moduleVec4Get); return jerry_number(v[1]);
return v ? jerry_number(v[1]) : jerry_undefined();
} }
moduleBaseFunction(moduleVec4SetV0) { moduleBaseFunction(moduleVec4SetV0) {
float_t *v = moduleVec4Get(callInfo); moduleBaseRequireArgs(1); moduleBaseGetOrReturn(float_t, v, moduleVec4Get);
if(v && argc > 0) v[1] = (float_t)jerry_value_as_number(args[0]); v[1] = moduleBaseArgFloat(0); return jerry_undefined();
return jerry_undefined();
} }
moduleBaseFunction(moduleVec4GetU1) { moduleBaseFunction(moduleVec4GetU1) {
float_t *v = moduleVec4Get(callInfo); moduleBaseGetOrReturn(float_t, v, moduleVec4Get); return jerry_number(v[2]);
return v ? jerry_number(v[2]) : jerry_undefined();
} }
moduleBaseFunction(moduleVec4SetU1) { moduleBaseFunction(moduleVec4SetU1) {
float_t *v = moduleVec4Get(callInfo); moduleBaseRequireArgs(1); moduleBaseGetOrReturn(float_t, v, moduleVec4Get);
if(v && argc > 0) v[2] = (float_t)jerry_value_as_number(args[0]); v[2] = moduleBaseArgFloat(0); return jerry_undefined();
return jerry_undefined();
} }
moduleBaseFunction(moduleVec4GetV1) { moduleBaseFunction(moduleVec4GetV1) {
float_t *v = moduleVec4Get(callInfo); moduleBaseGetOrReturn(float_t, v, moduleVec4Get); return jerry_number(v[3]);
return v ? jerry_number(v[3]) : jerry_undefined();
} }
moduleBaseFunction(moduleVec4SetV1) { moduleBaseFunction(moduleVec4SetV1) {
float_t *v = moduleVec4Get(callInfo); moduleBaseRequireArgs(1); moduleBaseGetOrReturn(float_t, v, moduleVec4Get);
if(v && argc > 0) v[3] = (float_t)jerry_value_as_number(args[0]); v[3] = moduleBaseArgFloat(0); return jerry_undefined();
return jerry_undefined();
} }
moduleBaseFunction(moduleVec4Dot) { moduleBaseFunction(moduleVec4Dot) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); moduleBaseRequireArgs(1);
float_t *a = moduleVec4Get(callInfo); float_t *a = moduleVec4Get(callInfo);
if(!a) return moduleBaseThrow("Vec4.dot: invalid this"); if(!a) return moduleBaseThrow("Vec4.dot: invalid this");
float_t *b = moduleVec4From(args[0]); float_t *b = moduleVec4From(args[0]);
@@ -158,7 +138,7 @@ moduleBaseFunction(moduleVec4Negate) {
} }
moduleBaseFunction(moduleVec4Add) { moduleBaseFunction(moduleVec4Add) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); moduleBaseRequireArgs(1);
float_t *a = moduleVec4Get(callInfo); float_t *a = moduleVec4Get(callInfo);
if(!a) return moduleBaseThrow("Vec4.add: invalid this"); if(!a) return moduleBaseThrow("Vec4.add: invalid this");
float_t *b = moduleVec4From(args[0]); float_t *b = moduleVec4From(args[0]);
@@ -169,7 +149,7 @@ moduleBaseFunction(moduleVec4Add) {
} }
moduleBaseFunction(moduleVec4Sub) { moduleBaseFunction(moduleVec4Sub) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); moduleBaseRequireArgs(1);
float_t *a = moduleVec4Get(callInfo); float_t *a = moduleVec4Get(callInfo);
if(!a) return moduleBaseThrow("Vec4.sub: invalid this"); if(!a) return moduleBaseThrow("Vec4.sub: invalid this");
float_t *b = moduleVec4From(args[0]); float_t *b = moduleVec4From(args[0]);
@@ -180,30 +160,22 @@ moduleBaseFunction(moduleVec4Sub) {
} }
moduleBaseFunction(moduleVec4Scale) { moduleBaseFunction(moduleVec4Scale) {
if(argc < 1) { moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
return moduleBaseThrow("Expected at least 1 argument");
}
moduleBaseRequireNumber(0);
float_t *v = moduleVec4Get(callInfo); float_t *v = moduleVec4Get(callInfo);
if(!v) return moduleBaseThrow("Vec4.scale: invalid this"); if(!v) return moduleBaseThrow("Vec4.scale: invalid this");
vec4 r; vec4 r;
glm_vec4_scale(v, (float_t)jerry_value_as_number(args[0]), r); glm_vec4_scale(v, moduleBaseArgFloat(0), r);
return scriptProtoCreateValue(&MODULE_VEC4_PROTO, r); return scriptProtoCreateValue(&MODULE_VEC4_PROTO, r);
} }
moduleBaseFunction(moduleVec4Lerp) { moduleBaseFunction(moduleVec4Lerp) {
if(argc < 2) { moduleBaseRequireArgs(2); moduleBaseRequireNumber(1);
return moduleBaseThrow("Expected at least 2 arguments");
}
moduleBaseRequireNumber(1);
float_t *a = moduleVec4Get(callInfo); float_t *a = moduleVec4Get(callInfo);
if(!a) return moduleBaseThrow("Vec4.lerp: invalid this"); if(!a) return moduleBaseThrow("Vec4.lerp: invalid this");
float_t *b = moduleVec4From(args[0]); float_t *b = moduleVec4From(args[0]);
if(!b) return moduleBaseThrow("Vec4.lerp: first argument must be a Vec4"); if(!b) return moduleBaseThrow("Vec4.lerp: first argument must be a Vec4");
vec4 r; vec4 r;
glm_vec4_lerp(a, b, (float_t)jerry_value_as_number(args[1]), r); glm_vec4_lerp(a, b, moduleBaseArgFloat(1), r);
return scriptProtoCreateValue(&MODULE_VEC4_PROTO, r); return scriptProtoCreateValue(&MODULE_VEC4_PROTO, r);
} }
+2
View File
@@ -29,6 +29,7 @@
#include "script/module/ui/moduletextbox.h" #include "script/module/ui/moduletextbox.h"
#include "script/module/ui/modulefullbox.h" #include "script/module/ui/modulefullbox.h"
#include "script/module/save/modulesave.h" #include "script/module/save/modulesave.h"
#include "script/module/overworld/modulemap.h"
static void moduleRegister(void) { static void moduleRegister(void) {
moduleInclude(); moduleInclude();
@@ -53,4 +54,5 @@ static void moduleRegister(void) {
moduleTextbox(); moduleTextbox();
moduleFullbox(); moduleFullbox();
moduleSave(); moduleSave();
moduleMap();
} }
+81
View File
@@ -264,6 +264,59 @@ static void moduleBaseCreateGlobalObject(
} \ } \
} while(0) } while(0)
/**
* Require at least N arguments; throw a TypeError if fewer were provided.
*
* Example: moduleBaseRequireArgs(2);
*/
#define moduleBaseRequireArgs(n) do { \
if(argc < (jerry_length_t)(n)) { \
return moduleBaseThrow("Expected at least " #n " argument(s)"); \
} \
} while(0)
/**
* Declare a typed pointer from a getter and immediately return undefined if it
* is NULL. The named variable is available for the rest of the function.
*
* Example:
* moduleBaseGetOrReturn(entitycamera_t, cam, moduleEntityCameraGet);
* return jerry_number(cam->nearClip);
*/
#define moduleBaseGetOrReturn(type, var, getter) \
type *var = (getter)(callInfo); \
if(!(var)) return jerry_undefined()
/**
* Cast argument i to float_t. Call after validating the arg is a number.
*/
#define moduleBaseArgFloat(i) ((float_t)jerry_value_as_number(args[(i)]))
/**
* Cast argument i to int32_t. Call after validating the arg is a number.
*/
#define moduleBaseArgInt(i) ((int32_t)jerry_value_as_number(args[(i)]))
/**
* Read argument i as a boolean (true/false).
*/
#define moduleBaseArgBool(i) (jerry_value_is_true(args[(i)]))
/**
* Read optional argument i as float_t. Returns def if the argument is missing
* or not a number.
*/
#define moduleBaseOptFloat(i, def) \
((jerry_length_t)(i) < argc && jerry_value_is_number(args[(i)]) \
? (float_t)jerry_value_as_number(args[(i)]) : (def))
/**
* Read optional argument i as int32_t. Returns def if the argument is missing
* or not a number.
*/
#define moduleBaseOptInt(i, def) \
((jerry_length_t)(i) < argc && jerry_value_is_number(args[(i)]) \
? (int32_t)jerry_value_as_number(args[(i)]) : (def))
/** /**
* Set a global numeric constant. * Set a global numeric constant.
@@ -430,3 +483,31 @@ static inline void moduleBaseDefineGlobalMethod(
moduleBaseDefineMethod(global, name, fn); moduleBaseDefineMethod(global, name, fn);
jerry_value_free(global); jerry_value_free(global);
} }
/**
* Get a named property from a JS object. Caller must free the returned value.
*/
static inline jerry_value_t moduleBaseGetProp(
jerry_value_t obj, const char_t *name
) {
jerry_value_t key = jerry_string_sz(name);
jerry_value_t val = jerry_object_get(obj, key);
jerry_value_free(key);
return val;
}
/**
* Cast a JS value to float_t. Use for non-args[] values (e.g. object
* properties). For args[], prefer moduleBaseArgFloat.
*/
static inline float_t moduleBaseValueFloat(jerry_value_t val) {
return (float_t)jerry_value_as_number(val);
}
/**
* Cast a JS value to int32_t. Use for non-args[] values (e.g. object
* properties). For args[], prefer moduleBaseArgInt.
*/
static inline int32_t moduleBaseValueInt(jerry_value_t val) {
return (int32_t)jerry_value_as_number(val);
}
@@ -0,0 +1,137 @@
/**
* 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 "overworld/map.h"
#include "modulemapchunk.h"
static scriptproto_t MODULE_MAP_PROTO;
moduleBaseFunction(moduleMapDefaultUpdate) {
return jerry_undefined();
}
moduleBaseFunction(moduleMapDefaultDispose) {
return jerry_undefined();
}
moduleBaseFunction(moduleMapDefaultConstructor) {
return jerry_undefined();
}
moduleBaseFunction(moduleMapLoad) {
moduleBaseRequireArgs(1); moduleBaseRequireString(0);
char_t handle[MAP_HANDLE_MAX];
moduleBaseToString(args[0], handle, sizeof(handle));
if(handle[0] == '\0') return moduleBaseThrow("Map.load: handle cannot be empty");
errorret_t err = mapLoad(handle);
if(err.code != ERROR_OK) return moduleBaseThrow("Map.load: failed to load map");
return jerry_undefined();
}
moduleBaseFunction(moduleMapIsLoaded) {
return jerry_boolean(mapIsLoaded());
}
moduleBaseFunction(moduleMapDispose) {
mapDispose();
return jerry_undefined();
}
moduleBaseFunction(moduleMapSetChunkSize) {
moduleBaseRequireArgs(3);
moduleBaseRequireNumber(0); moduleBaseRequireNumber(1); moduleBaseRequireNumber(2);
MAP.chunkTileWidth = (uint16_t)moduleBaseArgInt(0);
MAP.chunkTileHeight = (uint16_t)moduleBaseArgInt(1);
MAP.chunkTileDepth = (uint16_t)moduleBaseArgInt(2);
return jerry_undefined();
}
moduleBaseFunction(moduleMapSetPosition) {
moduleBaseRequireArgs(3);
moduleBaseRequireNumber(0); moduleBaseRequireNumber(1); moduleBaseRequireNumber(2);
tilepos_t pos = {
.x = (tileunit_t)moduleBaseArgInt(0),
.y = (tileunit_t)moduleBaseArgInt(1),
.z = (tileunit_t)moduleBaseArgInt(2),
};
errorret_t err = mapPositionSet(pos);
if(err.code != ERROR_OK) return moduleBaseThrow("Map.setPosition: failed");
return jerry_undefined();
}
static void moduleMapReset(void) {
if(MAP.scriptRef != MAP_SCRIPT_REF_NONE) {
jerry_value_free(MAP.scriptRef);
MAP.scriptRef = MAP_SCRIPT_REF_NONE;
}
jerry_value_t global = jerry_current_realm();
jerry_value_t key = jerry_string_sz("module");
jerry_value_t undef = jerry_undefined();
jerry_object_set(global, key, undef);
jerry_value_free(undef);
jerry_value_free(key);
jerry_value_free(global);
}
static errorret_t moduleMapCall(const char_t *method) {
assertStrLenMin(method, 1, "Method name cannot be empty");
if(MAP.scriptRef == MAP_SCRIPT_REF_NONE) errorOk();
jerry_value_t key = jerry_string_sz(method);
jerry_value_t fn = jerry_object_get(MAP.scriptRef, key);
jerry_value_free(key);
if(!jerry_value_is_function(fn)) {
jerry_value_free(fn);
errorOk();
}
jerry_value_t result = jerry_call(fn, MAP.scriptRef, NULL, 0);
jerry_value_free(fn);
if(jerry_value_is_exception(result)) {
char_t errMsg[512];
moduleBaseExceptionMessage(result, errMsg, sizeof(errMsg));
jerry_value_free(result);
errorThrow("Map:%s failed: %s", method, errMsg);
}
jerry_value_free(result);
errorOk();
}
static void moduleMap(void) {
moduleMapChunk();
scriptProtoInit(
&MODULE_MAP_PROTO,
"Map",
sizeof(uint8_t),
moduleMapDefaultConstructor
);
scriptProtoDefineFunc(&MODULE_MAP_PROTO, "update", moduleMapDefaultUpdate);
scriptProtoDefineFunc(&MODULE_MAP_PROTO, "dispose", moduleMapDefaultDispose);
scriptProtoDefineStaticFunc(&MODULE_MAP_PROTO, "load", moduleMapLoad);
scriptProtoDefineStaticFunc(&MODULE_MAP_PROTO, "dispose", moduleMapDispose);
scriptProtoDefineStaticFunc(&MODULE_MAP_PROTO, "setChunkSize", moduleMapSetChunkSize);
scriptProtoDefineStaticFunc(&MODULE_MAP_PROTO, "setPosition", moduleMapSetPosition);
scriptProtoDefineStaticProp(
&MODULE_MAP_PROTO, "isLoaded", moduleMapIsLoaded, NULL
);
}
@@ -0,0 +1,34 @@
/**
* 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 "overworld/mapchunk.h"
static scriptproto_t MODULE_MAP_CHUNK_PROTO;
moduleBaseFunction(moduleMapChunkDefaultConstructor) {
return jerry_undefined();
}
moduleBaseFunction(moduleMapChunkDefaultDispose) {
return jerry_undefined();
}
static void moduleMapChunk(void) {
scriptProtoInit(
&MODULE_MAP_CHUNK_PROTO,
"MapChunk",
sizeof(uint8_t),
moduleMapChunkDefaultConstructor
);
scriptProtoDefineFunc(
&MODULE_MAP_CHUNK_PROTO, "dispose", moduleMapChunkDefaultDispose
);
}
+15 -30
View File
@@ -22,58 +22,43 @@ moduleBaseFunction(moduleSaveGetCount) {
// Static Methods // Static Methods
moduleBaseFunction(moduleSaveLoad) { moduleBaseFunction(moduleSaveLoad) {
if(argc < 1) return moduleBaseThrow("Save.load: expected (slot)"); moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
moduleBaseRequireNumber(0); const uint8_t slot = (uint8_t)moduleBaseArgInt(0);
const uint8_t slot = (uint8_t)jerry_value_as_number(args[0]); if(slot >= SAVE_FILE_COUNT_MAX) return moduleBaseThrow("Save.load: slot out of range");
if(slot >= SAVE_FILE_COUNT_MAX) {
return moduleBaseThrow("Save.load: slot out of range");
}
errorret_t err = saveLoad(slot); errorret_t err = saveLoad(slot);
if(err.code != ERROR_OK) return moduleBaseThrowError(err); if(err.code != ERROR_OK) return moduleBaseThrowError(err);
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleSaveWrite) { moduleBaseFunction(moduleSaveWrite) {
if(argc < 1) return moduleBaseThrow("Save.write: expected (slot)"); moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
moduleBaseRequireNumber(0); const uint8_t slot = (uint8_t)moduleBaseArgInt(0);
const uint8_t slot = (uint8_t)jerry_value_as_number(args[0]); if(slot >= SAVE_FILE_COUNT_MAX) return moduleBaseThrow("Save.write: slot out of range");
if(slot >= SAVE_FILE_COUNT_MAX) {
return moduleBaseThrow("Save.write: slot out of range");
}
errorret_t err = saveWrite(slot); errorret_t err = saveWrite(slot);
if(err.code != ERROR_OK) return moduleBaseThrowError(err); if(err.code != ERROR_OK) return moduleBaseThrowError(err);
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleSaveDelete) { moduleBaseFunction(moduleSaveDelete) {
if(argc < 1) return moduleBaseThrow("Save.delete: expected (slot)"); moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
moduleBaseRequireNumber(0); const uint8_t slot = (uint8_t)moduleBaseArgInt(0);
const uint8_t slot = (uint8_t)jerry_value_as_number(args[0]); if(slot >= SAVE_FILE_COUNT_MAX) return moduleBaseThrow("Save.delete: slot out of range");
if(slot >= SAVE_FILE_COUNT_MAX) {
return moduleBaseThrow("Save.delete: slot out of range");
}
errorret_t err = saveDelete(slot); errorret_t err = saveDelete(slot);
if(err.code != ERROR_OK) return moduleBaseThrowError(err); if(err.code != ERROR_OK) return moduleBaseThrowError(err);
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleSaveExists) { moduleBaseFunction(moduleSaveExists) {
if(argc < 1) return moduleBaseThrow("Save.exists: expected (slot)"); moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
moduleBaseRequireNumber(0); const uint8_t slot = (uint8_t)moduleBaseArgInt(0);
const uint8_t slot = (uint8_t)jerry_value_as_number(args[0]); if(slot >= SAVE_FILE_COUNT_MAX) return moduleBaseThrow("Save.exists: slot out of range");
if(slot >= SAVE_FILE_COUNT_MAX) {
return moduleBaseThrow("Save.exists: slot out of range");
}
return jerry_boolean(saveExists(slot)); return jerry_boolean(saveExists(slot));
} }
moduleBaseFunction(moduleSaveGet) { moduleBaseFunction(moduleSaveGet) {
if(argc < 1) return moduleBaseThrow("Save.get: expected (slot)"); moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
moduleBaseRequireNumber(0); const uint8_t slot = (uint8_t)moduleBaseArgInt(0);
const uint8_t slot = (uint8_t)jerry_value_as_number(args[0]); if(slot >= SAVE_FILE_COUNT_MAX) return moduleBaseThrow("Save.get: slot out of range");
if(slot >= SAVE_FILE_COUNT_MAX) {
return moduleBaseThrow("Save.get: slot out of range");
}
return moduleSaveSlotCreate(slot); return moduleSaveSlotCreate(slot);
} }
+6 -12
View File
@@ -27,44 +27,38 @@ static inline saveslotscript_t * moduleSaveSlotGet(
// Properties // Properties
moduleBaseFunction(moduleSaveSlotGetSlot) { moduleBaseFunction(moduleSaveSlotGetSlot) {
saveslotscript_t *s = moduleSaveSlotGet(callInfo); moduleBaseGetOrReturn(saveslotscript_t, s, moduleSaveSlotGet);
if(!s) return jerry_undefined();
return jerry_number((double)s->slot); return jerry_number((double)s->slot);
} }
moduleBaseFunction(moduleSaveSlotGetExists) { moduleBaseFunction(moduleSaveSlotGetExists) {
saveslotscript_t *s = moduleSaveSlotGet(callInfo); moduleBaseGetOrReturn(saveslotscript_t, s, moduleSaveSlotGet);
if(!s) return jerry_boolean(false);
return jerry_boolean(saveExists(s->slot)); return jerry_boolean(saveExists(s->slot));
} }
moduleBaseFunction(moduleSaveSlotGetVersion) { moduleBaseFunction(moduleSaveSlotGetVersion) {
saveslotscript_t *s = moduleSaveSlotGet(callInfo); moduleBaseGetOrReturn(saveslotscript_t, s, moduleSaveSlotGet);
if(!s) return jerry_undefined();
return jerry_number((double)saveGet(s->slot)->version); return jerry_number((double)saveGet(s->slot)->version);
} }
// Methods // Methods
moduleBaseFunction(moduleSaveSlotLoad) { moduleBaseFunction(moduleSaveSlotLoad) {
saveslotscript_t *s = moduleSaveSlotGet(callInfo); moduleBaseGetOrReturn(saveslotscript_t, s, moduleSaveSlotGet);
if(!s) return jerry_undefined();
errorret_t err = saveLoad(s->slot); errorret_t err = saveLoad(s->slot);
if(err.code != ERROR_OK) return moduleBaseThrowError(err); if(err.code != ERROR_OK) return moduleBaseThrowError(err);
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleSaveSlotWrite) { moduleBaseFunction(moduleSaveSlotWrite) {
saveslotscript_t *s = moduleSaveSlotGet(callInfo); moduleBaseGetOrReturn(saveslotscript_t, s, moduleSaveSlotGet);
if(!s) return jerry_undefined();
errorret_t err = saveWrite(s->slot); errorret_t err = saveWrite(s->slot);
if(err.code != ERROR_OK) return moduleBaseThrowError(err); if(err.code != ERROR_OK) return moduleBaseThrowError(err);
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleSaveSlotDelete) { moduleBaseFunction(moduleSaveSlotDelete) {
saveslotscript_t *s = moduleSaveSlotGet(callInfo); moduleBaseGetOrReturn(saveslotscript_t, s, moduleSaveSlotGet);
if(!s) return jerry_undefined();
errorret_t err = saveDelete(s->slot); errorret_t err = saveDelete(s->slot);
if(err.code != ERROR_OK) return moduleBaseThrowError(err); if(err.code != ERROR_OK) return moduleBaseThrowError(err);
return jerry_undefined(); return jerry_undefined();
+1 -2
View File
@@ -25,8 +25,7 @@ moduleBaseFunction(moduleSceneDefaultConstructor) {
} }
moduleBaseFunction(moduleSceneSet) { moduleBaseFunction(moduleSceneSet) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); moduleBaseRequireArgs(1); moduleBaseRequireString(0);
moduleBaseRequireString(0);
char_t name[ASSET_FILE_NAME_MAX]; char_t name[ASSET_FILE_NAME_MAX];
moduleBaseToString(args[0], name, sizeof(name)); moduleBaseToString(args[0], name, sizeof(name));
@@ -10,9 +10,7 @@
#include "script/scriptmanager.h" #include "script/scriptmanager.h"
moduleBaseFunction(moduleIncludeInclude) { moduleBaseFunction(moduleIncludeInclude) {
if(argc < 1 || !jerry_value_is_string(args[0])) { moduleBaseRequireArgs(1); moduleBaseRequireString(0);
return moduleBaseThrow("Expected string filename");
}
char_t filename[1024]; char_t filename[1024];
moduleBaseToString(args[0], filename, sizeof(filename)); moduleBaseToString(args[0], filename, sizeof(filename));
+5 -8
View File
@@ -13,9 +13,8 @@
static scriptproto_t MODULE_STORY_FLAG_PROTO; static scriptproto_t MODULE_STORY_FLAG_PROTO;
moduleBaseFunction(moduleStoryFlagGet) { moduleBaseFunction(moduleStoryFlagGet) {
if(argc < 1) return moduleBaseThrow("Expected flagId"); moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
moduleBaseRequireNumber(0); storyflag_t flag = (storyflag_t)moduleBaseArgInt(0);
storyflag_t flag = (storyflag_t)jerry_value_as_number(args[0]);
if(flag <= STORY_FLAG_NULL || flag >= STORY_FLAG_COUNT) { if(flag <= STORY_FLAG_NULL || flag >= STORY_FLAG_COUNT) {
return moduleBaseThrow("StoryFlag.get: invalid flag ID"); return moduleBaseThrow("StoryFlag.get: invalid flag ID");
} }
@@ -23,14 +22,12 @@ moduleBaseFunction(moduleStoryFlagGet) {
} }
moduleBaseFunction(moduleStoryFlagSet) { moduleBaseFunction(moduleStoryFlagSet) {
if(argc < 2) return moduleBaseThrow("Expected (flagId, value)"); moduleBaseRequireArgs(2); moduleBaseRequireNumber(0); moduleBaseRequireNumber(1);
moduleBaseRequireNumber(0); storyflag_t flag = (storyflag_t)moduleBaseArgInt(0);
moduleBaseRequireNumber(1);
storyflag_t flag = (storyflag_t)jerry_value_as_number(args[0]);
if(flag <= STORY_FLAG_NULL || flag >= STORY_FLAG_COUNT) { if(flag <= STORY_FLAG_NULL || flag >= STORY_FLAG_COUNT) {
return moduleBaseThrow("StoryFlag.set: invalid flag ID"); return moduleBaseThrow("StoryFlag.set: invalid flag ID");
} }
storyFlagSet(flag, (storyflagvalue_t)jerry_value_as_number(args[1])); storyFlagSet(flag, (storyflagvalue_t)moduleBaseArgInt(1));
return jerry_undefined(); return jerry_undefined();
} }
+16 -65
View File
@@ -9,7 +9,6 @@
#include "script/module/display/modulecolor.h" #include "script/module/display/modulecolor.h"
#include "script/module/event/moduleEvent.h" #include "script/module/event/moduleEvent.h"
#include "ui/uifullbox.h" #include "ui/uifullbox.h"
#include "animation/easing.h"
static scriptproto_t MODULE_FULLBOX_UNDER_PROTO; static scriptproto_t MODULE_FULLBOX_UNDER_PROTO;
static scriptproto_t MODULE_FULLBOX_OVER_PROTO; static scriptproto_t MODULE_FULLBOX_OVER_PROTO;
@@ -18,65 +17,29 @@ static scriptproto_t MODULE_FULLBOX_OVER_PROTO;
static jerry_value_t MODULE_FULLBOX_UNDER_CALLBACK = 0; static jerry_value_t MODULE_FULLBOX_UNDER_CALLBACK = 0;
static jerry_value_t MODULE_FULLBOX_OVER_CALLBACK = 0; static jerry_value_t MODULE_FULLBOX_OVER_CALLBACK = 0;
static easingtype_t moduleFullboxReadEasing(jerry_value_t val) {
if(jerry_value_is_number(val)) {
return (easingtype_t)(int32_t)jerry_value_as_number(val);
}
jerry_value_t typeKey = jerry_string_sz("type");
jerry_value_t typeVal = jerry_object_get(val, typeKey);
jerry_value_free(typeKey);
easingtype_t type = EASING_LINEAR;
if(jerry_value_is_number(typeVal)) {
type = (easingtype_t)(int32_t)jerry_value_as_number(typeVal);
}
jerry_value_free(typeVal);
return type;
}
moduleBaseFunction(moduleFullboxUnderTransition) { moduleBaseFunction(moduleFullboxUnderTransition) {
if(argc < 4) { moduleBaseRequireArgs(4); moduleBaseRequireNumber(2);
return moduleBaseThrow("FullboxUnder.transition: expected 4 arguments");
}
color_t *from = (color_t*)scriptProtoGetValue(&MODULE_COLOR_PROTO, args[0]); color_t *from = (color_t*)scriptProtoGetValue(&MODULE_COLOR_PROTO, args[0]);
if(!from) return moduleBaseThrow("FullboxUnder.transition: arg 0 must be a Color"); if(!from) return moduleBaseThrow("FullboxUnder.transition: arg 0 must be a Color");
color_t *to = (color_t*)scriptProtoGetValue(&MODULE_COLOR_PROTO, args[1]); color_t *to = (color_t*)scriptProtoGetValue(&MODULE_COLOR_PROTO, args[1]);
if(!to) return moduleBaseThrow("FullboxUnder.transition: arg 1 must be a Color"); if(!to) return moduleBaseThrow("FullboxUnder.transition: arg 1 must be a Color");
if(!jerry_value_is_number(args[2])) {
return moduleBaseThrow("FullboxUnder.transition: arg 2 must be a number");
}
uiFullboxTransition( uiFullboxTransition(
&UI_FULLBOX_UNDER, &UI_FULLBOX_UNDER, *from, *to,
*from, *to, moduleBaseArgFloat(2), moduleReadEasing(args[3])
(float_t)jerry_value_as_number(args[2]),
moduleFullboxReadEasing(args[3])
); );
return jerry_undefined(); return jerry_undefined();
} }
moduleBaseFunction(moduleFullboxOverTransition) { moduleBaseFunction(moduleFullboxOverTransition) {
if(argc < 4) { moduleBaseRequireArgs(4); moduleBaseRequireNumber(2);
return moduleBaseThrow("FullboxOver.transition: expected 4 arguments");
}
color_t *from = (color_t*)scriptProtoGetValue(&MODULE_COLOR_PROTO, args[0]); color_t *from = (color_t*)scriptProtoGetValue(&MODULE_COLOR_PROTO, args[0]);
if(!from) return moduleBaseThrow("FullboxOver.transition: arg 0 must be a Color"); if(!from) return moduleBaseThrow("FullboxOver.transition: arg 0 must be a Color");
color_t *to = (color_t*)scriptProtoGetValue(&MODULE_COLOR_PROTO, args[1]); color_t *to = (color_t*)scriptProtoGetValue(&MODULE_COLOR_PROTO, args[1]);
if(!to) return moduleBaseThrow("FullboxOver.transition: arg 1 must be a Color"); if(!to) return moduleBaseThrow("FullboxOver.transition: arg 1 must be a Color");
if(!jerry_value_is_number(args[2])) {
return moduleBaseThrow("FullboxOver.transition: arg 2 must be a number");
}
uiFullboxTransition( uiFullboxTransition(
&UI_FULLBOX_OVER, &UI_FULLBOX_OVER, *from, *to,
*from, *to, moduleBaseArgFloat(2), moduleReadEasing(args[3])
(float_t)jerry_value_as_number(args[2]),
moduleFullboxReadEasing(args[3])
); );
return jerry_undefined(); return jerry_undefined();
} }
@@ -89,17 +52,11 @@ moduleBaseFunction(moduleFullboxUnderGetOnTransitionEnd) {
moduleBaseFunction(moduleFullboxUnderSetOnTransitionEnd) { moduleBaseFunction(moduleFullboxUnderSetOnTransitionEnd) {
(void)callInfo; (void)callInfo;
if(MODULE_FULLBOX_UNDER_CALLBACK) { moduleEventSetCallback(
moduleEventJsUnsubscribe( &MODULE_FULLBOX_UNDER_CALLBACK,
&UI_FULLBOX_UNDER.onTransitionEnd, MODULE_FULLBOX_UNDER_CALLBACK &UI_FULLBOX_UNDER.onTransitionEnd,
); argc >= 1 ? args[0] : jerry_undefined()
jerry_value_free(MODULE_FULLBOX_UNDER_CALLBACK); );
MODULE_FULLBOX_UNDER_CALLBACK = 0;
}
if(argc >= 1 && jerry_value_is_function(args[0])) {
MODULE_FULLBOX_UNDER_CALLBACK = jerry_value_copy(args[0]);
moduleEventJsSubscribe(&UI_FULLBOX_UNDER.onTransitionEnd, args[0]);
}
return jerry_undefined(); return jerry_undefined();
} }
@@ -111,17 +68,11 @@ moduleBaseFunction(moduleFullboxOverGetOnTransitionEnd) {
moduleBaseFunction(moduleFullboxOverSetOnTransitionEnd) { moduleBaseFunction(moduleFullboxOverSetOnTransitionEnd) {
(void)callInfo; (void)callInfo;
if(MODULE_FULLBOX_OVER_CALLBACK) { moduleEventSetCallback(
moduleEventJsUnsubscribe( &MODULE_FULLBOX_OVER_CALLBACK,
&UI_FULLBOX_OVER.onTransitionEnd, MODULE_FULLBOX_OVER_CALLBACK &UI_FULLBOX_OVER.onTransitionEnd,
); argc >= 1 ? args[0] : jerry_undefined()
jerry_value_free(MODULE_FULLBOX_OVER_CALLBACK); );
MODULE_FULLBOX_OVER_CALLBACK = 0;
}
if(argc >= 1 && jerry_value_is_function(args[0])) {
MODULE_FULLBOX_OVER_CALLBACK = jerry_value_copy(args[0]);
moduleEventJsSubscribe(&UI_FULLBOX_OVER.onTransitionEnd, args[0]);
}
return jerry_undefined(); return jerry_undefined();
} }
+15 -35
View File
@@ -15,9 +15,7 @@ static jerry_value_t MODULE_TEXTBOX_LAST_PAGE_CALLBACK = 0;
static scriptproto_t MODULE_TEXTBOX_PROTO; static scriptproto_t MODULE_TEXTBOX_PROTO;
moduleBaseFunction(moduleTextboxSetText) { moduleBaseFunction(moduleTextboxSetText) {
if(argc < 1 || !jerry_value_is_string(args[0])) { moduleBaseRequireArgs(1); moduleBaseRequireString(0);
return moduleBaseThrow("Textbox.setText: expected string");
}
char_t buf[UI_TEXTBOX_TEXT_MAX]; char_t buf[UI_TEXTBOX_TEXT_MAX];
moduleBaseToString(args[0], buf, sizeof(buf)); moduleBaseToString(args[0], buf, sizeof(buf));
uiTextboxSetText(buf); uiTextboxSetText(buf);
@@ -44,10 +42,8 @@ moduleBaseFunction(moduleTextboxGetScroll) {
} }
moduleBaseFunction(moduleTextboxSetScroll) { moduleBaseFunction(moduleTextboxSetScroll) {
if(argc < 1 || !jerry_value_is_number(args[0])) { moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
return moduleBaseThrow("Textbox.scroll: expected number"); UI_TEXTBOX.scroll = moduleBaseArgInt(0);
}
UI_TEXTBOX.scroll = (int32_t)jerry_value_as_number(args[0]);
return jerry_undefined(); return jerry_undefined();
} }
@@ -56,12 +52,8 @@ moduleBaseFunction(moduleTextboxGetAdvanceAction) {
} }
moduleBaseFunction(moduleTextboxSetAdvanceAction) { moduleBaseFunction(moduleTextboxSetAdvanceAction) {
if(argc < 1 || !jerry_value_is_number(args[0])) { moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
return moduleBaseThrow("Textbox.advanceAction: expected number"); UI_TEXTBOX.advanceAction = (inputaction_t)moduleBaseArgInt(0);
}
UI_TEXTBOX.advanceAction = (inputaction_t)(
(int32_t)jerry_value_as_number(args[0])
);
return jerry_undefined(); return jerry_undefined();
} }
@@ -89,17 +81,11 @@ moduleBaseFunction(moduleTextboxGetOnPageComplete) {
moduleBaseFunction(moduleTextboxSetOnPageComplete) { moduleBaseFunction(moduleTextboxSetOnPageComplete) {
(void)callInfo; (void)callInfo;
if(MODULE_TEXTBOX_PAGE_COMPLETE_CALLBACK) { moduleEventSetCallback(
moduleEventJsUnsubscribe( &MODULE_TEXTBOX_PAGE_COMPLETE_CALLBACK,
&UI_TEXTBOX.onPageComplete, MODULE_TEXTBOX_PAGE_COMPLETE_CALLBACK &UI_TEXTBOX.onPageComplete,
); argc >= 1 ? args[0] : jerry_undefined()
jerry_value_free(MODULE_TEXTBOX_PAGE_COMPLETE_CALLBACK); );
MODULE_TEXTBOX_PAGE_COMPLETE_CALLBACK = 0;
}
if(argc >= 1 && jerry_value_is_function(args[0])) {
MODULE_TEXTBOX_PAGE_COMPLETE_CALLBACK = jerry_value_copy(args[0]);
moduleEventJsSubscribe(&UI_TEXTBOX.onPageComplete, args[0]);
}
return jerry_undefined(); return jerry_undefined();
} }
@@ -111,17 +97,11 @@ moduleBaseFunction(moduleTextboxGetOnLastPage) {
moduleBaseFunction(moduleTextboxSetOnLastPage) { moduleBaseFunction(moduleTextboxSetOnLastPage) {
(void)callInfo; (void)callInfo;
if(MODULE_TEXTBOX_LAST_PAGE_CALLBACK) { moduleEventSetCallback(
moduleEventJsUnsubscribe( &MODULE_TEXTBOX_LAST_PAGE_CALLBACK,
&UI_TEXTBOX.onLastPage, MODULE_TEXTBOX_LAST_PAGE_CALLBACK &UI_TEXTBOX.onLastPage,
); argc >= 1 ? args[0] : jerry_undefined()
jerry_value_free(MODULE_TEXTBOX_LAST_PAGE_CALLBACK); );
MODULE_TEXTBOX_LAST_PAGE_CALLBACK = 0;
}
if(argc >= 1 && jerry_value_is_function(args[0])) {
MODULE_TEXTBOX_LAST_PAGE_CALLBACK = jerry_value_copy(args[0]);
moduleEventJsSubscribe(&UI_TEXTBOX.onLastPage, args[0]);
}
return jerry_undefined(); return jerry_undefined();
} }