Mon, 07 Jul 2025 22:51:06 +0200
remove separate vectors for position, rotation, scale from scene node
src/2d.c | file | annotate | diff | comparison | revisions | |
src/ascension/scene_node.h | file | annotate | diff | comparison | revisions | |
src/ascension/transform.h | file | annotate | diff | comparison | revisions | |
src/scene.c | file | annotate | diff | comparison | revisions | |
src/scene_node.c | file | annotate | diff | comparison | revisions | |
src/sprite.c | file | annotate | diff | comparison | revisions | |
src/text.c | file | annotate | diff | comparison | revisions | |
test/snake/snake.c | file | annotate | diff | comparison | revisions |
--- a/src/2d.c Mon Jul 07 22:41:48 2025 +0200 +++ b/src/2d.c Mon Jul 07 22:51:06 2025 +0200 @@ -157,14 +157,15 @@ AscSceneNode *asc_rectangle_create(struct asc_rectangle_create_args args) { AscRectangle *rectangle = cxZallocDefault(sizeof(AscRectangle)); + float pos_x, pos_y; if (args.bounds.size.width + args.bounds.size.height > 0) { - rectangle->node.position.x = (float) args.bounds.pos.x; - rectangle->node.position.y = (float) args.bounds.pos.y; + pos_x = (float) args.bounds.pos.x; + pos_y = (float) args.bounds.pos.y; rectangle->size.width = (float) args.bounds.size.width; rectangle->size.height = (float) args.bounds.size.height; } else { - rectangle->node.position.x = (float) args.x; - rectangle->node.position.y = (float) args.y; + pos_x = (float) args.x; + pos_y = (float) args.y; rectangle->size.width = (float) args.width; rectangle->size.height = (float) args.height; } @@ -187,8 +188,9 @@ } AscSceneNode *node = &rectangle->node; - node->position.z = ASC_SCENE_2D_DEPTH_OFFSET; - node->scale = ASC_VEC3F_1; + asc_transform_identity(node->transform); + asc_transform_translate3f(node->transform, + ASC_VEC3F(pos_x, pos_y, ASC_SCENE_2D_DEPTH_OFFSET)); node->render_group = asc_context.ink.alpha < 255 ? ASC_RENDER_GROUP_2D_BLEND : ASC_RENDER_GROUP_2D_OPAQUE; @@ -308,9 +310,10 @@ AscSceneNode *asc_ellipsis_create(struct asc_ellipsis_create_args args) { AscEllipsis *ellipsis = cxZallocDefault(sizeof(AscEllipsis)); + float pos_x, pos_y; if (args.bounds.size.width + args.bounds.size.height > 0) { - ellipsis->node.position.x = (float) args.bounds.pos.x; - ellipsis->node.position.y = (float) args.bounds.pos.y; + pos_x = (float) args.bounds.pos.x; + pos_y = (float) args.bounds.pos.y; ellipsis->radii.x = (float) args.bounds.size.width / 2.f; ellipsis->radii.y = (float) args.bounds.size.height / 2.f; } else { @@ -318,8 +321,8 @@ const unsigned cy = ASC_NONZERO_OR(args.y, args.center.y); const unsigned rx = ASC_NONZERO_OR(args.radius, args.radius_x); const unsigned ry = ASC_NONZERO_OR(args.radius, args.radius_y); - ellipsis->node.position.x = (float) (cx-rx); - ellipsis->node.position.y = (float) (cy-ry); + pos_x = (float) (cx-rx); + pos_y = (float) (cy-ry); ellipsis->radii.x = (float) rx; ellipsis->radii.y = (float) ry; } @@ -341,8 +344,9 @@ } AscSceneNode *node = &ellipsis->node; - node->position.z = ASC_SCENE_2D_DEPTH_OFFSET; - node->scale = ASC_VEC3F_1; + asc_transform_identity(node->transform); + asc_transform_translate3f(node->transform, + ASC_VEC3F(pos_x, pos_y, ASC_SCENE_2D_DEPTH_OFFSET)); node->render_group = asc_context.ink.alpha < 255 ? ASC_RENDER_GROUP_2D_BLEND : ASC_RENDER_GROUP_2D_OPAQUE;
--- a/src/ascension/scene_node.h Mon Jul 07 22:41:48 2025 +0200 +++ b/src/ascension/scene_node.h Mon Jul 07 22:51:06 2025 +0200 @@ -64,9 +64,6 @@ asc_scene_node_destroy_func destroy_func; asc_scene_node_update_func update_func; asc_scene_node_draw_func draw_func; - asc_vec3f position; - asc_vec3f rotation; - asc_vec3f scale; asc_transform transform; asc_transform world_transform; enum AscRenderGroup render_group; @@ -99,16 +96,6 @@ */ #define ASC_SCENE_NODE_TRANSFORM_UPDATED 0x08000000 /** - * Set when the node's transform is directly manipulated via matrix operations. - * When this flag is set, position/rotation/scale values won't be used to - * calculate the transform matrix. - */ -#define ASC_SCENE_NODE_CUSTOM_TRANSFORM 0x10000000 -/** - * Set when the node is not supposed to be shown on screen. - */ -#define ASC_SCENE_BEHAVIOR_PAUSED 0x40000000 -/** * Set when the node is not supposed to be shown on screen. */ #define ASC_SCENE_NODE_HIDDEN 0x80000000 @@ -123,7 +110,7 @@ */ AscSceneNode *asc_scene_node_empty(void); -// TODO: create a common init-function that all "subclasses" use, which also debug-logs the assigned name +// TODO: issue #695 - create a common init-function that all "subclasses" use, which also debug-logs the assigned name /** * Unlinks the node from its parent and frees the entire subtree. @@ -185,76 +172,37 @@ */ #define ASC_SCENE_2D_DEPTH_OFFSET 0.0078125f -ASC_TRANFORM_FUNC void asc_set_position(AscSceneNode *node, float x, float y, float z) { - node->position.x = x; - node->position.y = y; - node->position.z = z; - asc_clear_flag(node->flags, ASC_SCENE_NODE_CUSTOM_TRANSFORM); - asc_node_update_transform(node); -} - -ASC_TRANFORM_FUNC void asc_set_position2d(AscSceneNode *node, int x, int y) { - node->position.x = (float)x; - node->position.y = (float)y; - asc_clear_flag(node->flags, ASC_SCENE_NODE_CUSTOM_TRANSFORM); - asc_node_update_transform(node); -} - -ASC_TRANFORM_FUNC asc_vec2i asc_get_position2d(AscSceneNode *node) { - return ASC_VEC2I(node->position.x, node->position.y); -} - -ASC_TRANFORM_FUNC void asc_set_rotation(AscSceneNode *node, float pitch, float yaw, float roll) { - node->rotation.pitch = pitch; - node->rotation.yaw = yaw; - node->rotation.roll = roll; - asc_clear_flag(node->flags, ASC_SCENE_NODE_CUSTOM_TRANSFORM); - asc_node_update_transform(node); -} - -ASC_TRANFORM_FUNC void asc_set_scale(AscSceneNode *node, float width, float height, float depth) { - node->scale.width = width; - node->scale.height = height; - node->scale.depth = depth; - asc_clear_flag(node->flags, ASC_SCENE_NODE_CUSTOM_TRANSFORM); - asc_node_update_transform(node); -} - - /** - * Directly modifies the transformation matrix by multiplying it with another matrix. - * This will set the node to use the custom transform mode. + * Applies an affine transformation to a scene node. * * @param node the node to modify - * @param matrix the matrix to multiply with the current transform + * @param matrix the matrix to multiply with the current transformation matrix */ -ASC_TRANFORM_FUNC void asc_transform_multiply(AscSceneNode *node, const asc_transform matrix) { - asc_set_flag(node->flags, ASC_SCENE_NODE_CUSTOM_TRANSFORM); +ASC_TRANFORM_FUNC void asc_node_transform_apply(AscSceneNode *node, const asc_transform matrix) { asc_mat4f_mulst(node->transform, node->transform, matrix); asc_node_update_transform(node); } /** - * Directly sets the transformation matrix. - * This will set the node to use the custom transform mode. + * Overwrites the current local transformation matrix. * * @param node the node to modify - * @param matrix the matrix to set as the transform + * @param matrix the matrix to set as the new local transformation matrix */ -ASC_TRANFORM_FUNC void asc_transform_set_matrix(AscSceneNode *node, const asc_transform matrix) { - asc_set_flag(node->flags, ASC_SCENE_NODE_CUSTOM_TRANSFORM); - memcpy(node->transform, matrix, sizeof(asc_transform)); +ASC_TRANFORM_FUNC void asc_node_transform_set(AscSceneNode *node, const asc_transform matrix) { + asc_transform_copy(node->transform, matrix); asc_node_update_transform(node); } /** - * Resets the node to use component-based transformation. - * This will recalculate the transform matrix from position, rotation, and scale. + * Resets the node to use an identity transformation matrix. + * + * This is, for example, useful when you want to recalculate a chain of transformations from scratch. * - * @param node the node to modify + * @param node the node for which to reset the local transformation */ -ASC_TRANFORM_FUNC void asc_transform_reset_to_components(AscSceneNode *node) { - asc_clear_flag(node->flags, ASC_SCENE_NODE_CUSTOM_TRANSFORM); +ASC_TRANFORM_FUNC void asc_node_transform_reset(AscSceneNode *node) { + asc_transform_identity(node->transform); asc_node_update_transform(node); }
--- a/src/ascension/transform.h Mon Jul 07 22:41:48 2025 +0200 +++ b/src/ascension/transform.h Mon Jul 07 22:51:06 2025 +0200 @@ -42,14 +42,10 @@ ASC_TRANFORM_FUNC void asc_transform_identity(asc_transform transform) { - memset(transform, 0, ASC_TRANSFORM_SIZE); - transform[asc_mat4_index(0, 0)] = 1; - transform[asc_mat4_index(1, 1)] = 1; - transform[asc_mat4_index(2, 2)] = 1; - transform[asc_mat4_index(3, 3)] = 1; + asc_mat4f_unit(transform); } -ASC_TRANFORM_FUNC void asc_transform_copy(asc_transform dest, asc_transform src) { +ASC_TRANFORM_FUNC void asc_transform_copy(asc_transform dest, const asc_transform src) { memcpy(dest, src, ASC_TRANSFORM_SIZE); }
--- a/src/scene.c Mon Jul 07 22:41:48 2025 +0200 +++ b/src/scene.c Mon Jul 07 22:51:06 2025 +0200 @@ -149,35 +149,31 @@ // TODO: implement culling - // check if geometry needs update + // clear information flags from the previous frame asc_clear_flag(node->flags, ASC_SCENE_NODE_GRAPHICS_UPDATED | ASC_SCENE_NODE_TRANSFORM_UPDATED); + // check if geometry needs an update if (asc_test_flag(node->flags, ASC_SCENE_NODE_UPDATE_GRAPHICS)) { asc_set_flag(node->flags, ASC_SCENE_NODE_GRAPHICS_UPDATED); asc_clear_flag(node->flags, ASC_SCENE_NODE_UPDATE_GRAPHICS); assert(node->update_func != NULL); node->update_func(node); } + // check if transform needs an update if (asc_test_flag(node->flags, ASC_SCENE_NODE_UPDATE_TRANSFORM)) { asc_set_flag(node->flags, ASC_SCENE_NODE_TRANSFORM_UPDATED); asc_clear_flag(node->flags, ASC_SCENE_NODE_UPDATE_TRANSFORM); - - // Only recalculate from components if not using custom transform - if (!asc_test_flag(node->flags, ASC_SCENE_NODE_CUSTOM_TRANSFORM)) { - asc_transform_from_vec3f( + if (node->parent == scene->root) { + // skip unnecessary multiplication with unity matrix + asc_transform_copy(node->world_transform, node->transform); + } else { + asc_mat4f_mulst( + node->world_transform, node->transform, - node->position, - node->scale, - node->rotation + node->parent->world_transform ); } - - asc_mat4f_mulst( - node->world_transform, - node->transform, - node->parent->world_transform - ); } // add to render group
--- a/src/scene_node.c Mon Jul 07 22:41:48 2025 +0200 +++ b/src/scene_node.c Mon Jul 07 22:51:06 2025 +0200 @@ -48,7 +48,6 @@ AscSceneNode *asc_scene_node_empty(void) { AscSceneNode *node = cxZallocDefault(sizeof(AscSceneNode)); node->render_group = ASC_RENDER_GROUP_NONE; - node->scale = ASC_VEC3F_1; asc_transform_identity(node->transform); asc_transform_identity(node->world_transform); return node;
--- a/src/sprite.c Mon Jul 07 22:41:48 2025 +0200 +++ b/src/sprite.c Mon Jul 07 22:51:06 2025 +0200 @@ -133,8 +133,9 @@ node->destroy_func = asc_sprite_destroy; node->draw_func = asc_sprite_draw; - node->position = ASC_VEC3F(args.x, args.y, ASC_SCENE_2D_DEPTH_OFFSET); - node->scale = ASC_VEC3F_1; + asc_transform_identity(node->transform); + asc_transform_translate3f(node->transform, + ASC_VEC3F(args.x, args.y, ASC_SCENE_2D_DEPTH_OFFSET)); asc_node_update(node); return node;
--- a/src/text.c Mon Jul 07 22:41:48 2025 +0200 +++ b/src/text.c Mon Jul 07 22:51:06 2025 +0200 @@ -57,7 +57,7 @@ } if (asc_test_flag(text->base.data.flags, ASC_TEXT_CENTERED_FLAG)) { unsigned short newoffx = surface->w / 2; - node->position.x = node->position.x + (float)(text->offx - newoffx); + asc_transform_translate2f(node->transform, ASC_VEC2F(text->offx - newoffx, 0)); text->offx = newoffx; } @@ -102,8 +102,9 @@ node->destroy_func = asc_text_destroy; node->update_func = asc_text_update; node->draw_func = asc_sprite_draw; - node->position = ASC_VEC3F(args.x, args.y, ASC_SCENE_2D_DEPTH_OFFSET); - node->scale = ASC_VEC3F_1; + asc_transform_identity(node->transform); + asc_transform_translate3f(node->transform, + ASC_VEC3F(args.x, args.y, ASC_SCENE_2D_DEPTH_OFFSET)); // text properties node->flags = args.alignment; // use flags variable to save some space
--- a/test/snake/snake.c Mon Jul 07 22:41:48 2025 +0200 +++ b/test/snake/snake.c Mon Jul 07 22:51:06 2025 +0200 @@ -70,11 +70,13 @@ if (asc_test_flag(node->flags, ASC_SCENE_NODE_GRAPHICS_UPDATED) || asc_active_window->resized) { asc_vec2u bottom_right = asc_active_window->dimensions; asc_vec2u text_size = ((AscText*)node)->dimension; - asc_set_position2d( - node, - (int)bottom_right.x - (int)text_size.width - 10, - (int)bottom_right.y - (int)text_size.height - 10 - ); + asc_transform new_transform; + asc_transform_identity(new_transform); + asc_transform_translate2f(new_transform, ASC_VEC2F( + (int) bottom_right.x - (int) text_size.width - 10, + (int) bottom_right.y - (int) text_size.height - 10 + )); + asc_node_transform_set(node, new_transform); } }