Compare commits

..

52 Commits

Author SHA1 Message Date
Syoyo Fujita
c6817d206b Remove some assert() 2023-06-07 19:10:44 +09: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
Syoyo Fujita
a6c3945ed3 Bump version 2.8.0. 2023-01-10 20:42:24 +09:00
Syoyo Fujita
6614bddef3 Merge pull request #397 from pknowlesnv/encode_image_uri
urlencode image urls
2023-01-10 20:31:39 +09:00
Pyarelal Knowles
385946dfd8 add URI encode/decode API
Tinygltf is able to write files defined by a URI, so it needs to be able
to decode it. Since it may also modify the path where the image is saved
it may need to re-encode the URI too. This patch provides an API to set
URI encoding and decoding callbacks and exposes the default decode
method.

Uses the existing dlib::urldecode as a decode default. The encode
callback is left null, matching existing behaviour.

Updates the WriteImageDataFunction signature to include
tinygltf::URICallbacks.

Decodes the image and buffer uris before using them as a filename.

If the encode callback is set, encodes the written image location in the
default WriteImageDataFunction and encodes generated buffer locations
when writing .bin files.

Adds a save+load step to the test image-uri-spaces to verify uri
encoding.
2023-01-09 20:54:29 -08:00
Syoyo Fujita
03bbe0921c Merge pull request #396 from pknowlesnv/image_write_failure
propagate image writing failures
2022-12-30 17:59:41 +09:00
Pyarelal Knowles
a9121550b9 SerializeGltfImage: add missing & std::string ref
Hopefully the compiler would optimize this away but better to avoid the
copy in the first place.
2022-12-29 14:12:29 -08:00
Pyarelal Knowles
d2b0af6915 propagate image writing failures
Modifies UpdateImageObject() so that Returning false from the
WriteImageDataFunction callback results in the WriteGltfScene*() call
returning false.

Does not call WriteImageDataFunction if there is no image data.

Adds test case serialize-image-failure to verify the callback return
code is able to cause an overall failure to save the gltf.
2022-12-29 13:50:17 -08:00
Syoyo Fujita
695608dd11 Update readme. 2022-12-29 21:50:47 +09:00
8 changed files with 2227 additions and 1582 deletions

View File

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

View File

@@ -2,20 +2,22 @@
`TinyGLTF` is a header only C++11 glTF 2.0 https://github.com/KhronosGroup/glTF library. `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) (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 ## 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.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). - v2.6.0 Support serializing sparse accessor(Thanks to @fynv).
- v2.5.0 Add SetPreserveImageChannels() option to load image data as is. - v2.5.0 Add SetPreserveImageChannels() option to load image data as is.
- v2.4.0 Experimental RapidJSON support. Experimental C++14 support(C++14 may give better performance) - v2.4.0 Experimental RapidJSON support. Experimental C++14 support(C++14 may give better performance)
- v2.3.0 Modified Material representation according to glTF 2.0 schema(and introduced TextureInfo class) - v2.3.0 Modified Material representation according to glTF 2.0 schema(and introduced TextureInfo class)
- v2.2.0 release(Support loading 16bit PNG. Sparse accessor support) - v2.2.0 release(Support loading 16bit PNG. Sparse accessor support)
- v2.1.0 release(Draco support) - v2.1.0 release(Draco decoding support)
- v2.0.0 release(22 Aug, 2018)! - v2.0.0 release(22 Aug, 2018)!
### Branches ### Branches
@@ -104,7 +106,7 @@ WASI build example is located in [wasm](wasm) .
* [GlslViewer](https://github.com/patriciogonzalezvivo/glslViewer) - live GLSL coding for MacOS and Linux * [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. * [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 * [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 * [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. * [Supernova Engine](https://github.com/supernovaengine/supernova) - Game engine for 2D and 3D projects with Lua or C++ in data oriented design.
* Your projects here! (Please send PR) * Your projects here! (Please send PR)
@@ -195,6 +197,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_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. * `TINYGLTF_USE_CPP14` : Use C++14 feature(requires C++14 compiler). This may give better performance than C++11.
## CMake options ## CMake options
You can add tinygltf using `add_subdirectory` feature. You can add tinygltf using `add_subdirectory` feature.

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 writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
no warranty implied; use at your own risk no warranty implied; use at your own risk
@@ -10,11 +10,6 @@
Will probably not work correctly with strict-aliasing optimizations. 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: ABOUT:
This header file is a library for writing images to C stdio or a callback. This header file is a library for writing images to C stdio or a callback.
@@ -145,6 +140,7 @@ CREDITS:
Ivan Tikhonov Ivan Tikhonov
github:ignotion github:ignotion
Adam Schackart Adam Schackart
Andrew Kensler
LICENSE LICENSE
@@ -171,9 +167,9 @@ LICENSE
#endif #endif
#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations #ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations
extern int stbi_write_tga_with_rle; STBIWDEF int stbi_write_tga_with_rle;
extern int stbi_write_png_compression_level; STBIWDEF int stbi_write_png_compression_level;
extern int stbi_write_force_png_filter; STBIWDEF int stbi_write_force_png_filter;
#endif #endif
#ifndef STBI_WRITE_NO_STDIO #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_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); 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); STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);
#endif #endif
#endif #endif
@@ -252,17 +248,17 @@ STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean);
#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) #define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)
#ifdef STB_IMAGE_WRITE_STATIC #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_png_compression_level = 8;
static int stbi_write_tga_with_rle = 1; static int stbi_write_tga_with_rle = 1;
static int stbi_write_force_png_filter = -1; static int stbi_write_force_png_filter = -1;
#else #else
int stbi_write_png_compression_level = 8; int stbi_write_png_compression_level = 8;
int stbi__flip_vertically_on_write=0;
int stbi_write_tga_with_rle = 1; int stbi_write_tga_with_rle = 1;
int stbi_write_force_png_filter = -1; int stbi_write_force_png_filter = -1;
#endif #endif
static int stbi__flip_vertically_on_write = 0;
STBIWDEF void stbi_flip_vertically_on_write(int flag) STBIWDEF void stbi_flip_vertically_on_write(int flag)
{ {
stbi__flip_vertically_on_write = flag; stbi__flip_vertically_on_write = flag;
@@ -272,6 +268,8 @@ typedef struct
{ {
stbi_write_func *func; stbi_write_func *func;
void *context; void *context;
unsigned char buffer[64];
int buf_used;
} stbi__write_context; } stbi__write_context;
// initialize a callback-based 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); fwrite(data,1,size,(FILE*) context);
} }
#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) #if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8)
#ifdef __cplusplus #ifdef __cplusplus
#define STBIW_EXTERN extern "C" #define STBIW_EXTERN extern "C"
#else #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) 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 #endif
static FILE *stbiw__fopen(char const *filename, char const *mode) static FILE *stbiw__fopen(char const *filename, char const *mode)
{ {
FILE *f; FILE *f;
#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) #if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8)
wchar_t wMode[64]; wchar_t wMode[64];
wchar_t wFilename[1024]; wchar_t wFilename[1024];
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename)))
return 0; return 0;
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode)))
return 0; return 0;
#if _MSC_VER >= 1400 #if defined(_MSC_VER) && _MSC_VER >= 1400
if (0 != _wfopen_s(&f, wFilename, wMode)) if (0 != _wfopen_s(&f, wFilename, wMode))
f = 0; f = 0;
#else #else
f = _wfopen(wFilename, wMode); f = _wfopen(wFilename, wMode);
#endif #endif
@@ -385,16 +383,36 @@ static void stbiw__writef(stbi__write_context *s, const char *fmt, ...)
va_end(v); 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) static void stbiw__putc(stbi__write_context *s, unsigned char c)
{ {
s->func(s->context, &c, 1); 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) static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c)
{ {
unsigned char arr[3]; int n;
arr[0] = a, arr[1] = b, arr[2] = c; if ((size_t)s->buf_used + 3 > sizeof(s->buffer))
s->func(s->context, arr, 3); 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) 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; int k;
if (write_alpha < 0) if (write_alpha < 0)
s->func(s->context, &d[comp - 1], 1); stbiw__write1(s, d[comp - 1]);
switch (comp) { switch (comp) {
case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case 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) if (expand_mono)
stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp
else else
s->func(s->context, d, 1); // monochrome TGA stbiw__write1(s, d[0]); // monochrome TGA
break; break;
case 4: case 4:
if (!write_alpha) { if (!write_alpha) {
@@ -427,7 +445,7 @@ static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, in
break; break;
} }
if (write_alpha > 0) 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) 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) if (stbi__flip_vertically_on_write)
vdir *= -1; vdir *= -1;
if (vdir < 0) if (vdir < 0) {
j_end = -1, j = y-1; j_end = -1; j = y-1;
else } else {
j_end = y, j = 0; j_end = y; j = 0;
}
for (; j != j_end; j += vdir) { for (; j != j_end; j += vdir) {
for (i=0; i < x; ++i) { for (i=0; i < x; ++i) {
unsigned char *d = (unsigned char *) data + (j*x+i)*comp; unsigned char *d = (unsigned char *) data + (j*x+i)*comp;
stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d);
} }
stbiw__write_flush(s);
s->func(s->context, &zero, scanline_pad); 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) static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data)
{ {
int pad = (-x*3) & 3; if (comp != 4) {
return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, // write RGB bitmap
"11 4 22 4" "4 44 22 444444", int pad = (-x*3) & 3;
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad,
40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header "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) 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); stbi__start_write_callbacks(&s, func, context);
return stbi_write_bmp_core(&s, x, y, comp, data); 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 #ifndef STBI_WRITE_NO_STDIO
STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) 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)) { if (stbi__start_write_file(&s,filename)) {
int r = stbi_write_bmp_core(&s, x, y, comp, data); int r = stbi_write_bmp_core(&s, x, y, comp, data);
stbi__end_write_file(&s); 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) { if (diff) {
unsigned char header = STBIW_UCHAR(len - 1); unsigned char header = STBIW_UCHAR(len - 1);
s->func(s->context, &header, 1); stbiw__write1(s, header);
for (k = 0; k < len; ++k) { for (k = 0; k < len; ++k) {
stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp);
} }
} else { } else {
unsigned char header = STBIW_UCHAR(len - 129); 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_pixel(s, -1, comp, has_alpha, 0, begin);
} }
} }
} }
stbiw__write_flush(s);
} }
return 1; return 1;
} }
STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) 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); stbi__start_write_callbacks(&s, func, context);
return stbi_write_tga_core(&s, x, y, comp, (void *) data); 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 #ifndef STBI_WRITE_NO_STDIO
STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) 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)) { if (stbi__start_write_file(&s,filename)) {
int r = stbi_write_tga_core(&s, x, y, comp, (void *) data); int r = stbi_write_tga_core(&s, x, y, comp, (void *) data);
stbi__end_write_file(&s); 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)) #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) static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
{ {
int exponent; int exponent;
@@ -736,8 +770,8 @@ 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"; char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";
s->func(s->context, header, sizeof(header)-1); s->func(s->context, header, sizeof(header)-1);
#ifdef STBI_MSC_SECURE_CRT #ifdef __STDC_LIB_EXT1__
len = sprintf_s(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
#else #else
len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
#endif #endif
@@ -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) 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); stbi__start_write_callbacks(&s, func, context);
return stbi_write_hdr_core(&s, x, y, comp, (float *) data); 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) 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)) { if (stbi__start_write_file(&s,filename)) {
int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data); int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data);
stbi__end_write_file(&s); 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 #ifndef STBIW_ZLIB_COMPRESS
// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() // 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__sbm(a) stbiw__sbraw(a)[0]
#define stbiw__sbn(a) stbiw__sbraw(a)[1] #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; unsigned int bitbuf=0;
int i,j, bitcount=0; int i,j, bitcount=0;
unsigned char *out = NULL; 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) if (hash_table == NULL)
return NULL; return NULL;
if (quality < 5) quality = 5; 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) { for (j=0; j < n; ++j) {
if (hlist[j]-data > i-32768) { // if entry lies within window if (hlist[j]-data > i-32768) { // if entry lies within window
int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); 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 // 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]); (void) stbiw__sbfree(hash_table[i]);
STBIW_FREE(hash_table); 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 // compute adler32 on input
unsigned int s1=1, s2=0; unsigned int s1=1, s2=0;
int blocklen = (int) (data_len % 5552); int blocklen = (int) (data_len % 5552);
j=0; j=0;
while (j < data_len) { while (j < data_len) {
for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1; for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; }
s1 %= 65521, s2 %= 65521; s1 %= 65521; s2 %= 65521;
j += blocklen; j += blocklen;
blocklen = 5552; blocklen = 5552;
} }
@@ -1275,26 +1325,31 @@ static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) {
bits[0] = val & ((1<<bits[1])-1); 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 EOB[2] = { HTAC[0x00][0], HTAC[0x00][1] };
const unsigned short M16zeroes[2] = { HTAC[0xF0][0], HTAC[0xF0][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]; int DU[64];
// DCT rows // 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]); 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 // DCT columns
for(dataOff=0; dataOff<8; ++dataOff) { 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 // Quantize/descale/zigzag the coefficients
for(i=0; i<64; ++i) { for(y = 0, j=0; y < 8; ++y) {
float v = CDU[i]*fdtbl[i]; for(x = 0; x < 8; ++x,++j) {
// DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f)); float v;
// ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway? i = y*du_stride+x;
DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? v - 0.5f : v + 0.5f); 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 // Encode DC
@@ -1412,7 +1467,7 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
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 }; 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]; float fdtbl_Y[64], fdtbl_UV[64];
unsigned char YTable[64], UVTable[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; quality = quality ? quality : 90;
subsample = quality <= 90 ? 1 : 0;
quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; quality = quality < 1 ? 1 : quality > 100 ? 100 : quality;
quality = quality < 50 ? 5000 / quality : 200 - quality * 2; 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 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 }; 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), 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*)head0, sizeof(head0));
s->func(s->context, (void*)YTable, sizeof(YTable)); s->func(s->context, (void*)YTable, sizeof(YTable));
stbiw__putc(s, 1); 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 // Encode 8x8 macroblocks
{ {
static const unsigned short fillBits[] = {0x7F, 7}; static const unsigned short fillBits[] = {0x7F, 7};
const unsigned char *imageData = (const unsigned char *)data;
int DCY=0, DCU=0, DCV=0; int DCY=0, DCU=0, DCV=0;
int bitBuf=0, bitCnt=0; int bitBuf=0, bitCnt=0;
// comp == 2 is grey+alpha (alpha is ignored) // comp == 2 is grey+alpha (alpha is ignored)
int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; 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; int x, y, pos;
for(y = 0; y < height; y += 8) { if(subsample) {
for(x = 0; x < width; x += 8) { for(y = 0; y < height; y += 16) {
float YDU[64], UDU[64], VDU[64]; for(x = 0; x < width; x += 16) {
for(row = y, pos = 0; row < y+8; ++row) { float Y[256], U[256], V[256];
// row >= height => use last input row for(row = y, pos = 0; row < y+16; ++row) {
int clamped_row = (row < height) ? row : height - 1; // row >= height => use last input row
int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; int clamped_row = (row < height) ? row : height - 1;
for(col = x; col < x+8; ++col, ++pos) { int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp;
float r, g, b; for(col = x; col < x+16; ++col, ++pos) {
// if col >= width => use pixel from last input column // if col >= width => use pixel from last input column
int p = base_p + ((col < width) ? col : (width-1))*comp; 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]; // subsample U,V
g = imageData[p+ofsG]; {
b = imageData[p+ofsB]; float subU[64], subV[64];
YDU[pos]=+0.29900f*r+0.58700f*g+0.11400f*b-128; int yy, xx;
UDU[pos]=-0.16874f*r-0.33126f*g+0.50000f*b; for(yy = 0, pos = 0; yy < 8; ++yy) {
VDU[pos]=+0.50000f*r-0.41869f*g-0.08131f*b; 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); DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, VDU, fdtbl_UV, DCV, 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) 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); stbi__start_write_callbacks(&s, func, context);
return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality); 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 #ifndef STBI_WRITE_NO_STDIO
STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) 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)) { if (stbi__start_write_file(&s,filename)) {
int r = stbi_write_jpg_core(&s, x, y, comp, data, quality); int r = stbi_write_jpg_core(&s, x, y, comp, data, quality);
stbi__end_write_file(&s); stbi__end_write_file(&s);
@@ -1534,6 +1628,15 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const
#endif // STB_IMAGE_WRITE_IMPLEMENTATION #endif // STB_IMAGE_WRITE_IMPLEMENTATION
/* Revision history /* 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) 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) 1.09 (2018-02-11)
@@ -1566,7 +1669,7 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const
add HDR output add HDR output
fix monochrome BMP fix monochrome BMP
0.95 (2014-08-17) 0.95 (2014-08-17)
add monochrome TGA output add monochrome TGA output
0.94 (2014-05-31) 0.94 (2014-05-31)
rename private functions to avoid conflicts with stb_image.h rename private functions to avoid conflicts with stb_image.h
0.93 (2014-05-27) 0.93 (2014-05-27)

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

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

View File

@@ -16,10 +16,10 @@
#include <sstream> #include <sstream>
#include <fstream> #include <fstream>
static JsonDocument JsonConstruct(const char* str) static tinygltf::detail::JsonDocument JsonConstruct(const char* str)
{ {
JsonDocument doc; tinygltf::detail::JsonDocument doc;
JsonParse(doc, str, strlen(str)); tinygltf::detail::JsonParse(doc, str, strlen(str));
return doc; return doc;
} }
@@ -275,9 +275,9 @@ TEST_CASE("parse-integer", "[bounds-checking]") {
err.clear(); err.clear();
{ {
JsonDocument o; tinygltf::detail::JsonDocument o;
double nan = std::numeric_limits<double>::quiet_NaN(); 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( CHECK_FALSE(tinygltf::ParseIntegerProperty(
&result, &err, o, &result, &err, o,
"int", true)); "int", true));
@@ -321,9 +321,9 @@ TEST_CASE("parse-unsigned", "[bounds-checking]") {
err.clear(); err.clear();
{ {
JsonDocument o; tinygltf::detail::JsonDocument o;
double nan = std::numeric_limits<double>::quiet_NaN(); 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( CHECK_FALSE(tinygltf::ParseUnsignedProperty(
&result, &err, o, &result, &err, o,
"int", true)); "int", true));
@@ -392,27 +392,105 @@ TEST_CASE("pbr-khr-texture-transform", "[material]") {
TEST_CASE("image-uri-spaces", "[issue-236]") { TEST_CASE("image-uri-spaces", "[issue-236]") {
tinygltf::Model model;
tinygltf::TinyGLTF ctx; tinygltf::TinyGLTF ctx;
std::string err; std::string err;
std::string warn; std::string warn;
// Test image file with single spaces. // Test image file with single spaces.
bool ret = ctx.LoadASCIIFromFile(&model, &err, &warn, "../models/CubeImageUriSpaces/CubeImageUriSpaces.gltf"); {
if (!err.empty()) { tinygltf::Model model;
std::cerr << err << std::endl; bool ret = ctx.LoadASCIIFromFile(
} &model, &err, &warn,
"../models/CubeImageUriSpaces/CubeImageUriSpaces.gltf");
if (!warn.empty()) {
std::cerr << warn << std::endl;
}
if (!err.empty()) {
std::cerr << err << std::endl;
}
REQUIRE(true == ret); REQUIRE(true == ret);
REQUIRE(warn.empty());
REQUIRE(err.empty());
REQUIRE(model.images.size() == 1);
REQUIRE(model.images[0].uri.find(' ') != std::string::npos);
}
// Test image file with a beginning space, trailing space, and greater than // Test image file with a beginning space, trailing space, and greater than
// one consecutive spaces. // one consecutive spaces.
ret = ctx.LoadASCIIFromFile(&model, &err, &warn, "../models/CubeImageUriSpaces/CubeImageUriMultipleSpaces.gltf"); tinygltf::Model model;
bool ret = ctx.LoadASCIIFromFile(
&model, &err, &warn,
"../models/CubeImageUriSpaces/CubeImageUriMultipleSpaces.gltf");
if (!warn.empty()) {
std::cerr << warn << std::endl;
}
if (!err.empty()) { if (!err.empty()) {
std::cerr << err << std::endl; std::cerr << err << std::endl;
} }
REQUIRE(true == ret); REQUIRE(true == ret);
REQUIRE(warn.empty());
REQUIRE(err.empty());
REQUIRE(model.images.size() == 1);
REQUIRE(model.images[0].uri.size() > 1);
REQUIRE(model.images[0].uri[0] == ' ');
// Test the URI encoding API by saving and re-load the file, without embedding
// the image.
// TODO(syoyo): create temp directory.
{
// Encoder that only replaces spaces with "%20".
auto uriencode = [](const std::string &in_uri,
const std::string &object_type, std::string *out_uri,
void *user_data) -> bool {
(void)user_data;
bool imageOrBuffer = object_type == "image" || object_type == "buffer";
REQUIRE(true == imageOrBuffer);
*out_uri = {};
for (char c : in_uri) {
if (c == ' ')
*out_uri += "%20";
else
*out_uri += c;
}
return true;
};
// Remove the buffer URI, so a new one is generated based on the gltf
// filename and then encoded with the above callback.
model.buffers[0].uri.clear();
tinygltf::URICallbacks uri_cb{uriencode, tinygltf::URIDecode, nullptr};
ctx.SetURICallbacks(uri_cb);
ret = ctx.WriteGltfSceneToFile(&model, " issue-236.gltf", false, false);
REQUIRE(true == ret);
// read back serialized glTF
tinygltf::Model saved;
bool ret = ctx.LoadASCIIFromFile(&saved, &err, &warn, " issue-236.gltf");
if (!err.empty()) {
std::cerr << err << std::endl;
}
REQUIRE(true == ret);
REQUIRE(err.empty());
REQUIRE(!warn.empty()); // relative image path won't exist in tests/
REQUIRE(saved.images.size() == model.images.size());
// The image uri in CubeImageUriMultipleSpaces.gltf is not encoded and
// should be different after encoding spaces with %20.
REQUIRE(model.images[0].uri != saved.images[0].uri);
// Verify the image path remains the same after uri decoding
std::string image_uri, image_uri_saved;
(void)tinygltf::URIDecode(model.images[0].uri, &image_uri, nullptr);
(void)tinygltf::URIDecode(saved.images[0].uri, &image_uri_saved, nullptr);
REQUIRE(image_uri == image_uri_saved);
// Verify the buffer's generated and encoded URI
REQUIRE(saved.buffers.size() == model.buffers.size());
REQUIRE(saved.buffers[0].uri == "%20issue-236.bin");
}
} }
TEST_CASE("serialize-empty-material", "[issue-294]") { TEST_CASE("serialize-empty-material", "[issue-294]") {
@@ -426,7 +504,8 @@ TEST_CASE("serialize-empty-material", "[issue-294]") {
std::stringstream os; std::stringstream os;
tinygltf::TinyGLTF ctx; tinygltf::TinyGLTF ctx;
ctx.WriteGltfSceneToStream(&m, os, false, false); bool ret = ctx.WriteGltfSceneToStream(&m, os, false, false);
REQUIRE(true == ret);
// use nlohmann json // use nlohmann json
nlohmann::json j = nlohmann::json::parse(os.str()); nlohmann::json j = nlohmann::json::parse(os.str());
@@ -454,7 +533,8 @@ TEST_CASE("empty-skeleton-id", "[issue-321]") {
std::stringstream os; std::stringstream os;
ctx.WriteGltfSceneToStream(&model, os, false, false); ret = ctx.WriteGltfSceneToStream(&model, os, false, false);
REQUIRE(true == ret);
// use nlohmann json // use nlohmann json
nlohmann::json j = nlohmann::json::parse(os.str()); nlohmann::json j = nlohmann::json::parse(os.str());
@@ -556,8 +636,9 @@ TEST_CASE("serialize-const-image", "[issue-394]") {
std::stringstream os; std::stringstream os;
tinygltf::TinyGLTF ctx; 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); false);
REQUIRE(true == ret);
REQUIRE(m.images[0].uri == i.uri); REQUIRE(m.images[0].uri == i.uri);
// use nlohmann json // use nlohmann json
@@ -583,7 +664,11 @@ TEST_CASE("serialize-image-callback", "[issue-394]") {
auto writer = [](const std::string *basepath, const std::string *filename, auto writer = [](const std::string *basepath, const std::string *filename,
const tinygltf::Image *image, bool embedImages, const tinygltf::Image *image, bool embedImages,
std::string *out_uri, void *user_pointer) -> bool { const tinygltf::URICallbacks *uri_cb, std::string *out_uri,
void *user_pointer) -> bool {
(void)basepath;
(void)image;
(void)uri_cb;
REQUIRE(*filename == "foo"); REQUIRE(*filename == "foo");
REQUIRE(embedImages == true); REQUIRE(embedImages == true);
REQUIRE(user_pointer == (void *)0xba5e1e55); REQUIRE(user_pointer == (void *)0xba5e1e55);
@@ -593,13 +678,82 @@ TEST_CASE("serialize-image-callback", "[issue-394]") {
tinygltf::TinyGLTF ctx; tinygltf::TinyGLTF ctx;
ctx.SetImageWriter(writer, (void *)0xba5e1e55); ctx.SetImageWriter(writer, (void *)0xba5e1e55);
ctx.WriteGltfSceneToStream(const_cast<const tinygltf::Model *>(&m), os, false, bool result = ctx.WriteGltfSceneToStream(const_cast<const tinygltf::Model *>(&m), os, false,
false); false);
// use nlohmann json // use nlohmann json
nlohmann::json j = nlohmann::json::parse(os.str()); nlohmann::json j = nlohmann::json::parse(os.str());
REQUIRE(true == result);
REQUIRE(1 == j["images"].size()); REQUIRE(1 == j["images"].size());
REQUIRE(j["images"][0].is_object()); REQUIRE(j["images"][0].is_object());
REQUIRE(j["images"][0]["uri"].get<std::string>() == "bar"); REQUIRE(j["images"][0]["uri"].get<std::string>() == "bar");
} }
TEST_CASE("serialize-image-failure", "[issue-394]") {
tinygltf::Model m;
tinygltf::Image i;
// Set some data so the ImageWriter callback will be called
i.image = {255, 255, 255, 255};
m.images.push_back(i);
std::stringstream os;
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 {
(void)basepath;
(void)filename;
(void)image;
(void)embedImages;
(void)uri_cb;
(void)out_uri;
(void)user_pointer;
return false;
};
tinygltf::TinyGLTF ctx;
ctx.SetImageWriter(writer, (void *)0xba5e1e55);
bool result = ctx.WriteGltfSceneToStream(const_cast<const tinygltf::Model *>(&m), os, false,
false);
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);
}

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 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)) (NOTE: TinyGLTF itself does not use RTTI and threading feature(C++ threads, posix, win32 thread))
## Build examples and Run ## Build examples and Run