Add parent/child
This commit is contained in:
@@ -87,7 +87,7 @@ entityid_t componentGetEntitiesWithComponent(
|
|||||||
componentid_t used = ENTITY_MANAGER.entitiesWithComponent[
|
componentid_t used = ENTITY_MANAGER.entitiesWithComponent[
|
||||||
type * ENTITY_COUNT_MAX + i
|
type * ENTITY_COUNT_MAX + i
|
||||||
];
|
];
|
||||||
if(used == 0xFF) continue;
|
if(used == COMPONENT_ID_INVALID) continue;
|
||||||
assertTrue(
|
assertTrue(
|
||||||
ENTITY_MANAGER.components[componentGetIndex(i, used)].type == type,
|
ENTITY_MANAGER.components[componentGetIndex(i, used)].type == type,
|
||||||
"Component type mismatch in entitiesWithComponent lookup"
|
"Component type mismatch in entitiesWithComponent lookup"
|
||||||
|
|||||||
@@ -7,6 +7,33 @@
|
|||||||
|
|
||||||
#include "entity/entitymanager.h"
|
#include "entity/entitymanager.h"
|
||||||
|
|
||||||
|
// Lazily recompute worldTransform from the parent chain.
|
||||||
|
static void entityPositionUpdateWorld(entityposition_t *pos) {
|
||||||
|
if(!pos->dirty) return;
|
||||||
|
|
||||||
|
if(pos->parentEntityId == ENTITY_ID_INVALID) {
|
||||||
|
glm_mat4_copy(pos->localTransform, pos->worldTransform);
|
||||||
|
} else {
|
||||||
|
entityposition_t *parent = componentGetData(
|
||||||
|
pos->parentEntityId, pos->parentComponentId, COMPONENT_TYPE_POSITION
|
||||||
|
);
|
||||||
|
entityPositionUpdateWorld(parent);
|
||||||
|
glm_mat4_mul(parent->worldTransform, pos->localTransform, pos->worldTransform);
|
||||||
|
}
|
||||||
|
|
||||||
|
pos->dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void entityPositionMarkDirty(entityposition_t *pos) {
|
||||||
|
pos->dirty = true;
|
||||||
|
for(uint8_t i = 0; i < pos->childCount; i++) {
|
||||||
|
entityposition_t *child = componentGetData(
|
||||||
|
pos->childEntityIds[i], pos->childComponentIds[i], COMPONENT_TYPE_POSITION
|
||||||
|
);
|
||||||
|
entityPositionMarkDirty(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void entityPositionInit(
|
void entityPositionInit(
|
||||||
const entityid_t entityId,
|
const entityid_t entityId,
|
||||||
const componentid_t componentId
|
const componentid_t componentId
|
||||||
@@ -18,7 +45,12 @@ void entityPositionInit(
|
|||||||
glm_vec3_zero(pos->position);
|
glm_vec3_zero(pos->position);
|
||||||
glm_vec3_zero(pos->rotation);
|
glm_vec3_zero(pos->rotation);
|
||||||
glm_vec3_one(pos->scale);
|
glm_vec3_one(pos->scale);
|
||||||
glm_mat4_identity(pos->transform);
|
glm_mat4_identity(pos->localTransform);
|
||||||
|
glm_mat4_identity(pos->worldTransform);
|
||||||
|
pos->dirty = false;
|
||||||
|
pos->parentEntityId = ENTITY_ID_INVALID;
|
||||||
|
pos->parentComponentId = COMPONENT_ID_INVALID;
|
||||||
|
pos->childCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void entityPositionLookAt(
|
void entityPositionLookAt(
|
||||||
@@ -31,8 +63,9 @@ void entityPositionLookAt(
|
|||||||
entityposition_t *pos = componentGetData(
|
entityposition_t *pos = componentGetData(
|
||||||
entityId, componentId, COMPONENT_TYPE_POSITION
|
entityId, componentId, COMPONENT_TYPE_POSITION
|
||||||
);
|
);
|
||||||
glm_lookat(eye, target, up, pos->transform);
|
glm_lookat(eye, target, up, pos->localTransform);
|
||||||
entityPositionDecompose(pos);
|
entityPositionDecompose(pos);
|
||||||
|
entityPositionMarkDirty(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void entityPositionGetTransform(
|
void entityPositionGetTransform(
|
||||||
@@ -43,7 +76,19 @@ void entityPositionGetTransform(
|
|||||||
entityposition_t *pos = componentGetData(
|
entityposition_t *pos = componentGetData(
|
||||||
entityId, componentId, COMPONENT_TYPE_POSITION
|
entityId, componentId, COMPONENT_TYPE_POSITION
|
||||||
);
|
);
|
||||||
glm_mat4_copy(pos->transform, dest);
|
entityPositionUpdateWorld(pos);
|
||||||
|
glm_mat4_copy(pos->worldTransform, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
void entityPositionGetLocalTransform(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
mat4 dest
|
||||||
|
) {
|
||||||
|
entityposition_t *pos = componentGetData(
|
||||||
|
entityId, componentId, COMPONENT_TYPE_POSITION
|
||||||
|
);
|
||||||
|
glm_mat4_copy(pos->localTransform, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
void entityPositionGetPosition(
|
void entityPositionGetPosition(
|
||||||
@@ -115,6 +160,54 @@ void entityPositionSetScale(
|
|||||||
entityPositionRebuild(pos);
|
entityPositionRebuild(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void entityPositionSetParent(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
const entityid_t parentEntityId,
|
||||||
|
const componentid_t parentComponentId
|
||||||
|
) {
|
||||||
|
entityposition_t *pos = componentGetData(
|
||||||
|
entityId, componentId, COMPONENT_TYPE_POSITION
|
||||||
|
);
|
||||||
|
|
||||||
|
// Remove from old parent's child list.
|
||||||
|
if(pos->parentEntityId != ENTITY_ID_INVALID) {
|
||||||
|
entityposition_t *oldParent = componentGetData(
|
||||||
|
pos->parentEntityId, pos->parentComponentId, COMPONENT_TYPE_POSITION
|
||||||
|
);
|
||||||
|
for(uint8_t i = 0; i < oldParent->childCount; i++) {
|
||||||
|
if(
|
||||||
|
oldParent->childEntityIds[i] == entityId &&
|
||||||
|
oldParent->childComponentIds[i] == componentId
|
||||||
|
) {
|
||||||
|
oldParent->childCount--;
|
||||||
|
for(uint8_t j = i; j < oldParent->childCount; j++) {
|
||||||
|
oldParent->childEntityIds[j] = oldParent->childEntityIds[j + 1];
|
||||||
|
oldParent->childComponentIds[j] = oldParent->childComponentIds[j + 1];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pos->parentEntityId = parentEntityId;
|
||||||
|
pos->parentComponentId = parentComponentId;
|
||||||
|
|
||||||
|
// Register with new parent.
|
||||||
|
if(parentEntityId != ENTITY_ID_INVALID) {
|
||||||
|
entityposition_t *parent = componentGetData(
|
||||||
|
parentEntityId, parentComponentId, COMPONENT_TYPE_POSITION
|
||||||
|
);
|
||||||
|
if(parent->childCount < ENTITY_POSITION_CHILDREN_MAX) {
|
||||||
|
parent->childEntityIds[parent->childCount] = entityId;
|
||||||
|
parent->childComponentIds[parent->childCount] = componentId;
|
||||||
|
parent->childCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
entityPositionMarkDirty(pos);
|
||||||
|
}
|
||||||
|
|
||||||
entityposition_t *entityPositionGet(
|
entityposition_t *entityPositionGet(
|
||||||
const entityid_t entityId,
|
const entityid_t entityId,
|
||||||
const componentid_t componentId
|
const componentid_t componentId
|
||||||
@@ -125,57 +218,56 @@ entityposition_t *entityPositionGet(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void entityPositionRebuild(entityposition_t *pos) {
|
void entityPositionRebuild(entityposition_t *pos) {
|
||||||
glm_mat4_identity(pos->transform);
|
glm_mat4_identity(pos->localTransform);
|
||||||
glm_translate(pos->transform, pos->position);
|
glm_translate(pos->localTransform, pos->position);
|
||||||
glm_rotate_x(pos->transform, pos->rotation[0], pos->transform);
|
glm_rotate_x(pos->localTransform, pos->rotation[0], pos->localTransform);
|
||||||
glm_rotate_y(pos->transform, pos->rotation[1], pos->transform);
|
glm_rotate_y(pos->localTransform, pos->rotation[1], pos->localTransform);
|
||||||
glm_rotate_z(pos->transform, pos->rotation[2], pos->transform);
|
glm_rotate_z(pos->localTransform, pos->rotation[2], pos->localTransform);
|
||||||
glm_scale(pos->transform, pos->scale);
|
glm_scale(pos->localTransform, pos->scale);
|
||||||
|
entityPositionMarkDirty(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void entityPositionDecompose(entityposition_t *pos) {
|
void entityPositionDecompose(entityposition_t *pos) {
|
||||||
// Translation: column 3
|
// Translation: column 3
|
||||||
pos->position[0] = pos->transform[3][0];
|
pos->position[0] = pos->localTransform[3][0];
|
||||||
pos->position[1] = pos->transform[3][1];
|
pos->position[1] = pos->localTransform[3][1];
|
||||||
pos->position[2] = pos->transform[3][2];
|
pos->position[2] = pos->localTransform[3][2];
|
||||||
|
|
||||||
// Scale: length of each basis column (xyz only)
|
// Scale: length of each basis column (xyz only)
|
||||||
pos->scale[0] = sqrtf(
|
pos->scale[0] = sqrtf(
|
||||||
pos->transform[0][0] * pos->transform[0][0] +
|
pos->localTransform[0][0] * pos->localTransform[0][0] +
|
||||||
pos->transform[0][1] * pos->transform[0][1] +
|
pos->localTransform[0][1] * pos->localTransform[0][1] +
|
||||||
pos->transform[0][2] * pos->transform[0][2]
|
pos->localTransform[0][2] * pos->localTransform[0][2]
|
||||||
);
|
);
|
||||||
pos->scale[1] = sqrtf(
|
pos->scale[1] = sqrtf(
|
||||||
pos->transform[1][0] * pos->transform[1][0] +
|
pos->localTransform[1][0] * pos->localTransform[1][0] +
|
||||||
pos->transform[1][1] * pos->transform[1][1] +
|
pos->localTransform[1][1] * pos->localTransform[1][1] +
|
||||||
pos->transform[1][2] * pos->transform[1][2]
|
pos->localTransform[1][2] * pos->localTransform[1][2]
|
||||||
);
|
);
|
||||||
pos->scale[2] = sqrtf(
|
pos->scale[2] = sqrtf(
|
||||||
pos->transform[2][0] * pos->transform[2][0] +
|
pos->localTransform[2][0] * pos->localTransform[2][0] +
|
||||||
pos->transform[2][1] * pos->transform[2][1] +
|
pos->localTransform[2][1] * pos->localTransform[2][1] +
|
||||||
pos->transform[2][2] * pos->transform[2][2]
|
pos->localTransform[2][2] * pos->localTransform[2][2]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Normalize columns to isolate the rotation matrix
|
// Normalize columns to isolate the rotation matrix.
|
||||||
float invS0 = pos->scale[0] > 0.0f ? 1.0f / pos->scale[0] : 0.0f;
|
float invS0 = pos->scale[0] > 0.0f ? 1.0f / pos->scale[0] : 0.0f;
|
||||||
float invS1 = pos->scale[1] > 0.0f ? 1.0f / pos->scale[1] : 0.0f;
|
float invS1 = pos->scale[1] > 0.0f ? 1.0f / pos->scale[1] : 0.0f;
|
||||||
float invS2 = pos->scale[2] > 0.0f ? 1.0f / pos->scale[2] : 0.0f;
|
float invS2 = pos->scale[2] > 0.0f ? 1.0f / pos->scale[2] : 0.0f;
|
||||||
|
|
||||||
mat4 r;
|
mat4 r;
|
||||||
glm_mat4_identity(r);
|
glm_mat4_identity(r);
|
||||||
r[0][0] = pos->transform[0][0] * invS0;
|
r[0][0] = pos->localTransform[0][0] * invS0;
|
||||||
r[0][1] = pos->transform[0][1] * invS0;
|
r[0][1] = pos->localTransform[0][1] * invS0;
|
||||||
r[0][2] = pos->transform[0][2] * invS0;
|
r[0][2] = pos->localTransform[0][2] * invS0;
|
||||||
r[1][0] = pos->transform[1][0] * invS1;
|
r[1][0] = pos->localTransform[1][0] * invS1;
|
||||||
r[1][1] = pos->transform[1][1] * invS1;
|
r[1][1] = pos->localTransform[1][1] * invS1;
|
||||||
r[1][2] = pos->transform[1][2] * invS1;
|
r[1][2] = pos->localTransform[1][2] * invS1;
|
||||||
r[2][0] = pos->transform[2][0] * invS2;
|
r[2][0] = pos->localTransform[2][0] * invS2;
|
||||||
r[2][1] = pos->transform[2][1] * invS2;
|
r[2][1] = pos->localTransform[2][1] * invS2;
|
||||||
r[2][2] = pos->transform[2][2] * invS2;
|
r[2][2] = pos->localTransform[2][2] * invS2;
|
||||||
|
|
||||||
// Extract XYZ euler angles (R = Rx * Ry * Rz, column-major)
|
// Extract XYZ euler angles (R = Rx * Ry * Rz, column-major)
|
||||||
// r[2][0] = sin(Y), r[2][1] = -sin(X)*cos(Y), r[2][2] = cos(X)*cos(Y)
|
|
||||||
// r[0][0] = cos(Y)*cos(Z), r[1][0] = -cos(Y)*sin(Z)
|
|
||||||
float sinBeta = glm_clamp(r[2][0], -1.0f, 1.0f);
|
float sinBeta = glm_clamp(r[2][0], -1.0f, 1.0f);
|
||||||
pos->rotation[1] = asinf(sinBeta);
|
pos->rotation[1] = asinf(sinBeta);
|
||||||
float cosBeta = cosf(pos->rotation[1]);
|
float cosBeta = cosf(pos->rotation[1]);
|
||||||
@@ -184,7 +276,7 @@ void entityPositionDecompose(entityposition_t *pos) {
|
|||||||
pos->rotation[0] = atan2f(-r[2][1], r[2][2]);
|
pos->rotation[0] = atan2f(-r[2][1], r[2][2]);
|
||||||
pos->rotation[2] = atan2f(-r[1][0], r[0][0]);
|
pos->rotation[2] = atan2f(-r[1][0], r[0][0]);
|
||||||
} else {
|
} else {
|
||||||
// Gimbal lock: pin Z to 0, recover X from the remaining degree of freedom
|
// Gimbal lock: pin Z to 0, recover X.
|
||||||
pos->rotation[2] = 0.0f;
|
pos->rotation[2] = 0.0f;
|
||||||
pos->rotation[0] = (sinBeta > 0.0f)
|
pos->rotation[0] = (sinBeta > 0.0f)
|
||||||
? atan2f(r[0][1], r[1][1])
|
? atan2f(r[0][1], r[1][1])
|
||||||
|
|||||||
@@ -8,18 +8,24 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "entity/entitybase.h"
|
#include "entity/entitybase.h"
|
||||||
|
|
||||||
|
#define ENTITY_POSITION_CHILDREN_MAX 8
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
mat4 transform;
|
mat4 localTransform;
|
||||||
|
mat4 worldTransform;
|
||||||
vec3 position;
|
vec3 position;
|
||||||
vec3 rotation;
|
vec3 rotation;
|
||||||
vec3 scale;
|
vec3 scale;
|
||||||
|
bool dirty;
|
||||||
|
entityid_t parentEntityId;
|
||||||
|
componentid_t parentComponentId;
|
||||||
|
uint8_t childCount;
|
||||||
|
entityid_t childEntityIds[ENTITY_POSITION_CHILDREN_MAX];
|
||||||
|
componentid_t childComponentIds[ENTITY_POSITION_CHILDREN_MAX];
|
||||||
} entityposition_t;
|
} entityposition_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the entity position component.
|
* Initialize the entity position component.
|
||||||
*
|
|
||||||
* @param entityId The entity ID.
|
|
||||||
* @param componentId The component ID.
|
|
||||||
*/
|
*/
|
||||||
void entityPositionInit(
|
void entityPositionInit(
|
||||||
const entityid_t entityId,
|
const entityid_t entityId,
|
||||||
@@ -27,13 +33,13 @@ void entityPositionInit(
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms the entity's position to look at a target point.
|
* Transforms the entity's local transform to look at a target point.
|
||||||
*
|
*
|
||||||
* @param entityId The entity ID.
|
* @param entityId The entity ID.
|
||||||
* @param componentId The component ID.
|
* @param componentId The component ID.
|
||||||
* @param target The target point to look at.
|
* @param target The target point to look at.
|
||||||
* @param up The up vector for the look at transformation.
|
* @param up The up vector.
|
||||||
* @param eye The position of the camera/eye for the look at transformation.
|
* @param eye The eye/camera position.
|
||||||
*/
|
*/
|
||||||
void entityPositionLookAt(
|
void entityPositionLookAt(
|
||||||
const entityid_t entityId,
|
const entityid_t entityId,
|
||||||
@@ -44,11 +50,11 @@ void entityPositionLookAt(
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the transform matrix of the entity position component.
|
* Gets the world-space transform matrix, recomputing it lazily if dirty.
|
||||||
*
|
*
|
||||||
* @param entityId The entity ID.
|
* @param entityId The entity ID.
|
||||||
* @param componentId The component ID.
|
* @param componentId The component ID.
|
||||||
* @param dest The destination matrix to write the transform to.
|
* @param dest Destination matrix.
|
||||||
*/
|
*/
|
||||||
void entityPositionGetTransform(
|
void entityPositionGetTransform(
|
||||||
const entityid_t entityId,
|
const entityid_t entityId,
|
||||||
@@ -57,11 +63,20 @@ void entityPositionGetTransform(
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the cached position of the entity.
|
* Gets the local transform matrix (does not include parent transforms).
|
||||||
*
|
*
|
||||||
* @param entityId The entity ID.
|
* @param entityId The entity ID.
|
||||||
* @param componentId The component ID.
|
* @param componentId The component ID.
|
||||||
* @param dest The destination vec3 to write the position to.
|
* @param dest Destination matrix.
|
||||||
|
*/
|
||||||
|
void entityPositionGetLocalTransform(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
mat4 dest
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the cached local position.
|
||||||
*/
|
*/
|
||||||
void entityPositionGetPosition(
|
void entityPositionGetPosition(
|
||||||
const entityid_t entityId,
|
const entityid_t entityId,
|
||||||
@@ -70,11 +85,7 @@ void entityPositionGetPosition(
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the position of the entity and rebuilds the transform matrix.
|
* Sets the local position and marks the world transform dirty.
|
||||||
*
|
|
||||||
* @param entityId The entity ID.
|
|
||||||
* @param componentId The component ID.
|
|
||||||
* @param position The new position.
|
|
||||||
*/
|
*/
|
||||||
void entityPositionSetPosition(
|
void entityPositionSetPosition(
|
||||||
const entityid_t entityId,
|
const entityid_t entityId,
|
||||||
@@ -83,11 +94,7 @@ void entityPositionSetPosition(
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the cached euler rotation (XYZ, radians) of the entity.
|
* Gets the cached local euler rotation (XYZ, radians).
|
||||||
*
|
|
||||||
* @param entityId The entity ID.
|
|
||||||
* @param componentId The component ID.
|
|
||||||
* @param dest The destination vec3 to write the rotation to.
|
|
||||||
*/
|
*/
|
||||||
void entityPositionGetRotation(
|
void entityPositionGetRotation(
|
||||||
const entityid_t entityId,
|
const entityid_t entityId,
|
||||||
@@ -96,12 +103,7 @@ void entityPositionGetRotation(
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the euler rotation (XYZ, radians) of the entity and rebuilds the
|
* Sets the local euler rotation (XYZ, radians) and marks the world transform dirty.
|
||||||
* transform matrix.
|
|
||||||
*
|
|
||||||
* @param entityId The entity ID.
|
|
||||||
* @param componentId The component ID.
|
|
||||||
* @param rotation The new euler rotation in radians.
|
|
||||||
*/
|
*/
|
||||||
void entityPositionSetRotation(
|
void entityPositionSetRotation(
|
||||||
const entityid_t entityId,
|
const entityid_t entityId,
|
||||||
@@ -110,11 +112,7 @@ void entityPositionSetRotation(
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the cached scale of the entity.
|
* Gets the cached local scale.
|
||||||
*
|
|
||||||
* @param entityId The entity ID.
|
|
||||||
* @param componentId The component ID.
|
|
||||||
* @param dest The destination vec3 to write the scale to.
|
|
||||||
*/
|
*/
|
||||||
void entityPositionGetScale(
|
void entityPositionGetScale(
|
||||||
const entityid_t entityId,
|
const entityid_t entityId,
|
||||||
@@ -123,11 +121,7 @@ void entityPositionGetScale(
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the scale of the entity and rebuilds the transform matrix.
|
* Sets the local scale and marks the world transform dirty.
|
||||||
*
|
|
||||||
* @param entityId The entity ID.
|
|
||||||
* @param componentId The component ID.
|
|
||||||
* @param scale The new scale.
|
|
||||||
*/
|
*/
|
||||||
void entityPositionSetScale(
|
void entityPositionSetScale(
|
||||||
const entityid_t entityId,
|
const entityid_t entityId,
|
||||||
@@ -136,13 +130,24 @@ void entityPositionSetScale(
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a direct pointer to the entity position component data.
|
* Sets the parent of this entity's position component.
|
||||||
* After modifying position, rotation, or scale directly, call
|
* Pass ENTITY_ID_INVALID / COMPONENT_ID_INVALID to detach from any parent.
|
||||||
* entityPositionRebuild() to update the transform matrix.
|
|
||||||
*
|
*
|
||||||
* @param entityId The entity ID.
|
* @param entityId The child entity ID.
|
||||||
* @param componentId The component ID.
|
* @param componentId The child component ID.
|
||||||
* @return Pointer to the entity position component data.
|
* @param parentEntityId The parent entity ID.
|
||||||
|
* @param parentComponentId The parent component ID.
|
||||||
|
*/
|
||||||
|
void entityPositionSetParent(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
const entityid_t parentEntityId,
|
||||||
|
const componentid_t parentComponentId
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a direct pointer to the entity position component data.
|
||||||
|
* After modifying localTransform directly, call entityPositionMarkDirty().
|
||||||
*/
|
*/
|
||||||
entityposition_t *entityPositionGet(
|
entityposition_t *entityPositionGet(
|
||||||
const entityid_t entityId,
|
const entityid_t entityId,
|
||||||
@@ -150,15 +155,18 @@ entityposition_t *entityPositionGet(
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal function to rebuild the transform matrix of the entity position
|
* Rebuilds the local transform matrix from the cached position/rotation/scale,
|
||||||
* component based on the current position, rotation, and scale.
|
* then marks this node and all descendants dirty.
|
||||||
*/
|
*/
|
||||||
void entityPositionRebuild(entityposition_t *pos);
|
void entityPositionRebuild(entityposition_t *pos);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decomposes the transform matrix back into the position, rotation (XYZ euler,
|
* Marks this node and all descendants as having a stale world transform.
|
||||||
* radians), and scale cache fields. Call after any direct matrix modification.
|
*/
|
||||||
*
|
void entityPositionMarkDirty(entityposition_t *pos);
|
||||||
* @param pos Pointer to the entity position component data.
|
|
||||||
|
/**
|
||||||
|
* Decomposes the local transform matrix back into the position, rotation
|
||||||
|
* (XYZ euler, radians), and scale cache fields.
|
||||||
*/
|
*/
|
||||||
void entityPositionDecompose(entityposition_t *pos);
|
void entityPositionDecompose(entityposition_t *pos);
|
||||||
@@ -22,7 +22,7 @@ void entityInit(const entityid_t entityId) {
|
|||||||
) {
|
) {
|
||||||
ENTITY_MANAGER.entitiesWithComponent[
|
ENTITY_MANAGER.entitiesWithComponent[
|
||||||
compType * ENTITY_COUNT_MAX + entityId
|
compType * ENTITY_COUNT_MAX + entityId
|
||||||
] = 0xFF;
|
] = COMPONENT_ID_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
ent->state |= ENTITY_STATE_ACTIVE;
|
ent->state |= ENTITY_STATE_ACTIVE;
|
||||||
@@ -52,7 +52,7 @@ componentid_t entityAddComponent(
|
|||||||
}
|
}
|
||||||
|
|
||||||
assertUnreachable("Entity has no more component slots available");
|
assertUnreachable("Entity has no more component slots available");
|
||||||
return 0xFF;
|
return COMPONENT_ID_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
componentid_t entityGetComponent(
|
componentid_t entityGetComponent(
|
||||||
@@ -62,7 +62,7 @@ componentid_t entityGetComponent(
|
|||||||
componentid_t compId = ENTITY_MANAGER.entitiesWithComponent[
|
componentid_t compId = ENTITY_MANAGER.entitiesWithComponent[
|
||||||
type * ENTITY_COUNT_MAX + entityId
|
type * ENTITY_COUNT_MAX + entityId
|
||||||
];
|
];
|
||||||
if(compId == 0xFF) return compId;
|
if(compId == COMPONENT_ID_INVALID) return compId;
|
||||||
assertTrue(
|
assertTrue(
|
||||||
ENTITY_MANAGER.components[componentGetIndex(entityId, compId)].type == type,
|
ENTITY_MANAGER.components[componentGetIndex(entityId, compId)].type == type,
|
||||||
"Component type mismatch"
|
"Component type mismatch"
|
||||||
@@ -80,7 +80,7 @@ void entityDispose(const entityid_t entityId) {
|
|||||||
componentDispose(entityId, i);
|
componentDispose(entityId, i);
|
||||||
ENTITY_MANAGER.entitiesWithComponent[
|
ENTITY_MANAGER.entitiesWithComponent[
|
||||||
ENTITY_MANAGER.components[compInd].type * ENTITY_COUNT_MAX + entityId
|
ENTITY_MANAGER.components[compInd].type * ENTITY_COUNT_MAX + entityId
|
||||||
] = 0xFF;
|
] = COMPONENT_ID_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
ent->state = 0;
|
ent->state = 0;
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ componentid_t entityAddComponent(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the ID of the component of the given type on the entity with the given
|
* Gets the ID of the component of the given type on the entity with the given
|
||||||
* ID, or 0xFF if the entity lacks the component.
|
* ID, or COMPONENT_ID_INVALID if the entity lacks the component.
|
||||||
*
|
*
|
||||||
* @param entityId The ID of the entity to get the component from.
|
* @param entityId The ID of the entity to get the component from.
|
||||||
* @param type The type of the component to get.
|
* @param type The type of the component to get.
|
||||||
|
|||||||
@@ -11,6 +11,9 @@
|
|||||||
#define ENTITY_COUNT_MAX 20
|
#define ENTITY_COUNT_MAX 20
|
||||||
#define ENTITY_COMPONENT_COUNT_MAX 8
|
#define ENTITY_COMPONENT_COUNT_MAX 8
|
||||||
|
|
||||||
|
#define ENTITY_ID_INVALID 0xFF
|
||||||
|
#define COMPONENT_ID_INVALID 0xFF
|
||||||
|
|
||||||
typedef uint8_t entityid_t;
|
typedef uint8_t entityid_t;
|
||||||
typedef uint8_t componentid_t;
|
typedef uint8_t componentid_t;
|
||||||
typedef uint16_t componentindex_t;
|
typedef uint16_t componentindex_t;
|
||||||
@@ -15,7 +15,7 @@ entitymanager_t ENTITY_MANAGER;
|
|||||||
void entityManagerInit(void) {
|
void entityManagerInit(void) {
|
||||||
memoryZero(&ENTITY_MANAGER, sizeof(entitymanager_t));
|
memoryZero(&ENTITY_MANAGER, sizeof(entitymanager_t));
|
||||||
memorySet(
|
memorySet(
|
||||||
ENTITY_MANAGER.entitiesWithComponent, 0xFF,
|
ENTITY_MANAGER.entitiesWithComponent, COMPONENT_ID_INVALID,
|
||||||
sizeof(entityid_t) * COMPONENT_TYPE_COUNT * ENTITY_COUNT_MAX
|
sizeof(entityid_t) * COMPONENT_TYPE_COUNT * ENTITY_COUNT_MAX
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ entityid_t entityManagerAdd() {
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
assertUnreachable("No more entity IDs available");
|
assertUnreachable("No more entity IDs available");
|
||||||
return 0xFF;
|
return ENTITY_ID_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
void entityManagerDispose(void) {
|
void entityManagerDispose(void) {
|
||||||
|
|||||||
@@ -97,7 +97,11 @@ moduleBaseFunction(moduleEntityPositionSetScale) {
|
|||||||
|
|
||||||
moduleBaseFunction(moduleEntityPositionLookAt) {
|
moduleBaseFunction(moduleEntityPositionLookAt) {
|
||||||
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument");
|
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument");
|
||||||
entityposition_t *pos = moduleEntityPositionGet(callInfo);
|
componenthandle_t *h = scriptProtoGetValue(
|
||||||
|
&MODULE_ENTITY_POSITION_PROTO, callInfo->this_value
|
||||||
|
);
|
||||||
|
if(!h) return jerry_undefined();
|
||||||
|
entityposition_t *pos = entityPositionGet(h->eid, h->cid);
|
||||||
if(!pos) return jerry_undefined();
|
if(!pos) return jerry_undefined();
|
||||||
vec3 target;
|
vec3 target;
|
||||||
if(!moduleVec3AnyCheck(args[0], target)) {
|
if(!moduleVec3AnyCheck(args[0], target)) {
|
||||||
@@ -107,8 +111,37 @@ moduleBaseFunction(moduleEntityPositionLookAt) {
|
|||||||
if(argc >= 2 && !moduleVec3AnyCheck(args[1], up)) {
|
if(argc >= 2 && !moduleVec3AnyCheck(args[1], up)) {
|
||||||
return moduleBaseThrow("expected Vec3 up");
|
return moduleBaseThrow("expected Vec3 up");
|
||||||
}
|
}
|
||||||
glm_lookat(pos->position, target, up, pos->transform);
|
entityPositionLookAt(h->eid, h->cid, target, up, pos->position);
|
||||||
entityPositionDecompose(pos);
|
return jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleEntityPositionGetParent) {
|
||||||
|
componenthandle_t *h = scriptProtoGetValue(
|
||||||
|
&MODULE_ENTITY_POSITION_PROTO, callInfo->this_value
|
||||||
|
);
|
||||||
|
if(!h) return jerry_undefined();
|
||||||
|
entityposition_t *pos = entityPositionGet(h->eid, h->cid);
|
||||||
|
if(!pos || pos->parentEntityId == ENTITY_ID_INVALID) return jerry_null();
|
||||||
|
componenthandle_t ph = { .eid = pos->parentEntityId, .cid = pos->parentComponentId };
|
||||||
|
return scriptProtoCreateValue(&MODULE_ENTITY_POSITION_PROTO, &ph);
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleEntityPositionSetParentProp) {
|
||||||
|
componenthandle_t *h = scriptProtoGetValue(
|
||||||
|
&MODULE_ENTITY_POSITION_PROTO, callInfo->this_value
|
||||||
|
);
|
||||||
|
if(!h) return jerry_undefined();
|
||||||
|
|
||||||
|
if(argc < 1 || jerry_value_is_null(args[0]) || jerry_value_is_undefined(args[0])) {
|
||||||
|
entityPositionSetParent(h->eid, h->cid, ENTITY_ID_INVALID, COMPONENT_ID_INVALID);
|
||||||
|
return jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
componenthandle_t *ph = scriptProtoGetValue(
|
||||||
|
&MODULE_ENTITY_POSITION_PROTO, args[0]
|
||||||
|
);
|
||||||
|
if(!ph) return moduleBaseThrow("expected EntityPosition");
|
||||||
|
entityPositionSetParent(h->eid, h->cid, ph->eid, ph->cid);
|
||||||
return jerry_undefined();
|
return jerry_undefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,4 +180,9 @@ static void moduleEntityPOSITION(void) {
|
|||||||
&MODULE_ENTITY_POSITION_PROTO, "lookAt",
|
&MODULE_ENTITY_POSITION_PROTO, "lookAt",
|
||||||
moduleEntityPositionLookAt
|
moduleEntityPositionLookAt
|
||||||
);
|
);
|
||||||
|
|
||||||
|
scriptProtoDefineProp(
|
||||||
|
&MODULE_ENTITY_POSITION_PROTO, "parent",
|
||||||
|
moduleEntityPositionGetParent, moduleEntityPositionSetParentProp
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user