Add tinygltf_json.h: fast custom JSON parser with optional SIMD support

Co-authored-by: syoyo <18676+syoyo@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-03-17 15:49:46 +00:00
parent 1616826478
commit 8f8b5ec1e0
15 changed files with 2581 additions and 2 deletions

View File

@@ -18,6 +18,11 @@ option(TINYGLTF_BUILD_TESTS "Build unit tests" OFF)
option(TINYGLTF_HEADER_ONLY "On: header-only mode. Off: create tinygltf library(No TINYGLTF_IMPLEMENTATION required in your project)" OFF)
option(TINYGLTF_INSTALL "Install tinygltf files during install step. Usually set to OFF if you include tinygltf through add_subdirectory()" ON)
option(TINYGLTF_INSTALL_VENDOR "Install vendored nlohmann/json and nothings/stb headers" ON)
option(TINYGLTF_USE_CUSTOM_JSON "Use the built-in fast JSON parser (tinygltf_json.h) instead of nlohmann/json" OFF)
if (TINYGLTF_USE_CUSTOM_JSON)
add_definitions(-DTINYGLTF_USE_CUSTOM_JSON)
endif (TINYGLTF_USE_CUSTOM_JSON)
if (TINYGLTF_BUILD_LOADER_EXAMPLE)
add_executable(loader_example
@@ -80,6 +85,7 @@ if (TINYGLTF_INSTALL)
INSTALL ( FILES
tiny_gltf.h
tinygltf_json.h
${TINYGLTF_EXTRA_SOUECES}
DESTINATION
include

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 B

BIN
tests/ issue-236.bin Normal file

Binary file not shown.

151
tests/ issue-236.gltf Normal file
View File

@@ -0,0 +1,151 @@
{
"accessors": [
{
"bufferView": 0,
"componentType": 5121,
"count": 36,
"min": [
0
],
"max": [
23
],
"type": "SCALAR"
},
{
"bufferView": 1,
"componentType": 5126,
"count": 24,
"min": [
-0.5,
-0.5,
-0.5
],
"max": [
0.5,
0.5,
0.5
],
"type": "VEC3"
},
{
"bufferView": 2,
"componentType": 5126,
"count": 24,
"min": [
-1.0,
-1.0,
-1.0
],
"max": [
1.0,
1.0,
1.0
],
"type": "VEC3"
},
{
"bufferView": 3,
"componentType": 5126,
"count": 24,
"min": [
0.0,
0.0
],
"max": [
1.0,
1.0
],
"type": "VEC2"
}
],
"asset": {
"version": "2.0"
},
"bufferViews": [
{
"buffer": 0,
"byteLength": 36,
"target": 34963
},
{
"buffer": 0,
"byteLength": 288,
"byteOffset": 36,
"target": 34962
},
{
"buffer": 0,
"byteLength": 288,
"byteOffset": 324,
"target": 34962
},
{
"buffer": 0,
"byteLength": 192,
"byteOffset": 612,
"target": 34962
}
],
"materials": [
{
"pbrMetallicRoughness": {
"baseColorTexture": {
"index": 0
}
}
}
],
"meshes": [
{
"primitives": [
{
"attributes": {
"NORMAL": 2,
"POSITION": 1,
"TEXCOORD_0": 3
},
"indices": 0,
"material": 0,
"mode": 4
}
]
}
],
"nodes": [
{
"mesh": 0
}
],
"scene": 0,
"scenes": [
{
"nodes": [
0
]
}
],
"textures": [
{
"sampler": 0,
"source": 0
}
],
"samplers": [
{
"wrapS": 33071,
"wrapT": 33071
}
],
"buffers": [
{
"byteLength": 804,
"uri": "%20issue-236.bin"
}
],
"images": [
{
"uri": "%202x2%20image%20%20has%20multiple%20%20%20%20%20%20spaces.png"
}
]
}

BIN
tests/Cube.bin Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
tests/Cube.glb Normal file

Binary file not shown.

190
tests/Cube.gltf Normal file
View File

@@ -0,0 +1,190 @@
{
"accessors": [
{
"bufferView": 0,
"componentType": 5123,
"count": 36,
"min": [
0
],
"max": [
35
],
"type": "SCALAR"
},
{
"bufferView": 1,
"componentType": 5126,
"count": 36,
"min": [
-1.0,
-1.0,
-1.0
],
"max": [
1.0,
1.0,
1.0000009999999999
],
"type": "VEC3"
},
{
"bufferView": 2,
"componentType": 5126,
"count": 36,
"min": [
-1.0,
-1.0,
-1.0
],
"max": [
1.0,
1.0,
1.0
],
"type": "VEC3"
},
{
"bufferView": 3,
"componentType": 5126,
"count": 36,
"min": [
0.0,
-0.0,
-1.0,
-1.0
],
"max": [
1.0,
-0.0,
-0.0,
1.0
],
"type": "VEC4"
},
{
"bufferView": 4,
"componentType": 5126,
"count": 36,
"min": [
-1.0,
-1.0
],
"max": [
1.0,
1.0
],
"type": "VEC2"
}
],
"asset": {
"generator": "VKTS glTF 2.0 exporter",
"version": "2.0"
},
"bufferViews": [
{
"buffer": 0,
"byteLength": 72,
"target": 34963
},
{
"buffer": 0,
"byteLength": 432,
"byteOffset": 72,
"target": 34962
},
{
"buffer": 0,
"byteLength": 432,
"byteOffset": 504,
"target": 34962
},
{
"buffer": 0,
"byteLength": 576,
"byteOffset": 936,
"target": 34962
},
{
"buffer": 0,
"byteLength": 288,
"byteOffset": 1512,
"target": 34962
}
],
"materials": [
{
"name": "Cube",
"pbrMetallicRoughness": {
"baseColorTexture": {
"index": 0
},
"metallicRoughnessTexture": {
"index": 1
}
}
}
],
"meshes": [
{
"primitives": [
{
"attributes": {
"NORMAL": 2,
"POSITION": 1,
"TANGENT": 3,
"TEXCOORD_0": 4
},
"indices": 0,
"material": 0,
"mode": 4
}
],
"name": "Cube"
}
],
"nodes": [
{
"mesh": 0,
"name": "Cube"
}
],
"scene": 0,
"scenes": [
{
"nodes": [
0
]
}
],
"textures": [
{
"sampler": 0,
"source": 0
},
{
"sampler": 0,
"source": 1
}
],
"samplers": [
{
"wrapS": 10497,
"wrapT": 10497
}
],
"buffers": [
{
"byteLength": 1800,
"uri": "Cube.bin"
}
],
"images": [
{
"uri": "Cube_BaseColor.png"
},
{
"uri": "Cube_MetallicRoughness.png"
}
]
}

BIN
tests/Cube_BaseColor.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 871 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 B

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,190 @@
{
"accessors": [
{
"bufferView": 0,
"componentType": 5123,
"count": 36,
"min": [
0
],
"max": [
35
],
"type": "SCALAR"
},
{
"bufferView": 1,
"componentType": 5126,
"count": 36,
"min": [
-1.0,
-1.0,
-1.0
],
"max": [
1.0,
1.0,
1.0000009999999999
],
"type": "VEC3"
},
{
"bufferView": 2,
"componentType": 5126,
"count": 36,
"min": [
-1.0,
-1.0,
-1.0
],
"max": [
1.0,
1.0,
1.0
],
"type": "VEC3"
},
{
"bufferView": 3,
"componentType": 5126,
"count": 36,
"min": [
0.0,
-0.0,
-1.0,
-1.0
],
"max": [
1.0,
-0.0,
-0.0,
1.0
],
"type": "VEC4"
},
{
"bufferView": 4,
"componentType": 5126,
"count": 36,
"min": [
-1.0,
-1.0
],
"max": [
1.0,
1.0
],
"type": "VEC2"
}
],
"asset": {
"generator": "VKTS glTF 2.0 exporter",
"version": "2.0"
},
"bufferViews": [
{
"buffer": 0,
"byteLength": 72,
"target": 34963
},
{
"buffer": 0,
"byteLength": 432,
"byteOffset": 72,
"target": 34962
},
{
"buffer": 0,
"byteLength": 432,
"byteOffset": 504,
"target": 34962
},
{
"buffer": 0,
"byteLength": 576,
"byteOffset": 936,
"target": 34962
},
{
"buffer": 0,
"byteLength": 288,
"byteOffset": 1512,
"target": 34962
}
],
"materials": [
{
"name": "Cube",
"pbrMetallicRoughness": {
"baseColorTexture": {
"index": 0
},
"metallicRoughnessTexture": {
"index": 1
}
}
}
],
"meshes": [
{
"primitives": [
{
"attributes": {
"NORMAL": 2,
"POSITION": 1,
"TANGENT": 3,
"TEXCOORD_0": 4
},
"indices": 0,
"material": 0,
"mode": 4
}
],
"name": "Cube"
}
],
"nodes": [
{
"mesh": 0,
"name": "Cube"
}
],
"scene": 0,
"scenes": [
{
"nodes": [
0
]
}
],
"textures": [
{
"sampler": 0,
"source": 0
},
{
"sampler": 0,
"source": 1
}
],
"samplers": [
{
"wrapS": 10497,
"wrapT": 10497
}
],
"buffers": [
{
"byteLength": 1800,
"uri": "Cube.bin"
}
],
"images": [
{
"uri": "Cube_BaseColor.png"
},
{
"uri": "Cube_MetallicRoughness.png"
}
]
}

View File

@@ -0,0 +1,192 @@
{
"accessors": [
{
"bufferView": 0,
"componentType": 5123,
"count": 36,
"min": [
0
],
"max": [
35
],
"type": "SCALAR"
},
{
"bufferView": 1,
"componentType": 5126,
"count": 36,
"min": [
-1.0,
-1.0,
-1.0
],
"max": [
1.0,
1.0,
1.0000009999999999
],
"type": "VEC3"
},
{
"bufferView": 2,
"componentType": 5126,
"count": 36,
"min": [
-1.0,
-1.0,
-1.0
],
"max": [
1.0,
1.0,
1.0
],
"type": "VEC3"
},
{
"bufferView": 3,
"componentType": 5126,
"count": 36,
"min": [
0.0,
-0.0,
-1.0,
-1.0
],
"max": [
1.0,
-0.0,
-0.0,
1.0
],
"type": "VEC4"
},
{
"bufferView": 4,
"componentType": 5126,
"count": 36,
"min": [
-1.0,
-1.0
],
"max": [
1.0,
1.0
],
"type": "VEC2"
}
],
"asset": {
"generator": "VKTS glTF 2.0 exporter",
"version": "2.0"
},
"bufferViews": [
{
"buffer": 0,
"byteLength": 72,
"target": 34963
},
{
"buffer": 0,
"byteLength": 432,
"byteOffset": 72,
"target": 34962
},
{
"buffer": 0,
"byteLength": 432,
"byteOffset": 504,
"target": 34962
},
{
"buffer": 0,
"byteLength": 576,
"byteOffset": 936,
"target": 34962
},
{
"buffer": 0,
"byteLength": 288,
"byteOffset": 1512,
"target": 34962
}
],
"materials": [
{
"name": "Cube",
"pbrMetallicRoughness": {
"baseColorTexture": {
"index": 0
},
"metallicRoughnessTexture": {
"index": 1
}
}
}
],
"meshes": [
{
"primitives": [
{
"attributes": {
"NORMAL": 2,
"POSITION": 1,
"TANGENT": 3,
"TEXCOORD_0": 4
},
"indices": 0,
"material": 0,
"mode": 4
}
],
"name": "Cube"
}
],
"nodes": [
{
"mesh": 0,
"name": "Cube"
}
],
"scene": 0,
"scenes": [
{
"nodes": [
0
]
}
],
"textures": [
{
"sampler": 0,
"source": 0
},
{
"sampler": 0,
"source": 1
}
],
"samplers": [
{
"wrapS": 10497,
"wrapT": 10497
}
],
"buffers": [
{
"byteLength": 1800,
"uri": "Cube.bin"
}
],
"images": [
{
"mimeType": "",
"bufferView": -1
},
{
"mimeType": "",
"bufferView": -1
}
]
}

BIN
tests/tmp.glb Normal file

Binary file not shown.

View File

@@ -1711,7 +1711,11 @@ class TinyGLTF {
#endif // __GNUC__
#ifndef TINYGLTF_NO_INCLUDE_JSON
#ifndef TINYGLTF_USE_RAPIDJSON
#ifdef TINYGLTF_USE_CUSTOM_JSON
#ifndef TINYGLTF_NO_INCLUDE_CUSTOM_JSON
#include "tinygltf_json.h"
#endif
#elif !defined(TINYGLTF_USE_RAPIDJSON)
#include "json.hpp"
#else
#ifndef TINYGLTF_NO_INCLUDE_RAPIDJSON
@@ -1799,7 +1803,10 @@ class TinyGLTF {
namespace tinygltf {
namespace detail {
#ifdef TINYGLTF_USE_RAPIDJSON
#ifdef TINYGLTF_USE_CUSTOM_JSON
// Types and JsonParse are provided by tinygltf_json.h (already included above)
// via 'namespace tinygltf { namespace detail { ... } }' declarations.
#elif defined(TINYGLTF_USE_RAPIDJSON)
#ifdef TINYGLTF_USE_RAPIDJSON_CRTALLOCATOR
// This uses the RapidJSON CRTAllocator. It is thread safe and multiple
@@ -1871,6 +1878,7 @@ using json_const_array_iterator = json_const_iterator;
using JsonDocument = json;
#endif
#ifndef TINYGLTF_USE_CUSTOM_JSON
void JsonParse(JsonDocument &doc, const char *str, size_t length,
bool throwExc = false) {
#ifdef TINYGLTF_USE_RAPIDJSON
@@ -1880,6 +1888,7 @@ void JsonParse(JsonDocument &doc, const char *str, size_t length,
doc = detail::json::parse(str, str + length, nullptr, throwExc);
#endif
}
#endif // !TINYGLTF_USE_CUSTOM_JSON
} // namespace detail
} // namespace tinygltf
@@ -3436,6 +3445,7 @@ bool DecodeDataURI(std::vector<unsigned char> *out, std::string &mime_type,
return true;
}
#ifndef TINYGLTF_USE_CUSTOM_JSON
namespace detail {
bool GetInt(const detail::json &o, int &val) {
#ifdef TINYGLTF_USE_RAPIDJSON
@@ -3659,6 +3669,7 @@ std::string JsonToString(const detail::json &o, int spacing = -1) {
}
} // namespace detail
#endif // !TINYGLTF_USE_CUSTOM_JSON
static bool ParseJsonAsValue(Value *ret, const detail::json &o) {
Value val{};
@@ -6962,6 +6973,7 @@ bool TinyGLTF::LoadBinaryFromFile(Model *model, std::string *err,
///////////////////////
// GLTF Serialization
///////////////////////
#ifndef TINYGLTF_USE_CUSTOM_JSON
namespace detail {
detail::json JsonFromString(const char *s) {
#ifdef TINYGLTF_USE_RAPIDJSON
@@ -7034,6 +7046,7 @@ void JsonReserveArray(detail::json &o, size_t s) {
(void)(s);
}
} // namespace detail
#endif // !TINYGLTF_USE_CUSTOM_JSON
// typedef std::pair<std::string, detail::json> json_object_pair;

1647
tinygltf_json.h Normal file

File diff suppressed because it is too large Load Diff