SDL_ttf: Use indices to reduce the number of vertices we send.

From d7a1e4293005e5ac4b84ac1f0e13d048257487d7 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Mon, 30 Sep 2024 17:56:05 -0700
Subject: [PATCH] Use indices to reduce the number of vertices we send.

This will also potentially allow us to change the triangle winding order if it becomes important.
---
 src/SDL_renderer_textengine.c | 79 ++++++++++++++++++++---------------
 1 file changed, 46 insertions(+), 33 deletions(-)

diff --git a/src/SDL_renderer_textengine.c b/src/SDL_renderer_textengine.c
index ae2877c2..3c1947c7 100644
--- a/src/SDL_renderer_textengine.c
+++ b/src/SDL_renderer_textengine.c
@@ -39,7 +39,7 @@ struct AtlasGlyph
     int refcount;
     AtlasTexture *atlas;
     SDL_Rect rect;
-    float texcoords[12];
+    float texcoords[8];
     AtlasGlyph *next;
 };
 
@@ -60,6 +60,7 @@ struct AtlasDrawSequence
     SDL_Rect *rects;
     float *texcoords;
     float *positions;
+    int *indices;
     AtlasDrawSequence *next;
 };
 
@@ -237,22 +238,18 @@ static AtlasGlyph *CreateGlyph(AtlasTexture *atlas, const stbrp_rect *area)
     glyph->rect.w = area->w;
     glyph->rect.h = area->h;
 
-    const float minx = (float)area->x / ATLAS_TEXTURE_SIZE;
-    const float maxx = (float)(area->x + area->w) / ATLAS_TEXTURE_SIZE;
-    const float miny = (float)area->y / ATLAS_TEXTURE_SIZE;
-    const float maxy = (float)(area->y + area->h) / ATLAS_TEXTURE_SIZE;
-    glyph->texcoords[0] = minx;
-    glyph->texcoords[1] = miny;
-    glyph->texcoords[2] = maxx;
-    glyph->texcoords[3] = miny;
-    glyph->texcoords[4] = maxx;
-    glyph->texcoords[5] = maxy;
-    glyph->texcoords[6] = minx;
-    glyph->texcoords[7] = miny;
-    glyph->texcoords[8] = maxx;
-    glyph->texcoords[9] = maxy;
-    glyph->texcoords[10] = minx;
-    glyph->texcoords[11] = maxy;
+    const float minu = (float)area->x / ATLAS_TEXTURE_SIZE;
+    const float minv = (float)area->y / ATLAS_TEXTURE_SIZE;
+    const float maxu = (float)(area->x + area->w) / ATLAS_TEXTURE_SIZE;
+    const float maxv = (float)(area->y + area->h) / ATLAS_TEXTURE_SIZE;
+    glyph->texcoords[0] = minu;
+    glyph->texcoords[1] = minv;
+    glyph->texcoords[2] = maxu;
+    glyph->texcoords[3] = minv;
+    glyph->texcoords[4] = maxu;
+    glyph->texcoords[5] = maxv;
+    glyph->texcoords[6] = minu;
+    glyph->texcoords[7] = maxv;
 
     return glyph;
 }
@@ -506,6 +503,7 @@ static void DestroyDrawSequence(AtlasDrawSequence *data)
     }
     SDL_free(data->texcoords);
     SDL_free(data->positions);
+    SDL_free(data->indices);
     SDL_free(data);
 }
 
@@ -578,12 +576,31 @@ static AtlasDrawSequence *CreateDrawSequence(TTF_DrawOperation *ops, int num_ops
         }
     }
 
-    sequence->positions = (float *)SDL_malloc(count * 12 * sizeof(*sequence->positions));
+    sequence->positions = (float *)SDL_malloc(count * 8 * sizeof(*sequence->positions));
     if (!sequence->positions) {
         DestroyDrawSequence(sequence);
         return NULL;
     }
 
+    sequence->indices = (int *)SDL_malloc(count * 12 * sizeof(*sequence->indices));
+    if (!sequence->indices) {
+        DestroyDrawSequence(sequence);
+        return NULL;
+    }
+
+    static const Uint8 rect_index_order[] = { 0, 1, 2, 0, 2, 3 };
+    int vertex_index = 0;
+    int *indices = sequence->indices;
+    for (int i = 0; i < count; ++i) {
+        *indices++ = vertex_index + rect_index_order[0];
+        *indices++ = vertex_index + rect_index_order[1];
+        *indices++ = vertex_index + rect_index_order[2];
+        *indices++ = vertex_index + rect_index_order[3];
+        *indices++ = vertex_index + rect_index_order[4];
+        *indices++ = vertex_index + rect_index_order[5];
+        vertex_index += 4;
+    }
+
     if (count < num_ops) {
         sequence->next = CreateDrawSequence(ops + count, num_ops - count);
         if (!sequence->next) {
@@ -817,19 +834,15 @@ bool TTF_DrawRendererText(TTF_Text *text, float x, float y)
             float maxx = x + dst->x + dst->w;
             float miny = y + dst->y;
             float maxy = y + dst->y + dst->h;
-            position[0] = minx;
-            position[1] = miny;
-            position[2] = maxx;
-            position[3] = miny;
-            position[4] = maxx;
-            position[5] = maxy;
-            position[6] = minx;
-            position[7] = miny;
-            position[8] = maxx;
-            position[9] = maxy;
-            position[10] = minx;
-            position[11] = maxy;
-            position += 12;
+
+            *position++ = minx;
+            *position++ = miny;
+            *position++ = maxx;
+            *position++ = miny;
+            *position++ = maxx;
+            *position++ = maxy;
+            *position++ = minx;
+            *position++ = maxy;
         }
 
         SDL_RenderGeometryRaw(renderer,
@@ -837,8 +850,8 @@ bool TTF_DrawRendererText(TTF_Text *text, float x, float y)
                               sequence->positions, 2 * sizeof(float),
                               &text->color, 0,
                               sequence->texcoords, 2 * sizeof(float),
-                              sequence->num_rects * 6,
-                              NULL, 0, 0);
+                              sequence->num_rects * 4,
+                              sequence->indices, sequence->num_rects * 6, sizeof(*sequence->indices));
 
         sequence = sequence->next;
     }