Disable old ent code

This commit is contained in:
2026-05-21 10:18:20 -05:00
parent 6502822583
commit efd31237be
30 changed files with 104 additions and 124 deletions
-1
View File
@@ -56,7 +56,6 @@ add_subdirectory(console)
add_subdirectory(display)
add_subdirectory(log)
add_subdirectory(engine)
add_subdirectory(entity)
add_subdirectory(error)
add_subdirectory(input)
add_subdirectory(locale)
-4
View File
@@ -17,8 +17,6 @@
#include "ui/ui.h"
#include "ui/uitextbox.h"
#include "assert/assert.h"
#include "entity/entitymanager.h"
#include "entity/component/physics/entityphysics.h"
#include "physics/physicsmanager.h"
#include "network/network.h"
#include "system/system.h"
@@ -50,7 +48,6 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
errorChain(cutsceneInit());
errorChain(sceneInit());
entityManagerInit();
backpackInit();
physicsManagerInit();
errorChain(networkInit());
@@ -92,7 +89,6 @@ errorret_t engineDispose(void) {
cutsceneDispose();
sceneDispose();
errorChain(networkDispose());
entityManagerDispose();
localeManagerDispose();
uiDispose();
consoleDispose();
-15
View File
@@ -1,15 +0,0 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
entity.c
entitymanager.c
component.c
)
# Subdirs
add_subdirectory(component)
-133
View File
@@ -1,133 +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"
componentdefinition_t COMPONENT_DEFINITIONS[] = {
[COMPONENT_TYPE_NULL] = { 0 },
#define X(enm, type, field, iMethod, dMethod) \
[COMPONENT_TYPE_##enm] = { \
.enumName = #enm, \
.name = #field, \
.init = iMethod, \
.dispose = dMethod \
},
#include "componentlist.h"
#undef X
[COMPONENT_TYPE_COUNT] = { 0 }
};
void componentInit(
const entityid_t entityId,
const componentid_t componentId,
const componenttype_t type
) {
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 = &ENTITY_MANAGER.components[index];
memoryZero(cmp, sizeof(component_t));
cmp->type = type;
if(COMPONENT_DEFINITIONS[type].init) {
COMPONENT_DEFINITIONS[type].init(entityId, componentId);
}
}
void * componentGetData(
const entityid_t entityId,
const componentid_t componentId,
const componenttype_t type
) {
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 = &ENTITY_MANAGER.components[index];
assertTrue(cmp->type == type, "Component type mismatch");
return &cmp->data;
}
componentindex_t componentGetIndex(
const entityid_t entityId,
const componentid_t componentId
) {
assertTrue(entityId < ENTITY_COUNT_MAX, "Entity ID OOB");
assertTrue(componentId < ENTITY_COMPONENT_COUNT_MAX, "Component ID OOB");
return (entityId * ENTITY_COMPONENT_COUNT_MAX) + componentId;
}
entityid_t componentGetEntitiesWithComponent(
const componenttype_t type,
entityid_t outEntities[ENTITY_COUNT_MAX],
componentid_t outComponents[ENTITY_COUNT_MAX]
) {
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");
assertNotNull(outComponents, "Output components array cannot be null");
entityid_t written = 0;
for(entityid_t i = 0; i < ENTITY_COUNT_MAX; i++) {
componentid_t used = ENTITY_MANAGER.entitiesWithComponent[
type * ENTITY_COUNT_MAX + i
];
if(used == COMPONENT_ID_INVALID) continue;
assertTrue(
ENTITY_MANAGER.components[componentGetIndex(i, used)].type == type,
"Component type mismatch in entitiesWithComponent lookup"
);
assertTrue(
(ENTITY_MANAGER.entities[i].state & ENTITY_STATE_ACTIVE) != 0,
"Inactive entity in entitiesWithComponent lookup"
);
assertTrue(
used < ENTITY_COMPONENT_COUNT_MAX,
"Component ID OOB in entitiesWithComponent lookup"
);
assertTrue(
componentGetIndex(i,used) < ENTITY_COUNT_MAX*ENTITY_COMPONENT_COUNT_MAX,
"Component index OOB in entitiesWithComponent lookup"
);
assertTrue(
ENTITY_MANAGER.components[componentGetIndex(i,used)].type == type,
"Component type mismatch in entitiesWithComponent lookup"
);
outComponents[written] = used;
outEntities[written++] = i;
}
return written;
}
void componentDispose(
const entityid_t entityId,
const componentid_t componentId
) {
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 = &ENTITY_MANAGER.components[index];
if(cmp->type == COMPONENT_TYPE_NULL) return;
if(COMPONENT_DEFINITIONS[cmp->type].dispose) {
COMPONENT_DEFINITIONS[cmp->type].dispose(entityId, componentId);
}
cmp->type = COMPONENT_TYPE_NULL;
}
-110
View File
@@ -1,110 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "entitybase.h"
#define X(enumName, type, field, init, dispose) \
// do nothing
#include "componentlist.h"
#undef X
typedef union {
#define X(enumName, type, field, init, dispose) type field;
#include "componentlist.h"
#undef X
} componentdata_t;
typedef struct {
const char_t *enumName;
const char_t *name;
void (*init)(const entityid_t, const componentid_t);
void (*dispose)(const entityid_t, const componentid_t);
} componentdefinition_t;
typedef enum {
COMPONENT_TYPE_NULL,
#define X(enumName, type, field, init, dispose) \
COMPONENT_TYPE_##enumName,
#include "componentlist.h"
#undef X
COMPONENT_TYPE_COUNT
} componenttype_t;
typedef struct {
componenttype_t type;
componentdata_t data;
} component_t;
extern componentdefinition_t COMPONENT_DEFINITIONS[];
/**
* Initializes a component of the given type for the entity with component ID.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param type The type of the component to initialize.
*/
void componentInit(
const entityid_t entityId,
const componentid_t componentId,
const componenttype_t type
);
/**
* Gets the pointer to the data of a component for the entity with component ID.
*
* @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(
const entityid_t entityId,
const componentid_t componentId,
const componenttype_t type
);
/**
* Gets the index of a component for the entity with component ID.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @return The index of the component in the component array.
*/
componentindex_t componentGetIndex(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Gets the entity IDs of all entities with a component of the given type.
*
* @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.
* @param outComponents An array to write the component IDs to.
* @return The number of entity IDs written to outEntities.
*/
entityid_t componentGetEntitiesWithComponent(
const componenttype_t type,
entityid_t outEntities[ENTITY_COUNT_MAX],
componentid_t outComponents[ENTITY_COUNT_MAX]
);
/**
* Disposes of a component for the entity with component ID.
*
* @param entityId The entity ID.
* @param componentId The component ID.
*/
void componentDispose(
const entityid_t entityId,
const componentid_t componentId
);
-9
View File
@@ -1,9 +0,0 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
add_subdirectory(display)
add_subdirectory(physics)
add_subdirectory(script)
add_subdirectory(trigger)
@@ -1,12 +0,0 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
entityposition.c
entitycamera.c
entityrenderable.c
)
@@ -1,96 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "entity/entitymanager.h"
#include "entity/entity.h"
#include "entity/component/display/entityposition.h"
#include "display/framebuffer/framebuffer.h"
#include "display/screen/screen.h"
void entityCameraInit(const entityid_t ent, const componentid_t comp) {
entitycamera_t *cam = (entitycamera_t *)componentGetData(
ent, comp, COMPONENT_TYPE_CAMERA
);
cam->nearClip = 0.1f;
cam->farClip = 100.0f;
cam->projType = ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE;
cam->perspective.fov = glm_rad(45.0f);
}
void entityCameraGetProjection(
const entityid_t ent,
const componentid_t comp,
mat4 out
) {
entitycamera_t *cam = (entitycamera_t *)componentGetData(
ent, comp, COMPONENT_TYPE_CAMERA
);
if(
cam->projType == ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE ||
cam->projType == ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED
) {
glm_mat4_identity(out);
glm_perspective(
cam->perspective.fov,
SCREEN.aspect,
cam->nearClip,
cam->farClip,
out
);
if(cam->projType == ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED) {
out[1][1] *= -1.0f;
}
} else if(cam->projType == ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) {
glm_mat4_identity(out);
glm_ortho(
cam->orthographic.left,
cam->orthographic.right,
cam->orthographic.top,
cam->orthographic.bottom,
cam->nearClip,
cam->farClip,
out
);
}
}
entityid_t entityCameraGetCurrent(void) {
entityid_t camEnts[ENTITY_COUNT_MAX];
componentid_t camComps[ENTITY_COUNT_MAX];
entityid_t count = componentGetEntitiesWithComponent(
COMPONENT_TYPE_CAMERA, camEnts, camComps
);
if(count == 0) return ENTITY_COUNT_MAX;
return camEnts[0];
}
void entityCameraGetForward(const entityid_t entityId, vec2 out) {
componentid_t posComp = entityGetComponent(entityId, COMPONENT_TYPE_POSITION);
entityposition_t *pos = entityPositionGet(entityId, posComp);
// View matrix column layout: M[col][row],
// forward = {-M[0][2], -M[1][2], -M[2][2]}
float_t fx = -pos->worldTransform[0][2];
float_t fz = -pos->worldTransform[2][2];
float_t len = sqrtf(fx * fx + fz * fz);
if(len > 1e-6f) { fx /= len; fz /= len; }
out[0] = fx;
out[1] = fz;
}
void entityCameraGetRight(const entityid_t entityId, vec2 out) {
componentid_t posComp = entityGetComponent(entityId, COMPONENT_TYPE_POSITION);
entityposition_t *pos = entityPositionGet(entityId, posComp);
// View matrix column layout: right = {M[0][0], M[1][0], M[2][0]}
float_t rx = pos->worldTransform[0][0];
float_t rz = pos->worldTransform[2][0];
float_t len = sqrtf(rx * rx + rz * rz);
if(len > 1e-6f) { rx /= len; rz /= len; }
out[0] = rx;
out[1] = rz;
}
@@ -1,79 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "entity/entitybase.h"
typedef enum {
ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE,
ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED,
ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC
} entitycameraprojectiontype_t;
typedef struct {
union {
struct {
float_t fov;
} perspective;
struct {
float_t left;
float_t right;
float_t top;
float_t bottom;
} orthographic;
};
float_t nearClip;
float_t farClip;
entitycameraprojectiontype_t projType;
} entitycamera_t;
/**
* Initializes an entity camera component.
*
* @param ent The entity ID.
* @param comp The component ID.
*/
void entityCameraInit(const entityid_t ent, const componentid_t comp);
/**
* Renders out the projection matrix for the given camera.
*
* @param ent The entity ID.
* @param comp The component ID.
* @param out The output projection matrix.
*/
void entityCameraGetProjection(
const entityid_t ent,
const componentid_t comp,
mat4 out
);
/**
* Returns the entity ID of the first active camera, or ENTITY_COUNT_MAX if
* none are active.
*/
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 entityId The camera entity ID.
* @param out Output vec2: {forwardX, forwardZ} normalized.
*/
void entityCameraGetForward(const entityid_t entityId, vec2 out);
/**
* Gets the camera's horizontal right direction (XZ plane) from its position
* component. Automatically finds the position component on the entity.
*
* @param entityId The camera entity ID.
* @param out Output vec2: {rightX, rightZ} normalized.
*/
void entityCameraGetRight(const entityid_t entityId, vec2 out);
@@ -1,316 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "entity/entitymanager.h"
// Lazily recompute worldTransform from the parent chain.
static void entityPositionUpdateWorld(entityposition_t *pos) {
if(!pos->dirty) return;
if(pos->parentEntityId == ENTITY_ID_INVALID) {
glm_mat4_copy(pos->localTransform, pos->worldTransform);
} else {
entityposition_t *parent = componentGetData(
pos->parentEntityId, pos->parentComponentId, COMPONENT_TYPE_POSITION
);
entityPositionUpdateWorld(parent);
glm_mat4_mul(parent->worldTransform, pos->localTransform, pos->worldTransform);
}
pos->dirty = false;
}
void entityPositionMarkDirty(entityposition_t *pos) {
pos->dirty = true;
for(uint8_t i = 0; i < pos->childCount; i++) {
entityposition_t *child = componentGetData(
pos->childEntityIds[i], pos->childComponentIds[i], COMPONENT_TYPE_POSITION
);
entityPositionMarkDirty(child);
}
}
void entityPositionInit(
const entityid_t entityId,
const componentid_t componentId
) {
entityposition_t *pos = componentGetData(
entityId, componentId, COMPONENT_TYPE_POSITION
);
glm_vec3_zero(pos->position);
glm_vec3_zero(pos->rotation);
glm_vec3_one(pos->scale);
glm_mat4_identity(pos->localTransform);
glm_mat4_identity(pos->worldTransform);
pos->dirty = false;
pos->parentEntityId = ENTITY_ID_INVALID;
pos->parentComponentId = COMPONENT_ID_INVALID;
pos->childCount = 0;
}
void entityPositionLookAt(
const entityid_t entityId,
const componentid_t componentId,
vec3 target,
vec3 up,
vec3 eye
) {
entityposition_t *pos = componentGetData(
entityId, componentId, COMPONENT_TYPE_POSITION
);
glm_lookat(eye, target, up, pos->localTransform);
entityPositionDecompose(pos);
entityPositionMarkDirty(pos);
}
void entityPositionGetTransform(
const entityid_t entityId,
const componentid_t componentId,
mat4 dest
) {
entityposition_t *pos = componentGetData(
entityId, componentId, COMPONENT_TYPE_POSITION
);
entityPositionUpdateWorld(pos);
glm_mat4_copy(pos->worldTransform, dest);
}
void entityPositionGetLocalTransform(
const entityid_t entityId,
const componentid_t componentId,
mat4 dest
) {
entityposition_t *pos = componentGetData(
entityId, componentId, COMPONENT_TYPE_POSITION
);
glm_mat4_copy(pos->localTransform, dest);
}
void entityPositionGetPosition(
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
) {
entityposition_t *pos = componentGetData(
entityId, componentId, COMPONENT_TYPE_POSITION
);
glm_vec3_copy(pos->position, dest);
}
void entityPositionSetPosition(
const entityid_t entityId,
const componentid_t componentId,
vec3 position
) {
entityposition_t *pos = componentGetData(
entityId, componentId, COMPONENT_TYPE_POSITION
);
glm_vec3_copy(position, pos->position);
entityPositionRebuild(pos);
}
void entityPositionGetRotation(
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
) {
entityposition_t *pos = componentGetData(
entityId, componentId, COMPONENT_TYPE_POSITION
);
glm_vec3_copy(pos->rotation, dest);
}
void entityPositionSetRotation(
const entityid_t entityId,
const componentid_t componentId,
vec3 rotation
) {
entityposition_t *pos = componentGetData(
entityId, componentId, COMPONENT_TYPE_POSITION
);
glm_vec3_copy(rotation, pos->rotation);
entityPositionRebuild(pos);
}
void entityPositionGetScale(
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
) {
entityposition_t *pos = componentGetData(
entityId, componentId, COMPONENT_TYPE_POSITION
);
glm_vec3_copy(pos->scale, dest);
}
void entityPositionSetScale(
const entityid_t entityId,
const componentid_t componentId,
vec3 scale
) {
entityposition_t *pos = componentGetData(
entityId, componentId, COMPONENT_TYPE_POSITION
);
glm_vec3_copy(scale, pos->scale);
entityPositionRebuild(pos);
}
void entityPositionSetParent(
const entityid_t entityId,
const componentid_t componentId,
const entityid_t parentEntityId,
const componentid_t parentComponentId
) {
entityposition_t *pos = componentGetData(
entityId, componentId, COMPONENT_TYPE_POSITION
);
// Remove from old parent's child list.
if(pos->parentEntityId != ENTITY_ID_INVALID) {
entityposition_t *oldParent = componentGetData(
pos->parentEntityId, pos->parentComponentId, COMPONENT_TYPE_POSITION
);
for(uint8_t i = 0; i < oldParent->childCount; i++) {
if(
oldParent->childEntityIds[i] == entityId &&
oldParent->childComponentIds[i] == componentId
) {
oldParent->childCount--;
for(uint8_t j = i; j < oldParent->childCount; j++) {
oldParent->childEntityIds[j] = oldParent->childEntityIds[j + 1];
oldParent->childComponentIds[j] = oldParent->childComponentIds[j + 1];
}
break;
}
}
}
pos->parentEntityId = parentEntityId;
pos->parentComponentId = parentComponentId;
// Register with new parent.
if(parentEntityId != ENTITY_ID_INVALID) {
entityposition_t *parent = componentGetData(
parentEntityId, parentComponentId, COMPONENT_TYPE_POSITION
);
if(parent->childCount < ENTITY_POSITION_CHILDREN_MAX) {
parent->childEntityIds[parent->childCount] = entityId;
parent->childComponentIds[parent->childCount] = componentId;
parent->childCount++;
}
}
entityPositionMarkDirty(pos);
}
entityposition_t *entityPositionGet(
const entityid_t entityId,
const componentid_t componentId
) {
return componentGetData(
entityId, componentId, COMPONENT_TYPE_POSITION
);
}
void entityPositionRebuild(entityposition_t *pos) {
glm_mat4_identity(pos->localTransform);
glm_translate(pos->localTransform, pos->position);
glm_rotate_x(pos->localTransform, pos->rotation[0], pos->localTransform);
glm_rotate_y(pos->localTransform, pos->rotation[1], pos->localTransform);
glm_rotate_z(pos->localTransform, pos->rotation[2], pos->localTransform);
glm_scale(pos->localTransform, pos->scale);
entityPositionMarkDirty(pos);
}
void entityPositionDisposeDeep(
const entityid_t entityId,
const componentid_t componentId
) {
entityposition_t *pos = entityPositionGet(entityId, componentId);
// Detach from parent so the parent's child list stays consistent.
if(pos->parentEntityId != ENTITY_ID_INVALID) {
entityPositionSetParent(entityId, componentId, ENTITY_ID_INVALID, COMPONENT_ID_INVALID);
}
// Copy the child list before disposing self (entityDispose invalidates pos).
uint8_t childCount = pos->childCount;
entityid_t childEntityIds[ENTITY_POSITION_CHILDREN_MAX];
componentid_t childComponentIds[ENTITY_POSITION_CHILDREN_MAX];
for(uint8_t i = 0; i < childCount; i++) {
childEntityIds[i] = pos->childEntityIds[i];
childComponentIds[i] = pos->childComponentIds[i];
// Sever the child's parent link so it won't try to modify our disposed data.
entityposition_t *child = entityPositionGet(childEntityIds[i], childComponentIds[i]);
child->parentEntityId = ENTITY_ID_INVALID;
child->parentComponentId = COMPONENT_ID_INVALID;
}
entityDispose(entityId);
for(uint8_t i = 0; i < childCount; i++) {
entityPositionDisposeDeep(childEntityIds[i], childComponentIds[i]);
}
}
void entityPositionDecompose(entityposition_t *pos) {
// Translation: column 3
pos->position[0] = pos->localTransform[3][0];
pos->position[1] = pos->localTransform[3][1];
pos->position[2] = pos->localTransform[3][2];
// Scale: length of each basis column (xyz only)
pos->scale[0] = sqrtf(
pos->localTransform[0][0] * pos->localTransform[0][0] +
pos->localTransform[0][1] * pos->localTransform[0][1] +
pos->localTransform[0][2] * pos->localTransform[0][2]
);
pos->scale[1] = sqrtf(
pos->localTransform[1][0] * pos->localTransform[1][0] +
pos->localTransform[1][1] * pos->localTransform[1][1] +
pos->localTransform[1][2] * pos->localTransform[1][2]
);
pos->scale[2] = sqrtf(
pos->localTransform[2][0] * pos->localTransform[2][0] +
pos->localTransform[2][1] * pos->localTransform[2][1] +
pos->localTransform[2][2] * pos->localTransform[2][2]
);
// Normalize columns to isolate the rotation matrix.
float invS0 = pos->scale[0] > 0.0f ? 1.0f / pos->scale[0] : 0.0f;
float invS1 = pos->scale[1] > 0.0f ? 1.0f / pos->scale[1] : 0.0f;
float invS2 = pos->scale[2] > 0.0f ? 1.0f / pos->scale[2] : 0.0f;
mat4 r;
glm_mat4_identity(r);
r[0][0] = pos->localTransform[0][0] * invS0;
r[0][1] = pos->localTransform[0][1] * invS0;
r[0][2] = pos->localTransform[0][2] * invS0;
r[1][0] = pos->localTransform[1][0] * invS1;
r[1][1] = pos->localTransform[1][1] * invS1;
r[1][2] = pos->localTransform[1][2] * invS1;
r[2][0] = pos->localTransform[2][0] * invS2;
r[2][1] = pos->localTransform[2][1] * invS2;
r[2][2] = pos->localTransform[2][2] * invS2;
// Extract XYZ euler angles (R = Rx * Ry * Rz, column-major)
float sinBeta = glm_clamp(r[2][0], -1.0f, 1.0f);
pos->rotation[1] = asinf(sinBeta);
float cosBeta = cosf(pos->rotation[1]);
if(fabsf(cosBeta) > 1e-6f) {
pos->rotation[0] = atan2f(-r[2][1], r[2][2]);
pos->rotation[2] = atan2f(-r[1][0], r[0][0]);
} else {
// Gimbal lock: pin Z to 0, recover X.
pos->rotation[2] = 0.0f;
pos->rotation[0] = (sinBeta > 0.0f)
? atan2f(r[0][1], r[1][1])
: -atan2f(r[0][1], r[1][1]);
}
}
@@ -1,184 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "entity/entitybase.h"
#define ENTITY_POSITION_CHILDREN_MAX 8
typedef struct {
mat4 localTransform;
mat4 worldTransform;
vec3 position;
vec3 rotation;
vec3 scale;
bool dirty;
entityid_t parentEntityId;
componentid_t parentComponentId;
uint8_t childCount;
entityid_t childEntityIds[ENTITY_POSITION_CHILDREN_MAX];
componentid_t childComponentIds[ENTITY_POSITION_CHILDREN_MAX];
} entityposition_t;
/**
* Initialize the entity position component.
*/
void entityPositionInit(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Transforms the entity's local transform to look at a target point.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param target The target point to look at.
* @param up The up vector.
* @param eye The eye/camera position.
*/
void entityPositionLookAt(
const entityid_t entityId,
const componentid_t componentId,
vec3 target,
vec3 up,
vec3 eye
);
/**
* Gets the world-space transform matrix, recomputing it lazily if dirty.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param dest Destination matrix.
*/
void entityPositionGetTransform(
const entityid_t entityId,
const componentid_t componentId,
mat4 dest
);
/**
* Gets the local transform matrix (does not include parent transforms).
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param dest Destination matrix.
*/
void entityPositionGetLocalTransform(
const entityid_t entityId,
const componentid_t componentId,
mat4 dest
);
/**
* Gets the cached local position.
*/
void entityPositionGetPosition(
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
);
/**
* Sets the local position and marks the world transform dirty.
*/
void entityPositionSetPosition(
const entityid_t entityId,
const componentid_t componentId,
vec3 position
);
/**
* Gets the cached local euler rotation (XYZ, radians).
*/
void entityPositionGetRotation(
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
);
/**
* Sets the local euler rotation (XYZ, radians) and marks the world transform dirty.
*/
void entityPositionSetRotation(
const entityid_t entityId,
const componentid_t componentId,
vec3 rotation
);
/**
* Gets the cached local scale.
*/
void entityPositionGetScale(
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
);
/**
* Sets the local scale and marks the world transform dirty.
*/
void entityPositionSetScale(
const entityid_t entityId,
const componentid_t componentId,
vec3 scale
);
/**
* Sets the parent of this entity's position component.
* Pass ENTITY_ID_INVALID / COMPONENT_ID_INVALID to detach from any parent.
*
* @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(
const entityid_t entityId,
const componentid_t componentId,
const entityid_t parentEntityId,
const componentid_t parentComponentId
);
/**
* Returns a direct pointer to the entity position component data.
* After modifying localTransform directly, call entityPositionMarkDirty().
*/
entityposition_t *entityPositionGet(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Rebuilds the local transform matrix from the cached position/rotation/scale,
* then marks this node and all descendants dirty.
*/
void entityPositionRebuild(entityposition_t *pos);
/**
* Marks this node and all descendants as having a stale world transform.
*/
void entityPositionMarkDirty(entityposition_t *pos);
/**
* Disposes this entity and all of its position-component descendants
* recursively. Detaches from any parent before destroying.
*
* @param entityId The root entity ID.
* @param componentId The root position component ID.
*/
void entityPositionDisposeDeep(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Decomposes the local transform matrix back into the position, rotation
* (XYZ euler, radians), and scale cache fields.
*/
void entityPositionDecompose(entityposition_t *pos);
@@ -1,149 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "entityrenderable.h"
#include "entity/entitymanager.h"
#include "display/shader/shaderunlit.h"
#include "display/mesh/cube.h"
void entityRenderableInit(
const entityid_t entityId,
const componentid_t componentId
) {
entityrenderable_t *r = componentGetData(
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
r->type = ENTITY_RENDERABLE_TYPE_MATERIAL;
r->mesh = &CUBE_MESH_SIMPLE;
r->shader = &SHADER_UNLIT;
r->material.unlit.color = COLOR_WHITE;
}
entityrenderabletype_t entityRenderableGetType(
const entityid_t entityId,
const componentid_t componentId
) {
entityrenderable_t *r = componentGetData(
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
return r->type;
}
void entityRenderableSetType(
const entityid_t entityId,
const componentid_t componentId,
const entityrenderabletype_t type
) {
entityrenderable_t *r = componentGetData(
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
r->type = type;
}
mesh_t * entityRenderableGetMesh(
const entityid_t entityId,
const componentid_t componentId
) {
entityrenderable_t *r = componentGetData(
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
return r->mesh;
}
void entityRenderableSetMesh(
const entityid_t entityId,
const componentid_t componentId,
mesh_t *mesh
) {
entityrenderable_t *r = componentGetData(
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
r->mesh = mesh;
}
shader_t * entityRenderableGetShader(
const entityid_t entityId,
const componentid_t componentId
) {
entityrenderable_t *r = componentGetData(
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
return r->shader;
}
void entityRenderableSetShader(
const entityid_t entityId,
const componentid_t componentId,
shader_t *shader
) {
entityrenderable_t *r = componentGetData(
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
r->shader = shader;
}
shadermaterial_t * entityRenderableGetShaderMaterial(
const entityid_t entityId,
const componentid_t componentId
) {
entityrenderable_t *r = componentGetData(
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
return &r->material;
}
void entityRenderableSetColor(
const entityid_t entityId,
const componentid_t componentId,
const color_t color
) {
entityrenderable_t *r = componentGetData(
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
r->material.unlit.color = color;
}
void entityRenderableSpriteBatchAdd(
const entityid_t entityId,
const componentid_t componentId,
const spritebatchsprite_t *sprite
) {
entityrenderable_t *r = componentGetData(
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
if(r->spritebatch.spriteCount >= ENTITY_RENDERABLE_SPRITEBATCH_SPRITES_MAX) return;
r->spritebatch.sprites[r->spritebatch.spriteCount++] = *sprite;
}
void entityRenderableSpriteBatchClear(
const entityid_t entityId,
const componentid_t componentId
) {
entityrenderable_t *r = componentGetData(
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
r->spritebatch.spriteCount = 0;
}
void entityRenderableDispose(
const entityid_t entityId,
const componentid_t componentId
) {
entityrenderable_t *r = componentGetData(
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
if(
r->type == ENTITY_RENDERABLE_TYPE_CALLBACK &&
r->userFree &&
r->user
) {
r->userFree(r->user);
r->user = NULL;
}
r->mesh = NULL;
r->shader = NULL;
}
@@ -1,157 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "entity/entitybase.h"
#include "display/mesh/mesh.h"
#include "display/shader/shadermaterial.h"
#include "display/spritebatch/spritebatch.h"
#define ENTITY_RENDERABLE_SPRITEBATCH_SPRITES_MAX 64
typedef enum {
ENTITY_RENDERABLE_TYPE_MATERIAL = 0,
ENTITY_RENDERABLE_TYPE_SPRITEBATCH,
ENTITY_RENDERABLE_TYPE_CALLBACK,
} entityrenderabletype_t;
typedef errorret_t (*entityrenderablecallback_t)(
const entityid_t entityId,
const componentid_t componentId,
const mat4 view,
const mat4 proj,
const mat4 model,
void *user
);
typedef struct {
spritebatchsprite_t sprites[ENTITY_RENDERABLE_SPRITEBATCH_SPRITES_MAX];
uint16_t spriteCount;
} entityrenderablespritebatch_t;
typedef struct {
entityrenderabletype_t type;
shader_t *shader;
union {
struct {
mesh_t *mesh;
shadermaterial_t material;
};
entityrenderablespritebatch_t spritebatch;
struct {
entityrenderablecallback_t callback;
void (*userFree)(void *user);
void *user;
};
};
} entityrenderable_t;
/**
* Initializes the entity renderable component. Defaults to
* ENTITY_RENDERABLE_TYPE_MATERIAL, the unlit shader, white color, no mesh.
*/
void entityRenderableInit(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Disposes the entity renderable component, freeing any callback user data.
*/
void entityRenderableDispose(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Gets the renderable type.
*/
entityrenderabletype_t entityRenderableGetType(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Sets the renderable type.
*/
void entityRenderableSetType(
const entityid_t entityId,
const componentid_t componentId,
const entityrenderabletype_t type
);
/**
* Gets the mesh pointer (ENTITY_RENDERABLE_TYPE_MATERIAL only).
*/
mesh_t * entityRenderableGetMesh(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Sets the mesh pointer (ENTITY_RENDERABLE_TYPE_MATERIAL only).
*/
void entityRenderableSetMesh(
const entityid_t entityId,
const componentid_t componentId,
mesh_t *mesh
);
/**
* Gets the shader pointer.
*/
shader_t * entityRenderableGetShader(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Sets the shader pointer.
*/
void entityRenderableSetShader(
const entityid_t entityId,
const componentid_t componentId,
shader_t *shader
);
/**
* Gets a pointer to the shader material union
* (ENTITY_RENDERABLE_TYPE_MATERIAL only).
*/
shadermaterial_t * entityRenderableGetShaderMaterial(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Sets the unlit color (ENTITY_RENDERABLE_TYPE_MATERIAL only).
*/
void entityRenderableSetColor(
const entityid_t entityId,
const componentid_t componentId,
const color_t color
);
/**
* Appends a sprite to the spritebatch renderable
* (ENTITY_RENDERABLE_TYPE_SPRITEBATCH only).
* Does nothing if the sprite buffer is full.
*/
void entityRenderableSpriteBatchAdd(
const entityid_t entityId,
const componentid_t componentId,
const spritebatchsprite_t *sprite
);
/**
* Clears all buffered sprites from the spritebatch renderable
* (ENTITY_RENDERABLE_TYPE_SPRITEBATCH only).
*/
void entityRenderableSpriteBatchClear(
const entityid_t entityId,
const componentid_t componentId
);
@@ -1,10 +0,0 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
entityphysics.c
)
@@ -1,126 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "entityphysics.h"
#include "entity/entitymanager.h"
#include "entity/component/display/entityposition.h"
#include "physics/physicsmanager.h"
#include "assert/assert.h"
#include "util/memory.h"
void entityPhysicsInit(
const entityid_t entityId,
const componentid_t componentId
) {
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
assertNotNull(phys, "Failed to get physics component data");
memoryZero(phys, sizeof(entityphysics_t));
// Default to cube
phys->type = PHYSICS_BODY_DYNAMIC;
phys->shape.type = PHYSICS_SHAPE_CUBE;
phys->shape.data.cube.halfExtents[0] = 0.5f;
phys->shape.data.cube.halfExtents[1] = 0.5f;
phys->shape.data.cube.halfExtents[2] = 0.5f;
phys->gravityScale = 1.0f;
phys->onGround = false;
}
entityphysics_t *entityPhysicsGet(
const entityid_t entityId,
const componentid_t componentId
) {
return componentGetData(entityId, componentId, COMPONENT_TYPE_PHYSICS);
}
void entityPhysicsSetShape(
const entityid_t entityId,
const componentid_t componentId,
const physicsshape_t shape
) {
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
assertNotNull(phys, "Failed to get physics component data");
phys->shape = shape;
// TODO: Do I need to reset the state for ground/active?
}
physicsshape_t entityPhysicsGetShape(
const entityid_t entityId,
const componentid_t componentId
) {
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
assertNotNull(phys, "Failed to get physics component data");
return phys->shape;
}
void entityPhysicsGetVelocity(
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
) {
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
assertNotNull(phys, "Failed to get physics component data");
glm_vec3_copy(phys->velocity, dest);
}
void entityPhysicsSetVelocity(
const entityid_t entityId,
const componentid_t componentId,
vec3 velocity
) {
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
assertNotNull(phys, "Failed to get physics component data");
glm_vec3_copy(velocity, phys->velocity);
}
void entityPhysicsApplyImpulse(
const entityid_t entityId,
const componentid_t componentId,
vec3 impulse
) {
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
assertNotNull(phys, "Failed to get physics component data");
if(phys->type == PHYSICS_BODY_STATIC) return;
glm_vec3_add(phys->velocity, impulse, phys->velocity);
}
bool_t entityPhysicsIsOnGround(
const entityid_t entityId,
const componentid_t componentId
) {
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
assertNotNull(phys, "Failed to get physics component data");
return phys->onGround;
}
void entityPhysicsSetBodyType(
const entityid_t entityId,
const componentid_t componentId,
const physicsbodytype_t type
) {
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
assertNotNull(phys, "Failed to get physics component data");
phys->type = type;
}
physicsbodytype_t entityPhysicsGetBodyType(
const entityid_t entityId,
const componentid_t componentId
) {
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
assertNotNull(phys, "Failed to get physics component data");
return phys->type;
}
void entityPhysicsDispose(
const entityid_t entityId,
const componentid_t componentId
) {
}
@@ -1,157 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "entity/entitybase.h"
#include "physics/physicsshape.h"
#include "physics/physicsbodytype.h"
typedef struct {
physicsbodytype_t type;
physicsshape_t shape;
vec3 velocity;
float_t gravityScale;
bool_t onGround;
} entityphysics_t;
/**
* Initializes the physics component: allocates a body in PHYSICS_WORLD.
* Asserts if the world body limit is reached.
*/
void entityPhysicsInit(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Gets the underlying physics structure (temporarily) for the given entity.
* This is really just intended for doing operations faster than using the
* getters and setters, but it is preferred that you use those.
*
* @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(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Sets the shape of the entity's physics body. This will not reset the body
* state, so if you change from a cube to a sphere, it will keep the same
* velocity and onGround state.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param shape The new shape to set on the physics body.
*/
void entityPhysicsSetShape(
const entityid_t entityId,
const componentid_t componentId,
const physicsshape_t shape
);
/**
* Gets the shape of the entity's physics body.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @return The shape of the physics body.
*/
physicsshape_t entityPhysicsGetShape(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Gets the velocity of the entity's physics body.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param dest The destination vec3 to write the velocity to.
*/
void entityPhysicsGetVelocity(
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
);
/**
* Sets the velocity of the entity's physics body. This is not an impulse, so
* it will be affected by mass and drag.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param velocity The new velocity to set on the physics body.
*/
void entityPhysicsSetVelocity(
const entityid_t entityId,
const componentid_t componentId,
vec3 velocity
);
/**
* Applies an impulse to the entity's physics body. This is an immediate
* velocity change that is not affected by mass or drag. No-op on STATIC bodies.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param impulse The impulse to apply to the physics body.
*/
void entityPhysicsApplyImpulse(
const entityid_t entityId,
const componentid_t componentId,
vec3 impulse
);
/**
* Returns true if the entity's physics body rested on a surface during the last
* step or move.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @return True if the body is on the ground, false otherwise.
*/
bool_t entityPhysicsIsOnGround(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Sets the body type of the entity's physics body.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param type The body type to set.
*/
void entityPhysicsSetBodyType(
const entityid_t entityId,
const componentid_t componentId,
const physicsbodytype_t type
);
/**
* Gets the body type of the entity's physics body.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @return The body type of the physics body.
*/
physicsbodytype_t entityPhysicsGetBodyType(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Releases the body slot back to PHYSICS_WORLD. Called automatically when
* the component is disposed via the component system.
*/
void entityPhysicsDispose(
const entityid_t entityId,
const componentid_t componentId
);
@@ -1,7 +0,0 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
@@ -1,9 +0,0 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
entitytrigger.c
)
@@ -1,54 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "entity/entitymanager.h"
void entityTriggerInit(
const entityid_t entityId,
const componentid_t componentId
) {
entitytrigger_t *t = componentGetData(
entityId, componentId, COMPONENT_TYPE_TRIGGER
);
glm_vec3_zero(t->min);
glm_vec3_zero(t->max);
}
entitytrigger_t * entityTriggerGet(
const entityid_t entityId,
const componentid_t componentId
) {
return componentGetData(entityId, componentId, COMPONENT_TYPE_TRIGGER);
}
bool_t entityTriggerContains(
const entityid_t entityId,
const componentid_t componentId,
const vec3 point
) {
entitytrigger_t *t = componentGetData(
entityId, componentId, COMPONENT_TYPE_TRIGGER
);
return (
point[0] >= t->min[0] && point[0] <= t->max[0] &&
point[1] >= t->min[1] && point[1] <= t->max[1] &&
point[2] >= t->min[2] && point[2] <= t->max[2]
);
}
void entityTriggerSetBounds(
const entityid_t entityId,
const componentid_t componentId,
const vec3 min,
const vec3 max
) {
entitytrigger_t *t = componentGetData(
entityId, componentId, COMPONENT_TYPE_TRIGGER
);
glm_vec3_copy((float_t*)min, t->min);
glm_vec3_copy((float_t*)max, t->max);
}
@@ -1,49 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "entity/entitybase.h"
typedef struct {
vec3 min;
vec3 max;
} entitytrigger_t;
/**
* Initializes the trigger component with zeroed bounds.
*/
void entityTriggerInit(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Returns a pointer to the trigger component data.
*/
entitytrigger_t * entityTriggerGet(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Returns true if the given world-space point lies within [min, max].
*/
bool_t entityTriggerContains(
const entityid_t entityId,
const componentid_t componentId,
const vec3 point
);
/**
* Sets both bounds at once.
*/
void entityTriggerSetBounds(
const entityid_t entityId,
const componentid_t componentId,
const vec3 min,
const vec3 max
);
-24
View File
@@ -1,24 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "entity/component/display/entityposition.h"
#include "entity/component/display/entitycamera.h"
#include "entity/component/display/entityrenderable.h"
#include "entity/component/physics/entityphysics.h"
#include "entity/component/trigger/entitytrigger.h"
// Name (Uppercase)
// Structure
// Field name (lowercase)
// Init function (optional)
// Dispose function (optional)
X(POSITION, entityposition_t, position, entityPositionInit, NULL)
X(CAMERA, entitycamera_t, camera, entityCameraInit, NULL)
X(RENDERABLE, entityrenderable_t, renderable, entityRenderableInit, entityRenderableDispose)
X(PHYSICS, entityphysics_t, physics, entityPhysicsInit, entityPhysicsDispose)
X(TRIGGER, entitytrigger_t, trigger, entityTriggerInit, NULL)
-98
View File
@@ -1,98 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "entitymanager.h"
#include "component/display/entityposition.h"
#include "util/memory.h"
#include "assert/assert.h"
void entityInit(const entityid_t entityId) {
entity_t *ent = &ENTITY_MANAGER.entities[entityId];
memoryZero(ent, sizeof(entity_t));
// Mark all component types not using this entity.
for(
componenttype_t compType = 0;
compType < COMPONENT_TYPE_COUNT;
compType++
) {
ENTITY_MANAGER.entitiesWithComponent[
compType * ENTITY_COUNT_MAX + entityId
] = COMPONENT_ID_INVALID;
}
ent->state |= ENTITY_STATE_ACTIVE;
}
componentid_t entityAddComponent(
const entityid_t entityId,
const componenttype_t type
) {
componentindex_t compInd;
entity_t *ent = &ENTITY_MANAGER.entities[entityId];
for(componentid_t i = 0; i < ENTITY_COMPONENT_COUNT_MAX; i++) {
compInd = componentGetIndex(entityId, i);
if(ENTITY_MANAGER.components[compInd].type != COMPONENT_TYPE_NULL) {
assertTrue(
ENTITY_MANAGER.components[compInd].type != type,
"Entity already has component of this type"
);
continue;
}
componentInit(entityId, i, type);
ENTITY_MANAGER.entitiesWithComponent[
type * ENTITY_COUNT_MAX + entityId
] = i;
return i;
}
assertUnreachable("Entity has no more component slots available");
return COMPONENT_ID_INVALID;
}
componentid_t entityGetComponent(
const entityid_t entityId,
const componenttype_t type
) {
componentid_t compId = ENTITY_MANAGER.entitiesWithComponent[
type * ENTITY_COUNT_MAX + entityId
];
if(compId == COMPONENT_ID_INVALID) return compId;
assertTrue(
ENTITY_MANAGER.components[componentGetIndex(entityId, compId)].type == type,
"Component type mismatch"
);
return compId;
}
void entityDisposeDeep(const entityid_t entityId) {
componentid_t posComp = entityGetComponent(entityId, COMPONENT_TYPE_POSITION);
if(posComp != COMPONENT_ID_INVALID) {
entityPositionDisposeDeep(entityId, posComp);
} else {
entityDispose(entityId);
}
}
void entityDispose(const entityid_t entityId) {
componentindex_t compInd;
entity_t *ent = &ENTITY_MANAGER.entities[entityId];
for(componentid_t i = 0; i < ENTITY_COMPONENT_COUNT_MAX; i++) {
compInd = componentGetIndex(entityId, i);
componenttype_t type = ENTITY_MANAGER.components[compInd].type;
if(type == COMPONENT_TYPE_NULL) continue;
ENTITY_MANAGER.entitiesWithComponent[
type * ENTITY_COUNT_MAX + entityId
] = COMPONENT_ID_INVALID;
componentDispose(entityId, i);
}
ent->state = 0;
}
-63
View File
@@ -1,63 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "component.h"
#define ENTITY_STATE_ACTIVE (1 << 0)
typedef struct {
uint8_t state;
} entity_t;
/**
* Initializes an entity with the given ID.
*
* @param entityId The ID of the entity to initialize.
*/
void entityInit(const entityid_t entityId);
/**
* Adds a component of the given type to the entity with the given ID.
*
* @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(
const entityid_t entityId,
const componenttype_t type
);
/**
* 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 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(
const entityid_t entityId,
const componenttype_t type
);
/**
* Disposes of an entity with the given ID.
*
* @param entityId The ID of the entity to dispose of.
*/
void entityDispose(const entityid_t entityId);
/**
* Disposes of an entity and all of its position-component descendants
* recursively. If the entity has no position component, behaves like
* entityDispose.
*
* @param entityId The root entity ID.
*/
void entityDisposeDeep(const entityid_t entityId);
-19
View File
@@ -1,19 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
#define ENTITY_COUNT_MAX 20
#define ENTITY_COMPONENT_COUNT_MAX 8
#define ENTITY_ID_INVALID 0xFF
#define COMPONENT_ID_INVALID 0xFF
typedef uint8_t entityid_t;
typedef uint8_t componentid_t;
typedef uint16_t componentindex_t;
-44
View File
@@ -1,44 +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"
entitymanager_t ENTITY_MANAGER;
void entityManagerInit(void) {
memoryZero(&ENTITY_MANAGER, sizeof(entitymanager_t));
memorySet(
ENTITY_MANAGER.entitiesWithComponent, COMPONENT_ID_INVALID,
sizeof(entityid_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() {
for(entityid_t i = 0; i < ENTITY_COUNT_MAX; i++) {
if((ENTITY_MANAGER.entities[i].state & ENTITY_STATE_ACTIVE) != 0) continue;
entityInit(i);
return i;
}
assertUnreachable("No more entity IDs available");
return ENTITY_ID_INVALID;
}
void entityManagerDispose(void) {
for(entityid_t i = 0; i < ENTITY_COUNT_MAX; i++) {
if((ENTITY_MANAGER.entities[i].state & ENTITY_STATE_ACTIVE) == 0) continue;
entityDispose(i);
}
}
-34
View File
@@ -1,34 +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 {
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;
extern entitymanager_t ENTITY_MANAGER;
/**
* Initializes the entity manager.
*/
void entityManagerInit(void);
/**
* Adds / Reserves a new entity ID.
*
* @return The new entity ID.
*/
entityid_t entityManagerAdd();
/**
* Disposes of the entity manager, in turn freeing all entities and components.
*/
void entityManagerDispose(void);
-9
View File
@@ -7,16 +7,12 @@
#include "mapchunk.h"
#include "map.h"
#include "entity/entitymanager.h"
#include "util/memory.h"
#include "util/string.h"
#include "asset/asset.h"
#include "console/console.h"
errorret_t mapChunkLoad(mapchunk_t *chunk) {
chunk->entityCount = 0;
memoryZero(chunk->entities, sizeof(chunk->entities));
if(MAP.handle[0] == '\0') errorOk();
char_t path[ASSET_FILE_NAME_MAX];
@@ -48,9 +44,4 @@ void mapChunkUnload(mapchunk_t *chunk) {
(int)chunk->position.y,
(int)chunk->position.z
);
for(uint8_t i = 0; i < chunk->entityCount; i++) {
entityDispose(chunk->entities[i]);
}
chunk->entityCount = 0;
}
-3
View File
@@ -7,15 +7,12 @@
#pragma once
#include "maptypes.h"
#include "entity/entitybase.h"
#include "error/error.h"
#define MAP_CHUNK_ENTITY_COUNT_MAX 64
typedef struct {
chunkpos_t position;
entityid_t entities[MAP_CHUNK_ENTITY_COUNT_MAX];
uint8_t entityCount;
} mapchunk_t;
/**
+104 -104
View File
@@ -8,8 +8,8 @@
#include "physicsworld.h"
#include "assert/assert.h"
#include "util/memory.h"
#include "entity/entity.h"
#include "entity/component.h"
// #include "entity/entity.h"
// #include "entity/component.h"
#include "physicstest.h"
physicsworld_t PHYSICS_WORLD;
@@ -23,129 +23,129 @@ void physicsWorldInit() {
}
void physicsWorldStep(const float_t dt) {
assertTrue(dt > 0.0f, "Delta time must be positive");
// assertTrue(dt > 0.0f, "Delta time must be positive");
entityid_t physEnts[ENTITY_COUNT_MAX];
componentid_t physComps[ENTITY_COUNT_MAX];
entityid_t physCount = componentGetEntitiesWithComponent(
COMPONENT_TYPE_PHYSICS, physEnts, physComps
);
// entityid_t physEnts[ENTITY_COUNT_MAX];
// componentid_t physComps[ENTITY_COUNT_MAX];
// entityid_t physCount = componentGetEntitiesWithComponent(
// COMPONENT_TYPE_PHYSICS, physEnts, physComps
// );
/* Pre-fetch all position and physics pointers once. */
entityposition_t *positions[ENTITY_COUNT_MAX];
entityphysics_t *physBodies[ENTITY_COUNT_MAX];
for(entityid_t i = 0; i < physCount; i++) {
componentid_t posComp = entityGetComponent(
physEnts[i], COMPONENT_TYPE_POSITION
);
positions[i] = (posComp != 0xFF)
? entityPositionGet(physEnts[i], posComp)
: NULL;
physBodies[i] = entityPhysicsGet(physEnts[i], physComps[i]);
}
// /* Pre-fetch all position and physics pointers once. */
// entityposition_t *positions[ENTITY_COUNT_MAX];
// entityphysics_t *physBodies[ENTITY_COUNT_MAX];
// for(entityid_t i = 0; i < physCount; i++) {
// componentid_t posComp = entityGetComponent(
// physEnts[i], COMPONENT_TYPE_POSITION
// );
// positions[i] = (posComp != 0xFF)
// ? entityPositionGet(physEnts[i], posComp)
// : NULL;
// physBodies[i] = entityPhysicsGet(physEnts[i], physComps[i]);
// }
/* Phase 1: integrate dynamic bodies (gravity + velocity → position).
* Writes directly to pos->position, matrix rebuilt at end. */
for(entityid_t i = 0; i < physCount; i++) {
if(!positions[i]) continue;
entityphysics_t *phys = physBodies[i];
if(phys->type != PHYSICS_BODY_DYNAMIC) continue;
// /* Phase 1: integrate dynamic bodies (gravity + velocity → position).
// * Writes directly to pos->position, matrix rebuilt at end. */
// for(entityid_t i = 0; i < physCount; i++) {
// if(!positions[i]) continue;
// entityphysics_t *phys = physBodies[i];
// if(phys->type != PHYSICS_BODY_DYNAMIC) continue;
phys->onGround = false;
// phys->onGround = false;
phys->velocity[0] += PHYSICS_WORLD.gravity[0] * phys->gravityScale * dt;
phys->velocity[1] += PHYSICS_WORLD.gravity[1] * phys->gravityScale * dt;
phys->velocity[2] += PHYSICS_WORLD.gravity[2] * phys->gravityScale * dt;
// phys->velocity[0] += PHYSICS_WORLD.gravity[0] * phys->gravityScale * dt;
// phys->velocity[1] += PHYSICS_WORLD.gravity[1] * phys->gravityScale * dt;
// phys->velocity[2] += PHYSICS_WORLD.gravity[2] * phys->gravityScale * dt;
float_t *pos = positions[i]->position;
pos[0] += phys->velocity[0] * dt;
pos[1] += phys->velocity[1] * dt;
pos[2] += phys->velocity[2] * dt;
}
// float_t *pos = positions[i]->position;
// pos[0] += phys->velocity[0] * dt;
// pos[1] += phys->velocity[1] * dt;
// pos[2] += phys->velocity[2] * dt;
// }
/* Phase 2: dynamic vs static/kinematic. */
for(entityid_t i = 0; i < physCount; i++) {
if(!positions[i]) continue;
entityphysics_t *phys = physBodies[i];
if(phys->type != PHYSICS_BODY_DYNAMIC) continue;
// /* Phase 2: dynamic vs static/kinematic. */
// for(entityid_t i = 0; i < physCount; i++) {
// if(!positions[i]) continue;
// entityphysics_t *phys = physBodies[i];
// if(phys->type != PHYSICS_BODY_DYNAMIC) continue;
float_t *pos = positions[i]->position;
// float_t *pos = positions[i]->position;
for(entityid_t j = 0; j < physCount; j++) {
if(i == j || !positions[j]) continue;
entityphysics_t *otherPhys = physBodies[j];
if(otherPhys->type == PHYSICS_BODY_DYNAMIC) continue;
// for(entityid_t j = 0; j < physCount; j++) {
// if(i == j || !positions[j]) continue;
// entityphysics_t *otherPhys = physBodies[j];
// if(otherPhys->type == PHYSICS_BODY_DYNAMIC) continue;
vec3 normal; float_t depth;
if(!physicsTestShapeVsShape(
pos, phys->shape,
positions[j]->position, otherPhys->shape,
normal, &depth
)) continue;
// vec3 normal; float_t depth;
// if(!physicsTestShapeVsShape(
// pos, phys->shape,
// positions[j]->position, otherPhys->shape,
// normal, &depth
// )) continue;
pos[0] += normal[0] * depth;
pos[1] += normal[1] * depth;
pos[2] += normal[2] * depth;
// pos[0] += normal[0] * depth;
// pos[1] += normal[1] * depth;
// pos[2] += normal[2] * depth;
float_t vn = glm_vec3_dot(phys->velocity, normal);
if(vn < 0.0f) {
phys->velocity[0] -= vn * normal[0];
phys->velocity[1] -= vn * normal[1];
phys->velocity[2] -= vn * normal[2];
}
// float_t vn = glm_vec3_dot(phys->velocity, normal);
// if(vn < 0.0f) {
// phys->velocity[0] -= vn * normal[0];
// phys->velocity[1] -= vn * normal[1];
// phys->velocity[2] -= vn * normal[2];
// }
if(normal[1] > PHYSICS_GROUND_THRESHOLD) phys->onGround = true;
}
}
// if(normal[1] > PHYSICS_GROUND_THRESHOLD) phys->onGround = true;
// }
// }
/* Phase 3: dynamic vs dynamic. */
for(entityid_t i = 0; i < physCount; i++) {
if(!positions[i]) continue;
entityphysics_t *physA = physBodies[i];
if(physA->type != PHYSICS_BODY_DYNAMIC) continue;
// /* Phase 3: dynamic vs dynamic. */
// for(entityid_t i = 0; i < physCount; i++) {
// if(!positions[i]) continue;
// entityphysics_t *physA = physBodies[i];
// if(physA->type != PHYSICS_BODY_DYNAMIC) continue;
float_t *posA = positions[i]->position;
// float_t *posA = positions[i]->position;
for(entityid_t j = i + 1; j < physCount; j++) {
if(!positions[j]) continue;
entityphysics_t *physB = physBodies[j];
if(physB->type != PHYSICS_BODY_DYNAMIC) continue;
// for(entityid_t j = i + 1; j < physCount; j++) {
// if(!positions[j]) continue;
// entityphysics_t *physB = physBodies[j];
// if(physB->type != PHYSICS_BODY_DYNAMIC) continue;
float_t *posB = positions[j]->position;
// float_t *posB = positions[j]->position;
vec3 normal; float_t depth;
if(!physicsTestShapeVsShape(
posA, physA->shape, posB, physB->shape, normal, &depth
)) continue;
// vec3 normal; float_t depth;
// if(!physicsTestShapeVsShape(
// posA, physA->shape, posB, physB->shape, normal, &depth
// )) continue;
posA[0] += normal[0] * depth * 0.5f;
posA[1] += normal[1] * depth * 0.5f;
posA[2] += normal[2] * depth * 0.5f;
// posA[0] += normal[0] * depth * 0.5f;
// posA[1] += normal[1] * depth * 0.5f;
// posA[2] += normal[2] * depth * 0.5f;
posB[0] -= normal[0] * depth * 0.5f;
posB[1] -= normal[1] * depth * 0.5f;
posB[2] -= normal[2] * depth * 0.5f;
// posB[0] -= normal[0] * depth * 0.5f;
// posB[1] -= normal[1] * depth * 0.5f;
// posB[2] -= normal[2] * depth * 0.5f;
float_t v_rel = glm_vec3_dot(physA->velocity, normal)
- glm_vec3_dot(physB->velocity, normal);
if(v_rel < 0.0f) {
physA->velocity[0] -= v_rel * normal[0];
physA->velocity[1] -= v_rel * normal[1];
physA->velocity[2] -= v_rel * normal[2];
physB->velocity[0] += v_rel * normal[0];
physB->velocity[1] += v_rel * normal[1];
physB->velocity[2] += v_rel * normal[2];
}
// float_t v_rel = glm_vec3_dot(physA->velocity, normal)
// - glm_vec3_dot(physB->velocity, normal);
// if(v_rel < 0.0f) {
// physA->velocity[0] -= v_rel * normal[0];
// physA->velocity[1] -= v_rel * normal[1];
// physA->velocity[2] -= v_rel * normal[2];
// physB->velocity[0] += v_rel * normal[0];
// physB->velocity[1] += v_rel * normal[1];
// physB->velocity[2] += v_rel * normal[2];
// }
if( normal[1] > PHYSICS_GROUND_THRESHOLD) physA->onGround = true;
if(-normal[1] > PHYSICS_GROUND_THRESHOLD) physB->onGround = true;
}
}
// if( normal[1] > PHYSICS_GROUND_THRESHOLD) physA->onGround = true;
// if(-normal[1] > PHYSICS_GROUND_THRESHOLD) physB->onGround = true;
// }
// }
/* Rebuild transforms for all dynamic bodies once, after all phases. */
for(entityid_t i = 0; i < physCount; i++) {
if(!positions[i]) continue;
if(physBodies[i]->type != PHYSICS_BODY_DYNAMIC) continue;
entityPositionRebuild(positions[i]);
}
// /* Rebuild transforms for all dynamic bodies once, after all phases. */
// for(entityid_t i = 0; i < physCount; i++) {
// if(!positions[i]) continue;
// if(physBodies[i]->type != PHYSICS_BODY_DYNAMIC) continue;
// entityPositionRebuild(positions[i]);
// }
}
-3
View File
@@ -9,12 +9,9 @@
#include "log/log.h"
#include "time/time.h"
#include "display/screen/screen.h"
#include "entity/entitymanager.h"
#include "entity/component/display/entityrenderable.h"
#include "display/shader/shaderunlit.h"
#include "display/spritebatch/spritebatch.h"
#include "display/screen/screen.h"
#include "console/console.h"
#include "util/string.h"
#include "ui/ui.h"