Fix rendering
This commit is contained in:
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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)
|
||||
// );
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user