Script stuff
This commit is contained in:
@@ -74,6 +74,7 @@ errorret_t engineUpdate(void) {
|
||||
consoleUpdate();
|
||||
|
||||
errorChain(gameUpdate());
|
||||
errorChain(scriptManagerCallGlobal("update"));
|
||||
errorChain(sceneUpdate());
|
||||
errorChain(assetUpdate());
|
||||
errorChain(uiUpdate());
|
||||
|
||||
@@ -80,6 +80,32 @@ void entityRenderableSetColor(
|
||||
r->data.material.material.unlit.color = color;
|
||||
}
|
||||
|
||||
void entityRenderableSetMesh(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const uint8_t slot,
|
||||
mesh_t *mesh
|
||||
) {
|
||||
assertNotNull(mesh, "Mesh cannot be null");
|
||||
assertTrue(slot < ENTITY_RENDERABLE_MESHES_MAX, "Mesh slot out of bounds");
|
||||
|
||||
entityrenderable_t *r = componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
assertTrue(
|
||||
r->type == ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL,
|
||||
"Renderable must be ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL to set a mesh"
|
||||
);
|
||||
|
||||
r->data.material.meshes[slot] = mesh;
|
||||
r->data.material.meshOffsets[slot] = 0;
|
||||
r->data.material.meshCounts[slot] = -1;
|
||||
if(slot >= r->data.material.meshCount) {
|
||||
r->data.material.meshCount = slot + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void entityRenderableSetDraw(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
|
||||
@@ -142,6 +142,26 @@ void entityRenderableSetColor(
|
||||
const color_t color
|
||||
);
|
||||
|
||||
/**
|
||||
* Sets one of the material renderable's meshes, drawn in full (no offset/
|
||||
* count override). Only meaningful when the renderable is (or defaults
|
||||
* to) ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL -- asserts otherwise.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity to configure.
|
||||
* @param componentId The renderable component.
|
||||
* @param slot Index into the material's meshes array (0 to
|
||||
* ENTITY_RENDERABLE_MESHES_MAX - 1).
|
||||
* @param mesh The mesh to draw in that slot.
|
||||
*/
|
||||
void entityRenderableSetMesh(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const uint8_t slot,
|
||||
mesh_t *mesh
|
||||
);
|
||||
|
||||
/**
|
||||
* Sets the draw callback, switching the type to
|
||||
* ENTITY_RENDERABLE_TYPE_CUSTOM.
|
||||
|
||||
@@ -10,3 +10,6 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
|
||||
add_subdirectory(entity)
|
||||
add_subdirectory(scene)
|
||||
add_subdirectory(require)
|
||||
add_subdirectory(display)
|
||||
add_subdirectory(time)
|
||||
|
||||
@@ -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
|
||||
modulemesh.c
|
||||
)
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "modulemesh.h"
|
||||
#include "script/module/modulebase.h"
|
||||
#include "display/mesh/cube.h"
|
||||
#include "display/mesh/plane.h"
|
||||
#include "display/mesh/sphere.h"
|
||||
#include "display/mesh/capsule.h"
|
||||
#include "display/mesh/quad.h"
|
||||
#include "display/mesh/triprism.h"
|
||||
|
||||
void moduleMeshInit(void) {
|
||||
moduleBaseSetWrappedPointer("MESH_CUBE", &CUBE_MESH_SIMPLE);
|
||||
moduleBaseSetWrappedPointer("MESH_PLANE", &PLANE_MESH_SIMPLE);
|
||||
moduleBaseSetWrappedPointer("MESH_SPHERE", &SPHERE_MESH_SIMPLE);
|
||||
moduleBaseSetWrappedPointer("MESH_CAPSULE", &CAPSULE_MESH_SIMPLE);
|
||||
moduleBaseSetWrappedPointer("MESH_TRIPRISM", &TRIPRISM_MESH_SIMPLE);
|
||||
moduleBaseSetWrappedPointer("MESH_QUAD", &QUAD_MESH_SIMPLE);
|
||||
}
|
||||
|
||||
void moduleMeshDispose(void) {
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* Registers the built-in primitive meshes (MESH_CUBE, MESH_PLANE,
|
||||
* MESH_SPHERE, MESH_CAPSULE, MESH_TRIPRISM, MESH_QUAD) as global,
|
||||
* engine-owned pointer values usable with Renderable.setMesh().
|
||||
*/
|
||||
void moduleMeshInit(void);
|
||||
|
||||
/**
|
||||
* Disposes the mesh module's script resources.
|
||||
*/
|
||||
void moduleMeshDispose(void);
|
||||
@@ -6,4 +6,8 @@
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
modulecomponent.c
|
||||
modulecomponentlist.c
|
||||
)
|
||||
|
||||
add_subdirectory(display)
|
||||
add_subdirectory(physics)
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# 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
|
||||
modulepositioncomponent.c
|
||||
modulerenderablecomponent.c
|
||||
)
|
||||
@@ -0,0 +1,150 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "modulepositioncomponent.h"
|
||||
#include "script/module/modulebase.h"
|
||||
#include "entity/component/display/entityposition.h"
|
||||
#include "entity/component.h"
|
||||
#include "util/string.h"
|
||||
|
||||
scriptproto_t MODULE_POSITION_PROTO;
|
||||
|
||||
moduleBaseFunction(modulePositionGetType) {
|
||||
moduleBaseGetOrReturn(modulecomponenthandle_t, h, moduleEntityPositionGet);
|
||||
return jerry_number(h->type);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionGetEntityId) {
|
||||
moduleBaseGetOrReturn(modulecomponenthandle_t, h, moduleEntityPositionGet);
|
||||
return jerry_number(h->entityId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionDisposeMethod) {
|
||||
moduleBaseGetOrReturn(modulecomponenthandle_t, h, moduleEntityPositionGet);
|
||||
componentDispose(h->mgr, h->entityId, h->componentId);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionToString) {
|
||||
modulecomponenthandle_t *h = moduleEntityPositionGet(callInfo);
|
||||
if(!h) return jerry_string_sz("Position(?)");
|
||||
|
||||
char_t buf[32];
|
||||
stringFormat(buf, sizeof(buf), "Position(entityId=%d)", h->entityId);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionSetLocalPosition) {
|
||||
moduleBaseRequireArgs(3);
|
||||
moduleBaseRequireNumber(0); moduleBaseRequireNumber(1);
|
||||
moduleBaseRequireNumber(2);
|
||||
moduleBaseGetOrReturn(modulecomponenthandle_t, h, moduleEntityPositionGet);
|
||||
|
||||
entityPositionSetLocalPosition(h->mgr, h->entityId, h->componentId, (vec3){
|
||||
moduleBaseArgFloat(0), moduleBaseArgFloat(1), moduleBaseArgFloat(2)
|
||||
});
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionGetLocalPosition) {
|
||||
moduleBaseGetOrReturn(modulecomponenthandle_t, h, moduleEntityPositionGet);
|
||||
|
||||
vec3 pos;
|
||||
entityPositionGetLocalPosition(h->mgr, h->entityId, h->componentId, pos);
|
||||
return moduleBaseVec3ToObject(pos);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionSetLocalScale) {
|
||||
moduleBaseRequireArgs(3);
|
||||
moduleBaseRequireNumber(0); moduleBaseRequireNumber(1);
|
||||
moduleBaseRequireNumber(2);
|
||||
moduleBaseGetOrReturn(modulecomponenthandle_t, h, moduleEntityPositionGet);
|
||||
|
||||
entityPositionSetLocalScale(h->mgr, h->entityId, h->componentId, (vec3){
|
||||
moduleBaseArgFloat(0), moduleBaseArgFloat(1), moduleBaseArgFloat(2)
|
||||
});
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionGetLocalScale) {
|
||||
moduleBaseGetOrReturn(modulecomponenthandle_t, h, moduleEntityPositionGet);
|
||||
|
||||
vec3 scale;
|
||||
entityPositionGetLocalScale(h->mgr, h->entityId, h->componentId, scale);
|
||||
return moduleBaseVec3ToObject(scale);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionLookAt) {
|
||||
moduleBaseRequireArgs(9);
|
||||
for(jerry_length_t i = 0; i < 9; i++) moduleBaseRequireNumber(i);
|
||||
moduleBaseGetOrReturn(modulecomponenthandle_t, h, moduleEntityPositionGet);
|
||||
|
||||
entityPositionLookAt(
|
||||
h->mgr, h->entityId, h->componentId,
|
||||
(vec3){
|
||||
moduleBaseArgFloat(0), moduleBaseArgFloat(1), moduleBaseArgFloat(2)
|
||||
},
|
||||
(vec3){
|
||||
moduleBaseArgFloat(3), moduleBaseArgFloat(4), moduleBaseArgFloat(5)
|
||||
},
|
||||
(vec3){
|
||||
moduleBaseArgFloat(6), moduleBaseArgFloat(7), moduleBaseArgFloat(8)
|
||||
}
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
void moduleEntityPositionInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_POSITION_PROTO, "Position", sizeof(modulecomponenthandle_t), NULL
|
||||
);
|
||||
|
||||
scriptProtoDefineToString(&MODULE_POSITION_PROTO, modulePositionToString);
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_POSITION_PROTO, "type", modulePositionGetType, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_POSITION_PROTO, "entityId", modulePositionGetEntityId, NULL
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_POSITION_PROTO, "dispose", modulePositionDisposeMethod
|
||||
);
|
||||
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_POSITION_PROTO, "setLocalPosition", modulePositionSetLocalPosition
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_POSITION_PROTO, "getLocalPosition", modulePositionGetLocalPosition
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_POSITION_PROTO, "setLocalScale", modulePositionSetLocalScale
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_POSITION_PROTO, "getLocalScale", modulePositionGetLocalScale
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_POSITION_PROTO, "lookAt", modulePositionLookAt
|
||||
);
|
||||
}
|
||||
|
||||
void moduleEntityPositionDispose(void) {
|
||||
}
|
||||
|
||||
jerry_value_t moduleEntityPositionCreate(
|
||||
const modulecomponenthandle_t *handle
|
||||
) {
|
||||
return scriptProtoCreateValue(&MODULE_POSITION_PROTO, handle);
|
||||
}
|
||||
|
||||
modulecomponenthandle_t *moduleEntityPositionGet(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (modulecomponenthandle_t *)scriptProtoGetValue(
|
||||
&MODULE_POSITION_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/scriptproto.h"
|
||||
#include "script/module/entity/component/modulecomponent.h"
|
||||
#include <jerryscript.h>
|
||||
|
||||
extern scriptproto_t MODULE_POSITION_PROTO;
|
||||
|
||||
/**
|
||||
* Registers the Position class: a typed wrapper over COMPONENT_TYPE_
|
||||
* POSITION. Has no constructor -- instances are only ever created via
|
||||
* moduleEntityPositionCreate(), e.g. from Entity.add()/getComponent().
|
||||
*/
|
||||
void moduleEntityPositionInit(void);
|
||||
|
||||
/**
|
||||
* Disposes the Position class's script resources.
|
||||
*/
|
||||
void moduleEntityPositionDispose(void);
|
||||
|
||||
/**
|
||||
* Wraps a component handle as a new JS Position instance.
|
||||
*
|
||||
* @param handle The handle to copy into the new instance.
|
||||
* @return The new JS object.
|
||||
*/
|
||||
jerry_value_t moduleEntityPositionCreate(
|
||||
const modulecomponenthandle_t *handle
|
||||
);
|
||||
|
||||
/**
|
||||
* Internal. Gets the native handle wrapped by a Position instance's
|
||||
* `this` value.
|
||||
*
|
||||
* @param callInfo The JS call info, whose this_value is the instance.
|
||||
* @return The wrapped handle, or NULL if this_value isn't a Position.
|
||||
*/
|
||||
modulecomponenthandle_t *moduleEntityPositionGet(
|
||||
const jerry_call_info_t *callInfo
|
||||
);
|
||||
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "modulerenderablecomponent.h"
|
||||
#include "script/module/modulebase.h"
|
||||
#include "entity/component/display/entityrenderable.h"
|
||||
#include "entity/component.h"
|
||||
#include "display/color.h"
|
||||
#include "util/string.h"
|
||||
|
||||
scriptproto_t MODULE_RENDERABLE_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleRenderableGetType) {
|
||||
moduleBaseGetOrReturn(modulecomponenthandle_t, h, moduleEntityRenderableGet);
|
||||
return jerry_number(h->type);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableGetEntityId) {
|
||||
moduleBaseGetOrReturn(modulecomponenthandle_t, h, moduleEntityRenderableGet);
|
||||
return jerry_number(h->entityId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableDisposeMethod) {
|
||||
moduleBaseGetOrReturn(modulecomponenthandle_t, h, moduleEntityRenderableGet);
|
||||
componentDispose(h->mgr, h->entityId, h->componentId);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableToString) {
|
||||
modulecomponenthandle_t *h = moduleEntityRenderableGet(callInfo);
|
||||
if(!h) return jerry_string_sz("Renderable(?)");
|
||||
|
||||
char_t buf[32];
|
||||
stringFormat(buf, sizeof(buf), "Renderable(entityId=%d)", h->entityId);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableSetColor) {
|
||||
moduleBaseRequireArgs(4);
|
||||
moduleBaseRequireNumber(0); moduleBaseRequireNumber(1);
|
||||
moduleBaseRequireNumber(2); moduleBaseRequireNumber(3);
|
||||
moduleBaseGetOrReturn(modulecomponenthandle_t, h, moduleEntityRenderableGet);
|
||||
|
||||
entityRenderableSetColor(h->mgr, h->entityId, h->componentId, color(
|
||||
(uint8_t)moduleBaseArgInt(0), (uint8_t)moduleBaseArgInt(1),
|
||||
(uint8_t)moduleBaseArgInt(2), (uint8_t)moduleBaseArgInt(3)
|
||||
));
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableSetMesh) {
|
||||
moduleBaseRequireArgs(2); moduleBaseRequireNumber(0);
|
||||
moduleBaseRequireObject(1);
|
||||
moduleBaseGetOrReturn(modulecomponenthandle_t, h, moduleEntityRenderableGet);
|
||||
|
||||
mesh_t *mesh = (mesh_t *)moduleBaseUnwrapPointer(args[1]);
|
||||
if(!mesh) return moduleBaseThrow("Renderable.setMesh: invalid mesh");
|
||||
|
||||
entityRenderableSetMesh(
|
||||
h->mgr, h->entityId, h->componentId, (uint8_t)moduleBaseArgInt(0), mesh
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleRenderableSetPriority) {
|
||||
moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
|
||||
moduleBaseGetOrReturn(modulecomponenthandle_t, h, moduleEntityRenderableGet);
|
||||
|
||||
entityRenderableSetPriority(
|
||||
h->mgr, h->entityId, h->componentId, (int8_t)moduleBaseArgInt(0)
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
void moduleEntityRenderableInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_RENDERABLE_PROTO,
|
||||
"Renderable", sizeof(modulecomponenthandle_t), NULL
|
||||
);
|
||||
|
||||
scriptProtoDefineToString(&MODULE_RENDERABLE_PROTO, moduleRenderableToString);
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_RENDERABLE_PROTO, "type", moduleRenderableGetType, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_RENDERABLE_PROTO, "entityId", moduleRenderableGetEntityId, NULL
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_RENDERABLE_PROTO, "dispose", moduleRenderableDisposeMethod
|
||||
);
|
||||
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_RENDERABLE_PROTO, "setColor", moduleRenderableSetColor
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_RENDERABLE_PROTO, "setMesh", moduleRenderableSetMesh
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_RENDERABLE_PROTO, "setPriority", moduleRenderableSetPriority
|
||||
);
|
||||
}
|
||||
|
||||
void moduleEntityRenderableDispose(void) {
|
||||
}
|
||||
|
||||
jerry_value_t moduleEntityRenderableCreate(
|
||||
const modulecomponenthandle_t *handle
|
||||
) {
|
||||
return scriptProtoCreateValue(&MODULE_RENDERABLE_PROTO, handle);
|
||||
}
|
||||
|
||||
modulecomponenthandle_t *moduleEntityRenderableGet(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (modulecomponenthandle_t *)scriptProtoGetValue(
|
||||
&MODULE_RENDERABLE_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/scriptproto.h"
|
||||
#include "script/module/entity/component/modulecomponent.h"
|
||||
#include <jerryscript.h>
|
||||
|
||||
extern scriptproto_t MODULE_RENDERABLE_PROTO;
|
||||
|
||||
/**
|
||||
* Registers the Renderable class: a typed wrapper over COMPONENT_TYPE_
|
||||
* RENDERABLE. Has no constructor -- instances are only ever created via
|
||||
* moduleEntityRenderableCreate(), e.g. from Entity.add()/getComponent().
|
||||
*/
|
||||
void moduleEntityRenderableInit(void);
|
||||
|
||||
/**
|
||||
* Disposes the Renderable class's script resources.
|
||||
*/
|
||||
void moduleEntityRenderableDispose(void);
|
||||
|
||||
/**
|
||||
* Wraps a component handle as a new JS Renderable instance.
|
||||
*
|
||||
* @param handle The handle to copy into the new instance.
|
||||
* @return The new JS object.
|
||||
*/
|
||||
jerry_value_t moduleEntityRenderableCreate(
|
||||
const modulecomponenthandle_t *handle
|
||||
);
|
||||
|
||||
/**
|
||||
* Internal. Gets the native handle wrapped by a Renderable instance's
|
||||
* `this` value.
|
||||
*
|
||||
* @param callInfo The JS call info, whose this_value is the instance.
|
||||
* @return The wrapped handle, or NULL if this_value isn't a Renderable.
|
||||
*/
|
||||
modulecomponenthandle_t *moduleEntityRenderableGet(
|
||||
const jerry_call_info_t *callInfo
|
||||
);
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "modulecomponentlist.h"
|
||||
#include "script/module/entity/component/display/modulepositioncomponent.h"
|
||||
#include "script/module/entity/component/physics/modulephysicscomponent.h"
|
||||
#include "script/module/entity/component/display/modulerenderablecomponent.h"
|
||||
|
||||
void moduleComponentListInit(void) {
|
||||
moduleEntityPositionInit();
|
||||
moduleEntityPhysicsInit();
|
||||
moduleEntityRenderableInit();
|
||||
}
|
||||
|
||||
void moduleComponentListDispose(void) {
|
||||
moduleEntityRenderableDispose();
|
||||
moduleEntityPhysicsDispose();
|
||||
moduleEntityPositionDispose();
|
||||
}
|
||||
|
||||
jerry_value_t moduleComponentListCreate(
|
||||
const modulecomponenthandle_t *handle
|
||||
) {
|
||||
switch(handle->type) {
|
||||
case COMPONENT_TYPE_POSITION:
|
||||
return moduleEntityPositionCreate(handle);
|
||||
case COMPONENT_TYPE_PHYSICS:
|
||||
return moduleEntityPhysicsCreate(handle);
|
||||
case COMPONENT_TYPE_RENDERABLE:
|
||||
return moduleEntityRenderableCreate(handle);
|
||||
default:
|
||||
return moduleComponentCreate(handle);
|
||||
}
|
||||
}
|
||||
@@ -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/entity/component/modulecomponent.h"
|
||||
#include <jerryscript.h>
|
||||
|
||||
/**
|
||||
* Registers every typed per-component-type JS wrapper module (Position,
|
||||
* Physics, Renderable, ...). Called once by moduleListInit().
|
||||
*/
|
||||
void moduleComponentListInit(void);
|
||||
|
||||
/**
|
||||
* Disposes every typed component wrapper module. Called once by
|
||||
* moduleListDispose().
|
||||
*/
|
||||
void moduleComponentListDispose(void);
|
||||
|
||||
/**
|
||||
* Wraps a component handle using the most specific JS class available
|
||||
* for its type (e.g. Position for COMPONENT_TYPE_POSITION), falling back
|
||||
* to the generic Component wrapper for types with no typed wrapper yet.
|
||||
*
|
||||
* @param handle The handle to wrap.
|
||||
* @return The new JS object.
|
||||
*/
|
||||
jerry_value_t moduleComponentListCreate(
|
||||
const modulecomponenthandle_t *handle
|
||||
);
|
||||
@@ -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
|
||||
modulephysicscomponent.c
|
||||
)
|
||||
@@ -0,0 +1,211 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "modulephysicscomponent.h"
|
||||
#include "script/module/modulebase.h"
|
||||
#include "entity/component/physics/entityphysics.h"
|
||||
#include "entity/component.h"
|
||||
#include "util/string.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
scriptproto_t MODULE_PHYSICS_PROTO;
|
||||
|
||||
moduleBaseFunction(modulePhysicsGetType) {
|
||||
moduleBaseGetOrReturn(modulecomponenthandle_t, h, moduleEntityPhysicsGet);
|
||||
return jerry_number(h->type);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsGetEntityId) {
|
||||
moduleBaseGetOrReturn(modulecomponenthandle_t, h, moduleEntityPhysicsGet);
|
||||
return jerry_number(h->entityId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsDisposeMethod) {
|
||||
moduleBaseGetOrReturn(modulecomponenthandle_t, h, moduleEntityPhysicsGet);
|
||||
componentDispose(h->mgr, h->entityId, h->componentId);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsToString) {
|
||||
modulecomponenthandle_t *h = moduleEntityPhysicsGet(callInfo);
|
||||
if(!h) return jerry_string_sz("Physics(?)");
|
||||
|
||||
char_t buf[32];
|
||||
stringFormat(buf, sizeof(buf), "Physics(entityId=%d)", h->entityId);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsSetBodyType) {
|
||||
moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
|
||||
moduleBaseGetOrReturn(modulecomponenthandle_t, h, moduleEntityPhysicsGet);
|
||||
|
||||
entityPhysicsSetBodyType(
|
||||
h->mgr, h->entityId, h->componentId,
|
||||
(physicsbodytype_t)moduleBaseArgInt(0)
|
||||
);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsGetBodyType) {
|
||||
moduleBaseGetOrReturn(modulecomponenthandle_t, h, moduleEntityPhysicsGet);
|
||||
return jerry_number(
|
||||
entityPhysicsGetBodyType(h->mgr, h->entityId, h->componentId)
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsSetShape) {
|
||||
moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
|
||||
moduleBaseGetOrReturn(modulecomponenthandle_t, h, moduleEntityPhysicsGet);
|
||||
|
||||
physicsshape_t shape;
|
||||
memoryZero(&shape, sizeof(shape));
|
||||
shape.type = (physicshapetype_t)moduleBaseArgInt(0);
|
||||
|
||||
switch(shape.type) {
|
||||
case PHYSICS_SHAPE_CUBE:
|
||||
moduleBaseRequireArgs(4);
|
||||
moduleBaseRequireNumber(1); moduleBaseRequireNumber(2);
|
||||
moduleBaseRequireNumber(3);
|
||||
shape.data.cube.halfExtents[0] = moduleBaseArgFloat(1);
|
||||
shape.data.cube.halfExtents[1] = moduleBaseArgFloat(2);
|
||||
shape.data.cube.halfExtents[2] = moduleBaseArgFloat(3);
|
||||
break;
|
||||
|
||||
case PHYSICS_SHAPE_SPHERE:
|
||||
moduleBaseRequireArgs(2); moduleBaseRequireNumber(1);
|
||||
shape.data.sphere.radius = moduleBaseArgFloat(1);
|
||||
break;
|
||||
|
||||
case PHYSICS_SHAPE_CAPSULE:
|
||||
moduleBaseRequireArgs(3);
|
||||
moduleBaseRequireNumber(1); moduleBaseRequireNumber(2);
|
||||
shape.data.capsule.radius = moduleBaseArgFloat(1);
|
||||
shape.data.capsule.halfHeight = moduleBaseArgFloat(2);
|
||||
break;
|
||||
|
||||
case PHYSICS_SHAPE_PLANE:
|
||||
moduleBaseRequireArgs(5);
|
||||
moduleBaseRequireNumber(1); moduleBaseRequireNumber(2);
|
||||
moduleBaseRequireNumber(3); moduleBaseRequireNumber(4);
|
||||
shape.data.plane.normal[0] = moduleBaseArgFloat(1);
|
||||
shape.data.plane.normal[1] = moduleBaseArgFloat(2);
|
||||
shape.data.plane.normal[2] = moduleBaseArgFloat(3);
|
||||
shape.data.plane.distance = moduleBaseArgFloat(4);
|
||||
break;
|
||||
|
||||
default:
|
||||
return moduleBaseThrow("Physics.setShape: unsupported shape type");
|
||||
}
|
||||
|
||||
entityPhysicsSetShape(h->mgr, h->entityId, h->componentId, shape);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsSetVelocity) {
|
||||
moduleBaseRequireArgs(3);
|
||||
moduleBaseRequireNumber(0); moduleBaseRequireNumber(1);
|
||||
moduleBaseRequireNumber(2);
|
||||
moduleBaseGetOrReturn(modulecomponenthandle_t, h, moduleEntityPhysicsGet);
|
||||
|
||||
entityPhysicsSetVelocity(h->mgr, h->entityId, h->componentId, (vec3){
|
||||
moduleBaseArgFloat(0), moduleBaseArgFloat(1), moduleBaseArgFloat(2)
|
||||
});
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsGetVelocity) {
|
||||
moduleBaseGetOrReturn(modulecomponenthandle_t, h, moduleEntityPhysicsGet);
|
||||
|
||||
vec3 velocity;
|
||||
entityPhysicsGetVelocity(h->mgr, h->entityId, h->componentId, velocity);
|
||||
return moduleBaseVec3ToObject(velocity);
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsApplyImpulse) {
|
||||
moduleBaseRequireArgs(3);
|
||||
moduleBaseRequireNumber(0); moduleBaseRequireNumber(1);
|
||||
moduleBaseRequireNumber(2);
|
||||
moduleBaseGetOrReturn(modulecomponenthandle_t, h, moduleEntityPhysicsGet);
|
||||
|
||||
entityPhysicsApplyImpulse(h->mgr, h->entityId, h->componentId, (vec3){
|
||||
moduleBaseArgFloat(0), moduleBaseArgFloat(1), moduleBaseArgFloat(2)
|
||||
});
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePhysicsIsOnGround) {
|
||||
moduleBaseGetOrReturn(modulecomponenthandle_t, h, moduleEntityPhysicsGet);
|
||||
return jerry_boolean(
|
||||
entityPhysicsIsOnGround(h->mgr, h->entityId, h->componentId)
|
||||
);
|
||||
}
|
||||
|
||||
void moduleEntityPhysicsInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_PHYSICS_PROTO, "Physics", sizeof(modulecomponenthandle_t), NULL
|
||||
);
|
||||
|
||||
scriptProtoDefineToString(&MODULE_PHYSICS_PROTO, modulePhysicsToString);
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_PHYSICS_PROTO, "type", modulePhysicsGetType, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_PHYSICS_PROTO, "entityId", modulePhysicsGetEntityId, NULL
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_PHYSICS_PROTO, "dispose", modulePhysicsDisposeMethod
|
||||
);
|
||||
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_PHYSICS_PROTO, "setBodyType", modulePhysicsSetBodyType
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_PHYSICS_PROTO, "getBodyType", modulePhysicsGetBodyType
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_PHYSICS_PROTO, "setShape", modulePhysicsSetShape
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_PHYSICS_PROTO, "setVelocity", modulePhysicsSetVelocity
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_PHYSICS_PROTO, "getVelocity", modulePhysicsGetVelocity
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_PHYSICS_PROTO, "applyImpulse", modulePhysicsApplyImpulse
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_PHYSICS_PROTO, "isOnGround", modulePhysicsIsOnGround
|
||||
);
|
||||
|
||||
moduleBaseSetInt("PHYSICS_BODY_STATIC", PHYSICS_BODY_STATIC);
|
||||
moduleBaseSetInt("PHYSICS_BODY_DYNAMIC", PHYSICS_BODY_DYNAMIC);
|
||||
moduleBaseSetInt("PHYSICS_BODY_KINEMATIC", PHYSICS_BODY_KINEMATIC);
|
||||
|
||||
moduleBaseSetInt("PHYSICS_SHAPE_CUBE", PHYSICS_SHAPE_CUBE);
|
||||
moduleBaseSetInt("PHYSICS_SHAPE_SPHERE", PHYSICS_SHAPE_SPHERE);
|
||||
moduleBaseSetInt("PHYSICS_SHAPE_CAPSULE", PHYSICS_SHAPE_CAPSULE);
|
||||
moduleBaseSetInt("PHYSICS_SHAPE_PLANE", PHYSICS_SHAPE_PLANE);
|
||||
}
|
||||
|
||||
void moduleEntityPhysicsDispose(void) {
|
||||
}
|
||||
|
||||
jerry_value_t moduleEntityPhysicsCreate(
|
||||
const modulecomponenthandle_t *handle
|
||||
) {
|
||||
return scriptProtoCreateValue(&MODULE_PHYSICS_PROTO, handle);
|
||||
}
|
||||
|
||||
modulecomponenthandle_t *moduleEntityPhysicsGet(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (modulecomponenthandle_t *)scriptProtoGetValue(
|
||||
&MODULE_PHYSICS_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/scriptproto.h"
|
||||
#include "script/module/entity/component/modulecomponent.h"
|
||||
#include <jerryscript.h>
|
||||
|
||||
extern scriptproto_t MODULE_PHYSICS_PROTO;
|
||||
|
||||
/**
|
||||
* Registers the Physics class: a typed wrapper over COMPONENT_TYPE_
|
||||
* PHYSICS. Also registers PHYSICS_BODY_* and PHYSICS_SHAPE_* as global
|
||||
* integer constants for use with setBodyType()/setShape(). Has no
|
||||
* constructor -- instances are only ever created via
|
||||
* moduleEntityPhysicsCreate(), e.g. from Entity.add()/getComponent().
|
||||
*/
|
||||
void moduleEntityPhysicsInit(void);
|
||||
|
||||
/**
|
||||
* Disposes the Physics class's script resources.
|
||||
*/
|
||||
void moduleEntityPhysicsDispose(void);
|
||||
|
||||
/**
|
||||
* Wraps a component handle as a new JS Physics instance.
|
||||
*
|
||||
* @param handle The handle to copy into the new instance.
|
||||
* @return The new JS object.
|
||||
*/
|
||||
jerry_value_t moduleEntityPhysicsCreate(
|
||||
const modulecomponenthandle_t *handle
|
||||
);
|
||||
|
||||
/**
|
||||
* Internal. Gets the native handle wrapped by a Physics instance's
|
||||
* `this` value.
|
||||
*
|
||||
* @param callInfo The JS call info, whose this_value is the instance.
|
||||
* @return The wrapped handle, or NULL if this_value isn't a Physics.
|
||||
*/
|
||||
modulecomponenthandle_t *moduleEntityPhysicsGet(
|
||||
const jerry_call_info_t *callInfo
|
||||
);
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "moduleentity.h"
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/module/entity/component/modulecomponent.h"
|
||||
#include "script/module/entity/component/modulecomponentlist.h"
|
||||
#include "scene/scene.h"
|
||||
#include "entity/entitymanager.h"
|
||||
#include "entity/entity.h"
|
||||
@@ -67,7 +68,7 @@ moduleBaseFunction(moduleEntityAddComponent) {
|
||||
modulecomponenthandle_t h = {
|
||||
.mgr = inst->mgr, .entityId = inst->id, .componentId = id, .type = type
|
||||
};
|
||||
return moduleComponentCreate(&h);
|
||||
return moduleComponentListCreate(&h);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleEntityGetComponentMethod) {
|
||||
@@ -85,7 +86,7 @@ moduleBaseFunction(moduleEntityGetComponentMethod) {
|
||||
modulecomponenthandle_t h = {
|
||||
.mgr = inst->mgr, .entityId = inst->id, .componentId = id, .type = type
|
||||
};
|
||||
return moduleComponentCreate(&h);
|
||||
return moduleComponentListCreate(&h);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleEntityDisposeMethod) {
|
||||
|
||||
@@ -394,3 +394,30 @@ static inline float_t moduleBaseValueFloat(jerry_value_t val) {
|
||||
static inline int32_t moduleBaseValueInt(jerry_value_t val) {
|
||||
return (int32_t)jerry_value_as_number(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a vec3 as a plain JS {x, y, z} object.
|
||||
*/
|
||||
static inline jerry_value_t moduleBaseVec3ToObject(const vec3 v) {
|
||||
jerry_value_t obj = jerry_object();
|
||||
|
||||
jerry_value_t xKey = jerry_string_sz("x");
|
||||
jerry_value_t xVal = jerry_number(v[0]);
|
||||
jerry_object_set(obj, xKey, xVal);
|
||||
jerry_value_free(xVal);
|
||||
jerry_value_free(xKey);
|
||||
|
||||
jerry_value_t yKey = jerry_string_sz("y");
|
||||
jerry_value_t yVal = jerry_number(v[1]);
|
||||
jerry_object_set(obj, yKey, yVal);
|
||||
jerry_value_free(yVal);
|
||||
jerry_value_free(yKey);
|
||||
|
||||
jerry_value_t zKey = jerry_string_sz("z");
|
||||
jerry_value_t zVal = jerry_number(v[2]);
|
||||
jerry_object_set(obj, zKey, zVal);
|
||||
jerry_value_free(zVal);
|
||||
jerry_value_free(zKey);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
@@ -7,13 +7,21 @@
|
||||
|
||||
#include "modulelist.h"
|
||||
#include "script/module/moduleplatform.h"
|
||||
#include "script/module/require/modulerequire.h"
|
||||
#include "script/module/display/modulemesh.h"
|
||||
#include "script/module/time/moduletime.h"
|
||||
#include "script/module/entity/component/modulecomponent.h"
|
||||
#include "script/module/entity/component/modulecomponentlist.h"
|
||||
#include "script/module/entity/moduleentity.h"
|
||||
#include "script/module/scene/modulescene.h"
|
||||
|
||||
void moduleListInit(void) {
|
||||
modulePlatform();
|
||||
moduleRequireInit();
|
||||
moduleMeshInit();
|
||||
moduleTimeInit();
|
||||
moduleComponentInit();
|
||||
moduleComponentListInit();
|
||||
moduleEntityInit();
|
||||
moduleSceneInit();
|
||||
}
|
||||
@@ -21,5 +29,9 @@ void moduleListInit(void) {
|
||||
void moduleListDispose(void) {
|
||||
moduleSceneDispose();
|
||||
moduleEntityDispose();
|
||||
moduleComponentListDispose();
|
||||
moduleComponentDispose();
|
||||
moduleTimeDispose();
|
||||
moduleMeshDispose();
|
||||
moduleRequireDispose();
|
||||
}
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* Registers every script module (Component, Entity, Scene, the platform
|
||||
* globals). Called once by scriptManagerInit().
|
||||
* Registers every script module (Component + its typed per-type
|
||||
* wrappers, Entity, Scene, require(), Mesh, Time, the platform globals).
|
||||
* Called once by scriptManagerInit().
|
||||
*/
|
||||
void moduleListInit(void);
|
||||
|
||||
|
||||
@@ -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
|
||||
modulerequire.c
|
||||
)
|
||||
@@ -0,0 +1,271 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "modulerequire.h"
|
||||
#include "script/module/modulebase.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/string.h"
|
||||
|
||||
#define MODULE_REQUIRE_WRAP_PREFIX "(function(module){\n"
|
||||
#define MODULE_REQUIRE_WRAP_SUFFIX "\n})"
|
||||
|
||||
modulerequire_t MODULE_REQUIRE;
|
||||
|
||||
moduleBaseFunction(moduleRequireFn) {
|
||||
moduleBaseRequireArgs(1); moduleBaseRequireString(0);
|
||||
|
||||
char_t requested[ASSET_FILE_NAME_MAX];
|
||||
moduleBaseToString(args[0], requested, sizeof(requested));
|
||||
|
||||
char_t resolved[ASSET_FILE_NAME_MAX];
|
||||
moduleRequireResolvePath(requested, resolved, sizeof(resolved));
|
||||
|
||||
jerry_value_t cachedModule;
|
||||
if(moduleRequireCacheGet(resolved, &cachedModule)) {
|
||||
return moduleBaseGetProp(cachedModule, "exports");
|
||||
}
|
||||
|
||||
assetfile_t file;
|
||||
errorret_t err = assetFileInit(&file, resolved, NULL, NULL);
|
||||
if(errorIsNotOk(err)) return moduleBaseThrowError(err);
|
||||
|
||||
uint8_t *buffer = NULL;
|
||||
size_t size = 0;
|
||||
err = assetFileReadEntire(&file, &buffer, &size);
|
||||
if(errorIsNotOk(err)) return moduleBaseThrowError(err);
|
||||
|
||||
err = assetFileDispose(&file);
|
||||
if(errorIsNotOk(err)) {
|
||||
memoryFree(buffer);
|
||||
return moduleBaseThrowError(err);
|
||||
}
|
||||
|
||||
// Wrap the source in a function so `module` is a real parameter, not a
|
||||
// global - each required file's scope stays isolated from the others.
|
||||
const size_t prefixLen = sizeof(MODULE_REQUIRE_WRAP_PREFIX) - 1;
|
||||
const size_t suffixLen = sizeof(MODULE_REQUIRE_WRAP_SUFFIX) - 1;
|
||||
const size_t wrappedLen = prefixLen + size + suffixLen;
|
||||
char_t *wrapped = (char_t *)memoryAllocate(wrappedLen + 1);
|
||||
memoryCopy(wrapped, MODULE_REQUIRE_WRAP_PREFIX, prefixLen);
|
||||
memoryCopy(wrapped + prefixLen, buffer, size);
|
||||
memoryCopy(wrapped + prefixLen + size, MODULE_REQUIRE_WRAP_SUFFIX, suffixLen);
|
||||
wrapped[wrappedLen] = '\0';
|
||||
memoryFree(buffer);
|
||||
|
||||
jerry_value_t fnValue = jerry_eval(
|
||||
(const jerry_char_t *)wrapped, wrappedLen, JERRY_PARSE_NO_OPTS
|
||||
);
|
||||
memoryFree(wrapped);
|
||||
|
||||
if(jerry_value_is_exception(fnValue)) return fnValue;
|
||||
|
||||
// Cache before calling so a circular require() sees this module object
|
||||
// (with whatever `module.exports` has been set so far) instead of
|
||||
// recursing forever.
|
||||
jerry_value_t moduleObj = jerry_object();
|
||||
moduleRequireCacheSet(resolved, moduleObj);
|
||||
|
||||
char_t dir[ASSET_FILE_NAME_MAX];
|
||||
moduleRequireDirname(resolved, dir, sizeof(dir));
|
||||
moduleRequireDirPush(dir);
|
||||
|
||||
jerry_value_t callArgs[1] = { moduleObj };
|
||||
jerry_value_t callResult = jerry_call(fnValue, jerry_undefined(), callArgs, 1);
|
||||
jerry_value_free(fnValue);
|
||||
|
||||
moduleRequireDirPop();
|
||||
|
||||
if(jerry_value_is_exception(callResult)) {
|
||||
moduleRequireCacheDelete(resolved);
|
||||
jerry_value_free(moduleObj);
|
||||
return callResult;
|
||||
}
|
||||
jerry_value_free(callResult);
|
||||
|
||||
return moduleBaseGetProp(moduleObj, "exports");
|
||||
}
|
||||
|
||||
void moduleRequireInit(void) {
|
||||
memoryZero(&MODULE_REQUIRE, sizeof(modulerequire_t));
|
||||
moduleBaseDefineGlobalMethod("require", moduleRequireFn);
|
||||
}
|
||||
|
||||
void moduleRequireDispose(void) {
|
||||
for(uint8_t i = 0; i < MODULE_REQUIRE.cacheCount; i++) {
|
||||
jerry_value_free(MODULE_REQUIRE.cache[i].moduleObj);
|
||||
}
|
||||
MODULE_REQUIRE.cacheCount = 0;
|
||||
MODULE_REQUIRE.dirStackCount = 0;
|
||||
}
|
||||
|
||||
void moduleRequireResolvePath(
|
||||
const char_t *requested,
|
||||
char_t *outResolved,
|
||||
const size_t outResolvedSize
|
||||
) {
|
||||
assertNotNull(requested, "Requested path cannot be NULL");
|
||||
assertNotNull(outResolved, "Output buffer cannot be NULL");
|
||||
|
||||
bool_t isRelative = (
|
||||
(requested[0] == '.' && requested[1] == '/') ||
|
||||
(requested[0] == '.' && requested[1] == '.' && requested[2] == '/')
|
||||
);
|
||||
|
||||
char_t combined[MODULE_REQUIRE_PATH_MAX];
|
||||
if(isRelative) {
|
||||
stringFormat(
|
||||
combined, sizeof(combined) - 1, "%s%s",
|
||||
moduleRequireDirStackTop(), requested
|
||||
);
|
||||
} else {
|
||||
stringCopy(combined, requested, sizeof(combined) - 1);
|
||||
}
|
||||
|
||||
moduleRequireNormalize(combined, outResolved, outResolvedSize);
|
||||
}
|
||||
|
||||
void moduleRequireNormalize(
|
||||
const char_t *path,
|
||||
char_t *outNormalized,
|
||||
const size_t outSize
|
||||
) {
|
||||
assertNotNull(path, "Path cannot be NULL");
|
||||
assertNotNull(outNormalized, "Output buffer cannot be NULL");
|
||||
|
||||
char_t scratch[MODULE_REQUIRE_PATH_MAX];
|
||||
stringCopy(scratch, path, sizeof(scratch) - 1);
|
||||
|
||||
char_t *segments[MODULE_REQUIRE_SEGMENT_MAX];
|
||||
uint8_t segmentCount = 0;
|
||||
|
||||
char_t *cursor = scratch;
|
||||
bool_t more = true;
|
||||
while(more) {
|
||||
char_t *segment = cursor;
|
||||
while(*cursor != '/' && *cursor != '\0') cursor++;
|
||||
more = (*cursor == '/');
|
||||
if(more) { *cursor = '\0'; cursor++; }
|
||||
|
||||
if(segment[0] == '\0' || stringEquals(segment, ".")) {
|
||||
// Skip empty (e.g. leading/double slash) and "." segments.
|
||||
} else if(stringEquals(segment, "..")) {
|
||||
if(segmentCount > 0) segmentCount--;
|
||||
} else {
|
||||
assertTrue(
|
||||
segmentCount < MODULE_REQUIRE_SEGMENT_MAX,
|
||||
"require() path has too many segments"
|
||||
);
|
||||
segments[segmentCount++] = segment;
|
||||
}
|
||||
}
|
||||
|
||||
size_t written = 0;
|
||||
outNormalized[0] = '\0';
|
||||
for(uint8_t i = 0; i < segmentCount; i++) {
|
||||
if(i > 0) {
|
||||
assertTrue(written + 1 < outSize, "require() path too long");
|
||||
outNormalized[written++] = '/';
|
||||
}
|
||||
|
||||
size_t segLen = 0;
|
||||
while(segments[i][segLen] != '\0') segLen++;
|
||||
assertTrue(written + segLen < outSize, "require() path too long");
|
||||
memoryCopy(outNormalized + written, segments[i], segLen);
|
||||
written += segLen;
|
||||
}
|
||||
outNormalized[written] = '\0';
|
||||
}
|
||||
|
||||
void moduleRequireDirname(
|
||||
const char_t *path,
|
||||
char_t *outDir,
|
||||
const size_t outDirSize
|
||||
) {
|
||||
assertNotNull(path, "Path cannot be NULL");
|
||||
assertNotNull(outDir, "Output buffer cannot be NULL");
|
||||
|
||||
char_t *lastSlash = stringFindLastChar(path, '/');
|
||||
if(lastSlash == NULL) {
|
||||
outDir[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
size_t len = (size_t)(lastSlash - path) + 1;
|
||||
assertTrue(len < outDirSize, "Directory path too long");
|
||||
memoryCopy(outDir, path, len);
|
||||
outDir[len] = '\0';
|
||||
}
|
||||
|
||||
bool_t moduleRequireCacheGet(
|
||||
const char_t *resolvedPath,
|
||||
jerry_value_t *outModuleObj
|
||||
) {
|
||||
assertNotNull(resolvedPath, "Resolved path cannot be NULL");
|
||||
assertNotNull(outModuleObj, "Output module object cannot be NULL");
|
||||
|
||||
for(uint8_t i = 0; i < MODULE_REQUIRE.cacheCount; i++) {
|
||||
if(stringEquals(MODULE_REQUIRE.cache[i].path, resolvedPath)) {
|
||||
*outModuleObj = MODULE_REQUIRE.cache[i].moduleObj;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void moduleRequireCacheSet(
|
||||
const char_t *resolvedPath,
|
||||
const jerry_value_t moduleObj
|
||||
) {
|
||||
assertNotNull(resolvedPath, "Resolved path cannot be NULL");
|
||||
assertTrue(
|
||||
MODULE_REQUIRE.cacheCount < MODULE_REQUIRE_CACHE_MAX,
|
||||
"require() module cache is full"
|
||||
);
|
||||
|
||||
modulerequirecacheentry_t *entry =
|
||||
&MODULE_REQUIRE.cache[MODULE_REQUIRE.cacheCount++];
|
||||
stringCopy(entry->path, resolvedPath, ASSET_FILE_NAME_MAX - 1);
|
||||
entry->moduleObj = moduleObj;
|
||||
}
|
||||
|
||||
void moduleRequireCacheDelete(const char_t *resolvedPath) {
|
||||
assertNotNull(resolvedPath, "Resolved path cannot be NULL");
|
||||
|
||||
for(uint8_t i = 0; i < MODULE_REQUIRE.cacheCount; i++) {
|
||||
if(!stringEquals(MODULE_REQUIRE.cache[i].path, resolvedPath)) continue;
|
||||
|
||||
MODULE_REQUIRE.cacheCount--;
|
||||
MODULE_REQUIRE.cache[i] = MODULE_REQUIRE.cache[MODULE_REQUIRE.cacheCount];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void moduleRequireDirPush(const char_t *dir) {
|
||||
assertNotNull(dir, "Directory cannot be NULL");
|
||||
assertTrue(
|
||||
MODULE_REQUIRE.dirStackCount < MODULE_REQUIRE_STACK_MAX,
|
||||
"require() nesting too deep"
|
||||
);
|
||||
|
||||
stringCopy(
|
||||
MODULE_REQUIRE.dirStack[MODULE_REQUIRE.dirStackCount++],
|
||||
dir, ASSET_FILE_NAME_MAX - 1
|
||||
);
|
||||
}
|
||||
|
||||
void moduleRequireDirPop(void) {
|
||||
assertTrue(
|
||||
MODULE_REQUIRE.dirStackCount > 0, "require() dir stack underflow"
|
||||
);
|
||||
MODULE_REQUIRE.dirStackCount--;
|
||||
}
|
||||
|
||||
const char_t * moduleRequireDirStackTop(void) {
|
||||
if(MODULE_REQUIRE.dirStackCount == 0) return "";
|
||||
return MODULE_REQUIRE.dirStack[MODULE_REQUIRE.dirStackCount - 1];
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "error/error.h"
|
||||
#include "asset/assetfile.h"
|
||||
#include <jerryscript.h>
|
||||
|
||||
/** Max number of distinct files require() will keep resolved/cached. */
|
||||
#define MODULE_REQUIRE_CACHE_MAX 32
|
||||
|
||||
/** Max require() nesting depth (a file requiring a file requiring...). */
|
||||
#define MODULE_REQUIRE_STACK_MAX 16
|
||||
|
||||
/** Max path segments handled while resolving a single require() call. */
|
||||
#define MODULE_REQUIRE_SEGMENT_MAX 16
|
||||
|
||||
/** Scratch buffer size used while joining a base dir with a request. */
|
||||
#define MODULE_REQUIRE_PATH_MAX (ASSET_FILE_NAME_MAX * 2)
|
||||
|
||||
typedef struct {
|
||||
char_t path[ASSET_FILE_NAME_MAX];
|
||||
jerry_value_t moduleObj;
|
||||
} modulerequirecacheentry_t;
|
||||
|
||||
typedef struct {
|
||||
modulerequirecacheentry_t cache[MODULE_REQUIRE_CACHE_MAX];
|
||||
uint8_t cacheCount;
|
||||
|
||||
/** Directories of files currently mid-require(), innermost last. */
|
||||
char_t dirStack[MODULE_REQUIRE_STACK_MAX][ASSET_FILE_NAME_MAX];
|
||||
uint8_t dirStackCount;
|
||||
} modulerequire_t;
|
||||
|
||||
extern modulerequire_t MODULE_REQUIRE;
|
||||
|
||||
/**
|
||||
* Registers the global require() function.
|
||||
*/
|
||||
void moduleRequireInit(void);
|
||||
|
||||
/**
|
||||
* Frees every cached module object. Called once by moduleListDispose().
|
||||
*/
|
||||
void moduleRequireDispose(void);
|
||||
|
||||
/**
|
||||
* Resolves a require() argument to an asset-root-relative path. Paths
|
||||
* starting with "./" or "../" are resolved against the directory of the
|
||||
* file currently being required (or the asset root if require() is not
|
||||
* currently nested); any other path is treated as already asset-root-
|
||||
* relative. "." and ".." segments are collapsed either way.
|
||||
*
|
||||
* @param requested The raw string passed to require().
|
||||
* @param outResolved Output buffer for the resolved path.
|
||||
* @param outResolvedSize Capacity of outResolved, including the null
|
||||
* terminator.
|
||||
*/
|
||||
void moduleRequireResolvePath(
|
||||
const char_t *requested,
|
||||
char_t *outResolved,
|
||||
const size_t outResolvedSize
|
||||
);
|
||||
|
||||
/**
|
||||
* Collapses "." and ".." segments out of a slash-separated path.
|
||||
*
|
||||
* @param path The path to normalize.
|
||||
* @param outNormalized Output buffer for the normalized path.
|
||||
* @param outSize Capacity of outNormalized, including the null
|
||||
* terminator.
|
||||
*/
|
||||
void moduleRequireNormalize(
|
||||
const char_t *path,
|
||||
char_t *outNormalized,
|
||||
const size_t outSize
|
||||
);
|
||||
|
||||
/**
|
||||
* Extracts the directory portion (including trailing slash) of a
|
||||
* resolved path, or an empty string if the path has no directory.
|
||||
*
|
||||
* @param path The resolved path.
|
||||
* @param outDir Output buffer for the directory.
|
||||
* @param outDirSize Capacity of outDir, including the null terminator.
|
||||
*/
|
||||
void moduleRequireDirname(
|
||||
const char_t *path,
|
||||
char_t *outDir,
|
||||
const size_t outDirSize
|
||||
);
|
||||
|
||||
/**
|
||||
* Looks up a previously require()'d module by its resolved path.
|
||||
*
|
||||
* @param resolvedPath The resolved path to look up.
|
||||
* @param outModuleObj Receives the cached module object if found.
|
||||
* @return true if a cache entry was found.
|
||||
*/
|
||||
bool_t moduleRequireCacheGet(
|
||||
const char_t *resolvedPath,
|
||||
jerry_value_t *outModuleObj
|
||||
);
|
||||
|
||||
/**
|
||||
* Registers a module object under a resolved path. Takes ownership of
|
||||
* the passed value - it is only freed by moduleRequireDispose() or
|
||||
* moduleRequireCacheDelete().
|
||||
*
|
||||
* @param resolvedPath The resolved path to cache under.
|
||||
* @param moduleObj The module object to cache.
|
||||
*/
|
||||
void moduleRequireCacheSet(
|
||||
const char_t *resolvedPath,
|
||||
const jerry_value_t moduleObj
|
||||
);
|
||||
|
||||
/**
|
||||
* Evicts and frees a cache entry. Used to roll back a failed load so a
|
||||
* later require() of the same path can retry instead of being stuck
|
||||
* with a broken cache entry.
|
||||
*
|
||||
* @param resolvedPath The resolved path to evict.
|
||||
*/
|
||||
void moduleRequireCacheDelete(const char_t *resolvedPath);
|
||||
|
||||
/**
|
||||
* Pushes a directory onto the require() nesting stack, becoming the new
|
||||
* base for resolving relative requires until popped.
|
||||
*
|
||||
* @param dir The directory (including trailing slash, or empty) to push.
|
||||
*/
|
||||
void moduleRequireDirPush(const char_t *dir);
|
||||
|
||||
/**
|
||||
* Pops the require() nesting stack.
|
||||
*/
|
||||
void moduleRequireDirPop(void);
|
||||
|
||||
/**
|
||||
* Gets the current top of the require() nesting stack.
|
||||
*
|
||||
* @return The current base directory, or an empty string if the stack is
|
||||
* empty (i.e. require() is not currently nested).
|
||||
*/
|
||||
const char_t * moduleRequireDirStackTop(void);
|
||||
@@ -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
|
||||
moduletime.c
|
||||
)
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "moduletime.h"
|
||||
#include "script/module/modulebase.h"
|
||||
#include "time/time.h"
|
||||
|
||||
moduleBaseFunction(moduleTimeGetDelta) {
|
||||
return jerry_number(TIME.delta);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleTimeGetTime) {
|
||||
return jerry_number(TIME.time);
|
||||
}
|
||||
|
||||
void moduleTimeInit(void) {
|
||||
jerry_value_t timeObj = jerry_object();
|
||||
moduleBaseDefineProperty(timeObj, "delta", moduleTimeGetDelta, NULL);
|
||||
moduleBaseDefineProperty(timeObj, "time", moduleTimeGetTime, NULL);
|
||||
moduleBaseSetValue("Time", timeObj);
|
||||
jerry_value_free(timeObj);
|
||||
}
|
||||
|
||||
void moduleTimeDispose(void) {
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* Registers the global `Time` object, exposing `Time.delta` and
|
||||
* `Time.time` as live getters over the engine's TIME state (see
|
||||
* time/time.h). Values always reflect the most recent timeUpdate().
|
||||
*/
|
||||
void moduleTimeInit(void);
|
||||
|
||||
/**
|
||||
* Disposes the time module's script resources.
|
||||
*/
|
||||
void moduleTimeDispose(void);
|
||||
@@ -6,12 +6,10 @@
|
||||
*/
|
||||
|
||||
#include "game/game.h"
|
||||
#include "scene/scene.h"
|
||||
#include "scene/overworldscene.h"
|
||||
#include "script/scriptmanager.h"
|
||||
|
||||
errorret_t gameInit(void) {
|
||||
sceneid_t testSceneId = overworldSceneCreate();
|
||||
sceneSetActive(testSceneId);
|
||||
errorChain(scriptManagerExecFile("scripts/overworldscene.js", NULL));
|
||||
errorOk();
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,4 @@
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
overworldscene.c
|
||||
)
|
||||
|
||||
add_subdirectory(prefab)
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "overworldscene.h"
|
||||
#include "scene/scene.h"
|
||||
#include "entity/entitymanager.h"
|
||||
#include "entity/component/display/entityposition.h"
|
||||
#include "entity/component/display/entitycamera.h"
|
||||
#include "entity/component/display/entityrenderable.h"
|
||||
#include "entity/component/physics/entityphysics.h"
|
||||
#include "display/mesh/plane.h"
|
||||
#include "display/mesh/capsule.h"
|
||||
#include "display/color.h"
|
||||
#include "time/time.h"
|
||||
|
||||
// Radius must stay well outside the floor's footprint (a 20x20 plane has a
|
||||
// corner-to-center distance of 10*sqrt(2) =~ 14.1) -- orbiting inside that
|
||||
// puts parts of the floor's own geometry near/behind the camera's view
|
||||
// direction, which the PSP's legacy GU pipeline can't clip properly and
|
||||
// drops the whole triangle instead of clipping it.
|
||||
#define OVERWORLD_SCENE_CAMERA_ORBIT_RADIUS 18.0f
|
||||
#define OVERWORLD_SCENE_CAMERA_ORBIT_HEIGHT 10.0f
|
||||
#define OVERWORLD_SCENE_CAMERA_ORBIT_SPEED 0.5f
|
||||
|
||||
static overworldcameraorbit_t OVERWORLD_SCENE_CAMERA_ORBIT;
|
||||
|
||||
sceneid_t overworldSceneCreate(void) {
|
||||
sceneid_t sceneId = sceneCreate();
|
||||
entitymanager_t *mgr = sceneGetEntities(sceneId);
|
||||
|
||||
// Camera, orbiting the origin (see overworldSceneCameraOrbitUpdate).
|
||||
entityid_t camEntity = entityManagerAdd(mgr);
|
||||
componentid_t camPosition = entityAddComponent(
|
||||
mgr, camEntity, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
entityAddComponent(mgr, camEntity, COMPONENT_TYPE_CAMERA);
|
||||
|
||||
OVERWORLD_SCENE_CAMERA_ORBIT = (overworldcameraorbit_t){
|
||||
.angle = 0.0f,
|
||||
.radius = OVERWORLD_SCENE_CAMERA_ORBIT_RADIUS,
|
||||
.height = OVERWORLD_SCENE_CAMERA_ORBIT_HEIGHT,
|
||||
.speed = OVERWORLD_SCENE_CAMERA_ORBIT_SPEED
|
||||
};
|
||||
entityUpdateAdd(
|
||||
mgr, camEntity, overworldSceneCameraOrbitUpdate, camPosition,
|
||||
&OVERWORLD_SCENE_CAMERA_ORBIT
|
||||
);
|
||||
// Position it correctly for the very first rendered frame, rather than
|
||||
// waiting for the first fixed tick to run.
|
||||
overworldSceneCameraOrbitUpdate(
|
||||
mgr, camEntity, camPosition, &OVERWORLD_SCENE_CAMERA_ORBIT
|
||||
);
|
||||
|
||||
// Static ground plane. Physics ignores the entity's position component --
|
||||
// the shape's own normal/distance fully define the plane in world space.
|
||||
entityid_t planeEntity = entityManagerAdd(mgr);
|
||||
componentid_t planePosition = entityAddComponent(
|
||||
mgr, planeEntity, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
entityPositionSetLocalPosition(
|
||||
mgr, planeEntity, planePosition, (vec3){ -10.0f, 0.0f, -10.0f }
|
||||
);
|
||||
entityPositionSetLocalScale(
|
||||
mgr, planeEntity, planePosition, (vec3){ 20.0f, 1.0f, 20.0f }
|
||||
);
|
||||
componentid_t planePhysics = entityAddComponent(
|
||||
mgr, planeEntity, COMPONENT_TYPE_PHYSICS
|
||||
);
|
||||
entityPhysicsSetBodyType(
|
||||
mgr, planeEntity, planePhysics, PHYSICS_BODY_STATIC
|
||||
);
|
||||
entityPhysicsSetShape(mgr, planeEntity, planePhysics, (physicsshape_t){
|
||||
.type = PHYSICS_SHAPE_PLANE,
|
||||
.data.plane = { .normal = { 0.0f, 1.0f, 0.0f }, .distance = 0.0f }
|
||||
});
|
||||
componentid_t planeRenderable = entityAddComponent(
|
||||
mgr, planeEntity, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
entityrenderable_t *planeR = componentGetData(
|
||||
mgr, planeEntity, planeRenderable, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
planeR->data.material.meshes[0] = &PLANE_MESH_SIMPLE;
|
||||
entityRenderableSetColor(mgr, planeEntity, planeRenderable, COLOR_GRAY);
|
||||
|
||||
// Player: dynamic capsule body, moved relative to the camera by
|
||||
// COMPONENT_TYPE_PLAYER's own update callback (see entityplayer.c).
|
||||
entityid_t playerEntity = entityManagerAdd(mgr);
|
||||
componentid_t playerPosition = entityAddComponent(
|
||||
mgr, playerEntity, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
entityPositionSetLocalPosition(
|
||||
mgr, playerEntity, playerPosition, (vec3){ 0.0f, 2.0f, 0.0f }
|
||||
);
|
||||
componentid_t playerPhysics = entityAddComponent(
|
||||
mgr, playerEntity, COMPONENT_TYPE_PHYSICS
|
||||
);
|
||||
entityPhysicsSetShape(mgr, playerEntity, playerPhysics, (physicsshape_t){
|
||||
.type = PHYSICS_SHAPE_CAPSULE,
|
||||
.data.capsule = { .radius = 0.5f, .halfHeight = 0.5f }
|
||||
});
|
||||
componentid_t playerRenderable = entityAddComponent(
|
||||
mgr, playerEntity, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
entityrenderable_t *playerR = componentGetData(
|
||||
mgr, playerEntity, playerRenderable, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
playerR->data.material.meshes[0] = &CAPSULE_MESH_SIMPLE;
|
||||
entityRenderableSetColor(mgr, playerEntity, playerRenderable, COLOR_BLUE);
|
||||
entityAddComponent(mgr, playerEntity, COMPONENT_TYPE_PLAYER);
|
||||
|
||||
return sceneId;
|
||||
}
|
||||
|
||||
void overworldSceneCameraOrbitUpdate(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
void *user
|
||||
) {
|
||||
overworldcameraorbit_t *orbit = (overworldcameraorbit_t *)user;
|
||||
orbit->angle += TIME.delta * orbit->speed;
|
||||
|
||||
vec3 eye = {
|
||||
cosf(orbit->angle) * orbit->radius,
|
||||
orbit->height,
|
||||
sinf(orbit->angle) * orbit->radius
|
||||
};
|
||||
entityPositionLookAt(
|
||||
mgr, entityId, componentId,
|
||||
eye,
|
||||
(vec3){ 0.0f, 0.0f, 0.0f },
|
||||
(vec3){ 0.0f, 1.0f, 0.0f }
|
||||
);
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "scene/scenebase.h"
|
||||
#include "entity/entitybase.h"
|
||||
|
||||
typedef struct {
|
||||
float_t angle;
|
||||
float_t radius;
|
||||
float_t height;
|
||||
float_t speed;
|
||||
} overworldcameraorbit_t;
|
||||
|
||||
/**
|
||||
* Creates the overworld scene: a static ground plane, a player entity
|
||||
* (dynamic capsule body, moved relative to the camera by
|
||||
* COMPONENT_TYPE_PLAYER's own update callback), and a camera orbiting the
|
||||
* origin (see overworldSceneCameraOrbitUpdate). Does not make the scene
|
||||
* active -- call sceneSetActive with the returned ID.
|
||||
*
|
||||
* @return The ID of the newly created scene.
|
||||
*/
|
||||
sceneid_t overworldSceneCreate(void);
|
||||
|
||||
/**
|
||||
* Per-tick update for the test camera: orbits it around the world origin
|
||||
* at a fixed radius/height/speed, always looking back at the origin.
|
||||
* Registered automatically by overworldSceneCreate.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The camera entity ID.
|
||||
* @param componentId The camera's position component ID.
|
||||
* @param user Pointer to this camera's overworldcameraorbit_t state.
|
||||
*/
|
||||
void overworldSceneCameraOrbitUpdate(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
void *user
|
||||
);
|
||||
Reference in New Issue
Block a user