summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2023-02-25 11:07:02 -0800
committer3gg <3gg@shellblade.net>2023-02-25 11:07:02 -0800
commitf815866f62e0f6a371c0e1cb4a385b41bcffd1ce (patch)
tree1d79245a1fdc8714eb3bc41ede47bd4973ab4220
parent9a22d4eb956e6eadc488fa3f4c336a0b2b2dda55 (diff)
Simplify buffer creation, add support for dynamic geometry.
-rw-r--r--gfx/include/gfx/render_backend.h73
-rw-r--r--gfx/src/render/buffer.c49
-rw-r--r--gfx/src/render/buffer.h13
-rw-r--r--gfx/src/render/geometry.c214
-rw-r--r--gfx/src/render/geometry.h20
-rw-r--r--gfx/src/render/render_backend.c36
-rw-r--r--gfx/src/util/geometry.c22
-rw-r--r--gfx/src/util/scene.c15
8 files changed, 244 insertions, 198 deletions
diff --git a/gfx/include/gfx/render_backend.h b/gfx/include/gfx/render_backend.h
index 785c4b9..ef6e4e9 100644
--- a/gfx/include/gfx/render_backend.h
+++ b/gfx/include/gfx/render_backend.h
@@ -38,6 +38,44 @@ typedef enum PrimitiveType {
38 TriangleStrip 38 TriangleStrip
39} PrimitiveType; 39} PrimitiveType;
40 40
41/// Buffer usage.
42typedef enum BufferUsage { BufferStatic, BufferDynamic } BufferUsage;
43
44/// Buffer type.
45typedef enum BufferType {
46 BufferUntyped,
47 Buffer2d,
48 Buffer3d,
49 Buffer4d,
50 BufferU8,
51 BufferU16
52} BufferType;
53
54/// Buffer descriptor.
55///
56/// 'count' is the number of elements in the array. For untyped buffers, this is
57/// the size in bytes of the 'data' array. For other types, it is the number of
58/// vec2s, vec3s, etc. in the corresponding array.
59///
60/// The data pointers can also be null. In such a case, a buffer of the given
61/// size is created with its contents uninitialized.
62///
63/// TODO: Think about typed buffers (Buffer, Buffer2d, Buffer3d, BufferU8, etc).
64/// Typed buffers don't work well with interleaved vertex attributes. Not sure
65/// this is really worth it.
66typedef struct BufferDesc {
67 BufferUsage usage;
68 BufferType type;
69 union {
70 const void* data;
71 const vec2* vec2s;
72 const vec3* vec3s;
73 const uint8_t* u8s;
74 const uint16_t* u16s;
75 };
76 size_t count;
77} BufferDesc;
78
41/// A buffer view for vertex data (attributes or indices). 79/// A buffer view for vertex data (attributes or indices).
42/// Either 'data' or 'buffer' must be set. 80/// Either 'data' or 'buffer' must be set.
43#define MAKE_BUFFER_VIEW(NAME, TYPE) \ 81#define MAKE_BUFFER_VIEW(NAME, TYPE) \
@@ -78,8 +116,8 @@ MAKE_BUFFER_VIEW(BufferViewIdx16, uint16_t)
78 116
79/// Describes a piece of geometry. 117/// Describes a piece of geometry.
80/// 118///
81/// Currently we support only 16-bit vertex indices. Might have to change this 119/// Currently we support only up to 16-bit vertex indices. Might have to change
82/// to support a larger variety of 3D models. 120/// this to support a larger variety of 3D models.
83typedef struct GeometryDesc { 121typedef struct GeometryDesc {
84 BufferView2d positions2d; 122 BufferView2d positions2d;
85 BufferView3d positions3d; 123 BufferView3d positions3d;
@@ -265,22 +303,7 @@ void gfx_get_viewport(RenderBackend*, int* width, int* height);
265// ----------------------------------------------------------------------------- 303// -----------------------------------------------------------------------------
266 304
267/// Create a buffer from raw data. 305/// Create a buffer from raw data.
268Buffer* gfx_make_buffer(RenderBackend*, const void*, size_t size_bytes); 306Buffer* gfx_make_buffer(RenderBackend*, const BufferDesc*);
269
270/// Create a buffer from 2D vertices.
271Buffer* gfx_make_buffer2d(RenderBackend*, const vec2* verts, size_t count);
272
273/// Create a buffer from 3D vertices.
274Buffer* gfx_make_buffer3d(RenderBackend*, const vec3* verts, size_t count);
275
276/// Create a buffer from 4D vertices.
277Buffer* gfx_make_buffer4d(RenderBackend*, const vec4* verts, size_t count);
278
279/// Create a buffer from 8-bit unsigned integers.
280Buffer* gfx_make_bufferu8(RenderBackend*, const uint8_t* vals, size_t count);
281
282/// Create a buffer from 16-bit unsigned integers.
283Buffer* gfx_make_bufferu16(RenderBackend*, const uint16_t* vals, size_t count);
284 307
285/// Destroy the buffer. 308/// Destroy the buffer.
286void gfx_destroy_buffer(RenderBackend*, Buffer**); 309void gfx_destroy_buffer(RenderBackend*, Buffer**);
@@ -295,6 +318,20 @@ Geometry* gfx_make_geometry(RenderBackend*, const GeometryDesc*);
295/// Destroy the geometry. 318/// Destroy the geometry.
296void gfx_destroy_geometry(RenderBackend*, Geometry**); 319void gfx_destroy_geometry(RenderBackend*, Geometry**);
297 320
321/// Upload new vertex data for the geometry.
322///
323/// This is similar to gfx_make_geometry(), but the geometry need not be
324/// entirely specified. Only the vertex attributes set in the descriptor are
325/// updated.
326///
327/// This function only updates vertex attributes, not indices or primitive type.
328///
329/// Note that the descriptor cannot specify more vertex attributes than the
330/// geometry was created with. If the size or any other attribute not handled
331/// by this update function needs to be changed, then a new geometry must be
332/// created.
333void gfx_update_geometry(Geometry*, const GeometryDesc*);
334
298/// Render the geometry. 335/// Render the geometry.
299void gfx_render_geometry(const Geometry*); 336void gfx_render_geometry(const Geometry*);
300 337
diff --git a/gfx/src/render/buffer.c b/gfx/src/render/buffer.c
index 3536dcb..392777c 100644
--- a/gfx/src/render/buffer.c
+++ b/gfx/src/render/buffer.c
@@ -1,32 +1,51 @@
1#include "buffer.h" 1#include "buffer.h"
2 2
3#include <gfx/render_backend.h>
4
3#include <math/vec2.h> 5#include <math/vec2.h>
4#include <math/vec3.h> 6#include <math/vec3.h>
5#include <math/vec4.h> 7#include <math/vec4.h>
6 8
7bool gfx_init_buffer(Buffer* buffer, const void* data, size_t size_bytes) { 9static size_t get_buffer_size_bytes(const BufferDesc* desc) {
10 switch (desc->type) {
11 case BufferUntyped:
12 return desc->count;
13 case Buffer2d:
14 return desc->count * sizeof(vec2);
15 case Buffer3d:
16 return desc->count * sizeof(vec3);
17 case Buffer4d:
18 return desc->count * sizeof(vec4);
19 case BufferU8:
20 return desc->count * sizeof(uint8_t);
21 case BufferU16:
22 return desc->count * sizeof(uint16_t);
23 }
24}
25
26static GLenum get_buffer_usage(BufferUsage usage) {
27 switch (usage) {
28 case BufferStatic:
29 return GL_STATIC_DRAW;
30 case BufferDynamic:
31 return GL_DYNAMIC_DRAW;
32 }
33 assert(false);
34 return GL_STATIC_DRAW;
35}
36
37bool gfx_init_buffer(Buffer* buffer, const BufferDesc* desc) {
8 assert(buffer); 38 assert(buffer);
9 buffer->size_bytes = size_bytes; 39 buffer->size_bytes = get_buffer_size_bytes(desc);
40 const GLenum usage = get_buffer_usage(desc->usage);
10 glGenBuffers(1, &buffer->vbo); 41 glGenBuffers(1, &buffer->vbo);
11 glBindBuffer(GL_ARRAY_BUFFER, buffer->vbo); 42 glBindBuffer(GL_ARRAY_BUFFER, buffer->vbo);
12 glBufferData(GL_ARRAY_BUFFER, size_bytes, data, GL_STATIC_DRAW); 43 glBufferData(GL_ARRAY_BUFFER, buffer->size_bytes, desc->data, usage);
13 glBindBuffer(GL_ARRAY_BUFFER, 0); 44 glBindBuffer(GL_ARRAY_BUFFER, 0);
14 ASSERT_GL; 45 ASSERT_GL;
15 return true; 46 return true;
16} 47}
17 48
18bool gfx_init_buffer_2d(Buffer* buffer, const vec2* verts, size_t count) {
19 return gfx_init_buffer(buffer, (const void*)verts, count * sizeof(vec2));
20}
21
22bool gfx_init_buffer_3d(Buffer* buffer, const vec3* verts, size_t count) {
23 return gfx_init_buffer(buffer, (const void*)verts, count * sizeof(vec3));
24}
25
26bool gfx_init_buffer_4d(Buffer* buffer, const vec4* verts, size_t count) {
27 return gfx_init_buffer(buffer, (const void*)verts, count * sizeof(vec4));
28}
29
30void gfx_del_buffer(Buffer* buffer) { 49void gfx_del_buffer(Buffer* buffer) {
31 assert(buffer); 50 assert(buffer);
32 if (buffer->vbo) { 51 if (buffer->vbo) {
diff --git a/gfx/src/render/buffer.h b/gfx/src/render/buffer.h
index 5cff53a..575fbb9 100644
--- a/gfx/src/render/buffer.h
+++ b/gfx/src/render/buffer.h
@@ -7,22 +7,15 @@
7#include <stdbool.h> 7#include <stdbool.h>
8#include <stddef.h> 8#include <stddef.h>
9 9
10typedef struct BufferDesc BufferDesc;
11
10typedef struct Buffer { 12typedef struct Buffer {
11 GLuint vbo; 13 GLuint vbo;
12 size_t size_bytes; 14 size_t size_bytes;
13} Buffer; 15} Buffer;
14 16
15/// Create a buffer from raw data. 17/// Create a buffer from raw data.
16bool gfx_init_buffer(Buffer*, const void* data, size_t size_bytes); 18bool gfx_init_buffer(Buffer*, const BufferDesc*);
17
18/// Create a buffer from 2D vertices.
19bool gfx_init_buffer_2d(Buffer*, const vec2* verts, size_t count);
20
21/// Create a buffer from 3D vertices.
22bool gfx_init_buffer_3d(Buffer*, const vec3* verts, size_t count);
23
24/// Create a buffer from 4D vertices.
25bool gfx_init_buffer_4d(Buffer*, const vec4* verts, size_t count);
26 19
27/// Destroy the buffer. 20/// Destroy the buffer.
28void gfx_del_buffer(Buffer*); 21void gfx_del_buffer(Buffer*);
diff --git a/gfx/src/render/geometry.c b/gfx/src/render/geometry.c
index 7f3fc46..076a956 100644
--- a/gfx/src/render/geometry.c
+++ b/gfx/src/render/geometry.c
@@ -25,35 +25,38 @@ static GLenum primitive_type_to_gl(PrimitiveType type) {
25/// Create a buffer for the view. 25/// Create a buffer for the view.
26/// 26///
27/// If the view already has a buffer, return the buffer. Otherwise create a 27/// If the view already has a buffer, return the buffer. Otherwise create a
28/// buffer from the view's data. 28/// buffer from the view's data and assign it to the view.
29static const Buffer* get_or_make_buffer( 29static const Buffer* get_or_make_view_buffer(
30 RenderBackend* render_backend, const BufferView* view) { 30 RenderBackend* render_backend, BufferView* view) {
31 if (view->buffer) { 31 if (view->buffer) {
32 return view->buffer; 32 return view->buffer;
33 } else { 33 } else {
34 return gfx_make_buffer(render_backend, view->data, view->size_bytes); 34 return view->buffer = gfx_make_buffer(
35 render_backend, &(BufferDesc){
36 .usage = BufferStatic,
37 .type = BufferUntyped,
38 .data = view->data,
39 .count = view->size_bytes});
35 } 40 }
36} 41}
37 42
38/// Create a buffer for the view, then configure it in the VAO. 43/// Create a buffer for the view, then configure it in the VAO.
39static bool configure_buffer( 44static bool configure_buffer(
40 RenderBackend* render_backend, const GeometryDesc* desc, 45 RenderBackend* render_backend, const GeometryDesc* desc, BufferView* view,
41 const BufferView* view, size_t num_components, size_t component_size_bytes, 46 size_t num_components, size_t component_size_bytes, GLenum component_type,
42 GLenum component_type, GLboolean normalized, GLuint channel, 47 GLboolean normalized, GLuint channel) {
43 const Buffer** buffer) {
44 assert(render_backend); 48 assert(render_backend);
45 assert(desc); 49 assert(desc);
46 assert(view); 50 assert(view);
47 assert(buffer);
48 assert( 51 assert(
49 desc->num_verts <= 52 desc->num_verts <=
50 view->size_bytes / (num_components * component_size_bytes)); 53 view->size_bytes / (num_components * component_size_bytes));
51 *buffer = get_or_make_buffer(render_backend, view); 54 const Buffer* buffer = get_or_make_view_buffer(render_backend, view);
52 if (!(*buffer)) { 55 if (!buffer) {
53 return false; 56 return false;
54 } 57 }
55 assert(view->size_bytes <= (*buffer)->size_bytes); 58 assert(view->size_bytes <= buffer->size_bytes);
56 glBindBuffer(GL_ARRAY_BUFFER, (*buffer)->vbo); 59 glBindBuffer(GL_ARRAY_BUFFER, buffer->vbo);
57 glEnableVertexAttribArray(channel); 60 glEnableVertexAttribArray(channel);
58 if ((component_type == GL_FLOAT) || normalized) { 61 if ((component_type == GL_FLOAT) || normalized) {
59 glVertexAttribPointer( 62 glVertexAttribPointer(
@@ -72,132 +75,130 @@ static bool configure_buffer(
72 return true; 75 return true;
73} 76}
74 77
75bool gfx_init_geometry( 78static bool configure_vertex_attributes(
76 Geometry* geometry, RenderBackend* render_backend, 79 RenderBackend* render_backend, GeometryDesc* desc) {
77 const GeometryDesc* desc) {
78 assert(geometry);
79 assert(render_backend); 80 assert(render_backend);
80 assert(desc); 81 assert(desc);
81 assert(
82 view_is_populated(desc->positions3d) ||
83 view_is_populated(desc->positions2d));
84 assert(desc->num_verts > 0);
85
86 geometry->mode = primitive_type_to_gl(desc->type);
87 geometry->num_verts = desc->num_verts;
88 geometry->num_indices = desc->num_indices;
89
90 glGenVertexArrays(1, &geometry->vao);
91 glBindVertexArray(geometry->vao);
92 82
93 bool result = true; 83 bool result = true;
94 84
95 if (view_is_populated(desc->positions3d)) { 85 if (view_is_populated(desc->positions3d)) {
96 result = result && 86 result =
97 configure_buffer( 87 result && configure_buffer(
98 render_backend, desc, (const BufferView*)&desc->positions3d, 3, 88 render_backend, desc, (BufferView*)&desc->positions3d, 3,
99 sizeof(float), GL_FLOAT, GL_FALSE, GFX_POSITION_CHANNEL, 89 sizeof(float), GL_FLOAT, GL_FALSE, GFX_POSITION_CHANNEL);
100 &geometry->positions);
101 } else if (view_is_populated(desc->positions2d)) { 90 } else if (view_is_populated(desc->positions2d)) {
102 result = result && 91 result =
103 configure_buffer( 92 result && configure_buffer(
104 render_backend, desc, (const BufferView*)&desc->positions2d, 2, 93 render_backend, desc, (BufferView*)&desc->positions2d, 2,
105 sizeof(float), GL_FLOAT, GL_FALSE, GFX_POSITION_CHANNEL, 94 sizeof(float), GL_FLOAT, GL_FALSE, GFX_POSITION_CHANNEL);
106 &geometry->positions);
107 } 95 }
108 96
109 if (view_is_populated(desc->normals)) { 97 if (view_is_populated(desc->normals)) {
110 result = 98 result =
111 result && configure_buffer( 99 result && configure_buffer(
112 render_backend, desc, (const BufferView*)&desc->normals, 100 render_backend, desc, (BufferView*)&desc->normals, 3,
113 3, sizeof(float), GL_FLOAT, GL_FALSE, GFX_NORMAL_CHANNEL, 101 sizeof(float), GL_FLOAT, GL_FALSE, GFX_NORMAL_CHANNEL);
114 &geometry->normals);
115 } 102 }
116 103
117 if (view_is_populated(desc->tangents)) { 104 if (view_is_populated(desc->tangents)) {
118 result = 105 result =
119 result && configure_buffer( 106 result && configure_buffer(
120 render_backend, desc, (const BufferView*)&desc->tangents, 107 render_backend, desc, (BufferView*)&desc->tangents, 4,
121 4, sizeof(float), GL_FLOAT, GL_FALSE, GFX_TANGENT_CHANNEL, 108 sizeof(float), GL_FLOAT, GL_FALSE, GFX_TANGENT_CHANNEL);
122 &geometry->tangents);
123 } 109 }
124 110
125 if (view_is_populated(desc->texcoords)) { 111 if (view_is_populated(desc->texcoords)) {
126 result = 112 result =
127 result && configure_buffer( 113 result && configure_buffer(
128 render_backend, desc, (const BufferView*)&desc->texcoords, 114 render_backend, desc, (BufferView*)&desc->texcoords, 2,
129 2, sizeof(float), GL_FLOAT, GL_FALSE, 115 sizeof(float), GL_FLOAT, GL_FALSE, GFX_TEXCOORDS_CHANNEL);
130 GFX_TEXCOORDS_CHANNEL, &geometry->texcoords);
131 } 116 }
132 117
133 if (view_is_populated(desc->joints.u8)) { 118 if (view_is_populated(desc->joints.u8)) {
134 result = 119 result = result && configure_buffer(
135 result && configure_buffer( 120 render_backend, desc, (BufferView*)&desc->joints.u8,
136 render_backend, desc, (const BufferView*)&desc->joints.u8, 121 4, sizeof(uint8_t), GL_UNSIGNED_BYTE, GL_FALSE,
137 4, sizeof(uint8_t), GL_UNSIGNED_BYTE, GL_FALSE, 122 GFX_JOINTS_CHANNEL);
138 GFX_JOINTS_CHANNEL, &geometry->joints);
139 } else if (view_is_populated(desc->joints.u16)) { 123 } else if (view_is_populated(desc->joints.u16)) {
140 result = result && 124 result = result && configure_buffer(
141 configure_buffer( 125 render_backend, desc, (BufferView*)&desc->joints.u16,
142 render_backend, desc, (const BufferView*)&desc->joints.u16, 4, 126 4, sizeof(uint16_t), GL_UNSIGNED_SHORT, GL_FALSE,
143 sizeof(uint16_t), GL_UNSIGNED_SHORT, GL_FALSE, 127 GFX_JOINTS_CHANNEL);
144 GFX_JOINTS_CHANNEL, &geometry->joints);
145 } 128 }
146 129
147 // If weights are given as unsigned integers, then they are normalized when 130 // If weights are given as unsigned integers, then they are normalized when
148 // read by the shader. 131 // read by the shader.
149 if (view_is_populated(desc->weights.u8)) { 132 if (view_is_populated(desc->weights.u8)) {
150 result = result && 133 result = result && configure_buffer(
151 configure_buffer( 134 render_backend, desc, (BufferView*)&desc->weights.u8,
152 render_backend, desc, (const BufferView*)&desc->weights.u8, 4, 135 4, sizeof(uint8_t), GL_UNSIGNED_BYTE, GL_TRUE,
153 sizeof(uint8_t), GL_UNSIGNED_BYTE, GL_TRUE, 136 GFX_WEIGHTS_CHANNEL);
154 GFX_WEIGHTS_CHANNEL, &geometry->weights);
155 } else if (view_is_populated(desc->weights.u16)) { 137 } else if (view_is_populated(desc->weights.u16)) {
156 result = result && 138 result = result && configure_buffer(
157 configure_buffer( 139 render_backend, desc,
158 render_backend, desc, (const BufferView*)&desc->weights.u16, 4, 140 (BufferView*)&desc->weights.u16, 4, sizeof(uint16_t),
159 sizeof(uint16_t), GL_UNSIGNED_SHORT, GL_TRUE, 141 GL_UNSIGNED_SHORT, GL_TRUE, GFX_WEIGHTS_CHANNEL);
160 GFX_WEIGHTS_CHANNEL, &geometry->weights);
161 } else if (view_is_populated(desc->weights.floats)) { 142 } else if (view_is_populated(desc->weights.floats)) {
162 result = result && 143 result = result &&
163 configure_buffer( 144 configure_buffer(
164 render_backend, desc, (const BufferView*)&desc->weights.floats, 145 render_backend, desc, (BufferView*)&desc->weights.floats, 4,
165 4, sizeof(float), GL_FLOAT, GL_FALSE, GFX_WEIGHTS_CHANNEL, 146 sizeof(float), GL_FLOAT, GL_FALSE, GFX_WEIGHTS_CHANNEL);
166 &geometry->weights);
167 } 147 }
168 148
169 if (!result) { 149 glBindBuffer(GL_ARRAY_BUFFER, 0);
150 return result;
151}
152
153bool gfx_init_geometry(
154 Geometry* geometry, RenderBackend* render_backend,
155 const GeometryDesc* input_desc) {
156 assert(geometry);
157 assert(render_backend);
158 assert(input_desc);
159 assert(
160 view_is_populated(input_desc->positions3d) ||
161 view_is_populated(input_desc->positions2d));
162 assert(input_desc->num_verts > 0);
163
164 geometry->mode = primitive_type_to_gl(input_desc->type);
165 geometry->desc = *input_desc;
166 geometry->render_backend = render_backend;
167
168 // We manipulate the descriptor copy below. Create a shorter name for it.
169 GeometryDesc* desc = &geometry->desc;
170
171 glGenVertexArrays(1, &geometry->vao);
172 glBindVertexArray(geometry->vao);
173
174 if (!configure_vertex_attributes(render_backend, desc)) {
170 gfx_del_geometry(geometry); 175 gfx_del_geometry(geometry);
171 return false; 176 return false;
172 } 177 }
173 178
174 glBindBuffer(GL_ARRAY_BUFFER, 0);
175
176 if (view_is_populated(desc->indices8)) { 179 if (view_is_populated(desc->indices8)) {
177 assert(desc->num_indices > 0); 180 assert(desc->num_indices > 0);
178 assert( 181 assert(
179 desc->num_indices <= desc->indices8.size_bytes / sizeof(VertexIndex8)); 182 desc->num_indices <= desc->indices8.size_bytes / sizeof(VertexIndex8));
180 geometry->indices_offset_bytes = desc->indices8.offset_bytes; 183 const Buffer* buffer =
181 geometry->indices8 = 184 get_or_make_view_buffer(render_backend, (BufferView*)&desc->indices8);
182 get_or_make_buffer(render_backend, (const BufferView*)&desc->indices8); 185 if (!buffer) {
183 if (!geometry->indices8) {
184 gfx_del_geometry(geometry); 186 gfx_del_geometry(geometry);
185 return false; 187 return false;
186 } 188 }
187 assert(desc->indices8.size_bytes <= geometry->indices8->size_bytes); 189 assert(desc->indices8.size_bytes <= buffer->size_bytes);
188 } else if (view_is_populated(desc->indices16)) { 190 } else if (view_is_populated(desc->indices16)) {
189 assert(desc->num_indices > 0); 191 assert(desc->num_indices > 0);
190 assert( 192 assert(
191 desc->num_indices <= 193 desc->num_indices <=
192 desc->indices16.size_bytes / sizeof(VertexIndex16)); 194 desc->indices16.size_bytes / sizeof(VertexIndex16));
193 geometry->indices_offset_bytes = desc->indices16.offset_bytes; 195 const Buffer* buffer =
194 geometry->indices16 = 196 get_or_make_view_buffer(render_backend, (BufferView*)&desc->indices16);
195 get_or_make_buffer(render_backend, (const BufferView*)&desc->indices16); 197 if (!buffer) {
196 if (!geometry->indices16) {
197 gfx_del_geometry(geometry); 198 gfx_del_geometry(geometry);
198 return false; 199 return false;
199 } 200 }
200 assert(desc->indices16.size_bytes <= geometry->indices16->size_bytes); 201 assert(desc->indices16.size_bytes <= buffer->size_bytes);
201 } 202 }
202 203
203 glBindVertexArray(0); 204 glBindVertexArray(0);
@@ -213,21 +214,50 @@ void gfx_del_geometry(Geometry* geometry) {
213 } 214 }
214} 215}
215 216
217void gfx_update_geometry(Geometry* geometry, const GeometryDesc* desc) {
218 assert(geometry);
219 assert(desc);
220 assert(desc->positions3d.size_bytes <= geometry->desc.positions3d.size_bytes);
221 assert(desc->positions2d.size_bytes <= geometry->desc.positions2d.size_bytes);
222 assert(desc->normals.size_bytes <= geometry->desc.normals.size_bytes);
223 assert(desc->tangents.size_bytes <= geometry->desc.tangents.size_bytes);
224 assert(desc->texcoords.size_bytes <= geometry->desc.texcoords.size_bytes);
225 assert(desc->joints.u8.size_bytes <= geometry->desc.joints.u8.size_bytes);
226 assert(desc->joints.u16.size_bytes <= geometry->desc.joints.u16.size_bytes);
227 assert(desc->weights.u8.size_bytes <= geometry->desc.weights.u8.size_bytes);
228 assert(desc->weights.u16.size_bytes <= geometry->desc.weights.u16.size_bytes);
229 assert(
230 desc->weights.floats.size_bytes <=
231 geometry->desc.weights.floats.size_bytes);
232
233 geometry->desc = *desc;
234
235 glBindVertexArray(geometry->vao);
236 bool result =
237 configure_vertex_attributes(geometry->render_backend, &geometry->desc);
238 // Shouldn't fail since we're just uploading buffer data, not creating new
239 // buffers.
240 assert(result);
241 glBindVertexArray(0);
242}
243
216void gfx_render_geometry(const Geometry* geometry) { 244void gfx_render_geometry(const Geometry* geometry) {
217 assert(geometry); 245 assert(geometry);
218 assert(geometry->vao); 246 assert(geometry->vao);
247 const GeometryDesc* desc = &geometry->desc;
219 glBindVertexArray(geometry->vao); 248 glBindVertexArray(geometry->vao);
220 if (geometry->indices8) { 249 if (desc->indices8.buffer) {
221 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geometry->indices8->vbo); 250 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, desc->indices8.buffer->vbo);
222 glDrawElements( 251 glDrawElements(
223 geometry->mode, geometry->num_indices, GL_UNSIGNED_BYTE, 252 geometry->mode, desc->num_indices, GL_UNSIGNED_BYTE,
224 (const void*)geometry->indices_offset_bytes); 253 (const void*)desc->indices8.offset_bytes);
225 } else if (geometry->indices16) { 254 } else if (desc->indices16.buffer) {
226 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geometry->indices16->vbo); 255 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, desc->indices16.buffer->vbo);
227 glDrawElements( 256 glDrawElements(
228 geometry->mode, geometry->num_indices, GL_UNSIGNED_SHORT, 257 geometry->mode, desc->num_indices, GL_UNSIGNED_SHORT,
229 (const void*)geometry->indices_offset_bytes); 258 (const void*)desc->indices16.offset_bytes);
230 } else { 259 } else {
231 glDrawArrays(geometry->mode, 0, geometry->num_verts); 260 glDrawArrays(geometry->mode, 0, desc->num_verts);
232 } 261 }
262 glBindVertexArray(0);
233} 263}
diff --git a/gfx/src/render/geometry.h b/gfx/src/render/geometry.h
index fb8f923..8fb36da 100644
--- a/gfx/src/render/geometry.h
+++ b/gfx/src/render/geometry.h
@@ -13,22 +13,10 @@
13/// the renderer assumes ownership of all rendering resources, which simplifies 13/// the renderer assumes ownership of all rendering resources, which simplifies
14/// their management. 14/// their management.
15typedef struct Geometry { 15typedef struct Geometry {
16 GLuint vao; 16 GLuint vao;
17 GLenum mode; 17 GLenum mode;
18 VertexCount num_verts; 18 GeometryDesc desc;
19 size_t num_indices; 19 RenderBackend* render_backend;
20 size_t indices_offset_bytes;
21 // Buffer pointers are no longer needed once the VAO is created, but we store
22 // them here so that we can keep track of what Geometry objects use what
23 // Buffer objects.
24 const Buffer* positions;
25 const Buffer* normals;
26 const Buffer* tangents;
27 const Buffer* texcoords;
28 const Buffer* joints;
29 const Buffer* weights;
30 const Buffer* indices8;
31 const Buffer* indices16;
32} Geometry; 20} Geometry;
33 21
34/// Create new geometry. 22/// Create new geometry.
diff --git a/gfx/src/render/render_backend.c b/gfx/src/render/render_backend.c
index b3f832b..8feefab 100644
--- a/gfx/src/render/render_backend.c
+++ b/gfx/src/render/render_backend.c
@@ -100,50 +100,20 @@ void gfx_get_viewport(RenderBackend* render_backend, int* width, int* height) {
100// Buffers. 100// Buffers.
101// ----------------------------------------------------------------------------- 101// -----------------------------------------------------------------------------
102 102
103Buffer* gfx_make_buffer( 103Buffer* gfx_make_buffer(RenderBackend* render_backend, const BufferDesc* desc) {
104 RenderBackend* render_backend, const void* data, size_t size_bytes) {
105 assert(render_backend); 104 assert(render_backend);
105 assert(desc);
106 Buffer* buffer = mempool_alloc(&render_backend->buffers); 106 Buffer* buffer = mempool_alloc(&render_backend->buffers);
107 if (!buffer) { 107 if (!buffer) {
108 return 0; 108 return 0;
109 } 109 }
110 if (!gfx_init_buffer(buffer, data, size_bytes)) { 110 if (!gfx_init_buffer(buffer, desc)) {
111 mempool_free(&render_backend->buffers, &buffer); 111 mempool_free(&render_backend->buffers, &buffer);
112 return 0; 112 return 0;
113 } 113 }
114 return buffer; 114 return buffer;
115} 115}
116 116
117Buffer* gfx_make_buffer2d(
118 RenderBackend* render_backend, const vec2* verts, size_t count) {
119 return gfx_make_buffer(
120 render_backend, (const void*)verts, count * 2 * sizeof(float));
121}
122
123Buffer* gfx_make_buffer3d(
124 RenderBackend* render_backend, const vec3* verts, size_t count) {
125 return gfx_make_buffer(
126 render_backend, (const void*)verts, count * 3 * sizeof(float));
127}
128
129Buffer* gfx_make_buffer4d(
130 RenderBackend* render_backend, const vec4* verts, size_t count) {
131 return gfx_make_buffer(
132 render_backend, (const void*)verts, count * 4 * sizeof(float));
133}
134
135Buffer* gfx_make_bufferu8(
136 RenderBackend* render_backend, const uint8_t* vals, size_t count) {
137 return gfx_make_buffer(
138 render_backend, (const void*)vals, count * sizeof(uint8_t));
139}
140
141Buffer* gfx_make_bufferu16(
142 RenderBackend* render_backend, const uint16_t* vals, size_t count) {
143 return gfx_make_buffer(
144 render_backend, (const void*)vals, count * sizeof(uint16_t));
145}
146
147void gfx_destroy_buffer(RenderBackend* render_backend, Buffer** buffer) { 117void gfx_destroy_buffer(RenderBackend* render_backend, Buffer** buffer) {
148 assert(render_backend); 118 assert(render_backend);
149 assert(buffer); 119 assert(buffer);
diff --git a/gfx/src/util/geometry.c b/gfx/src/util/geometry.c
index d485125..84435ce 100644
--- a/gfx/src/util/geometry.c
+++ b/gfx/src/util/geometry.c
@@ -2,26 +2,26 @@
2 2
3#include <math/vec2.h> 3#include <math/vec2.h>
4 4
5static void gfx_make_quad_11_positions(vec2 positions[4]) { 5static void make_quad_11_positions(vec2 positions[4]) {
6 positions[0] = vec2_make(-1, +1); 6 positions[0] = vec2_make(-1, +1);
7 positions[1] = vec2_make(-1, -1); 7 positions[1] = vec2_make(-1, -1);
8 positions[2] = vec2_make(+1, +1); 8 positions[2] = vec2_make(+1, +1);
9 positions[3] = vec2_make(+1, -1); 9 positions[3] = vec2_make(+1, -1);
10} 10}
11 11
12static void gfx_make_quad_01_positions(vec2 positions[4]) { 12static void make_quad_01_positions(vec2 positions[4]) {
13 positions[0] = vec2_make(0, 0); 13 positions[0] = vec2_make(0, 0);
14 positions[1] = vec2_make(1, 0); 14 positions[1] = vec2_make(1, 0);
15 positions[2] = vec2_make(1, 1); 15 positions[2] = vec2_make(1, 1);
16 positions[3] = vec2_make(0, 1); 16 positions[3] = vec2_make(0, 1);
17} 17}
18 18
19static GeometryDesc gfx_make_quad_desc(vec2 positions[4]) { 19static GeometryDesc make_quad_desc(vec2 positions[4]) {
20 GeometryDesc desc = (GeometryDesc){0}; 20 GeometryDesc desc = (GeometryDesc){0};
21 desc.positions2d.data = positions; 21 desc.positions2d.data = positions;
22 desc.positions2d.size_bytes = 4 * sizeof(vec2); 22 desc.positions2d.size_bytes = 4 * sizeof(vec2);
23 desc.num_verts = 4; 23 desc.num_verts = 4;
24 desc.type = TriangleStrip; 24 desc.type = TriangleStrip;
25 return desc; 25 return desc;
26} 26}
27 27
@@ -29,8 +29,8 @@ Geometry* gfx_make_quad_11(RenderBackend* render_backend) {
29 assert(render_backend); 29 assert(render_backend);
30 30
31 vec2 positions[4]; 31 vec2 positions[4];
32 gfx_make_quad_11_positions(positions); 32 make_quad_11_positions(positions);
33 const GeometryDesc geometry_desc = gfx_make_quad_desc(positions); 33 const GeometryDesc geometry_desc = make_quad_desc(positions);
34 return gfx_make_geometry(render_backend, &geometry_desc); 34 return gfx_make_geometry(render_backend, &geometry_desc);
35} 35}
36 36
@@ -38,7 +38,7 @@ Geometry* gfx_make_quad_01(RenderBackend* render_backend) {
38 assert(render_backend); 38 assert(render_backend);
39 39
40 vec2 positions[4]; 40 vec2 positions[4];
41 gfx_make_quad_01_positions(positions); 41 make_quad_01_positions(positions);
42 const GeometryDesc geometry_desc = gfx_make_quad_desc(positions); 42 const GeometryDesc geometry_desc = make_quad_desc(positions);
43 return gfx_make_geometry(render_backend, &geometry_desc); 43 return gfx_make_geometry(render_backend, &geometry_desc);
44} 44}
diff --git a/gfx/src/util/scene.c b/gfx/src/util/scene.c
index 40d6686..e8dd6b1 100644
--- a/gfx/src/util/scene.c
+++ b/gfx/src/util/scene.c
@@ -536,7 +536,12 @@ static bool load_buffers(
536 for (cgltf_size i = 0; i < data->buffers_count; ++i) { 536 for (cgltf_size i = 0; i < data->buffers_count; ++i) {
537 const cgltf_buffer* buffer = &data->buffers[i]; 537 const cgltf_buffer* buffer = &data->buffers[i];
538 assert(buffer->data); 538 assert(buffer->data);
539 buffers[i] = gfx_make_buffer(render_backend, buffer->data, buffer->size); 539 buffers[i] = gfx_make_buffer(
540 render_backend, &(BufferDesc){
541 .usage = BufferStatic,
542 .type = BufferUntyped,
543 .data = buffer->data,
544 .count = buffer->size});
540 if (!buffers[i]) { 545 if (!buffers[i]) {
541 return false; 546 return false;
542 } 547 }
@@ -557,8 +562,12 @@ static bool load_tangent_buffers(
557 for (cgltf_size i = 0; i < num_tangent_buffers; ++i) { 562 for (cgltf_size i = 0; i < num_tangent_buffers; ++i) {
558 const cgltfTangentBuffer* buffer = &cgltf_tangent_buffers[i]; 563 const cgltfTangentBuffer* buffer = &cgltf_tangent_buffers[i];
559 assert(buffer->data); 564 assert(buffer->data);
560 tangent_buffers[i] = 565 tangent_buffers[i] = gfx_make_buffer(
561 gfx_make_buffer(render_backend, buffer->data, buffer->size_bytes); 566 render_backend, &(BufferDesc){
567 .usage = BufferStatic,
568 .type = BufferUntyped,
569 .data = buffer->data,
570 .count = buffer->size_bytes});
562 if (!tangent_buffers[i]) { 571 if (!tangent_buffers[i]) {
563 return false; 572 return false;
564 } 573 }