diff options
-rw-r--r-- | gfx/include/gfx/render_backend.h | 73 | ||||
-rw-r--r-- | gfx/src/render/buffer.c | 49 | ||||
-rw-r--r-- | gfx/src/render/buffer.h | 13 | ||||
-rw-r--r-- | gfx/src/render/geometry.c | 214 | ||||
-rw-r--r-- | gfx/src/render/geometry.h | 20 | ||||
-rw-r--r-- | gfx/src/render/render_backend.c | 36 | ||||
-rw-r--r-- | gfx/src/util/geometry.c | 22 | ||||
-rw-r--r-- | gfx/src/util/scene.c | 15 |
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. | ||
42 | typedef enum BufferUsage { BufferStatic, BufferDynamic } BufferUsage; | ||
43 | |||
44 | /// Buffer type. | ||
45 | typedef 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. | ||
66 | typedef 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. |
83 | typedef struct GeometryDesc { | 121 | typedef 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. |
268 | Buffer* gfx_make_buffer(RenderBackend*, const void*, size_t size_bytes); | 306 | Buffer* gfx_make_buffer(RenderBackend*, const BufferDesc*); |
269 | |||
270 | /// Create a buffer from 2D vertices. | ||
271 | Buffer* gfx_make_buffer2d(RenderBackend*, const vec2* verts, size_t count); | ||
272 | |||
273 | /// Create a buffer from 3D vertices. | ||
274 | Buffer* gfx_make_buffer3d(RenderBackend*, const vec3* verts, size_t count); | ||
275 | |||
276 | /// Create a buffer from 4D vertices. | ||
277 | Buffer* gfx_make_buffer4d(RenderBackend*, const vec4* verts, size_t count); | ||
278 | |||
279 | /// Create a buffer from 8-bit unsigned integers. | ||
280 | Buffer* gfx_make_bufferu8(RenderBackend*, const uint8_t* vals, size_t count); | ||
281 | |||
282 | /// Create a buffer from 16-bit unsigned integers. | ||
283 | Buffer* gfx_make_bufferu16(RenderBackend*, const uint16_t* vals, size_t count); | ||
284 | 307 | ||
285 | /// Destroy the buffer. | 308 | /// Destroy the buffer. |
286 | void gfx_destroy_buffer(RenderBackend*, Buffer**); | 309 | void gfx_destroy_buffer(RenderBackend*, Buffer**); |
@@ -295,6 +318,20 @@ Geometry* gfx_make_geometry(RenderBackend*, const GeometryDesc*); | |||
295 | /// Destroy the geometry. | 318 | /// Destroy the geometry. |
296 | void gfx_destroy_geometry(RenderBackend*, Geometry**); | 319 | void 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. | ||
333 | void gfx_update_geometry(Geometry*, const GeometryDesc*); | ||
334 | |||
298 | /// Render the geometry. | 335 | /// Render the geometry. |
299 | void gfx_render_geometry(const Geometry*); | 336 | void 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 | ||
7 | bool gfx_init_buffer(Buffer* buffer, const void* data, size_t size_bytes) { | 9 | static 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 | |||
26 | static 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 | |||
37 | bool 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 | ||
18 | bool 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 | |||
22 | bool 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 | |||
26 | bool 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 | |||
30 | void gfx_del_buffer(Buffer* buffer) { | 49 | void 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 | ||
10 | typedef struct BufferDesc BufferDesc; | ||
11 | |||
10 | typedef struct Buffer { | 12 | typedef 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. |
16 | bool gfx_init_buffer(Buffer*, const void* data, size_t size_bytes); | 18 | bool gfx_init_buffer(Buffer*, const BufferDesc*); |
17 | |||
18 | /// Create a buffer from 2D vertices. | ||
19 | bool gfx_init_buffer_2d(Buffer*, const vec2* verts, size_t count); | ||
20 | |||
21 | /// Create a buffer from 3D vertices. | ||
22 | bool gfx_init_buffer_3d(Buffer*, const vec3* verts, size_t count); | ||
23 | |||
24 | /// Create a buffer from 4D vertices. | ||
25 | bool gfx_init_buffer_4d(Buffer*, const vec4* verts, size_t count); | ||
26 | 19 | ||
27 | /// Destroy the buffer. | 20 | /// Destroy the buffer. |
28 | void gfx_del_buffer(Buffer*); | 21 | void 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. |
29 | static const Buffer* get_or_make_buffer( | 29 | static 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. |
39 | static bool configure_buffer( | 44 | static 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 | ||
75 | bool gfx_init_geometry( | 78 | static 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 | |||
153 | bool 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 | ||
217 | void 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 | |||
216 | void gfx_render_geometry(const Geometry* geometry) { | 244 | void 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. |
15 | typedef struct Geometry { | 15 | typedef 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 | ||
103 | Buffer* gfx_make_buffer( | 103 | Buffer* 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 | ||
117 | Buffer* 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 | |||
123 | Buffer* 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 | |||
129 | Buffer* 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 | |||
135 | Buffer* 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 | |||
141 | Buffer* 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 | |||
147 | void gfx_destroy_buffer(RenderBackend* render_backend, Buffer** buffer) { | 117 | void 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 | ||
5 | static void gfx_make_quad_11_positions(vec2 positions[4]) { | 5 | static 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 | ||
12 | static void gfx_make_quad_01_positions(vec2 positions[4]) { | 12 | static 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 | ||
19 | static GeometryDesc gfx_make_quad_desc(vec2 positions[4]) { | 19 | static 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 | } |