Bring the entity-component system online: rendering, scene manager, scripting

entityRenderAll() (src/dusk/entity/entityrender.c) ports ac2's
scene.c:sceneRender() camera/view-matrix/draw-loop logic as a standalone
function - find the active camera, bind SHADER_UNLIT with its projection/
view, draw every COMPONENT_TYPE_RENDERABLE entity. display.c calls it each
frame between the screen clear and screenUnbind(), the same spot the old
sceneRender() used to sit.

A single-scene scene manager (src/dusk/scene/, ported from ac2 minus its
prefab system and physics/trigger stepping - that module hasn't been
ported yet) sits alongside this but isn't wired into the engine loop yet;
only one scene can ever exist (no SCENE_COUNT_MAX array).

entitymanager.c/h removed entirely: its three arrays (entities/components/
entitiesWithComponent) are now plain globals in entity.h/.c
(ENTITIES/COMPONENTS/ENTITIES_WITH_COMPONENT), and every entity/component
function across the whole ECS (entity, component, position, camera,
renderable, physics, trigger, animation) drops its entitymanager_t *mgr
parameter to operate on them directly - there was only ever one instance of
that struct in the whole engine, so the indirection bought nothing.

New duskscript bindings (src/dusk/script/native/entity/) expose entityAdd,
entityAddComponent/entityGetComponent, entitySetName/entityGetName/
entityFindByName, entityDispose/entityDisposeDeep,
entityPositionSetLocalPosition/entityPositionLookAt,
entityRenderableSetMesh (by name - cube/plane/sphere/capsule/triprism/quad),
and COMPONENT_TYPE_*/ENTITY_ID_INVALID/COMPONENT_ID_INVALID constants.
assets/init.ds uses them to spawn a camera (via LookAt from (3,3,3) at the
origin), a cube and a plane as the engine's first real content on the new
ECS.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
YourWishesandClaude Sonnet 5 committed 2026-10-15 09:08:20 -05:00
1 parent fdfdfa3a66
commit 9a24b3d7db
43 files changed
+1084 -605

No files matched your search

+19 -1
View File
@@ -1,2 +1,20 @@
// Entry point, run once by the engine after every other system is ready.
consolePrint("Test");
var camera = entityAdd();
var cameraPosition = entityAddComponent(camera, COMPONENT_TYPE_POSITION);
entityAddComponent(camera, COMPONENT_TYPE_CAMERA);
entityPositionLookAt(camera, cameraPosition, 3, 3, 3, 0, 0, 0);
var cube = entityAdd();
var cubePosition = entityAddComponent(cube, COMPONENT_TYPE_POSITION);
var cubeRenderable = entityAddComponent(cube, COMPONENT_TYPE_RENDERABLE);
entityRenderableSetMesh(cube, cubeRenderable, "cube");
entityPositionSetLocalPosition(cube, cubePosition, 0, 0, 0);
var plane = entityAdd();
var planePosition = entityAddComponent(plane, COMPONENT_TYPE_POSITION);
var planeRenderable = entityAddComponent(plane, COMPONENT_TYPE_RENDERABLE);
entityRenderableSetMesh(plane, planeRenderable, "plane");
entityPositionSetLocalPosition(plane, planePosition, 0, 0, 0);
consolePrint("Camera, cube and plane created");
+1 -3
View File
@@ -82,12 +82,10 @@ add_subdirectory(error)
add_subdirectory(input)
add_subdirectory(locale)
add_subdirectory(perf)
add_subdirectory(rpg)
add_subdirectory(script)
add_subdirectory(scene)
add_subdirectory(script)
add_subdirectory(system)
add_subdirectory(time)
add_subdirectory(ui)
add_subdirectory(save)
add_subdirectory(util)
add_subdirectory(thread)
+4 -4
View File
@@ -7,7 +7,8 @@
#include "display/display.h"
#include "display/framebuffer/framebuffer.h"
#include "scene/scene.h"
#include "entity/entity.h"
#include "entity/entityrender.h"
#include "display/spritebatch/spritebatch.h"
#include "display/mesh/quad.h"
#include "display/mesh/cube.h"
@@ -16,7 +17,6 @@
#include "display/mesh/capsule.h"
#include "display/mesh/triprism.h"
#include "display/screen/screen.h"
#include "ui/ui.h"
#include "display/text/text.h"
#include "assert/assert.h"
#include "util/memory.h"
@@ -76,14 +76,14 @@ errorret_t displayUpdate(void) {
spriteBatchClear();
errorChain(frameBufferBind(NULL));
// Bind screen and render scene
// Bind screen and render the entity world
errorChain(screenBind());
frameBufferClear(
FRAMEBUFFER_CLEAR_COLOR | FRAMEBUFFER_CLEAR_DEPTH,
SCREEN.background
);
errorChain(sceneRender());
errorChain(entityRenderAll());
// Finish up
screenUnbind();
+4 -14
View File
@@ -11,11 +11,9 @@
#include "time/time.h"
#include "input/input.h"
#include "locale/localemanager.h"
#include "rpg/rpg.h"
#include "display/display.h"
#include "scene/scene.h"
#include "entity/entity.h"
#include "asset/asset.h"
#include "ui/ui.h"
#include "assert/assert.h"
#ifdef DUSK_NETWORK
#include "network/network.h"
@@ -48,13 +46,11 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
errorChain(localeManagerInit());
errorChain(displayInit());
errorChain(audioInit());
errorChain(rpgInit());
errorChain(uiInit());
entityManagerInit();
#ifdef DUSK_NETWORK
errorChain(networkInit());
#endif
errorChain(scriptInit());
errorChain(sceneInit());
// Runs once every other system is ready, so init.ds can use any of them.
scripterror_t scriptInitError;
@@ -70,8 +66,6 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
consolePrint("Assertions real");
#endif
sceneSet(SCENE_TYPE_INITIAL);
errorOk();
}
@@ -85,10 +79,8 @@ errorret_t engineUpdate(void) {
inputUpdate();
consoleUpdate();
errorChain(audioUpdateEarly());
errorChain(rpgUpdate());
errorChain(sceneUpdate());
errorChain(assetUpdate());
errorChain(uiUpdate());
entityManagerUpdate();
// Render
errorChain(displayUpdate());
@@ -102,14 +94,12 @@ void engineExit(void) {
}
errorret_t engineDispose(void) {
errorChain(sceneDispose());
errorChain(scriptDispose());
entityManagerDispose();
#ifdef DUSK_NETWORK
errorChain(networkDispose());
#endif
errorChain(rpgDispose());
localeManagerDispose();
errorChain(uiDispose());
errorChain(audioDispose());
consoleDispose();
errorChain(displayDispose());
+1 -1
View File
@@ -7,7 +7,7 @@
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
entity.c
entitymanager.c
entityrender.c
component.c
)
+13 -22
View File
@@ -5,7 +5,7 @@
* https://opensource.org/licenses/MIT
*/
#include "entitymanager.h"
#include "entity.h"
#include "assert/assert.h"
#include "util/memory.h"
@@ -28,41 +28,37 @@ componentdefinition_t COMPONENT_DEFINITIONS[] = {
};
void componentInit(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const componenttype_t type
) {
assertNotNull(mgr, "Entity manager cannot be null");
assertTrue(entityId < ENTITY_COUNT_MAX, "Entity ID OOB");
assertTrue(componentId < ENTITY_COMPONENT_COUNT_MAX, "Component ID OOB");
assertTrue(type < COMPONENT_TYPE_COUNT, "Component type OOB");
assertTrue(type != COMPONENT_TYPE_NULL, "Cannot initialize null component");
componentindex_t index = componentGetIndex(entityId, componentId);
component_t *cmp = &mgr->components[index];
component_t *cmp = &COMPONENTS[index];
memoryZero(cmp, sizeof(component_t));
cmp->type = type;
if(COMPONENT_DEFINITIONS[type].init) {
COMPONENT_DEFINITIONS[type].init(mgr, entityId, componentId);
COMPONENT_DEFINITIONS[type].init(entityId, componentId);
}
}
void * componentGetData(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const componenttype_t type
) {
assertNotNull(mgr, "Entity manager cannot be null");
assertTrue(entityId < ENTITY_COUNT_MAX, "Entity ID OOB");
assertTrue(componentId < ENTITY_COMPONENT_COUNT_MAX, "Component ID OOB");
assertTrue(type < COMPONENT_TYPE_COUNT, "Component type OOB");
assertTrue(type != COMPONENT_TYPE_NULL, "Cannot get data of null component");
componentindex_t index = componentGetIndex(entityId, componentId);
component_t *cmp = &mgr->components[index];
component_t *cmp = &COMPONENTS[index];
assertTrue(cmp->type == type, "Component type mismatch");
return &cmp->data;
@@ -78,12 +74,10 @@ componentindex_t componentGetIndex(
}
entityid_t componentGetEntitiesWithComponent(
entitymanager_t *mgr,
const componenttype_t type,
entityid_t outEntities[ENTITY_COUNT_MAX],
componentid_t outComponents[ENTITY_COUNT_MAX]
) {
assertNotNull(mgr, "Entity manager cannot be null");
assertTrue(type < COMPONENT_TYPE_COUNT, "Component type OOB");
assertTrue(type != COMPONENT_TYPE_NULL, "Cannot check NULL type");
assertNotNull(outEntities, "Output entities array cannot be null");
@@ -91,16 +85,16 @@ entityid_t componentGetEntitiesWithComponent(
entityid_t written = 0;
for(entityid_t i = 0; i < ENTITY_COUNT_MAX; i++) {
componentid_t used = mgr->entitiesWithComponent[
componentid_t used = ENTITIES_WITH_COMPONENT[
type * ENTITY_COUNT_MAX + i
];
if(used == COMPONENT_ID_INVALID) continue;
assertTrue(
mgr->components[componentGetIndex(i, used)].type == type,
COMPONENTS[componentGetIndex(i, used)].type == type,
"Component type mismatch in entitiesWithComponent lookup"
);
assertTrue(
(mgr->entities[i].state & ENTITY_STATE_ACTIVE) != 0,
(ENTITIES[i].state & ENTITY_STATE_ACTIVE) != 0,
"Inactive entity in entitiesWithComponent lookup"
);
assertTrue(
@@ -117,35 +111,32 @@ entityid_t componentGetEntitiesWithComponent(
return written;
}
errorret_t componentRenderAll(entitymanager_t *mgr) {
assertNotNull(mgr, "Entity manager cannot be null");
errorret_t componentRenderAll(void) {
for(entityid_t eid = 0; eid < ENTITY_COUNT_MAX; eid++) {
if(!(mgr->entities[eid].state & ENTITY_STATE_ACTIVE)) continue;
if(!(ENTITIES[eid].state & ENTITY_STATE_ACTIVE)) continue;
for(componentid_t cid = 0; cid < ENTITY_COMPONENT_COUNT_MAX; cid++) {
component_t *cmp = &mgr->components[componentGetIndex(eid, cid)];
component_t *cmp = &COMPONENTS[componentGetIndex(eid, cid)];
if(cmp->type == COMPONENT_TYPE_NULL) continue;
if(!COMPONENT_DEFINITIONS[cmp->type].render) continue;
errorChain(COMPONENT_DEFINITIONS[cmp->type].render(mgr, eid, cid));
errorChain(COMPONENT_DEFINITIONS[cmp->type].render(eid, cid));
}
}
errorOk();
}
void componentDispose(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
) {
assertNotNull(mgr, "Entity manager cannot be null");
assertTrue(entityId < ENTITY_COUNT_MAX, "Entity ID OOB");
assertTrue(componentId < ENTITY_COMPONENT_COUNT_MAX, "Component ID OOB");
componentindex_t index = componentGetIndex(entityId, componentId);
component_t *cmp = &mgr->components[index];
component_t *cmp = &COMPONENTS[index];
if(cmp->type == COMPONENT_TYPE_NULL) return;
if(COMPONENT_DEFINITIONS[cmp->type].dispose) {
COMPONENT_DEFINITIONS[cmp->type].dispose(mgr, entityId, componentId);
COMPONENT_DEFINITIONS[cmp->type].dispose(entityId, componentId);
}
cmp->type = COMPONENT_TYPE_NULL;
+1 -14
View File
@@ -23,12 +23,10 @@ typedef union {
/**
* Callback signature for a component's init/dispose hooks.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
*/
typedef void (*componentcallback_t)(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
);
@@ -36,13 +34,11 @@ typedef void (*componentcallback_t)(
/**
* Callback signature for a component's render hook.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @return Error state.
*/
typedef errorret_t (*componentcallbackerror_t)(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
);
@@ -76,13 +72,11 @@ extern componentdefinition_t COMPONENT_DEFINITIONS[];
/**
* Initializes a component of the given type for the entity with component ID.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param type The type of the component to initialize.
*/
void componentInit(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const componenttype_t type
@@ -91,14 +85,12 @@ void componentInit(
/**
* Gets the pointer to the data of a component for the entity with component ID.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param type The type of the component to get, only used for assertion.
* @return A pointer to the component data.
*/
void * componentGetData(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const componenttype_t type
@@ -119,7 +111,6 @@ componentindex_t componentGetIndex(
/**
* Gets the entity IDs of all entities with a component of the given type.
*
* @param mgr The entity manager to search.
* @param type The type of the component to get entities for.
* @param outEntities An array to write the entity IDs to, must be at least
* ENTITY_COUNT_MAX in size.
@@ -127,7 +118,6 @@ componentindex_t componentGetIndex(
* @return The number of entity IDs written to outEntities.
*/
entityid_t componentGetEntitiesWithComponent(
entitymanager_t *mgr,
const componenttype_t type,
entityid_t outEntities[ENTITY_COUNT_MAX],
componentid_t outComponents[ENTITY_COUNT_MAX]
@@ -136,12 +126,10 @@ entityid_t componentGetEntitiesWithComponent(
/**
* Disposes of a component for the entity with component ID.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
*/
void componentDispose(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
);
@@ -151,7 +139,6 @@ void componentDispose(
* Iterates all active entities and all their component slots. No-op for
* components whose definition has render == NULL.
*
* @param mgr The entity manager to render.
* @return Error state.
*/
errorret_t componentRenderAll(entitymanager_t *mgr);
errorret_t componentRenderAll(void);
@@ -6,53 +6,49 @@
*/
#include "entityanimation.h"
#include "entity/entitymanager.h"
#include "entity/entity.h"
#include "util/memory.h"
#include "time/time.h"
void entityAnimationInit(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
) {
entityanimation_t *animComp = entityAnimationGet(mgr, entityId, componentId);
entityanimation_t *animComp = entityAnimationGet(entityId, componentId);
memoryZero(animComp, sizeof(entityanimation_t));
animComp->speed = 1.0f;
entityUpdateAdd(mgr, entityId, entityAnimationUpdate, componentId, NULL);
entityUpdateAdd(entityId, entityAnimationUpdate, componentId, NULL);
}
entityanimation_t *entityAnimationGet(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
) {
return componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_ANIMATION
entityId, componentId, COMPONENT_TYPE_ANIMATION
);
}
void entityAnimationSetKeyframes(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
keyframe_t *keyframes,
uint16_t *keyframeCounts,
const uint16_t layerCount
) {
entityanimation_t *animComp = entityAnimationGet(mgr, entityId, componentId);
entityanimation_t *animComp = entityAnimationGet(entityId, componentId);
animationInit(&animComp->anim, keyframes, keyframeCounts, layerCount);
animComp->speed = 1.0f;
animComp->playing = false;
}
void entityAnimationPlay(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
) {
entityanimation_t *animComp = entityAnimationGet(mgr, entityId, componentId);
entityanimation_t *animComp = entityAnimationGet(entityId, componentId);
animComp->anim.time = 0.0f;
// Clear the internal completed latch so a previously-finished
// (non-looping) animation can actually advance again.
@@ -61,61 +57,55 @@ void entityAnimationPlay(
}
void entityAnimationStop(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
) {
entityanimation_t *animComp = entityAnimationGet(mgr, entityId, componentId);
entityanimation_t *animComp = entityAnimationGet(entityId, componentId);
animComp->playing = false;
}
bool_t entityAnimationIsPlaying(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
) {
entityanimation_t *animComp = entityAnimationGet(mgr, entityId, componentId);
entityanimation_t *animComp = entityAnimationGet(entityId, componentId);
return animComp->playing;
}
void entityAnimationSetLoop(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const bool_t loop
) {
entityanimation_t *animComp = entityAnimationGet(mgr, entityId, componentId);
entityanimation_t *animComp = entityAnimationGet(entityId, componentId);
if(loop) animComp->anim.flags |= ANIMATION_FLAG_LOOP;
else animComp->anim.flags &= ~ANIMATION_FLAG_LOOP;
}
void entityAnimationSetSpeed(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const float_t speed
) {
entityanimation_t *animComp = entityAnimationGet(mgr, entityId, componentId);
entityanimation_t *animComp = entityAnimationGet(entityId, componentId);
animComp->speed = speed;
}
float_t entityAnimationGetValue(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const uint16_t channelIndex
) {
entityanimation_t *animComp = entityAnimationGet(mgr, entityId, componentId);
entityanimation_t *animComp = entityAnimationGet(entityId, componentId);
return animationGetLayerValue(&animComp->anim, channelIndex);
}
void entityAnimationUpdate(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
void *user
) {
entityanimation_t *animComp = entityAnimationGet(mgr, entityId, componentId);
entityanimation_t *animComp = entityAnimationGet(entityId, componentId);
if(!animComp->playing) return;
animationUpdate(&animComp->anim, TIME.delta * animComp->speed);
}
@@ -34,12 +34,10 @@ typedef struct {
* entityAnimationUpdate as an update callback. Call
* entityAnimationSetKeyframes() before entityAnimationPlay().
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
*/
void entityAnimationInit(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
);
@@ -48,14 +46,12 @@ void entityAnimationInit(
* Gets the underlying animation structure (temporarily) for the given
* entity. Prefer the dedicated getters/setters where possible.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @return The animation component data for the given entity and
* component ID.
*/
entityanimation_t *entityAnimationGet(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
);
@@ -66,7 +62,6 @@ entityanimation_t *entityAnimationGet(
* they point to are not copied, and must outlive this component (e.g.
* static/const arrays owned by the caller).
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param keyframes Flat array of keyframe_t, one contiguous run per layer
@@ -76,7 +71,6 @@ entityanimation_t *entityAnimationGet(
* @param layerCount The number of layers/channels.
*/
void entityAnimationSetKeyframes(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
keyframe_t *keyframes,
@@ -87,12 +81,10 @@ void entityAnimationSetKeyframes(
/**
* Starts (or restarts) playback from time 0.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
*/
void entityAnimationPlay(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
);
@@ -100,12 +92,10 @@ void entityAnimationPlay(
/**
* Stops playback without resetting the current time.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
*/
void entityAnimationStop(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
);
@@ -113,13 +103,11 @@ void entityAnimationStop(
/**
* Checks whether the animation is currently playing.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @return True if playing.
*/
bool_t entityAnimationIsPlaying(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
);
@@ -128,13 +116,11 @@ bool_t entityAnimationIsPlaying(
* Sets whether the animation loops on reaching its final keyframe, rather
* than stopping there.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param loop True to loop, false to stop at the end.
*/
void entityAnimationSetLoop(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const bool_t loop
@@ -143,13 +129,11 @@ void entityAnimationSetLoop(
/**
* Sets the animation's playback rate multiplier.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param speed The new playback rate; 1.0 = normal speed.
*/
void entityAnimationSetSpeed(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const float_t speed
@@ -159,7 +143,6 @@ void entityAnimationSetSpeed(
* Evaluates one of the animation's channels at its current playback
* time, regardless of whether it's currently playing.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param channelIndex The channel to evaluate, in [0, channelCount) as
@@ -167,7 +150,6 @@ void entityAnimationSetSpeed(
* @return That channel's value at the current time.
*/
float_t entityAnimationGetValue(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const uint16_t channelIndex
@@ -178,13 +160,11 @@ float_t entityAnimationGetValue(
* (a no-op if not playing). Registered automatically as an update
* callback by entityAnimationInit.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param user Unused.
*/
void entityAnimationUpdate(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
void *user
@@ -5,18 +5,16 @@
* https://opensource.org/licenses/MIT
*/
#include "entity/entitymanager.h"
#include "entity/entity.h"
#include "entity/component/display/entityposition.h"
#include "display/screen/screen.h"
void entityCameraInit(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
) {
entitycamera_t *cam = (entitycamera_t *)componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_CAMERA
entityId, componentId, COMPONENT_TYPE_CAMERA
);
cam->nearClip = 0.1f;
cam->farClip = 5000.0f;
@@ -25,13 +23,12 @@ void entityCameraInit(
}
void entityCameraGetProjection(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
mat4 out
) {
entitycamera_t *cam = (entitycamera_t *)componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_CAMERA
entityId, componentId, COMPONENT_TYPE_CAMERA
);
if(
@@ -64,26 +61,25 @@ void entityCameraGetProjection(
}
}
entityid_t entityCameraGetCurrent(entitymanager_t *mgr) {
entityid_t entityCameraGetCurrent(void) {
entityid_t camEnts[ENTITY_COUNT_MAX];
componentid_t camComps[ENTITY_COUNT_MAX];
entityid_t count = componentGetEntitiesWithComponent(
mgr, COMPONENT_TYPE_CAMERA, camEnts, camComps
COMPONENT_TYPE_CAMERA, camEnts, camComps
);
if(count == 0) return ENTITY_ID_INVALID;
return camEnts[0];
}
void entityCameraGetForward(
entitymanager_t *mgr,
const entityid_t entityId,
vec2 out
) {
componentid_t posComp = entityGetComponent(
mgr, entityId, COMPONENT_TYPE_POSITION
entityId, COMPONENT_TYPE_POSITION
);
mat4 transform;
entityPositionGetTransform(mgr, entityId, posComp, transform);
entityPositionGetTransform(entityId, posComp, transform);
// transform is an object->world matrix; column 2 is the entity's local Z
// axis expressed in world space. Cameras look down their local -Z.
float_t fx = -transform[2][0];
@@ -95,15 +91,14 @@ void entityCameraGetForward(
}
void entityCameraGetRight(
entitymanager_t *mgr,
const entityid_t entityId,
vec2 out
) {
componentid_t posComp = entityGetComponent(
mgr, entityId, COMPONENT_TYPE_POSITION
entityId, COMPONENT_TYPE_POSITION
);
mat4 transform;
entityPositionGetTransform(mgr, entityId, posComp, transform);
entityPositionGetTransform(entityId, posComp, transform);
// transform is an object->world matrix; column 0 is the entity's local X
// (right) axis expressed in world space.
float_t rx = transform[0][0];
@@ -115,7 +110,6 @@ void entityCameraGetRight(
}
void entityCameraLookAtPixelPerfect(
entitymanager_t *mgr,
const entityid_t ent,
const componentid_t posComp,
const componentid_t camComp,
@@ -124,7 +118,7 @@ void entityCameraLookAtPixelPerfect(
const float_t scale
) {
entitycamera_t *cam = (entitycamera_t *)componentGetData(
mgr, ent, camComp, COMPONENT_TYPE_CAMERA
ent, camComp, COMPONENT_TYPE_CAMERA
);
float_t dist = (
(float_t)SCREEN.height / (2.0f * scale * tanf(cam->perspective.fov * 0.5f))
@@ -136,5 +130,5 @@ void entityCameraLookAtPixelPerfect(
point[2] + eyeOffset[2]
};
vec3 up = { 0.0f, 0.0f, -1.0f };
entityPositionLookAt(mgr, ent, posComp, eye, (float_t *)point, up);
entityPositionLookAt(ent, posComp, eye, (float_t *)point, up);
}
@@ -37,12 +37,10 @@ typedef struct {
/**
* Initializes an entity camera component.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
*/
void entityCameraInit(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
);
@@ -50,13 +48,11 @@ void entityCameraInit(
/**
* Renders out the projection matrix for the given camera.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param out The output projection matrix.
*/
void entityCameraGetProjection(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
mat4 out
@@ -66,21 +62,18 @@ void entityCameraGetProjection(
* Returns the entity ID of the first active camera, or ENTITY_ID_INVALID if
* none are active.
*
* @param mgr The entity manager to search.
*/
entityid_t entityCameraGetCurrent(entitymanager_t *mgr);
entityid_t entityCameraGetCurrent(void);
/**
* Gets the camera's horizontal forward direction (XZ plane) from its
* position component. Automatically finds the position component on the
* entity.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The camera entity ID.
* @param out Output vec2: {forwardX, forwardZ} normalized.
*/
void entityCameraGetForward(
entitymanager_t *mgr,
const entityid_t entityId,
vec2 out
);
@@ -89,12 +82,10 @@ void entityCameraGetForward(
* Gets the camera's horizontal right direction (XZ plane) from its position
* component. Automatically finds the position component on the entity.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The camera entity ID.
* @param out Output vec2: {rightX, rightZ} normalized.
*/
void entityCameraGetRight(
entitymanager_t *mgr,
const entityid_t entityId,
vec2 out
);
@@ -103,7 +94,6 @@ void entityCameraGetRight(
* Positions the camera to look at a 3D point at a pixel-perfect distance
* derived from the camera's FOV and screen height.
*
* @param mgr The entity manager that owns the entity.
* @param ent The camera entity ID.
* @param posComp The position component ID.
* @param camComp The camera component ID.
@@ -112,7 +102,6 @@ void entityCameraGetRight(
* @param scale Pixels per world unit. 1.0 = pixel perfect, 2.0 = 2px per unit.
*/
void entityCameraLookAtPixelPerfect(
entitymanager_t *mgr,
const entityid_t ent,
const componentid_t posComp,
const componentid_t camComp,
@@ -5,16 +5,15 @@
* https://opensource.org/licenses/MIT
*/
#include "entity/entitymanager.h"
#include "entity/entity.h"
#include "assert/assert.h"
void entityPositionInit(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
) {
entityposition_t *pos = componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
entityId, componentId, COMPONENT_TYPE_POSITION
);
pos->flags = 0;
@@ -29,7 +28,6 @@ void entityPositionInit(
}
void entityPositionLookAt(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 eye,
@@ -37,7 +35,7 @@ void entityPositionLookAt(
vec3 up
) {
entityposition_t *pos = componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
entityId, componentId, COMPONENT_TYPE_POSITION
);
// glm_lookat() produces a view matrix (world -> eye space). Every other
// setter treats localTransform as this entity's placement in world space
@@ -50,19 +48,18 @@ void entityPositionLookAt(
pos->flags = (pos->flags | ENTITY_POSITION_FLAG_PRS_DIRTY)
& ~(ENTITY_POSITION_FLAG_ROTATION_DIRTY |
ENTITY_POSITION_FLAG_POSITION_DIRTY);
entityPositionMarkDirty(mgr, pos);
entityPositionMarkDirty(pos);
}
void entityPositionGetTransform(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
mat4 dest
) {
entityposition_t *pos = componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
entityId, componentId, COMPONENT_TYPE_POSITION
);
entityPositionEnsureWorld(mgr, pos);
entityPositionEnsureWorld(pos);
glm_mat4_copy(
pos->parentEntityId == ENTITY_ID_INVALID
? pos->localTransform : pos->worldTransform,
@@ -71,71 +68,67 @@ void entityPositionGetTransform(
}
void entityPositionGetLocalTransform(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
mat4 dest
) {
entityposition_t *pos = componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
entityId, componentId, COMPONENT_TYPE_POSITION
);
entityPositionEnsureLocal(pos);
glm_mat4_copy(pos->localTransform, dest);
}
void entityPositionGetLocalPosition(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
) {
entityposition_t *pos = componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
entityId, componentId, COMPONENT_TYPE_POSITION
);
entityPositionEnsurePRS(pos);
glm_vec3_copy(pos->position, dest);
}
void entityPositionGetWorldPosition(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
) {
entityposition_t *pos = componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
entityId, componentId, COMPONENT_TYPE_POSITION
);
if(pos->parentEntityId == ENTITY_ID_INVALID) {
entityPositionEnsurePRS(pos);
glm_vec3_copy(pos->position, dest);
return;
}
entityPositionEnsureWorld(mgr, pos);
entityPositionEnsureWorld(pos);
dest[0] = pos->worldTransform[3][0];
dest[1] = pos->worldTransform[3][1];
dest[2] = pos->worldTransform[3][2];
}
void entityPositionSetWorldPosition(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 position
) {
entityposition_t *pos = componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
entityId, componentId, COMPONENT_TYPE_POSITION
);
if(pos->parentEntityId == ENTITY_ID_INVALID) {
glm_vec3_copy(position, pos->position);
pos->flags = (pos->flags | ENTITY_POSITION_FLAG_POSITION_DIRTY)
& ~ENTITY_POSITION_FLAG_PRS_DIRTY;
entityPositionMarkDirty(mgr, pos);
entityPositionMarkDirty(pos);
return;
}
entityposition_t *parent = componentGetData(
mgr, pos->parentEntityId, pos->parentComponentId, COMPONENT_TYPE_POSITION
pos->parentEntityId, pos->parentComponentId, COMPONENT_TYPE_POSITION
);
entityPositionEnsureWorld(mgr, parent);
entityPositionEnsureWorld(parent);
mat4 invParent;
glm_mat4_inv(parent->worldTransform, invParent);
vec3 localPos;
@@ -143,52 +136,49 @@ void entityPositionSetWorldPosition(
glm_vec3_copy(localPos, pos->position);
pos->flags = (pos->flags | ENTITY_POSITION_FLAG_POSITION_DIRTY)
& ~ENTITY_POSITION_FLAG_PRS_DIRTY;
entityPositionMarkDirty(mgr, pos);
entityPositionMarkDirty(pos);
}
void entityPositionSetLocalPosition(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 position
) {
entityposition_t *pos = componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
entityId, componentId, COMPONENT_TYPE_POSITION
);
glm_vec3_copy(position, pos->position);
pos->flags = (pos->flags | ENTITY_POSITION_FLAG_POSITION_DIRTY)
& ~ENTITY_POSITION_FLAG_PRS_DIRTY;
entityPositionMarkDirty(mgr, pos);
entityPositionMarkDirty(pos);
}
void entityPositionGetLocalRotation(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
) {
entityposition_t *pos = componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
entityId, componentId, COMPONENT_TYPE_POSITION
);
entityPositionEnsurePRS(pos);
glm_vec3_copy(pos->rotation, dest);
}
void entityPositionGetWorldRotation(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
) {
entityposition_t *pos = componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
entityId, componentId, COMPONENT_TYPE_POSITION
);
if(pos->parentEntityId == ENTITY_ID_INVALID) {
entityPositionEnsurePRS(pos);
glm_vec3_copy(pos->rotation, dest);
return;
}
entityPositionEnsureWorld(mgr, pos);
entityPositionEnsureWorld(pos);
const float_t (*wt)[4] = pos->worldTransform;
const float_t sx = sqrtf(
wt[0][0]*wt[0][0] + wt[0][1]*wt[0][1] + wt[0][2]*wt[0][2]
@@ -219,40 +209,38 @@ void entityPositionGetWorldRotation(
}
void entityPositionSetLocalRotation(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 rotation
) {
entityposition_t *pos = componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
entityId, componentId, COMPONENT_TYPE_POSITION
);
glm_vec3_copy(rotation, pos->rotation);
pos->flags = (pos->flags | ENTITY_POSITION_FLAG_ROTATION_DIRTY)
& ~ENTITY_POSITION_FLAG_PRS_DIRTY;
entityPositionMarkDirty(mgr, pos);
entityPositionMarkDirty(pos);
}
void entityPositionSetWorldRotation(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 rotation
) {
entityposition_t *pos = componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
entityId, componentId, COMPONENT_TYPE_POSITION
);
if(pos->parentEntityId == ENTITY_ID_INVALID) {
glm_vec3_copy(rotation, pos->rotation);
pos->flags = (pos->flags | ENTITY_POSITION_FLAG_ROTATION_DIRTY)
& ~ENTITY_POSITION_FLAG_PRS_DIRTY;
entityPositionMarkDirty(mgr, pos);
entityPositionMarkDirty(pos);
return;
}
entityposition_t *parent = componentGetData(
mgr, pos->parentEntityId, pos->parentComponentId, COMPONENT_TYPE_POSITION
pos->parentEntityId, pos->parentComponentId, COMPONENT_TYPE_POSITION
);
entityPositionEnsureWorld(mgr, parent);
entityPositionEnsureWorld(parent);
// Build target world rotation matrix (unit scale) from XYZ euler.
const float_t c0 = cosf(rotation[0]), s0 = sinf(rotation[0]);
@@ -319,37 +307,35 @@ void entityPositionSetWorldRotation(
}
pos->flags = (pos->flags | ENTITY_POSITION_FLAG_ROTATION_DIRTY)
& ~ENTITY_POSITION_FLAG_PRS_DIRTY;
entityPositionMarkDirty(mgr, pos);
entityPositionMarkDirty(pos);
}
void entityPositionGetLocalScale(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
) {
entityposition_t *pos = componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
entityId, componentId, COMPONENT_TYPE_POSITION
);
entityPositionEnsurePRS(pos);
glm_vec3_copy(pos->scale, dest);
}
void entityPositionGetWorldScale(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
) {
entityposition_t *pos = componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
entityId, componentId, COMPONENT_TYPE_POSITION
);
if(pos->parentEntityId == ENTITY_ID_INVALID) {
entityPositionEnsurePRS(pos);
glm_vec3_copy(pos->scale, dest);
return;
}
entityPositionEnsureWorld(mgr, pos);
entityPositionEnsureWorld(pos);
const float_t (*wt)[4] = pos->worldTransform;
dest[0] = sqrtf(wt[0][0]*wt[0][0] + wt[0][1]*wt[0][1] + wt[0][2]*wt[0][2]);
dest[1] = sqrtf(wt[1][0]*wt[1][0] + wt[1][1]*wt[1][1] + wt[1][2]*wt[1][2]);
@@ -357,40 +343,38 @@ void entityPositionGetWorldScale(
}
void entityPositionSetLocalScale(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 scale
) {
entityposition_t *pos = componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
entityId, componentId, COMPONENT_TYPE_POSITION
);
glm_vec3_copy(scale, pos->scale);
pos->flags = (pos->flags | ENTITY_POSITION_FLAG_ROTATION_DIRTY)
& ~ENTITY_POSITION_FLAG_PRS_DIRTY;
entityPositionMarkDirty(mgr, pos);
entityPositionMarkDirty(pos);
}
void entityPositionSetWorldScale(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 scale
) {
entityposition_t *pos = componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
entityId, componentId, COMPONENT_TYPE_POSITION
);
if(pos->parentEntityId == ENTITY_ID_INVALID) {
glm_vec3_copy(scale, pos->scale);
pos->flags = (pos->flags | ENTITY_POSITION_FLAG_ROTATION_DIRTY)
& ~ENTITY_POSITION_FLAG_PRS_DIRTY;
entityPositionMarkDirty(mgr, pos);
entityPositionMarkDirty(pos);
return;
}
entityposition_t *parent = componentGetData(
mgr, pos->parentEntityId, pos->parentComponentId, COMPONENT_TYPE_POSITION
pos->parentEntityId, pos->parentComponentId, COMPONENT_TYPE_POSITION
);
entityPositionEnsureWorld(mgr, parent);
entityPositionEnsureWorld(parent);
const float_t (*pt)[4] = parent->worldTransform;
const float_t psx = sqrtf(
pt[0][0]*pt[0][0] + pt[0][1]*pt[0][1] + pt[0][2]*pt[0][2]
@@ -406,24 +390,23 @@ void entityPositionSetWorldScale(
pos->scale[2] = psz > 0.0f ? scale[2] / psz : scale[2];
pos->flags = (pos->flags | ENTITY_POSITION_FLAG_ROTATION_DIRTY)
& ~ENTITY_POSITION_FLAG_PRS_DIRTY;
entityPositionMarkDirty(mgr, pos);
entityPositionMarkDirty(pos);
}
void entityPositionSetParent(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const entityid_t parentEntityId,
const componentid_t parentComponentId
) {
entityposition_t *pos = componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
entityId, componentId, COMPONENT_TYPE_POSITION
);
// Remove from old parent's child list.
if(pos->parentEntityId != ENTITY_ID_INVALID) {
entityposition_t *oldParent = componentGetData(
mgr, pos->parentEntityId, pos->parentComponentId,
pos->parentEntityId, pos->parentComponentId,
COMPONENT_TYPE_POSITION
);
for(uint8_t i = 0; i < oldParent->childCount; i++) {
@@ -447,7 +430,7 @@ void entityPositionSetParent(
// Register with new parent.
if(parentEntityId != ENTITY_ID_INVALID) {
entityposition_t *parent = componentGetData(
mgr, parentEntityId, parentComponentId, COMPONENT_TYPE_POSITION
parentEntityId, parentComponentId, COMPONENT_TYPE_POSITION
);
if(parent->childCount < ENTITY_POSITION_CHILDREN_MAX) {
parent->childEntityIds[parent->childCount] = entityId;
@@ -456,62 +439,59 @@ void entityPositionSetParent(
}
}
entityPositionMarkDirty(mgr, pos);
entityPositionMarkDirty(pos);
}
entityid_t entityPositionGetParent(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
) {
entityposition_t *pos = componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
entityId, componentId, COMPONENT_TYPE_POSITION
);
return pos->parentEntityId;
}
entityposition_t *entityPositionGet(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
) {
return componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
entityId, componentId, COMPONENT_TYPE_POSITION
);
}
void entityPositionRebuild(entitymanager_t *mgr, entityposition_t *pos) {
void entityPositionRebuild(entityposition_t *pos) {
pos->flags = (
pos->flags |
ENTITY_POSITION_FLAG_ROTATION_DIRTY |
ENTITY_POSITION_FLAG_POSITION_DIRTY
) & ~ENTITY_POSITION_FLAG_PRS_DIRTY;
entityPositionMarkDirty(mgr, pos);
entityPositionMarkDirty(pos);
}
void entityPositionMarkDirty(entitymanager_t *mgr, entityposition_t *pos) {
void entityPositionMarkDirty(entityposition_t *pos) {
if(pos->flags & ENTITY_POSITION_FLAG_WORLD_DIRTY) return;
pos->flags |= ENTITY_POSITION_FLAG_WORLD_DIRTY;
for(uint8_t i = 0; i < pos->childCount; i++) {
entityposition_t *child = componentGetData(
mgr, pos->childEntityIds[i], pos->childComponentIds[i],
pos->childEntityIds[i], pos->childComponentIds[i],
COMPONENT_TYPE_POSITION
);
entityPositionMarkDirty(mgr, child);
entityPositionMarkDirty(child);
}
}
void entityPositionDisposeDeep(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
) {
entityposition_t *pos = entityPositionGet(mgr, entityId, 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(
mgr, entityId, componentId, ENTITY_ID_INVALID, COMPONENT_ID_INVALID
entityId, componentId, ENTITY_ID_INVALID, COMPONENT_ID_INVALID
);
}
@@ -526,16 +506,16 @@ void entityPositionDisposeDeep(
// Sever child's parent link so it won't try to modify our disposed
// data.
entityposition_t *child = entityPositionGet(
mgr, childEntityIds[i], childComponentIds[i]
childEntityIds[i], childComponentIds[i]
);
child->parentEntityId = ENTITY_ID_INVALID;
child->parentComponentId = COMPONENT_ID_INVALID;
}
entityDispose(mgr, entityId);
entityDispose(entityId);
for(uint8_t i = 0; i < childCount; i++) {
entityPositionDisposeDeep(mgr, childEntityIds[i], childComponentIds[i]);
entityPositionDisposeDeep(childEntityIds[i], childComponentIds[i]);
}
}
@@ -642,7 +622,7 @@ void entityPositionEnsureLocal(entityposition_t *pos) {
);
}
void entityPositionEnsureWorld(entitymanager_t *mgr, entityposition_t *pos) {
void entityPositionEnsureWorld(entityposition_t *pos) {
if(!(pos->flags & ENTITY_POSITION_FLAG_WORLD_DIRTY)) return;
entityPositionEnsureLocal(pos);
@@ -650,10 +630,10 @@ void entityPositionEnsureWorld(entitymanager_t *mgr, entityposition_t *pos) {
// Parented: world = parent.world x local. worldTransform must be
// written because children (and this node's getters) read it.
entityposition_t *parent = componentGetData(
mgr, pos->parentEntityId, pos->parentComponentId,
pos->parentEntityId, pos->parentComponentId,
COMPONENT_TYPE_POSITION
);
entityPositionEnsureWorld(mgr, parent);
entityPositionEnsureWorld(parent);
glm_mat4_mul(
parent->worldTransform, pos->localTransform, pos->worldTransform
);
@@ -83,12 +83,10 @@ typedef struct {
* Initializes the entity position component, setting identity transforms and
* zeroing all parent/child state.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
*/
void entityPositionInit(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
);
@@ -99,7 +97,6 @@ void entityPositionInit(
* setter), not as a view matrix -- invert entityPositionGetTransform()'s
* result to get a view matrix for rendering.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param eye The eye/camera position.
@@ -107,7 +104,6 @@ void entityPositionInit(
* @param up The up vector.
*/
void entityPositionLookAt(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 eye,
@@ -118,13 +114,11 @@ void entityPositionLookAt(
/**
* Gets the world-space transform matrix, recomputing it lazily if dirty.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param dest Destination matrix.
*/
void entityPositionGetTransform(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
mat4 dest
@@ -133,13 +127,11 @@ void entityPositionGetTransform(
/**
* Gets the local transform matrix (does not include parent transforms).
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param dest Destination matrix.
*/
void entityPositionGetLocalTransform(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
mat4 dest
@@ -150,13 +142,11 @@ void entityPositionGetLocalTransform(
* first if ENTITY_POSITION_FLAG_PRS_DIRTY is set; never triggers a matrix
* rebuild or world-transform update.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param dest Destination vector.
*/
void entityPositionGetLocalPosition(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
@@ -166,13 +156,11 @@ void entityPositionGetLocalPosition(
* Gets the world-space position. For parentless entities this is the same as
* the local position.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param dest Destination vector.
*/
void entityPositionGetWorldPosition(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
@@ -183,13 +171,11 @@ void entityPositionGetWorldPosition(
* to entityPositionSetLocalPosition. For parented entities the position is
* converted to local space via the inverted parent world transform.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param position The desired world-space position.
*/
void entityPositionSetWorldPosition(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 position
@@ -199,13 +185,11 @@ void entityPositionSetWorldPosition(
* Sets the local position, marks localTransform and worldTransform (self +
* descendants) dirty.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param position The new local position.
*/
void entityPositionSetLocalPosition(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 position
@@ -215,13 +199,11 @@ void entityPositionSetLocalPosition(
* Gets the cached local euler rotation (XYZ, radians). Decomposes
* localTransform first if ENTITY_POSITION_FLAG_PRS_DIRTY is set.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param dest Destination vector.
*/
void entityPositionGetLocalRotation(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
@@ -232,13 +214,11 @@ void entityPositionGetLocalRotation(
* world transform. For parentless entities this is the same as local
* rotation.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param dest Destination vector.
*/
void entityPositionGetWorldRotation(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
@@ -247,13 +227,11 @@ void entityPositionGetWorldRotation(
/**
* Sets the local euler rotation (XYZ, radians) and marks transforms dirty.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param rotation The new local rotation.
*/
void entityPositionSetLocalRotation(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 rotation
@@ -265,13 +243,11 @@ void entityPositionSetLocalRotation(
* parented entities the rotation is converted to local space by removing
* the parent world rotation.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param rotation The desired world-space euler rotation.
*/
void entityPositionSetWorldRotation(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 rotation
@@ -281,13 +257,11 @@ void entityPositionSetWorldRotation(
* Gets the cached local scale. Decomposes localTransform first if
* ENTITY_POSITION_FLAG_PRS_DIRTY is set.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param dest Destination vector.
*/
void entityPositionGetLocalScale(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
@@ -297,13 +271,11 @@ void entityPositionGetLocalScale(
* Gets the world-space scale by extracting column lengths from the world
* transform. For parentless entities this is the same as local scale.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param dest Destination vector.
*/
void entityPositionGetWorldScale(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
@@ -312,13 +284,11 @@ void entityPositionGetWorldScale(
/**
* Sets the local scale and marks transforms dirty.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param scale The new local scale.
*/
void entityPositionSetLocalScale(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 scale
@@ -329,13 +299,11 @@ void entityPositionSetLocalScale(
* entityPositionSetLocalScale. For parented entities the scale is converted
* to local space by dividing by the parent world scale (assumes no shear).
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param scale The desired world-space scale.
*/
void entityPositionSetWorldScale(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 scale
@@ -345,14 +313,12 @@ void entityPositionSetWorldScale(
* Sets the parent of this entity's position component.
* Pass ENTITY_ID_INVALID / COMPONENT_ID_INVALID to detach from any parent.
*
* @param mgr The entity manager that owns both entities.
* @param entityId The child entity ID.
* @param componentId The child component ID.
* @param parentEntityId The parent entity ID.
* @param parentComponentId The parent component ID.
*/
void entityPositionSetParent(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const entityid_t parentEntityId,
@@ -362,13 +328,11 @@ void entityPositionSetParent(
/**
* Gets the entity ID of this position component's parent.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @return The parent entity ID, or ENTITY_ID_INVALID if unparented.
*/
entityid_t entityPositionGetParent(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
);
@@ -379,13 +343,11 @@ entityid_t entityPositionGetParent(
* set ENTITY_POSITION_FLAG_WORLD_DIRTY on self and descendants. After
* modifying PRS directly, call entityPositionRebuild() instead.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @return Pointer to the component data.
*/
entityposition_t *entityPositionGet(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
);
@@ -397,31 +359,27 @@ entityposition_t *entityPositionGet(
* ENTITY_POSITION_FLAG_PRS_DIRTY, propagates ENTITY_POSITION_FLAG_WORLD_DIRTY
* to self and all descendants.
*
* @param mgr The entity manager that owns pos and its descendants.
* @param pos The position component whose PRS was modified.
*/
void entityPositionRebuild(entitymanager_t *mgr, entityposition_t *pos);
void entityPositionRebuild(entityposition_t *pos);
/**
* Sets ENTITY_POSITION_FLAG_WORLD_DIRTY on this node and all descendants,
* indicating that worldTransform must be recomputed before it is read.
* Call this after modifying localTransform directly.
*
* @param mgr The entity manager that owns pos and its descendants.
* @param pos The position component to mark dirty.
*/
void entityPositionMarkDirty(entitymanager_t *mgr, entityposition_t *pos);
void entityPositionMarkDirty(entityposition_t *pos);
/**
* Disposes this entity and all of its position-component descendants
* recursively. Detaches from any parent before destroying.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The root entity ID.
* @param componentId The root position component ID.
*/
void entityPositionDisposeDeep(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
);
@@ -454,7 +412,6 @@ void entityPositionEnsureLocal(entityposition_t *pos);
* Internal. Recomputes worldTransform from the parent chain if
* ENTITY_POSITION_FLAG_WORLD_DIRTY is set.
*
* @param mgr The entity manager that owns pos and its ancestors.
* @param pos The position component to update.
*/
void entityPositionEnsureWorld(entitymanager_t *mgr, entityposition_t *pos);
void entityPositionEnsureWorld(entityposition_t *pos);
@@ -6,7 +6,7 @@
*/
#include "entityrenderable.h"
#include "entity/entitymanager.h"
#include "entity/entity.h"
#include "display/shader/shadermaterial.h"
#include "display/shader/shaderunlit.h"
#include "display/display.h"
@@ -15,12 +15,11 @@
#include "assert/assert.h"
void entityRenderableInit(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
) {
entityrenderable_t *r = componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_RENDERABLE
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
memoryZero(r, sizeof(entityrenderable_t));
r->type = ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL;
@@ -34,44 +33,40 @@ void entityRenderableInit(
}
void entityRenderableDispose(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
) {
}
void entityRenderableSetType(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const entityrenderabletype_t type
) {
entityrenderable_t *r = componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_RENDERABLE
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
r->type = type;
}
void entityRenderableSetPriority(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const int8_t priority
) {
entityrenderable_t *r = componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_RENDERABLE
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
r->priority = priority;
}
void entityRenderableSetColor(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const color_t color
) {
entityrenderable_t *r = componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_RENDERABLE
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
assertTrue(
r->type == ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL,
@@ -81,7 +76,6 @@ void entityRenderableSetColor(
}
void entityRenderableSetMesh(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const uint8_t slot,
@@ -91,7 +85,7 @@ void entityRenderableSetMesh(
assertTrue(slot < ENTITY_RENDERABLE_MESHES_MAX, "Mesh slot out of bounds");
entityrenderable_t *r = componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_RENDERABLE
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
assertTrue(
r->type == ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL,
@@ -107,11 +101,9 @@ void entityRenderableSetMesh(
}
void entityRenderableSetDraw(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
errorret_t (*draw)(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
void *user
@@ -120,7 +112,7 @@ void entityRenderableSetDraw(
) {
assertNotNull(draw, "Draw callback cannot be null");
entityrenderable_t *r = componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_RENDERABLE
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
r->type = ENTITY_RENDERABLE_TYPE_CUSTOM;
r->data.custom.draw = draw;
@@ -128,12 +120,11 @@ void entityRenderableSetDraw(
}
errorret_t entityRenderableDraw(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
) {
entityrenderable_t *r = componentGetData(
mgr, entityId, componentId, COMPONENT_TYPE_RENDERABLE
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
switch(r->type) {
case ENTITY_RENDERABLE_TYPE_SPRITEBATCH:
@@ -142,7 +133,7 @@ errorret_t entityRenderableDraw(
return entityRenderableDrawMaterial(&r->data.material);
case ENTITY_RENDERABLE_TYPE_CUSTOM:
return entityRenderableDrawCustom(
mgr, entityId, componentId, &r->data.custom
entityId, componentId, &r->data.custom
);
default:
assertUnreachable("Invalid renderable type");
@@ -183,10 +174,9 @@ errorret_t entityRenderableDrawMaterial(const entityrenderablematerial_t *m) {
}
errorret_t entityRenderableDrawCustom(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const entityrenderablecustom_t *custom
) {
return custom->draw(mgr, entityId, componentId, custom->drawUser);
return custom->draw(entityId, componentId, custom->drawUser);
}
@@ -40,7 +40,6 @@ typedef struct {
typedef struct {
errorret_t (*draw)(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
void *user
@@ -70,12 +69,10 @@ typedef struct {
* ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL with the unlit shader, a white
* cube, and depth-test enabled.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity to initialize the component for.
* @param componentId The renderable component of the entity.
*/
void entityRenderableInit(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
);
@@ -83,12 +80,10 @@ void entityRenderableInit(
/**
* Disposes the entity renderable component.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity to dispose the component for.
* @param componentId The renderable component of the entity.
*/
void entityRenderableDispose(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
);
@@ -97,13 +92,11 @@ void entityRenderableDispose(
* Sets the rendering type for the renderable component. Resets
* type-specific data to zero.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity to configure.
* @param componentId The renderable component.
* @param type The rendering type to use.
*/
void entityRenderableSetType(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const entityrenderabletype_t type
@@ -113,13 +106,11 @@ void entityRenderableSetType(
* Sets the render priority. 0 = auto (derived from type/flags). Higher
* values render later (on top). Use non-zero to force ordering.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity to configure.
* @param componentId The renderable component.
* @param priority The priority value, or 0 for auto.
*/
void entityRenderableSetPriority(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const int8_t priority
@@ -130,13 +121,11 @@ void entityRenderableSetPriority(
* (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 color The color to tint the material with.
*/
void entityRenderableSetColor(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const color_t color
@@ -147,7 +136,6 @@ void entityRenderableSetColor(
* 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
@@ -155,7 +143,6 @@ void entityRenderableSetColor(
* @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,
@@ -166,18 +153,15 @@ void entityRenderableSetMesh(
* Sets the draw callback, switching the type to
* ENTITY_RENDERABLE_TYPE_CUSTOM.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity to configure.
* @param componentId The renderable component of the entity.
* @param draw The draw callback to assign.
* @param user Userdata passed to the callback.
*/
void entityRenderableSetDraw(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
errorret_t (*draw)(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
void *user
@@ -188,13 +172,11 @@ void entityRenderableSetDraw(
/**
* Draws the entity using its renderable component data.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity to draw.
* @param componentId The renderable component of the entity.
* @return Any error state that happened.
*/
errorret_t entityRenderableDraw(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
);
@@ -220,14 +202,12 @@ errorret_t entityRenderableDrawMaterial(const entityrenderablematerial_t *m);
/**
* Internal. Invokes a custom-type renderable's draw callback.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity being drawn.
* @param componentId The renderable component of the entity.
* @param custom The custom draw data.
* @return Error state.
*/
errorret_t entityRenderableDrawCustom(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const entityrenderablecustom_t *custom
@@ -6,15 +6,14 @@
*/
#include "entityphysics.h"
#include "entity/entitymanager.h"
#include "entity/entity.h"
#include "util/memory.h"
void entityPhysicsInit(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
) {
entityphysics_t *phys = entityPhysicsGet(mgr, entityId, componentId);
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
memoryZero(phys, sizeof(entityphysics_t));
@@ -30,106 +29,95 @@ void entityPhysicsInit(
}
entityphysics_t *entityPhysicsGet(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
) {
return componentGetData(mgr, entityId, componentId, COMPONENT_TYPE_PHYSICS);
return componentGetData(entityId, componentId, COMPONENT_TYPE_PHYSICS);
}
void entityPhysicsSetShape(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const physicsshape_t shape
) {
entityphysics_t *phys = entityPhysicsGet(mgr, entityId, componentId);
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
phys->shape = shape;
}
physicsshape_t entityPhysicsGetShape(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
) {
entityphysics_t *phys = entityPhysicsGet(mgr, entityId, componentId);
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
return phys->shape;
}
void entityPhysicsGetVelocity(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
) {
entityphysics_t *phys = entityPhysicsGet(mgr, entityId, componentId);
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
glm_vec3_copy(phys->velocity, dest);
}
void entityPhysicsSetVelocity(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 velocity
) {
entityphysics_t *phys = entityPhysicsGet(mgr, entityId, componentId);
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
glm_vec3_copy(velocity, phys->velocity);
}
void entityPhysicsApplyImpulse(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 impulse
) {
entityphysics_t *phys = entityPhysicsGet(mgr, entityId, componentId);
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
if(phys->type == PHYSICS_BODY_STATIC) return;
glm_vec3_add(phys->velocity, impulse, phys->velocity);
}
bool_t entityPhysicsIsOnGround(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
) {
entityphysics_t *phys = entityPhysicsGet(mgr, entityId, componentId);
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
return phys->onGround;
}
void entityPhysicsSetBodyType(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const physicsbodytype_t type
) {
entityphysics_t *phys = entityPhysicsGet(mgr, entityId, componentId);
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
phys->type = type;
}
physicsbodytype_t entityPhysicsGetBodyType(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
) {
entityphysics_t *phys = entityPhysicsGet(mgr, entityId, componentId);
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
return phys->type;
}
void entityPhysicsSetCollideMask(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const uint32_t mask
) {
entityphysics_t *phys = entityPhysicsGet(mgr, entityId, componentId);
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
phys->collideMask = mask;
}
uint32_t entityPhysicsGetCollideMask(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
) {
entityphysics_t *phys = entityPhysicsGet(mgr, entityId, componentId);
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
return phys->collideMask;
}
@@ -31,12 +31,10 @@ typedef struct {
* Initializes the physics component: defaults to a dynamic 1x1x1 cube
* body, zero velocity, unit gravity scale, and onGround false.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
*/
void entityPhysicsInit(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
);
@@ -46,13 +44,11 @@ void entityPhysicsInit(
* This is really just intended for doing operations faster than using the
* getters and setters, but it is preferred that you use those.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @return The physics component data for the given entity and component ID.
*/
entityphysics_t *entityPhysicsGet(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
);
@@ -62,13 +58,11 @@ entityphysics_t *entityPhysicsGet(
* state, so if you change from a cube to a sphere, it will keep the same
* velocity and onGround state.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param shape The new shape to set on the physics body.
*/
void entityPhysicsSetShape(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const physicsshape_t shape
@@ -77,13 +71,11 @@ void entityPhysicsSetShape(
/**
* Gets the shape of the entity's physics body.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @return The shape of the physics body.
*/
physicsshape_t entityPhysicsGetShape(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
);
@@ -91,13 +83,11 @@ physicsshape_t entityPhysicsGetShape(
/**
* Gets the velocity of the entity's physics body.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param dest The destination vec3 to write the velocity to.
*/
void entityPhysicsGetVelocity(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
@@ -107,13 +97,11 @@ void entityPhysicsGetVelocity(
* Sets the velocity of the entity's physics body. This is not an impulse, so
* it will be affected by mass and drag.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param velocity The new velocity to set on the physics body.
*/
void entityPhysicsSetVelocity(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 velocity
@@ -124,13 +112,11 @@ void entityPhysicsSetVelocity(
* velocity change that is not affected by mass or drag. No-op on STATIC
* bodies.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param impulse The impulse to apply to the physics body.
*/
void entityPhysicsApplyImpulse(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
vec3 impulse
@@ -140,13 +126,11 @@ void entityPhysicsApplyImpulse(
* Returns true if the entity's physics body rested on a surface during the
* last physicsWorldStep.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @return True if the body is on the ground, false otherwise.
*/
bool_t entityPhysicsIsOnGround(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
);
@@ -154,13 +138,11 @@ bool_t entityPhysicsIsOnGround(
/**
* Sets the body type of the entity's physics body.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param type The body type to set.
*/
void entityPhysicsSetBodyType(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const physicsbodytype_t type
@@ -169,13 +151,11 @@ void entityPhysicsSetBodyType(
/**
* Gets the body type of the entity's physics body.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @return The body type of the physics body.
*/
physicsbodytype_t entityPhysicsGetBodyType(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
);
@@ -184,13 +164,11 @@ physicsbodytype_t entityPhysicsGetBodyType(
* Sets the collision mask of the entity's physics body. Two bodies only
* collide if their masks share at least one set bit.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param mask The new collision mask to set on the physics body.
*/
void entityPhysicsSetCollideMask(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const uint32_t mask
@@ -199,13 +177,11 @@ void entityPhysicsSetCollideMask(
/**
* Gets the collision mask of the entity's physics body.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @return The collision mask of the physics body.
*/
uint32_t entityPhysicsGetCollideMask(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
);
@@ -6,15 +6,14 @@
*/
#include "entitytrigger.h"
#include "entity/entitymanager.h"
#include "entity/entity.h"
#include "util/memory.h"
void entityTriggerInit(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
) {
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
memoryZero(trig, sizeof(entitytrigger_t));
@@ -26,78 +25,70 @@ void entityTriggerInit(
}
entitytrigger_t *entityTriggerGet(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
) {
return componentGetData(mgr, entityId, componentId, COMPONENT_TYPE_TRIGGER);
return componentGetData(entityId, componentId, COMPONENT_TYPE_TRIGGER);
}
void entityTriggerSetShape(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const physicsshape_t shape
) {
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
trig->shape = shape;
}
physicsshape_t entityTriggerGetShape(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
) {
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
return trig->shape;
}
void entityTriggerSetCollideMask(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const uint32_t mask
) {
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
trig->collideMask = mask;
}
uint32_t entityTriggerGetCollideMask(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
) {
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
return trig->collideMask;
}
uint8_t entityTriggerGetOccupantCount(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
) {
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
return trig->occupantCount;
}
entityid_t entityTriggerGetOccupantEntityId(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const uint8_t index
) {
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
if(index >= trig->occupantCount) return ENTITY_ID_INVALID;
return trig->occupants[index].entityId;
}
bool_t entityTriggerIsOccupyingEntity(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const entityid_t otherEntityId
) {
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
for(uint8_t i = 0; i < trig->occupantCount; i++) {
if(trig->occupants[i].entityId == otherEntityId) return true;
}
@@ -20,7 +20,6 @@
* Callback invoked for a trigger's onEnter/onActive/onMove/onLeave events.
* See entityTriggerOnEnterAdd() and its onActive/onMove/onLeave siblings.
*
* @param mgr The entity manager that owns both entities.
* @param triggerEntityId The entity ID of the trigger volume.
* @param triggerComponentId The TRIGGER component ID.
* @param otherEntityId The entity ID that entered/is inside/left the
@@ -29,7 +28,6 @@
* @param user The user pointer passed to the matching *Add() call.
*/
typedef void (*triggercallback_t)(
entitymanager_t *mgr,
const entityid_t triggerEntityId,
const componentid_t triggerComponentId,
const entityid_t otherEntityId,
@@ -93,12 +91,10 @@ typedef struct {
* Initializes the trigger component: defaults to a 1x1x1 cube volume, no
* tracked occupants, and no event subscribers.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
*/
void entityTriggerInit(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
);
@@ -107,13 +103,11 @@ void entityTriggerInit(
* Gets the underlying trigger structure (temporarily) for the given
* entity. Prefer the dedicated getters/setters where possible.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @return The trigger component data for the given entity and component ID.
*/
entitytrigger_t *entityTriggerGet(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
);
@@ -121,13 +115,11 @@ entitytrigger_t *entityTriggerGet(
/**
* Sets the shape of the trigger volume.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param shape The new shape to set on the trigger volume.
*/
void entityTriggerSetShape(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const physicsshape_t shape
@@ -136,13 +128,11 @@ void entityTriggerSetShape(
/**
* Gets the shape of the trigger volume.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @return The shape of the trigger volume.
*/
physicsshape_t entityTriggerGetShape(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
);
@@ -151,13 +141,11 @@ physicsshape_t entityTriggerGetShape(
* Sets the collision mask of the trigger volume. An entity's PHYSICS body
* is only detected if their masks share at least one set bit.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param mask The new collision mask to set on the trigger volume.
*/
void entityTriggerSetCollideMask(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const uint32_t mask
@@ -166,13 +154,11 @@ void entityTriggerSetCollideMask(
/**
* Gets the collision mask of the trigger volume.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @return The collision mask of the trigger volume.
*/
uint32_t entityTriggerGetCollideMask(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
);
@@ -180,13 +166,11 @@ uint32_t entityTriggerGetCollideMask(
/**
* Gets the number of entities currently overlapping this trigger.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @return The number of currently tracked occupants.
*/
uint8_t entityTriggerGetOccupantCount(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId
);
@@ -195,7 +179,6 @@ uint8_t entityTriggerGetOccupantCount(
* Gets the entity ID of the occupant at the given index, in [0,
* entityTriggerGetOccupantCount()). Order is not stable across steps.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param index The occupant index.
@@ -203,7 +186,6 @@ uint8_t entityTriggerGetOccupantCount(
* of range.
*/
entityid_t entityTriggerGetOccupantEntityId(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const uint8_t index
@@ -212,14 +194,12 @@ entityid_t entityTriggerGetOccupantEntityId(
/**
* Checks whether a specific entity is currently overlapping this trigger.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param otherEntityId The entity ID to check for.
* @return True if otherEntityId is a currently tracked occupant.
*/
bool_t entityTriggerIsOccupyingEntity(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const entityid_t otherEntityId
@@ -9,13 +9,12 @@
#include "assert/assert.h"
void entityTriggerOnEnterAdd(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const triggercallback_t callback,
void *user
) {
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
assertTrue(
trig->onEnterCount < ENTITY_TRIGGER_CALLBACK_COUNT_MAX,
"Trigger onEnter callback slots full"
@@ -26,12 +25,11 @@ void entityTriggerOnEnterAdd(
}
void entityTriggerOnEnterRemove(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const triggercallback_t callback
) {
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
for(uint8_t i = 0; i < trig->onEnterCount; i++) {
if(trig->onEnter[i] != callback) continue;
trig->onEnterCount--;
@@ -44,13 +42,12 @@ void entityTriggerOnEnterRemove(
}
void entityTriggerOnActiveAdd(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const triggercallback_t callback,
void *user
) {
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
assertTrue(
trig->onActiveCount < ENTITY_TRIGGER_CALLBACK_COUNT_MAX,
"Trigger onActive callback slots full"
@@ -61,12 +58,11 @@ void entityTriggerOnActiveAdd(
}
void entityTriggerOnActiveRemove(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const triggercallback_t callback
) {
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
for(uint8_t i = 0; i < trig->onActiveCount; i++) {
if(trig->onActive[i] != callback) continue;
trig->onActiveCount--;
@@ -79,13 +75,12 @@ void entityTriggerOnActiveRemove(
}
void entityTriggerOnMoveAdd(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const triggercallback_t callback,
void *user
) {
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
assertTrue(
trig->onMoveCount < ENTITY_TRIGGER_CALLBACK_COUNT_MAX,
"Trigger onMove callback slots full"
@@ -96,12 +91,11 @@ void entityTriggerOnMoveAdd(
}
void entityTriggerOnMoveRemove(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const triggercallback_t callback
) {
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
for(uint8_t i = 0; i < trig->onMoveCount; i++) {
if(trig->onMove[i] != callback) continue;
trig->onMoveCount--;
@@ -114,13 +108,12 @@ void entityTriggerOnMoveRemove(
}
void entityTriggerOnLeaveAdd(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const triggercallback_t callback,
void *user
) {
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
assertTrue(
trig->onLeaveCount < ENTITY_TRIGGER_CALLBACK_COUNT_MAX,
"Trigger onLeave callback slots full"
@@ -131,12 +124,11 @@ void entityTriggerOnLeaveAdd(
}
void entityTriggerOnLeaveRemove(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const triggercallback_t callback
) {
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
for(uint8_t i = 0; i < trig->onLeaveCount; i++) {
if(trig->onLeave[i] != callback) continue;
trig->onLeaveCount--;
@@ -149,72 +141,68 @@ void entityTriggerOnLeaveRemove(
}
void entityTriggerFireEnter(
entitymanager_t *mgr,
const entityid_t triggerEntityId,
const componentid_t triggerComponentId,
const entityid_t otherEntityId,
const componentid_t otherComponentId
) {
entitytrigger_t *trig = entityTriggerGet(
mgr, triggerEntityId, triggerComponentId
triggerEntityId, triggerComponentId
);
for(uint8_t i = 0; i < trig->onEnterCount; i++) {
trig->onEnter[i](
mgr, triggerEntityId, triggerComponentId,
triggerEntityId, triggerComponentId,
otherEntityId, otherComponentId, trig->onEnterUser[i]
);
}
}
void entityTriggerFireActive(
entitymanager_t *mgr,
const entityid_t triggerEntityId,
const componentid_t triggerComponentId,
const entityid_t otherEntityId,
const componentid_t otherComponentId
) {
entitytrigger_t *trig = entityTriggerGet(
mgr, triggerEntityId, triggerComponentId
triggerEntityId, triggerComponentId
);
for(uint8_t i = 0; i < trig->onActiveCount; i++) {
trig->onActive[i](
mgr, triggerEntityId, triggerComponentId,
triggerEntityId, triggerComponentId,
otherEntityId, otherComponentId, trig->onActiveUser[i]
);
}
}
void entityTriggerFireMove(
entitymanager_t *mgr,
const entityid_t triggerEntityId,
const componentid_t triggerComponentId,
const entityid_t otherEntityId,
const componentid_t otherComponentId
) {
entitytrigger_t *trig = entityTriggerGet(
mgr, triggerEntityId, triggerComponentId
triggerEntityId, triggerComponentId
);
for(uint8_t i = 0; i < trig->onMoveCount; i++) {
trig->onMove[i](
mgr, triggerEntityId, triggerComponentId,
triggerEntityId, triggerComponentId,
otherEntityId, otherComponentId, trig->onMoveUser[i]
);
}
}
void entityTriggerFireLeave(
entitymanager_t *mgr,
const entityid_t triggerEntityId,
const componentid_t triggerComponentId,
const entityid_t otherEntityId,
const componentid_t otherComponentId
) {
entitytrigger_t *trig = entityTriggerGet(
mgr, triggerEntityId, triggerComponentId
triggerEntityId, triggerComponentId
);
for(uint8_t i = 0; i < trig->onLeaveCount; i++) {
trig->onLeave[i](
mgr, triggerEntityId, triggerComponentId,
triggerEntityId, triggerComponentId,
otherEntityId, otherComponentId, trig->onLeaveUser[i]
);
}
@@ -12,14 +12,12 @@
* Subscribes a callback to a trigger's onEnter event, fired the step an
* entity begins overlapping the trigger volume.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param callback The callback to invoke.
* @param user Arbitrary pointer forwarded to the callback unchanged.
*/
void entityTriggerOnEnterAdd(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const triggercallback_t callback,
@@ -30,13 +28,11 @@ void entityTriggerOnEnterAdd(
* Unsubscribes a previously added onEnter callback. No-op if not
* currently subscribed.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param callback The callback that was passed to entityTriggerOnEnterAdd().
*/
void entityTriggerOnEnterRemove(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const triggercallback_t callback
@@ -47,14 +43,12 @@ void entityTriggerOnEnterRemove(
* entity continues overlapping the trigger volume (starting the step
* after onEnter fired).
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param callback The callback to invoke.
* @param user Arbitrary pointer forwarded to the callback unchanged.
*/
void entityTriggerOnActiveAdd(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const triggercallback_t callback,
@@ -65,13 +59,11 @@ void entityTriggerOnActiveAdd(
* Unsubscribes a previously added onActive callback. No-op if not
* currently subscribed.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param callback The callback that was passed to entityTriggerOnActiveAdd().
*/
void entityTriggerOnActiveRemove(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const triggercallback_t callback
@@ -82,14 +74,12 @@ void entityTriggerOnActiveRemove(
* onActive on any step where the overlapping entity's position changed
* since the previous step.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param callback The callback to invoke.
* @param user Arbitrary pointer forwarded to the callback unchanged.
*/
void entityTriggerOnMoveAdd(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const triggercallback_t callback,
@@ -100,13 +90,11 @@ void entityTriggerOnMoveAdd(
* Unsubscribes a previously added onMove callback. No-op if not currently
* subscribed.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param callback The callback that was passed to entityTriggerOnMoveAdd().
*/
void entityTriggerOnMoveRemove(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const triggercallback_t callback
@@ -116,14 +104,12 @@ void entityTriggerOnMoveRemove(
* Subscribes a callback to a trigger's onLeave event, fired the step an
* entity stops overlapping the trigger volume.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param callback The callback to invoke.
* @param user Arbitrary pointer forwarded to the callback unchanged.
*/
void entityTriggerOnLeaveAdd(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const triggercallback_t callback,
@@ -134,13 +120,11 @@ void entityTriggerOnLeaveAdd(
* Unsubscribes a previously added onLeave callback. No-op if not
* currently subscribed.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param callback The callback that was passed to entityTriggerOnLeaveAdd().
*/
void entityTriggerOnLeaveRemove(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
const triggercallback_t callback
@@ -150,14 +134,12 @@ void entityTriggerOnLeaveRemove(
* Internal. Invokes every subscribed onEnter callback for a trigger.
* Called by triggerSystemStep() when an entity begins overlapping.
*
* @param mgr The entity manager that owns both entities.
* @param triggerEntityId The entity ID of the trigger volume.
* @param triggerComponentId The TRIGGER component ID.
* @param otherEntityId The entity ID that entered the trigger volume.
* @param otherComponentId The other entity's POSITION component ID.
*/
void entityTriggerFireEnter(
entitymanager_t *mgr,
const entityid_t triggerEntityId,
const componentid_t triggerComponentId,
const entityid_t otherEntityId,
@@ -168,14 +150,12 @@ void entityTriggerFireEnter(
* Internal. Invokes every subscribed onActive callback for a trigger.
* Called by triggerSystemStep() for every entity still overlapping.
*
* @param mgr The entity manager that owns both entities.
* @param triggerEntityId The entity ID of the trigger volume.
* @param triggerComponentId The TRIGGER component ID.
* @param otherEntityId The entity ID still inside the trigger volume.
* @param otherComponentId The other entity's POSITION component ID.
*/
void entityTriggerFireActive(
entitymanager_t *mgr,
const entityid_t triggerEntityId,
const componentid_t triggerComponentId,
const entityid_t otherEntityId,
@@ -187,14 +167,12 @@ void entityTriggerFireActive(
* Called by triggerSystemStep() when an overlapping entity's position
* changed since the previous step.
*
* @param mgr The entity manager that owns both entities.
* @param triggerEntityId The entity ID of the trigger volume.
* @param triggerComponentId The TRIGGER component ID.
* @param otherEntityId The entity ID that moved within the trigger volume.
* @param otherComponentId The other entity's POSITION component ID.
*/
void entityTriggerFireMove(
entitymanager_t *mgr,
const entityid_t triggerEntityId,
const componentid_t triggerComponentId,
const entityid_t otherEntityId,
@@ -205,14 +183,12 @@ void entityTriggerFireMove(
* Internal. Invokes every subscribed onLeave callback for a trigger.
* Called by triggerSystemStep() when an entity stops overlapping.
*
* @param mgr The entity manager that owns both entities.
* @param triggerEntityId The entity ID of the trigger volume.
* @param triggerComponentId The TRIGGER component ID.
* @param otherEntityId The entity ID that left the trigger volume.
* @param otherComponentId The other entity's POSITION component ID.
*/
void entityTriggerFireLeave(
entitymanager_t *mgr,
const entityid_t triggerEntityId,
const componentid_t triggerComponentId,
const entityid_t otherEntityId,
+80 -40
View File
@@ -5,14 +5,63 @@
* https://opensource.org/licenses/MIT
*/
#include "entitymanager.h"
#include "entity.h"
#include "component/display/entityposition.h"
#include "util/memory.h"
#include "util/string.h"
#include "assert/assert.h"
#include "console/console.h"
void entityInit(entitymanager_t *mgr, const entityid_t entityId) {
entity_t *ent = &mgr->entities[entityId];
entity_t ENTITIES[ENTITY_COUNT_MAX];
component_t COMPONENTS[ENTITY_COUNT_MAX * ENTITY_COMPONENT_COUNT_MAX];
componentid_t ENTITIES_WITH_COMPONENT[COMPONENT_TYPE_COUNT * ENTITY_COUNT_MAX];
void entityManagerInit(void) {
memoryZero(ENTITIES, sizeof(ENTITIES));
memoryZero(COMPONENTS, sizeof(COMPONENTS));
memorySet(
ENTITIES_WITH_COMPONENT, COMPONENT_ID_INVALID,
sizeof(ENTITIES_WITH_COMPONENT)
);
size_t totalSize =
sizeof(ENTITIES) + sizeof(COMPONENTS) + sizeof(ENTITIES_WITH_COMPONENT);
consolePrint(
"Entity manager size: %zu bytes (%.2f KB)",
totalSize,
totalSize / 1024.0f
);
}
entityid_t entityManagerAdd(void) {
for(entityid_t i = 0; i < ENTITY_COUNT_MAX; i++) {
if((ENTITIES[i].state & ENTITY_STATE_ACTIVE) != 0) continue;
entityInit(i);
return i;
}
assertUnreachable("No more entity IDs available");
return ENTITY_ID_INVALID;
}
void entityManagerUpdate(void) {
entityid_t i = 0;
while(i < ENTITY_COUNT_MAX) {
if((ENTITIES[i].state & ENTITY_STATE_ACTIVE) != 0) {
entityUpdate(i);
}
i++;
}
}
void entityManagerDispose(void) {
for(entityid_t i = 0; i < ENTITY_COUNT_MAX; i++) {
if((ENTITIES[i].state & ENTITY_STATE_ACTIVE) == 0) continue;
entityDispose(i);
}
}
void entityInit(const entityid_t entityId) {
entity_t *ent = &ENTITIES[entityId];
memoryZero(ent, sizeof(entity_t));
@@ -22,7 +71,7 @@ void entityInit(entitymanager_t *mgr, const entityid_t entityId) {
compType < COMPONENT_TYPE_COUNT;
compType++
) {
mgr->entitiesWithComponent[
ENTITIES_WITH_COMPONENT[
compType * ENTITY_COUNT_MAX + entityId
] = COMPONENT_ID_INVALID;
}
@@ -31,7 +80,6 @@ void entityInit(entitymanager_t *mgr, const entityid_t entityId) {
}
componentid_t entityAddComponent(
entitymanager_t *mgr,
const entityid_t entityId,
const componenttype_t type
) {
@@ -39,15 +87,15 @@ componentid_t entityAddComponent(
for(componentid_t i = 0; i < ENTITY_COMPONENT_COUNT_MAX; i++) {
compInd = componentGetIndex(entityId, i);
if(mgr->components[compInd].type != COMPONENT_TYPE_NULL) {
if(COMPONENTS[compInd].type != COMPONENT_TYPE_NULL) {
assertTrue(
mgr->components[compInd].type != type,
COMPONENTS[compInd].type != type,
"Entity already has component of this type"
);
continue;
}
componentInit(mgr, entityId, i, type);
mgr->entitiesWithComponent[
componentInit(entityId, i, type);
ENTITIES_WITH_COMPONENT[
type * ENTITY_COUNT_MAX + entityId
] = i;
return i;
@@ -58,98 +106,93 @@ componentid_t entityAddComponent(
}
componentid_t entityGetComponent(
entitymanager_t *mgr,
const entityid_t entityId,
const componenttype_t type
) {
componentid_t compId = mgr->entitiesWithComponent[
componentid_t compId = ENTITIES_WITH_COMPONENT[
type * ENTITY_COUNT_MAX + entityId
];
if(compId == COMPONENT_ID_INVALID) return compId;
assertTrue(
mgr->components[componentGetIndex(entityId, compId)].type == type,
COMPONENTS[componentGetIndex(entityId, compId)].type == type,
"Component type mismatch"
);
return compId;
}
void entitySetName(
entitymanager_t *mgr,
const entityid_t entityId,
const char_t *name
) {
stringCopy(mgr->entities[entityId].name, name, ENTITY_NAME_MAX);
stringCopy(ENTITIES[entityId].name, name, ENTITY_NAME_MAX);
}
const char_t *entityGetName(
entitymanager_t *mgr,
const entityid_t entityId
) {
return mgr->entities[entityId].name;
return ENTITIES[entityId].name;
}
entityid_t entityFindByName(
entitymanager_t *mgr,
const char_t *name
) {
for(entityid_t i = 0; i < ENTITY_COUNT_MAX; i++) {
if(!(mgr->entities[i].state & ENTITY_STATE_ACTIVE)) continue;
if(stringEquals(mgr->entities[i].name, name)) return i;
if(!(ENTITIES[i].state & ENTITY_STATE_ACTIVE)) continue;
if(stringEquals(ENTITIES[i].name, name)) return i;
}
return ENTITY_ID_INVALID;
}
void entityDisposeDeep(entitymanager_t *mgr, const entityid_t entityId) {
void entityDisposeDeep(const entityid_t entityId) {
componentid_t posComp = entityGetComponent(
mgr, entityId, COMPONENT_TYPE_POSITION
entityId, COMPONENT_TYPE_POSITION
);
if(posComp != COMPONENT_ID_INVALID) {
entityPositionDisposeDeep(mgr, entityId, posComp);
entityPositionDisposeDeep(entityId, posComp);
} else {
entityDispose(mgr, entityId);
entityDispose(entityId);
}
}
void entityUpdate(entitymanager_t *mgr, const entityid_t entityId) {
entity_t *ent = &mgr->entities[entityId];
void entityUpdate(const entityid_t entityId) {
entity_t *ent = &ENTITIES[entityId];
for(uint8_t i = 0; i < ent->updateCount; i++) {
ent->onUpdate[i](
mgr, entityId, ent->updateComponentId[i], ent->updateUser[i]
entityId, ent->updateComponentId[i], ent->updateUser[i]
);
}
}
void entityDispose(entitymanager_t *mgr, const entityid_t entityId) {
void entityDispose(const entityid_t entityId) {
componentindex_t compInd;
entity_t *ent = &mgr->entities[entityId];
entity_t *ent = &ENTITIES[entityId];
for(uint8_t i = 0; i < ent->disposeCount; i++) {
ent->onDispose[i](
mgr, entityId, ent->disposeComponentId[i], ent->disposeUser[i]
entityId, ent->disposeComponentId[i], ent->disposeUser[i]
);
}
for(componentid_t i = 0; i < ENTITY_COMPONENT_COUNT_MAX; i++) {
compInd = componentGetIndex(entityId, i);
componenttype_t type = mgr->components[compInd].type;
componenttype_t type = COMPONENTS[compInd].type;
if(type == COMPONENT_TYPE_NULL) continue;
mgr->entitiesWithComponent[
ENTITIES_WITH_COMPONENT[
type * ENTITY_COUNT_MAX + entityId
] = COMPONENT_ID_INVALID;
componentDispose(mgr, entityId, i);
componentDispose(entityId, i);
}
ent->state = 0;
}
void entityUpdateAdd(
entitymanager_t *mgr,
const entityid_t entityId,
const entitycallback_t callback,
const componentid_t componentId,
void *user
) {
entity_t *ent = &mgr->entities[entityId];
entity_t *ent = &ENTITIES[entityId];
assertTrue(
ent->updateCount < ENTITY_UPDATE_CALLBACK_COUNT_MAX,
"Entity update callback slots full"
@@ -161,11 +204,10 @@ void entityUpdateAdd(
}
void entityUpdateRemove(
entitymanager_t *mgr,
const entityid_t entityId,
const entitycallback_t callback
) {
entity_t *ent = &mgr->entities[entityId];
entity_t *ent = &ENTITIES[entityId];
for(uint8_t i = 0; i < ent->updateCount; i++) {
if(ent->onUpdate[i] != callback) continue;
ent->updateCount--;
@@ -179,13 +221,12 @@ void entityUpdateRemove(
}
void entityDisposeAdd(
entitymanager_t *mgr,
const entityid_t entityId,
const entitycallback_t callback,
const componentid_t componentId,
void *user
) {
entity_t *ent = &mgr->entities[entityId];
entity_t *ent = &ENTITIES[entityId];
assertTrue(
ent->disposeCount < ENTITY_DISPOSE_CALLBACK_COUNT_MAX,
"Entity dispose callback slots full"
@@ -197,11 +238,10 @@ void entityDisposeAdd(
}
void entityDisposeRemove(
entitymanager_t *mgr,
const entityid_t entityId,
const entitycallback_t callback
) {
entity_t *ent = &mgr->entities[entityId];
entity_t *ent = &ENTITIES[entityId];
for(uint8_t i = 0; i < ent->disposeCount; i++) {
if(ent->onDispose[i] != callback) continue;
ent->disposeCount--;
+32 -27
View File
@@ -16,7 +16,6 @@
#define ENTITY_NAME_MAX 32
typedef void (*entitycallback_t)(
entitymanager_t *mgr,
const entityid_t entityId,
const componentid_t componentId,
void *user
@@ -35,24 +34,49 @@ typedef struct {
void *disposeUser[ENTITY_DISPOSE_CALLBACK_COUNT_MAX];
} entity_t;
extern entity_t ENTITIES[ENTITY_COUNT_MAX];
extern component_t COMPONENTS[ENTITY_COUNT_MAX * ENTITY_COMPONENT_COUNT_MAX];
extern componentid_t ENTITIES_WITH_COMPONENT[COMPONENT_TYPE_COUNT * ENTITY_COUNT_MAX];
/**
* Initializes the entity system, marking all entities and components as
* unused.
*/
void entityManagerInit(void);
/**
* Adds / Reserves a new entity ID.
*
* @return The new entity ID.
*/
entityid_t entityManagerAdd(void);
/**
* Updates all active entities.
*/
void entityManagerUpdate(void);
/**
* Disposes of the entity system, in turn freeing all entities and
* components.
*/
void entityManagerDispose(void);
/**
* Initializes an entity with the given ID.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The ID of the entity to initialize.
*/
void entityInit(entitymanager_t *mgr, const entityid_t entityId);
void entityInit(const entityid_t entityId);
/**
* Adds a component of the given type to the entity with the given ID.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The ID of the entity to add the component to.
* @param type The type of the component to add.
* @return The ID of the entity with component.
*/
componentid_t entityAddComponent(
entitymanager_t *mgr,
const entityid_t entityId,
const componenttype_t type
);
@@ -61,13 +85,11 @@ componentid_t entityAddComponent(
* Gets the ID of the component of the given type on the entity with the
* given ID, or COMPONENT_ID_INVALID if the entity lacks the component.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The ID of the entity to get the component from.
* @param type The type of the component to get.
* @return The ID of the component.
*/
componentid_t entityGetComponent(
entitymanager_t *mgr,
const entityid_t entityId,
const componenttype_t type
);
@@ -78,13 +100,11 @@ componentid_t entityGetComponent(
* entity referenceable by name, e.g. as a parent via
* entityPositionSetParent().
*
* @param mgr The entity manager that owns the entity.
* @param entityId The ID of the entity to name.
* @param name The name to give the entity. Must be shorter than
* ENTITY_NAME_MAX.
*/
void entitySetName(
entitymanager_t *mgr,
const entityid_t entityId,
const char_t *name
);
@@ -92,65 +112,56 @@ void entitySetName(
/**
* Gets an entity's name, or an empty string if it has none.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The ID of the entity to get the name of.
* @return The entity's name.
*/
const char_t *entityGetName(
entitymanager_t *mgr,
const entityid_t entityId
);
/**
* Finds the first active entity with the given name.
*
* @param mgr The entity manager to search.
* @param name The name to search for.
* @return The entity ID, or ENTITY_ID_INVALID if no active entity matches.
*/
entityid_t entityFindByName(
entitymanager_t *mgr,
const char_t *name
);
/**
* Runs all registered update callbacks for the entity.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The ID of the entity to update.
*/
void entityUpdate(entitymanager_t *mgr, const entityid_t entityId);
void entityUpdate(const entityid_t entityId);
/**
* Disposes of an entity with the given ID. Fires all dispose callbacks
* before cleaning up components and state.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The ID of the entity to dispose of.
*/
void entityDispose(entitymanager_t *mgr, 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 mgr The entity manager that owns the entity.
* @param entityId The root entity ID.
*/
void entityDisposeDeep(entitymanager_t *mgr, const entityid_t entityId);
void entityDisposeDeep(const entityid_t entityId);
/**
* Registers an update callback, invoked each time entityUpdate is called.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity to register on.
* @param callback The function to call.
* @param componentId The component ID passed back to the callback.
* @param user Userdata passed back to the callback.
*/
void entityUpdateAdd(
entitymanager_t *mgr,
const entityid_t entityId,
const entitycallback_t callback,
const componentid_t componentId,
@@ -160,12 +171,10 @@ void entityUpdateAdd(
/**
* Removes a previously registered update callback.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity to remove from.
* @param callback The function to remove.
*/
void entityUpdateRemove(
entitymanager_t *mgr,
const entityid_t entityId,
const entitycallback_t callback
);
@@ -174,14 +183,12 @@ void entityUpdateRemove(
* Registers a dispose callback, invoked at the start of entityDispose
* before any component or state cleanup.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity to register on.
* @param callback The function to call.
* @param componentId The component ID passed back to the callback.
* @param user Userdata passed back to the callback.
*/
void entityDisposeAdd(
entitymanager_t *mgr,
const entityid_t entityId,
const entitycallback_t callback,
const componentid_t componentId,
@@ -191,12 +198,10 @@ void entityDisposeAdd(
/**
* Removes a previously registered dispose callback.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity to remove from.
* @param callback The function to remove.
*/
void entityDisposeRemove(
entitymanager_t *mgr,
const entityid_t entityId,
const entitycallback_t callback
);
-5
View File
@@ -17,8 +17,3 @@
typedef uint8_t entityid_t;
typedef uint8_t componentid_t;
typedef uint16_t componentindex_t;
// Forward declared here (rather than in component.h) so every entity/
// component header can reference entitymanager_t* regardless of include
// order, without needing a full entitymanager.h include.
typedef struct entitymanager_t entitymanager_t;
-56
View File
@@ -1,56 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "entitymanager.h"
#include "assert/assert.h"
#include "util/memory.h"
#include "console/console.h"
void entityManagerInit(entitymanager_t *mgr) {
assertNotNull(mgr, "Entity manager cannot be null");
memoryZero(mgr, sizeof(entitymanager_t));
memorySet(
mgr->entitiesWithComponent, COMPONENT_ID_INVALID,
sizeof(componentid_t) * COMPONENT_TYPE_COUNT * ENTITY_COUNT_MAX
);
consolePrint(
"Entity manager size: %zu bytes (%.2f KB)",
sizeof(entitymanager_t),
sizeof(entitymanager_t) / 1024.0f
);
}
entityid_t entityManagerAdd(entitymanager_t *mgr) {
assertNotNull(mgr, "Entity manager cannot be null");
for(entityid_t i = 0; i < ENTITY_COUNT_MAX; i++) {
if((mgr->entities[i].state & ENTITY_STATE_ACTIVE) != 0) continue;
entityInit(mgr, i);
return i;
}
assertUnreachable("No more entity IDs available");
return ENTITY_ID_INVALID;
}
void entityManagerUpdate(entitymanager_t *mgr) {
assertNotNull(mgr, "Entity manager cannot be null");
entityid_t i = 0;
while(i < ENTITY_COUNT_MAX) {
if((mgr->entities[i].state & ENTITY_STATE_ACTIVE) != 0) {
entityUpdate(mgr, i);
}
i++;
}
}
void entityManagerDispose(entitymanager_t *mgr) {
assertNotNull(mgr, "Entity manager cannot be null");
for(entityid_t i = 0; i < ENTITY_COUNT_MAX; i++) {
if((mgr->entities[i].state & ENTITY_STATE_ACTIVE) == 0) continue;
entityDispose(mgr, i);
}
}
-46
View File
@@ -1,46 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "entity.h"
typedef struct entitymanager_t {
entity_t entities[ENTITY_COUNT_MAX];
component_t components[ENTITY_COUNT_MAX * ENTITY_COMPONENT_COUNT_MAX];
componentid_t entitiesWithComponent[COMPONENT_TYPE_COUNT * ENTITY_COUNT_MAX];
} entitymanager_t;
/**
* Initializes an entity manager, marking all entities and components as
* unused.
*
* @param mgr The entity manager to initialize.
*/
void entityManagerInit(entitymanager_t *mgr);
/**
* Adds / Reserves a new entity ID in the given manager.
*
* @param mgr The entity manager to allocate the entity in.
* @return The new entity ID.
*/
entityid_t entityManagerAdd(entitymanager_t *mgr);
/**
* Updates all active entities in the given manager.
*
* @param mgr The entity manager to update.
*/
void entityManagerUpdate(entitymanager_t *mgr);
/**
* Disposes of the entity manager, in turn freeing all entities and
* components.
*
* @param mgr The entity manager to dispose.
*/
void entityManagerDispose(entitymanager_t *mgr);
+64
View File
@@ -0,0 +1,64 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "entityrender.h"
#include "component/display/entitycamera.h"
#include "component/display/entityposition.h"
#include "component/display/entityrenderable.h"
#include "display/shader/shaderunlit.h"
errorret_t entityRenderAll(void) {
entityid_t camEntity = entityCameraGetCurrent();
if(camEntity == ENTITY_ID_INVALID) errorOk();
componentid_t camComp = entityGetComponent(
camEntity, COMPONENT_TYPE_CAMERA
);
componentid_t camPosComp = entityGetComponent(
camEntity, COMPONENT_TYPE_POSITION
);
mat4 proj;
entityCameraGetProjection(camEntity, camComp, proj);
mat4 view;
glm_mat4_identity(view);
if(camPosComp != COMPONENT_ID_INVALID) {
mat4 camTransform;
entityPositionGetTransform(camEntity, camPosComp, camTransform);
// Position components always store world-space placement (eye ->
// world), regardless of how they were set (SetPosition/Rotation or
// LookAt) -- invert to get the view matrix (world -> eye).
glm_mat4_inv(camTransform, view);
}
errorChain(shaderBind(&SHADER_UNLIT));
errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_PROJECTION, proj));
errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_VIEW, view));
entityid_t renderEntities[ENTITY_COUNT_MAX];
componentid_t renderComponents[ENTITY_COUNT_MAX];
entityid_t renderCount = componentGetEntitiesWithComponent(
COMPONENT_TYPE_RENDERABLE, renderEntities, renderComponents
);
for(entityid_t i = 0; i < renderCount; i++) {
mat4 model;
componentid_t posComp = entityGetComponent(
renderEntities[i], COMPONENT_TYPE_POSITION
);
if(posComp == COMPONENT_ID_INVALID) {
glm_mat4_identity(model);
} else {
entityPositionGetTransform(renderEntities[i], posComp, model);
}
errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_MODEL, model));
errorChain(entityRenderableDraw(renderEntities[i], renderComponents[i]));
}
errorOk();
}
+18
View File
@@ -0,0 +1,18 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "entity.h"
#include "error/error.h"
/**
* Renders every COMPONENT_TYPE_RENDERABLE entity, from the view of its
* first COMPONENT_TYPE_CAMERA entity. A no-op if there is no camera.
*
* @return Error state.
*/
errorret_t entityRenderAll(void);
+9
View File
@@ -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
scene.c
)
+75
View File
@@ -0,0 +1,75 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "scene.h"
#include "entity/entity.h"
#include "entity/entityrender.h"
#include "assert/assert.h"
#include "util/memory.h"
#include "time/time.h"
scenemanager_t SCENE_MANAGER;
errorret_t sceneInit(void) {
memoryZero(&SCENE_MANAGER, sizeof(scenemanager_t));
SCENE_MANAGER.active = SCENE_ID_INVALID;
errorOk();
}
sceneid_t sceneCreate(void) {
assertTrue(!SCENE_MANAGER.scene.used, "Scene is already in use");
SCENE_MANAGER.scene.used = true;
return 0;
}
void sceneDestroy(const sceneid_t id) {
assertTrue(id == 0, "Scene ID OOB");
if(!SCENE_MANAGER.scene.used) return;
SCENE_MANAGER.scene.used = false;
if(SCENE_MANAGER.active == id) SCENE_MANAGER.active = SCENE_ID_INVALID;
}
void sceneSetActive(const sceneid_t id) {
assertTrue(
id == SCENE_ID_INVALID || id == 0, "Scene ID OOB"
);
SCENE_MANAGER.active = id;
}
sceneid_t sceneGetActive(void) {
return SCENE_MANAGER.active;
}
errorret_t sceneUpdate(void) {
#if DUSK_TIME_DYNAMIC
if(TIME.dynamicUpdate) errorOk();
#endif
errorChain(sceneFixedUpdate());
errorOk();
}
errorret_t sceneFixedUpdate(void) {
if(SCENE_MANAGER.active == SCENE_ID_INVALID) errorOk();
entityManagerUpdate();
errorOk();
}
errorret_t sceneRender(void) {
if(SCENE_MANAGER.active != SCENE_ID_INVALID) {
errorChain(entityRenderAll());
}
errorOk();
}
errorret_t sceneDispose(void) {
sceneDestroy(0);
errorOk();
}
+106
View File
@@ -0,0 +1,106 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "scenebase.h"
#include "error/error.h"
typedef struct {
bool_t used;
} scene_t;
typedef struct {
scene_t scene;
sceneid_t active;
} scenemanager_t;
extern scenemanager_t SCENE_MANAGER;
/**
* Initialises the scene manager. No scenes are created or active until
* sceneCreate()/sceneSetActive() are called.
*
* @return An error if the init failed, or errorOk() if it succeeded.
*/
errorret_t sceneInit(void);
/**
* Creates the single scene. There is no per-scene entity pool -- entities
* are global (see entity.h) -- so this just marks the scene as used. Not
* made active automatically.
*
* @return The ID of the new scene (always 0).
*/
sceneid_t sceneCreate(void);
/**
* Destroys the scene. Does not touch the global entity arrays -- entity
* lifecycle is the engine's job (entityManagerInit()/entityManagerDispose()),
* not scoped to scene create/destroy. If the scene was active, no scene is
* active afterwards.
*
* @param id The ID of the scene to destroy. Must be 0.
*/
void sceneDestroy(const sceneid_t id);
/**
* Sets which scene is active. Only the active scene is ticked and rendered
* by sceneUpdate()/sceneRender(). Previously active scenes are left running
* in the background (paused, not disposed) until sceneDestroy() is called.
*
* @param id The ID of the scene to make active, or SCENE_ID_INVALID to make
* no scene active.
*/
void sceneSetActive(const sceneid_t id);
/**
* Gets the ID of the currently active scene.
*
* @return The active scene ID, or SCENE_ID_INVALID if none is active.
*/
sceneid_t sceneGetActive(void);
/**
* Called every frame (every call to engineUpdate). On a non-dynamic-time
* platform (DUSK_TIME_DYNAMIC undefined) every frame is itself a fixed
* timestep, so this calls sceneFixedUpdate() every time. On a
* dynamic-time platform, most calls are sub-steps still accumulating
* toward the next fixed timestep (TIME.dynamicUpdate is true) and do
* nothing here; this calls sceneFixedUpdate() only on the one call where
* TIME.dynamicUpdate is false, i.e. exactly once per fixed timestep.
*
* @return An error if the update failed, or errorOk() if it succeeded.
*/
errorret_t sceneUpdate(void);
/**
* Ticks the active scene's entities (update callbacks) by one fixed
* timestep (TIME.delta). Called by sceneUpdate() at the fixed-timestep
* cadence described there -- never once per rendered frame on a
* dynamic-time platform, so game logic stays frame-rate independent and
* deterministic. Does not step physics or triggers yet -- physicsworld_t/
* triggersystem_t haven't been ported from ac2 onto this branch, so a
* scene's entities can't collide or trigger each other until that lands.
*
* @return An error if the update failed, or errorOk() if it succeeded.
*/
errorret_t sceneFixedUpdate(void);
/**
* Renders the active scene's entities, from the view of its active
* camera (see entityRenderAll).
*
* @return An error if the render failed, or errorOk() if it succeeded.
*/
errorret_t sceneRender(void);
/**
* Destroys the scene.
*
* @return An error if the dispose failed, or errorOk() if it succeeded.
*/
errorret_t sceneDispose(void);
+13
View File
@@ -0,0 +1,13 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
#define SCENE_ID_INVALID 0xFF
typedef uint8_t sceneid_t;
+3
View File
@@ -7,3 +7,6 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
scriptnativeconsole.c
)
# Subdirs
add_subdirectory(entity)
@@ -0,0 +1,12 @@
# 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
scriptnativeentity.c
scriptnativeentitymanager.c
scriptnativeentityposition.c
scriptnativeentityrenderable.c
)
@@ -0,0 +1,126 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "scriptnativeentity.h"
#include "entity/entity.h"
#include "util/memory.h"
#include "assert/assert.h"
SCRIPT_NATIVE(scriptNativeEntityAddComponent) {
entityid_t entityId;
componenttype_t type;
componentid_t componentId;
scriptArgCount(runtime, argc, 2, 2);
entityId = (entityid_t)scriptArgInteger(runtime, args, argc, 0);
type = (componenttype_t)scriptArgInteger(runtime, args, argc, 1);
componentId = entityAddComponent(entityId, type);
return scriptNumber((float)componentId);
}
SCRIPT_NATIVE(scriptNativeEntityGetComponent) {
entityid_t entityId;
componenttype_t type;
componentid_t componentId;
scriptArgCount(runtime, argc, 2, 2);
entityId = (entityid_t)scriptArgInteger(runtime, args, argc, 0);
type = (componenttype_t)scriptArgInteger(runtime, args, argc, 1);
componentId = entityGetComponent(entityId, type);
return scriptNumber((float)componentId);
}
SCRIPT_NATIVE(scriptNativeEntitySetName) {
entityid_t entityId;
scriptstring_t *name;
char_t buffer[ENTITY_NAME_MAX];
uint16_t length;
scriptArgCount(runtime, argc, 2, 2);
entityId = (entityid_t)scriptArgInteger(runtime, args, argc, 0);
name = scriptArgString(runtime, args, argc, 1);
// name->data isn't null terminated - entitySetName needs a C string.
length = name->length;
if(length > ENTITY_NAME_MAX - 1) length = ENTITY_NAME_MAX - 1;
if(length) memoryCopy(buffer, name->data, length);
buffer[length] = 0;
entitySetName(entityId, buffer);
return scriptUndefined();
}
SCRIPT_NATIVE(scriptNativeEntityGetName) {
entityid_t entityId;
scriptArgCount(runtime, argc, 1, 1);
entityId = (entityid_t)scriptArgInteger(runtime, args, argc, 0);
return scriptStringFromC(
runtime, entityGetName(entityId)
);
}
SCRIPT_NATIVE(scriptNativeEntityFindByName) {
scriptstring_t *name;
char_t buffer[ENTITY_NAME_MAX];
uint16_t length;
entityid_t entityId;
scriptArgCount(runtime, argc, 1, 1);
name = scriptArgString(runtime, args, argc, 0);
length = name->length;
if(length > ENTITY_NAME_MAX - 1) length = ENTITY_NAME_MAX - 1;
if(length) memoryCopy(buffer, name->data, length);
buffer[length] = 0;
entityId = entityFindByName(buffer);
return scriptNumber((float)entityId);
}
SCRIPT_NATIVE(scriptNativeEntityDispose) {
entityid_t entityId;
scriptArgCount(runtime, argc, 1, 1);
entityId = (entityid_t)scriptArgInteger(runtime, args, argc, 0);
entityDispose(entityId);
return scriptUndefined();
}
SCRIPT_NATIVE(scriptNativeEntityDisposeDeep) {
entityid_t entityId;
scriptArgCount(runtime, argc, 1, 1);
entityId = (entityid_t)scriptArgInteger(runtime, args, argc, 0);
entityDisposeDeep(entityId);
return scriptUndefined();
}
void scriptNativeEntityRegister(scriptruntime_t *runtime) {
assertNotNull(runtime, "scriptNativeEntityRegister needs a runtime, not NULL");
scriptBuiltinAdd(runtime, "entityAddComponent", scriptNativeEntityAddComponent);
scriptBuiltinAdd(runtime, "entityGetComponent", scriptNativeEntityGetComponent);
scriptBuiltinAdd(runtime, "entitySetName", scriptNativeEntitySetName);
scriptBuiltinAdd(runtime, "entityGetName", scriptNativeEntityGetName);
scriptBuiltinAdd(runtime, "entityFindByName", scriptNativeEntityFindByName);
scriptBuiltinAdd(runtime, "entityDispose", scriptNativeEntityDispose);
scriptBuiltinAdd(runtime, "entityDisposeDeep", scriptNativeEntityDisposeDeep);
scriptBuiltinAddInt(runtime, "ENTITY_ID_INVALID", ENTITY_ID_INVALID);
scriptBuiltinAddInt(runtime, "COMPONENT_ID_INVALID", COMPONENT_ID_INVALID);
#define X(enumName, type, field, init, dispose, render) \
scriptBuiltinAddInt(runtime, "COMPONENT_TYPE_" #enumName, COMPONENT_TYPE_##enumName);
#include "entity/componentlist.h"
#undef X
}
@@ -0,0 +1,107 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "script/script.h"
#include "entity/entity.h"
/**
* Registers the entity natives (entityAddComponent, entityGetComponent,
* entitySetName, entityGetName, entityFindByName, entityDispose,
* entityDisposeDeep) and the ENTITY_ID_INVALID/COMPONENT_ID_INVALID and
* COMPONENT_TYPE_* constants they take, against the engine's global
* entity/component arrays (entity.h). See scriptNativeEntityManagerRegister
* for the entityAdd() native.
*
* @param runtime The runtime to add them to.
*/
void scriptNativeEntityRegister(scriptruntime_t *runtime);
/**
* Native implementation of entityAddComponent(entityId, type): adds a
* component of the given COMPONENT_TYPE_* to the entity.
*
* @param runtime The runtime.
* @param args The arguments: an entity ID and a component type.
* @param argc Number of arguments.
* @param self The native function value.
* @return The new component's ID.
*/
SCRIPT_NATIVE(scriptNativeEntityAddComponent);
/**
* Native implementation of entityGetComponent(entityId, type): finds the
* entity's component of the given COMPONENT_TYPE_*, or COMPONENT_ID_INVALID
* if it has none.
*
* @param runtime The runtime.
* @param args The arguments: an entity ID and a component type.
* @param argc Number of arguments.
* @param self The native function value.
* @return The component's ID, or COMPONENT_ID_INVALID.
*/
SCRIPT_NATIVE(scriptNativeEntityGetComponent);
/**
* Native implementation of entitySetName(entityId, name): names an entity,
* making it referenceable by entityFindByName.
*
* @param runtime The runtime.
* @param args The arguments: an entity ID and a name.
* @param argc Number of arguments.
* @param self The native function value.
* @return undefined.
*/
SCRIPT_NATIVE(scriptNativeEntitySetName);
/**
* Native implementation of entityGetName(entityId): gets an entity's name,
* or an empty string if it has none.
*
* @param runtime The runtime.
* @param args The arguments: an entity ID.
* @param argc Number of arguments.
* @param self The native function value.
* @return The entity's name.
*/
SCRIPT_NATIVE(scriptNativeEntityGetName);
/**
* Native implementation of entityFindByName(name): finds the first active
* entity with the given name, or ENTITY_ID_INVALID if none matches.
*
* @param runtime The runtime.
* @param args The arguments: a name.
* @param argc Number of arguments.
* @param self The native function value.
* @return The entity's ID, or ENTITY_ID_INVALID.
*/
SCRIPT_NATIVE(scriptNativeEntityFindByName);
/**
* Native implementation of entityDispose(entityId): disposes an entity and
* its components.
*
* @param runtime The runtime.
* @param args The arguments: an entity ID.
* @param argc Number of arguments.
* @param self The native function value.
* @return undefined.
*/
SCRIPT_NATIVE(scriptNativeEntityDispose);
/**
* Native implementation of entityDisposeDeep(entityId): disposes an entity
* and, recursively, every position-component descendant of it.
*
* @param runtime The runtime.
* @param args The arguments: an entity ID.
* @param argc Number of arguments.
* @param self The native function value.
* @return undefined.
*/
SCRIPT_NATIVE(scriptNativeEntityDisposeDeep);
@@ -0,0 +1,20 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "scriptnativeentitymanager.h"
#include "assert/assert.h"
SCRIPT_NATIVE(scriptNativeEntityAdd) {
scriptArgCount(runtime, argc, 0, 0);
return scriptNumber((float)entityManagerAdd());
}
void scriptNativeEntityManagerRegister(scriptruntime_t *runtime) {
assertNotNull(runtime, "scriptNativeEntityManagerRegister needs a runtime, not NULL");
scriptBuiltinAdd(runtime, "entityAdd", scriptNativeEntityAdd);
}
@@ -0,0 +1,28 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "script/script.h"
#include "entity/entity.h"
/**
* Registers the entityAdd() native.
*
* @param runtime The runtime to add it to.
*/
void scriptNativeEntityManagerRegister(scriptruntime_t *runtime);
/**
* Native implementation of entityAdd(): reserves a new entity ID.
*
* @param runtime The runtime.
* @param args Unused, takes no arguments.
* @param argc Number of arguments.
* @param self The native function value.
* @return The new entity's ID.
*/
SCRIPT_NATIVE(scriptNativeEntityAdd);
@@ -0,0 +1,61 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "scriptnativeentityposition.h"
#include "entity/entity.h"
#include "assert/assert.h"
SCRIPT_NATIVE(scriptNativeEntityPositionSetLocalPosition) {
entityid_t entityId;
componentid_t componentId;
vec3 position;
scriptArgCount(runtime, argc, 5, 5);
entityId = (entityid_t)scriptArgInteger(runtime, args, argc, 0);
componentId = (componentid_t)scriptArgInteger(runtime, args, argc, 1);
position[0] = scriptArgNumber(runtime, args, argc, 2).as.number;
position[1] = scriptArgNumber(runtime, args, argc, 3).as.number;
position[2] = scriptArgNumber(runtime, args, argc, 4).as.number;
entityPositionSetLocalPosition(
entityId, componentId, position
);
return scriptUndefined();
}
SCRIPT_NATIVE(scriptNativeEntityPositionLookAt) {
entityid_t entityId;
componentid_t componentId;
vec3 eye;
vec3 target;
vec3 up = { 0.0f, 1.0f, 0.0f };
scriptArgCount(runtime, argc, 8, 8);
entityId = (entityid_t)scriptArgInteger(runtime, args, argc, 0);
componentId = (componentid_t)scriptArgInteger(runtime, args, argc, 1);
eye[0] = scriptArgNumber(runtime, args, argc, 2).as.number;
eye[1] = scriptArgNumber(runtime, args, argc, 3).as.number;
eye[2] = scriptArgNumber(runtime, args, argc, 4).as.number;
target[0] = scriptArgNumber(runtime, args, argc, 5).as.number;
target[1] = scriptArgNumber(runtime, args, argc, 6).as.number;
target[2] = scriptArgNumber(runtime, args, argc, 7).as.number;
entityPositionLookAt(entityId, componentId, eye, target, up);
return scriptUndefined();
}
void scriptNativeEntityPositionRegister(scriptruntime_t *runtime) {
assertNotNull(runtime, "scriptNativeEntityPositionRegister needs a runtime, not NULL");
scriptBuiltinAdd(
runtime, "entityPositionSetLocalPosition",
scriptNativeEntityPositionSetLocalPosition
);
scriptBuiltinAdd(
runtime, "entityPositionLookAt", scriptNativeEntityPositionLookAt
);
}
@@ -0,0 +1,45 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "script/script.h"
#include "entity/component/display/entityposition.h"
/**
* Registers the entityPositionSetLocalPosition and entityPositionLookAt
* natives.
*
* @param runtime The runtime to add it to.
*/
void scriptNativeEntityPositionRegister(scriptruntime_t *runtime);
/**
* Native implementation of
* entityPositionSetLocalPosition(entityId, componentId, x, y, z).
*
* @param runtime The runtime.
* @param args The arguments: an entity ID, a position component ID, and x/y/z.
* @param argc Number of arguments.
* @param self The native function value.
* @return undefined.
*/
SCRIPT_NATIVE(scriptNativeEntityPositionSetLocalPosition);
/**
* Native implementation of
* entityPositionLookAt(entityId, componentId, eyeX, eyeY, eyeZ, targetX,
* targetY, targetZ): places the entity at eye, facing target, with world
* up (0, 1, 0) - SCRIPT_PARAMS_MAX leaves no room for an up argument too.
*
* @param runtime The runtime.
* @param args The arguments: an entity ID, a position component ID, and the
* eye and target points.
* @param argc Number of arguments.
* @param self The native function value.
* @return undefined.
*/
SCRIPT_NATIVE(scriptNativeEntityPositionLookAt);
@@ -0,0 +1,71 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "scriptnativeentityrenderable.h"
#include "entity/entity.h"
#include "error/scriptraise.h"
#include "display/mesh/cube.h"
#include "display/mesh/plane.h"
#include "display/mesh/sphere.h"
#include "display/mesh/capsule.h"
#include "display/mesh/triprism.h"
#include "display/mesh/quad.h"
#include "util/memory.h"
#include "util/string.h"
#include "assert/assert.h"
#define SCRIPT_NATIVE_ENTITY_RENDERABLE_MESH_NAME_MAX 16
// Scripts don't have mesh assets to point at yet, so this just names the
// engine's built in primitive shapes.
static mesh_t *scriptNativeEntityRenderableResolveMesh(const char_t *name) {
if(stringEquals(name, "cube")) return &CUBE_MESH_SIMPLE;
if(stringEquals(name, "plane")) return &PLANE_MESH_SIMPLE;
if(stringEquals(name, "sphere")) return &SPHERE_MESH_SIMPLE;
if(stringEquals(name, "capsule")) return &CAPSULE_MESH_SIMPLE;
if(stringEquals(name, "triprism")) return &TRIPRISM_MESH_SIMPLE;
if(stringEquals(name, "quad")) return &QUAD_MESH_SIMPLE;
return NULL;
}
SCRIPT_NATIVE(scriptNativeEntityRenderableSetMesh) {
entityid_t entityId;
componentid_t componentId;
scriptstring_t *nameArg;
char_t name[SCRIPT_NATIVE_ENTITY_RENDERABLE_MESH_NAME_MAX];
uint16_t length;
mesh_t *mesh;
scriptArgCount(runtime, argc, 3, 3);
entityId = (entityid_t)scriptArgInteger(runtime, args, argc, 0);
componentId = (componentid_t)scriptArgInteger(runtime, args, argc, 1);
nameArg = scriptArgString(runtime, args, argc, 2);
// nameArg->data isn't null terminated - need a C string to compare.
length = nameArg->length;
if(length > SCRIPT_NATIVE_ENTITY_RENDERABLE_MESH_NAME_MAX - 1) {
length = SCRIPT_NATIVE_ENTITY_RENDERABLE_MESH_NAME_MAX - 1;
}
if(length) memoryCopy(name, nameArg->data, length);
name[length] = 0;
mesh = scriptNativeEntityRenderableResolveMesh(name);
if(!mesh) scriptRaise(runtime, "Unknown mesh '%s'", name);
entityRenderableSetMesh(
entityId, componentId, 0, mesh
);
return scriptUndefined();
}
void scriptNativeEntityRenderableRegister(scriptruntime_t *runtime) {
assertNotNull(runtime, "scriptNativeEntityRenderableRegister needs a runtime, not NULL");
scriptBuiltinAdd(
runtime, "entityRenderableSetMesh", scriptNativeEntityRenderableSetMesh
);
}
@@ -0,0 +1,32 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "script/script.h"
#include "entity/component/display/entityrenderable.h"
/**
* Registers the entityRenderableSetMesh native.
*
* @param runtime The runtime to add it to.
*/
void scriptNativeEntityRenderableRegister(scriptruntime_t *runtime);
/**
* Native implementation of
* entityRenderableSetMesh(entityId, componentId, name): sets slot 0 of a
* material renderable to one of the engine's built in primitive meshes, by
* name - "cube", "plane", "sphere", "capsule", "triprism" or "quad".
*
* @param runtime The runtime.
* @param args The arguments: an entity ID, a renderable component ID, and a
* mesh name.
* @param argc Number of arguments.
* @param self The native function value.
* @return undefined.
*/
SCRIPT_NATIVE(scriptNativeEntityRenderableSetMesh);
+8
View File
@@ -7,6 +7,10 @@
#include "script.h"
#include "native/scriptnativeconsole.h"
#include "native/entity/scriptnativeentity.h"
#include "native/entity/scriptnativeentitymanager.h"
#include "native/entity/scriptnativeentityposition.h"
#include "native/entity/scriptnativeentityrenderable.h"
#include "builtin/scriptbuiltinregister.h"
#include "console/console.h"
#include "asset/asset.h"
@@ -68,6 +72,10 @@ errorret_t scriptInit(void) {
scriptBuiltinsRegister(SCRIPT.runtime);
scriptNativeConsoleRegister(SCRIPT.runtime);
scriptNativeEntityManagerRegister(SCRIPT.runtime);
scriptNativeEntityRegister(SCRIPT.runtime);
scriptNativeEntityPositionRegister(SCRIPT.runtime);
scriptNativeEntityRenderableRegister(SCRIPT.runtime);
scriptVmAttach(SCRIPT.runtime);
scriptRuntimeSetPrintHandler(SCRIPT.runtime, scriptPrintHandler);
scriptRuntimeSetLoadHandler(SCRIPT.runtime, scriptLoadHandler);