From a6767082a78e8b090fcce8c386fcbd359da8ecee Mon Sep 17 00:00:00 2001
From: 3gg <3gg@shellblade.net>
Date: Wed, 21 Jun 2023 08:56:34 -0700
Subject: Fix bug in Geometry that would over-allocate buffers.

---
 gfx/src/render/buffer.c   |  44 +++++------
 gfx/src/render/buffer.h   |   3 +
 gfx/src/render/geometry.c | 183 +++++++++++++++++++++++++---------------------
 3 files changed, 124 insertions(+), 106 deletions(-)

diff --git a/gfx/src/render/buffer.c b/gfx/src/render/buffer.c
index 3c0c794..55c68cc 100644
--- a/gfx/src/render/buffer.c
+++ b/gfx/src/render/buffer.c
@@ -8,24 +8,7 @@
 
 static size_t get_buffer_size_bytes(
     BufferType type, const BufferDataDesc* desc) {
-  switch (type) {
-  case BufferUntyped:
-    return desc->count;
-  case Buffer2d:
-    return desc->count * sizeof(vec2);
-  case Buffer3d:
-    return desc->count * sizeof(vec3);
-  case Buffer4d:
-    return desc->count * sizeof(vec4);
-  case BufferFloat:
-    return desc->count * sizeof(float);
-  case BufferU8:
-    return desc->count * sizeof(uint8_t);
-  case BufferU16:
-    return desc->count * sizeof(uint16_t);
-  }
-  assert(false);
-  return 0;
+  return desc->count * gfx_get_buffer_type_size_bytes(type);
 }
 
 static GLenum get_buffer_usage(BufferUsage usage) {
@@ -39,6 +22,27 @@ static GLenum get_buffer_usage(BufferUsage usage) {
   return GL_STATIC_DRAW;
 }
 
+size_t gfx_get_buffer_type_size_bytes(BufferType type) {
+  switch (type) {
+  case BufferUntyped:
+    return 1;
+  case Buffer2d:
+    return sizeof(vec2);
+  case Buffer3d:
+    return sizeof(vec3);
+  case Buffer4d:
+    return sizeof(vec4);
+  case BufferFloat:
+    return sizeof(float);
+  case BufferU8:
+    return sizeof(uint8_t);
+  case BufferU16:
+    return sizeof(uint16_t);
+  }
+  assert(false);
+  return 0;
+}
+
 bool gfx_init_buffer(Buffer* buffer, const BufferDesc* desc) {
   assert(buffer);
   buffer->type       = desc->type;
@@ -61,9 +65,7 @@ void gfx_del_buffer(Buffer* buffer) {
   }
 }
 
-void gfx_update_buffer(
-    RenderBackend* render_backend, Buffer* buffer, const BufferDataDesc* desc) {
-  assert(render_backend);
+void gfx_update_buffer(Buffer* buffer, const BufferDataDesc* desc) {
   assert(buffer);
   assert(desc);
   // OpenGL allows updating static buffers, but it is not optimal for
diff --git a/gfx/src/render/buffer.h b/gfx/src/render/buffer.h
index 0c81e7b..3adfd8e 100644
--- a/gfx/src/render/buffer.h
+++ b/gfx/src/render/buffer.h
@@ -16,6 +16,9 @@ typedef struct Buffer {
   size_t      size_bytes;
 } Buffer;
 
+/// Return the buffer type size in bytes.
+size_t gfx_get_buffer_type_size_bytes(BufferType);
+
 /// Create a buffer from raw data.
 bool gfx_init_buffer(Buffer*, const BufferDesc*);
 
diff --git a/gfx/src/render/geometry.c b/gfx/src/render/geometry.c
index e9d3ae5..44bfd04 100644
--- a/gfx/src/render/geometry.c
+++ b/gfx/src/render/geometry.c
@@ -26,21 +26,26 @@ static GLenum primitive_type_to_gl(PrimitiveType type) {
   }
 }
 
-/// Create a buffer for the buffer view if the view does not already point to
-/// a buffer.
-#define INIT_VIEW_BUFFER(render_backend, view, buffer_type, buffer_usage) \
-  if (!view.buffer) {                                                     \
-    view.buffer = (__typeof__(view.buffer))gfx_make_buffer(               \
-        render_backend, &(BufferDesc){                                    \
-                            .usage      = buffer_usage,                   \
-                            .type       = buffer_type,                    \
-                            .data.data  = view.data,                      \
-                            .data.count = view.size_bytes});              \
-  }                                                                       \
-  assert(view.size_bytes <= view.buffer->size_bytes);
+/// Create a typed buffer for the buffer view if the view does not already point
+/// to a buffer.
+void init_view_buffer(
+    RenderBackend* render_backend, BufferView* view, BufferType buffer_type,
+    BufferUsage buffer_usage) {
+  if (!view->buffer) {
+    view->buffer = gfx_make_buffer(
+        render_backend,
+        &(BufferDesc){
+            .usage      = buffer_usage,
+            .type       = buffer_type,
+            .data.data  = view->data,
+            .data.count = view->size_bytes /
+                          gfx_get_buffer_type_size_bytes(buffer_type)});
+  }
+  assert(view->size_bytes <= view->buffer->size_bytes);
+}
 
-/// Create a buffer for the view, then configure it in the VAO.
-static bool configure_buffer(
+/// Configure the buffer in teh VAO.
+static void configure_buffer(
     RenderBackend* render_backend, const GeometryDesc* desc, BufferView* view,
     size_t num_components, size_t component_size_bytes, GLenum component_type,
     GLboolean normalized, GLuint channel) {
@@ -70,8 +75,6 @@ static bool configure_buffer(
         (const void*)view->offset_bytes);
   }
   glBindBuffer(GL_ARRAY_BUFFER, 0);
-
-  return true;
 }
 
 static bool configure_vertex_attributes(
@@ -80,105 +83,113 @@ static bool configure_vertex_attributes(
   assert(desc);
 
   if (view_is_populated(desc->positions3d)) {
-    INIT_VIEW_BUFFER(
-        render_backend, desc->positions3d, Buffer3d, desc->buffer_usage);
-    if (!desc->positions3d.buffer ||
-        !configure_buffer(
-            render_backend, desc, (BufferView*)&desc->positions3d, 3,
-            sizeof(float), GL_FLOAT, GL_FALSE, GFX_POSITION_CHANNEL)) {
+    init_view_buffer(
+        render_backend, (BufferView*)&desc->positions3d, Buffer3d,
+        desc->buffer_usage);
+    if (!desc->positions3d.buffer) {
       return false;
     }
+    configure_buffer(
+        render_backend, desc, (BufferView*)&desc->positions3d, 3, sizeof(float),
+        GL_FLOAT, GL_FALSE, GFX_POSITION_CHANNEL);
   } else if (view_is_populated(desc->positions2d)) {
-    INIT_VIEW_BUFFER(
-        render_backend, desc->positions2d, Buffer2d, desc->buffer_usage);
-    if (!desc->positions2d.buffer ||
-        !configure_buffer(
-            render_backend, desc, (BufferView*)&desc->positions2d, 2,
-            sizeof(float), GL_FLOAT, GL_FALSE, GFX_POSITION_CHANNEL)) {
+    init_view_buffer(
+        render_backend, (BufferView*)&desc->positions2d, Buffer2d,
+        desc->buffer_usage);
+    if (!desc->positions2d.buffer) {
       return false;
     }
+    configure_buffer(
+        render_backend, desc, (BufferView*)&desc->positions2d, 2, sizeof(float),
+        GL_FLOAT, GL_FALSE, GFX_POSITION_CHANNEL);
   }
   if (view_is_populated(desc->normals)) {
-    INIT_VIEW_BUFFER(
-        render_backend, desc->normals, Buffer3d, desc->buffer_usage);
-    if (!desc->normals.buffer ||
-        !configure_buffer(
-            render_backend, desc, (BufferView*)&desc->normals, 3, sizeof(float),
-            GL_FLOAT, GL_FALSE, GFX_NORMAL_CHANNEL)) {
+    init_view_buffer(
+        render_backend, (BufferView*)&desc->normals, Buffer3d,
+        desc->buffer_usage);
+    if (!desc->normals.buffer) {
       return false;
     }
+    configure_buffer(
+        render_backend, desc, (BufferView*)&desc->normals, 3, sizeof(float),
+        GL_FLOAT, GL_FALSE, GFX_NORMAL_CHANNEL);
   }
   if (view_is_populated(desc->tangents)) {
-    INIT_VIEW_BUFFER(
-        render_backend, desc->tangents, Buffer4d, desc->buffer_usage);
-    if (!desc->tangents.buffer ||
-        !configure_buffer(
-            render_backend, desc, (BufferView*)&desc->tangents, 4,
-            sizeof(float), GL_FLOAT, GL_FALSE, GFX_TANGENT_CHANNEL)) {
+    init_view_buffer(
+        render_backend, (BufferView*)&desc->tangents, Buffer4d,
+        desc->buffer_usage);
+    if (!desc->tangents.buffer) {
       return false;
     }
+    configure_buffer(
+        render_backend, desc, (BufferView*)&desc->tangents, 4, sizeof(float),
+        GL_FLOAT, GL_FALSE, GFX_TANGENT_CHANNEL);
   }
   if (view_is_populated(desc->texcoords)) {
-    INIT_VIEW_BUFFER(
-        render_backend, desc->texcoords, Buffer2d, desc->buffer_usage);
-    if (!desc->texcoords.buffer ||
-        !configure_buffer(
-            render_backend, desc, (BufferView*)&desc->texcoords, 2,
-            sizeof(float), GL_FLOAT, GL_FALSE, GFX_TEXCOORDS_CHANNEL)) {
+    init_view_buffer(
+        render_backend, (BufferView*)&desc->texcoords, Buffer2d,
+        desc->buffer_usage);
+    if (!desc->texcoords.buffer) {
       return false;
     }
+    configure_buffer(
+        render_backend, desc, (BufferView*)&desc->texcoords, 2, sizeof(float),
+        GL_FLOAT, GL_FALSE, GFX_TEXCOORDS_CHANNEL);
   }
   if (view_is_populated(desc->joints.u8)) {
-    INIT_VIEW_BUFFER(
-        render_backend, desc->joints.u8, BufferU8, desc->buffer_usage);
-    if (!desc->joints.u8.buffer ||
-        !configure_buffer(
-            render_backend, desc, (BufferView*)&desc->joints.u8, 4,
-            sizeof(uint8_t), GL_UNSIGNED_BYTE, GL_FALSE, GFX_JOINTS_CHANNEL)) {
+    init_view_buffer(
+        render_backend, (BufferView*)&desc->joints.u8, BufferU8,
+        desc->buffer_usage);
+    if (!desc->joints.u8.buffer) {
       return false;
     }
+    configure_buffer(
+        render_backend, desc, (BufferView*)&desc->joints.u8, 4, sizeof(uint8_t),
+        GL_UNSIGNED_BYTE, GL_FALSE, GFX_JOINTS_CHANNEL);
   } else if (view_is_populated(desc->joints.u16)) {
-    INIT_VIEW_BUFFER(
-        render_backend, desc->joints.u16, BufferU16, desc->buffer_usage);
-    if (!desc->joints.u16.buffer ||
-        !configure_buffer(
-            render_backend, desc, (BufferView*)&desc->joints.u16, 4,
-            sizeof(uint16_t), GL_UNSIGNED_SHORT, GL_FALSE,
-            GFX_JOINTS_CHANNEL)) {
+    init_view_buffer(
+        render_backend, (BufferView*)&desc->joints.u16, BufferU16,
+        desc->buffer_usage);
+    if (!desc->joints.u16.buffer) {
       return false;
     }
+    configure_buffer(
+        render_backend, desc, (BufferView*)&desc->joints.u16, 4,
+        sizeof(uint16_t), GL_UNSIGNED_SHORT, GL_FALSE, GFX_JOINTS_CHANNEL);
   }
 
-  // If weights are given as unsigned integers, then they are normalized when
-  // read by the shader.
+  // If weights are given as unsigned integers, then they are normalized
+  // when read by the shader.
   if (view_is_populated(desc->weights.u8)) {
-    INIT_VIEW_BUFFER(
-        render_backend, desc->weights.u8, BufferU8, desc->buffer_usage);
-    if (!desc->weights.u8.buffer ||
-        !configure_buffer(
-            render_backend, desc, (BufferView*)&desc->weights.u8, 4,
-            sizeof(uint8_t), GL_UNSIGNED_BYTE, GL_TRUE, GFX_WEIGHTS_CHANNEL)) {
+    init_view_buffer(
+        render_backend, (BufferView*)&desc->weights.u8, BufferU8,
+        desc->buffer_usage);
+    if (!desc->weights.u8.buffer) {
       return false;
     }
+    configure_buffer(
+        render_backend, desc, (BufferView*)&desc->weights.u8, 4,
+        sizeof(uint8_t), GL_UNSIGNED_BYTE, GL_TRUE, GFX_WEIGHTS_CHANNEL);
   } else if (view_is_populated(desc->weights.u16)) {
-    INIT_VIEW_BUFFER(
-        render_backend, desc->weights.u16, BufferU16, desc->buffer_usage);
-    if (!desc->weights.u16.buffer ||
-        !configure_buffer(
-            render_backend, desc, (BufferView*)&desc->weights.u16, 4,
-            sizeof(uint16_t), GL_UNSIGNED_SHORT, GL_TRUE,
-            GFX_WEIGHTS_CHANNEL)) {
+    init_view_buffer(
+        render_backend, (BufferView*)&desc->weights.u16, BufferU16,
+        desc->buffer_usage);
+    if (!desc->weights.u16.buffer) {
       return false;
     }
+    configure_buffer(
+        render_backend, desc, (BufferView*)&desc->weights.u16, 4,
+        sizeof(uint16_t), GL_UNSIGNED_SHORT, GL_TRUE, GFX_WEIGHTS_CHANNEL);
   } else if (view_is_populated(desc->weights.floats)) {
-    INIT_VIEW_BUFFER(
-        render_backend, desc->weights.floats, BufferFloat, desc->buffer_usage);
-    if (!desc->weights.floats.buffer ||
-        !configure_buffer(
-            render_backend, desc, (BufferView*)&desc->weights.floats, 4,
-            sizeof(float), GL_FLOAT, GL_FALSE, GFX_WEIGHTS_CHANNEL)) {
+    init_view_buffer(
+        render_backend, (BufferView*)&desc->weights.floats, BufferFloat,
+        desc->buffer_usage);
+    if (!desc->weights.floats.buffer) {
       return false;
     }
+    configure_buffer(
+        render_backend, desc, (BufferView*)&desc->weights.floats, 4,
+        sizeof(float), GL_FLOAT, GL_FALSE, GFX_WEIGHTS_CHANNEL);
   }
 
   return true;
@@ -193,8 +204,9 @@ static bool configure_indices(
     assert(desc->num_indices > 0);
     assert(
         desc->num_indices <= desc->indices8.size_bytes / sizeof(VertexIndex8));
-    INIT_VIEW_BUFFER(
-        render_backend, desc->indices8, BufferU8, desc->buffer_usage);
+    init_view_buffer(
+        render_backend, (BufferView*)&desc->indices8, BufferU8,
+        desc->buffer_usage);
     if (!desc->indices8.buffer) {
       return false;
     }
@@ -203,8 +215,9 @@ static bool configure_indices(
     assert(
         desc->num_indices <=
         desc->indices16.size_bytes / sizeof(VertexIndex16));
-    INIT_VIEW_BUFFER(
-        render_backend, desc->indices16, BufferU16, desc->buffer_usage);
+    init_view_buffer(
+        render_backend, (BufferView*)&desc->indices16, BufferU16,
+        desc->buffer_usage);
     if (!desc->indices16.buffer) {
       return false;
     }
@@ -280,7 +293,7 @@ void gfx_update_geometry(Geometry* geometry, const GeometryDesc* desc) {
     // The geometry must already have an underlying GPU buffer.
     assert(geometry->desc.positions3d.buffer);
     gfx_update_buffer(
-        geometry->render_backend, geometry->desc.positions3d.buffer,
+        geometry->desc.positions3d.buffer,
         &(BufferDataDesc){
             .vec3s = desc->positions3d.data,
             .count = desc->positions3d.size_bytes / sizeof(vec3)});
-- 
cgit v1.2.3