SDL_ttf: GPU text engine api improvements (#443)

From 6b5eeb2e7c18f2b33fe75c8dc6b5c8954ab22275 Mon Sep 17 00:00:00 2001
From: Captain <[EMAIL REDACTED]>
Date: Mon, 23 Dec 2024 04:20:23 +0530
Subject: [PATCH] GPU text engine api improvements (#443)

* testgputext: apply vertex offset while drawing the text
* changed the float arrays to SDL_FPoint array
---
 examples/testgputext.c     | 19 +++++++------------
 include/SDL3_ttf/SDL_ttf.h |  6 ++----
 src/SDL_gpu_textengine.c   | 12 ++++++------
 3 files changed, 15 insertions(+), 22 deletions(-)

diff --git a/examples/testgputext.c b/examples/testgputext.c
index d8f27888..bc4a7e6f 100644
--- a/examples/testgputext.c
+++ b/examples/testgputext.c
@@ -13,10 +13,7 @@
 #define MAX_INDEX_COUNT  6000
 #define SUPPORTED_SHADER_FORMATS (SDL_GPU_SHADERFORMAT_SPIRV | SDL_GPU_SHADERFORMAT_DXBC | SDL_GPU_SHADERFORMAT_DXIL | SDL_GPU_SHADERFORMAT_METALLIB)
 
-typedef struct Vec2
-{
-    float x, y;
-} Vec2;
+typedef SDL_FPoint Vec2;
 
 typedef struct Vec3
 {
@@ -112,13 +109,10 @@ void queue_text_sequence(GeometryData *geometry_data, TTF_GPUAtlasDrawSequence *
 {
     for (int i = 0; i < sequence->num_vertices; i++) {
         Vertex vert;
-        const float *xy = (float *)((Uint8 *)sequence->xy + i * sequence->xy_stride);
-        vert.pos = (Vec3){ xy[0], xy[1], 0.0f };
-
+        const SDL_FPoint pos = sequence->xy[i];
+        vert.pos = (Vec3){ pos.x, pos.y, 0.0f };
         vert.colour = *colour;
-
-        const float *uv = (float *)((Uint8 *)sequence->uv + i * sequence->uv_stride);
-        SDL_memcpy(&vert.uv, uv, 2 * sizeof(float));
+        vert.uv = sequence->uv[i];
 
         geometry_data->vertices[geometry_data->vertex_count + i] = vert;
     }
@@ -199,7 +193,7 @@ void draw(Context *context, SDL_Mat4X4 *matrices, int num_matrices, TTF_GPUAtlas
             SDL_GPU_INDEXELEMENTSIZE_32BIT);
         SDL_PushGPUVertexUniformData(context->cmd_buf, 0, matrices, sizeof(SDL_Mat4X4) * num_matrices);
 
-        int index_offset = 0;
+        int index_offset = 0, vertex_offset = 0;
         for (TTF_GPUAtlasDrawSequence *seq = draw_sequence; seq != NULL; seq = seq->next) {
             SDL_BindGPUFragmentSamplers(
                 render_pass, 0,
@@ -207,9 +201,10 @@ void draw(Context *context, SDL_Mat4X4 *matrices, int num_matrices, TTF_GPUAtlas
                     .texture = seq->atlas_texture, .sampler = context->sampler },
                 1);
 
-            SDL_DrawGPUIndexedPrimitives(render_pass, seq->num_indices, 1, index_offset, 0, 0);
+            SDL_DrawGPUIndexedPrimitives(render_pass, seq->num_indices, 1, index_offset, vertex_offset, 0);
 
             index_offset += seq->num_indices;
+            vertex_offset += seq->num_vertices;
         }
         SDL_EndGPURenderPass(render_pass);
     }
diff --git a/include/SDL3_ttf/SDL_ttf.h b/include/SDL3_ttf/SDL_ttf.h
index 734c9cf6..2d395ab8 100644
--- a/include/SDL3_ttf/SDL_ttf.h
+++ b/include/SDL3_ttf/SDL_ttf.h
@@ -1653,10 +1653,8 @@ extern SDL_DECLSPEC TTF_TextEngine * SDLCALL TTF_CreateGPUTextEngine(SDL_GPUDevi
 typedef struct TTF_GPUAtlasDrawSequence
 {
     SDL_GPUTexture *atlas_texture;          /**< Texture atlas that stores the glyphs */
-    float *xy;                              /**< Vertex positions */
-    int xy_stride;                          /**< Byte size to move from one element to the next element */
-    float *uv;                              /**< Vertex normalized texture coordinates */
-    int uv_stride;                          /**< Byte size to move from one element to the next element */
+    SDL_FPoint *xy;                         /**< An array of vertex positions */
+    SDL_FPoint *uv;                         /**< An array of normalized texture coordinates for each vertex */
     int num_vertices;                       /**< Number of vertices */
     int *indices;                           /**< An array of indices into the 'vertices' arrays */
     int num_indices;                        /**< Number of indices */
diff --git a/src/SDL_gpu_textengine.c b/src/SDL_gpu_textengine.c
index a5e4e64e..1801e894 100644
--- a/src/SDL_gpu_textengine.c
+++ b/src/SDL_gpu_textengine.c
@@ -18,6 +18,7 @@
      misrepresented as being the original software.
   3. This notice may not be removed or altered from any source distribution.
 */
+#include <SDL3/SDL.h>
 #include <SDL3_ttf/SDL_textengine.h>
 
 #include "SDL_hashtable.h"
@@ -588,6 +589,7 @@ static AtlasDrawSequence *CreateDrawSequence(TTF_DrawOperation *ops, int num_ops
     }
 
     SDL_assert(num_ops > 0);
+    SDL_COMPILE_TIME_ASSERT(sizeof_SDL_FPoint, sizeof(SDL_FPoint) == 2 * sizeof(float));
 
     SDL_GPUTexture *texture = GetOperationTexture(&ops[0]);
     TTF_DrawOperation *end = NULL;
@@ -602,19 +604,17 @@ static AtlasDrawSequence *CreateDrawSequence(TTF_DrawOperation *ops, int num_ops
     sequence->atlas_texture = texture;
     sequence->num_vertices = count * 4;
     sequence->num_indices = count * 6;
-    sequence->xy_stride = sizeof(float) * 2;
-    sequence->uv_stride = sizeof(float) * 2;
 
     if (texture) {
         AtlasGlyph *glyph;
 
-        sequence->uv = (float *)SDL_malloc(count * sizeof(glyph->texcoords));
+        sequence->uv = (SDL_FPoint *)SDL_malloc(count * sizeof(glyph->texcoords));
         if (!sequence->uv) {
             DestroyDrawSequence(sequence);
             return NULL;
         }
 
-        float *uv = sequence->uv;
+        float *uv = (float *)sequence->uv;
         for (int i = 0; i < count; ++i) {
             AtlasGlyph *glyph = (AtlasGlyph *)ops[i].copy.reserved;
             SDL_memcpy(uv, glyph->texcoords, sizeof(glyph->texcoords));
@@ -622,12 +622,12 @@ static AtlasDrawSequence *CreateDrawSequence(TTF_DrawOperation *ops, int num_ops
         }
     }
 
-    sequence->xy = (float *)SDL_malloc(count * 8 * sizeof(*sequence->xy));
+    sequence->xy = (SDL_FPoint *)SDL_malloc(count * 4 * sizeof(*sequence->xy));
     if (!sequence->xy) {
         DestroyDrawSequence(sequence);
         return NULL;
     }
-    float *xy = sequence->xy;
+    float *xy = (float *)sequence->xy;
     for (int i = 0; i < count; ++i) {
         TTF_DrawOperation *op = &ops[i];
         SDL_Rect *dst = NULL;