SDL: DirectFB: add partial support for RenderGeometry

From 83d600904b63d4ae7f7f6176cf978d31a53f3f55 Mon Sep 17 00:00:00 2001
From: Sylvain <[EMAIL REDACTED]>
Date: Thu, 30 Sep 2021 23:47:37 +0200
Subject: [PATCH] DirectFB: add partial support for RenderGeometry allow to
 fill triangles with color or texture but only uniform vertex color is handled
 (not per vertex color)

---
 src/video/directfb/SDL_DirectFB_render.c | 197 +++++++++++++++++++++++
 1 file changed, 197 insertions(+)

diff --git a/src/video/directfb/SDL_DirectFB_render.c b/src/video/directfb/SDL_DirectFB_render.c
index 744779a171..90adccb385 100644
--- a/src/video/directfb/SDL_DirectFB_render.c
+++ b/src/video/directfb/SDL_DirectFB_render.c
@@ -615,6 +615,64 @@ DirectFB_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const
     return 0;
 }
 
+static int
+DirectFB_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture,
+        const float *xy, int xy_stride, const int *color, int color_stride, const float *uv, int uv_stride,
+        int num_vertices, const void *indices, int num_indices, int size_indices,
+        float scale_x, float scale_y)
+{
+    DirectFB_TextureData *texturedata = NULL;
+    int i;
+    int count = indices ? num_indices : num_vertices;
+    float *verts;
+    int sz = 2 + 4 + (texture ? 2 : 0);
+
+    verts = (float *) SDL_AllocateRenderVertices(renderer, count * sz * sizeof (float), 0, &cmd->data.draw.first);
+    if (!verts) {
+        return -1;
+    }
+
+    if (texture) {
+        texturedata = (DirectFB_TextureData *) texture->driverdata;
+    }
+
+    cmd->data.draw.count = count;
+    size_indices = indices ? size_indices : 0;
+
+    for (i = 0; i < count; i++) {
+        int j;
+        float *xy_;
+        SDL_Color col_;
+        if (size_indices == 4) {
+            j = ((const Uint32 *)indices)[i];
+        } else if (size_indices == 2) {
+            j = ((const Uint16 *)indices)[i];
+        } else if (size_indices == 1) {
+            j = ((const Uint8 *)indices)[i];
+        } else {
+            j = i;
+        }
+
+        xy_ = (float *)((char*)xy + j * xy_stride);
+        col_ = *(SDL_Color *)((char*)color + j * color_stride);
+
+        *(verts++) = xy_[0] * scale_x;
+        *(verts++) = xy_[1] * scale_y;
+
+        *(verts++) = col_.r;
+        *(verts++) = col_.g;
+        *(verts++) = col_.b;
+        *(verts++) = col_.a;
+
+        if (texture) {
+            float *uv_ = (float *)((char*)uv + j * uv_stride);
+            *(verts++) = uv_[0];
+            *(verts++) = uv_[1];
+        }
+    }
+    return 0;
+}
+
 static int
 DirectFB_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
 {
@@ -814,6 +872,144 @@ DirectFB_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *
                 break;
             }
 
+
+            case SDL_RENDERCMD_GEOMETRY: {
+                const float *verts = (float *) (((Uint8 *) vertices) + cmd->data.draw.first);
+                SDL_Texture *texture = cmd->data.draw.texture;
+                const size_t count = cmd->data.draw.count;
+
+                Uint8 save_r = cmd->data.draw.r;
+                Uint8 save_g = cmd->data.draw.g;
+                Uint8 save_b = cmd->data.draw.b;
+                Uint8 save_a = cmd->data.draw.a;
+
+                int j;
+                for (j = 0; j < count; j += 3)
+                {
+                    float x1, y1, r1, g1, b1, a1, u1, v1;
+                    float x2, y2, r2, g2, b2, a2, u2, v2;
+                    float x3, y3, r3, g3, b3, a3, u3, v3;
+
+                    x1 = *(verts++);
+                    y1 = *(verts++);
+                    r1 = *(verts++);
+                    g1 = *(verts++);
+                    b1 = *(verts++);
+                    a1 = *(verts++);
+                    if (texture) {
+                        u1 = *(verts++);
+                        v1 = *(verts++);
+                    }
+                    x2 = *(verts++);
+                    y2 = *(verts++);
+                    r2 = *(verts++);
+                    g2 = *(verts++);
+                    b2 = *(verts++);
+                    a2 = *(verts++);
+                    if (texture) {
+                        u2 = *(verts++);
+                        v2 = *(verts++);
+                    }
+                    x3 = *(verts++);
+                    y3 = *(verts++);
+                    r3 = *(verts++);
+                    g3 = *(verts++);
+                    b3 = *(verts++);
+                    a3 = *(verts++);
+                    if (texture) {
+                        u3 = *(verts++);
+                        v3 = *(verts++);
+                    }
+
+
+                    if (texture) {
+                        DFBVertex vertices[3];
+
+                        DirectFB_TextureData *texturedata = (DirectFB_TextureData *) texture->driverdata;
+
+                        DFBSurfaceBlittingFlags flags = 0;
+
+                        int r = (r1 + r2 + r3) / 3;
+                        int g = (g1 + g2 + g3) / 3;
+                        int b = (b1 + b2 + b3) / 3;
+                        int a = (a1 + a2 + a3) / 3;
+
+
+                        if (texturedata->isDirty) {
+                            const SDL_Rect rect = { 0, 0, texture->w, texture->h };
+                            DirectFB_UpdateTexture(renderer, texture, &rect, texturedata->pixels, texturedata->pitch);
+                        }
+
+                        if (a != 0xFF) {
+                            flags |= DSBLIT_BLEND_COLORALPHA;
+                        }
+
+                        if ((r & g & b) != 0xFF) {
+                            flags |= DSBLIT_COLORIZE;
+                        }
+
+                        destsurf->SetColor(destsurf, r, g, b, a);
+
+                        /* ???? flags |= DSBLIT_SRC_PREMULTCOLOR; */
+
+                        SetBlendMode(data, texture->blendMode, texturedata);
+
+                        destsurf->SetBlittingFlags(destsurf, data->blitFlags | flags);
+
+#if (DFB_VERSION_ATLEAST(1,2,0))
+                        destsurf->SetRenderOptions(destsurf, texturedata->render_options);
+#endif
+
+                        vertices[0].x = x1;
+                        vertices[0].y = y1;
+                        vertices[0].z = 0;
+                        vertices[0].w = 0;
+                        vertices[0].s = u1;
+                        vertices[0].t = v1;
+
+                        vertices[1].x = x2;
+                        vertices[1].y = y2;
+                        vertices[1].z = 0;
+                        vertices[1].w = 0;
+                        vertices[1].s = u2;
+                        vertices[1].t = v2;
+
+                        vertices[2].x = x3;
+                        vertices[2].y = y3;
+                        vertices[2].z = 0;
+                        vertices[2].w = 0;
+                        vertices[2].s = u3;
+                        vertices[2].t = v3;
+
+                        destsurf->TextureTriangles(destsurf, texturedata->surface, vertices, NULL, 3, DTTF_LIST);
+                    } else {
+                        DFBTriangle tris;
+                        tris.x1 = x1;
+                        tris.y1 = y1;
+                        tris.x2 = x2;
+                        tris.y2 = y2;
+                        tris.x3 = x3;
+                        tris.y3 = y3;
+
+                        cmd->data.draw.r = (r1 + r2 + r3) / 3;
+                        cmd->data.draw.g = (g1 + g2 + g3) / 3;
+                        cmd->data.draw.b = (b1 + b2 + b3) / 3;
+                        cmd->data.draw.a = (a1 + a2 + a3) / 3;
+
+                        PrepareDraw(renderer, cmd);
+
+                        destsurf->FillTriangles(destsurf, &tris, 1);
+                    }
+                }
+
+                cmd->data.draw.r = save_r;
+                cmd->data.draw.g = save_g;
+                cmd->data.draw.b = save_b;
+                cmd->data.draw.a = save_a;
+                break;
+            }
+
+
             case SDL_RENDERCMD_COPY_EX:
                 break;  /* unsupported */
 
@@ -984,6 +1180,7 @@ DirectFB_CreateRenderer(SDL_Window * window, Uint32 flags)
     renderer->QueueSetDrawColor = DirectFB_QueueSetViewport;  /* SetViewport and SetDrawColor are (currently) no-ops. */
     renderer->QueueDrawPoints = DirectFB_QueueDrawPoints;
     renderer->QueueDrawLines = DirectFB_QueueDrawPoints;  /* lines and points queue vertices the same way. */
+    renderer->QueueGeometry = DirectFB_QueueGeometry;
     renderer->QueueFillRects = DirectFB_QueueFillRects;
     renderer->QueueCopy = DirectFB_QueueCopy;
     renderer->QueueCopyEx = DirectFB_QueueCopyEx;