Mon, 12 May 2025 20:51:57 +0200
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); }