From e5a151a1f6891ba9fd850c5a75bc7eeb60737ede Mon Sep 17 00:00:00 2001
From: Dominic Masters <dominic@domsplace.com>
Date: Tue, 12 Dec 2023 13:40:50 -0600
Subject: [PATCH] Example of Rendering UI done.

---
 src/dawn/component/ui/UICanvas.cpp            | 64 +++++++-----
 src/dawn/component/ui/UICanvas.hpp            |  2 +
 src/dawn/display/mesh/QuadMesh.cpp            | 43 +++++++-
 src/dawn/display/mesh/QuadMesh.hpp            | 25 ++++-
 src/dawn/ui/UIComponent.cpp                   |  8 +-
 src/dawn/ui/UIComponent.hpp                   |  6 +-
 src/dawn/ui/UIQuad.hpp                        | 34 -------
 src/dawn/ui/UIRectangle.cpp                   | 15 ++-
 src/dawn/ui/UIRectangle.hpp                   |  2 +-
 src/dawn/util/Macro.hpp                       | 11 +++
 src/dawnhelloworld/scene/HelloWorldScene.cpp  |  6 ++
 src/dawnopengl/display/shader/Shader.hpp      |  2 +-
 .../display/shader/ShaderStructure.hpp        |  6 +-
 src/dawnopengl/display/shader/UIShader.cpp    | 98 ++++++++++++++-----
 src/dawnopengl/display/shader/UIShader.hpp    | 14 +--
 15 files changed, 218 insertions(+), 118 deletions(-)
 delete mode 100644 src/dawn/ui/UIQuad.hpp
 create mode 100644 src/dawn/util/Macro.hpp

diff --git a/src/dawn/component/ui/UICanvas.cpp b/src/dawn/component/ui/UICanvas.cpp
index 5dc6fe11..c6f18cf3 100644
--- a/src/dawn/component/ui/UICanvas.cpp
+++ b/src/dawn/component/ui/UICanvas.cpp
@@ -12,52 +12,66 @@
 using namespace Dawn;
 
 void UICanvas::onInit() {
-  
+  mesh = std::make_shared<Mesh>();
+  mesh->createBuffers(
+    QUAD_VERTICE_COUNT * UI_SHADER_QUAD_COUNT,
+    QUAD_INDICE_COUNT * UI_SHADER_QUAD_COUNT
+  );
+
+  for(int32_t i = 0; i < UI_SHADER_QUAD_COUNT; i++) {
+    QuadMesh::bufferWithIndex(
+      mesh,
+      glm::vec4(0, 0, 1, 1),
+      glm::vec4(0, 0, 1, 1),
+      i * QUAD_VERTICE_COUNT,
+      i * QUAD_INDICE_COUNT,
+      i * QUAD_VERTICE_COUNT
+    );
+  }
 }
 
 void UICanvas::onDispose() {
-
+  mesh = nullptr;
 }
 
 std::vector<std::shared_ptr<IRenderPass>> UICanvas::getPasses(
   struct RenderPassContext &ctx
 ) {
   std::vector<std::shared_ptr<IRenderPass>> passes;
-
-  auto selfTransform = this->getItem()->getWorldTransform();
-
-  auto mesh = std::make_shared<Mesh>();
-  mesh->createBuffers(QUAD_VERTICE_COUNT, QUAD_INDICE_COUNT);
-  QuadMesh::buffer(mesh, glm::vec4(0, 0, 32, 32), glm::vec4(0, 0, 1, 1), 0, 0);
+  std::unordered_map<shadertexturebinding_t, std::shared_ptr<Texture>> textures;
   UIShaderData data = {
     .projection = ctx.camera->getProjection(),
     .view = ctx.camera->getItem()->getWorldTransform(),
-    .model = selfTransform
+    .model = this->getItem()->getWorldTransform()
   };
   
-  data.test.first = COLOR_RED;
-  data.test.random = glm::vec3(0, 1, 0);
-  data.test.second = COLOR_BLUE;
-
-  auto pass = createRenderPass<UIShader, UIShaderData>(
-    std::ref(*this),
-    data,
-    std::unordered_map<shadertexturebinding_t, std::shared_ptr<Texture>>(),
-    mesh,
-    MeshDrawMode::TRIANGLES,
-    0, -1
-  );
-  passes.push_back(pass);
-
+  size_t quadCount = 0;
   auto itComponents = components.begin();
   while(itComponents != components.end()) {
     auto component = *itComponents;
 
     // Get this components' quads.
-    auto quads = component->getQuads(selfTransform);
-    
+    auto quads = component->getQuads(glm::mat4(1.0));
+    for(auto quad : quads) {
+      data.quads[quadCount++] = quad;
+      assertTrue(quadCount <= UI_SHADER_QUAD_COUNT, "Too many UI quads!");
+    }
     ++itComponents;
   }
 
+  // No render passes if no quads.
+  if(quadCount == 0) return passes;
+
+  auto pass = createRenderPass<UIShader, UIShaderData>(
+    std::ref(*this),
+    data,
+    textures,
+    mesh,
+    MeshDrawMode::TRIANGLES,
+    0, quadCount * QUAD_INDICE_COUNT
+  );
+  passes.push_back(pass);
+
+
   return passes;
 }
\ No newline at end of file
diff --git a/src/dawn/component/ui/UICanvas.hpp b/src/dawn/component/ui/UICanvas.hpp
index 1e75fa69..4c121715 100644
--- a/src/dawn/component/ui/UICanvas.hpp
+++ b/src/dawn/component/ui/UICanvas.hpp
@@ -14,6 +14,8 @@ namespace Dawn {
     public IRenderableComponent
   {
     protected:
+      std::shared_ptr<Mesh> mesh;
+
       virtual void onInit() override;
       virtual void onDispose() override;
 
diff --git a/src/dawn/display/mesh/QuadMesh.cpp b/src/dawn/display/mesh/QuadMesh.cpp
index 8fb6e0d4..c094c2e6 100644
--- a/src/dawn/display/mesh/QuadMesh.cpp
+++ b/src/dawn/display/mesh/QuadMesh.cpp
@@ -12,13 +12,46 @@ void QuadMesh::buffer(
   const glm::vec4 positions,
   const glm::vec4 coordinates,
   const int32_t verticeStart,
-  const int32_t indiceStart
+  const int32_t indiceStart,
+  const float_t depth
 ) {
   glm::vec3 vertices[QUAD_VERTICE_COUNT] = {
-    glm::vec3(positions.x, positions.y, 0),
-    glm::vec3(positions.z, positions.y, 0),
-    glm::vec3(positions.x, positions.w, 0),
-    glm::vec3(positions.z, positions.w, 0)
+    glm::vec3(positions.x, positions.y, depth),
+    glm::vec3(positions.z, positions.y, depth),
+    glm::vec3(positions.x, positions.w, depth),
+    glm::vec3(positions.z, positions.w, depth)
+  };
+
+  glm::vec2 coords[QUAD_VERTICE_COUNT] = {
+    glm::vec2(coordinates.x, coordinates.y),
+    glm::vec2(coordinates.z, coordinates.y),
+    glm::vec2(coordinates.x, coordinates.w),
+    glm::vec2(coordinates.z, coordinates.w)
+  };
+
+  int32_t indices[QUAD_INDICE_COUNT] = {
+    verticeStart, verticeStart + 1, verticeStart + 3,
+    verticeStart, verticeStart + 2, verticeStart + 3
+  };
+
+  mesh->bufferPositions(verticeStart, vertices, QUAD_VERTICE_COUNT);
+  mesh->bufferCoordinates(verticeStart, coords, QUAD_VERTICE_COUNT);
+  mesh->bufferIndices(indiceStart, indices, QUAD_INDICE_COUNT);
+}
+
+void QuadMesh::bufferWithIndex(
+  const std::shared_ptr<Mesh> mesh,
+  const glm::vec4 positions,
+  const glm::vec4 coordinates,
+  const int32_t verticeStart,
+  const int32_t indiceStart,
+  const int32_t indexOffset
+) {
+  glm::vec3 vertices[QUAD_VERTICE_COUNT] = {
+    glm::vec3(positions.x, positions.y, indexOffset),
+    glm::vec3(positions.z, positions.y, indexOffset + 1),
+    glm::vec3(positions.x, positions.w, indexOffset + 2),
+    glm::vec3(positions.z, positions.w, indexOffset + 3)
   };
 
   glm::vec2 coords[QUAD_VERTICE_COUNT] = {
diff --git a/src/dawn/display/mesh/QuadMesh.hpp b/src/dawn/display/mesh/QuadMesh.hpp
index bbe15ecb..009fcdad 100644
--- a/src/dawn/display/mesh/QuadMesh.hpp
+++ b/src/dawn/display/mesh/QuadMesh.hpp
@@ -20,13 +20,36 @@ namespace Dawn {
        * @param coordinates The coordinates of the vertices.
        * @param verticeStart The starting index of the vertices.
        * @param indiceStart The starting index of the indices.
+       * @param depth The depth of the vertices (Z coordinate).
        */
       static void buffer(
         const std::shared_ptr<Mesh> mesh,
         const glm::vec4 positions,
         const glm::vec4 coordinates,
         const int32_t verticeStart,
-        const int32_t indiceStart
+        const int32_t indiceStart,
+        const float_t depth = 0.0f
+      );
+
+      /**
+       * Buffers quad mesh vertices and indices into the given mesh. This will
+       * store the index of the vertice in the Z component, allowing you to find
+       * which vertex ID you are rendering in your shader.
+       * 
+       * @param mesh The mesh to buffer into.
+       * @param positions The positions of the vertices.
+       * @param coordinates The coordinates of the vertices.
+       * @param verticeStart The starting index of the vertices.
+       * @param indiceStart The starting index of the indices.
+       * @param indexOffset The offset to add to the index of each vertex.
+       */
+      static void bufferWithIndex(
+        const std::shared_ptr<Mesh> mesh,
+        const glm::vec4 positions,
+        const glm::vec4 coordinates,
+        const int32_t verticeStart,
+        const int32_t indiceStart,
+        const int32_t indexOffset = 0
       );
   };
 }
\ No newline at end of file
diff --git a/src/dawn/ui/UIComponent.cpp b/src/dawn/ui/UIComponent.cpp
index 9e3fc14d..2469e7cb 100644
--- a/src/dawn/ui/UIComponent.cpp
+++ b/src/dawn/ui/UIComponent.cpp
@@ -11,20 +11,20 @@ std::vector<std::shared_ptr<UIComponent>> UIComponent::getChildren() {
   return {};
 }
 
-std::vector<struct UIQuad> UIComponent::getQuads(
+std::vector<struct UIShaderQuad> UIComponent::getQuads(
   const glm::mat4 parent
 ) {
   // Get self transform
   glm::mat4 transform = glm::translate(
-    glm::mat4(1.0f), glm::vec3(position, 0.0f)
+    glm::mat4(1.0f),
+    glm::vec3(position, 0.0f)
   );
 
   // Add parent transform
   transform = parent * transform;
 
   // Get self quads and insert new transform.
-  std::vector<struct UIQuad> quads;
-  auto selfQuads = this->getSelfQuads(transform);
+  std::vector<struct UIShaderQuad> quads = this->getSelfQuads(transform);
 
   // Get children
   auto children = getChildren();
diff --git a/src/dawn/ui/UIComponent.hpp b/src/dawn/ui/UIComponent.hpp
index c4b86877..66a43de3 100644
--- a/src/dawn/ui/UIComponent.hpp
+++ b/src/dawn/ui/UIComponent.hpp
@@ -5,20 +5,20 @@
 
 #pragma once
 #include "ui/UIAlign.hpp"
-#include "ui/UIQuad.hpp"
+#include "display/shader/UIShader.hpp"
 
 namespace Dawn {
   class UICanvas;
 
   class UIComponent {
     protected:
-      virtual std::vector<struct UIQuad> getSelfQuads(
+      virtual std::vector<struct UIShaderQuad> getSelfQuads(
         const glm::mat4 transform
       ) = 0;
 
       virtual std::vector<std::shared_ptr<UIComponent>> getChildren();
 
-      std::vector<struct UIQuad> getQuads(
+      std::vector<struct UIShaderQuad> getQuads(
         const glm::mat4 parent
       );
 
diff --git a/src/dawn/ui/UIQuad.hpp b/src/dawn/ui/UIQuad.hpp
deleted file mode 100644
index 5b727609..00000000
--- a/src/dawn/ui/UIQuad.hpp
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2023 Dominic Masters
-// 
-// This software is released under the MIT License.
-// https://opensource.org/licenses/MIT
-
-#pragma once
-#include "display/Color.hpp"
-#include "display/Texture.hpp"
-
-namespace Dawn {
-  struct UIQuad {
-    glm::mat4 transform;
-    glm::vec4 quad;
-    glm::vec4 uv;
-    struct Color color;
-    std::shared_ptr<Texture> texture;
-
-    UIQuad(
-      const glm::mat4 transform,
-      const glm::vec4 quad,
-      const glm::vec4 uv,
-      const struct Color color,
-      const std::shared_ptr<Texture> texture
-    ) :
-      transform(transform),
-      quad(quad),
-      uv(uv),
-      color(color),
-      texture(texture)
-    {
-
-    }
-  };
-}
\ No newline at end of file
diff --git a/src/dawn/ui/UIRectangle.cpp b/src/dawn/ui/UIRectangle.cpp
index b4fa3e8b..9c25786d 100644
--- a/src/dawn/ui/UIRectangle.cpp
+++ b/src/dawn/ui/UIRectangle.cpp
@@ -7,18 +7,15 @@
 
 using namespace Dawn;
 
-std::vector<struct UIQuad> UIRectangle::getSelfQuads(
+std::vector<struct UIShaderQuad> UIRectangle::getSelfQuads(
   const glm::mat4 transform
 ) {
-  std::vector<struct UIQuad> quads;
-  
-  quads.push_back(UIQuad(
+  std::vector<struct UIShaderQuad> quads;
+  quads.push_back({
     transform,
-    glm::vec4(0,0,size.x,size.y),
+    glm::vec4(0, 0, size.x, size.y),
     uv,
-    color,
-    texture
-  ));
-
+    color
+  });
   return quads;
 }
\ No newline at end of file
diff --git a/src/dawn/ui/UIRectangle.hpp b/src/dawn/ui/UIRectangle.hpp
index 826bba31..3f6dbe21 100644
--- a/src/dawn/ui/UIRectangle.hpp
+++ b/src/dawn/ui/UIRectangle.hpp
@@ -9,7 +9,7 @@
 namespace Dawn {
   class UIRectangle final : public UIComponent {
     protected:
-      std::vector<struct UIQuad> getSelfQuads(
+      std::vector<struct UIShaderQuad> getSelfQuads(
         const glm::mat4 transform
       ) override;
 
diff --git a/src/dawn/util/Macro.hpp b/src/dawn/util/Macro.hpp
new file mode 100644
index 00000000..bcfb26e8
--- /dev/null
+++ b/src/dawn/util/Macro.hpp
@@ -0,0 +1,11 @@
+// Copyright (c) 2023 Dominic Masters
+// 
+// This software is released under the MIT License.
+// https://opensource.org/licenses/MIT
+
+#pragma once
+
+#define MACRO_STRINGIFY_RAW(x) #x
+#define MACRO_STRINGIFY(x) MACRO_STRINGIFY_RAW(x)
+
+#define MACRO_JOIN(x, y) x ## y
\ No newline at end of file
diff --git a/src/dawnhelloworld/scene/HelloWorldScene.cpp b/src/dawnhelloworld/scene/HelloWorldScene.cpp
index 87553782..fa0ac942 100644
--- a/src/dawnhelloworld/scene/HelloWorldScene.cpp
+++ b/src/dawnhelloworld/scene/HelloWorldScene.cpp
@@ -53,5 +53,11 @@ void Dawn::helloWorldScene(Scene &s) {
   auto uiCanvas = uiCanvasItem->addComponent<UICanvas>();
 
   auto rect = std::make_shared<UIRectangle>();
+  rect->position = { -32, -32 };
   uiCanvas->components.push_back(rect);
+
+  auto rect2 = std::make_shared<UIRectangle>();
+  rect2->color = COLOR_MAGENTA;
+  rect2->position = { 10, 10 };
+  uiCanvas->components.push_back(rect2);
 }
\ No newline at end of file
diff --git a/src/dawnopengl/display/shader/Shader.hpp b/src/dawnopengl/display/shader/Shader.hpp
index 28378a26..86109020 100644
--- a/src/dawnopengl/display/shader/Shader.hpp
+++ b/src/dawnopengl/display/shader/Shader.hpp
@@ -208,7 +208,7 @@ namespace Dawn {
               assertNoGLError();
               glBufferData(
                 GL_UNIFORM_BUFFER,
-                structure.size,
+                structure.size * structure.count,
                 (void*)((size_t)&this->data + (size_t)structure.offset),
                 GL_STATIC_DRAW
               );
diff --git a/src/dawnopengl/display/shader/ShaderStructure.hpp b/src/dawnopengl/display/shader/ShaderStructure.hpp
index 4cbc9048..dc672560 100644
--- a/src/dawnopengl/display/shader/ShaderStructure.hpp
+++ b/src/dawnopengl/display/shader/ShaderStructure.hpp
@@ -16,7 +16,7 @@ namespace Dawn {
     size_t offset;
     enum ShaderOpenGLStructureType structureType;
     size_t size;
-    // size_t count;
+    size_t count;
     std::vector<struct ShaderParameter> parameters;
     GLint location = -1;
     GLuint buffer = -1;
@@ -46,12 +46,14 @@ namespace Dawn {
         const enum ShaderOpenGLStructureType structureType,
         std::function<
           void(const T&, std::vector<struct ShaderParameter>&)
-        > getParameters
+        > getParameters,
+        size_t count = 1
       ) {
         this->structureName = structureName;
         this->offset = (size_t)offset;
         this->structureType = structureType;
         this->size = sizeof(T);
+        this->count = count;
         this->parameters = std::vector<struct ShaderParameter>();
 
         T dummy;
diff --git a/src/dawnopengl/display/shader/UIShader.cpp b/src/dawnopengl/display/shader/UIShader.cpp
index 34d2487b..f794439b 100644
--- a/src/dawnopengl/display/shader/UIShader.cpp
+++ b/src/dawnopengl/display/shader/UIShader.cpp
@@ -4,6 +4,7 @@
 // https://opensource.org/licenses/MIT
 
 #include "display/shader/UIShader.hpp"
+#include "util/Macro.hpp"
 
 using namespace Dawn;
 
@@ -28,10 +29,50 @@ void UIShader::getStages(
         "uniform mat4 u_Projection;\n"
         "uniform mat4 u_View;\n"
         "uniform mat4 u_Model;\n"
+        "struct UIShaderQuad {\n"
+          "mat4 transform;\n"
+          "vec4 quad;\n"
+          "vec4 uv;\n"
+          "vec4 color;\n"
+        "};\n"
+        "layout (std140) uniform ub_Quad {\n"
+          "UIShaderQuad quads[" MACRO_STRINGIFY(UI_SHADER_QUAD_COUNT) "];\n"
+        "};\n"
         "out vec2 o_TextCoord;\n"
+        "out vec4 v_Color;\n"
         "void main() {\n"
-          "gl_Position = u_Projection * u_View * u_Model * vec4(aPos, 1.0);\n"
-          "o_TextCoord = vec2(aTexCoord.x, aTexCoord.y);\n"
+          "vec4 pos;\n"
+          "vec2 coord;\n"
+          "int index = int(aPos.z);\n"
+          "int quadIndex = index / 4;\n"
+          "int vertexIndex = index % 4;\n"
+          "struct UIShaderQuad quad = quads[quadIndex];\n"
+          "if(vertexIndex == 0) {\n"
+            "pos.x = quad.quad.x;\n"
+            "pos.y = quad.quad.y;\n"
+            "coord.x = quad.uv.x;\n"
+            "coord.y = quad.uv.y;\n"
+          "} else if(vertexIndex == 1) {\n"
+            "pos.x = quad.quad.z;\n"
+            "pos.y = quad.quad.y;\n"
+            "coord.x = quad.uv.z;\n"
+            "coord.y = quad.uv.y;\n"
+          "} else if(vertexIndex == 2) {\n"
+            "pos.y = quad.quad.w;\n"
+            "pos.x = quad.quad.x;\n"
+            "coord.x = quad.uv.x;\n"
+            "coord.y = quad.uv.w;\n"
+          "} else if(vertexIndex == 3) {\n"
+            "pos.x = quad.quad.z;\n"
+            "pos.y = quad.quad.w;\n"
+            "coord.x = quad.uv.z;\n"
+            "coord.y = quad.uv.w;\n"
+          "}\n"
+          "pos.z = 0;\n"
+          "pos.w = 1;\n"
+          "gl_Position = u_Projection * u_View * u_Model * quad.transform * pos;\n"
+          "o_TextCoord = coord;\n"
+          "v_Color = quad.color;\n"
         "}"
       );
       
@@ -39,14 +80,10 @@ void UIShader::getStages(
         ShaderStageType::FRAGMENT,
         "#version 330 core\n"
         "in vec2 o_TextCoord;\n"
-        "layout (std140) uniform ub_Color {\n"
-          "vec4 first;\n"
-          "vec3 random;\n"
-          "vec4 second;\n"
-        "};\n"
+        "in vec4 v_Color;\n"
         "out vec4 o_Color;\n"
         "void main() {\n"
-          "o_Color = second;\n"
+          "o_Color = v_Color;\n"
         "}\n"
       );
       break;
@@ -78,28 +115,35 @@ void UIShader::getStages(
     ShaderParameterType::MAT4
   ));
   
-  structures.push_back(ShaderStructure<struct TestStruct>(
-    "ub_Color",
-    &rel->test,
+  structures.push_back(ShaderStructure<struct UIShaderQuad>(
+    "ub_Quad",
+    &rel->quads,
     ShaderOpenGLStructureType::STD140,
-    [&](const struct TestStruct &rel, std::vector<struct ShaderParameter> &parameters) {
+    [&](const struct UIShaderQuad &rel, std::vector<struct ShaderParameter> &parameters) {
       parameters.push_back(ShaderParameter(
-        "first",
-        &rel.first,
+        "u_Transform",
+        &rel.transform,
+        ShaderParameterType::MAT4
+      ));
+
+      parameters.push_back(ShaderParameter(
+        "u_Quad",
+        &rel.quad,
+        ShaderParameterType::VEC4
+      ));
+
+      parameters.push_back(ShaderParameter(
+        "u_UV",
+        &rel.uv,
+        ShaderParameterType::VEC4
+      ));
+
+      parameters.push_back(ShaderParameter(
+        "u_Color",
+        &rel.color,
         ShaderParameterType::COLOR
       ));
-      
-      parameters.push_back(ShaderParameter(
-        "random",
-        &rel.random,
-        ShaderParameterType::VEC3
-      ));
-      
-      parameters.push_back(ShaderParameter(
-        "second",
-        &rel.second,
-        ShaderParameterType::COLOR
-      ));
-    }
+    },
+    2
   ));
 }
\ No newline at end of file
diff --git a/src/dawnopengl/display/shader/UIShader.hpp b/src/dawnopengl/display/shader/UIShader.hpp
index f5f85e46..741d11d9 100644
--- a/src/dawnopengl/display/shader/UIShader.hpp
+++ b/src/dawnopengl/display/shader/UIShader.hpp
@@ -7,18 +7,20 @@
 #include "display/shader/Shader.hpp"
 
 namespace Dawn {
-  struct TestStruct {
-    struct Color first;
-    glm::vec3 random;
-    float_t padded;
-    struct Color second;
+  #define UI_SHADER_QUAD_COUNT 32
+
+  struct UIShaderQuad {
+    glm::mat4 transform;
+    glm::vec4 quad;
+    glm::vec4 uv;
+    struct Color color;
   };
   
   struct UIShaderData {
     glm::mat4 projection;
     glm::mat4 view;
     glm::mat4 model;
-    struct TestStruct test;
+    struct UIShaderQuad quads[UI_SHADER_QUAD_COUNT];
   };
 
   class UIShader : public Shader<UIShaderData> {