add transformation matrix

Mon, 04 Mar 2024 21:16:46 +0100

author
Mike Becker <universe@uap-core.de>
date
Mon, 04 Mar 2024 21:16:46 +0100
changeset 32
86468a71dd73
parent 31
8324037e0148
child 33
e7ddb52facd3

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
--- a/src/Makefile	Mon Feb 26 21:16:00 2024 +0100
+++ b/src/Makefile	Mon Mar 04 21:16:46 2024 +0100
@@ -43,14 +43,15 @@
 
 $(BUILD_DIR)/context.o: context.c ascension/context.h \
  ascension/datatypes.h ascension/window.h ascension/primitives.h \
- ascension/mesh.h ascension/scene.h ascension/font.h ascension/error.h \
- ascension/utils.h ascension/shader.h
+ ascension/mesh.h ascension/scene.h ascension/transform.h \
+ ascension/font.h ascension/error.h ascension/utils.h ascension/shader.h
 	@echo "Compiling $<"
 	$(CC) -o $@ $(CFLAGS) -c $<
 
 $(BUILD_DIR)/error.o: error.c ascension/context.h ascension/datatypes.h \
  ascension/window.h ascension/primitives.h ascension/mesh.h \
- ascension/scene.h ascension/font.h ascension/error.h ascension/utils.h
+ ascension/scene.h ascension/transform.h ascension/font.h \
+ ascension/error.h ascension/utils.h
 	@echo "Compiling $<"
 	$(CC) -o $@ $(CFLAGS) -c $<
 
@@ -60,18 +61,20 @@
 
 $(BUILD_DIR)/font.o: font.c ascension/font.h ascension/context.h \
  ascension/datatypes.h ascension/window.h ascension/primitives.h \
- ascension/mesh.h ascension/scene.h ascension/font.h ascension/error.h
+ ascension/mesh.h ascension/scene.h ascension/transform.h \
+ ascension/font.h ascension/error.h
 	@echo "Compiling $<"
 	$(CC) -o $@ $(CFLAGS) -c $<
 
 $(BUILD_DIR)/primitives.o: primitives.c ascension/primitives.h \
  ascension/mesh.h ascension/error.h ascension/context.h \
  ascension/datatypes.h ascension/window.h ascension/primitives.h \
- ascension/scene.h ascension/font.h
+ ascension/scene.h ascension/transform.h ascension/font.h
 	@echo "Compiling $<"
 	$(CC) -o $@ $(CFLAGS) -c $<
 
-$(BUILD_DIR)/scene.o: scene.c ascension/scene.h ascension/error.h
+$(BUILD_DIR)/scene.o: scene.c ascension/scene.h ascension/transform.h \
+ ascension/datatypes.h ascension/error.h
 	@echo "Compiling $<"
 	$(CC) -o $@ $(CFLAGS) -c $<
 
@@ -81,16 +84,16 @@
 	$(CC) -o $@ $(CFLAGS) -c $<
 
 $(BUILD_DIR)/text.o: text.c ascension/text.h ascension/font.h \
- ascension/datatypes.h ascension/scene.h ascension/context.h \
- ascension/window.h ascension/primitives.h ascension/mesh.h \
- ascension/error.h ascension/shader.h
+ ascension/scene.h ascension/transform.h ascension/datatypes.h \
+ ascension/context.h ascension/window.h ascension/primitives.h \
+ ascension/mesh.h ascension/error.h ascension/shader.h
 	@echo "Compiling $<"
 	$(CC) -o $@ $(CFLAGS) -c $<
 
 $(BUILD_DIR)/window.o: window.c ascension/window.h ascension/datatypes.h \
  ascension/primitives.h ascension/mesh.h ascension/scene.h \
- ascension/context.h ascension/window.h ascension/font.h \
- ascension/error.h ascension/utils.h
+ ascension/transform.h ascension/context.h ascension/window.h \
+ ascension/font.h ascension/error.h ascension/utils.h
 	@echo "Compiling $<"
 	$(CC) -o $@ $(CFLAGS) -c $<
 
--- a/src/ascension/datatypes.h	Mon Feb 26 21:16:00 2024 +0100
+++ b/src/ascension/datatypes.h	Mon Mar 04 21:16:46 2024 +0100
@@ -92,7 +92,7 @@
 }
 
 static inline SDL_Color asc_col_sdl(asc_col4i col) {
-    return (SDL_Color) {.r = col.red, .g = col.green, .b =col.blue, .a = col.alpha};
+    return (SDL_Color) {.r = col.red, .g = col.green, .b = col.blue, .a = col.alpha};
 }
 
 // --------------------------------------------------------------------------
--- a/src/ascension/scene.h	Mon Feb 26 21:16:00 2024 +0100
+++ b/src/ascension/scene.h	Mon Mar 04 21:16:46 2024 +0100
@@ -28,9 +28,12 @@
 #ifndef ASCENSION_SCENE_H
 #define ASCENSION_SCENE_H
 
+#include "transform.h"
+
 typedef struct AscSceneNode AscSceneNode;
 
 typedef void(*asc_scene_free_func)(AscSceneNode*);
+typedef void(*asc_scene_update_func)(AscSceneNode*);
 typedef void(*asc_scene_draw_func)(AscSceneNode const*);
 
 struct AscSceneNode {
@@ -39,16 +42,21 @@
     AscSceneNode *next;
     AscSceneNode *children;
     asc_scene_free_func free_func;
+    asc_scene_update_func update_func;
     asc_scene_draw_func draw_func;
+    asc_transform transform;
+    bool need_update;
     // TODO: add more node contents
 };
 
 /**
  * Place this as first member of a structure that shall be usable as a scene node.
  */
-#define extend_asc_scene_node AscSceneNode node
+#define extend_asc_scene_node AscSceneNode base
 
-#define asc_node(obj) (&((obj)->node))
+#define asc_node(obj) ((AscSceneNode*)obj)
+
+#define asc_node_update(node) ((AscSceneNode*)node)->need_update = true
 
 typedef struct AscScene {
     AscSceneNode *root;
--- a/src/ascension/text.h	Mon Feb 26 21:16:00 2024 +0100
+++ b/src/ascension/text.h	Mon Mar 04 21:16:46 2024 +0100
@@ -29,7 +29,6 @@
 #define ASCENSION_TEXT_H
 
 #include "font.h"
-#include "datatypes.h"
 #include "scene.h"
 
 typedef struct AscText {
@@ -42,7 +41,6 @@
     bool hidden;
     bool centered;
     struct {
-        asc_vec2i dimension;
         unsigned tex_id;
     } internal;
 } AscText;
@@ -65,16 +63,6 @@
 AscText *asc_text(int x, int y, char const* text);
 
 /**
- * Updates the internal state of the text node.
- *
- * You must invoke this method after changing the state of the struct,
- * but not in every frame.
- *
- * @param node the text node
- */
-void asc_text_update(AscText *node);
-
-/**
  * Releases all the memory of this node.
  *
  * @param node the text node
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ascension/transform.h	Mon Mar 04 21:16:46 2024 +0100
@@ -0,0 +1,98 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ * Copyright 2023 Mike Becker. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ASCENSION_TRANSFORM_H
+#define ASCENSION_TRANSFORM_H
+
+#include "datatypes.h"
+
+typedef asc_mat4f asc_transform;
+
+#define ASC_TRANSFORM_SIZE (sizeof(float)*16)
+
+#ifdef __GNUC__
+#define ASC_TRANFORM_FUNC_ATTRIBUTES \
+    __attribute__((__nonnull__, __always_inline__))
+#else
+#define ASC_TRANFORM_FUNC_ATTRIBUTES
+#endif
+#define ASC_TRANFORM_FUNC ASC_TRANFORM_FUNC_ATTRIBUTES static inline
+
+
+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_TRANFORM_FUNC void asc_transform_copy(asc_transform dest, asc_transform src) {
+    memcpy(dest, src, ASC_TRANSFORM_SIZE);
+}
+
+ASC_TRANFORM_FUNC void asc_transform_translate(
+        asc_transform transform,
+        float x, float y, float z
+) {
+    transform[asc_mat4_index(3, 0)] += x;
+    transform[asc_mat4_index(3, 1)] += y;
+    transform[asc_mat4_index(3, 2)] += z;
+}
+
+ASC_TRANFORM_FUNC void asc_transform_translate2i(
+        asc_transform transform,
+        asc_vec2i position
+) {
+    asc_transform_translate(
+            transform,
+            (float) position.x, (float) position.y, 0
+    );
+}
+
+ASC_TRANFORM_FUNC void asc_transform_scale(
+        asc_transform transform,
+        float x, float y, float z
+) {
+    for (unsigned i = 0 ; i < 3 ; i++) {
+        transform[asc_mat4_index(0, i)] *= x;
+        transform[asc_mat4_index(1, i)] *= y;
+        transform[asc_mat4_index(2, i)] *= z;
+    }
+}
+
+ASC_TRANFORM_FUNC void asc_transform_scale2i(
+        asc_transform transform,
+        asc_vec2i dimensions
+) {
+    asc_transform_scale(
+            transform,
+            (float) dimensions.width, (float) dimensions.height, 0
+    );
+}
+
+#endif //ASCENSION_TRANSFORM_H
--- a/src/scene.c	Mon Feb 26 21:16:00 2024 +0100
+++ b/src/scene.c	Mon Mar 04 21:16:46 2024 +0100
@@ -52,12 +52,23 @@
 
 void asc_scene_add(AscScene *scene, AscSceneNode *node) {
     asc_scene_node_link(scene->root, node);
+    asc_node_update(node);
 }
 
 void asc_scene_draw(AscScene const *scene) {
-    // TODO: don't visit the tree, visit the render groups
     CxTreeIterator iter = cx_tree_iterator(scene->root, false, child_list_off_);
+
+    // skip the root node deliberately, we know it's just the container
+    cxIteratorNext(iter);
+
+    // draw the children
     cx_foreach(AscSceneNode*, node, iter) {
+        if (node->need_update && node->update_func != NULL) {
+            node->need_update = false;
+            asc_transform_copy(node->transform, node->parent->transform);
+            node->update_func(node);
+        }
+        // TODO: don't visit the tree for drawing, visit the render groups
         if (node->draw_func != NULL) {
             node->draw_func(node);
         }
@@ -65,10 +76,10 @@
 }
 
 AscSceneNode *asc_scene_node_empty(void) {
-    // TODO: check if this can remain a calloc or if it's too expensive
     AscSceneNode *node = calloc(1, sizeof(AscSceneNode));
     assert(node != NULL);
     node->free_func = (asc_scene_free_func) free;
+    asc_transform_identity(node->transform);
     return node;
 }
 
--- a/src/text.c	Mon Feb 26 21:16:00 2024 +0100
+++ b/src/text.c	Mon Mar 04 21:16:46 2024 +0100
@@ -37,21 +37,15 @@
         return;
     }
 
+    // TODO: when we group draw calls, we don't need to activate shader here
     glUseProgram(ASC_SHADER_FONT.base.id);
 
-    // Upload projection
-    // TODO: when we group UI draw calls, we don't need this
+    // TODO: when we group UI draw calls, we don't need to upload matrices here
+    // Upload matrices
     glUniformMatrix4fv(ASC_SHADER_FONT.base.projection, 1,
                        GL_FALSE, asc_context.active_window->projection);
-
-    // Upload model matrix
-    asc_mat4f model = {0};
-    model[asc_mat4_index(0, 0)] = node->internal.dimension.width;
-    model[asc_mat4_index(1, 1)] = node->internal.dimension.height;
-    model[asc_mat4_index(3, 0)] = node->position.x;
-    model[asc_mat4_index(3, 1)] = node->position.y;
-    model[asc_mat4_index(3, 3)] = 1;
-    glUniformMatrix4fv(ASC_SHADER_FONT.base.model, 1, GL_FALSE, model);
+    glUniformMatrix4fv(ASC_SHADER_FONT.base.model, 1,
+                       GL_FALSE, node->base.transform);
 
     // Upload surface
     glActiveTexture(GL_TEXTURE0);
@@ -62,27 +56,7 @@
     asc_primitives_draw_plane();
 }
 
-AscText *asc_text(int x, int y, char const *text) {
-    AscText *node = calloc(1, sizeof(AscText));
-    if (node == NULL) {
-        asc_error("Out of memory.");
-        return NULL;
-    }
-
-    node->node.free_func = (asc_scene_free_func) asc_text_free;
-    node->node.draw_func = (asc_scene_draw_func) asc_text_draw;
-
-    node->position = (asc_vec2i) {x, y};
-    node->font = asc_context.active_font;
-    node->color = asc_context.ink;
-    if (text != NULL) {
-        node->text = strdup(text);
-    }
-
-    return node;
-}
-
-void asc_text_update(AscText *node) {
+static void asc_text_update(AscText *node) {
     // short circuit if fully transparent or hidden, we don't need anything
     if (node->color.alpha == 0 || node->hidden) {
         return;
@@ -109,10 +83,9 @@
         return;
     }
 
-    // Store basic node information
-    node->position = node->position;
-    node->internal.dimension.width = surface->w;
-    node->internal.dimension.height = surface->h;
+    // Transform
+    asc_transform_scale(node->base.transform, (float) surface->w, (float) surface->h, 0);
+    asc_transform_translate2i(node->base.transform, node->position);
 
     // Transfer Image Data
     // TODO: move the image data transfer to a separate function - we will need it more often
@@ -126,6 +99,28 @@
     SDL_FreeSurface(surface);
 }
 
+AscText *asc_text(int x, int y, char const *text) {
+    AscText *node = calloc(1, sizeof(AscText));
+    if (node == NULL) {
+        asc_error("Out of memory.");
+        return NULL;
+    }
+
+    node->base.free_func = (asc_scene_free_func) asc_text_free;
+    node->base.update_func = (asc_scene_update_func) asc_text_update;
+    node->base.draw_func = (asc_scene_draw_func) asc_text_draw;
+
+    node->position.x = x;
+    node->position.y = y;
+    node->font = asc_context.active_font;
+    node->color = asc_context.ink;
+    if (text != NULL) {
+        node->text = strdup(text);
+    }
+
+    return node;
+}
+
 void asc_text_free(AscText *node) {
     asc_dprintf("Release text node texture: %u", node->internal.tex_id);
     glDeleteTextures(1, &node->internal.tex_id);
--- a/test/Makefile	Mon Feb 26 21:16:00 2024 +0100
+++ b/test/Makefile	Mon Mar 04 21:16:46 2024 +0100
@@ -45,8 +45,9 @@
  ../src/ascension/error.h ../src/ascension/context.h \
  ../src/ascension/datatypes.h ../src/ascension/window.h \
  ../src/ascension/primitives.h ../src/ascension/mesh.h \
- ../src/ascension/scene.h ../src/ascension/font.h \
- ../src/ascension/shader.h ../src/ascension/text.h
+ ../src/ascension/scene.h ../src/ascension/transform.h \
+ ../src/ascension/font.h ../src/ascension/shader.h \
+ ../src/ascension/text.h
 	@echo "Compiling $<"
 	$(CC) -o $@ $(CFLAGS) -c $<
 
--- a/test/sandbox.c	Mon Feb 26 21:16:00 2024 +0100
+++ b/test/sandbox.c	Mon Mar 04 21:16:46 2024 +0100
@@ -69,7 +69,7 @@
             if (fps != last_fps) {
                 last_fps = fps;
                 snprintf(fps_counter->text, 9, "%u FPS", fps);
-                asc_text_update(fps_counter);
+                asc_node_update(fps_counter);
             }
         }
     } while (asc_loop_next());

mercurial