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 | } |
