Compare commits

...

175 Commits

Author SHA1 Message Date
Syoyo Fujita
b3e0d78bf9 Add CMake test target and fix Windows test failure
- Add TINYGLTF_BUILD_TESTS option to build unit tests via CMake
- Test runs from tests/ directory so relative paths work correctly
- Fix Windows file sharing violation in images-as-is test by closing
  fstream before stbi_load attempts to open the same file

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 04:45:27 +09:00
Syoyo Fujita
280986940b Merge pull request #528 from syoyo/copilot/add-copilot-review-instructions
Add Copilot review instructions for code quality and security checks
2026-02-03 08:55:23 +09:00
copilot-swe-agent[bot]
55930ff737 Add Copilot review instructions for tinygltf repository
Co-authored-by: syoyo <18676+syoyo@users.noreply.github.com>
2026-02-02 23:48:15 +00:00
copilot-swe-agent[bot]
d8a00f0f4e Initial plan 2026-02-02 23:46:46 +00:00
Syoyo Fujita
488a70a3df Merge branch 'release' of github.com:syoyo/tinygltf into release 2025-11-02 10:11:11 +09:00
Syoyo Fujita
148ed6c507 Update the usage code: https://github.com/syoyo/tinygltf/pull/524 2025-11-02 10:10:11 +09:00
Syoyo Fujita
f996e3b092 Merge pull request #525 from nyalldawson/performance
Minor performance fixes
2025-11-02 10:08:23 +09:00
Nyall Dawson
f9f49d355d Fix some 'use of auto that causes a copy' warnings 2025-10-31 08:44:42 +10:00
Nyall Dawson
c61ab2c7bb Fix some variable copied when could be moved warnings 2025-10-31 08:44:26 +10:00
Syoyo Fujita
26422192e2 Merge pull request #517 from nepp95/release
Removed TINYGLTF_USE_CPP14 option since it is unused
2025-05-20 06:31:38 +09:00
Niels Eppenhof
77fec96878 Removed TINYGLTF_USE_CPP14 option since it is unused 2025-05-19 14:58:41 +02:00
Syoyo Fujita
4b7e16741d Merge pull request #516 from DrQuackeroo/c24695-fix
Initialize Accessor::Sparse members to default values
2025-05-06 09:14:08 +09:00
Sammy Newhide
213dcc7919 Revert e957334 by adding default constructor for Accessor 2025-05-05 17:04:52 -07:00
Sammy Newhide
e9573349e7 Remove explicit default constructor for Accessor
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-05-05 16:43:20 -07:00
Sammy Newhide
8a319d3efc Initialize Accessor::Sparse members to default values 2025-05-05 15:20:30 -07:00
Syoyo Fujita
b956fa3e9d Merge pull request #512 from ctrlaltf2/oob-fix
Add bounds check to images loaded from bufferviews
2025-01-22 22:45:07 +09:00
ctrlaltf2
baa70db5a8 Add bounds check to images loaded from bufferviews 2025-01-20 23:43:07 -05:00
Syoyo Fujita
5f330f3952 Merge pull request #509 from NoirMorilec/fix-no-fs
Added NO_FS definition for std::ofstream usage
2024-12-30 22:11:09 +09:00
Leonid
5d7fa94a4b Added NO_FS definition for std::ofstream usage 2024-12-30 03:12:20 +08:00
Syoyo Fujita
a93facf9b2 Merge pull request #507 from thearchivalone/release
Documentation: Submodule hint added
2024-12-21 19:59:42 +09:00
Brad
0c4b226f1f Documentation: Submodule hint added 2024-12-20 17:49:51 -06:00
Syoyo Fujita
2d31d6fe74 Merge pull request #504 from nim65s/vendor 2024-10-16 23:27:42 +09:00
Syoyo Fujita
50a29a6cf6 Merge pull request #503 from nim65s/release 2024-10-16 23:26:53 +09:00
Guilhem Saurel
bf23ecdfe1 CMake: fix export install dir 2024-10-16 15:53:48 +02:00
Guilhem Saurel
ce27d3cb2b CMake: allow opt-out of installing vendored headers 2024-10-16 14:58:42 +02:00
Syoyo Fujita
14ba27113e Merge pull request #501 from msklywenn/release
Fix Animation extensions being loaded in place of Sampler extensions
2024-08-08 21:47:56 +09:00
Daniel Borges
1b983add49 Merge branch 'syoyo:release' into release 2024-08-08 10:25:11 +02:00
Syoyo Fujita
f132d242aa Merge pull request #496 from ptc-tgamper/bug/issue-495
Allow WriteImageDataFunction() callback to be called with empty images
2024-07-26 21:44:16 +09:00
Thomas Gamper
bde9ad61c1 fixes #495
Fix issues that block custom image loaders and writers to deal with empty images
2024-07-23 11:45:54 +02:00
Daniel Borges
314faac311 fixed ParseAnimation loading animation's extensions into sampler instead of sample's extensions. 2024-07-19 12:34:16 +02:00
Syoyo Fujita
3cb2822512 Merge pull request #493 from ptc-tgamper/bug/model_clear_on_load
Properly clear the model before loading
2024-07-06 02:43:52 +09:00
Thomas Gamper
7c16fd3b43 Properly clear the model before loading 2024-07-05 08:57:36 +02:00
Syoyo Fujita
35d3f5ae0a Update README.md 2024-07-04 03:01:46 +09:00
Syoyo Fujita
5a20fbd7f7 Merge pull request #492 from danwillm/inverse-bind-matrix
Make inverseBindMatrices optional
2024-07-04 02:59:35 +09:00
danwillm
0e28f1ef38 Add test for inverse bind matrices being optional 2024-07-01 22:32:17 +01:00
danwillm
54fd914bc1 Make inverseBindMatrices optional 2024-07-01 18:31:00 +01:00
Syoyo Fujita
43055c0ed1 bump minor version. 2024-06-28 21:30:43 +09:00
Syoyo Fujita
953bf8bd1c Merge pull request #491 from ptc-tgamper/bug/image_saving
Fix images not being saved due to missing filesystem callbacks
2024-06-28 21:24:53 +09:00
Thomas Gamper
9cf25ef930 fixes #487
Support image as_is flag in loading and saving
2024-06-28 12:17:38 +02:00
Thomas Gamper
a440b44ef9 fixes #473
tiny_gltf.h - explicitly pass filesystem callbacks to image related functions
tester.cc - add respective test case, fix image uri test case
2024-06-25 15:12:30 +02:00
Syoyo Fujita
efe2957c4a Merge pull request #489 from SeanCurtis-TRI/PR_callback_as_function
Update typedefs of C-style function pointers to std::function
2024-06-12 04:01:37 +09:00
Sean Curtis
4692f7a714 Remove asserts 2024-06-10 14:18:31 -07:00
Sean Curtis
5d1882cf2f Update typedefs of C-style function pointers to std::function
This allows for the callback to maintain their own state (without recourse
to globals).

In addition, added some incidental clean up:

  - URICallback, passed by pointer, is now asserted to be non-null before
    accessing.
  - FSCallbacks are validated when they are set (in debug builds).
2024-06-06 07:45:01 -07:00
Syoyo Fujita
9aa1c3c393 Merge pull request #486 from pmcgvr/release
Fix stripping of slashes from paths
2024-05-24 02:49:22 +09:00
Syoyo Fujita
394c48c25d Merge pull request #485 from bwrsandman/patch-1
msvc 32bit: Fix C4244 warning
2024-05-21 04:11:31 +09:00
Patrick Mc Gartoll
30457a5373 Fix stripping of slashes from paths 2024-05-16 18:11:26 -07:00
Sandy
73b2d0926f msvc 32bit: Fix C4244 warning
On 32 bit msvc compilers with warnings on, there are C4244 warnings about  from 'std::streamoff' to size_t to vector::size_type
2024-05-10 08:47:23 -04:00
Syoyo Fujita
3a65e2ddb8 Merge pull request #482 from jam3sward/fix-c4018-warnings-msvc-win32
Fix C4018 warnings in MSVC on WIN32
2024-03-27 03:43:42 +09:00
jamesvert
8a61c041d5 Resolve overload ambiguity in VS2015 (version 14.0) 2024-03-26 11:32:43 +00:00
jamesvert
c74040e9f0 Fix C4018 warnings in MSVC on WIN32 2024-03-26 11:06:16 +00:00
Syoyo Fujita
223a51270a Merge pull request #481 from jam3sward/fix-c4267-warnings-vs-win32
Fix C4267 warnings in Visual Studio on WIN32
2024-03-26 05:23:03 +09:00
James Ward
d98da79545 Fix C4267 warnings in Visual Studio on WIN32 2024-03-25 17:50:33 +00:00
Syoyo Fujita
26d0bc2e1a Merge pull request #479 from The0Dev/fix_wopen_ronly
Added the pmode argument to _wopen to fix the access permission on MinGW
2024-03-26 02:36:27 +09:00
Syoyo Fujita
b2c885f9c7 Merge pull request #480 from ptc-tgamper/bug/msft_lod_extension_used
Bug/msft lod extension used
2024-03-26 02:35:51 +09:00
Thomas Gamper
8248a41b9e tester.cc - extend MSFT_lod test 2024-03-25 17:01:08 +01:00
Thomas Gamper
eb5d4ade15 tiny_gltf.h - register MSFT_lod with the model's used extensions 2024-03-25 17:00:41 +01:00
TheDev
9f7af47e45 Added the pmode argument to _wopen to fix the access permission on MinGW 2024-03-25 18:21:20 +03:00
Syoyo Fujita
b7f07dc946 Merge pull request #475 from jam3sward/issue-474
M_PI was not defined by <cmath>
2024-03-20 21:11:56 +09:00
James Ward
e3b6789a7c M_PI was not defined by <cmath> 2024-03-19 19:06:19 +00:00
Syoyo Fujita
d9c2bbe90c Merge pull request #471 from ptc-tgamper/ftr/msft_lods
[Feature] Add basic support for MSFT_lod extension
2024-02-06 23:22:38 +09:00
Thomas Gamper
b8366a1c4b tester.cc - add test case for the crash fix in KHR_audio node serialization 2024-02-06 14:48:58 +01:00
Thomas Gamper
ec027b581b tester.cc - add MSFT_lods test case 2024-02-05 17:03:16 +01:00
Thomas Gamper
6bfcb71a0c tiny_gltf.h - add/remove MSFT_extension as required 2024-02-05 16:50:46 +01:00
Thomas Gamper
90e2995bad tiny_gltf.h - parse node and material lods 2024-02-05 15:42:49 +01:00
Syoyo Fujita
ffa2c665f9 Allow zero-sized BIN chunk. Fixes #440 2024-01-24 05:43:27 +09:00
Syoyo Fujita
29cfe103f8 Deprecate Travis CI and remove Travis CI scripts. Fixes #439 2023-12-11 21:00:35 +09:00
Syoyo Fujita
1f91e9b662 Merge pull request #467 from rhiskey/release
Small security and overflow patch
2023-12-05 06:42:19 +09:00
rhiskey
4df21f6df6 Update stb_image_write.h
Provided `sizeof(buffer)` in `sptintf`
2023-12-05 00:28:18 +03:00
rhiskey
ae7b113cad Revert back stb_image_write.h to original code 2023-12-05 00:21:41 +03:00
rhiskey
359cf50a0f Update stb_image_write.h
Fixed case when  `__STDC_LIB_EXT1__ ` is not defined - for Linux, etc. According to the C99 standart @syoyo
2023-12-05 00:15:50 +03:00
rhiskey
cf55186b0b Update tiny_gltf.h
Removed `#undef` 
and used the @syoyo method:

https://github.com/syoyo/tinygltf/pull/467#issuecomment-1838703699
2023-12-04 17:11:59 +03:00
rhiskey
808ab042e9 Update tiny_gltf.h
Fixed `Windows.h` MINMAX error and reverted to original numeric limits of type `uint32_t`
2023-12-04 16:57:36 +03:00
rhiskey
aa2fb04ab7 Merge branch 'syoyo:release' into release 2023-12-04 16:55:16 +03:00
Syoyo Fujita
354c1146ee Fix possible nullptr dereferencing.
Add missing `return false`
2023-12-04 22:50:49 +09:00
rhiskey
a68be31c9d Update stb_image_write.h
Securing printing output via `sprintf_s` instead `sprintf`.
2023-12-04 14:22:14 +03:00
rhiskey
46fd11cef1 Update tiny_gltf.h
Fix max size of `header_and_json_size` limit.
In case of 4GB will check ` sizeof(uint64_t)` insted deprecated max
2023-12-04 14:21:06 +03:00
Syoyo Fujita
fb3ff961f8 Merge pull request #465 from ptc-tgamper/bug/issue464
Fix Empty scenes are wrongly serialized as null Issue #464
2023-11-23 23:28:39 +09:00
Thomas Gamper
cef28f1791 Fix #464
tinygltf.h - serialize empty scenes as empty json objects; tester.cc - ad respective test case, bring test cases in correct order, tag test case for light index with correct issue number and fix it to compare to deserialozed model
2023-11-23 15:14:46 +01:00
Syoyo Fujita
cb4dcef520 Merge pull request #463 from ptc-tgamper/bug/issue458
Fix Light reference in the node issue #457
2023-11-23 22:19:05 +09:00
Thomas Gamper
46a1e426d1 fix #457
tiny_gltf.h - access correct json object when serializing a light, this fixes an assert and causes us to serialze the light index properly; tester.cc - add respective testcase
2023-11-23 14:13:12 +01:00
Syoyo Fujita
f54bbd847e Merge pull request #462 from ptc-tgamper/bug/issue457
Fix Empty nodes are wrongly serialized as null Issue #457
2023-11-23 21:52:47 +09:00
Thomas Gamper
439d103665 fix #457
tiny_gltf.h - make sure to serialize null node as empty object; tester.cc - add respective test case
2023-11-23 11:59:18 +01:00
Syoyo Fujita
a65d2d6de1 Merge pull request #460 from ptc-tgamper/bug/issue459
Fix Default constructed Material has wrong emissiveFactor #459
2023-11-23 02:21:28 +09:00
Thomas Gamper
d66d9d291b fix #459
tiny_gltf.h - use member initialization
2023-11-22 15:59:13 +01:00
Thomas Gamper
925d783330 fix #459
tiny_gltf.h - properly initialise emissiveFactor; tests/tester.cc - add test case
2023-11-22 14:17:46 +01:00
Syoyo Fujita
817ce1a9d0 Merge pull request #456 from haroonq/patch-1
Allow BufferView indices to be unspecified.
2023-10-10 21:24:51 +09:00
haroonq
8036d6a00f 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
e525653fbd 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
1fc0f8056d Fix incorrect component type shown in warning message 2023-09-12 08:46:14 +10:00
Syoyo Fujita
d7449cc0d6 Remove unused code. Fixes #454 2023-09-07 22:03:46 +09:00
Syoyo Fujita
616604c5c5 Merge pull request #453 from nyalldawson/fix_draco
Fix build with draco
2023-09-07 21:35:55 +09:00
Nyall Dawson
7db1b126b8 Fix build with draco 2023-09-07 08:20:28 +10:00
Syoyo Fujita
9f4ac79720 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
e387e3a221 Relax bin chunk end alignment check in permissive mode 2023-09-07 07:08:26 +10:00
Syoyo Fujita
0e5a1c9be9 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
7f514ca27b Fix msvc build -- STRICT is a msvc macro name 2023-09-07 06:28:37 +10:00
Syoyo Fujita
706cfb4cde Merge pull request #451 from nyalldawson/mingw
Add mingw msys2 workflow
2023-09-06 20:55:14 +09:00
Nyall Dawson
b4e5d07c9f Add mingw msys2 workflow 2023-09-06 08:26:34 +10:00
Nyall Dawson
2aad0ce782 Fix warning when building without draco support 2023-09-03 09:04:56 +10:00
Syoyo Fujita
9977c05b4b 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
7b2ae68239 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
8b24ce8f3a Consistently use size_t for all byteOffset's 2023-09-02 09:39:53 +02:00
Nyall Dawson
3cf58eef43 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
7dc9766ce1 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
Syoyo Fujita
c94ffcfeb7 Merge pull request #445 from nyalldawson/permissive
Be tolerant when encountering emissiveFactor with array length 4
2023-09-01 23:10:29 +09:00
Nyall Dawson
285e87211c Add method to set parsing strictness 2023-08-28 12:56:09 +10:00
Nyall Dawson
e65694cc7d Raise a warning when encountering emissiveFactor with array length
of 4 instead of aborting the model loading
2023-08-28 12:46:44 +10:00
Syoyo Fujita
5d3c322e89 Merge pull request #446 from nyalldawson/fix_error
Fix misleading error message
2023-08-24 22:11:50 +09:00
Nyall Dawson
6c6e131792 Fix misleading error message
Avoids a confusing "Must have 4 bytes or more bytes, but got 4."
error.
2023-08-24 11:48:09 +10:00
Syoyo Fujita
c015b60ddd Merge pull request #442 from turanszkij/release-1
added project link to readme
2023-08-07 18:32:30 +09:00
Turánszki János
9b5fe332a2 added project link to readme 2023-08-07 06:59:35 +02:00
Syoyo Fujita
737a0b57c6 Merge pull request #433 from dyollb/modernize
Modernize
2023-07-11 19:43:53 +09:00
Syoyo Fujita
fe42a91023 Merge pull request #436 from dimitri-tdg/bugfix_extensions_primitive
Fix issue when serializing extensions of a primitive
2023-07-10 23:30:40 +09:00
KUDELSKI Dimitri
ebbcdf999f Fix issue when serializing extensions of a primitive 2023-07-10 15:13:09 +02:00
Syoyo Fujita
64a818821e Merge pull request #435 from RE-Kovalev/release
MinGW _wfopen_s fix
2023-07-05 18:41:22 +09:00
R.E. Kovalev
7979314811 MinGW _wfopen_s fix 2023-07-05 09:11:57 +03:00
Bryn Lloyd
879cf43bab cppcoreguidelines-prefer-member-initializer 2023-06-21 22:30:14 +02:00
Bryn Lloyd
0817693edd modernize-use-equals-default 2023-06-21 22:15:49 +02:00
Bryn Lloyd
4f9e144547 readability-redundant-string-init 2023-06-21 18:42:24 +02:00
Bryn Lloyd
210d56b07f modernize-use-default-member-init 2023-06-21 18:40:18 +02:00
Bryn Lloyd
d955fd38e7 minor cleanup of cmakelists 2023-06-21 18:26:43 +02:00
Syoyo Fujita
927457b104 Initialize light and emitter members. Fixes #431
Include `light` and `emitter` comparison in Node::operator==()
2023-06-19 21:52:13 +09:00
Syoyo Fujita
1fcfcaeaca Merge pull request #429 from AdamFull/release
KHR_audio parsing support (ASCII only)
2023-06-13 21:40:45 +09:00
Baranob_Ilya
f082c5d6b3 Added parsing and serializing of audio emitters for scene (global sources) 2023-06-12 13:35:05 +04:00
Baranob_Ilya
d5c7d72786 Forgot to add KHR_audio to used extensions 2023-06-12 12:34:34 +04:00
Baranob_Ilya
b4729fe0be Update .gitignore 2023-06-12 12:30:04 +04:00
Baranob_Ilya
b1309d47a8 Added KHR_audio extension. Parsing and serialization.
Added KHR_audio extension parsing and serializing. Only for ascii
2023-06-12 10:43:52 +04:00
Syoyo Fujita
c656765f4d Merge pull request #426 from agnat/serialize_light_refs
KHR_lights_punctual: Serialize node light refs
2023-06-09 05:03:01 +09:00
David Siegel
75bf1532ee clean up 2023-06-07 15:35:35 +02:00
David Siegel
29107bbcc6 fix syntax error 2023-06-07 15:30:02 +02:00
David Siegel
9bbc79e27e KHR_lights_punctual: Serialize node light refs
This is surprisingly involved:

1. Add non-const json iterators, FindMember(…) and GetValue(…)
2. Add json utilities IsEmpty(…) and Erase(…)
3. Serialize the property and clean up
2023-06-07 15:18:38 +02:00
Syoyo Fujita
2dfc7eb661 Merge pull request #422 from agnat/fix/add_missing_extras_and_extensions
Add missing extras and extensions fields
2023-06-07 02:47:59 +09:00
Syoyo Fujita
3246fa4d8c Merge pull request #423 from agnat/finish_KHR_lights_puncutal
KHR_lights_punctual: parse light source references from scene nodes
2023-06-06 23:12:50 +09:00
Syoyo Fujita
2b5e669ac1 Merge pull request #424 from agnat/rewrite_ForEachInArray
get rid of std::function
2023-06-06 23:11:12 +09:00
David Siegel
db9ec34b4e refactor extension and extra serialization
Add missing serialization:

accessor.extensions
accessor.sparse.extensions
accessor.sparse.extras
accessor.sparse.indices.extensions
accessor.sparse.indices.extras
accessor.sparse.values.extensions
accessor.sparse.values.extras
animation.channel.target.extras
animation.sampler.extensions
buffer.extensions
bufferView.extensions
sampler.extensions
camera.orthographic.extensions
camera.perspective.extensions
skin.extras
skin.extensions
2023-06-06 15:40:29 +02:00
David Siegel
a782975b74 rewrite ForEachInArray as a simple C++11 function
no need for std::function here. A free function with an unspecified callback will do nicely.
2023-06-06 15:36:07 +02:00
David Siegel
41c3ed9b0e fix: add missing nullptr check 2023-06-06 15:31:58 +02:00
David Siegel
8c3bf572db parse light source references 2023-06-06 06:18:14 +02:00
David Siegel
b875b65987 Add missing extras and extensions fields
Handle extras and extensions in nested “sub-objects”:

animation.channel.target.extras
accessor.sparse.extras
accessor.sparse.extensions
accessor.sparse.indices.extras
accessor.sparse.indices.extensions
accessor.sparse.values.extras
accessor.sparse.values.extensions
2023-06-06 00:07:37 +02:00
David Siegel
6e768f27c9 remove duplicate code
use a function to parse extras and extensions
2023-06-06 00:07:37 +02:00
David Siegel
0037b05e18 fix warnings: unused variable 2023-06-06 00:07:37 +02:00
Syoyo Fujita
c0cde4de4a Simplify version comment in tiny_gltf.h
Remove wuffs code(which was accidently adde to `release` branch)
2023-06-04 19:07:00 +09:00
Syoyo Fujita
d96d324975 Prevent duplicated key generation when serializing lights + RapidJSON backend. Fixes #420 2023-06-04 05:45:24 +09:00
Syoyo Fujita
3abcc4c5fd Merge pull request #418 from agnat/fix_get_file_size_bug
[Bugfix] Actually invoke the user-supplied function instead of subtracting from a pointer...
2023-04-26 19:28:58 +09:00
David Siegel
81b27d8491 Fix: Actually invoke the user-supplied function 2023-04-26 12:13:41 +02:00
Syoyo Fujita
011eb1be6c Merge pull request #417 from syoyo/filesize-check
Fix to #416
2023-04-23 23:15:07 +09:00
Syoyo Fujita
8ead2d8ad9 Fix MSVC compile failure on AppVeyor CI. 2023-04-23 23:08:41 +09:00
Syoyo Fujita
0dfd6e9cdb Format error message.
Add regression test of issue-416.
2023-04-23 21:47:31 +09:00
Syoyo Fujita
1a4bd46e16 Fix syntax. 2023-04-23 21:40:23 +09:00
Syoyo Fujita
8997b0ce35 - Add GetFileSizeInBytes Filesystem Callback
- Add feature to limit file size for external resources(images, buffers)
- Use strlen to correctly retrieve a string from a string which contains multiple null-characters.
- Return fail when opening a directory(Posix only). Fixes #416
2023-04-23 21:31:30 +09:00
Syoyo Fujita
753576f817 Merge pull request #415 from louwaque/release
Fix serialization of AnimationChannel::target_node when it is zero
2023-04-19 05:17:06 +09:00
Loïc Escales
578c518fd0 Fix serialization of AnimationChannel::target_node when it is zero 2023-04-18 21:03:39 +02:00
Syoyo Fujita
e2ade37808 Merge pull request #412 from agnat/add_char_pointer_ctor
Fix #411 by adding a Value(const char *) constructor.
2023-04-10 19:11:35 +09:00
Syoyo Fujita
8c8f9bc243 Deprecate ubuntu-18.04 image and update CI build configuration. 2023-04-10 18:51:29 +09:00
David Siegel
1a31f42a98 Fix #411 by adding a Value(const char *) constructor.
Avoid implicit conversion of pointers to bool. Closes #411.
2023-04-08 23:44:53 +02:00
Syoyo Fujita
0a9ba62baa Merge pull request #409 from NeilBickford-NV/nbickford/update-stb-image
Updates stb_image and stb_image_write
2023-03-30 18:13:12 +09:00
Neil Bickford
3a11ec3bbc stb_image: Apply https://github.com/nothings/stb/pull/1443 2023-03-29 12:00:24 -07:00
Neil Bickford
cc18aed49d stb_image: Apply https://github.com/nothings/stb/pull/1454 2023-03-29 11:57:27 -07:00
Neil Bickford
7f6bcba697 Update stb_image and stb_image_write to latest nothings/stb dev branch: 9f1776a36d 2023-03-29 11:56:13 -07:00
Syoyo Fujita
c0967f718d Merge pull request #408 from marco-langer/feature/ostream_error_handling
Added error checking to ostream writing
2023-03-13 21:18:02 +09:00
Marco Langer
3add08b761 Added error handling to ostream writing 2023-03-12 19:26:05 +01:00
Syoyo Fujita
d171eee434 Merge pull request #407 from DavidSM64/release
Added detail namespace to prevent json namespace conflicts
2023-02-19 02:08:19 +09:00
David
4562a88070 Fixed global namespace issue 2023-02-15 23:35:51 -06:00
David
032351882c Fix RapidJSON implementation (hopefully) 2023-02-15 23:21:09 -06:00
David
60831b59de Added detail namespace to prevent namespace conflicts 2023-02-15 22:56:18 -06:00
Syoyo Fujita
b18b0024c1 Merge pull request #405 from tioez326/patch-2
Fix typo
2023-02-10 21:00:27 +09:00
tioez326
165df4c474 Fix typo 2023-02-10 12:09:12 +01:00
Syoyo Fujita
9dc44e5389 Update README.md 2023-01-16 05:46:11 +09:00
Syoyo Fujita
b3c071d103 Merge pull request #401 from jmousseau/animation-channel-node-optionality
Fix animation channel target node optionality
2023-01-16 05:33:40 +09:00
Jack Mousseau
ca8d44bcc7 Fix animation channel target node optionality 2023-01-15 11:45:45 -08:00
Syoyo Fujita
041356d019 v2.8.1 2023-01-13 18:15:21 +09:00
Syoyo Fujita
48fbd4e223 Merge pull request #399 from e2e4e6/texture_sampler_name_fix
Missed serialization texture sampler name fixed.
2023-01-13 18:13:12 +09:00
s00665032
1fa71c34f8 Missed serialization texture sampler name fixed.
According to the glTF 2.0 specification it exists, the internal tinygltf structure contains 'name' field as well.
2023-01-13 12:52:08 +07:00
Syoyo Fujita
22bc14c27e Merge pull request #398 from nicolas-raoul/patch-1
Fixed typo
2023-01-12 16:21:35 +09:00
Nicolas Raoul
52fbd461a3 Fixed typo 2023-01-12 15:29:32 +09:00
18 changed files with 3958 additions and 2054 deletions

View File

@@ -0,0 +1,92 @@
# Copilot Review Instructions for TinyGLTF
This document provides guidelines for reviewing code changes in the TinyGLTF repository.
## Memory Safety
- **Buffer Overflows**: Check for proper bounds checking when accessing arrays, vectors, and buffers. Verify that buffer sizes are validated before read/write operations.
- **Null Pointer Dereferences**: Ensure all pointers are checked for null before dereferencing, especially when handling optional glTF fields.
- **Memory Leaks**: Verify proper resource management, including RAII patterns for file handles, image data, and dynamically allocated memory.
- **Use-After-Free**: Check for proper lifetime management of objects, especially when dealing with callbacks and asynchronous operations.
## Error Handling
- **File I/O**: Verify that all file operations have proper error checking and meaningful error messages.
- **JSON Parsing**: Ensure JSON parsing errors are caught and reported with helpful context about the location and nature of the error.
- **Resource Loading**: Check that failures in loading images, buffers, and other resources are properly handled and don't cause crashes.
- **Error Propagation**: Verify that errors are properly propagated through the call stack with appropriate error messages.
## glTF 2.0 Specification Compliance
- **Required Fields**: Ensure all required glTF fields are validated and present.
- **Data Types**: Verify that data types match the glTF specification (e.g., component types, accessor types).
- **Constraints**: Check that glTF constraints are enforced (e.g., valid ranges for enums, buffer stride requirements).
- **Extensions**: Verify proper handling of glTF extensions and that unknown extensions are handled gracefully.
- **Validation**: Ensure new features align with the glTF 2.0 specification from the Khronos Group.
## Cross-Platform Compatibility
- **Windows**: Check for proper handling of Windows-specific issues (path separators, line endings, file operations).
- **Linux**: Verify compatibility with various Linux distributions and compilers (GCC, Clang).
- **macOS**: Ensure macOS-specific considerations are addressed (case-sensitive filesystems, Clang compatibility).
- **Mobile Platforms**: Consider Android and iOS compatibility where applicable.
- **Endianness**: Verify proper handling of byte order when reading binary data.
- **Compiler Compatibility**: Ensure code compiles with C++11 standard and supported compilers (MSVC, GCC, Clang).
## Edge Cases in glTF Parsing
- **Empty/Minimal Files**: Verify handling of minimal valid glTF files.
- **Large Files**: Check for proper handling of large glTF files and buffers without memory exhaustion.
- **Malformed Data**: Ensure graceful handling of malformed or invalid glTF data.
- **Missing Optional Fields**: Verify correct behavior when optional glTF fields are absent.
- **Edge Values**: Check handling of boundary values (e.g., maximum buffer sizes, extreme floating-point values).
- **Base64 Encoding**: Verify proper handling of base64-encoded data URIs and invalid encodings.
## Backwards Compatibility
- **API Changes**: Ensure public API changes maintain backwards compatibility or are properly deprecated.
- **Breaking Changes**: Flag any breaking changes for major version updates and document migration paths.
- **Binary Compatibility**: Consider ABI stability for header-only library changes.
- **Default Behavior**: Verify that default behavior of existing functionality remains unchanged.
## Performance Considerations
- **Parsing Performance**: Check for unnecessary copies, redundant allocations, and inefficient algorithms in parsing logic.
- **Memory Usage**: Verify efficient memory usage, especially when loading large glTF files.
- **I/O Operations**: Ensure efficient file reading and minimize unnecessary disk access.
- **String Operations**: Check for efficient string handling (use of string_view, move semantics).
- **STL Usage**: Verify appropriate use of STL containers and algorithms.
## Documentation
- **Public API**: Ensure all public functions, classes, and methods have clear documentation comments.
- **Parameters**: Verify that function parameters are documented, including expected ranges and constraints.
- **Return Values**: Document return values and possible error conditions.
- **Examples**: Check that complex features include usage examples.
- **Changelog**: Verify that significant changes are documented in release notes or changelog.
## Testing
- **Test Coverage**: Ensure new features include appropriate unit tests or integration tests.
- **Edge Cases**: Verify that tests cover edge cases and error conditions.
- **Cross-Platform Tests**: Check that tests run on all supported platforms.
- **Regression Tests**: Ensure bug fixes include regression tests to prevent recurrence.
- **Sample Files**: Verify that changes are tested with various valid and invalid glTF sample files.
## Code Style Consistency
- **Header-Only Pattern**: Maintain the header-only library structure.
- **Naming Conventions**: Follow existing naming conventions (CamelCase for types, snake_case for functions where applicable).
- **Formatting**: Adhere to the existing code formatting style (check `.clang-format` if available).
- **Include Guards**: Verify proper include guards and header organization.
- **Namespace Usage**: Ensure proper use of the `tinygltf` namespace.
- **Comments**: Maintain consistent comment style with existing code.
- **C++11 Compliance**: Verify that code uses C++11 features appropriately and doesn't require newer standards unless specified.
## Additional Considerations
- **Third-Party Dependencies**: Minimize new dependencies; prefer existing dependencies (json.hpp, stb_image).
- **Warnings**: Ensure code compiles without warnings on supported compilers.
- **const Correctness**: Verify proper use of const for parameters and methods.
- **RAII**: Prefer RAII patterns for resource management over manual cleanup.
- **noexcept**: Use noexcept appropriately for move constructors and move assignment operators.

View File

@@ -4,41 +4,43 @@ on: [push, pull_request]
jobs:
# compile with older gcc4.8
build-gcc48:
# gcc4.8 is too old and ubuntu-18.04 image is not supported in GitHub Actions anymore,
# so disable this build.
## compile with older gcc4.8
#build-gcc48:
runs-on: ubuntu-18.04
name: Build with gcc 4.8
# runs-on: ubuntu-18.04
# name: Build with gcc 4.8
steps:
- name: Checkout
uses: actions/checkout@v1
# steps:
# - name: Checkout
# uses: actions/checkout@v1
- name: Build
run: |
sudo apt-get update
sudo apt-get install -y build-essential
sudo apt-get install -y gcc-4.8 g++-4.8
g++-4.8 -std=c++11 -o loader_example loader_example.cc
# - name: Build
# run: |
# sudo apt-get update
# sudo apt-get install -y build-essential
# sudo apt-get install -y gcc-4.8 g++-4.8
# g++-4.8 -std=c++11 -o loader_example loader_example.cc
- name: NoexceptBuild
run: |
g++-4.8 -DTINYGLTF_NOEXCEPTION -std=c++11 -o loader_example loader_example.cc
# - name: NoexceptBuild
# run: |
# g++-4.8 -DTINYGLTF_NOEXCEPTION -std=c++11 -o loader_example loader_example.cc
- name: RapidjsonBuild
run: |
git clone https://github.com/Tencent/rapidjson
g++-4.8 -DTINYGLTF_USE_RAPIDJSON -I./rapidjson/include/rapidjson -std=c++11 -o loader_example loader_example.cc
# - name: RapidjsonBuild
# run: |
# git clone https://github.com/Tencent/rapidjson
# g++-4.8 -DTINYGLTF_USE_RAPIDJSON -I./rapidjson/include/rapidjson -std=c++11 -o loader_example loader_example.cc
# compile with mingw gcc cross
build-mingw-cross:
runs-on: ubuntu-18.04
runs-on: ubuntu-latest
name: Build with MinGW gcc cross
steps:
- name: Checkout
uses: actions/checkout@v1
uses: actions/checkout@v2
- name: Build
run: |
@@ -133,20 +135,20 @@ jobs:
# Cross-compile for aarch64 linux target
build-cross-aarch64:
runs-on: ubuntu-18.04
runs-on: ubuntu-latest
name: Build on cross aarch64
steps:
- name: Checkout
uses: actions/checkout@v1
uses: actions/checkout@v2
- name: Build
run: |
sudo apt-get update
sudo apt-get install -y build-essential
sudo apt-get install -y gcc-8-aarch64-linux-gnu g++-8-aarch64-linux-gnu
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
git clone https://github.com/Tencent/rapidjson
aarch64-linux-gnu-g++-8 -DTINYGLTF_USE_RAPIDJSON -I./rapidjson/include/rapidjson -std=c++11 -g -O0 -o loader_example loader_example.cc
aarch64-linux-gnu-g++ -DTINYGLTF_USE_RAPIDJSON -I./rapidjson/include/rapidjson -std=c++11 -g -O0 -o loader_example loader_example.cc
# macOS clang
build-macos:

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

1
.gitignore vendored
View File

@@ -24,6 +24,7 @@ premake5.tar.gz
#binary directories
bin/
obj/
out/
#runtime gui config
imgui.ini

View File

@@ -1,10 +0,0 @@
#!/bin/bash
if [[ "$TRAVIS_OS_NAME" == "osx" ]]
then
brew upgrade
curl -o premake5.tar.gz https://github.com/premake/premake-core/releases/download/v5.0.0-alpha12/premake-5.0.0-alpha12-macosx.tar.gz
else
wget https://github.com/premake/premake-core/releases/download/v5.0.0-alpha12/premake-5.0.0-alpha12-linux.tar.gz -O premake5.tar.gz
fi
tar xzf premake5.tar.gz

View File

@@ -1,63 +0,0 @@
language: cpp
sudo: false
matrix:
include:
- addons: &1
apt:
sources:
- george-edison55-precise-backports
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-3.9
packages:
- g++-4.9
- clang-3.9
compiler: clang
env: COMPILER_VERSION=3.9 BUILD_TYPE=Debug
- addons: *1
compiler: clang
env: COMPILER_VERSION=3.9 BUILD_TYPE=Release
- addons: &2
apt:
sources:
- george-edison55-precise-backports
- ubuntu-toolchain-r-test
packages:
- g++-4.9
compiler: gcc
env: COMPILER_VERSION=4.9 BUILD_TYPE=Debug EXTRA_CXXFLAGS="-fsanitize=address"
- addons: *2
compiler: gcc
env: COMPILER_VERSION=4.9 BUILD_TYPE=Release EXTRA_CXXFLAGS="-fsanitize=address"
- addons: *1
compiler: clang
env: COMPILER_VERSION=3.9 BUILD_TYPE=Debug CFLAGS="-O0" CXXFLAGS="-O0"
- addons: &3
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.8
compiler: gcc
env: COMPILER_VERSION=4.8 BUILD_TYPE=Debug
- addons: *3
compiler: gcc
env: COMPILER_VERSION=4.8 BUILD_TYPE=Release
before_install:
- ./.travis-before-install.sh
script:
- export CC="${CC}-${COMPILER_VERSION}"
- export CXX="${CXX}-${COMPILER_VERSION}"
- ${CC} -v
- ${CXX} ${EXTRA_CXXFLAGS} -std=c++11 -Wall -g -o loader_example loader_example.cc
- ./loader_example ./models/Cube/Cube.gltf
- cd tests
- clang++ -v
- make
- ./tester
- ./tester_noexcept
- cd ../examples/raytrace
- ../../premake5 gmake
- make

View File

@@ -1,38 +1,53 @@
cmake_minimum_required(VERSION 3.6)
PROJECT (tinygltf)
project(tinygltf)
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
SET(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED On)
set(CMAKE_CXX_EXTENSIONS Off)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
option(TINYGLTF_BUILD_LOADER_EXAMPLE "Build loader_example(load glTF and dump infos)" ON)
option(TINYGLTF_BUILD_GL_EXAMPLES "Build GL exampels(requires glfw, OpenGL, etc)" OFF)
option(TINYGLTF_BUILD_VALIDATOR_EXAMPLE "Build validator exampe" OFF)
option(TINYGLTF_BUILD_BUILDER_EXAMPLE "Build glTF builder example" OFF)
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)
if (TINYGLTF_BUILD_LOADER_EXAMPLE)
ADD_EXECUTABLE ( loader_example
add_executable(loader_example
loader_example.cc
)
endif (TINYGLTF_BUILD_LOADER_EXAMPLE)
if (TINYGLTF_BUILD_GL_EXAMPLES)
ADD_SUBDIRECTORY ( examples/gltfutil )
ADD_SUBDIRECTORY ( examples/glview )
add_subdirectory( examples/gltfutil )
add_subdirectory( examples/glview )
endif (TINYGLTF_BUILD_GL_EXAMPLES)
if (TINYGLTF_BUILD_VALIDATOR_EXAMPLE)
ADD_SUBDIRECTORY ( examples/validator )
add_subdirectory( examples/validator )
endif (TINYGLTF_BUILD_VALIDATOR_EXAMPLE)
if (TINYGLTF_BUILD_BUILDER_EXAMPLE)
ADD_SUBDIRECTORY ( examples/build-gltf )
add_subdirectory ( examples/build-gltf )
endif (TINYGLTF_BUILD_BUILDER_EXAMPLE)
if (TINYGLTF_BUILD_TESTS)
enable_testing()
add_executable(tester tests/tester.cc)
target_include_directories(tester PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/tests
)
add_test(NAME tester COMMAND tester WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests)
endif (TINYGLTF_BUILD_TESTS)
#
# for add_subdirectory and standalone build
#
@@ -58,19 +73,26 @@ endif (TINYGLTF_HEADER_ONLY)
if (TINYGLTF_INSTALL)
install(TARGETS tinygltf EXPORT tinygltfTargets)
install(EXPORT tinygltfTargets NAMESPACE tinygltf:: FILE TinyGLTFTargets.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake)
install(EXPORT tinygltfTargets NAMESPACE tinygltf:: FILE TinyGLTFTargets.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/tinygltf)
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/TinyGLTFConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/TinyGLTFConfig.cmake INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/TinyGLTFConfig.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/TinyGLTFConfig.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/tinygltf)
# Do not install .lib even if !TINYGLTF_HEADER_ONLY
INSTALL ( FILES
json.hpp
stb_image.h
stb_image_write.h
tiny_gltf.h
${TINYGLTF_EXTRA_SOUECES}
DESTINATION
include
)
if(TINYGLTF_INSTALL_VENDOR)
INSTALL ( FILES
json.hpp
stb_image.h
stb_image_write.h
DESTINATION
include
)
endif()
endif(TINYGLTF_INSTALL)

View File

@@ -2,14 +2,14 @@
`TinyGLTF` is a header only C++11 glTF 2.0 https://github.com/KhronosGroup/glTF library.
`TinyGLTF` uses Niels Lohmann's json library(https://github.com/nlohmann/json), so now it requires C++11 compiler.
`TinyGLTF` uses Niels Lohmann's json library (https://github.com/nlohmann/json), so now it requires C++11 compiler.
(Also, you can use RadpidJSON as an JSON backend)
If you are looking for old, C++03 version, please use `devel-picojson` branch(but not maintained anymore).
If you are looking for old, C++03 version, please use `devel-picojson` branch (but not maintained anymore).
## Status
Currently TinyGLTF is stable and maintainance mode. No drastic changes and feature additions planned.
Currently TinyGLTF is stable and maintenance mode. No drastic changes and feature additions planned.
- v2.9.0 Various fixes and improvements. Filesystem callback API change.
- v2.8.0 Add URICallbacks for custom URI handling in Buffer and Image. PR#397
- v2.7.0 Change WriteImageDataFunction user callback function signature. PR#393
- v2.6.0 Support serializing sparse accessor(Thanks to @fynv).
@@ -26,8 +26,6 @@ Currently TinyGLTF is stable and maintainance mode. No drastic changes and featu
## Builds
[![Build Status](https://travis-ci.org/syoyo/tinygltf.svg?branch=devel)](https://travis-ci.org/syoyo/tinygltf)
[![Build status](https://ci.appveyor.com/api/projects/status/warngenu9wjjhlm8?svg=true)](https://ci.appveyor.com/project/syoyo/tinygltf)
![C/C++ CI](https://github.com/syoyo/tinygltf/workflows/C/C++%20CI/badge.svg)
@@ -106,9 +104,10 @@ WASI build example is located in [wasm](wasm) .
* [GlslViewer](https://github.com/patriciogonzalezvivo/glslViewer) - live GLSL coding for MacOS and Linux
* [Vulkan-Samples](https://github.com/KhronosGroup/Vulkan-Samples) - The Vulkan Samples is collection of resources to help you develop optimized Vulkan applications.
* [TDME2](https://github.com/andreasdr/tdme2) - TDME2 - ThreeDeeMiniEngine2 is a lightweight 3D engine including tools suited for 3D game development using C++11
* [SanityEngine](https://github.com/DethRaid/SanityEngine) - A C++/D3D12 renderer focused on the personal and proessional development of its developer
* [SanityEngine](https://github.com/DethRaid/SanityEngine) - A C++/D3D12 renderer focused on the personal and professional development of its developer
* [Open3D](http://www.open3d.org/) - A Modern Library for 3D Data Processing
* [Supernova Engine](https://github.com/supernovaengine/supernova) - Game engine for 2D and 3D projects with Lua or C++ in data oriented design.
* [Wicked Engine<img src="https://github.com/turanszkij/WickedEngine/blob/master/Content/logo_small.png" width="28px" align="center"/>](https://github.com/turanszkij/WickedEngine) - 3D engine with modern graphics
* Your projects here! (Please send PR)
## TODOs
@@ -160,9 +159,10 @@ Model model;
TinyGLTF loader;
std::string err;
std::string warn;
std::string filename = "input.gltf";
bool ret = loader.LoadASCIIFromFile(&model, &err, &warn, argv[1]);
//bool ret = loader.LoadBinaryFromFile(&model, &err, &warn, argv[1]); // for binary glTF(.glb)
bool ret = loader.LoadASCIIFromFile(&model, &err, &warn, filename);
//bool ret = loader.LoadBinaryFromFile(&model, &err, &warn, filename); // for binary glTF(.glb)
if (!warn.empty()) {
printf("Warn: %s\n", warn.c_str());
@@ -173,8 +173,7 @@ if (!err.empty()) {
}
if (!ret) {
printf("Failed to parse glTF\n");
return -1;
printf("Failed to parse glTF: %s\n", filename.c_str());
}
```
@@ -195,7 +194,7 @@ if (!ret) {
* `TINYGLTF_NO_INCLUDE_STB_IMAGE `: Disable including `stb_image.h` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
* `TINYGLTF_NO_INCLUDE_STB_IMAGE_WRITE `: Disable including `stb_image_write.h` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
* `TINYGLTF_USE_RAPIDJSON` : Use RapidJSON as a JSON parser/serializer. RapidJSON files are not included in TinyGLTF repo. Please set an include path to RapidJSON if you enable this feature.
* `TINYGLTF_USE_CPP14` : Use C++14 feature(requires C++14 compiler). This may give better performance than C++11.
## CMake options
@@ -211,6 +210,11 @@ set(TINYGLTF_INSTALL OFF CACHE INTERNAL "" FORCE)
add_subdirectory(/path/to/tinygltf)
```
NOTE: Using tinygltf as a submodule doesn't automatically add the headers to your include path (as standard for many libraries). To get this functionality, add the following to the CMakeLists.txt file from above:
```
target_include_directories(${PROJECT_NAME} PRIVATE "/path/to/tinygltf")
```
### Saving gltTF 2.0 model

View File

@@ -0,0 +1,5 @@
include_directories(${CMAKE_SOURCE_DIR})
add_executable(create_triangle_gltf create_triangle_gltf.cpp)
target_compile_options(create_triangle_gltf PUBLIC -Wall)
target_link_libraries(create_triangle_gltf )

View File

@@ -788,8 +788,10 @@ static void QuatToAngleAxis(const std::vector<double> quaternion,
return;
}
constexpr double pi = 3.14159265358979323846;
double denom = sqrt(1-qw*qw);
outAngleDegrees = angleRadians * 180.0 / M_PI;
outAngleDegrees = angleRadians * 180.0 / pi;
axis[0] = qx / denom;
axis[1] = qy / denom;
axis[2] = qz / denom;

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
/* stb_image_write - v1.11 - public domain - http://nothings.org/stb/stb_image_write.h
/* stb_image_write - v1.16 - public domain - http://nothings.org/stb
writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
no warranty implied; use at your own risk
@@ -10,11 +10,6 @@
Will probably not work correctly with strict-aliasing optimizations.
If using a modern Microsoft Compiler, non-safe versions of CRT calls may cause
compilation warnings or even errors. To avoid this, also before #including,
#define STBI_MSC_SECURE_CRT
ABOUT:
This header file is a library for writing images to C stdio or a callback.
@@ -110,7 +105,7 @@ USAGE:
TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed
data, set the global variable 'stbi_write_tga_with_rle' to 0.
JPEG does ignore alpha channels in input data; quality is between 1 and 100.
Higher quality looks better but results in a bigger image.
JPEG baseline (no JPEG progressive).
@@ -118,7 +113,7 @@ USAGE:
CREDITS:
Sean Barrett - PNG/BMP/TGA
Sean Barrett - PNG/BMP/TGA
Baldur Karlsson - HDR
Jean-Sebastien Guay - TGA monochrome
Tim Kelsey - misc enhancements
@@ -145,6 +140,7 @@ CREDITS:
Ivan Tikhonov
github:ignotion
Adam Schackart
Andrew Kensler
LICENSE
@@ -171,9 +167,9 @@ LICENSE
#endif
#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations
extern int stbi_write_tga_with_rle;
extern int stbi_write_png_compression_level;
extern int stbi_write_force_png_filter;
STBIWDEF int stbi_write_tga_with_rle;
STBIWDEF int stbi_write_png_compression_level;
STBIWDEF int stbi_write_force_png_filter;
#endif
#ifndef STBI_WRITE_NO_STDIO
@@ -183,7 +179,7 @@ STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const
STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality);
#ifdef STBI_WINDOWS_UTF8
#ifdef STBIW_WINDOWS_UTF8
STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);
#endif
#endif
@@ -252,17 +248,17 @@ STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean);
#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)
#ifdef STB_IMAGE_WRITE_STATIC
static int stbi__flip_vertically_on_write=0;
static int stbi_write_png_compression_level = 8;
static int stbi_write_tga_with_rle = 1;
static int stbi_write_force_png_filter = -1;
#else
int stbi_write_png_compression_level = 8;
int stbi__flip_vertically_on_write=0;
int stbi_write_tga_with_rle = 1;
int stbi_write_force_png_filter = -1;
#endif
static int stbi__flip_vertically_on_write = 0;
STBIWDEF void stbi_flip_vertically_on_write(int flag)
{
stbi__flip_vertically_on_write = flag;
@@ -272,6 +268,8 @@ typedef struct
{
stbi_write_func *func;
void *context;
unsigned char buffer[64];
int buf_used;
} stbi__write_context;
// initialize a callback-based context
@@ -288,7 +286,7 @@ static void stbi__stdio_write(void *context, void *data, int size)
fwrite(data,1,size,(FILE*) context);
}
#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)
#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8)
#ifdef __cplusplus
#define STBIW_EXTERN extern "C"
#else
@@ -299,25 +297,25 @@ STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned in
STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input)
{
return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, bufferlen, NULL, NULL);
return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL);
}
#endif
static FILE *stbiw__fopen(char const *filename, char const *mode)
{
FILE *f;
#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)
#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8)
wchar_t wMode[64];
wchar_t wFilename[1024];
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)))
return 0;
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)))
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename)))
return 0;
#if _MSC_VER >= 1400
if (0 != _wfopen_s(&f, wFilename, wMode))
f = 0;
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode)))
return 0;
#if defined(_MSC_VER) && _MSC_VER >= 1400
if (0 != _wfopen_s(&f, wFilename, wMode))
f = 0;
#else
f = _wfopen(wFilename, wMode);
#endif
@@ -385,16 +383,36 @@ static void stbiw__writef(stbi__write_context *s, const char *fmt, ...)
va_end(v);
}
static void stbiw__write_flush(stbi__write_context *s)
{
if (s->buf_used) {
s->func(s->context, &s->buffer, s->buf_used);
s->buf_used = 0;
}
}
static void stbiw__putc(stbi__write_context *s, unsigned char c)
{
s->func(s->context, &c, 1);
}
static void stbiw__write1(stbi__write_context *s, unsigned char a)
{
if ((size_t)s->buf_used + 1 > sizeof(s->buffer))
stbiw__write_flush(s);
s->buffer[s->buf_used++] = a;
}
static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c)
{
unsigned char arr[3];
arr[0] = a, arr[1] = b, arr[2] = c;
s->func(s->context, arr, 3);
int n;
if ((size_t)s->buf_used + 3 > sizeof(s->buffer))
stbiw__write_flush(s);
n = s->buf_used;
s->buf_used = n+3;
s->buffer[n+0] = a;
s->buffer[n+1] = b;
s->buffer[n+2] = c;
}
static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d)
@@ -403,7 +421,7 @@ static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, in
int k;
if (write_alpha < 0)
s->func(s->context, &d[comp - 1], 1);
stbiw__write1(s, d[comp - 1]);
switch (comp) {
case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case
@@ -411,7 +429,7 @@ static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, in
if (expand_mono)
stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp
else
s->func(s->context, d, 1); // monochrome TGA
stbiw__write1(s, d[0]); // monochrome TGA
break;
case 4:
if (!write_alpha) {
@@ -427,7 +445,7 @@ static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, in
break;
}
if (write_alpha > 0)
s->func(s->context, &d[comp - 1], 1);
stbiw__write1(s, d[comp - 1]);
}
static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono)
@@ -441,16 +459,18 @@ static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, i
if (stbi__flip_vertically_on_write)
vdir *= -1;
if (vdir < 0)
j_end = -1, j = y-1;
else
j_end = y, j = 0;
if (vdir < 0) {
j_end = -1; j = y-1;
} else {
j_end = y; j = 0;
}
for (; j != j_end; j += vdir) {
for (i=0; i < x; ++i) {
unsigned char *d = (unsigned char *) data + (j*x+i)*comp;
stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d);
}
stbiw__write_flush(s);
s->func(s->context, &zero, scanline_pad);
}
}
@@ -471,16 +491,27 @@ static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x,
static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data)
{
int pad = (-x*3) & 3;
return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad,
"11 4 22 4" "4 44 22 444444",
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
if (comp != 4) {
// write RGB bitmap
int pad = (-x*3) & 3;
return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad,
"11 4 22 4" "4 44 22 444444",
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
} else {
// RGBA bitmaps need a v4 header
// use BI_BITFIELDS mode with 32bpp and alpha mask
// (straight BI_RGB with alpha mask doesn't work in most readers)
return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *)data,1,0,
"11 4 22 4" "4 44 22 444444 4444 4 444 444 444 444",
'B', 'M', 14+108+x*y*4, 0, 0, 14+108, // file header
108, x,y, 1,32, 3,0,0,0,0,0, 0xff0000,0xff00,0xff,0xff000000u, 0, 0,0,0, 0,0,0, 0,0,0, 0,0,0); // bitmap V4 header
}
}
STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
{
stbi__write_context s;
stbi__write_context s = { 0 };
stbi__start_write_callbacks(&s, func, context);
return stbi_write_bmp_core(&s, x, y, comp, data);
}
@@ -488,7 +519,7 @@ STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x,
#ifndef STBI_WRITE_NO_STDIO
STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
{
stbi__write_context s;
stbi__write_context s = { 0 };
if (stbi__start_write_file(&s,filename)) {
int r = stbi_write_bmp_core(&s, x, y, comp, data);
stbi__end_write_file(&s);
@@ -561,24 +592,25 @@ static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, v
if (diff) {
unsigned char header = STBIW_UCHAR(len - 1);
s->func(s->context, &header, 1);
stbiw__write1(s, header);
for (k = 0; k < len; ++k) {
stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp);
}
} else {
unsigned char header = STBIW_UCHAR(len - 129);
s->func(s->context, &header, 1);
stbiw__write1(s, header);
stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin);
}
}
}
stbiw__write_flush(s);
}
return 1;
}
STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
{
stbi__write_context s;
stbi__write_context s = { 0 };
stbi__start_write_callbacks(&s, func, context);
return stbi_write_tga_core(&s, x, y, comp, (void *) data);
}
@@ -586,7 +618,7 @@ STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x,
#ifndef STBI_WRITE_NO_STDIO
STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
{
stbi__write_context s;
stbi__write_context s = { 0 };
if (stbi__start_write_file(&s,filename)) {
int r = stbi_write_tga_core(&s, x, y, comp, (void *) data);
stbi__end_write_file(&s);
@@ -602,6 +634,8 @@ STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const
#define stbiw__max(a, b) ((a) > (b) ? (a) : (b))
#ifndef STBI_WRITE_NO_STDIO
static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
{
int exponent;
@@ -736,10 +770,10 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f
char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";
s->func(s->context, header, sizeof(header)-1);
#ifdef STBI_MSC_SECURE_CRT
len = sprintf_s(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
#ifdef __STDC_LIB_EXT1__
len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
#else
len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
len = snprintf(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
#endif
s->func(s->context, buffer, len);
@@ -752,15 +786,14 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f
STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data)
{
stbi__write_context s;
stbi__write_context s = { 0 };
stbi__start_write_callbacks(&s, func, context);
return stbi_write_hdr_core(&s, x, y, comp, (float *) data);
}
#ifndef STBI_WRITE_NO_STDIO
STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
{
stbi__write_context s;
stbi__write_context s = { 0 };
if (stbi__start_write_file(&s,filename)) {
int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data);
stbi__end_write_file(&s);
@@ -778,7 +811,7 @@ STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const
#ifndef STBIW_ZLIB_COMPRESS
// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
#define stbiw__sbraw(a) ((int *) (a) - 2)
#define stbiw__sbraw(a) ((int *) (void *) (a) - 2)
#define stbiw__sbm(a) stbiw__sbraw(a)[0]
#define stbiw__sbn(a) stbiw__sbraw(a)[1]
@@ -872,7 +905,7 @@ STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, i
unsigned int bitbuf=0;
int i,j, bitcount=0;
unsigned char *out = NULL;
unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**));
unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char**));
if (hash_table == NULL)
return NULL;
if (quality < 5) quality = 5;
@@ -895,7 +928,7 @@ STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, i
for (j=0; j < n; ++j) {
if (hlist[j]-data > i-32768) { // if entry lies within window
int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i);
if (d >= best) best=d,bestloc=hlist[j];
if (d >= best) { best=d; bestloc=hlist[j]; }
}
}
// when hash table entry is too long, delete half the entries
@@ -948,14 +981,31 @@ STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, i
(void) stbiw__sbfree(hash_table[i]);
STBIW_FREE(hash_table);
// store uncompressed instead if compression was worse
if (stbiw__sbn(out) > data_len + 2 + ((data_len+32766)/32767)*5) {
stbiw__sbn(out) = 2; // truncate to DEFLATE 32K window and FLEVEL = 1
for (j = 0; j < data_len;) {
int blocklen = data_len - j;
if (blocklen > 32767) blocklen = 32767;
stbiw__sbpush(out, data_len - j == blocklen); // BFINAL = ?, BTYPE = 0 -- no compression
stbiw__sbpush(out, STBIW_UCHAR(blocklen)); // LEN
stbiw__sbpush(out, STBIW_UCHAR(blocklen >> 8));
stbiw__sbpush(out, STBIW_UCHAR(~blocklen)); // NLEN
stbiw__sbpush(out, STBIW_UCHAR(~blocklen >> 8));
memcpy(out+stbiw__sbn(out), data+j, blocklen);
stbiw__sbn(out) += blocklen;
j += blocklen;
}
}
{
// compute adler32 on input
unsigned int s1=1, s2=0;
int blocklen = (int) (data_len % 5552);
j=0;
while (j < data_len) {
for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1;
s1 %= 65521, s2 %= 65521;
for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; }
s1 %= 65521; s2 %= 65521;
j += blocklen;
blocklen = 5552;
}
@@ -1048,13 +1098,13 @@ static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int
int type = mymap[filter_type];
unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y);
int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes;
if (type==0) {
memcpy(line_buffer, z, width*n);
return;
}
// first loop isn't optimized since it's just one pixel
// first loop isn't optimized since it's just one pixel
for (i = 0; i < n; ++i) {
switch (type) {
case 1: line_buffer[i] = z[i]; break;
@@ -1275,26 +1325,31 @@ static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) {
bits[0] = val & ((1<<bits[1])-1);
}
static int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, float *CDU, float *fdtbl, int DC, const unsigned short HTDC[256][2], const unsigned short HTAC[256][2]) {
static int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, float *CDU, int du_stride, float *fdtbl, int DC, const unsigned short HTDC[256][2], const unsigned short HTAC[256][2]) {
const unsigned short EOB[2] = { HTAC[0x00][0], HTAC[0x00][1] };
const unsigned short M16zeroes[2] = { HTAC[0xF0][0], HTAC[0xF0][1] };
int dataOff, i, diff, end0pos;
int dataOff, i, j, n, diff, end0pos, x, y;
int DU[64];
// DCT rows
for(dataOff=0; dataOff<64; dataOff+=8) {
for(dataOff=0, n=du_stride*8; dataOff<n; dataOff+=du_stride) {
stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+1], &CDU[dataOff+2], &CDU[dataOff+3], &CDU[dataOff+4], &CDU[dataOff+5], &CDU[dataOff+6], &CDU[dataOff+7]);
}
// DCT columns
for(dataOff=0; dataOff<8; ++dataOff) {
stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+8], &CDU[dataOff+16], &CDU[dataOff+24], &CDU[dataOff+32], &CDU[dataOff+40], &CDU[dataOff+48], &CDU[dataOff+56]);
stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+du_stride], &CDU[dataOff+du_stride*2], &CDU[dataOff+du_stride*3], &CDU[dataOff+du_stride*4],
&CDU[dataOff+du_stride*5], &CDU[dataOff+du_stride*6], &CDU[dataOff+du_stride*7]);
}
// Quantize/descale/zigzag the coefficients
for(i=0; i<64; ++i) {
float v = CDU[i]*fdtbl[i];
// DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f));
// ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway?
DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? v - 0.5f : v + 0.5f);
for(y = 0, j=0; y < 8; ++y) {
for(x = 0; x < 8; ++x,++j) {
float v;
i = y*du_stride+x;
v = CDU[i]*fdtbl[j];
// DU[stbiw__jpg_ZigZag[j]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f));
// ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway?
DU[stbiw__jpg_ZigZag[j]] = (int)(v < 0 ? v - 0.5f : v + 0.5f);
}
}
// Encode DC
@@ -1409,10 +1464,10 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99};
static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99,
99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99};
static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f,
static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f,
1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f };
int row, col, i, k;
int row, col, i, k, subsample;
float fdtbl_Y[64], fdtbl_UV[64];
unsigned char YTable[64], UVTable[64];
@@ -1421,6 +1476,7 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
}
quality = quality ? quality : 90;
subsample = quality <= 90 ? 1 : 0;
quality = quality < 1 ? 1 : quality > 100 ? 100 : quality;
quality = quality < 50 ? 5000 / quality : 200 - quality * 2;
@@ -1443,7 +1499,7 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 };
static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 };
const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width),
3,1,0x11,0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 };
3,1,(unsigned char)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 };
s->func(s->context, (void*)head0, sizeof(head0));
s->func(s->context, (void*)YTable, sizeof(YTable));
stbiw__putc(s, 1);
@@ -1466,36 +1522,74 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
// Encode 8x8 macroblocks
{
static const unsigned short fillBits[] = {0x7F, 7};
const unsigned char *imageData = (const unsigned char *)data;
int DCY=0, DCU=0, DCV=0;
int bitBuf=0, bitCnt=0;
// comp == 2 is grey+alpha (alpha is ignored)
int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0;
const unsigned char *dataR = (const unsigned char *)data;
const unsigned char *dataG = dataR + ofsG;
const unsigned char *dataB = dataR + ofsB;
int x, y, pos;
for(y = 0; y < height; y += 8) {
for(x = 0; x < width; x += 8) {
float YDU[64], UDU[64], VDU[64];
for(row = y, pos = 0; row < y+8; ++row) {
// row >= height => use last input row
int clamped_row = (row < height) ? row : height - 1;
int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp;
for(col = x; col < x+8; ++col, ++pos) {
float r, g, b;
// if col >= width => use pixel from last input column
int p = base_p + ((col < width) ? col : (width-1))*comp;
if(subsample) {
for(y = 0; y < height; y += 16) {
for(x = 0; x < width; x += 16) {
float Y[256], U[256], V[256];
for(row = y, pos = 0; row < y+16; ++row) {
// row >= height => use last input row
int clamped_row = (row < height) ? row : height - 1;
int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp;
for(col = x; col < x+16; ++col, ++pos) {
// if col >= width => use pixel from last input column
int p = base_p + ((col < width) ? col : (width-1))*comp;
float r = dataR[p], g = dataG[p], b = dataB[p];
Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128;
U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b;
V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b;
}
}
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+0, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+8, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
r = imageData[p+0];
g = imageData[p+ofsG];
b = imageData[p+ofsB];
YDU[pos]=+0.29900f*r+0.58700f*g+0.11400f*b-128;
UDU[pos]=-0.16874f*r-0.33126f*g+0.50000f*b;
VDU[pos]=+0.50000f*r-0.41869f*g-0.08131f*b;
// subsample U,V
{
float subU[64], subV[64];
int yy, xx;
for(yy = 0, pos = 0; yy < 8; ++yy) {
for(xx = 0; xx < 8; ++xx, ++pos) {
int j = yy*32+xx*2;
subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f;
subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f;
}
}
DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
}
}
}
} else {
for(y = 0; y < height; y += 8) {
for(x = 0; x < width; x += 8) {
float Y[64], U[64], V[64];
for(row = y, pos = 0; row < y+8; ++row) {
// row >= height => use last input row
int clamped_row = (row < height) ? row : height - 1;
int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp;
for(col = x; col < x+8; ++col, ++pos) {
// if col >= width => use pixel from last input column
int p = base_p + ((col < width) ? col : (width-1))*comp;
float r = dataR[p], g = dataG[p], b = dataB[p];
Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128;
U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b;
V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b;
}
}
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
}
}
}
@@ -1512,7 +1606,7 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality)
{
stbi__write_context s;
stbi__write_context s = { 0 };
stbi__start_write_callbacks(&s, func, context);
return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality);
}
@@ -1521,7 +1615,7 @@ STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x,
#ifndef STBI_WRITE_NO_STDIO
STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality)
{
stbi__write_context s;
stbi__write_context s = { 0 };
if (stbi__start_write_file(&s,filename)) {
int r = stbi_write_jpg_core(&s, x, y, comp, data, quality);
stbi__end_write_file(&s);
@@ -1534,8 +1628,17 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const
#endif // STB_IMAGE_WRITE_IMPLEMENTATION
/* Revision history
1.16 (2021-07-11)
make Deflate code emit uncompressed blocks when it would otherwise expand
support writing BMPs with alpha channel
1.15 (2020-07-13) unknown
1.14 (2020-02-02) updated JPEG writer to downsample chroma channels
1.13
1.12
1.11 (2019-08-11)
1.10 (2019-02-07)
support utf8 filenames in Windows; fix warnings and platform ifdefs
support utf8 filenames in Windows; fix warnings and platform ifdefs
1.09 (2018-02-11)
fix typo in zlib quality API, improve STB_I_W_STATIC in C++
1.08 (2018-01-29)
@@ -1566,7 +1669,7 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const
add HDR output
fix monochrome BMP
0.95 (2014-08-17)
add monochrome TGA output
add monochrome TGA output
0.94 (2014-05-31)
rename private functions to avoid conflicts with stb_image.h
0.93 (2014-05-27)
@@ -1584,38 +1687,38 @@ This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

1
tests/issue-416.gltf Normal file
View File

@@ -0,0 +1 @@
{"images":[{"uri":"%!QAAAQAAA5"}],"asset":{"version":""}}

BIN
tests/issue-492.glb Normal file

Binary file not shown.

View File

@@ -16,10 +16,10 @@
#include <sstream>
#include <fstream>
static JsonDocument JsonConstruct(const char* str)
static tinygltf::detail::JsonDocument JsonConstruct(const char* str)
{
JsonDocument doc;
JsonParse(doc, str, strlen(str));
tinygltf::detail::JsonDocument doc;
tinygltf::detail::JsonParse(doc, str, strlen(str));
return doc;
}
@@ -275,9 +275,9 @@ TEST_CASE("parse-integer", "[bounds-checking]") {
err.clear();
{
JsonDocument o;
tinygltf::detail::JsonDocument o;
double nan = std::numeric_limits<double>::quiet_NaN();
tinygltf::JsonAddMember(o, "int", json(nan));
tinygltf::detail::JsonAddMember(o, "int", tinygltf::detail::json(nan));
CHECK_FALSE(tinygltf::ParseIntegerProperty(
&result, &err, o,
"int", true));
@@ -321,9 +321,9 @@ TEST_CASE("parse-unsigned", "[bounds-checking]") {
err.clear();
{
JsonDocument o;
tinygltf::detail::JsonDocument o;
double nan = std::numeric_limits<double>::quiet_NaN();
tinygltf::JsonAddMember(o, "int", json(nan));
tinygltf::detail::JsonAddMember(o, "int", tinygltf::detail::json(nan));
CHECK_FALSE(tinygltf::ParseUnsignedProperty(
&result, &err, o,
"int", true));
@@ -474,7 +474,7 @@ TEST_CASE("image-uri-spaces", "[issue-236]") {
}
REQUIRE(true == ret);
REQUIRE(err.empty());
REQUIRE(!warn.empty()); // relative image path won't exist in tests/
REQUIRE(warn.empty());
REQUIRE(saved.images.size() == model.images.size());
// The image uri in CubeImageUriMultipleSpaces.gltf is not encoded and
@@ -494,24 +494,23 @@ TEST_CASE("image-uri-spaces", "[issue-236]") {
}
TEST_CASE("serialize-empty-material", "[issue-294]") {
tinygltf::Model m;
tinygltf::Material mat;
mat.pbrMetallicRoughness.baseColorFactor = {1.0f, 1.0f, 1.0f, 1.0f}; // default baseColorFactor
m.materials.push_back(mat);
// Add default constructed material to model
m.materials.push_back({});
// Serialize model to output stream
std::stringstream os;
tinygltf::TinyGLTF ctx;
ctx.WriteGltfSceneToStream(&m, os, false, false);
// use nlohmann json
bool ret = ctx.WriteGltfSceneToStream(&m, os, false, false);
REQUIRE(true == ret);
// Parse serialized model
nlohmann::json j = nlohmann::json::parse(os.str());
// Serialized materials shall hold an empty object that
// represents the default constructed material
REQUIRE(j.find("materials") != j.end());
REQUIRE(j["materials"].is_array());
REQUIRE(1 == j["materials"].size());
REQUIRE(j["materials"][0].is_object());
CHECK(j["materials"][0].is_object());
CHECK(j["materials"][0].empty());
}
TEST_CASE("empty-skeleton-id", "[issue-321]") {
@@ -532,7 +531,8 @@ TEST_CASE("empty-skeleton-id", "[issue-321]") {
std::stringstream os;
ctx.WriteGltfSceneToStream(&model, os, false, false);
ret = ctx.WriteGltfSceneToStream(&model, os, false, false);
REQUIRE(true == ret);
// use nlohmann json
nlohmann::json j = nlohmann::json::parse(os.str());
@@ -634,8 +634,9 @@ TEST_CASE("serialize-const-image", "[issue-394]") {
std::stringstream os;
tinygltf::TinyGLTF ctx;
ctx.WriteGltfSceneToStream(const_cast<const tinygltf::Model *>(&m), os, false,
bool ret = ctx.WriteGltfSceneToStream(const_cast<const tinygltf::Model *>(&m), os, false,
false);
REQUIRE(true == ret);
REQUIRE(m.images[0].uri == i.uri);
// use nlohmann json
@@ -661,10 +662,11 @@ TEST_CASE("serialize-image-callback", "[issue-394]") {
auto writer = [](const std::string *basepath, const std::string *filename,
const tinygltf::Image *image, bool embedImages,
const tinygltf::URICallbacks *uri_cb, std::string *out_uri,
void *user_pointer) -> bool {
const tinygltf::FsCallbacks* fs, const tinygltf::URICallbacks *uri_cb,
std::string *out_uri, void *user_pointer) -> bool {
(void)basepath;
(void)image;
(void)fs;
(void)uri_cb;
REQUIRE(*filename == "foo");
REQUIRE(embedImages == true);
@@ -698,12 +700,13 @@ TEST_CASE("serialize-image-failure", "[issue-394]") {
auto writer = [](const std::string *basepath, const std::string *filename,
const tinygltf::Image *image, bool embedImages,
const tinygltf::URICallbacks *uri_cb, std::string *out_uri,
void *user_pointer) -> bool {
const tinygltf::FsCallbacks* fs, const tinygltf::URICallbacks *uri_cb,
std::string *out_uri, void *user_pointer) -> bool {
(void)basepath;
(void)filename;
(void)image;
(void)embedImages;
(void)fs;
(void)uri_cb;
(void)out_uri;
(void)user_pointer;
@@ -718,3 +721,531 @@ TEST_CASE("serialize-image-failure", "[issue-394]") {
REQUIRE(false == result);
REQUIRE(os.str().size() == 0);
}
TEST_CASE("filesize-check", "[issue-416]") {
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
ctx.SetMaxExternalFileSize(10); // 10 bytes. will fail to load texture image.
bool ret = ctx.LoadASCIIFromFile(&model, &err, &warn, "../models/Cube/Cube.gltf");
if (!err.empty()) {
std::cerr << err << std::endl;
}
REQUIRE(false == ret);
}
TEST_CASE("load-issue-416-model", "[issue-416]") {
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
bool ret = ctx.LoadASCIIFromFile(&model, &err, &warn, "issue-416.gltf");
if (!warn.empty()) {
std::cout << "WARN:" << warn << std::endl;
}
if (!err.empty()) {
std::cerr << "ERR:" << err << std::endl;
}
// external file load fails, but reading glTF itself is ok.
REQUIRE(true == ret);
}
TEST_CASE("serialize-empty-node", "[issue-457]") {
tinygltf::Model m;
// Add default constructed node to model
m.nodes.push_back({});
// Add scene to model
m.scenes.push_back({});
// The scene's only node is the empty node
m.scenes.front().nodes.push_back(0);
// Serialize model to output stream
std::stringstream os;
tinygltf::TinyGLTF ctx;
bool ret = ctx.WriteGltfSceneToStream(&m, os, false, false);
REQUIRE(true == ret);
// Parse serialized model
nlohmann::json j = nlohmann::json::parse(os.str());
// Serialized nodes shall hold an empty object that
// represents the default constructed node
REQUIRE(j.find("nodes") != j.end());
REQUIRE(j["nodes"].is_array());
REQUIRE(1 == j["nodes"].size());
CHECK(j["nodes"][0].is_object());
CHECK(j["nodes"][0].empty());
// We also want to make sure that the serialized scene
// is referencing the empty node.
// There shall be a single serialized scene
auto scenes = j.find("scenes");
REQUIRE(scenes != j.end());
REQUIRE(scenes->is_array());
REQUIRE(1 == scenes->size());
auto scene = scenes->at(0);
REQUIRE(scene.is_object());
// The scene's nodes array shall hold a reference
// to the single node
auto nodes = scene.find("nodes");
REQUIRE(nodes != scene.end());
REQUIRE(nodes->is_array());
REQUIRE(1 == nodes->size());
auto node = nodes->at(0);
CHECK(node.is_number_integer());
int idx = -1;
node.get_to(idx);
CHECK(0 == idx);
}
TEST_CASE("serialize-light-index", "[issue-458]") {
// Create the light
tinygltf::Light light;
light.type = "point";
light.intensity = 0.75;
light.color = std::vector<double>{1.0, 0.8, 0.95};
// Stream to serialize to
std::stringstream os;
{
tinygltf::Model m;
tinygltf::Scene scene;
// Add the light to the model
m.lights.push_back(light);
// Create a node that uses the light
tinygltf::Node node;
node.light = 0;
// Add the node to the model
m.nodes.push_back(node);
// Add the node to the scene
scene.nodes.push_back(0);
// Add the scene to the model
m.scenes.push_back(scene);
// Serialize model to output stream
tinygltf::TinyGLTF ctx;
bool ret = ctx.WriteGltfSceneToStream(&m, os, false, false);
REQUIRE(true == ret);
}
{
tinygltf::Model m;
tinygltf::TinyGLTF ctx;
// Parse the serialized model
bool ok = ctx.LoadASCIIFromString(&m, nullptr, nullptr, os.str().c_str(), os.str().size(), "");
REQUIRE(true == ok);
// Check if the light was correctly serialized
REQUIRE(1 == m.lights.size());
CHECK(m.lights[0] == light);
// Check that the node properly references the light
REQUIRE(1 == m.nodes.size());
CHECK(m.nodes[0].light == 0);
}
}
TEST_CASE("default-material", "[issue-459]") {
const std::vector<double> default_emissive_factor{ 0.0, 0.0, 0.0 };
const std::vector<double> default_base_color_factor{ 1.0, 1.0, 1.0, 1.0 };
const std::string default_alpha_mode = "OPAQUE";
const double default_alpha_cutoff = 0.5;
const bool default_double_sided = false;
const double default_metallic_factor = 1.0;
const double default_roughness_factor = 1.0;
// Check that default constructed material
// holds actual default GLTF material properties
tinygltf::Material mat;
CHECK(mat.alphaMode == default_alpha_mode);
CHECK(mat.alphaCutoff == default_alpha_cutoff);
CHECK(mat.doubleSided == default_double_sided);
CHECK(mat.emissiveFactor == default_emissive_factor);
CHECK(mat.pbrMetallicRoughness.baseColorFactor == default_base_color_factor);
CHECK(mat.pbrMetallicRoughness.metallicFactor == default_metallic_factor);
CHECK(mat.pbrMetallicRoughness.roughnessFactor == default_roughness_factor);
// None of the textures should be set
CHECK(mat.normalTexture.index == -1);
CHECK(mat.occlusionTexture.index == -1);
CHECK(mat.emissiveTexture.index == -1);
}
TEST_CASE("serialize-empty-scene", "[issue-464]") {
// Stream to serialize to
std::stringstream os;
{
tinygltf::Model m;
// Add empty scene to the model
m.scenes.push_back({});
// Serialize model to output stream
tinygltf::TinyGLTF ctx;
bool ret = ctx.WriteGltfSceneToStream(&m, os, false, false);
REQUIRE(true == ret);
}
{
tinygltf::Model m;
tinygltf::TinyGLTF ctx;
// Parse the serialized model
bool ok = ctx.LoadASCIIFromString(&m, nullptr, nullptr, os.str().c_str(), os.str().size(), "");
REQUIRE(true == ok);
// Make sure the empty scene is there
REQUIRE(1 == m.scenes.size());
tinygltf::Scene scene{};
// Check that the scene is empty
CHECK(m.scenes[0] == scene);
}
}
TEST_CASE("zero-sized-bin-chunk-glb", "[issue-440]") {
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
// Input glb has zero-sized data in bin chunk(8 bytes for BIN chunk, and chunksize == 0)
// The spec https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#binary-buffer says
//
// When the binary buffer is empty or when it is stored by other means, this chunk SHOULD be omitted.
//
// 'SHOULD' mean 'RECOMMENDED', so we'll need to allow such zero-sized bin chunk is NOT omitted.
bool ret = ctx.LoadBinaryFromFile(&model, &err, &warn, "../models/regression/zero-sized-bin-chunk-issue-440.glb");
if (!warn.empty()) {
std::cout << "WARN: " << warn << "\n";
}
if (!err.empty()) {
std::cerr << err << std::endl;
}
REQUIRE(true == ret);
}
TEST_CASE("serialize-node-emitter", "[KHR_audio]") {
// Stream to serialize to
std::stringstream os;
{
tinygltf::Model m;
// Create a default audio emitter
m.audioEmitters.resize(1);
// Create a single node
m.nodes.resize(1);
// The node references the single emitter
m.nodes[0].emitter = 0;
// Create a single scene
m.scenes.resize(1);
// Make the scene reference the single node
m.scenes[0].nodes.push_back(0);
// Serialize model to output stream
tinygltf::TinyGLTF ctx;
bool ret = ctx.WriteGltfSceneToStream(&m, os, false, false);
REQUIRE(true == ret);
}
{
tinygltf::Model m;
tinygltf::TinyGLTF ctx;
// Parse the serialized model
bool ok = ctx.LoadASCIIFromString(&m, nullptr, nullptr, os.str().c_str(), os.str().size(), "");
REQUIRE(true == ok);
// Make sure the single scene is there
REQUIRE(1 == m.scenes.size());
// Make sure all three nodes are there
REQUIRE(1 == m.nodes.size());
// Make sure the single root node of the scene is there
REQUIRE(1 == m.scenes[0].nodes.size());
REQUIRE(0 == m.scenes[0].nodes[0]);
// Retrieve the scene root node
const tinygltf::Node& node = m.nodes[m.scenes[0].nodes[0]];
// Make sure the single root node has both lod nodes
REQUIRE(0 == node.emitter);
}
}
TEST_CASE("serialize-lods", "[lods]") {
// Stream to serialize to
std::stringstream os;
{
tinygltf::Model m;
m.nodes.resize(4);
// Add Node 1 and Node 2 as lods to Node 0
m.nodes[0].lods.push_back(1);
m.nodes[0].lods.push_back(2);
// Add Material 1 and Material 2 as lods to Material 0
m.materials.resize(4);
m.materials[0].lods.push_back(1);
m.materials[0].lods.push_back(2);
tinygltf::Scene scene;
// Scene uses Node 0 and 3 as root node
scene.nodes.push_back(0);
scene.nodes.push_back(3);
// Add scene to the model
m.scenes.push_back(scene);
// Serialize model to output stream
tinygltf::TinyGLTF ctx;
bool ret = ctx.WriteGltfSceneToStream(&m, os, false, false);
REQUIRE(true == ret);
}
{
tinygltf::Model m;
tinygltf::TinyGLTF ctx;
// Parse the serialized model
bool ok = ctx.LoadASCIIFromString(&m, nullptr, nullptr, os.str().c_str(), os.str().size(), "");
REQUIRE(true == ok);
// Make sure the model's used extensions hold MSFT_lod
CHECK(m.extensionsUsed.size() == 1);
CHECK(m.extensionsUsed[0].compare("MSFT_lod") == 0);
// MSFT_lod is not a required extension
CHECK(m.extensionsRequired.size() == 0);
// Make sure all four materials are there
REQUIRE(4 == m.materials.size());
// Make sure the first material has both lod materials
REQUIRE(2 == m.materials[0].lods.size());
// Make sure the order is still the same after serialization and deserialization
CHECK(1 == m.materials[0].lods[0]);
CHECK(2 == m.materials[0].lods[1]);
// Make sure the material with lods exposes the MSFT_lod extension
CHECK(m.materials[0].extensions.size() == 1);
CHECK(m.materials[0].extensions.count("MSFT_lod") == 1);
// Make sure the last material has no lod materials
CHECK(0 == m.materials[3].lods.size());
// Make sure the material without lods does not exposes the MSFT_lod extension
CHECK(m.materials[3].extensions.size() == 0);
CHECK(m.materials[3].extensions.count("MSFT_lod") == 0);
// Make sure the single scene is there
REQUIRE(1 == m.scenes.size());
// Make sure all four nodes are there
REQUIRE(4 == m.nodes.size());
// Make sure the two root nodes of the scene are there
REQUIRE(2 == m.scenes[0].nodes.size());
REQUIRE(0 == m.scenes[0].nodes[0]);
REQUIRE(3 == m.scenes[0].nodes[1]);
// Retrieve the node with lods
const tinygltf::Node& nodeWithLods = m.nodes[m.scenes[0].nodes[0]];
// Make sure the node has both lod nodes
REQUIRE(2 == nodeWithLods.lods.size());
// Make sure the order is still the same after serialization and deserialization
CHECK(1 == nodeWithLods.lods[0]);
CHECK(2 == nodeWithLods.lods[1]);
// Make sure the node with lods exposes the MSFT_lod extension
CHECK(nodeWithLods.extensions.size() == 1);
CHECK(nodeWithLods.extensions.count("MSFT_lod") == 1);
// Retrieve the node without lods
const tinygltf::Node& nodeWithoutLods = m.nodes[m.scenes[0].nodes[1]];
// Make sure the node has no lod nodes
CHECK(0 == nodeWithoutLods.lods.size());
// Make sure the node without lods does not exposes the MSFT_lod extension
CHECK(nodeWithoutLods.extensions.size() == 0);
CHECK(nodeWithoutLods.extensions.count("MSFT_lod") == 0);
}
}
TEST_CASE("write-image-issue", "[issue-473]") {
std::string err;
std::string warn;
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
bool ok = ctx.LoadASCIIFromFile(&model, &err, &warn, "../models/Cube/Cube.gltf");
REQUIRE(ok);
REQUIRE(err.empty());
REQUIRE(warn.empty());
REQUIRE(model.images.size() == 2);
REQUIRE(model.images[0].uri == "Cube_BaseColor.png");
REQUIRE(model.images[1].uri == "Cube_MetallicRoughness.png");
REQUIRE_FALSE(model.images[0].image.empty());
REQUIRE_FALSE(model.images[1].image.empty());
ok = ctx.WriteGltfSceneToFile(&model, "Cube.gltf");
REQUIRE(ok);
for (const auto& image : model.images) {
std::fstream file(image.uri);
CHECK(file.good());
}
}
TEST_CASE("images-as-is", "[issue-487]") {
std::string err;
std::string warn;
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
ctx.SetImagesAsIs(true);
bool ok = ctx.LoadASCIIFromFile(&model, &err, &warn, "../models/Cube/Cube.gltf");
REQUIRE(ok);
REQUIRE(err.empty());
REQUIRE(warn.empty());
for (const auto& image : model.images) {
CHECK(image.as_is == true);
CHECK_FALSE(image.uri.empty());
CHECK_FALSE(image.image.empty());
#ifndef TINYGLTF_NO_STB_IMAGE
// Make sure we can decode the images
int w = -1, h = -1, component = -1;
unsigned char *data = stbi_load_from_memory(image.image.data(), static_cast<int>(image.image.size()), &w, &h, &component, 0);
CHECK(data != nullptr);
CHECK(w == 512);
CHECK(h == 512);
CHECK(component >= 3);
stbi_image_free(data);
#endif
}
// Write glTF model to disk, and images as separate files
{
ok = ctx.WriteGltfSceneToFile(&model, "Cube_with_image_files.gltf");
REQUIRE(ok);
// All the images should have been written to disk with their original data
for (const auto& image : model.images) {
// Make sure the image files exist
{
std::fstream file(image.uri);
CHECK(file.good());
} // Close file before stbi_load (Windows sharing violation fix)
#ifndef TINYGLTF_NO_STB_IMAGE
// Make sure we can load the images
int w = -1, h = -1, component = -1;
unsigned char *data = stbi_load(image.uri.c_str(), &w, &h, &component, 0);
CHECK(data != nullptr);
CHECK(w == 512);
CHECK(h == 512);
CHECK(component >= 3);
stbi_image_free(data);
#endif
}
}
// Write glTF model to disk, and embed images as data URIs
{
ok = ctx.WriteGltfSceneToFile(&model, "Cube_with_embedded_images.gltf", true, false);
REQUIRE(ok);
// Load above model again, and check if the images are loaded properly
tinygltf::Model embeddedImages;
ctx.SetImagesAsIs(false);
bool ok = ctx.LoadASCIIFromFile(&embeddedImages, &err, &warn, "Cube_with_embedded_images.gltf");
REQUIRE(ok);
REQUIRE(err.empty());
REQUIRE(warn.empty());
for (const auto& image : embeddedImages.images) {
CHECK(image.as_is == false);
CHECK_FALSE(image.mimeType.empty());
CHECK_FALSE(image.image.empty());
CHECK(image.width == 512);
CHECK(image.height == 512);
CHECK(image.component >= 3);
}
}
// Write glTF model to disk, as GLB
{
ok = ctx.WriteGltfSceneToFile(&model, "Cube.glb", true, true, true, true);
REQUIRE(ok);
// Load above model again, and check if the images are loaded properly
tinygltf::Model glbModel;
ctx.SetImagesAsIs(false);
bool ok = ctx.LoadBinaryFromFile(&glbModel, &err, &warn, "Cube.glb");
REQUIRE(ok);
REQUIRE(err.empty());
REQUIRE(warn.empty());
for (const auto& image : glbModel.images) {
CHECK(image.as_is == false);
CHECK_FALSE(image.mimeType.empty());
CHECK_FALSE(image.image.empty());
CHECK(image.width == 512);
CHECK(image.height == 512);
CHECK(image.component >= 3);
}
}
}
TEST_CASE("inverse-bind-matrices-optional", "[issue-492]") {
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
bool ret = ctx.LoadBinaryFromFile(&model, &err, &warn, "issue-492.glb");
if (!warn.empty()) {
std::cout << "WARN:" << warn << std::endl;
}
if (!err.empty()) {
std::cerr << "ERR:" << err << std::endl;
}
REQUIRE(true == ret);
REQUIRE(err.empty());
}
bool LoadImageData(tinygltf::Image * /* image */, const int /* image_idx */, std::string * /* err */,
std::string * /* warn */, int /* req_width */, int /* req_height */,
const unsigned char * /* bytes */, int /* size */, void * /*user_data */) {
return true;
}
bool WriteImageData(const std::string * /* basepath */, const std::string * /* filename */,
const tinygltf::Image *image, bool /* embedImages */,
const tinygltf::FsCallbacks * /* fs_cb */, const tinygltf::URICallbacks * /* uri_cb */,
std::string * /* out_uri */, void * user_pointer) {
REQUIRE(user_pointer != nullptr);
auto counter = static_cast<int*>(user_pointer);
*counter = *counter + 1;
return true;
}
TEST_CASE("empty-images-not-written", "[issue-495]") {
std::string err;
std::string warn;
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
ctx.SetImageLoader(LoadImageData, nullptr);
bool ok = ctx.LoadASCIIFromFile(&model, &err, &warn, "../models/Cube/Cube.gltf");
REQUIRE(ok);
REQUIRE(err.empty());
REQUIRE(warn.empty());
CHECK(model.images.size() == 2);
for (const auto& image : model.images) {
// No data loaded or decoded
CHECK(image.image.empty());
// The URI is kept
CHECK_FALSE(image.uri.empty());
// The URI should not be a data URI
CHECK(image.uri.find("data:") != 0);
}
// Now write the loaded model
int counter = 0;
ctx.SetImageWriter(WriteImageData, &counter);
ok = ctx.WriteGltfSceneToFile(&model, "issue-495-external.gltf");
CHECK(ok);
// WriteImageData should be invoked for both images
CHECK(counter == 2);
}

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@ Experimental WASI/WASM build
Download wasi-sdk https://github.com/WebAssembly/wasi-sdk
Compile tinygltf with C++ exceptions and threads off. See `Makefile` for details
Compile tinygltf without C++ exceptions and threads. See `Makefile` for details
(NOTE: TinyGLTF itself does not use RTTI and threading feature(C++ threads, posix, win32 thread))
## Build examples and Run