summaryrefslogtreecommitdiff
path: root/gfx/src/core/geometry.c
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/src/core/geometry.c')
-rw-r--r--gfx/src/core/geometry.c326
1 files changed, 326 insertions, 0 deletions
diff --git a/gfx/src/core/geometry.c b/gfx/src/core/geometry.c
new file mode 100644
index 0000000..cfc749f
--- /dev/null
+++ b/gfx/src/core/geometry.c
@@ -0,0 +1,326 @@
1#include "geometry.h"
2
3#include "buffer.h"
4#include "constants.h"
5
6#include <gfx_assert.h>
7
8#include <math/vec2.h>
9#include <math/vec3.h>
10
11/// Determines whether a view is populated.
12///
13/// Note that views are allowed to have no data, in which case a buffer of the
14/// specified size is created.
15#define view_is_populated(BUFFER_VIEW) (BUFFER_VIEW.size_bytes > 0)
16
17static GLenum primitive_type_to_gl(PrimitiveType type) {
18 switch (type) {
19 case Triangles:
20 return GL_TRIANGLES;
21 case TriangleFan:
22 return GL_TRIANGLE_FAN;
23 case TriangleStrip:
24 return GL_TRIANGLE_STRIP;
25 }
26 FAIL("primitive_type_to_gl(): missing case");
27 return GL_INVALID_ENUM;
28}
29
30/// Create a typed buffer for the buffer view if the view does not already point
31/// to a buffer.
32void init_view_buffer(
33 GfxCore* gfxcore, BufferView* view, BufferType buffer_type,
34 BufferUsage buffer_usage) {
35 if (!view->buffer) {
36 view->buffer = gfx_make_buffer(
37 gfxcore,
38 &(BufferDesc){
39 .usage = buffer_usage,
40 .type = buffer_type,
41 .data.data = view->data,
42 .data.count = view->size_bytes /
43 gfx_get_buffer_type_size_bytes(buffer_type)});
44 }
45 assert(view->size_bytes <= view->buffer->size_bytes);
46}
47
48/// Configure the buffer in teh VAO.
49static void configure_buffer(
50 GfxCore* gfxcore, const GeometryDesc* desc, BufferView* view,
51 size_t num_components, size_t component_size_bytes, GLenum component_type,
52 GLboolean normalized, GLuint channel) {
53 assert(gfxcore);
54 assert(desc);
55 assert(view);
56 assert(view->buffer);
57 assert(
58 desc->num_verts <=
59 view->size_bytes / (num_components * component_size_bytes));
60 assert(view->size_bytes <= view->buffer->size_bytes);
61
62 glBindBuffer(GL_ARRAY_BUFFER, view->buffer->vbo);
63 glEnableVertexAttribArray(channel);
64 if ((component_type == GL_FLOAT) || normalized) {
65 glVertexAttribPointer(
66 channel, num_components, component_type, normalized, view->stride_bytes,
67 (const void*)view->offset_bytes);
68 } else {
69 assert(!normalized);
70 assert(
71 (component_type == GL_BYTE) || (component_type == GL_UNSIGNED_BYTE) ||
72 (component_type == GL_SHORT) || (component_type == GL_UNSIGNED_SHORT) ||
73 (component_type == GL_INT) || component_type == GL_UNSIGNED_INT);
74 glVertexAttribIPointer(
75 channel, num_components, component_type, view->stride_bytes,
76 (const void*)view->offset_bytes);
77 }
78 glBindBuffer(GL_ARRAY_BUFFER, 0);
79}
80
81static bool configure_vertex_attributes(GfxCore* gfxcore, GeometryDesc* desc) {
82 assert(gfxcore);
83 assert(desc);
84
85 if (view_is_populated(desc->positions3d)) {
86 init_view_buffer(
87 gfxcore, (BufferView*)&desc->positions3d, Buffer3d, desc->buffer_usage);
88 if (!desc->positions3d.buffer) {
89 return false;
90 }
91 configure_buffer(
92 gfxcore, desc, (BufferView*)&desc->positions3d, 3, sizeof(float),
93 GL_FLOAT, GL_FALSE, GFX_POSITION_CHANNEL);
94 } else if (view_is_populated(desc->positions2d)) {
95 init_view_buffer(
96 gfxcore, (BufferView*)&desc->positions2d, Buffer2d, desc->buffer_usage);
97 if (!desc->positions2d.buffer) {
98 return false;
99 }
100 configure_buffer(
101 gfxcore, desc, (BufferView*)&desc->positions2d, 2, sizeof(float),
102 GL_FLOAT, GL_FALSE, GFX_POSITION_CHANNEL);
103 }
104 if (view_is_populated(desc->normals)) {
105 init_view_buffer(
106 gfxcore, (BufferView*)&desc->normals, Buffer3d, desc->buffer_usage);
107 if (!desc->normals.buffer) {
108 return false;
109 }
110 configure_buffer(
111 gfxcore, desc, (BufferView*)&desc->normals, 3, sizeof(float), GL_FLOAT,
112 GL_FALSE, GFX_NORMAL_CHANNEL);
113 }
114 if (view_is_populated(desc->tangents)) {
115 init_view_buffer(
116 gfxcore, (BufferView*)&desc->tangents, Buffer4d, desc->buffer_usage);
117 if (!desc->tangents.buffer) {
118 return false;
119 }
120 configure_buffer(
121 gfxcore, desc, (BufferView*)&desc->tangents, 4, sizeof(float), GL_FLOAT,
122 GL_FALSE, GFX_TANGENT_CHANNEL);
123 }
124 if (view_is_populated(desc->texcoords)) {
125 init_view_buffer(
126 gfxcore, (BufferView*)&desc->texcoords, Buffer2d, desc->buffer_usage);
127 if (!desc->texcoords.buffer) {
128 return false;
129 }
130 configure_buffer(
131 gfxcore, desc, (BufferView*)&desc->texcoords, 2, sizeof(float),
132 GL_FLOAT, GL_FALSE, GFX_TEXCOORDS_CHANNEL);
133 }
134 if (view_is_populated(desc->joints.u8)) {
135 init_view_buffer(
136 gfxcore, (BufferView*)&desc->joints.u8, BufferU8, desc->buffer_usage);
137 if (!desc->joints.u8.buffer) {
138 return false;
139 }
140 configure_buffer(
141 gfxcore, desc, (BufferView*)&desc->joints.u8, 4, sizeof(uint8_t),
142 GL_UNSIGNED_BYTE, GL_FALSE, GFX_JOINTS_CHANNEL);
143 } else if (view_is_populated(desc->joints.u16)) {
144 init_view_buffer(
145 gfxcore, (BufferView*)&desc->joints.u16, BufferU16, desc->buffer_usage);
146 if (!desc->joints.u16.buffer) {
147 return false;
148 }
149 configure_buffer(
150 gfxcore, desc, (BufferView*)&desc->joints.u16, 4, sizeof(uint16_t),
151 GL_UNSIGNED_SHORT, GL_FALSE, GFX_JOINTS_CHANNEL);
152 }
153
154 // If weights are given as unsigned integers, then they are normalized
155 // when read by the shader.
156 if (view_is_populated(desc->weights.u8)) {
157 init_view_buffer(
158 gfxcore, (BufferView*)&desc->weights.u8, BufferU8, desc->buffer_usage);
159 if (!desc->weights.u8.buffer) {
160 return false;
161 }
162 configure_buffer(
163 gfxcore, desc, (BufferView*)&desc->weights.u8, 4, sizeof(uint8_t),
164 GL_UNSIGNED_BYTE, GL_TRUE, GFX_WEIGHTS_CHANNEL);
165 } else if (view_is_populated(desc->weights.u16)) {
166 init_view_buffer(
167 gfxcore, (BufferView*)&desc->weights.u16, BufferU16,
168 desc->buffer_usage);
169 if (!desc->weights.u16.buffer) {
170 return false;
171 }
172 configure_buffer(
173 gfxcore, desc, (BufferView*)&desc->weights.u16, 4, sizeof(uint16_t),
174 GL_UNSIGNED_SHORT, GL_TRUE, GFX_WEIGHTS_CHANNEL);
175 } else if (view_is_populated(desc->weights.floats)) {
176 init_view_buffer(
177 gfxcore, (BufferView*)&desc->weights.floats, BufferFloat,
178 desc->buffer_usage);
179 if (!desc->weights.floats.buffer) {
180 return false;
181 }
182 configure_buffer(
183 gfxcore, desc, (BufferView*)&desc->weights.floats, 4, sizeof(float),
184 GL_FLOAT, GL_FALSE, GFX_WEIGHTS_CHANNEL);
185 }
186
187 return true;
188}
189
190static bool configure_indices(GfxCore* gfxcore, GeometryDesc* desc) {
191 assert(gfxcore);
192 assert(desc);
193
194 if (view_is_populated(desc->indices8)) {
195 assert(desc->num_indices > 0);
196 assert(
197 desc->num_indices <= desc->indices8.size_bytes / sizeof(VertexIndex8));
198 init_view_buffer(
199 gfxcore, (BufferView*)&desc->indices8, BufferU8, desc->buffer_usage);
200 if (!desc->indices8.buffer) {
201 return false;
202 }
203 } else if (view_is_populated(desc->indices16)) {
204 assert(desc->num_indices > 0);
205 assert(
206 desc->num_indices <=
207 desc->indices16.size_bytes / sizeof(VertexIndex16));
208 init_view_buffer(
209 gfxcore, (BufferView*)&desc->indices16, BufferU16, desc->buffer_usage);
210 if (!desc->indices16.buffer) {
211 return false;
212 }
213 }
214
215 return true;
216}
217
218bool gfx_init_geometry(
219 Geometry* geometry, GfxCore* gfxcore, const GeometryDesc* input_desc) {
220 assert(geometry);
221 assert(gfxcore);
222 assert(input_desc);
223 assert(
224 view_is_populated(input_desc->positions3d) ||
225 view_is_populated(input_desc->positions2d));
226 assert(input_desc->num_verts > 0);
227
228 geometry->mode = primitive_type_to_gl(input_desc->type);
229 geometry->desc = *input_desc;
230 geometry->num_verts = input_desc->num_verts;
231 geometry->gfxcore = gfxcore;
232
233 // The geometry's copy of the descriptor is manipulated below. Create a
234 // shorter name for it.
235 GeometryDesc* desc = &geometry->desc;
236
237 glGenVertexArrays(1, &geometry->vao);
238 glBindVertexArray(geometry->vao);
239 if (!configure_vertex_attributes(gfxcore, desc)) {
240 goto cleanup;
241 }
242 if (!configure_indices(gfxcore, desc)) {
243 goto cleanup;
244 }
245 glBindVertexArray(0);
246 ASSERT_GL;
247
248 return true;
249
250cleanup:
251 gfx_del_geometry(geometry);
252 return 0;
253}
254
255void gfx_del_geometry(Geometry* geometry) {
256 assert(geometry);
257 if (geometry->vao) {
258 glDeleteVertexArrays(1, &geometry->vao);
259 geometry->vao = 0;
260 }
261}
262
263void gfx_update_geometry(Geometry* geometry, const GeometryDesc* desc) {
264 assert(geometry);
265 assert(desc);
266 // New geometry size cannot exceed original size.
267 assert(desc->positions3d.size_bytes <= geometry->desc.positions3d.size_bytes);
268 assert(desc->positions2d.size_bytes <= geometry->desc.positions2d.size_bytes);
269 assert(desc->normals.size_bytes <= geometry->desc.normals.size_bytes);
270 assert(desc->tangents.size_bytes <= geometry->desc.tangents.size_bytes);
271 assert(desc->texcoords.size_bytes <= geometry->desc.texcoords.size_bytes);
272 assert(desc->joints.u8.size_bytes <= geometry->desc.joints.u8.size_bytes);
273 assert(desc->joints.u16.size_bytes <= geometry->desc.joints.u16.size_bytes);
274 assert(desc->weights.u8.size_bytes <= geometry->desc.weights.u8.size_bytes);
275 assert(desc->weights.u16.size_bytes <= geometry->desc.weights.u16.size_bytes);
276 assert(
277 desc->weights.floats.size_bytes <=
278 geometry->desc.weights.floats.size_bytes);
279
280 if (desc->positions3d.data) {
281 // The geometry must already have an underlying GPU buffer.
282 assert(geometry->desc.positions3d.buffer);
283 gfx_update_buffer(
284 geometry->desc.positions3d.buffer,
285 &(BufferDataDesc){
286 .vec3s = desc->positions3d.data,
287 .count = desc->positions3d.size_bytes / sizeof(vec3)});
288 }
289 // TODO: more
290 else {
291 FAIL("TODO: gfx_update_geometry() - handle other buffer types");
292 }
293
294 if (desc->num_verts != 0) {
295 geometry->num_verts = desc->num_verts;
296 }
297}
298
299void gfx_render_geometry(const Geometry* geometry) {
300 assert(geometry);
301 assert(geometry->vao);
302
303 const GeometryDesc* desc = &geometry->desc;
304 glBindVertexArray(geometry->vao);
305
306 if (desc->indices8.buffer) {
307 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, desc->indices8.buffer->vbo);
308 glDrawElements(
309 geometry->mode, desc->num_indices, GL_UNSIGNED_BYTE,
310 (const void*)desc->indices8.offset_bytes);
311 } else if (desc->indices16.buffer) {
312 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, desc->indices16.buffer->vbo);
313 glDrawElements(
314 geometry->mode, desc->num_indices, GL_UNSIGNED_SHORT,
315 (const void*)desc->indices16.offset_bytes);
316 } else {
317 glDrawArrays(geometry->mode, 0, geometry->num_verts);
318 }
319
320 glBindVertexArray(0);
321}
322
323aabb3 gfx_get_geometry_aabb(const Geometry* geometry) {
324 assert(geometry);
325 return geometry->desc.aabb;
326}