Compare commits

..

19 Commits

Author SHA1 Message Date
Syoyo Fujita
5e8a7fd602 Merge pull request #456 from haroonq/patch-1
Allow BufferView indices to be unspecified.
2023-10-10 21:24:51 +09:00
haroonq
8098a9e8ed Allow BufferView indices to be unspecified.
Allow BufferView indices for element array buffers to be unspecified to support some extensions.

Note that this is similar to how invalid array buffers are handled in order to support, for example, sparse morph targets.
2023-10-09 10:30:25 +00:00
Syoyo Fujita
e0b393c695 Merge pull request #455 from nyalldawson/fix_message
Fix incorrect component type shown in warning message
2023-09-12 20:28:35 +09:00
Nyall Dawson
c35819f0b7 Fix incorrect component type shown in warning message 2023-09-12 08:46:14 +10:00
Syoyo Fujita
4b9cfc8c1e Remove unused code. Fixes #454 2023-09-07 22:03:46 +09:00
Syoyo Fujita
c40c9c223e Merge pull request #453 from nyalldawson/fix_draco
Fix build with draco
2023-09-07 21:35:55 +09:00
Nyall Dawson
0067b4d941 Fix build with draco 2023-09-07 08:20:28 +10:00
Syoyo Fujita
35735bb686 Merge pull request #452 from nyalldawson/permissive_align
Relax bin chunk end alignment check in permissive mode
2023-09-07 06:46:11 +09:00
Nyall Dawson
4d119d7268 Relax bin chunk end alignment check in permissive mode 2023-09-07 07:08:26 +10:00
Syoyo Fujita
fe6a18269f Merge pull request #450 from nyalldawson/fix_win
Fix msvc build -- STRICT is a msvc macro name
2023-09-07 05:59:12 +09:00
Nyall Dawson
bbc1eaeecf Fix msvc build -- STRICT is a msvc macro name 2023-09-07 06:28:37 +10:00
Syoyo Fujita
62cc92566e Merge pull request #451 from nyalldawson/mingw
Add mingw msys2 workflow
2023-09-06 20:55:14 +09:00
Nyall Dawson
b2aca1ecef Add mingw msys2 workflow 2023-09-06 08:26:34 +10:00
Nyall Dawson
5a7b8278cd Fix warning when building without draco support 2023-09-03 09:04:56 +10:00
Syoyo Fujita
3d445cc65d Merge pull request #449 from emimvi/consistent_byteOffset
Always use size_t for byte offsets
2023-09-03 02:20:35 +09:00
Syoyo Fujita
51530ee500 Merge pull request #447 from nyalldawson/draco_fix
Handle the situation where the recorded component type does not match the required type for the actual number of stored points
2023-09-03 02:17:12 +09:00
emimvi
759976e087 Consistently use size_t for all byteOffset's 2023-09-02 09:39:53 +02:00
Nyall Dawson
6e3d666cf3 When in permissive mode, handle the situation where the
recorded component type does not match the required type
for the actual number of stored points

This situation arises when decoding certain malformed files, most
notably it's seen in glb tiles from Google Earth's 3d tileset.

It's a port of the workaround used by Cesium native here:

d9172461e2/CesiumGltfReader/src/decodeDraco.cpp (L101)
2023-09-02 10:16:04 +10:00
emimvi
bf7120f8a0 Serialize byteOffset as size_t, avoiding cast
Fixes silently writing an overflowed int in the output file.
2023-09-02 00:11:41 +02:00
2 changed files with 126 additions and 38 deletions

45
.github/workflows/mingw-w64-msys2.yml vendored Normal file
View File

@@ -0,0 +1,45 @@
name: MSYS2 MinGW-w64 Windows 64bit Build
on:
push:
branches:
- release
- devel
paths:
- 'tiny_gltf.*'
- 'CMakeLists.txt'
- '.github/workflows/mingw-w64-msys2.yml'
pull_request:
workflow_dispatch:
jobs:
mingw-w64-msys2-build:
name: MSYS2 MinGW-w64 Windows Build
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v3
- name: Install core & build dependencies
uses: msys2/setup-msys2@v2
with:
msystem: UCRT64
install: base-devel
pacboy: >-
cc:p cmake:p ninja:p
update: true
release: false
- name: Configure
run: |
cmake \
-G"Ninja" \
-S . \
-B build
- name: Build
run: |
cmake --build build

View File

@@ -196,8 +196,8 @@ typedef enum {
} Type;
typedef enum {
PERMISSIVE,
STRICT
Permissive,
Strict
} ParseStrictness;
static inline int32_t GetComponentSizeInBytes(uint32_t componentType) {
@@ -837,7 +837,7 @@ struct Accessor {
int count;
bool isSparse;
struct {
int byteOffset;
size_t byteOffset;
int bufferView;
int componentType; // a TINYGLTF_COMPONENT_TYPE_ value
Value extras;
@@ -847,7 +847,7 @@ struct Accessor {
} indices;
struct {
int bufferView;
int byteOffset;
size_t byteOffset;
Value extras;
ExtensionMap extensions;
std::string extras_json_string;
@@ -1562,7 +1562,7 @@ class TinyGLTF {
size_t bin_size_ = 0;
bool is_binary_ = false;
ParseStrictness strictness_ = ParseStrictness::STRICT;
ParseStrictness strictness_ = ParseStrictness::Strict;
bool serialize_default_values_ = false; ///< Serialize default values?
@@ -4648,24 +4648,26 @@ static bool ParseSparseAccessor(
const detail::json &indices_obj = detail::GetValue(indices_iterator);
const detail::json &values_obj = detail::GetValue(values_iterator);
int indices_buffer_view = 0, indices_byte_offset = 0, component_type = 0;
int indices_buffer_view = 0, component_type = 0;
size_t indices_byte_offset = 0;
if (!ParseIntegerProperty(&indices_buffer_view, err, indices_obj,
"bufferView", true, "SparseAccessor")) {
return false;
}
ParseIntegerProperty(&indices_byte_offset, err, indices_obj, "byteOffset",
ParseUnsignedProperty(&indices_byte_offset, err, indices_obj, "byteOffset",
false);
if (!ParseIntegerProperty(&component_type, err, indices_obj, "componentType",
true, "SparseAccessor")) {
return false;
}
int values_buffer_view = 0, values_byte_offset = 0;
int values_buffer_view = 0;
size_t values_byte_offset = 0;
if (!ParseIntegerProperty(&values_buffer_view, err, values_obj, "bufferView",
true, "SparseAccessor")) {
return false;
}
ParseIntegerProperty(&values_byte_offset, err, values_obj, "byteOffset",
ParseUnsignedProperty(&values_byte_offset, err, values_obj, "byteOffset",
false);
sparse->count = count;
@@ -4873,8 +4875,9 @@ static bool GetAttributeForAllPoints(uint32_t componentType, draco::Mesh *mesh,
}
static bool ParseDracoExtension(Primitive *primitive, Model *model,
std::string *err,
const Value &dracoExtensionValue) {
std::string *err, std::string *warn,
const Value &dracoExtensionValue,
ParseStrictness strictness) {
(void)err;
auto bufferViewValue = dracoExtensionValue.Get("bufferView");
if (!bufferViewValue.IsInt()) return false;
@@ -4906,6 +4909,33 @@ static bool ParseDracoExtension(Primitive *primitive, Model *model,
// create new bufferView for indices
if (primitive->indices >= 0) {
if (strictness == ParseStrictness::Permissive) {
const draco::PointIndex::ValueType numPoint = mesh->num_points();
// handle the situation where the stored component type does not match the
// required type for the actual number of stored points
int supposedComponentType = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE;
if (numPoint < static_cast<draco::PointIndex::ValueType>(
std::numeric_limits<uint8_t>::max())) {
supposedComponentType = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE;
} else if (
numPoint < static_cast<draco::PointIndex::ValueType>(
std::numeric_limits<uint16_t>::max())) {
supposedComponentType = TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT;
} else {
supposedComponentType = TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT;
}
if (supposedComponentType > model->accessors[primitive->indices].componentType) {
if (warn) {
(*warn) +=
"GLTF component type " + std::to_string(model->accessors[primitive->indices].componentType) +
" is not sufficient for number of stored points,"
" treating as " + std::to_string(supposedComponentType) + "\n";
}
model->accessors[primitive->indices].componentType = supposedComponentType;
}
}
int32_t componentSize = GetComponentSizeInBytes(
model->accessors[primitive->indices].componentType);
Buffer decodedIndexBuffer;
@@ -4971,9 +5001,11 @@ static bool ParseDracoExtension(Primitive *primitive, Model *model,
}
#endif
static bool ParsePrimitive(Primitive *primitive, Model *model, std::string *err,
static bool ParsePrimitive(Primitive *primitive, Model *model,
std::string *err, std::string *warn,
const detail::json &o,
bool store_original_json_for_extras_and_extensions) {
bool store_original_json_for_extras_and_extensions,
ParseStrictness strictness) {
int material = -1;
ParseIntegerProperty(&material, err, o, "material", false);
primitive->material = material;
@@ -5022,18 +5054,22 @@ static bool ParsePrimitive(Primitive *primitive, Model *model, std::string *err,
auto dracoExtension =
primitive->extensions.find("KHR_draco_mesh_compression");
if (dracoExtension != primitive->extensions.end()) {
ParseDracoExtension(primitive, model, err, dracoExtension->second);
ParseDracoExtension(primitive, model, err, warn, dracoExtension->second, strictness);
}
#else
(void)model;
(void)warn;
(void)strictness;
#endif
return true;
}
static bool ParseMesh(Mesh *mesh, Model *model, std::string *err,
static bool ParseMesh(Mesh *mesh, Model *model,
std::string *err, std::string *warn,
const detail::json &o,
bool store_original_json_for_extras_and_extensions) {
bool store_original_json_for_extras_and_extensions,
ParseStrictness strictness) {
ParseStringProperty(&mesh->name, err, o, "name", false);
mesh->primitives.clear();
@@ -5046,8 +5082,9 @@ static bool ParseMesh(Mesh *mesh, Model *model, std::string *err,
detail::ArrayBegin(detail::GetValue(primObject));
i != primEnd; ++i) {
Primitive primitive;
if (ParsePrimitive(&primitive, model, err, *i,
store_original_json_for_extras_and_extensions)) {
if (ParsePrimitive(&primitive, model, err, warn, *i,
store_original_json_for_extras_and_extensions,
strictness)) {
// Only add the primitive if the parsing succeeds.
mesh->primitives.emplace_back(std::move(primitive));
}
@@ -5217,7 +5254,7 @@ static bool ParseMaterial(Material *material, std::string *err, std::string *war
if (ParseNumberArrayProperty(&material->emissiveFactor, err, o,
"emissiveFactor",
/* required */ false)) {
if (strictness==ParseStrictness::PERMISSIVE && material->emissiveFactor.size() == 4) {
if (strictness==ParseStrictness::Permissive && material->emissiveFactor.size() == 4) {
if (warn) {
(*warn) +=
"Array length of `emissiveFactor` parameter in "
@@ -6078,8 +6115,9 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
return false;
}
Mesh mesh;
if (!ParseMesh(&mesh, model, err, o,
store_original_json_for_extras_and_extensions_)) {
if (!ParseMesh(&mesh, model, err, warn, o,
store_original_json_for_extras_and_extensions_,
strictness_)) {
return false;
}
@@ -6107,20 +6145,22 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
return false;
}
auto bufferView =
const auto bufferView =
model->accessors[size_t(primitive.indices)].bufferView;
if (bufferView < 0 || size_t(bufferView) >= model->bufferViews.size()) {
if (bufferView < 0) {
// skip, bufferView could be null(-1) for certain extensions
} else if (size_t(bufferView) >= model->bufferViews.size()) {
if (err) {
(*err) += "accessor[" + std::to_string(primitive.indices) +
"] invalid bufferView";
}
return false;
} else {
model->bufferViews[size_t(bufferView)].target =
TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER;
// we could optionally check if accessors' bufferView type is Scalar, as
// it should be
}
model->bufferViews[size_t(bufferView)].target =
TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER;
// we could optionally check if accessors' bufferView type is Scalar, as
// it should be
}
for (auto &attribute : primitive.attributes) {
@@ -6695,10 +6735,17 @@ bool TinyGLTF::LoadBinaryFromMemory(Model *model, std::string *err,
}
if ((chunk1_length % 4) != 0) {
if (err) {
(*err) = "BIN Chunk end does not aligned to a 4-byte boundary.";
if (strictness_==ParseStrictness::Permissive) {
if (warn) {
(*warn) += "BIN Chunk end is not aligned to a 4-byte boundary.\n";
}
}
else {
if (err) {
(*err) = "BIN Chunk end is not aligned to a 4-byte boundary.";
}
return false;
}
return false;
}
if (uint64_t(chunk1_length) + header_and_json_size > uint64_t(length)) {
@@ -6723,10 +6770,6 @@ bool TinyGLTF::LoadBinaryFromMemory(Model *model, std::string *err,
bin_size_ = size_t(chunk1_length);
}
// Extract JSON string.
std::string jsonString(reinterpret_cast<const char *>(&bytes[20]),
chunk0_length);
is_binary_ = true;
bool ret = LoadFromString(model, err, warn,
@@ -7124,7 +7167,7 @@ static void SerializeGltfAccessor(const Accessor &accessor, detail::json &o) {
SerializeNumberProperty<int>("bufferView", accessor.bufferView, o);
if (accessor.byteOffset != 0)
SerializeNumberProperty<int>("byteOffset", int(accessor.byteOffset), o);
SerializeNumberProperty<size_t>("byteOffset", accessor.byteOffset, o);
SerializeNumberProperty<int>("componentType", accessor.componentType, o);
SerializeNumberProperty<size_t>("count", accessor.count, o);
@@ -7195,7 +7238,7 @@ static void SerializeGltfAccessor(const Accessor &accessor, detail::json &o) {
detail::json indices;
SerializeNumberProperty<int>("bufferView",
accessor.sparse.indices.bufferView, indices);
SerializeNumberProperty<int>("byteOffset",
SerializeNumberProperty<size_t>("byteOffset",
accessor.sparse.indices.byteOffset, indices);
SerializeNumberProperty<int>(
"componentType", accessor.sparse.indices.componentType, indices);
@@ -7206,7 +7249,7 @@ static void SerializeGltfAccessor(const Accessor &accessor, detail::json &o) {
detail::json values;
SerializeNumberProperty<int>("bufferView",
accessor.sparse.values.bufferView, values);
SerializeNumberProperty<int>("byteOffset",
SerializeNumberProperty<size_t>("byteOffset",
accessor.sparse.values.byteOffset, values);
SerializeExtrasAndExtensions(accessor.sparse.values, values);
detail::JsonAddMember(sparse, "values", std::move(values));