Mon, 04 Mar 2024 21:16:46 +0100
add transformation matrix
src/Makefile | file | annotate | diff | comparison | revisions | |
src/ascension/datatypes.h | file | annotate | diff | comparison | revisions | |
src/ascension/scene.h | file | annotate | diff | comparison | revisions | |
src/ascension/text.h | file | annotate | diff | comparison | revisions | |
src/ascension/transform.h | file | annotate | diff | comparison | revisions | |
src/scene.c | file | annotate | diff | comparison | revisions | |
src/text.c | file | annotate | diff | comparison | revisions | |
test/Makefile | file | annotate | diff | comparison | revisions | |
test/sandbox.c | file | annotate | diff | comparison | revisions |
1.1 --- a/src/Makefile Mon Feb 26 21:16:00 2024 +0100 1.2 +++ b/src/Makefile Mon Mar 04 21:16:46 2024 +0100 1.3 @@ -43,14 +43,15 @@ 1.4 1.5 $(BUILD_DIR)/context.o: context.c ascension/context.h \ 1.6 ascension/datatypes.h ascension/window.h ascension/primitives.h \ 1.7 - ascension/mesh.h ascension/scene.h ascension/font.h ascension/error.h \ 1.8 - ascension/utils.h ascension/shader.h 1.9 + ascension/mesh.h ascension/scene.h ascension/transform.h \ 1.10 + ascension/font.h ascension/error.h ascension/utils.h ascension/shader.h 1.11 @echo "Compiling $<" 1.12 $(CC) -o $@ $(CFLAGS) -c $< 1.13 1.14 $(BUILD_DIR)/error.o: error.c ascension/context.h ascension/datatypes.h \ 1.15 ascension/window.h ascension/primitives.h ascension/mesh.h \ 1.16 - ascension/scene.h ascension/font.h ascension/error.h ascension/utils.h 1.17 + ascension/scene.h ascension/transform.h ascension/font.h \ 1.18 + ascension/error.h ascension/utils.h 1.19 @echo "Compiling $<" 1.20 $(CC) -o $@ $(CFLAGS) -c $< 1.21 1.22 @@ -60,18 +61,20 @@ 1.23 1.24 $(BUILD_DIR)/font.o: font.c ascension/font.h ascension/context.h \ 1.25 ascension/datatypes.h ascension/window.h ascension/primitives.h \ 1.26 - ascension/mesh.h ascension/scene.h ascension/font.h ascension/error.h 1.27 + ascension/mesh.h ascension/scene.h ascension/transform.h \ 1.28 + ascension/font.h ascension/error.h 1.29 @echo "Compiling $<" 1.30 $(CC) -o $@ $(CFLAGS) -c $< 1.31 1.32 $(BUILD_DIR)/primitives.o: primitives.c ascension/primitives.h \ 1.33 ascension/mesh.h ascension/error.h ascension/context.h \ 1.34 ascension/datatypes.h ascension/window.h ascension/primitives.h \ 1.35 - ascension/scene.h ascension/font.h 1.36 + ascension/scene.h ascension/transform.h ascension/font.h 1.37 @echo "Compiling $<" 1.38 $(CC) -o $@ $(CFLAGS) -c $< 1.39 1.40 -$(BUILD_DIR)/scene.o: scene.c ascension/scene.h ascension/error.h 1.41 +$(BUILD_DIR)/scene.o: scene.c ascension/scene.h ascension/transform.h \ 1.42 + ascension/datatypes.h ascension/error.h 1.43 @echo "Compiling $<" 1.44 $(CC) -o $@ $(CFLAGS) -c $< 1.45 1.46 @@ -81,16 +84,16 @@ 1.47 $(CC) -o $@ $(CFLAGS) -c $< 1.48 1.49 $(BUILD_DIR)/text.o: text.c ascension/text.h ascension/font.h \ 1.50 - ascension/datatypes.h ascension/scene.h ascension/context.h \ 1.51 - ascension/window.h ascension/primitives.h ascension/mesh.h \ 1.52 - ascension/error.h ascension/shader.h 1.53 + ascension/scene.h ascension/transform.h ascension/datatypes.h \ 1.54 + ascension/context.h ascension/window.h ascension/primitives.h \ 1.55 + ascension/mesh.h ascension/error.h ascension/shader.h 1.56 @echo "Compiling $<" 1.57 $(CC) -o $@ $(CFLAGS) -c $< 1.58 1.59 $(BUILD_DIR)/window.o: window.c ascension/window.h ascension/datatypes.h \ 1.60 ascension/primitives.h ascension/mesh.h ascension/scene.h \ 1.61 - ascension/context.h ascension/window.h ascension/font.h \ 1.62 - ascension/error.h ascension/utils.h 1.63 + ascension/transform.h ascension/context.h ascension/window.h \ 1.64 + ascension/font.h ascension/error.h ascension/utils.h 1.65 @echo "Compiling $<" 1.66 $(CC) -o $@ $(CFLAGS) -c $< 1.67
2.1 --- a/src/ascension/datatypes.h Mon Feb 26 21:16:00 2024 +0100 2.2 +++ b/src/ascension/datatypes.h Mon Mar 04 21:16:46 2024 +0100 2.3 @@ -92,7 +92,7 @@ 2.4 } 2.5 2.6 static inline SDL_Color asc_col_sdl(asc_col4i col) { 2.7 - return (SDL_Color) {.r = col.red, .g = col.green, .b =col.blue, .a = col.alpha}; 2.8 + return (SDL_Color) {.r = col.red, .g = col.green, .b = col.blue, .a = col.alpha}; 2.9 } 2.10 2.11 // --------------------------------------------------------------------------
3.1 --- a/src/ascension/scene.h Mon Feb 26 21:16:00 2024 +0100 3.2 +++ b/src/ascension/scene.h Mon Mar 04 21:16:46 2024 +0100 3.3 @@ -28,9 +28,12 @@ 3.4 #ifndef ASCENSION_SCENE_H 3.5 #define ASCENSION_SCENE_H 3.6 3.7 +#include "transform.h" 3.8 + 3.9 typedef struct AscSceneNode AscSceneNode; 3.10 3.11 typedef void(*asc_scene_free_func)(AscSceneNode*); 3.12 +typedef void(*asc_scene_update_func)(AscSceneNode*); 3.13 typedef void(*asc_scene_draw_func)(AscSceneNode const*); 3.14 3.15 struct AscSceneNode { 3.16 @@ -39,16 +42,21 @@ 3.17 AscSceneNode *next; 3.18 AscSceneNode *children; 3.19 asc_scene_free_func free_func; 3.20 + asc_scene_update_func update_func; 3.21 asc_scene_draw_func draw_func; 3.22 + asc_transform transform; 3.23 + bool need_update; 3.24 // TODO: add more node contents 3.25 }; 3.26 3.27 /** 3.28 * Place this as first member of a structure that shall be usable as a scene node. 3.29 */ 3.30 -#define extend_asc_scene_node AscSceneNode node 3.31 +#define extend_asc_scene_node AscSceneNode base 3.32 3.33 -#define asc_node(obj) (&((obj)->node)) 3.34 +#define asc_node(obj) ((AscSceneNode*)obj) 3.35 + 3.36 +#define asc_node_update(node) ((AscSceneNode*)node)->need_update = true 3.37 3.38 typedef struct AscScene { 3.39 AscSceneNode *root;
4.1 --- a/src/ascension/text.h Mon Feb 26 21:16:00 2024 +0100 4.2 +++ b/src/ascension/text.h Mon Mar 04 21:16:46 2024 +0100 4.3 @@ -29,7 +29,6 @@ 4.4 #define ASCENSION_TEXT_H 4.5 4.6 #include "font.h" 4.7 -#include "datatypes.h" 4.8 #include "scene.h" 4.9 4.10 typedef struct AscText { 4.11 @@ -42,7 +41,6 @@ 4.12 bool hidden; 4.13 bool centered; 4.14 struct { 4.15 - asc_vec2i dimension; 4.16 unsigned tex_id; 4.17 } internal; 4.18 } AscText; 4.19 @@ -65,16 +63,6 @@ 4.20 AscText *asc_text(int x, int y, char const* text); 4.21 4.22 /** 4.23 - * Updates the internal state of the text node. 4.24 - * 4.25 - * You must invoke this method after changing the state of the struct, 4.26 - * but not in every frame. 4.27 - * 4.28 - * @param node the text node 4.29 - */ 4.30 -void asc_text_update(AscText *node); 4.31 - 4.32 -/** 4.33 * Releases all the memory of this node. 4.34 * 4.35 * @param node the text node
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/src/ascension/transform.h Mon Mar 04 21:16:46 2024 +0100 5.3 @@ -0,0 +1,98 @@ 5.4 +/* 5.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 5.6 + * Copyright 2023 Mike Becker. All rights reserved. 5.7 + * 5.8 + * Redistribution and use in source and binary forms, with or without 5.9 + * modification, are permitted provided that the following conditions are met: 5.10 + * 5.11 + * 1. Redistributions of source code must retain the above copyright 5.12 + * notice, this list of conditions and the following disclaimer. 5.13 + * 5.14 + * 2. Redistributions in binary form must reproduce the above copyright 5.15 + * notice, this list of conditions and the following disclaimer in the 5.16 + * documentation and/or other materials provided with the distribution. 5.17 + * 5.18 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 5.19 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5.20 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5.21 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 5.22 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 5.23 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 5.24 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 5.25 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 5.26 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 5.27 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 5.28 + * POSSIBILITY OF SUCH DAMAGE. 5.29 + */ 5.30 + 5.31 +#ifndef ASCENSION_TRANSFORM_H 5.32 +#define ASCENSION_TRANSFORM_H 5.33 + 5.34 +#include "datatypes.h" 5.35 + 5.36 +typedef asc_mat4f asc_transform; 5.37 + 5.38 +#define ASC_TRANSFORM_SIZE (sizeof(float)*16) 5.39 + 5.40 +#ifdef __GNUC__ 5.41 +#define ASC_TRANFORM_FUNC_ATTRIBUTES \ 5.42 + __attribute__((__nonnull__, __always_inline__)) 5.43 +#else 5.44 +#define ASC_TRANFORM_FUNC_ATTRIBUTES 5.45 +#endif 5.46 +#define ASC_TRANFORM_FUNC ASC_TRANFORM_FUNC_ATTRIBUTES static inline 5.47 + 5.48 + 5.49 +ASC_TRANFORM_FUNC void asc_transform_identity(asc_transform transform) { 5.50 + memset(transform, 0, ASC_TRANSFORM_SIZE); 5.51 + transform[asc_mat4_index(0, 0)] = 1; 5.52 + transform[asc_mat4_index(1, 1)] = 1; 5.53 + transform[asc_mat4_index(2, 2)] = 1; 5.54 + transform[asc_mat4_index(3, 3)] = 1; 5.55 +} 5.56 + 5.57 +ASC_TRANFORM_FUNC void asc_transform_copy(asc_transform dest, asc_transform src) { 5.58 + memcpy(dest, src, ASC_TRANSFORM_SIZE); 5.59 +} 5.60 + 5.61 +ASC_TRANFORM_FUNC void asc_transform_translate( 5.62 + asc_transform transform, 5.63 + float x, float y, float z 5.64 +) { 5.65 + transform[asc_mat4_index(3, 0)] += x; 5.66 + transform[asc_mat4_index(3, 1)] += y; 5.67 + transform[asc_mat4_index(3, 2)] += z; 5.68 +} 5.69 + 5.70 +ASC_TRANFORM_FUNC void asc_transform_translate2i( 5.71 + asc_transform transform, 5.72 + asc_vec2i position 5.73 +) { 5.74 + asc_transform_translate( 5.75 + transform, 5.76 + (float) position.x, (float) position.y, 0 5.77 + ); 5.78 +} 5.79 + 5.80 +ASC_TRANFORM_FUNC void asc_transform_scale( 5.81 + asc_transform transform, 5.82 + float x, float y, float z 5.83 +) { 5.84 + for (unsigned i = 0 ; i < 3 ; i++) { 5.85 + transform[asc_mat4_index(0, i)] *= x; 5.86 + transform[asc_mat4_index(1, i)] *= y; 5.87 + transform[asc_mat4_index(2, i)] *= z; 5.88 + } 5.89 +} 5.90 + 5.91 +ASC_TRANFORM_FUNC void asc_transform_scale2i( 5.92 + asc_transform transform, 5.93 + asc_vec2i dimensions 5.94 +) { 5.95 + asc_transform_scale( 5.96 + transform, 5.97 + (float) dimensions.width, (float) dimensions.height, 0 5.98 + ); 5.99 +} 5.100 + 5.101 +#endif //ASCENSION_TRANSFORM_H
6.1 --- a/src/scene.c Mon Feb 26 21:16:00 2024 +0100 6.2 +++ b/src/scene.c Mon Mar 04 21:16:46 2024 +0100 6.3 @@ -52,12 +52,23 @@ 6.4 6.5 void asc_scene_add(AscScene *scene, AscSceneNode *node) { 6.6 asc_scene_node_link(scene->root, node); 6.7 + asc_node_update(node); 6.8 } 6.9 6.10 void asc_scene_draw(AscScene const *scene) { 6.11 - // TODO: don't visit the tree, visit the render groups 6.12 CxTreeIterator iter = cx_tree_iterator(scene->root, false, child_list_off_); 6.13 + 6.14 + // skip the root node deliberately, we know it's just the container 6.15 + cxIteratorNext(iter); 6.16 + 6.17 + // draw the children 6.18 cx_foreach(AscSceneNode*, node, iter) { 6.19 + if (node->need_update && node->update_func != NULL) { 6.20 + node->need_update = false; 6.21 + asc_transform_copy(node->transform, node->parent->transform); 6.22 + node->update_func(node); 6.23 + } 6.24 + // TODO: don't visit the tree for drawing, visit the render groups 6.25 if (node->draw_func != NULL) { 6.26 node->draw_func(node); 6.27 } 6.28 @@ -65,10 +76,10 @@ 6.29 } 6.30 6.31 AscSceneNode *asc_scene_node_empty(void) { 6.32 - // TODO: check if this can remain a calloc or if it's too expensive 6.33 AscSceneNode *node = calloc(1, sizeof(AscSceneNode)); 6.34 assert(node != NULL); 6.35 node->free_func = (asc_scene_free_func) free; 6.36 + asc_transform_identity(node->transform); 6.37 return node; 6.38 } 6.39
7.1 --- a/src/text.c Mon Feb 26 21:16:00 2024 +0100 7.2 +++ b/src/text.c Mon Mar 04 21:16:46 2024 +0100 7.3 @@ -37,21 +37,15 @@ 7.4 return; 7.5 } 7.6 7.7 + // TODO: when we group draw calls, we don't need to activate shader here 7.8 glUseProgram(ASC_SHADER_FONT.base.id); 7.9 7.10 - // Upload projection 7.11 - // TODO: when we group UI draw calls, we don't need this 7.12 + // TODO: when we group UI draw calls, we don't need to upload matrices here 7.13 + // Upload matrices 7.14 glUniformMatrix4fv(ASC_SHADER_FONT.base.projection, 1, 7.15 GL_FALSE, asc_context.active_window->projection); 7.16 - 7.17 - // Upload model matrix 7.18 - asc_mat4f model = {0}; 7.19 - model[asc_mat4_index(0, 0)] = node->internal.dimension.width; 7.20 - model[asc_mat4_index(1, 1)] = node->internal.dimension.height; 7.21 - model[asc_mat4_index(3, 0)] = node->position.x; 7.22 - model[asc_mat4_index(3, 1)] = node->position.y; 7.23 - model[asc_mat4_index(3, 3)] = 1; 7.24 - glUniformMatrix4fv(ASC_SHADER_FONT.base.model, 1, GL_FALSE, model); 7.25 + glUniformMatrix4fv(ASC_SHADER_FONT.base.model, 1, 7.26 + GL_FALSE, node->base.transform); 7.27 7.28 // Upload surface 7.29 glActiveTexture(GL_TEXTURE0); 7.30 @@ -62,27 +56,7 @@ 7.31 asc_primitives_draw_plane(); 7.32 } 7.33 7.34 -AscText *asc_text(int x, int y, char const *text) { 7.35 - AscText *node = calloc(1, sizeof(AscText)); 7.36 - if (node == NULL) { 7.37 - asc_error("Out of memory."); 7.38 - return NULL; 7.39 - } 7.40 - 7.41 - node->node.free_func = (asc_scene_free_func) asc_text_free; 7.42 - node->node.draw_func = (asc_scene_draw_func) asc_text_draw; 7.43 - 7.44 - node->position = (asc_vec2i) {x, y}; 7.45 - node->font = asc_context.active_font; 7.46 - node->color = asc_context.ink; 7.47 - if (text != NULL) { 7.48 - node->text = strdup(text); 7.49 - } 7.50 - 7.51 - return node; 7.52 -} 7.53 - 7.54 -void asc_text_update(AscText *node) { 7.55 +static void asc_text_update(AscText *node) { 7.56 // short circuit if fully transparent or hidden, we don't need anything 7.57 if (node->color.alpha == 0 || node->hidden) { 7.58 return; 7.59 @@ -109,10 +83,9 @@ 7.60 return; 7.61 } 7.62 7.63 - // Store basic node information 7.64 - node->position = node->position; 7.65 - node->internal.dimension.width = surface->w; 7.66 - node->internal.dimension.height = surface->h; 7.67 + // Transform 7.68 + asc_transform_scale(node->base.transform, (float) surface->w, (float) surface->h, 0); 7.69 + asc_transform_translate2i(node->base.transform, node->position); 7.70 7.71 // Transfer Image Data 7.72 // TODO: move the image data transfer to a separate function - we will need it more often 7.73 @@ -126,6 +99,28 @@ 7.74 SDL_FreeSurface(surface); 7.75 } 7.76 7.77 +AscText *asc_text(int x, int y, char const *text) { 7.78 + AscText *node = calloc(1, sizeof(AscText)); 7.79 + if (node == NULL) { 7.80 + asc_error("Out of memory."); 7.81 + return NULL; 7.82 + } 7.83 + 7.84 + node->base.free_func = (asc_scene_free_func) asc_text_free; 7.85 + node->base.update_func = (asc_scene_update_func) asc_text_update; 7.86 + node->base.draw_func = (asc_scene_draw_func) asc_text_draw; 7.87 + 7.88 + node->position.x = x; 7.89 + node->position.y = y; 7.90 + node->font = asc_context.active_font; 7.91 + node->color = asc_context.ink; 7.92 + if (text != NULL) { 7.93 + node->text = strdup(text); 7.94 + } 7.95 + 7.96 + return node; 7.97 +} 7.98 + 7.99 void asc_text_free(AscText *node) { 7.100 asc_dprintf("Release text node texture: %u", node->internal.tex_id); 7.101 glDeleteTextures(1, &node->internal.tex_id);
8.1 --- a/test/Makefile Mon Feb 26 21:16:00 2024 +0100 8.2 +++ b/test/Makefile Mon Mar 04 21:16:46 2024 +0100 8.3 @@ -45,8 +45,9 @@ 8.4 ../src/ascension/error.h ../src/ascension/context.h \ 8.5 ../src/ascension/datatypes.h ../src/ascension/window.h \ 8.6 ../src/ascension/primitives.h ../src/ascension/mesh.h \ 8.7 - ../src/ascension/scene.h ../src/ascension/font.h \ 8.8 - ../src/ascension/shader.h ../src/ascension/text.h 8.9 + ../src/ascension/scene.h ../src/ascension/transform.h \ 8.10 + ../src/ascension/font.h ../src/ascension/shader.h \ 8.11 + ../src/ascension/text.h 8.12 @echo "Compiling $<" 8.13 $(CC) -o $@ $(CFLAGS) -c $< 8.14
9.1 --- a/test/sandbox.c Mon Feb 26 21:16:00 2024 +0100 9.2 +++ b/test/sandbox.c Mon Mar 04 21:16:46 2024 +0100 9.3 @@ -69,7 +69,7 @@ 9.4 if (fps != last_fps) { 9.5 last_fps = fps; 9.6 snprintf(fps_counter->text, 9, "%u FPS", fps); 9.7 - asc_text_update(fps_counter); 9.8 + asc_node_update(fps_counter); 9.9 } 9.10 } 9.11 } while (asc_loop_next());