Fix rendering

This commit is contained in:
2026-05-21 18:24:18 -05:00
parent 23e617ea21
commit ba7857f4df
11 changed files with 487 additions and 56 deletions
+1
View File
@@ -68,6 +68,7 @@ errorret_t engineUpdate(void) {
timeUpdate();
inputUpdate();
consoleUpdate();
entityManagerUpdate();
uiUpdate();
errorChain(uiTextboxUpdate());
physicsManagerUpdate();
@@ -166,7 +166,7 @@ void entityPositionGetLocalPosition(
glm_vec3_copy(pos->position, dest);
}
void entityPositionGetPosition(
void entityPositionGetWorldPosition(
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
@@ -174,7 +174,6 @@ void entityPositionGetPosition(
entityposition_t *pos = componentGetData(
entityId, componentId, COMPONENT_TYPE_POSITION
);
// Parentless fast path: world position == pos->position, no matrix needed.
if(pos->parentEntityId == ENTITY_ID_INVALID) {
entityPositionEnsurePRS(pos);
glm_vec3_copy(pos->position, dest);
@@ -186,7 +185,36 @@ void entityPositionGetPosition(
dest[2] = pos->worldTransform[3][2];
}
void entityPositionSetPosition(
void entityPositionSetWorldPosition(
const entityid_t entityId,
const componentid_t componentId,
vec3 position
) {
entityposition_t *pos = componentGetData(
entityId, componentId, COMPONENT_TYPE_POSITION
);
if(pos->parentEntityId == ENTITY_ID_INVALID) {
glm_vec3_copy(position, pos->position);
pos->flags = (pos->flags | ENTITY_POSITION_FLAG_POSITION_DIRTY)
& ~ENTITY_POSITION_FLAG_PRS_DIRTY;
entityPositionMarkDirty(pos);
return;
}
entityposition_t *parent = componentGetData(
pos->parentEntityId, pos->parentComponentId, COMPONENT_TYPE_POSITION
);
entityPositionEnsureWorld(parent);
mat4 invParent;
glm_mat4_inv(parent->worldTransform, invParent);
vec3 localPos;
glm_mat4_mulv3(invParent, position, 1.0f, localPos);
glm_vec3_copy(localPos, pos->position);
pos->flags = (pos->flags | ENTITY_POSITION_FLAG_POSITION_DIRTY)
& ~ENTITY_POSITION_FLAG_PRS_DIRTY;
entityPositionMarkDirty(pos);
}
void entityPositionSetLocalPosition(
const entityid_t entityId,
const componentid_t componentId,
vec3 position
@@ -200,7 +228,7 @@ void entityPositionSetPosition(
entityPositionMarkDirty(pos);
}
void entityPositionGetRotation(
void entityPositionGetLocalRotation(
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
@@ -212,7 +240,44 @@ void entityPositionGetRotation(
glm_vec3_copy(pos->rotation, dest);
}
void entityPositionSetRotation(
void entityPositionGetWorldRotation(
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
) {
entityposition_t *pos = componentGetData(
entityId, componentId, COMPONENT_TYPE_POSITION
);
if(pos->parentEntityId == ENTITY_ID_INVALID) {
entityPositionEnsurePRS(pos);
glm_vec3_copy(pos->rotation, dest);
return;
}
entityPositionEnsureWorld(pos);
const float (*wt)[4] = pos->worldTransform;
const float sx = sqrtf(wt[0][0]*wt[0][0] + wt[0][1]*wt[0][1] + wt[0][2]*wt[0][2]);
const float sy = sqrtf(wt[1][0]*wt[1][0] + wt[1][1]*wt[1][1] + wt[1][2]*wt[1][2]);
const float sz = sqrtf(wt[2][0]*wt[2][0] + wt[2][1]*wt[2][1] + wt[2][2]*wt[2][2]);
const float r00 = sx > 0.0f ? wt[0][0]/sx : 0.0f;
const float r10 = sy > 0.0f ? wt[1][0]/sy : 0.0f;
const float r20 = sz > 0.0f ? wt[2][0]/sz : 0.0f;
const float r01 = sx > 0.0f ? wt[0][1]/sx : 0.0f;
const float r11 = sy > 0.0f ? wt[1][1]/sy : 0.0f;
const float r21 = sz > 0.0f ? wt[2][1]/sz : 0.0f;
const float r22 = sz > 0.0f ? wt[2][2]/sz : 0.0f;
const float sinBeta = glm_clamp(r20, -1.0f, 1.0f);
dest[1] = asinf(sinBeta);
const float cosBeta = cosf(dest[1]);
if(fabsf(cosBeta) > 1e-6f) {
dest[0] = atan2f(-r21, r22);
dest[2] = atan2f(-r10, r00);
} else {
dest[2] = 0.0f;
dest[0] = (sinBeta > 0.0f) ? atan2f(r01, r11) : -atan2f(r01, r11);
}
}
void entityPositionSetLocalRotation(
const entityid_t entityId,
const componentid_t componentId,
vec3 rotation
@@ -226,7 +291,82 @@ void entityPositionSetRotation(
entityPositionMarkDirty(pos);
}
void entityPositionGetScale(
void entityPositionSetWorldRotation(
const entityid_t entityId,
const componentid_t componentId,
vec3 rotation
) {
entityposition_t *pos = componentGetData(
entityId, componentId, COMPONENT_TYPE_POSITION
);
if(pos->parentEntityId == ENTITY_ID_INVALID) {
glm_vec3_copy(rotation, pos->rotation);
pos->flags = (pos->flags | ENTITY_POSITION_FLAG_ROTATION_DIRTY)
& ~ENTITY_POSITION_FLAG_PRS_DIRTY;
entityPositionMarkDirty(pos);
return;
}
entityposition_t *parent = componentGetData(
pos->parentEntityId, pos->parentComponentId, COMPONENT_TYPE_POSITION
);
entityPositionEnsureWorld(parent);
// Build target world rotation matrix (unit scale) from XYZ euler.
const float c0 = cosf(rotation[0]), s0 = sinf(rotation[0]);
const float c1 = cosf(rotation[1]), s1 = sinf(rotation[1]);
const float c2 = cosf(rotation[2]), s2 = sinf(rotation[2]);
const float s0s1 = s0*s1, c0s1 = c0*s1;
// Named wr[col_stored][row_stored] matching cglm column-major layout.
const float wr00 = c1*c2, wr01 = c0*s2 + s0s1*c2, wr02 = s0*s2 - c0s1*c2;
const float wr10 = -c1*s2, wr11 = c0*c2 - s0s1*s2, wr12 = s0*c2 + c0s1*s2;
const float wr20 = s1, wr21 = -s0*c1, wr22 = c0*c1;
// Normalize parent world columns to extract pure rotation.
const float (*pt)[4] = parent->worldTransform;
const float psx = sqrtf(pt[0][0]*pt[0][0] + pt[0][1]*pt[0][1] + pt[0][2]*pt[0][2]);
const float psy = sqrtf(pt[1][0]*pt[1][0] + pt[1][1]*pt[1][1] + pt[1][2]*pt[1][2]);
const float psz = sqrtf(pt[2][0]*pt[2][0] + pt[2][1]*pt[2][1] + pt[2][2]*pt[2][2]);
const float pr00 = psx > 0.f ? pt[0][0]/psx : 0.f;
const float pr01 = psx > 0.f ? pt[0][1]/psx : 0.f;
const float pr02 = psx > 0.f ? pt[0][2]/psx : 0.f;
const float pr10 = psy > 0.f ? pt[1][0]/psy : 0.f;
const float pr11 = psy > 0.f ? pt[1][1]/psy : 0.f;
const float pr12 = psy > 0.f ? pt[1][2]/psy : 0.f;
const float pr20 = psz > 0.f ? pt[2][0]/psz : 0.f;
const float pr21 = psz > 0.f ? pt[2][1]/psz : 0.f;
const float pr22 = psz > 0.f ? pt[2][2]/psz : 0.f;
// local_R = parent_R^T * world_R (R^-1 == R^T for orthogonal matrices).
// Compute only the 7 entries of the local rotation matrix needed for XYZ
// euler extraction (stored column-major: [col][row] = math [row][col]).
// sinBeta = stored[2][0] = math[0][2]
// r21/r22 = stored[2][1..2] = math[1..2][2]
// r10/r00 = stored[1][0], stored[0][0] = math[0][1], math[0][0]
// gimbal = stored[0][1], stored[1][1] = math[1][0], math[1][1]
const float lr00 = pr00*wr00 + pr01*wr10 + pr02*wr20; // math[0][0]
const float lr10 = pr00*wr01 + pr01*wr11 + pr02*wr21; // math[0][1]
const float lr20 = pr00*wr02 + pr01*wr12 + pr02*wr22; // math[0][2] → sinBeta
const float lr01 = pr10*wr00 + pr11*wr10 + pr12*wr20; // math[1][0]
const float lr11 = pr10*wr01 + pr11*wr11 + pr12*wr21; // math[1][1]
const float lr21 = pr10*wr02 + pr11*wr12 + pr12*wr22; // math[1][2] → r21
const float lr22 = pr20*wr02 + pr21*wr12 + pr22*wr22; // math[2][2] → r22
const float sinBeta = glm_clamp(lr20, -1.0f, 1.0f);
pos->rotation[1] = asinf(sinBeta);
const float cosBeta = cosf(pos->rotation[1]);
if(fabsf(cosBeta) > 1e-6f) {
pos->rotation[0] = atan2f(-lr21, lr22);
pos->rotation[2] = atan2f(-lr10, lr00);
} else {
pos->rotation[2] = 0.0f;
pos->rotation[0] = (sinBeta > 0.0f) ? atan2f(lr01, lr11) : -atan2f(lr01, lr11);
}
pos->flags = (pos->flags | ENTITY_POSITION_FLAG_ROTATION_DIRTY)
& ~ENTITY_POSITION_FLAG_PRS_DIRTY;
entityPositionMarkDirty(pos);
}
void entityPositionGetLocalScale(
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
@@ -238,7 +378,27 @@ void entityPositionGetScale(
glm_vec3_copy(pos->scale, dest);
}
void entityPositionSetScale(
void entityPositionGetWorldScale(
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
) {
entityposition_t *pos = componentGetData(
entityId, componentId, COMPONENT_TYPE_POSITION
);
if(pos->parentEntityId == ENTITY_ID_INVALID) {
entityPositionEnsurePRS(pos);
glm_vec3_copy(pos->scale, dest);
return;
}
entityPositionEnsureWorld(pos);
const float (*wt)[4] = pos->worldTransform;
dest[0] = sqrtf(wt[0][0]*wt[0][0] + wt[0][1]*wt[0][1] + wt[0][2]*wt[0][2]);
dest[1] = sqrtf(wt[1][0]*wt[1][0] + wt[1][1]*wt[1][1] + wt[1][2]*wt[1][2]);
dest[2] = sqrtf(wt[2][0]*wt[2][0] + wt[2][1]*wt[2][1] + wt[2][2]*wt[2][2]);
}
void entityPositionSetLocalScale(
const entityid_t entityId,
const componentid_t componentId,
vec3 scale
@@ -252,6 +412,37 @@ void entityPositionSetScale(
entityPositionMarkDirty(pos);
}
void entityPositionSetWorldScale(
const entityid_t entityId,
const componentid_t componentId,
vec3 scale
) {
entityposition_t *pos = componentGetData(
entityId, componentId, COMPONENT_TYPE_POSITION
);
if(pos->parentEntityId == ENTITY_ID_INVALID) {
glm_vec3_copy(scale, pos->scale);
pos->flags = (pos->flags | ENTITY_POSITION_FLAG_ROTATION_DIRTY)
& ~ENTITY_POSITION_FLAG_PRS_DIRTY;
entityPositionMarkDirty(pos);
return;
}
entityposition_t *parent = componentGetData(
pos->parentEntityId, pos->parentComponentId, COMPONENT_TYPE_POSITION
);
entityPositionEnsureWorld(parent);
const float (*pt)[4] = parent->worldTransform;
const float psx = sqrtf(pt[0][0]*pt[0][0] + pt[0][1]*pt[0][1] + pt[0][2]*pt[0][2]);
const float psy = sqrtf(pt[1][0]*pt[1][0] + pt[1][1]*pt[1][1] + pt[1][2]*pt[1][2]);
const float psz = sqrtf(pt[2][0]*pt[2][0] + pt[2][1]*pt[2][1] + pt[2][2]*pt[2][2]);
pos->scale[0] = psx > 0.0f ? scale[0] / psx : scale[0];
pos->scale[1] = psy > 0.0f ? scale[1] / psy : scale[1];
pos->scale[2] = psz > 0.0f ? scale[2] / psz : scale[2];
pos->flags = (pos->flags | ENTITY_POSITION_FLAG_ROTATION_DIRTY)
& ~ENTITY_POSITION_FLAG_PRS_DIRTY;
entityPositionMarkDirty(pos);
}
void entityPositionSetParent(
const entityid_t entityId,
const componentid_t componentId,
@@ -15,7 +15,7 @@
* PRS cache is stale. localTransform was written directly (e.g. lookAt) and
* position/rotation/scale need to be decomposed before they can be read.
*/
#define ENTITY_POSITION_FLAG_PRS_DIRTY (1 << 0)
#define ENTITY_POSITION_FLAG_PRS_DIRTY (1 << 0)
/**
* Columns 0-2 of localTransform are stale. Rotation or scale changed; the
@@ -34,7 +34,7 @@
* worldTransform is stale. Either the local matrix changed or an ancestor
* moved; the full parent-chain multiply must be rerun before world data is read.
*/
#define ENTITY_POSITION_FLAG_WORLD_DIRTY (1 << 3)
#define ENTITY_POSITION_FLAG_WORLD_DIRTY (1 << 3)
typedef struct {
/*
@@ -81,7 +81,7 @@ typedef struct {
* Initializes the entity position component, setting identity transforms and
* zeroing all parent/child state.
*
* @param entityId The entity ID.
* @param entityId The entity ID.
* @param componentId The component ID.
*/
void entityPositionInit(
@@ -92,7 +92,7 @@ void entityPositionInit(
/**
* 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 eye The eye/camera position.
* @param target The target point to look at.
@@ -137,9 +137,9 @@ void entityPositionGetLocalTransform(
* first if ENTITY_POSITION_FLAG_PRS_DIRTY is set; never triggers a matrix
* rebuild or world-transform update.
*
* @param entityId The entity ID.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param dest Destination vector.
* @param dest Destination vector.
*/
void entityPositionGetLocalPosition(
const entityid_t entityId,
@@ -148,29 +148,43 @@ void entityPositionGetLocalPosition(
);
/**
* Gets the world-space position. Rebuilds localTransform from PRS if
* ENTITY_POSITION_FLAG_LOCAL_DIRTY is set, then recomputes worldTransform
* from the parent chain if ENTITY_POSITION_FLAG_WORLD_DIRTY is set.
* Gets the world-space position. For parentless entities this is the same as
* the local position.
*
* @param entityId The entity ID.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param dest Destination vector.
* @param dest Destination vector.
*/
void entityPositionGetPosition(
void entityPositionGetWorldPosition(
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
);
/**
* Sets the local position, updates the PRS cache immediately, and lazily
* flags localTransform and worldTransform (self + descendants) for rebuild.
* Sets the world-space position. For parentless entities this is equivalent to
* entityPositionSetLocalPosition. For parented entities the position is
* converted to local space via the inverted parent world transform.
*
* @param entityId The entity ID.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param position The new local position.
* @param position The desired world-space position.
*/
void entityPositionSetPosition(
void entityPositionSetWorldPosition(
const entityid_t entityId,
const componentid_t componentId,
vec3 position
);
/**
* Sets the local position, marks localTransform and worldTransform (self +
* descendants) dirty.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param position The new local position.
*/
void entityPositionSetLocalPosition(
const entityid_t entityId,
const componentid_t componentId,
vec3 position
@@ -178,55 +192,112 @@ void entityPositionSetPosition(
/**
* Gets the cached local euler rotation (XYZ, radians). Decomposes
* localTransform into PRS first if ENTITY_POSITION_FLAG_PRS_DIRTY is set.
* localTransform first if ENTITY_POSITION_FLAG_PRS_DIRTY is set.
*
* @param entityId The entity ID.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param dest Destination vector.
* @param dest Destination vector.
*/
void entityPositionGetRotation(
void entityPositionGetLocalRotation(
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
);
/**
* Sets the local euler rotation (XYZ, radians), updates the PRS cache
* immediately, and lazily flags localTransform and worldTransform for rebuild.
* Gets the world-space euler rotation (XYZ, radians) by decomposing the world
* transform. For parentless entities this is the same as local rotation.
*
* @param entityId The entity ID.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param rotation The new local rotation.
* @param dest Destination vector.
*/
void entityPositionSetRotation(
void entityPositionGetWorldRotation(
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
);
/**
* Sets the local euler rotation (XYZ, radians) and marks transforms dirty.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param rotation The new local rotation.
*/
void entityPositionSetLocalRotation(
const entityid_t entityId,
const componentid_t componentId,
vec3 rotation
);
/**
* Gets the cached local scale. Decomposes localTransform into PRS first if
* Sets the world-space euler rotation (XYZ, radians). For parentless entities
* this is equivalent to entityPositionSetLocalRotation. For parented entities
* the rotation is converted to local space by removing the parent world
* rotation.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param rotation The desired world-space euler rotation.
*/
void entityPositionSetWorldRotation(
const entityid_t entityId,
const componentid_t componentId,
vec3 rotation
);
/**
* Gets the cached local scale. Decomposes localTransform first if
* ENTITY_POSITION_FLAG_PRS_DIRTY is set.
*
* @param entityId The entity ID.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param dest Destination vector.
* @param dest Destination vector.
*/
void entityPositionGetScale(
void entityPositionGetLocalScale(
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
);
/**
* Sets the local scale, updates the PRS cache immediately, and lazily flags
* localTransform and worldTransform for rebuild.
* Gets the world-space scale by extracting column lengths from the world
* transform. For parentless entities this is the same as local scale.
*
* @param entityId The entity ID.
* @param entityId The entity ID.
* @param componentId The component ID.
* @param scale The new local scale.
* @param dest Destination vector.
*/
void entityPositionSetScale(
void entityPositionGetWorldScale(
const entityid_t entityId,
const componentid_t componentId,
vec3 dest
);
/**
* Sets the local scale and marks transforms dirty.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param scale The new local scale.
*/
void entityPositionSetLocalScale(
const entityid_t entityId,
const componentid_t componentId,
vec3 scale
);
/**
* Sets the world-space scale. For parentless entities this is equivalent to
* entityPositionSetLocalScale. For parented entities the scale is converted to
* local space by dividing by the parent world scale (assumes no shear).
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param scale The desired world-space scale.
*/
void entityPositionSetWorldScale(
const entityid_t entityId,
const componentid_t componentId,
vec3 scale
@@ -254,7 +325,7 @@ void entityPositionSetParent(
* set ENTITY_POSITION_FLAG_WORLD_DIRTY on self and descendants. After
* modifying PRS directly, call entityPositionRebuild() instead.
*
* @param entityId The entity ID.
* @param entityId The entity ID.
* @param componentId The component ID.
* @return Pointer to the component data.
*/
@@ -287,7 +358,7 @@ 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 entityId The root entity ID.
* @param componentId The root position component ID.
*/
void entityPositionDisposeDeep(
+53
View File
@@ -80,10 +80,21 @@ void entityDisposeDeep(const entityid_t entityId) {
}
}
void entityUpdate(const entityid_t entityId) {
entity_t *ent = &ENTITY_MANAGER.entities[entityId];
for(uint8_t i = 0; i < ent->updateCount; i++) {
ent->onUpdate[i](entityId);
}
}
void entityDispose(const entityid_t entityId) {
componentindex_t compInd;
entity_t *ent = &ENTITY_MANAGER.entities[entityId];
for(uint8_t i = 0; i < ent->disposeCount; i++) {
ent->onDispose[i](entityId);
}
for(componentid_t i = 0; i < ENTITY_COMPONENT_COUNT_MAX; i++) {
compInd = componentGetIndex(entityId, i);
componenttype_t type = ENTITY_MANAGER.components[compInd].type;
@@ -95,4 +106,46 @@ void entityDispose(const entityid_t entityId) {
}
ent->state = 0;
}
void entityUpdateAdd(const entityid_t entityId, const entitycallback_t callback) {
entity_t *ent = &ENTITY_MANAGER.entities[entityId];
assertTrue(
ent->updateCount < ENTITY_UPDATE_CALLBACK_COUNT_MAX,
"Entity update callback slots full"
);
ent->onUpdate[ent->updateCount++] = callback;
}
void entityUpdateRemove(const entityid_t entityId, const entitycallback_t callback) {
entity_t *ent = &ENTITY_MANAGER.entities[entityId];
for(uint8_t i = 0; i < ent->updateCount; i++) {
if(ent->onUpdate[i] != callback) continue;
ent->updateCount--;
for(uint8_t j = i; j < ent->updateCount; j++) {
ent->onUpdate[j] = ent->onUpdate[j + 1];
}
return;
}
}
void entityDisposeAdd(const entityid_t entityId, const entitycallback_t callback) {
entity_t *ent = &ENTITY_MANAGER.entities[entityId];
assertTrue(
ent->disposeCount < ENTITY_DISPOSE_CALLBACK_COUNT_MAX,
"Entity dispose callback slots full"
);
ent->onDispose[ent->disposeCount++] = callback;
}
void entityDisposeRemove(const entityid_t entityId, const entitycallback_t callback) {
entity_t *ent = &ENTITY_MANAGER.entities[entityId];
for(uint8_t i = 0; i < ent->disposeCount; i++) {
if(ent->onDispose[i] != callback) continue;
ent->disposeCount--;
for(uint8_t j = i; j < ent->disposeCount; j++) {
ent->onDispose[j] = ent->onDispose[j + 1];
}
return;
}
}
+52 -2
View File
@@ -10,8 +10,17 @@
#define ENTITY_STATE_ACTIVE (1 << 0)
#define ENTITY_UPDATE_CALLBACK_COUNT_MAX 5
#define ENTITY_DISPOSE_CALLBACK_COUNT_MAX 5
typedef void (*entitycallback_t)(const entityid_t entityId);
typedef struct {
uint8_t state;
uint8_t updateCount;
uint8_t disposeCount;
entitycallback_t onUpdate[ENTITY_UPDATE_CALLBACK_COUNT_MAX];
entitycallback_t onDispose[ENTITY_DISPOSE_CALLBACK_COUNT_MAX];
} entity_t;
/**
@@ -47,7 +56,15 @@ componentid_t entityGetComponent(
);
/**
* Disposes of an entity with the given ID.
* Runs all registered update callbacks for the entity.
*
* @param entityId The ID of the entity to update.
*/
void entityUpdate(const entityid_t entityId);
/**
* Disposes of an entity with the given ID. Fires all dispose callbacks before
* cleaning up components and state.
*
* @param entityId The ID of the entity to dispose of.
*/
@@ -60,4 +77,37 @@ void entityDispose(const entityid_t entityId);
*
* @param entityId The root entity ID.
*/
void entityDisposeDeep(const entityid_t entityId);
void entityDisposeDeep(const entityid_t entityId);
/**
* Registers an update callback, invoked each time entityUpdate is called.
*
* @param entityId The entity to register on.
* @param callback The function to call.
*/
void entityUpdateAdd(const entityid_t entityId, const entitycallback_t callback);
/**
* Removes a previously registered update callback.
*
* @param entityId The entity to remove from.
* @param callback The function to remove.
*/
void entityUpdateRemove(const entityid_t entityId, const entitycallback_t callback);
/**
* Registers a dispose callback, invoked at the start of entityDispose before
* any component or state cleanup.
*
* @param entityId The entity to register on.
* @param callback The function to call.
*/
void entityDisposeAdd(const entityid_t entityId, const entitycallback_t callback);
/**
* Removes a previously registered dispose callback.
*
* @param entityId The entity to remove from.
* @param callback The function to remove.
*/
void entityDisposeRemove(const entityid_t entityId, const entitycallback_t callback);
+10
View File
@@ -36,6 +36,16 @@ entityid_t entityManagerAdd() {
return ENTITY_ID_INVALID;
}
void entityManagerUpdate(void) {
entityid_t i = 0;
while(i < ENTITY_COUNT_MAX) {
if((ENTITY_MANAGER.entities[i].state & ENTITY_STATE_ACTIVE) != 0) {
entityUpdate(i);
}
i++;
}
}
void entityManagerDispose(void) {
for(entityid_t i = 0; i < ENTITY_COUNT_MAX; i++) {
if((ENTITY_MANAGER.entities[i].state & ENTITY_STATE_ACTIVE) == 0) continue;
+5
View File
@@ -28,6 +28,11 @@ void entityManagerInit(void);
*/
entityid_t entityManagerAdd();
/**
* Updates all active entities.
*/
void entityManagerUpdate(void);
/**
* Disposes of the entity manager, in turn freeing all entities and components.
*/
+22 -2
View File
@@ -162,6 +162,28 @@ void inputAxis2D(
result[1] = inputAxis(negY, posY);
}
void inputAngle2D(
const inputaction_t negX, const inputaction_t posX,
const inputaction_t negY, const inputaction_t posY,
vec2 result
) {
assertNotNull(result, "Result vector cannot be null");
float_t x = inputAxis(negX, posX);
float_t y = inputAxis(negY, posY);
float_t mag = sqrtf(x * x + y * y);
if(mag <= 0.0f) {
result[0] = 0.0f;
result[1] = 0.0f;
return;
}
if(mag > 1.0f) {
x /= mag;
y /= mag;
}
result[0] = x;
result[1] = y;
}
void inputBind(const inputbutton_t button, const inputaction_t act) {
assertTrue(
act < INPUT_ACTION_COUNT,
@@ -177,8 +199,6 @@ void inputBind(const inputbutton_t button, const inputaction_t act) {
data->action = act;
}
float_t inputDeadzone(const float_t rawValue, const float_t deadzone) {
if(rawValue < deadzone) return 0.0f;
return (rawValue - deadzone) / (1.0f - deadzone);
+16
View File
@@ -126,6 +126,22 @@ void inputAxis2D(
vec2 result
);
/**
* Returns an angled 2D vector based on the input of 4 actions. Functionally
* using atan2 to get the angle of the input then multiplying by a unit vector.
*
* @param negX The action representing the negative direction of the X axis.
* @param posX The action representing the positive direction of the X axis.
* @param negY The action representing the negative direction of the Y axis.
* @param posY The action representing the positive direction of the Y axis.
* @param result A vec2 to store the resulting axis values (-1.0f to 1.0f).
*/
void inputAngle2D(
const inputaction_t negX, const inputaction_t posX,
const inputaction_t negY, const inputaction_t posY,
vec2 result
);
/**
* Binds an input button to an action.
*
+22 -2
View File
@@ -10,8 +10,27 @@
#include "display/spritebatch/spritebatch.h"
#include "display/screen/screen.h"
#include "entity/entitymanager.h"
#include "input/input.h"
#include "display/shader/shaderunlit.h"
void initialSceneCubeUpdate(const entityid_t entityId) {
vec3 pos;
componentid_t posComp = entityGetComponent(entityId, COMPONENT_TYPE_POSITION);
vec2 movement;
inputAngle2D(
INPUT_ACTION_LEFT, INPUT_ACTION_RIGHT,
INPUT_ACTION_DOWN, INPUT_ACTION_UP,
movement
);
if(movement[0] == 0.0f && movement[1] == 0.0f) return;
const float_t speed = 1.0f;
entityPositionGetLocalPosition(entityId, posComp, pos);
pos[0] += movement[0] * TIME.delta * speed;
pos[2] -= movement[1] * TIME.delta * speed;
entityPositionSetLocalPosition(entityId, posComp, pos);
}
void initialSceneInit(void) {
consolePrint("Initial scene initialized");
@@ -23,8 +42,9 @@ void initialSceneInit(void) {
// entitycamera_t *camData = (entitycamera_t*)entityGetComponent(camera, camCam);
entityid_t cube = entityManagerAdd();
// componentid_t cubePos = entityAddComponent(cube, COMPONENT_TYPE_POSITION);
(void)entityAddComponent(cube, COMPONENT_TYPE_POSITION);
componentid_t cubeDraw = entityAddComponent(cube, COMPONENT_TYPE_RENDERABLE);
entityUpdateAdd(cube, initialSceneCubeUpdate);
// entityrenderable_t *cubeDrawData = (
// (entityrenderable_t*)entityGetComponent(cube, cubeDraw)
// );
-6
View File
@@ -34,10 +34,6 @@ errorret_t sceneInit(void) {
}
errorret_t sceneUpdate(void) {
if(SCENE.nextType == SCENE_TYPE_NULL) {
errorOk();
}
// Handle scene change
if(SCENE.nextType != SCENE_TYPE_NULL) {
// Dispose current scene.
@@ -72,8 +68,6 @@ errorret_t sceneUpdate(void) {
errorOk();
}
dusktimeepoch_t LAST;
errorret_t sceneRender(void) {
mat4 proj, view, model, ident;
glm_mat4_identity(ident);