Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 43 additions & 4 deletions extern/cgltf.h
Original file line number Diff line number Diff line change
Expand Up @@ -2352,11 +2352,46 @@ const cgltf_accessor* cgltf_find_accessor(const cgltf_primitive* prim, cgltf_att
return NULL;
}

static const uint8_t* cgltf_find_sparse_index(const cgltf_accessor* accessor, cgltf_size needle)
{
const cgltf_accessor_sparse* sparse = &accessor->sparse;
const uint8_t* index_data = cgltf_buffer_view_data(sparse->indices_buffer_view);
const uint8_t* value_data = cgltf_buffer_view_data(sparse->values_buffer_view);

if (index_data == NULL || value_data == NULL)
return NULL;

index_data += sparse->indices_byte_offset;
value_data += sparse->values_byte_offset;

cgltf_size index_stride = cgltf_component_size(sparse->indices_component_type);

cgltf_size offset = 0;
cgltf_size length = sparse->count;

while (length)
{
cgltf_size rem = length % 2;
length /= 2;

cgltf_size index = cgltf_component_read_index(index_data + (offset + length) * index_stride, sparse->indices_component_type);
offset += index < needle ? length + rem : 0;
}

if (offset == sparse->count)
return NULL;

cgltf_size index = offset < sparse->count ? cgltf_component_read_index(index_data + offset * index_stride, sparse->indices_component_type) : (cgltf_size)-1;
return index == needle ? value_data + offset * accessor->stride : NULL;
}

cgltf_bool cgltf_accessor_read_float(const cgltf_accessor* accessor, cgltf_size index, cgltf_float* out, cgltf_size element_size)
{
if (accessor->is_sparse)
{
return 0;
const uint8_t* element = cgltf_find_sparse_index(accessor, index);
if (element)
return cgltf_element_read_float(element, accessor->type, accessor->component_type, accessor->normalized, out, element_size);
}
if (accessor->buffer_view == NULL)
{
Expand Down Expand Up @@ -2500,11 +2535,13 @@ cgltf_bool cgltf_accessor_read_uint(const cgltf_accessor* accessor, cgltf_size i
{
if (accessor->is_sparse)
{
return 0;
const uint8_t* element = cgltf_find_sparse_index(accessor, index);
if (element)
return cgltf_element_read_uint(element, accessor->type, accessor->component_type, out, element_size);
}
if (accessor->buffer_view == NULL)
{
memset(out, 0, element_size * sizeof( cgltf_uint ));
memset(out, 0, element_size * sizeof(cgltf_uint));
return 1;
}
const uint8_t* element = cgltf_buffer_view_data(accessor->buffer_view);
Expand All @@ -2520,7 +2557,9 @@ cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size
{
if (accessor->is_sparse)
{
return 0; // This is an error case, but we can't communicate the error with existing interface.
const uint8_t* element = cgltf_find_sparse_index(accessor, index);
if (element)
return cgltf_component_read_index(element, accessor->component_type);
}
if (accessor->buffer_view == NULL)
{
Expand Down
42 changes: 33 additions & 9 deletions gltf/parsegltf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ static void readAccessor(std::vector<Attr>& data, const cgltf_accessor* accessor
}
}

static void readAccessor(std::vector<Attr>& data, const cgltf_accessor* accessor, const std::vector<unsigned int>& sparse)
{
data.resize(sparse.size());

for (size_t i = 0; i < sparse.size(); ++i)
cgltf_accessor_read_float(accessor, sparse[i], &data[i].f[0], 4);
}

static void fixupIndices(std::vector<unsigned int>& indices, cgltf_primitive_type& type)
{
if (type == cgltf_primitive_type_line_loop)
Expand Down Expand Up @@ -177,11 +185,8 @@ static void parseMeshesGltf(cgltf_data* data, std::vector<Mesh>& meshes, std::ve
Mesh& result = meshes.back();

result.scene = -1;

result.material = primitive.material;

result.extras = primitive.extras;

result.type = primitive.type;

result.streams.reserve(primitive.attributes_count);
Expand All @@ -199,14 +204,27 @@ static void parseMeshesGltf(cgltf_data* data, std::vector<Mesh>& meshes, std::ve
}
else if (primitive.type != cgltf_primitive_type_points)
{
// note, while we could generate a good index buffer, reindexMesh will take care of this
// note, while we could generate a good index buffer here, mesh will be reindexed during processing
result.indices.resize(vertex_count);
for (size_t i = 0; i < vertex_count; ++i)
result.indices[i] = unsigned(i);
}

// convert line loops and line/triangle strips to lists
fixupIndices(result.indices, result.type);

std::vector<unsigned int> sparse;

// if the index data is very sparse, switch to deindexing on the fly to avoid the excessive cost of reading large accessors
if (!result.indices.empty() && result.indices.size() < vertex_count / 2)
{
sparse = result.indices;

// mesh will be reindexed during processing
for (size_t i = 0; i < result.indices.size(); ++i)
result.indices[i] = unsigned(i);
}

for (size_t ai = 0; ai < primitive.attributes_count; ++ai)
{
const cgltf_attribute& attr = primitive.attributes[ai];
Expand All @@ -232,7 +250,10 @@ static void parseMeshesGltf(cgltf_data* data, std::vector<Mesh>& meshes, std::ve
if (attr.type == cgltf_attribute_type_custom)
s.custom_name = attr.name;

readAccessor(s.data, attr.data);
if (sparse.empty())
readAccessor(s.data, attr.data);
else
readAccessor(s.data, attr.data, sparse);

if (attr.type == cgltf_attribute_type_color && attr.data->type == cgltf_type_vec3)
{
Expand Down Expand Up @@ -262,7 +283,10 @@ static void parseMeshesGltf(cgltf_data* data, std::vector<Mesh>& meshes, std::ve
s.index = attr.index;
s.target = int(ti + 1);

readAccessor(s.data, attr.data);
if (sparse.empty())
readAccessor(s.data, attr.data);
else
readAccessor(s.data, attr.data, sparse);
}
}

Expand Down Expand Up @@ -312,11 +336,11 @@ static void parseMeshInstancesGltf(std::vector<Transform>& instances, cgltf_node
for (size_t i = 0; i < count; ++i)
{
if (translation)
cgltf_accessor_read_float(translation, i, instance.translation, sizeof(float));
cgltf_accessor_read_float(translation, i, instance.translation, 4);
if (rotation)
cgltf_accessor_read_float(rotation, i, instance.rotation, sizeof(float));
cgltf_accessor_read_float(rotation, i, instance.rotation, 4);
if (scale)
cgltf_accessor_read_float(scale, i, instance.scale, sizeof(float));
cgltf_accessor_read_float(scale, i, instance.scale, 4);

Transform xf;
cgltf_node_transform_world(&instance, xf.data);
Expand Down