Compare commits

...

160 Commits

Author SHA1 Message Date
Syoyo Fujita
a5e653e46c 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
d530cd410b Add bounds check to images loaded from bufferviews 2025-01-20 23:43:07 -05:00
Syoyo Fujita
1831424c71 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
5e008af65d Added NO_FS definition for std::ofstream usage 2024-12-30 03:12:20 +08:00
Syoyo Fujita
fbff1f45b5 Merge pull request #507 from thearchivalone/release
Documentation: Submodule hint added
2024-12-21 19:59:42 +09:00
Brad
d950e7cd9b Documentation: Submodule hint added 2024-12-20 17:49:51 -06:00
Syoyo Fujita
116d0030f9 Merge pull request #504 from nim65s/vendor 2024-10-16 23:27:42 +09:00
Syoyo Fujita
ff972dcf1b Merge pull request #503 from nim65s/release 2024-10-16 23:26:53 +09:00
Guilhem Saurel
8bec431699 CMake: fix export install dir 2024-10-16 15:53:48 +02:00
Guilhem Saurel
21485496b1 CMake: allow opt-out of installing vendored headers 2024-10-16 14:58:42 +02:00
Syoyo Fujita
fda7422022 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
decfabd67e Merge branch 'syoyo:release' into release 2024-08-08 10:25:11 +02:00
Syoyo Fujita
10b23b6af2 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
fe3cfbe996 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
3b73caa8e8 fixed ParseAnimation loading animation's extensions into sampler instead of sample's extensions. 2024-07-19 12:34:16 +02:00
Syoyo Fujita
fea6786129 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
fb58f88a4e Properly clear the model before loading 2024-07-05 08:57:36 +02:00
Syoyo Fujita
143ff45b61 Update README.md 2024-07-04 03:01:46 +09:00
Syoyo Fujita
cfbec35dc7 Merge pull request #492 from danwillm/inverse-bind-matrix
Make inverseBindMatrices optional
2024-07-04 02:59:35 +09:00
danwillm
4ad8c82c9e Add test for inverse bind matrices being optional 2024-07-01 22:32:17 +01:00
danwillm
2e7ba45a6c Make inverseBindMatrices optional 2024-07-01 18:31:00 +01:00
Syoyo Fujita
cf9767668a bump minor version. 2024-06-28 21:30:43 +09:00
Syoyo Fujita
8a269aa5e9 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
38614763e9 fixes #487
Support image as_is flag in loading and saving
2024-06-28 12:17:38 +02:00
Thomas Gamper
3245906248 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
847df8456a 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
6482c08cf7 Remove asserts 2024-06-10 14:18:31 -07:00
Sean Curtis
e08df72575 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
f03fe26579 Merge pull request #486 from pmcgvr/release
Fix stripping of slashes from paths
2024-05-24 02:49:22 +09:00
Syoyo Fujita
e54660fbf9 Merge pull request #485 from bwrsandman/patch-1
msvc 32bit: Fix C4244 warning
2024-05-21 04:11:31 +09:00
Patrick Mc Gartoll
1bdd404c04 Fix stripping of slashes from paths 2024-05-16 18:11:26 -07:00
Sandy
2191085580 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
cde43ef668 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
e3f9a7d8b3 Resolve overload ambiguity in VS2015 (version 14.0) 2024-03-26 11:32:43 +00:00
jamesvert
f57d18ad74 Fix C4018 warnings in MSVC on WIN32 2024-03-26 11:06:16 +00:00
Syoyo Fujita
ed3d1ec2f5 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
9b4e1eae9e Fix C4267 warnings in Visual Studio on WIN32 2024-03-25 17:50:33 +00:00
Syoyo Fujita
cbc8e1bea6 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
212de904ca 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
1f5b8f8b8c tester.cc - extend MSFT_lod test 2024-03-25 17:01:08 +01:00
Thomas Gamper
b274b34972 tiny_gltf.h - register MSFT_lod with the model's used extensions 2024-03-25 17:00:41 +01:00
TheDev
22dfeab315 Added the pmode argument to _wopen to fix the access permission on MinGW 2024-03-25 18:21:20 +03:00
Syoyo Fujita
b132612307 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
50d90c91ac M_PI was not defined by <cmath> 2024-03-19 19:06:19 +00:00
Syoyo Fujita
4bfc1fc180 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
e0cc45e88d tester.cc - add test case for the crash fix in KHR_audio node serialization 2024-02-06 14:48:58 +01:00
Thomas Gamper
c3bbe97a9e tester.cc - add MSFT_lods test case 2024-02-05 17:03:16 +01:00
Thomas Gamper
f1bdf43e15 tiny_gltf.h - add/remove MSFT_extension as required 2024-02-05 16:50:46 +01:00
Thomas Gamper
a42263bdba tiny_gltf.h - parse node and material lods 2024-02-05 15:42:49 +01:00
Syoyo Fujita
4fea26f6c8 Allow zero-sized BIN chunk. Fixes #440 2024-01-24 05:43:27 +09:00
Syoyo Fujita
c5641f2c22 Deprecate Travis CI and remove Travis CI scripts. Fixes #439 2023-12-11 21:00:35 +09:00
Syoyo Fujita
6782f887bb Merge pull request #467 from rhiskey/release
Small security and overflow patch
2023-12-05 06:42:19 +09:00
rhiskey
8fdeca146e Update stb_image_write.h
Provided `sizeof(buffer)` in `sptintf`
2023-12-05 00:28:18 +03:00
rhiskey
7fd75df70e Revert back stb_image_write.h to original code 2023-12-05 00:21:41 +03:00
rhiskey
77238cf23c 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
8acf861db7 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
03b3a31e02 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
30ec815748 Merge branch 'syoyo:release' into release 2023-12-04 16:55:16 +03:00
Syoyo Fujita
8387fdbd50 Fix possible nullptr dereferencing.
Add missing `return false`
2023-12-04 22:50:49 +09:00
rhiskey
32198f757f Update stb_image_write.h
Securing printing output via `sprintf_s` instead `sprintf`.
2023-12-04 14:22:14 +03:00
rhiskey
1c6f6efafc 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
d32f1fb2fb 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
3203e1985e 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
211f86e3f5 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
afcfb57898 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
b6e2398e1d 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
d4ea67cae1 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
f32475c952 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
1f42c963e6 fix #459
tiny_gltf.h - use member initialization
2023-11-22 15:59:13 +01:00
Thomas Gamper
fd6c7855e7 fix #459
tiny_gltf.h - properly initialise emissiveFactor; tests/tester.cc - add test case
2023-11-22 14:17:46 +01:00
Syoyo Fujita
5e8a7fd602 Merge pull request #456 from haroonq/patch-1
Allow BufferView indices to be unspecified.
2023-10-10 21:24:51 +09:00
haroonq
8098a9e8ed Allow BufferView indices to be unspecified.
Allow BufferView indices for element array buffers to be unspecified to support some extensions.

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

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

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

d9172461e2/CesiumGltfReader/src/decodeDraco.cpp (L101)
2023-09-02 10:16:04 +10:00
emimvi
bf7120f8a0 Serialize byteOffset as size_t, avoiding cast
Fixes silently writing an overflowed int in the output file.
2023-09-02 00:11:41 +02:00
Syoyo Fujita
acf1e8a2b1 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
8c85d5e387 Add method to set parsing strictness 2023-08-28 12:56:09 +10:00
Nyall Dawson
02e8b8da1e 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
ddc76f7724 Merge pull request #446 from nyalldawson/fix_error
Fix misleading error message
2023-08-24 22:11:50 +09:00
Nyall Dawson
8e9aadf569 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
0eaa23fbfc 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
2a5dc852cc added project link to readme 2023-08-07 06:59:35 +02:00
Syoyo Fujita
f51243da48 Merge pull request #433 from dyollb/modernize
Modernize
2023-07-11 19:43:53 +09:00
Syoyo Fujita
a080377e6f 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
69d75573f5 Fix issue when serializing extensions of a primitive 2023-07-10 15:13:09 +02:00
Syoyo Fujita
aaf631c984 Merge pull request #435 from RE-Kovalev/release
MinGW _wfopen_s fix
2023-07-05 18:41:22 +09:00
R.E. Kovalev
112e3537ff MinGW _wfopen_s fix 2023-07-05 09:11:57 +03:00
Bryn Lloyd
cb6a707014 cppcoreguidelines-prefer-member-initializer 2023-06-21 22:30:14 +02:00
Bryn Lloyd
3e98ac4564 modernize-use-equals-default 2023-06-21 22:15:49 +02:00
Bryn Lloyd
c704d73bd0 readability-redundant-string-init 2023-06-21 18:42:24 +02:00
Bryn Lloyd
a64f4b4442 modernize-use-default-member-init 2023-06-21 18:40:18 +02:00
Bryn Lloyd
85b4322ade minor cleanup of cmakelists 2023-06-21 18:26:43 +02:00
Syoyo Fujita
7a570c88d9 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
e12e0a9392 Merge pull request #429 from AdamFull/release
KHR_audio parsing support (ASCII only)
2023-06-13 21:40:45 +09:00
Baranob_Ilya
879cb473a3 Added parsing and serializing of audio emitters for scene (global sources) 2023-06-12 13:35:05 +04:00
Baranob_Ilya
c9657be1de Forgot to add KHR_audio to used extensions 2023-06-12 12:34:34 +04:00
Baranob_Ilya
95bbf15ce2 Update .gitignore 2023-06-12 12:30:04 +04:00
Baranob_Ilya
78864c8d3a 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
14c86324d7 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
8d5d0b34be clean up 2023-06-07 15:35:35 +02:00
David Siegel
a1a34cb54d fix syntax error 2023-06-07 15:30:02 +02:00
David Siegel
cfe64fb6c8 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
c201efb998 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
b88e9cc52a 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
9417144f48 Merge pull request #424 from agnat/rewrite_ForEachInArray
get rid of std::function
2023-06-06 23:11:12 +09:00
David Siegel
07616e8190 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
bec8a6d54f 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
157063fa1b fix: add missing nullptr check 2023-06-06 15:31:58 +02:00
David Siegel
c164878d0f parse light source references 2023-06-06 06:18:14 +02:00
David Siegel
d852f50d49 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
22cafa1032 remove duplicate code
use a function to parse extras and extensions
2023-06-06 00:07:37 +02:00
David Siegel
47208b234d fix warnings: unused variable 2023-06-06 00:07:37 +02:00
Syoyo Fujita
5a6df34d99 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
147a00a601 Prevent duplicated key generation when serializing lights + RapidJSON backend. Fixes #420 2023-06-04 05:45:24 +09:00
Syoyo Fujita
350c296802 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
cc93e1fd25 Fix: Actually invoke the user-supplied function 2023-04-26 12:13:41 +02:00
Syoyo Fujita
59cc44ad4f Merge pull request #417 from syoyo/filesize-check
Fix to #416
2023-04-23 23:15:07 +09:00
Syoyo Fujita
1a5046e06b Fix MSVC compile failure on AppVeyor CI. 2023-04-23 23:08:41 +09:00
Syoyo Fujita
877d856e71 Format error message.
Add regression test of issue-416.
2023-04-23 21:47:31 +09:00
Syoyo Fujita
b534b6b0d8 Fix syntax. 2023-04-23 21:40:23 +09:00
Syoyo Fujita
ecfd37dee2 - 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
5c06b7d03b 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
a75355b018 Fix serialization of AnimationChannel::target_node when it is zero 2023-04-18 21:03:39 +02:00
Syoyo Fujita
a977f7a16f 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
5a6c55870e Deprecate ubuntu-18.04 image and update CI build configuration. 2023-04-10 18:51:29 +09:00
David Siegel
49caa65177 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
d71c6f61f3 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
b5d27fd151 stb_image: Apply https://github.com/nothings/stb/pull/1443 2023-03-29 12:00:24 -07:00
Neil Bickford
af4456ba68 stb_image: Apply https://github.com/nothings/stb/pull/1454 2023-03-29 11:57:27 -07:00
Neil Bickford
344669ddf6 Update stb_image and stb_image_write to latest nothings/stb dev branch: 9f1776a36d 2023-03-29 11:56:13 -07:00
Syoyo Fujita
967c98dd90 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
7658624bb4 Added error handling to ostream writing 2023-03-12 19:26:05 +01:00
Syoyo Fujita
84a83d39f5 Merge pull request #407 from DavidSM64/release
Added detail namespace to prevent json namespace conflicts
2023-02-19 02:08:19 +09:00
David
03ad33cc8d Fixed global namespace issue 2023-02-15 23:35:51 -06:00
David
3831802717 Fix RapidJSON implementation (hopefully) 2023-02-15 23:21:09 -06:00
David
1f9a4b97a3 Added detail namespace to prevent namespace conflicts 2023-02-15 22:56:18 -06:00
Syoyo Fujita
6dba104c54 Merge pull request #405 from tioez326/patch-2
Fix typo
2023-02-10 21:00:27 +09:00
tioez326
b5e1b35ef1 Fix typo 2023-02-10 12:09:12 +01:00
Syoyo Fujita
52b73c7f0b Update README.md 2023-01-16 05:46:11 +09:00
Syoyo Fujita
98adbb3fb3 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
283b552a4e Fix animation channel target node optionality 2023-01-15 11:45:45 -08:00
Syoyo Fujita
c2ca97b38b v2.8.1 2023-01-13 18:15:21 +09:00
Syoyo Fujita
f051892c55 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
137a7ca999 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
477d977fea Merge pull request #398 from nicolas-raoul/patch-1
Fixed typo
2023-01-12 16:21:35 +09:00
Nicolas Raoul
8cd5e759d0 Fixed typo 2023-01-12 15:29:32 +09:00
17 changed files with 3846 additions and 2036 deletions

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,11 +1,14 @@
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)
@@ -13,24 +16,25 @@ option(TINYGLTF_BUILD_VALIDATOR_EXAMPLE "Build validator exampe" OFF)
option(TINYGLTF_BUILD_BUILDER_EXAMPLE "Build glTF builder example" 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)
#
@@ -58,19 +62,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
@@ -197,6 +196,7 @@ if (!ret) {
* `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
You can add tinygltf using `add_subdirectory` feature.
@@ -211,6 +211,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,529 @@ 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());
#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