implement texture scaling

Mon, 12 May 2025 20:51:57 +0200

author
Mike Becker <universe@uap-core.de>
date
Mon, 12 May 2025 20:51:57 +0200
changeset 117
d1267f656a97
parent 116
bfb2a7d62047
child 118
830608f7e7d9

implement texture scaling

src/ascension/2d/sprite.h file | annotate | diff | comparison | revisions
src/ascension/datatypes.h file | annotate | diff | comparison | revisions
src/ascension/texture.h file | annotate | diff | comparison | revisions
src/mesh.c file | annotate | diff | comparison | revisions
src/sprite.c file | annotate | diff | comparison | revisions
src/texture.c file | annotate | diff | comparison | revisions
test/snake/snake.c file | annotate | diff | comparison | revisions
--- a/src/ascension/2d/sprite.h	Sun May 11 14:51:00 2025 +0200
+++ b/src/ascension/2d/sprite.h	Mon May 12 20:51:57 2025 +0200
@@ -53,6 +53,9 @@
      * If zero, the texture height will be used.
      */
     unsigned height;
+    enum asc_texture_scale_mode texture_scale_mode;
+    float texture_scale_x;
+    float texture_scale_y;
     bool opaque;
 };
 
--- a/src/ascension/datatypes.h	Sun May 11 14:51:00 2025 +0200
+++ b/src/ascension/datatypes.h	Mon May 12 20:51:57 2025 +0200
@@ -44,6 +44,15 @@
 #define ASC_NANOS_MILLISECOND 1000000ull
 #define ASC_NANOS_MICROSECOND 1000000ull
 
+/**
+ * Tests a value if it is zero and returns an alternative when it is.
+ *
+ * @param y the alternative
+ * @param x the value that shall be tested
+ * @return x if nonzero, y otherwise
+ */
+#define ASC_NONZERO_OR(y, x)  (x ? x : y)
+
 // --------------------------------------------------------------------------
 //    Datatype Definitions
 // --------------------------------------------------------------------------
--- a/src/ascension/texture.h	Sun May 11 14:51:00 2025 +0200
+++ b/src/ascension/texture.h	Mon May 12 20:51:57 2025 +0200
@@ -28,6 +28,8 @@
 #ifndef ASCENSION_TEXTURE_H
 #define ASCENSION_TEXTURE_H
 
+#include "datatypes.h"
+
 #include <SDL2/SDL_surface.h>
 
 typedef struct AscTexture AscTexture;
@@ -38,6 +40,7 @@
     unsigned width;
     unsigned height;
     unsigned refcount;
+    // TODO: add support for texture atlas - idea: rects are defined in AscTexture and can be indexed
 };
 
 enum asc_texture_target {
@@ -59,6 +62,11 @@
     ASC_TEXTURE_MAG_FILTER_LINEAR
 };
 
+enum asc_texture_scale_mode {
+    ASC_TEXTURE_SCALE_FIT,
+    ASC_TEXTURE_SCALE_REPEAT
+};
+
 __attribute__((__nonnull__))
 void asc_texture_init(
         AscTexture *tex,
@@ -88,4 +96,15 @@
 __attribute__((__nonnull__))
 void asc_texture_from_file(AscTexture *tex, const char *name);
 
+
+/**
+ * Calculates UV scaling factors depending on texture and surface dimensions.
+ *
+ * @param tex the texture
+ * @param surface_dimension the dimensions of the surface the texture is applied to
+ * @param factors additional scaling factors
+ * @return the calculated UV scaling factors
+ */
+asc_vec2f asc_texture_calculate_uv_scale(const AscTexture *tex, asc_vec2u surface_dimension, asc_vec2f factors);
+
 #endif //ASCENSION_TEXTURE_H
--- a/src/mesh.c	Sun May 11 14:51:00 2025 +0200
+++ b/src/mesh.c	Mon May 12 20:51:57 2025 +0200
@@ -84,10 +84,10 @@
     free(mesh->vtx_data);
 
     // default values
-    if (args.size.x == 0.0f) args.size.x = 1.0f;
-    if (args.size.y == 0.0f) args.size.y = 1.0f;
-    if (args.uv_scale.x == 0.0f) args.uv_scale.x = 1.0f;
-    if (args.uv_scale.y == 0.0f) args.uv_scale.y = 1.0f;
+    args.size.x = ASC_NONZERO_OR(1.f, args.size.x);
+    args.size.y = ASC_NONZERO_OR(1.f, args.size.y);
+    args.uv_scale.x = ASC_NONZERO_OR(1.f, args.uv_scale.x);
+    args.uv_scale.y = ASC_NONZERO_OR(1.f, args.uv_scale.y);
 
     asc_dprintf("Create plane in VBO %u and VAO %u", mesh->vbo, mesh->vao);
     mesh->vtx_count = 4;
--- a/src/sprite.c	Sun May 11 14:51:00 2025 +0200
+++ b/src/sprite.c	Mon May 12 20:51:57 2025 +0200
@@ -59,10 +59,19 @@
     node->scale = asc_vec3f_one;
     asc_node_update_transform(node);
 
+    // calculate texture parameters
+    asc_vec2f uv_scale;
+    uv_scale.u = ASC_NONZERO_OR(1.f, args.texture_scale_x);
+    uv_scale.v = ASC_NONZERO_OR(1.f, args.texture_scale_y);
+    if (args.texture_scale_mode == ASC_TEXTURE_SCALE_REPEAT) {
+        uv_scale = asc_texture_calculate_uv_scale(args.texture,
+            asc_vec2u_new(args.width, args.height), uv_scale);
+    }
+
     // initialize mesh
     asc_mesh_plane_2d(&sprite->mesh,
         .size = asc_vec2f_new(args.width, args.height),
-        // TODO: support different texture modes
+        .uv_scale = uv_scale
     );
 
     return node;
--- a/src/texture.c	Sun May 11 14:51:00 2025 +0200
+++ b/src/texture.c	Mon May 12 20:51:57 2025 +0200
@@ -162,3 +162,16 @@
     }
     glDeleteTextures(count, textures);
 }
+
+asc_vec2f asc_texture_calculate_uv_scale(const AscTexture *tex, asc_vec2u surface_dimension, asc_vec2f factors) {
+    if (surface_dimension.width == 0 || surface_dimension.height == 0) {
+        asc_wprintf("Tried to calculate UV scale for texture %u with zero dimensions.", tex->tex_id);
+        return factors;
+    }
+    asc_vec2f uv_scale = factors;
+    uv_scale.u *= (float) tex->width;
+    uv_scale.u /= (float) surface_dimension.width;
+    uv_scale.v *= (float) tex->height;
+    uv_scale.v /= (float) surface_dimension.height;
+    return uv_scale;
+}
--- a/test/snake/snake.c	Sun May 11 14:51:00 2025 +0200
+++ b/test/snake/snake.c	Mon May 12 20:51:57 2025 +0200
@@ -88,12 +88,14 @@
         asc_vec2u window_size = asc_active_window->dimensions;
         // TODO: replace scale with asc_sprite_set_size()
         asc_set_scale(node, (float)window_size.width, (float)window_size.height, 1);
-        // TODO: implement texture repetition
     }
 }
 
 static void create_backdrop(void) {
-    AscSceneNode *node = asc_sprite(.texture = TEXTURE_BACKDROP);
+    AscSceneNode *node = asc_sprite(
+        .texture = TEXTURE_BACKDROP,
+        .texture_scale_mode = ASC_TEXTURE_SCALE_REPEAT
+    );
     asc_behavior_add(node, .func = scale_backdrop);
     asc_scene_add_node(BACKDROP_SCENE, node);
 }

mercurial