From bb7c41c7540d4b4daf661c23dc08125aee0b3d66 Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Fri, 10 Apr 2026 18:47:46 -0500 Subject: [PATCH] Rotation --- src/dusk/engine/engine.c | 22 ++- .../entity/component/display/entityposition.c | 141 ++++++++++++++++++ .../entity/component/display/entityposition.h | 100 ++++++++++++- 3 files changed, 253 insertions(+), 10 deletions(-) diff --git a/src/dusk/engine/engine.c b/src/dusk/engine/engine.c index b9c9f2b7..1155a8c7 100644 --- a/src/dusk/engine/engine.c +++ b/src/dusk/engine/engine.c @@ -23,14 +23,16 @@ engine_t ENGINE; texture_t TEXTURE; -#pragma pack(push, 1) color_t TEXTURE_COLORS[] = { COLOR_RED, COLOR_GREEN, COLOR_MAGENTA, COLOR_CYAN, COLOR_BLUE, COLOR_WHITE, COLOR_YELLOW, COLOR_BLACK, COLOR_CYAN, COLOR_MAGENTA, COLOR_GREEN, COLOR_RED, COLOR_WHITE, COLOR_BLUE, COLOR_BLACK, COLOR_YELLOW }; -#pragma pack(pop) +entityid_t ent1; +componentid_t ent1Pos; +componentid_t ent1Mesh; +componentid_t ent1Mat; errorret_t engineInit(const int32_t argc, const char_t **argv) { memoryZero(&ENGINE, sizeof(engine_t)); @@ -62,10 +64,10 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) { ); componentid_t camCam = entityAddComponent(cam, COMPONENT_TYPE_CAMERA); - entityid_t ent1 = entityManagerAdd(); - componentid_t ent1Pos = entityAddComponent(ent1, COMPONENT_TYPE_POSITION); - componentid_t ent1Mesh = entityAddComponent(ent1, COMPONENT_TYPE_MESH); - componentid_t ent1Mat = entityAddComponent(ent1, COMPONENT_TYPE_MATERIAL); + ent1 = entityManagerAdd(); + ent1Pos = entityAddComponent(ent1, COMPONENT_TYPE_POSITION); + ent1Mesh = entityAddComponent(ent1, COMPONENT_TYPE_MESH); + ent1Mat = entityAddComponent(ent1, COMPONENT_TYPE_MATERIAL); textureInit(&TEXTURE, 4, 4, TEXTURE_FORMAT_RGBA, (texturedata_t){ .rgbaColors = TEXTURE_COLORS @@ -80,8 +82,7 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) { )); shadermaterial_t *mat = entityMaterialGetShaderMaterial(ent1, ent1Mat); - // mat->unlit.color = COLOR_WHITE; - mat->unlit.color = COLOR_RED; + mat->unlit.color = COLOR_WHITE; mat->unlit.texture = &TEXTURE; // EOF @@ -99,6 +100,11 @@ errorret_t engineUpdate(void) { timeUpdate(); inputUpdate(); + vec3 rotation; + entityPositionGetRotation(ent1, ent1Pos, rotation); + rotation[1] += 0.01f; + entityPositionSetRotation(ent1, ent1Pos, rotation); + uiUpdate(); errorChain(sceneUpdate()); errorChain(gameUpdate()); diff --git a/src/dusk/entity/component/display/entityposition.c b/src/dusk/entity/component/display/entityposition.c index 3a3685d5..20dd72f2 100644 --- a/src/dusk/entity/component/display/entityposition.c +++ b/src/dusk/entity/component/display/entityposition.c @@ -15,6 +15,9 @@ void entityPositionInit( entityId, componentId, COMPONENT_TYPE_POSITION ); + glm_vec3_zero(pos->position); + glm_vec3_zero(pos->rotation); + glm_vec3_one(pos->scale); glm_mat4_identity(pos->transform); } @@ -29,6 +32,7 @@ void entityPositionLookAt( entityId, componentId, COMPONENT_TYPE_POSITION ); glm_lookat(eye, target, up, pos->transform); + entityPositionDecompose(pos); } void entityPositionGetTransform( @@ -40,4 +44,141 @@ void entityPositionGetTransform( entityId, componentId, COMPONENT_TYPE_POSITION ); glm_mat4_copy(pos->transform, 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 entityPositionRebuild(entityposition_t *pos) { + glm_mat4_identity(pos->transform); + glm_translate(pos->transform, pos->position); + glm_rotate_x(pos->transform, pos->rotation[0], pos->transform); + glm_rotate_y(pos->transform, pos->rotation[1], pos->transform); + glm_rotate_z(pos->transform, pos->rotation[2], pos->transform); + glm_scale(pos->transform, pos->scale); +} + +void entityPositionDecompose(entityposition_t *pos) { + // Translation: column 3 + pos->position[0] = pos->transform[3][0]; + pos->position[1] = pos->transform[3][1]; + pos->position[2] = pos->transform[3][2]; + + // Scale: length of each basis column (xyz only) + pos->scale[0] = sqrtf( + pos->transform[0][0] * pos->transform[0][0] + + pos->transform[0][1] * pos->transform[0][1] + + pos->transform[0][2] * pos->transform[0][2] + ); + pos->scale[1] = sqrtf( + pos->transform[1][0] * pos->transform[1][0] + + pos->transform[1][1] * pos->transform[1][1] + + pos->transform[1][2] * pos->transform[1][2] + ); + pos->scale[2] = sqrtf( + pos->transform[2][0] * pos->transform[2][0] + + pos->transform[2][1] * pos->transform[2][1] + + pos->transform[2][2] * pos->transform[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->transform[0][0] * invS0; + r[0][1] = pos->transform[0][1] * invS0; + r[0][2] = pos->transform[0][2] * invS0; + r[1][0] = pos->transform[1][0] * invS1; + r[1][1] = pos->transform[1][1] * invS1; + r[1][2] = pos->transform[1][2] * invS1; + r[2][0] = pos->transform[2][0] * invS2; + r[2][1] = pos->transform[2][1] * invS2; + r[2][2] = pos->transform[2][2] * invS2; + + // 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); + 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 from the remaining degree of freedom + 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]); + } } \ No newline at end of file diff --git a/src/dusk/entity/component/display/entityposition.h b/src/dusk/entity/component/display/entityposition.h index cdc4b90e..70d7108d 100644 --- a/src/dusk/entity/component/display/entityposition.h +++ b/src/dusk/entity/component/display/entityposition.h @@ -10,6 +10,9 @@ typedef struct { mat4 transform; + vec3 position; + vec3 rotation; + vec3 scale; } entityposition_t; /** @@ -42,7 +45,7 @@ void entityPositionLookAt( /** * Gets the transform matrix of the entity position component. - * + * * @param entityId The entity ID. * @param componentId The component ID. * @param dest The destination matrix to write the transform to. @@ -51,4 +54,97 @@ void entityPositionGetTransform( const entityid_t entityId, const componentid_t componentId, mat4 dest -); \ No newline at end of file +); + +/** + * Gets the cached position of the entity. + * + * @param entityId The entity ID. + * @param componentId The component ID. + * @param dest The destination vec3 to write the position to. + */ +void entityPositionGetPosition( + const entityid_t entityId, + const componentid_t componentId, + vec3 dest +); + +/** + * Sets the position of the entity and rebuilds the transform matrix. + * + * @param entityId The entity ID. + * @param componentId The component ID. + * @param position The new position. + */ +void entityPositionSetPosition( + const entityid_t entityId, + const componentid_t componentId, + vec3 position +); + +/** + * Gets the cached euler rotation (XYZ, radians) of the entity. + * + * @param entityId The entity ID. + * @param componentId The component ID. + * @param dest The destination vec3 to write the rotation to. + */ +void entityPositionGetRotation( + const entityid_t entityId, + const componentid_t componentId, + vec3 dest +); + +/** + * Sets the euler rotation (XYZ, radians) of the entity and rebuilds the + * transform matrix. + * + * @param entityId The entity ID. + * @param componentId The component ID. + * @param rotation The new euler rotation in radians. + */ +void entityPositionSetRotation( + const entityid_t entityId, + const componentid_t componentId, + vec3 rotation +); + +/** + * Gets the cached scale of the entity. + * + * @param entityId The entity ID. + * @param componentId The component ID. + * @param dest The destination vec3 to write the scale to. + */ +void entityPositionGetScale( + const entityid_t entityId, + const componentid_t componentId, + vec3 dest +); + +/** + * Sets the scale of the entity and rebuilds the transform matrix. + * + * @param entityId The entity ID. + * @param componentId The component ID. + * @param scale The new scale. + */ +void entityPositionSetScale( + const entityid_t entityId, + const componentid_t componentId, + vec3 scale +); + +/** + * Internal function to rebuild the transform matrix of the entity position + * component based on the current position, rotation, and scale. + */ +void entityPositionRebuild(entityposition_t *pos); + +/** + * Decomposes the transform matrix back into the position, rotation (XYZ euler, + * radians), and scale cache fields. Call after any direct matrix modification. + * + * @param pos Pointer to the entity position component data. + */ +void entityPositionDecompose(entityposition_t *pos); \ No newline at end of file