Merge pull request #45 from Squareys/custom-image-loaders

Allow custom image loaders
This commit is contained in:
Syoyo Fujita 2018-03-14 10:07:49 +09:00 committed by GitHub
commit 4f0b893d73
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 84 additions and 37 deletions

View File

@ -101,6 +101,7 @@ if (!ret) {
## Compile options
* `TINYGLTF_NOEXCEPTION` : Disable C++ exception in JSON parsing. You can use `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION` and `TINYGLTF_NOEXCEPTION` to fully remove C++ exception codes when compiling TinyGLTF.
* `TINYGLTF_NO_STB_IMAGE` : Do not load images with stb_image. Instead use `TinyGLTF::SetImageLoader(LoadimageDataFunction LoadImageData, void *user_data)` to set a callback for loading images.
### Saving gltTF 2.0 model

View File

@ -450,7 +450,7 @@ struct Image {
std::vector<unsigned char> image;
int bufferView; // (required if no uri)
std::string mimeType; // (required if no uri) ["image/jpeg", "image/png", "image/bmp", "image/gif"]
std::string uri; // (reqiored if no mimeType)
std::string uri; // (required if no mimeType)
Value extras;
Image() { bufferView = -1; }
@ -725,6 +725,17 @@ enum SectionCheck {
REQUIRE_ALL = 0x3f
};
///
/// LoadImageDataFunction type. Signature for custom image loading callbacks.
///
typedef bool (*LoadImageDataFunction)(Image *, std::string *, int, int, const unsigned char *, int, void *);
#ifndef TINYGLTF_NO_STB_IMAGE
// Declaration of default image loader callback
static bool LoadImageData(Image *image, std::string *err, int req_width,
int req_height, const unsigned char *bytes,
int size, void*);
#endif
class TinyGLTF {
public:
@ -788,6 +799,11 @@ class TinyGLTF {
const std::string &
filename /*, bool embedImages, bool embedBuffers, bool writeBinary*/);
///
/// Set callback to use for loading image data
///
void SetImageLoader(LoadImageDataFunction LoadImageData, void *user_data);
private:
///
/// Loads glTF asset from string(memory).
@ -801,6 +817,14 @@ class TinyGLTF {
const unsigned char *bin_data_;
size_t bin_size_;
bool is_binary_;
LoadImageDataFunction LoadImageData =
#ifndef TINYGLTF_NO_STB_IMAGE
&tinygltf::LoadImageData;
#else
nullptr;
#endif
void *load_image_user_data_ = nullptr;
};
#ifdef __clang__
@ -847,7 +871,11 @@ class TinyGLTF {
#endif
#include "./json.hpp"
#ifndef TINYGLTF_NO_STB_IMAGE
#include "./stb_image.h"
#endif
#ifdef __clang__
#pragma clang diagnostic pop
#endif
@ -1159,11 +1187,15 @@ static bool LoadExternalFile(std::vector<unsigned char> *out, std::string *err,
return true;
}
void TinyGLTF::SetImageLoader(LoadImageDataFunction func, void *user_data) {
LoadImageData = func;
load_image_user_data_ = user_data;
}
#ifndef TINYGLTF_NO_STB_IMAGE
static bool LoadImageData(Image *image, std::string *err, int req_width,
int req_height, const unsigned char *bytes,
int size) {
//std::cout << "size " << size << std::endl;
int size, void*) {
int w, h, comp;
// if image cannot be decoded, ignore parsing and keep it by its path
// don't break in this case
@ -1217,6 +1249,7 @@ static bool LoadImageData(Image *image, std::string *err, int req_width,
return true;
}
#endif
static bool IsDataURI(const std::string &in) {
std::string header = "data:application/octet-stream;base64,";
@ -1228,12 +1261,12 @@ static bool IsDataURI(const std::string &in) {
if (in.find(header) == 0) {
return true;
}
header = "data:image/png;base64,";
if (in.find(header) == 0) {
return true;
}
header = "data:image/bmp;base64,";
if(in.find(header) == 0) {
return true;
@ -1274,7 +1307,7 @@ static bool DecodeDataURI(std::vector<unsigned char> *out,
data = base64_decode(in.substr(header.size())); // cut mime string.
}
}
if (data.empty()) {
header = "data:image/bmp;base64,";
if (in.find(header) == 0) {
@ -1611,7 +1644,8 @@ static bool ParseAsset(Asset *asset, std::string *err,
static bool ParseImage(Image *image, std::string *err,
const json &o, const std::string &basedir,
bool is_binary, const unsigned char *bin_data,
size_t bin_size) {
size_t bin_size, LoadImageDataFunction* LoadImageData = nullptr,
void *user_data = nullptr) {
// A glTF image must either reference a bufferView or an image uri
double bufferView = -1;
bool isEmbedded =
@ -1703,8 +1737,14 @@ static bool ParseImage(Image *image, std::string *err,
}
}
return LoadImageData(image, err, 0, 0, &img.at(0),
static_cast<int>(img.size()));
if (*LoadImageData == nullptr) {
if (err) {
(*err) += "No LoadImageData callback specified.\n";
}
return false;
}
return (*LoadImageData)(image, err, 0, 0, &img.at(0),
static_cast<int>(img.size()), user_data);
}
static bool ParseTexture(Texture *texture, std::string *err,
@ -2560,7 +2600,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
// FIXME Maybe a better way to handle it than removing the code
{
json::const_iterator it = v.find("scenes");
json::const_iterator it = v.find("scenes");
if ((it != v.end()) && it.value().is_array()) {
// OK
} else if (check_sections & REQUIRE_SCENES) {
@ -2572,7 +2612,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
}
{
json::const_iterator it = v.find("nodes");
json::const_iterator it = v.find("nodes");
if ((it != v.end()) && it.value().is_array()) {
// OK
} else if (check_sections & REQUIRE_NODES) {
@ -2584,7 +2624,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
}
{
json::const_iterator it = v.find("accessors");
json::const_iterator it = v.find("accessors");
if ((it != v.end()) && it.value().is_array()) {
// OK
} else if (check_sections & REQUIRE_ACCESSORS) {
@ -2596,7 +2636,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
}
{
json::const_iterator it = v.find("buffers");
json::const_iterator it = v.find("buffers");
if ((it != v.end()) && it.value().is_array()) {
// OK
} else if (check_sections & REQUIRE_BUFFERS) {
@ -2608,7 +2648,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
}
{
json::const_iterator it = v.find("bufferViews");
json::const_iterator it = v.find("bufferViews");
if ((it != v.end()) && it.value().is_array()) {
// OK
} else if (check_sections & REQUIRE_BUFFER_VIEWS) {
@ -2631,7 +2671,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
// 1. Parse Asset
{
json::const_iterator it = v.find("asset");
json::const_iterator it = v.find("asset");
if ((it != v.end()) && it.value().is_object()) {
const json &root = it.value();
@ -2641,7 +2681,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
// 2. Parse extensionUsed
{
json::const_iterator it = v.find("extensionsUsed");
json::const_iterator it = v.find("extensionsUsed");
if ((it != v.end()) && it.value().is_array()) {
const json &root = it.value();
for (unsigned int i = 0; i < root.size(); ++i) {
@ -2651,7 +2691,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
}
{
json::const_iterator it = v.find("extensionsRequired");
json::const_iterator it = v.find("extensionsRequired");
if ((it != v.end()) && it.value().is_array()) {
const json &root = it.value();
for (unsigned int i = 0; i < root.size(); ++i) {
@ -2662,7 +2702,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
// 3. Parse Buffer
{
json::const_iterator rootIt = v.find("buffers");
json::const_iterator rootIt = v.find("buffers");
if ((rootIt != v.end()) && rootIt.value().is_array()) {
const json &root = rootIt.value();
@ -2685,10 +2725,10 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
}
}
}
// 4. Parse BufferView
{
json::const_iterator rootIt = v.find("bufferViews");
json::const_iterator rootIt = v.find("bufferViews");
if ((rootIt != v.end()) && rootIt.value().is_array()) {
const json &root = rootIt.value();
@ -2713,7 +2753,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
// 5. Parse Accessor
{
json::const_iterator rootIt = v.find("accessors");
json::const_iterator rootIt = v.find("accessors");
if ((rootIt != v.end()) && rootIt.value().is_array()) {
const json &root = rootIt.value();
@ -2738,7 +2778,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
// 6. Parse Mesh
{
json::const_iterator rootIt = v.find("meshes");
json::const_iterator rootIt = v.find("meshes");
if ((rootIt != v.end()) && rootIt.value().is_array()) {
const json &root = rootIt.value();
@ -2763,7 +2803,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
// 7. Parse Node
{
json::const_iterator rootIt = v.find("nodes");
json::const_iterator rootIt = v.find("nodes");
if ((rootIt != v.end()) && rootIt.value().is_array()) {
const json &root = rootIt.value();
@ -2788,7 +2828,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
// 8. Parse scenes.
{
json::const_iterator rootIt = v.find("scenes");
json::const_iterator rootIt = v.find("scenes");
if ((rootIt != v.end()) && rootIt.value().is_array()) {
const json &root = rootIt.value();
@ -2823,7 +2863,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
// 9. Parse default scenes.
{
json::const_iterator rootIt = v.find("scene");
json::const_iterator rootIt = v.find("scene");
if ((rootIt != v.end()) && rootIt.value().is_number_integer()) {
const int defaultScene = rootIt.value();
@ -2833,7 +2873,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
// 10. Parse Material
{
json::const_iterator rootIt = v.find("materials");
json::const_iterator rootIt = v.find("materials");
if ((rootIt != v.end()) && rootIt.value().is_array()) {
const json &root = rootIt.value();
@ -2862,7 +2902,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
// 11. Parse Image
{
json::const_iterator rootIt = v.find("images");
json::const_iterator rootIt = v.find("images");
if ((rootIt != v.end()) && rootIt.value().is_array()) {
const json &root = rootIt.value();
@ -2877,7 +2917,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
}
Image image;
if (!ParseImage(&image, err, it.value(), base_dir,
is_binary_, bin_data_, bin_size_)) {
is_binary_, bin_data_, bin_size_, &this->LoadImageData, load_image_user_data_)) {
return false;
}
@ -2897,9 +2937,15 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
model->bufferViews[size_t(image.bufferView)];
const Buffer &buffer = model->buffers[size_t(bufferView.buffer)];
if (*LoadImageData == nullptr) {
if (err) {
(*err) += "No LoadImageData callback specified.\n";
}
return false;
}
bool ret = LoadImageData(&image, err, image.width, image.height,
&buffer.data[bufferView.byteOffset],
static_cast<int>(bufferView.byteLength));
static_cast<int>(bufferView.byteLength), load_image_user_data_);
if (!ret) {
return false;
}
@ -2912,7 +2958,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
// 12. Parse Texture
{
json::const_iterator rootIt = v.find("textures");
json::const_iterator rootIt = v.find("textures");
if ((rootIt != v.end()) && rootIt.value().is_array()) {
const json &root = rootIt.value();
@ -2937,7 +2983,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
// 13. Parse Animation
{
json::const_iterator rootIt = v.find("animations");
json::const_iterator rootIt = v.find("animations");
if ((rootIt != v.end()) && rootIt.value().is_array()) {
const json &root = rootIt.value();
@ -2962,7 +3008,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
// 14. Parse Skin
{
json::const_iterator rootIt = v.find("skins");
json::const_iterator rootIt = v.find("skins");
if ((rootIt != v.end()) && rootIt.value().is_array()) {
const json &root = rootIt.value();
@ -2987,7 +3033,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
// 15. Parse Sampler
{
json::const_iterator rootIt = v.find("samplers");
json::const_iterator rootIt = v.find("samplers");
if ((rootIt != v.end()) && rootIt.value().is_array()) {
const json &root = rootIt.value();
@ -3012,7 +3058,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
// 16. Parse Camera
{
json::const_iterator rootIt = v.find("cameras");
json::const_iterator rootIt = v.find("cameras");
if ((rootIt != v.end()) && rootIt.value().is_array()) {
const json &root = rootIt.value();
@ -3037,7 +3083,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
// 17. Parse Extensions
{
json::const_iterator rootIt = v.find("extensions");
json::const_iterator rootIt = v.find("extensions");
if ((rootIt != v.end()) && rootIt.value().is_object()) {
const json &root = rootIt.value();
@ -3283,7 +3329,7 @@ static void SerializeValue(const std::string &key, const Value &value,
for (unsigned int i = 0; i < valueKeys.size(); ++i) {
Value elementValue = value.Get(valueKeys[i]);
if (elementValue.IsInt())
jsonValue[valueKeys[i]] =
jsonValue[valueKeys[i]] =
static_cast<double>(elementValue.Get<int>());
}