From d7220ee51c59cd3e51927f2f5e0388c8573f1792 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Sun, 2 Nov 2025 15:57:16 -0800 Subject: Fix view/accessor offset and invariants; fix loading of Flight Helmet --- include/gfx/core.h | 1 + src/asset/model.c | 34 ++++++++++++++----------- src/core/geometry.c | 73 +++++++++++++++++++++++++---------------------------- src/render/imm.c | 14 +++++----- src/util/geometry.c | 13 +++++----- 5 files changed, 69 insertions(+), 66 deletions(-) diff --git a/include/gfx/core.h b/include/gfx/core.h index 5a05cda..25b8779 100644 --- a/include/gfx/core.h +++ b/include/gfx/core.h @@ -93,6 +93,7 @@ typedef struct BufferDesc { size_t offset_bytes; \ size_t size_bytes; \ size_t stride_bytes; \ + size_t count; \ } NAME; /// A buffer view for untyped data. diff --git a/src/asset/model.c b/src/asset/model.c index a97d20e..b5c6b0d 100644 --- a/src/asset/model.c +++ b/src/asset/model.c @@ -1030,7 +1030,6 @@ static bool load_meshes( const cgltf_attribute* attrib = &prim->attributes[a]; const cgltf_accessor* accessor = attrib->data; const cgltf_buffer_view* view = accessor->buffer_view; - const cgltf_size offset = accessor->offset + view->offset; const cgltf_size buffer_index = view->buffer - data->buffers; assert(buffer_index < data->buffers_count); @@ -1120,12 +1119,20 @@ static bool load_meshes( break; } -#define CONFIGURE_BUFFER(buf) \ - if (buf) { \ - buf->buffer = buffer; \ - buf->offset_bytes = offset; \ - buf->size_bytes = view->size; \ - buf->stride_bytes = view->stride; \ + // See comments here for accessor/view/buffer invariants: + // https://github.com/KhronosGroup/glTF-Sample-Assets/issues/242 + // Gfx only has Buffer and BufferView, not accessors. We must combine + // the glTF's accessor and view offsets correctly. + const cgltf_size offset = accessor->offset + view->offset; + const cgltf_size size_bytes = view->size - accessor->offset; + +#define CONFIGURE_BUFFER(buf) \ + if (buf) { \ + buf->buffer = buffer; \ + buf->offset_bytes = offset; \ + buf->size_bytes = size_bytes; \ + buf->stride_bytes = view->stride; \ + buf->count = accessor->count; \ } CONFIGURE_BUFFER(buffer_view_2d); CONFIGURE_BUFFER(buffer_view_3d); @@ -1160,14 +1167,11 @@ static bool load_meshes( // either 2d or 3d positions but not both, here we can perform addition // to compute the total number of vertices. geometry_desc.num_verts = - (geometry_desc.positions2d.size_bytes / sizeof(vec2)) + - (geometry_desc.positions3d.size_bytes / sizeof(vec3)); - -#define CHECK_COUNT(buffer_view, type, num_components) \ - if (geometry_desc.buffer_view.buffer) { \ - assert( \ - (geometry_desc.buffer_view.size_bytes / \ - (num_components * sizeof(type))) == geometry_desc.num_verts); \ + geometry_desc.positions2d.count + geometry_desc.positions3d.count; + +#define CHECK_COUNT(buffer_view, type, num_components) \ + if (geometry_desc.buffer_view.buffer) { \ + assert(geometry_desc.buffer_view.count == geometry_desc.num_verts); \ } // Check that the number of vertices is consistent across all vertex diff --git a/src/core/geometry.c b/src/core/geometry.c index cfc749f..488dc23 100644 --- a/src/core/geometry.c +++ b/src/core/geometry.c @@ -12,7 +12,7 @@ /// /// Note that views are allowed to have no data, in which case a buffer of the /// specified size is created. -#define view_is_populated(BUFFER_VIEW) (BUFFER_VIEW.size_bytes > 0) +#define view_is_populated(BUFFER_VIEW) (BUFFER_VIEW.count > 0) static GLenum primitive_type_to_gl(PrimitiveType type) { switch (type) { @@ -34,30 +34,25 @@ void init_view_buffer( BufferUsage buffer_usage) { if (!view->buffer) { view->buffer = gfx_make_buffer( - gfxcore, - &(BufferDesc){ - .usage = buffer_usage, - .type = buffer_type, - .data.data = view->data, - .data.count = view->size_bytes / - gfx_get_buffer_type_size_bytes(buffer_type)}); + gfxcore, &(BufferDesc){.usage = buffer_usage, + .type = buffer_type, + .data.data = view->data, + .data.count = view->count}); + assert(view->buffer); } - assert(view->size_bytes <= view->buffer->size_bytes); } -/// Configure the buffer in teh VAO. +/// Configure the buffer in the VAO. static void configure_buffer( GfxCore* gfxcore, const GeometryDesc* desc, BufferView* view, - size_t num_components, size_t component_size_bytes, GLenum component_type, - GLboolean normalized, GLuint channel) { + size_t num_components, GLenum component_type, GLboolean normalized, + GLuint channel) { assert(gfxcore); assert(desc); assert(view); assert(view->buffer); - assert( - desc->num_verts <= - view->size_bytes / (num_components * component_size_bytes)); - assert(view->size_bytes <= view->buffer->size_bytes); + assert(view->count == desc->num_verts); + assert((view->offset_bytes + view->size_bytes) <= view->buffer->size_bytes); glBindBuffer(GL_ARRAY_BUFFER, view->buffer->vbo); glEnableVertexAttribArray(channel); @@ -89,8 +84,8 @@ static bool configure_vertex_attributes(GfxCore* gfxcore, GeometryDesc* desc) { return false; } configure_buffer( - gfxcore, desc, (BufferView*)&desc->positions3d, 3, sizeof(float), - GL_FLOAT, GL_FALSE, GFX_POSITION_CHANNEL); + gfxcore, desc, (BufferView*)&desc->positions3d, 3, GL_FLOAT, GL_FALSE, + GFX_POSITION_CHANNEL); } else if (view_is_populated(desc->positions2d)) { init_view_buffer( gfxcore, (BufferView*)&desc->positions2d, Buffer2d, desc->buffer_usage); @@ -98,8 +93,8 @@ static bool configure_vertex_attributes(GfxCore* gfxcore, GeometryDesc* desc) { return false; } configure_buffer( - gfxcore, desc, (BufferView*)&desc->positions2d, 2, sizeof(float), - GL_FLOAT, GL_FALSE, GFX_POSITION_CHANNEL); + gfxcore, desc, (BufferView*)&desc->positions2d, 2, GL_FLOAT, GL_FALSE, + GFX_POSITION_CHANNEL); } if (view_is_populated(desc->normals)) { init_view_buffer( @@ -108,8 +103,8 @@ static bool configure_vertex_attributes(GfxCore* gfxcore, GeometryDesc* desc) { return false; } configure_buffer( - gfxcore, desc, (BufferView*)&desc->normals, 3, sizeof(float), GL_FLOAT, - GL_FALSE, GFX_NORMAL_CHANNEL); + gfxcore, desc, (BufferView*)&desc->normals, 3, GL_FLOAT, GL_FALSE, + GFX_NORMAL_CHANNEL); } if (view_is_populated(desc->tangents)) { init_view_buffer( @@ -118,8 +113,8 @@ static bool configure_vertex_attributes(GfxCore* gfxcore, GeometryDesc* desc) { return false; } configure_buffer( - gfxcore, desc, (BufferView*)&desc->tangents, 4, sizeof(float), GL_FLOAT, - GL_FALSE, GFX_TANGENT_CHANNEL); + gfxcore, desc, (BufferView*)&desc->tangents, 4, GL_FLOAT, GL_FALSE, + GFX_TANGENT_CHANNEL); } if (view_is_populated(desc->texcoords)) { init_view_buffer( @@ -128,8 +123,8 @@ static bool configure_vertex_attributes(GfxCore* gfxcore, GeometryDesc* desc) { return false; } configure_buffer( - gfxcore, desc, (BufferView*)&desc->texcoords, 2, sizeof(float), - GL_FLOAT, GL_FALSE, GFX_TEXCOORDS_CHANNEL); + gfxcore, desc, (BufferView*)&desc->texcoords, 2, GL_FLOAT, GL_FALSE, + GFX_TEXCOORDS_CHANNEL); } if (view_is_populated(desc->joints.u8)) { init_view_buffer( @@ -138,8 +133,8 @@ static bool configure_vertex_attributes(GfxCore* gfxcore, GeometryDesc* desc) { return false; } configure_buffer( - gfxcore, desc, (BufferView*)&desc->joints.u8, 4, sizeof(uint8_t), - GL_UNSIGNED_BYTE, GL_FALSE, GFX_JOINTS_CHANNEL); + gfxcore, desc, (BufferView*)&desc->joints.u8, 4, GL_UNSIGNED_BYTE, + GL_FALSE, GFX_JOINTS_CHANNEL); } else if (view_is_populated(desc->joints.u16)) { init_view_buffer( gfxcore, (BufferView*)&desc->joints.u16, BufferU16, desc->buffer_usage); @@ -147,8 +142,8 @@ static bool configure_vertex_attributes(GfxCore* gfxcore, GeometryDesc* desc) { return false; } configure_buffer( - gfxcore, desc, (BufferView*)&desc->joints.u16, 4, sizeof(uint16_t), - GL_UNSIGNED_SHORT, GL_FALSE, GFX_JOINTS_CHANNEL); + gfxcore, desc, (BufferView*)&desc->joints.u16, 4, GL_UNSIGNED_SHORT, + GL_FALSE, GFX_JOINTS_CHANNEL); } // If weights are given as unsigned integers, then they are normalized @@ -160,8 +155,8 @@ static bool configure_vertex_attributes(GfxCore* gfxcore, GeometryDesc* desc) { return false; } configure_buffer( - gfxcore, desc, (BufferView*)&desc->weights.u8, 4, sizeof(uint8_t), - GL_UNSIGNED_BYTE, GL_TRUE, GFX_WEIGHTS_CHANNEL); + gfxcore, desc, (BufferView*)&desc->weights.u8, 4, GL_UNSIGNED_BYTE, + GL_TRUE, GFX_WEIGHTS_CHANNEL); } else if (view_is_populated(desc->weights.u16)) { init_view_buffer( gfxcore, (BufferView*)&desc->weights.u16, BufferU16, @@ -170,8 +165,8 @@ static bool configure_vertex_attributes(GfxCore* gfxcore, GeometryDesc* desc) { return false; } configure_buffer( - gfxcore, desc, (BufferView*)&desc->weights.u16, 4, sizeof(uint16_t), - GL_UNSIGNED_SHORT, GL_TRUE, GFX_WEIGHTS_CHANNEL); + gfxcore, desc, (BufferView*)&desc->weights.u16, 4, GL_UNSIGNED_SHORT, + GL_TRUE, GFX_WEIGHTS_CHANNEL); } else if (view_is_populated(desc->weights.floats)) { init_view_buffer( gfxcore, (BufferView*)&desc->weights.floats, BufferFloat, @@ -180,8 +175,8 @@ static bool configure_vertex_attributes(GfxCore* gfxcore, GeometryDesc* desc) { return false; } configure_buffer( - gfxcore, desc, (BufferView*)&desc->weights.floats, 4, sizeof(float), - GL_FLOAT, GL_FALSE, GFX_WEIGHTS_CHANNEL); + gfxcore, desc, (BufferView*)&desc->weights.floats, 4, GL_FLOAT, + GL_FALSE, GFX_WEIGHTS_CHANNEL); } return true; @@ -282,9 +277,9 @@ void gfx_update_geometry(Geometry* geometry, const GeometryDesc* desc) { assert(geometry->desc.positions3d.buffer); gfx_update_buffer( geometry->desc.positions3d.buffer, - &(BufferDataDesc){ - .vec3s = desc->positions3d.data, - .count = desc->positions3d.size_bytes / sizeof(vec3)}); + &(BufferDataDesc){.vec3s = desc->positions3d.data, + .count = + desc->positions3d.size_bytes / sizeof(vec3)}); } // TODO: more else { diff --git a/src/render/imm.c b/src/render/imm.c index 8a93488..7ab8d62 100644 --- a/src/render/imm.c +++ b/src/render/imm.c @@ -21,12 +21,14 @@ bool gfx_imm_make(Imm* renderer, GfxCore* gfxcore, LLR* llr) { renderer->llr = llr; renderer->triangles = gfx_make_geometry( - gfxcore, - &(GeometryDesc){.type = Triangles, - .buffer_usage = BufferDynamic, - .num_verts = num_triangle_verts, - .positions3d = (BufferView3d){ - .size_bytes = num_triangle_verts * sizeof(vec3)}}); + gfxcore, &(GeometryDesc){ + .type = Triangles, + .buffer_usage = BufferDynamic, + .num_verts = num_triangle_verts, + .positions3d = (BufferView3d){ + .size_bytes = num_triangle_verts * sizeof(vec3), + .count = num_triangle_verts} + }); if (!renderer->triangles) { goto cleanup; } diff --git a/src/util/geometry.c b/src/util/geometry.c index afe0109..2ea0c82 100644 --- a/src/util/geometry.c +++ b/src/util/geometry.c @@ -17,12 +17,13 @@ static void make_quad_01_positions(vec2 positions[4]) { } static GeometryDesc make_quad_desc(vec2 positions[4]) { - GeometryDesc desc = (GeometryDesc){0}; - desc.positions2d.data = positions; - desc.positions2d.size_bytes = 4 * sizeof(vec2); - desc.num_verts = 4; - desc.type = TriangleStrip; - return desc; + return (GeometryDesc){ + .positions2d = (BufferView2d){.data = positions, + .size_bytes = 4 * sizeof(vec2), + .count = 4}, + .num_verts = 4, + .type = TriangleStrip + }; } Geometry* gfx_make_quad_11(GfxCore* gfxcore) { -- cgit v1.2.3