mirror of
https://github.com/syoyo/tinygltf.git
synced 2026-06-28 18:18:51 +00:00
Compare commits
19 Commits
json11
...
16bit-lode
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8a46c4e1d | ||
|
|
8fd91aea04 | ||
|
|
8f76d790b8 | ||
|
|
853f6df7b5 | ||
|
|
758a1240c9 | ||
|
|
7bdfed3bec | ||
|
|
962552c5c8 | ||
|
|
5a4c898912 | ||
|
|
f2addc0e44 | ||
|
|
70d16a7b92 | ||
|
|
326d7ea310 | ||
|
|
eb011068c0 | ||
|
|
87be0ce34b | ||
|
|
7d9a0bda3a | ||
|
|
7ece5c8275 | ||
|
|
6bdffedcbe | ||
|
|
d2fb7dc2af | ||
|
|
62a72c4845 | ||
|
|
73584ba7b7 |
25
README.md
25
README.md
@@ -3,11 +3,13 @@
|
||||
`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.
|
||||
If you are looking for old, C++03 version, please use `devel-picojson` branch.
|
||||
If you are looking for old, C++03 version, please use `devel-picojson` branch.
|
||||
|
||||
## Status
|
||||
|
||||
v2.0.0 release(22 Aug, 2018)!
|
||||
v2.2.0 release(Support loading 16bit PNG)
|
||||
v2.1.0 release(Draco support)
|
||||
v2.0.0 release(22 Aug, 2018)!
|
||||
|
||||
## Builds
|
||||
|
||||
@@ -38,14 +40,15 @@ v2.0.0 release(22 Aug, 2018)!
|
||||
* Image(Using stb_image)
|
||||
* [x] Parse BASE64 encoded embedded image data(DataURI).
|
||||
* [x] Load external image file.
|
||||
* [x] PNG(8bit only)
|
||||
* [x] JPEG(8bit only)
|
||||
* [x] BMP
|
||||
* [x] GIF
|
||||
* [x] Load PNG(8bit and 16bit)
|
||||
* [x] Load JPEG(8bit only)
|
||||
* [x] Load BMP
|
||||
* [x] Load GIF
|
||||
* [x] Custom Image decoder callback(e.g. for decoding OpenEXR image)
|
||||
* Load from memory
|
||||
* Custom callback handler
|
||||
* [x] Image load
|
||||
* [x] Image save
|
||||
* Extensions
|
||||
* [x] Draco mesh decoding
|
||||
|
||||
@@ -69,10 +72,12 @@ v2.0.0 release(22 Aug, 2018)!
|
||||
* [ ] Mesh Compression/decompression(Open3DGC, etc)
|
||||
* [x] Load Draco compressed mesh
|
||||
* [x] Save Draco compressed mesh
|
||||
* [ ] Open3DGC?
|
||||
* [ ] Support `extensions` and `extras` property
|
||||
* [ ] HDR image?
|
||||
* [ ] OpenEXR extension through TinyEXR.
|
||||
* [ ] Write example and tests for `animation` and `skin`
|
||||
* [ ] 16bit PNG support in Serialization
|
||||
* [ ] Write example and tests for `animation` and `skin`
|
||||
* [ ] Skinning
|
||||
* [ ] Morph targets
|
||||
|
||||
@@ -104,13 +109,13 @@ Copy `stb_image.h`, `stb_image_write.h`, `json.hpp` and `tiny_gltf.h` to your pr
|
||||
|
||||
using namespace tinygltf;
|
||||
|
||||
Model model;
|
||||
Model model;
|
||||
TinyGLTF loader;
|
||||
std::string err;
|
||||
std::string warn;
|
||||
|
||||
|
||||
bool ret = loader.LoadASCIIFromFile(&model, &err, &warn, argv[1]);
|
||||
//bool ret = loader.LoadBinaryFromFile(&model, &err, &warn, argv[1]); // for binary glTF(.glb)
|
||||
//bool ret = loader.LoadBinaryFromFile(&model, &err, &warn, argv[1]); // for binary glTF(.glb)
|
||||
|
||||
if (!warn.empty()) {
|
||||
printf("Warn: %s\n", warn.c_str());
|
||||
|
||||
@@ -50,8 +50,9 @@ std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos,
|
||||
From spec2.0 readme:
|
||||
https://github.com/KhronosGroup/glTF/tree/master/specification/2.0
|
||||
... drawArrays function should be used with a count equal to
|
||||
the count property of any of the accessors referenced by the attributes
|
||||
property (they are all equal for a given primitive).
|
||||
the count property of any of the accessors referenced by the
|
||||
attributes property (they are all equal for a given
|
||||
primitive).
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -112,8 +113,29 @@ std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos,
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
|
||||
GLenum format = GL_RGBA;
|
||||
|
||||
if (image.component == 1) {
|
||||
format = GL_RED;
|
||||
} else if (image.component == 2) {
|
||||
format = GL_RG;
|
||||
} else if (image.component == 3) {
|
||||
format = GL_RGB;
|
||||
} else {
|
||||
// ???
|
||||
}
|
||||
|
||||
GLenum type = GL_UNSIGNED_BYTE;
|
||||
if (image.bits == 8) {
|
||||
// ok
|
||||
} else if (image.bits == 16) {
|
||||
type = GL_UNSIGNED_SHORT;
|
||||
} else {
|
||||
// ???
|
||||
}
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, &image.image.at(0));
|
||||
format, type, &image.image.at(0));
|
||||
}
|
||||
|
||||
return vbos;
|
||||
@@ -255,7 +277,7 @@ void displayLoop(Window &window, const std::string &filename) {
|
||||
glm::vec3 model_pos = glm::vec3(-3, 0, -3);
|
||||
|
||||
// generate a camera view, based on eye-position and lookAt world-position
|
||||
glm::mat4 view_mat = genView(glm::vec3(2, 2, 2), model_pos);
|
||||
glm::mat4 view_mat = genView(glm::vec3(2, 2, 20), model_pos);
|
||||
|
||||
glm::vec3 sun_position = glm::vec3(3.0, 10.0, -5.0);
|
||||
glm::vec3 sun_color = glm::vec3(1.0);
|
||||
@@ -287,6 +309,11 @@ void displayLoop(Window &window, const std::string &filename) {
|
||||
}
|
||||
}
|
||||
|
||||
static void error_callback(int error, const char *description) {
|
||||
(void)error;
|
||||
fprintf(stderr, "Error: %s\n", description);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
std::string filename = "../../models/Cube/Cube.gltf";
|
||||
|
||||
@@ -294,14 +321,18 @@ int main(int argc, char **argv) {
|
||||
filename = argv[1];
|
||||
}
|
||||
|
||||
glfwSetErrorCallback(error_callback);
|
||||
|
||||
if (!glfwInit()) return -1;
|
||||
|
||||
// Force create 3.3 profile.
|
||||
// Force create OpenGL 3.3
|
||||
// NOTE(syoyo): Linux + NVIDIA driver segfaults for some reason? commenting out glfwWindowHint will work.
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
#ifdef __APPLE__
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Window window = Window(800, 600, "TinyGLTF basic example");
|
||||
|
||||
21
examples/common/LICENSE.lodepng
Normal file
21
examples/common/LICENSE.lodepng
Normal file
@@ -0,0 +1,21 @@
|
||||
Copyright (c) 2005-2018 Lode Vandevenne
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
|
||||
5992
examples/common/lodepng.cpp
Normal file
5992
examples/common/lodepng.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1919
examples/common/lodepng.h
Normal file
1919
examples/common/lodepng.h
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -4,9 +4,10 @@ project(gltfutil)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
include_directories(../../)
|
||||
include_directories(../common/)
|
||||
|
||||
file(GLOB gltfutil_sources *.cc *.h)
|
||||
add_executable(gltfutil ${gltfutil_sources})
|
||||
add_executable(gltfutil ${gltfutil_sources} ../common/lodepng.cpp)
|
||||
|
||||
install ( TARGETS
|
||||
gltfutil
|
||||
|
||||
@@ -49,6 +49,7 @@ struct configuration {
|
||||
cli_action action = cli_action::not_set;
|
||||
texture_dumper::texture_output_format requested_format =
|
||||
texture_dumper::texture_output_format::not_specified;
|
||||
bool use_exr = false;
|
||||
|
||||
bool has_output_dir;
|
||||
bool is_valid() {
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include "stb_image_write.h"
|
||||
|
||||
#define TINYEXR_IMPLEMENTATION
|
||||
#include "tinyexr.h"
|
||||
|
||||
namespace gltfutil {
|
||||
int usage(int ret = 0) {
|
||||
using std::cout;
|
||||
@@ -20,8 +23,9 @@ int usage(int ret = 0) {
|
||||
"[path to output directory])\n\n"
|
||||
//<< "\t\t -i: start in interactive mode\n"
|
||||
<< "\t\t -d: dump enclosed content (image assets)\n"
|
||||
<< "\t\t -f: file format for image output"
|
||||
<< "\t\t -o: ouptput directory path"
|
||||
<< "\t\t -f: file format for image output\n"
|
||||
<< "\t\t -o: ouptput directory path\n"
|
||||
<< "\t\t -e: Use OpenEXR format for 16bit image\n"
|
||||
<< "\t\t -h: print this help\n";
|
||||
return ret;
|
||||
}
|
||||
@@ -44,6 +48,9 @@ int parse_args(int argc, char** argv) {
|
||||
config.mode = ui_mode::cli;
|
||||
config.action = cli_action::dump;
|
||||
break;
|
||||
case 'e':
|
||||
config.use_exr = true;
|
||||
break;
|
||||
case 'i':
|
||||
config.mode = ui_mode::interactive;
|
||||
break;
|
||||
@@ -97,6 +104,11 @@ int parse_args(int argc, char** argv) {
|
||||
|
||||
case cli_action::dump: {
|
||||
texture_dumper dumper(model);
|
||||
|
||||
if (config.use_exr) {
|
||||
dumper.set_use_exr(true);
|
||||
}
|
||||
|
||||
if (config.requested_format !=
|
||||
texture_dumper::texture_output_format::not_specified)
|
||||
dumper.set_output_format(config.requested_format);
|
||||
|
||||
@@ -1,15 +1,84 @@
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
#include "stb_image_write.h"
|
||||
#include "texture_dumper.h"
|
||||
|
||||
#include "lodepng.h" // ../common
|
||||
|
||||
#include "tinyexr.h"
|
||||
|
||||
#include <tiny_gltf.h>
|
||||
|
||||
using namespace gltfutil;
|
||||
using namespace tinygltf;
|
||||
using std::cout;
|
||||
|
||||
static LodePNGColorType GetLodePNGColorType(int channels) {
|
||||
if (channels == 1) {
|
||||
return LodePNGColorType::LCT_GREY;
|
||||
} else if (channels == 2) {
|
||||
return LodePNGColorType::LCT_GREY_ALPHA;
|
||||
} else if (channels == 3) {
|
||||
return LodePNGColorType::LCT_RGB;
|
||||
} else if (channels == 4) {
|
||||
return LodePNGColorType::LCT_RGBA;
|
||||
} else {
|
||||
std::cerr << "??? unsupported channels " << channels << "\n";
|
||||
return LodePNGColorType::LCT_RGB; // FIXME(syoyo): Raise error
|
||||
}
|
||||
}
|
||||
|
||||
static void ToBigEndian(std::vector<uint8_t>* image) {
|
||||
|
||||
assert(image->size() % 2 == 0);
|
||||
|
||||
union {
|
||||
unsigned int i;
|
||||
char c[4];
|
||||
} bint = {0x01020304};
|
||||
|
||||
bool is_big_endian = (bint.c[0] == 1);
|
||||
|
||||
if (is_big_endian) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t *ptr = reinterpret_cast<uint16_t *>(image->data());
|
||||
size_t n = image->size() / 2;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
ptr[i] = ((0xFF00 & ptr[i]) >> 8) | ((0x00FF & ptr[i]) << 8);
|
||||
}
|
||||
}
|
||||
|
||||
static bool Save16bitImageAsEXR(const std::string& filename,
|
||||
const tinygltf::Image& image) {
|
||||
assert(image.bits == 16);
|
||||
|
||||
std::vector<float> buf(image.width * image.height * image.component);
|
||||
|
||||
// widen to float image.
|
||||
// Store as is(i.e, pixel value range is [0.0, 65535.0])
|
||||
const unsigned short* ptr =
|
||||
reinterpret_cast<const unsigned short*>(image.image.data());
|
||||
for (size_t i = 0; i < image.width * image.height * image.component; i++) {
|
||||
buf[i] = float(ptr[i]);
|
||||
}
|
||||
|
||||
const char* err = nullptr;
|
||||
int ret = SaveEXR(buf.data(), image.width, image.height, image.component,
|
||||
/* save_as_fp16 */ 0, filename.c_str(), &err);
|
||||
|
||||
if (err) {
|
||||
std::cerr << "EXR err: " << err << std::endl;
|
||||
FreeEXRErrorMessage(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
return (ret == TINYEXR_SUCCESS);
|
||||
}
|
||||
|
||||
texture_dumper::texture_dumper(const Model& input)
|
||||
: model(input), configured_format(texture_output_format::png) {
|
||||
cout << "Texture dumper\n";
|
||||
@@ -26,26 +95,58 @@ void texture_dumper::dump_to_folder(const std::string& path) {
|
||||
cout << "image name is: \"" << image.name << "\"\n";
|
||||
cout << "image size is: " << image.width << 'x' << image.height << '\n';
|
||||
cout << "pixel channel count :" << image.component << '\n';
|
||||
std::string name = image.name.empty() ? std::to_string(index) : image.name;
|
||||
cout << "pixel bit depth :" << image.bits << '\n';
|
||||
std::string basename =
|
||||
image.name.empty() ? std::to_string(index) : image.name;
|
||||
|
||||
unsigned char* bytes_to_write =
|
||||
const_cast<unsigned char*>(image.image.data());
|
||||
|
||||
std::string filename;
|
||||
switch (configured_format) {
|
||||
case texture_output_format::png:
|
||||
name = path + "/" + name + ".png";
|
||||
std::cout << "Image will be written to " << name << '\n';
|
||||
stbi_write_png(name.c_str(), image.width, image.height, image.component,
|
||||
image.image.data(), 0);
|
||||
filename = path + "/" + basename + ".png";
|
||||
|
||||
if (this->use_exr) {
|
||||
if (image.pixel_type == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
|
||||
filename = path + "/" + basename + ".exr";
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Image will be written to " << filename << '\n';
|
||||
|
||||
if (image.pixel_type == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
|
||||
if (this->use_exr) {
|
||||
bool ret = Save16bitImageAsEXR(filename, image);
|
||||
assert(ret);
|
||||
} else {
|
||||
// Use lodepng to save 16bit PNG.
|
||||
// NOTE(syoyo): `loadpng::encode` requires image data must be stored in big endian.
|
||||
std::vector<uint8_t> tmp = image.image; // copy
|
||||
ToBigEndian(&tmp);
|
||||
|
||||
unsigned ret = lodepng::encode(
|
||||
filename, tmp.data(), image.width, image.height,
|
||||
GetLodePNGColorType(image.component), /* bits */ 16);
|
||||
assert(ret == 0); // 0 = no err.
|
||||
}
|
||||
} else {
|
||||
// TODO(syoyo): check status
|
||||
stbi_write_png(filename.c_str(), image.width, image.height,
|
||||
image.component, bytes_to_write, 0);
|
||||
}
|
||||
break;
|
||||
case texture_output_format::bmp:
|
||||
std::cout << "Image will be written to " << name << '\n';
|
||||
name = path + "/" + name + ".bmp";
|
||||
stbi_write_bmp(name.c_str(), image.width, image.height, image.component,
|
||||
image.image.data());
|
||||
filename = path + "/" + basename + ".bmp";
|
||||
std::cout << "Image will be written to " << filename << '\n';
|
||||
stbi_write_bmp(filename.c_str(), image.width, image.height,
|
||||
image.component, bytes_to_write);
|
||||
break;
|
||||
case texture_output_format::tga:
|
||||
std::cout << "Image will be written to " << name << '\n';
|
||||
name = path + "/" + name + ".tga";
|
||||
stbi_write_tga(name.c_str(), image.width, image.height, image.component,
|
||||
image.image.data());
|
||||
filename = path + "/" + basename + ".tga";
|
||||
std::cout << "Image will be written to " << filename << '\n';
|
||||
stbi_write_tga(filename.c_str(), image.width, image.height,
|
||||
image.component, bytes_to_write);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,15 @@ class texture_dumper {
|
||||
private:
|
||||
const tinygltf::Model& model;
|
||||
texture_output_format configured_format;
|
||||
bool use_exr = false; // Use EXR for 16bit image?
|
||||
|
||||
public:
|
||||
texture_dumper(const tinygltf::Model& inputModel);
|
||||
void dump_to_folder(const std::string& path = "./");
|
||||
void set_output_format(texture_output_format format);
|
||||
void set_use_exr(const bool value) {
|
||||
use_exr = value;
|
||||
}
|
||||
|
||||
static texture_output_format get_fromat_from_string(const std::string& str);
|
||||
};
|
||||
|
||||
2753
stb_image.h
2753
stb_image.h
File diff suppressed because it is too large
Load Diff
2632
stb_image_write.h
2632
stb_image_write.h
File diff suppressed because it is too large
Load Diff
138
tiny_gltf.h
138
tiny_gltf.h
@@ -26,6 +26,7 @@
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Version:
|
||||
// - v2.2.0 Add loading 16bit PNG support.
|
||||
// - v2.1.0 Add draco compression.
|
||||
// - v2.0.1 Add comparsion feature(Thanks to @Selmar).
|
||||
// - v2.0.0 glTF 2.0!.
|
||||
@@ -380,6 +381,17 @@ struct Parameter {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// Return the index of a texture coordinate set if this Parameter is a texture map.
|
||||
/// Returned value is only valid if the parameter represent a texture from a
|
||||
/// material
|
||||
int TextureTexCoord() const {
|
||||
const auto it = json_double_value.find("texCoord");
|
||||
if (it != std::end(json_double_value)) {
|
||||
return int(it->second);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Material factor, like the roughness or metalness of a material
|
||||
/// Returned value is only valid if the parameter represent a texture from a
|
||||
/// material
|
||||
@@ -468,7 +480,9 @@ struct Sampler {
|
||||
Value extras;
|
||||
|
||||
Sampler()
|
||||
: wrapS(TINYGLTF_TEXTURE_WRAP_REPEAT),
|
||||
: minFilter(TINYGLTF_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR),
|
||||
magFilter(TINYGLTF_TEXTURE_FILTER_LINEAR),
|
||||
wrapS(TINYGLTF_TEXTURE_WRAP_REPEAT),
|
||||
wrapT(TINYGLTF_TEXTURE_WRAP_REPEAT),
|
||||
wrapR(TINYGLTF_TEXTURE_WRAP_REPEAT){}
|
||||
bool operator==(const Sampler &) const;
|
||||
@@ -479,6 +493,8 @@ struct Image {
|
||||
int width;
|
||||
int height;
|
||||
int component;
|
||||
int bits; // bit depth per channel. 8(byte), 16 or 32.
|
||||
int pixel_type; // pixel type(TINYGLTF_COMPONENT_TYPE_***). usually UBYTE(bits = 8) or USHORT(bits = 16)
|
||||
std::vector<unsigned char> image;
|
||||
int bufferView; // (required if no uri)
|
||||
std::string mimeType; // (required if no uri) ["image/jpeg", "image/png",
|
||||
@@ -1062,7 +1078,19 @@ class TinyGLTF {
|
||||
#if __has_warning("-Wnewline-eof")
|
||||
#pragma clang diagnostic ignored "-Wnewline-eof"
|
||||
#endif
|
||||
#if __has_warning("-Wunused-parameter")
|
||||
#pragma clang diagnostic ignored "-Wunused-parameter"
|
||||
#endif
|
||||
#if __has_warning("-Wmismatched-tags")
|
||||
#pragma clang diagnostic ignored "-Wmismatched-tags"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Disable GCC warnigs
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wtype-limits"
|
||||
#endif // __GNUC__
|
||||
|
||||
#include "json.hpp"
|
||||
|
||||
@@ -1083,8 +1111,34 @@ class TinyGLTF {
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
|
||||
// issue 143.
|
||||
// Define NOMINMAX to avoid min/max defines,
|
||||
// but undef it after included windows.h
|
||||
#ifndef NOMINMAX
|
||||
#define TINYGLTF_INTERNAL_NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define TINYGLTF_INTERNAL_WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h> // include API for expanding a file path
|
||||
|
||||
#ifdef TINYGLTF_INTERNAL_WIN32_LEAN_AND_MEAN
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#if defined(TINYGLTF_INTERNAL_NOMINMAX)
|
||||
#undef NOMINMAX
|
||||
#endif
|
||||
|
||||
#elif !defined(__ANDROID__)
|
||||
#include <wordexp.h>
|
||||
#endif
|
||||
@@ -1598,46 +1652,73 @@ void TinyGLTF::SetImageLoader(LoadImageDataFunction func, void *user_data) {
|
||||
}
|
||||
|
||||
#ifndef TINYGLTF_NO_STB_IMAGE
|
||||
bool LoadImageData(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) {
|
||||
bool LoadImageData(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) {
|
||||
(void)user_data;
|
||||
(void)warn;
|
||||
|
||||
int w, h, comp, req_comp;
|
||||
|
||||
unsigned char *data = nullptr;
|
||||
|
||||
// force 32-bit textures for common Vulkan compatibility. It appears that
|
||||
// some GPU drivers do not support 24-bit images for Vulkan
|
||||
req_comp = 4;
|
||||
int bits = 8;
|
||||
int pixel_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE;
|
||||
|
||||
// It is possible that the image we want to load is a 16bit per channel image
|
||||
// We are going to attempt to load it as 16bit per channel, and if it worked,
|
||||
// set the image data accodingly. We are casting the returned pointer into
|
||||
// unsigned char, because we are representing "bytes". But we are updating
|
||||
// the Image metadata to signal that this image uses 2 bytes (16bits) per
|
||||
// channel:
|
||||
if (stbi_is_16_bit_from_memory(bytes, size)) {
|
||||
data = (unsigned char *)stbi_load_16_from_memory(bytes, size, &w, &h, &comp,
|
||||
req_comp);
|
||||
if (data) {
|
||||
bits = 16;
|
||||
pixel_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT;
|
||||
}
|
||||
}
|
||||
|
||||
// at this point, if data is still NULL, it means that the image wasn't
|
||||
// 16bit per channel, we are going to load it as a normal 8bit per channel
|
||||
// mage as we used to do:
|
||||
// if image cannot be decoded, ignore parsing and keep it by its path
|
||||
// don't break in this case
|
||||
// FIXME we should only enter this function if the image is embedded. If
|
||||
// image->uri references
|
||||
// an image file, it should be left as it is. Image loading should not be
|
||||
// mandatory (to support other formats)
|
||||
unsigned char *data =
|
||||
stbi_load_from_memory(bytes, size, &w, &h, &comp, req_comp);
|
||||
if (!data) data = stbi_load_from_memory(bytes, size, &w, &h, &comp, req_comp);
|
||||
if (!data) {
|
||||
// NOTE: you can use `warn` instead of `err`
|
||||
if (err) {
|
||||
(*err) += "Unknown image format. STB cannot decode image data for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\". Proably 16bit PNG?\n";
|
||||
(*err) +=
|
||||
"Unknown image format. STB cannot decode image data for image[" +
|
||||
std::to_string(image_idx) + "] name = \"" + image->name + "\".\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (w < 1 || h < 1) {
|
||||
free(data);
|
||||
stbi_image_free(data);
|
||||
if (err) {
|
||||
(*err) += "Invalid image data for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n";
|
||||
(*err) += "Invalid image data for image[" + std::to_string(image_idx) +
|
||||
"] name = \"" + image->name + "\"\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (req_width > 0) {
|
||||
if (req_width != w) {
|
||||
free(data);
|
||||
stbi_image_free(data);
|
||||
if (err) {
|
||||
(*err) += "Image width mismatch for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n";
|
||||
(*err) += "Image width mismatch for image[" +
|
||||
std::to_string(image_idx) + "] name = \"" + image->name +
|
||||
"\"\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1645,9 +1726,11 @@ bool LoadImageData(Image *image, const int image_idx, std::string *err, std::str
|
||||
|
||||
if (req_height > 0) {
|
||||
if (req_height != h) {
|
||||
free(data);
|
||||
stbi_image_free(data);
|
||||
if (err) {
|
||||
(*err) += "Image height mismatch. for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n";
|
||||
(*err) += "Image height mismatch. for image[" +
|
||||
std::to_string(image_idx) + "] name = \"" + image->name +
|
||||
"\"\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1656,10 +1739,11 @@ bool LoadImageData(Image *image, const int image_idx, std::string *err, std::str
|
||||
image->width = w;
|
||||
image->height = h;
|
||||
image->component = req_comp;
|
||||
image->image.resize(static_cast<size_t>(w * h * req_comp));
|
||||
std::copy(data, data + w * h * req_comp, image->image.begin());
|
||||
|
||||
free(data);
|
||||
image->bits = bits;
|
||||
image->pixel_type = pixel_type;
|
||||
image->image.resize(static_cast<size_t>(w * h * req_comp) * (bits / 8));
|
||||
std::copy(data, data + w * h * req_comp * (bits / 8), image->image.begin());
|
||||
stbi_image_free(data);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1689,6 +1773,11 @@ bool WriteImageData(const std::string *basepath, const std::string *filename,
|
||||
std::vector<unsigned char> data;
|
||||
|
||||
if (ext == "png") {
|
||||
if ((image->bits != 8) || (image->pixel_type != TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE)) {
|
||||
// Unsupported pixel format
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!stbi_write_png_to_func(WriteToMemory_stbi, &data, image->width,
|
||||
image->height, image->component,
|
||||
&image->image[0], 0)) {
|
||||
@@ -3045,6 +3134,8 @@ static bool ParsePrimitive(Primitive *primitive, Model *model, std::string *err,
|
||||
{
|
||||
ParseDracoExtension(primitive, model, err, dracoExtension->second);
|
||||
}
|
||||
#else
|
||||
(void)model;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
@@ -3261,13 +3352,8 @@ static bool ParseAnimation(Animation *animation, std::string *err,
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!ParseStringProperty(&sampler.interpolation, err, s,
|
||||
"interpolation", true)) {
|
||||
if (err) {
|
||||
(*err) += "`interpolation` field is missing in animation.sampler\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
ParseStringProperty(&sampler.interpolation, err, s, "interpolation",
|
||||
false);
|
||||
if (!ParseNumberProperty(&outputIndex, err, s, "output", true)) {
|
||||
if (err) {
|
||||
(*err) += "`output` field is missing in animation.sampler\n";
|
||||
@@ -4825,7 +4911,7 @@ static void WriteBinaryGltfFile(const std::string &output,
|
||||
|
||||
// 12 bytes for header, JSON content length, 8 bytes for JSON chunk info, padding
|
||||
const int length = 12 + 8 + int(content.size()) + padding_size;
|
||||
|
||||
|
||||
gltfFile.write(header.c_str(), header.size());
|
||||
gltfFile.write(reinterpret_cast<const char *>(&version), sizeof(version));
|
||||
gltfFile.write(reinterpret_cast<const char *>(&length), sizeof(length));
|
||||
|
||||
Reference in New Issue
Block a user