Disable old ent code
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
# 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)
|
||||
@@ -0,0 +1,12 @@
|
||||
# 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
|
||||
)
|
||||
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* 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);
|
||||
@@ -0,0 +1,316 @@
|
||||
/**
|
||||
* 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]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/**
|
||||
* 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);
|
||||
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "entityrenderable.h"
|
||||
#include "entity/entitymanager.h"
|
||||
#include "display/shader/shaderunlit.h"
|
||||
#include "display/mesh/cube.h"
|
||||
|
||||
void entityRenderableInit(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entityrenderable_t *r = componentGetData(
|
||||
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
r->type = ENTITY_RENDERABLE_TYPE_MATERIAL;
|
||||
r->mesh = &CUBE_MESH_SIMPLE;
|
||||
r->shader = &SHADER_UNLIT;
|
||||
r->material.unlit.color = COLOR_WHITE;
|
||||
}
|
||||
|
||||
entityrenderabletype_t entityRenderableGetType(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entityrenderable_t *r = componentGetData(
|
||||
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
return r->type;
|
||||
}
|
||||
|
||||
void entityRenderableSetType(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const entityrenderabletype_t type
|
||||
) {
|
||||
entityrenderable_t *r = componentGetData(
|
||||
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
r->type = type;
|
||||
}
|
||||
|
||||
mesh_t * entityRenderableGetMesh(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entityrenderable_t *r = componentGetData(
|
||||
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
return r->mesh;
|
||||
}
|
||||
|
||||
void entityRenderableSetMesh(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
mesh_t *mesh
|
||||
) {
|
||||
entityrenderable_t *r = componentGetData(
|
||||
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
r->mesh = mesh;
|
||||
}
|
||||
|
||||
shader_t * entityRenderableGetShader(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entityrenderable_t *r = componentGetData(
|
||||
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
return r->shader;
|
||||
}
|
||||
|
||||
void entityRenderableSetShader(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
shader_t *shader
|
||||
) {
|
||||
entityrenderable_t *r = componentGetData(
|
||||
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
r->shader = shader;
|
||||
}
|
||||
|
||||
shadermaterial_t * entityRenderableGetShaderMaterial(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entityrenderable_t *r = componentGetData(
|
||||
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
return &r->material;
|
||||
}
|
||||
|
||||
void entityRenderableSetColor(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const color_t color
|
||||
) {
|
||||
entityrenderable_t *r = componentGetData(
|
||||
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
r->material.unlit.color = color;
|
||||
}
|
||||
|
||||
void entityRenderableSpriteBatchAdd(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const spritebatchsprite_t *sprite
|
||||
) {
|
||||
entityrenderable_t *r = componentGetData(
|
||||
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
if(r->spritebatch.spriteCount >= ENTITY_RENDERABLE_SPRITEBATCH_SPRITES_MAX) return;
|
||||
r->spritebatch.sprites[r->spritebatch.spriteCount++] = *sprite;
|
||||
}
|
||||
|
||||
void entityRenderableSpriteBatchClear(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entityrenderable_t *r = componentGetData(
|
||||
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
r->spritebatch.spriteCount = 0;
|
||||
}
|
||||
|
||||
void entityRenderableDispose(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entityrenderable_t *r = componentGetData(
|
||||
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
if(
|
||||
r->type == ENTITY_RENDERABLE_TYPE_CALLBACK &&
|
||||
r->userFree &&
|
||||
r->user
|
||||
) {
|
||||
r->userFree(r->user);
|
||||
r->user = NULL;
|
||||
}
|
||||
r->mesh = NULL;
|
||||
r->shader = NULL;
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "entity/entitybase.h"
|
||||
#include "display/mesh/mesh.h"
|
||||
#include "display/shader/shadermaterial.h"
|
||||
#include "display/spritebatch/spritebatch.h"
|
||||
|
||||
#define ENTITY_RENDERABLE_SPRITEBATCH_SPRITES_MAX 64
|
||||
|
||||
typedef enum {
|
||||
ENTITY_RENDERABLE_TYPE_MATERIAL = 0,
|
||||
ENTITY_RENDERABLE_TYPE_SPRITEBATCH,
|
||||
ENTITY_RENDERABLE_TYPE_CALLBACK,
|
||||
} entityrenderabletype_t;
|
||||
|
||||
typedef errorret_t (*entityrenderablecallback_t)(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const mat4 view,
|
||||
const mat4 proj,
|
||||
const mat4 model,
|
||||
void *user
|
||||
);
|
||||
|
||||
typedef struct {
|
||||
spritebatchsprite_t sprites[ENTITY_RENDERABLE_SPRITEBATCH_SPRITES_MAX];
|
||||
uint16_t spriteCount;
|
||||
} entityrenderablespritebatch_t;
|
||||
|
||||
typedef struct {
|
||||
entityrenderabletype_t type;
|
||||
shader_t *shader;
|
||||
union {
|
||||
struct {
|
||||
mesh_t *mesh;
|
||||
shadermaterial_t material;
|
||||
};
|
||||
entityrenderablespritebatch_t spritebatch;
|
||||
struct {
|
||||
entityrenderablecallback_t callback;
|
||||
void (*userFree)(void *user);
|
||||
void *user;
|
||||
};
|
||||
};
|
||||
} entityrenderable_t;
|
||||
|
||||
/**
|
||||
* Initializes the entity renderable component. Defaults to
|
||||
* ENTITY_RENDERABLE_TYPE_MATERIAL, the unlit shader, white color, no mesh.
|
||||
*/
|
||||
void entityRenderableInit(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
|
||||
/**
|
||||
* Disposes the entity renderable component, freeing any callback user data.
|
||||
*/
|
||||
void entityRenderableDispose(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets the renderable type.
|
||||
*/
|
||||
entityrenderabletype_t entityRenderableGetType(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
|
||||
/**
|
||||
* Sets the renderable type.
|
||||
*/
|
||||
void entityRenderableSetType(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const entityrenderabletype_t type
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets the mesh pointer (ENTITY_RENDERABLE_TYPE_MATERIAL only).
|
||||
*/
|
||||
mesh_t * entityRenderableGetMesh(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
|
||||
/**
|
||||
* Sets the mesh pointer (ENTITY_RENDERABLE_TYPE_MATERIAL only).
|
||||
*/
|
||||
void entityRenderableSetMesh(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
mesh_t *mesh
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets the shader pointer.
|
||||
*/
|
||||
shader_t * entityRenderableGetShader(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
|
||||
/**
|
||||
* Sets the shader pointer.
|
||||
*/
|
||||
void entityRenderableSetShader(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
shader_t *shader
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets a pointer to the shader material union
|
||||
* (ENTITY_RENDERABLE_TYPE_MATERIAL only).
|
||||
*/
|
||||
shadermaterial_t * entityRenderableGetShaderMaterial(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
|
||||
/**
|
||||
* Sets the unlit color (ENTITY_RENDERABLE_TYPE_MATERIAL only).
|
||||
*/
|
||||
void entityRenderableSetColor(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const color_t color
|
||||
);
|
||||
|
||||
/**
|
||||
* Appends a sprite to the spritebatch renderable
|
||||
* (ENTITY_RENDERABLE_TYPE_SPRITEBATCH only).
|
||||
* Does nothing if the sprite buffer is full.
|
||||
*/
|
||||
void entityRenderableSpriteBatchAdd(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const spritebatchsprite_t *sprite
|
||||
);
|
||||
|
||||
/**
|
||||
* Clears all buffered sprites from the spritebatch renderable
|
||||
* (ENTITY_RENDERABLE_TYPE_SPRITEBATCH only).
|
||||
*/
|
||||
void entityRenderableSpriteBatchClear(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -0,0 +1,10 @@
|
||||
# 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
|
||||
)
|
||||
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* 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
|
||||
) {
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "entity/entitybase.h"
|
||||
#include "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
|
||||
);
|
||||
@@ -0,0 +1,7 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
entitytrigger.c
|
||||
)
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "entity/entitymanager.h"
|
||||
|
||||
void entityTriggerInit(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entitytrigger_t *t = componentGetData(
|
||||
entityId, componentId, COMPONENT_TYPE_TRIGGER
|
||||
);
|
||||
glm_vec3_zero(t->min);
|
||||
glm_vec3_zero(t->max);
|
||||
}
|
||||
|
||||
entitytrigger_t * entityTriggerGet(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
return componentGetData(entityId, componentId, COMPONENT_TYPE_TRIGGER);
|
||||
}
|
||||
|
||||
bool_t entityTriggerContains(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const vec3 point
|
||||
) {
|
||||
entitytrigger_t *t = componentGetData(
|
||||
entityId, componentId, COMPONENT_TYPE_TRIGGER
|
||||
);
|
||||
return (
|
||||
point[0] >= t->min[0] && point[0] <= t->max[0] &&
|
||||
point[1] >= t->min[1] && point[1] <= t->max[1] &&
|
||||
point[2] >= t->min[2] && point[2] <= t->max[2]
|
||||
);
|
||||
}
|
||||
|
||||
void entityTriggerSetBounds(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const vec3 min,
|
||||
const vec3 max
|
||||
) {
|
||||
entitytrigger_t *t = componentGetData(
|
||||
entityId, componentId, COMPONENT_TYPE_TRIGGER
|
||||
);
|
||||
glm_vec3_copy((float_t*)min, t->min);
|
||||
glm_vec3_copy((float_t*)max, t->max);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "entity/entitybase.h"
|
||||
|
||||
typedef struct {
|
||||
vec3 min;
|
||||
vec3 max;
|
||||
} entitytrigger_t;
|
||||
|
||||
/**
|
||||
* Initializes the trigger component with zeroed bounds.
|
||||
*/
|
||||
void entityTriggerInit(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns a pointer to the trigger component data.
|
||||
*/
|
||||
entitytrigger_t * entityTriggerGet(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns true if the given world-space point lies within [min, max].
|
||||
*/
|
||||
bool_t entityTriggerContains(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const vec3 point
|
||||
);
|
||||
|
||||
/**
|
||||
* Sets both bounds at once.
|
||||
*/
|
||||
void entityTriggerSetBounds(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const vec3 min,
|
||||
const vec3 max
|
||||
);
|
||||
Reference in New Issue
Block a user