Compare commits

..

9 Commits

Author SHA1 Message Date
Syoyo Fujita
1b7994a4f4 Make lodepng optional. 2019-01-14 21:33:56 +09:00
Syoyo Fujita
c91b6468e8 Merge pull request #133 from Ybalrid/lodepng
fix ci build of example
2019-01-11 02:29:29 +09:00
Arthur Brainville (Ybalrid)
d4f8fcea10 fix ci build of example 2019-01-10 18:19:20 +00:00
Syoyo Fujita
ab069ffb40 Initial support of loading 16bit PNG using lodepng. 2019-01-07 02:27:28 +09:00
Syoyo Fujita
cbf13fef62 Merge branch 'master' into lodepng 2019-01-07 01:05:12 +09:00
Syoyo Fujita
57074aee04 Add single file version of lodepng. 2019-01-07 01:04:37 +09:00
Syoyo Fujita
af3ebb2e76 Show more expressive messages when parsing image. 2019-01-06 18:55:57 +09:00
Syoyo Fujita
105694b468 Merge pull request #129 from SaschaWillems/master
Added new compiler option for loading all gltf related files from android app asset package
2018-12-29 12:33:34 +09:00
Sascha Willems
5f9cb24245 Added new feature for loading all gltf related files (including textures, binaries, etc.) from assets packaged with an Android app 2018-12-28 20:53:41 +01:00
12 changed files with 8028 additions and 548 deletions

21
LICENSE.lodepng Normal file
View 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.

View File

@@ -62,7 +62,6 @@ v2.0.0 release(22 Aug, 2018)!
## TODOs
* [ ] Sparse accesors(e.g. for efficient morph targets)
* [ ] Write C++ code generator which emits C++ code from JSON schema for robust parsing.
* [ ] Mesh Compression/decompression(Open3DGC, etc)
* [ ] Load Draco compressed mesh
@@ -83,6 +82,7 @@ TinyGLTF uses the following third party libraries.
* base64 : Copyright (C) 2004-2008 René Nyffenegger
* stb_image.h : v2.08 - public domain image loader - [Github link](https://github.com/nothings/stb/blob/master/stb_image.h)
* stb_image_write.h : v1.09 - public domain image writer - [Github link](https://github.com/nothings/stb/blob/master/stb_image_write.h)
* lodepng : Copyright (c) 2005-2018 Lode Vandevenne. zlib license. https://lodev.org/lodepng/
## Build and example
@@ -129,6 +129,8 @@ if (!ret) {
* `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.
* `TINYGLTF_NO_STB_IMAGE_WRITE` : Do not write images with stb_image_write. Instead use `TinyGLTF::SetImageWriter(WriteimageDataFunction WriteImageData, void *user_data)` to set a callback for writing images.
* `TINYGLTF_NO_EXTERNAL_IMAGE` : Do not try to load external image file. This option woulde be helpful if you do not want load image file during glTF parsing.
* `TINYGLTF_ANDROID_LOAD_FROM_ASSETS`: Load all files from packaged app assets instead of the regular file system. **Note:** You must pass a valid asset manager from your android app to `tinygltf::asset_manager` beforehand.
* `TINYGLTF_USE_LODEPNG` : Load 16bit PNG image with lodepng(Valid when `TINYGLTF_NO_STB_IMAGE` was **not** defined). Must defined `LODEPNG_IMPLEMENTATION` in one .cc.
### Saving gltTF 2.0 model
* [ ] Buffers.
@@ -170,4 +172,5 @@ $ ./tester_noexcept
* json.hpp : Licensed under the MIT License <http://opensource.org/licenses/MIT>. Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
* stb_image : Public domain.
* lodepng : zlib license
* catch : Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. Distributed under the Boost Software License, Version 1.0.

View File

@@ -1,6 +0,0 @@
# Use this for strict compilation check(will work on clang 3.8+)
#EXTRA_CXXFLAGS := -fsanitize=address -Wall -Werror -Weverything -Wno-c++11-long-long -Wno-c++98-compat
all:
clang++ -I../../ $(EXTRA_CXXFLAGS) -std=c++11 -g -O0 -o anim-dump anim-dump.cc

View File

@@ -1,2 +0,0 @@
# Simple animation value dumper

View File

@@ -1,178 +0,0 @@
//
// TODO(syoyo): Print extensions and extras for each glTF object.
//
#include "tiny_gltf_util.h"
#define TINYGLTF_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "tiny_gltf.h"
#include <cstdio>
#include <fstream>
#include <iostream>
static std::string GetFilePathExtension(const std::string &FileName) {
if (FileName.find_last_of(".") != std::string::npos)
return FileName.substr(FileName.find_last_of(".") + 1);
return "";
}
static std::string Indent(const int indent) {
std::string s;
for (int i = 0; i < indent; i++) {
s += " ";
}
return s;
}
static void ProcessAnimation(const tinygltf::Animation &animation, const tinygltf::Model &model)
{
#if 0
if (animaton_channel.target_path.compare("translation") == 0) {
} else if (animaton_channel.target_path.compare("rotation") == 0) {
} else if (animaton_channel.target_path.compare("scale") == 0) {
} else if (animaton_channel.target_path.compare("weights") == 0) {
}
#endif
for (size_t j = 0; j < animation.samplers.size(); j++) {
std::cout << "== samplers[" << j << "] ===============" << std::endl;
const tinygltf::AnimationSampler &sampler = animation.samplers[j];
std::cout << Indent(1) << "interpolation = " << sampler.interpolation<< std::endl;
std::cout << Indent(1) << "input = " << sampler.input << std::endl;
std::cout << Indent(1) << "output = " << sampler.output << std::endl;
// input accessor must have min/max property.
const tinygltf::Accessor &accessor = model.accessors[sampler.input];
for (size_t i = 0; i < accessor.minValues.size(); i++) {
std::cout << Indent(1) << "input min[" << i << "] = " << accessor.minValues[i] << std::endl;
}
for (size_t i = 0; i < accessor.maxValues.size(); i++) {
std::cout << Indent(1) << "input max[" << i << "] = " << accessor.maxValues[i] << std::endl;
}
std::cout << Indent(1) << "input count = " << accessor.count << std::endl;
for (size_t i = 0; i < accessor.count; i++) {
if (accessor.type == TINYGLTF_TYPE_SCALAR) {
float v;
if (tinygltf::util::DecodeScalarAnimationValue(i, accessor, model, &v)) {
std::cout << Indent(2) << "input value[" << i << "] = " << v << std::endl;
}
}
}
//const tinygltf::Accessor &accessor = model.accessors[sampler.output];
//std::cout << Indent(2) << "output : " << sampler.output
// << std::endl;
}
}
static void DumpAnim(const tinygltf::Model &model) {
std::cout << "=== Dump glTF ===" << std::endl;
std::cout << "asset.copyright : " << model.asset.copyright
<< std::endl;
std::cout << "asset.generator : " << model.asset.generator
<< std::endl;
std::cout << "asset.version : " << model.asset.version
<< std::endl;
std::cout << "asset.minVersion : " << model.asset.minVersion
<< std::endl;
std::cout << std::endl;
std::cout << "=== Dump scene ===" << std::endl;
std::cout << "defaultScene: " << model.defaultScene << std::endl;
{
std::cout << "animations(items=" << model.animations.size() << ")"
<< std::endl;
for (size_t i = 0; i < model.animations.size(); i++) {
const tinygltf::Animation &animation = model.animations[i];
std::cout << Indent(1) << "name : " << animation.name
<< std::endl;
std::cout << Indent(1) << "channels : [ " << std::endl;
for (size_t j = 0; i < animation.channels.size(); i++) {
std::cout << Indent(2)
<< "sampler : " << animation.channels[j].sampler
<< std::endl;
std::cout << Indent(2)
<< "target.id : " << animation.channels[j].target_node
<< std::endl;
std::cout << Indent(2)
<< "target.path : " << animation.channels[j].target_path
<< std::endl;
std::cout << ((i != (animation.channels.size() - 1)) ? " , " : "");
}
std::cout << " ]" << std::endl;
std::cout << Indent(1) << "samplers(items=" << animation.samplers.size()
<< ")" << std::endl;
for (size_t j = 0; j < animation.samplers.size(); j++) {
const tinygltf::AnimationSampler &sampler = animation.samplers[j];
std::cout << Indent(2) << "input : " << sampler.input
<< std::endl;
std::cout << Indent(2) << "interpolation : " << sampler.interpolation
<< std::endl;
std::cout << Indent(2) << "output : " << sampler.output
<< std::endl;
}
ProcessAnimation(animation, model);
}
}
}
int main(int argc, char **argv) {
if (argc < 2) {
printf("Needs input.gltf\n");
exit(1);
}
tinygltf::Model model;
tinygltf::TinyGLTF gltf_ctx;
std::string err;
std::string warn;
std::string input_filename(argv[1]);
std::string ext = GetFilePathExtension(input_filename);
bool ret = false;
if (ext.compare("glb") == 0) {
std::cout << "Reading binary glTF" << std::endl;
// assume binary glTF.
ret = gltf_ctx.LoadBinaryFromFile(&model, &err, &warn, input_filename.c_str());
} else {
std::cout << "Reading ASCII glTF" << std::endl;
// assume ascii glTF.
ret = gltf_ctx.LoadASCIIFromFile(&model, &err, &warn, input_filename.c_str());
}
if (!warn.empty()) {
printf("Warn: %s\n", warn.c_str());
}
if (!err.empty()) {
printf("Err: %s\n", err.c_str());
}
if (!ret) {
printf("Failed to parse glTF\n");
return -1;
}
DumpAnim(model);
return 0;
}

View File

@@ -0,0 +1,6 @@
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define LODEPNG_IMPLEMENTATION
#include "lodepng.h"

View File

@@ -1,3 +1,5 @@
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define LODEPNG_IMPLEMENTATION
#include "lodepng.h"

View File

@@ -9,7 +9,7 @@ newoption {
}
sources = {
"stbi-impl.cc",
"img-loaders.cc",
"main.cc",
"render.cc",
"render-config.cc",

View File

@@ -4,6 +4,7 @@
#define TINYGLTF_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#define LODEPNG_IMPLEMENTATION
#include "tiny_gltf.h"
#include <cstdio>

7866
lodepng.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -34,6 +34,7 @@
// - jsonhpp: C++ JSON library.
// - base64: base64 decode/encode library.
// - stb_image: Image loading library.
// - lodepng: Load 16bit PNG.
//
#ifndef TINY_GLTF_H_
#define TINY_GLTF_H_
@@ -47,6 +48,12 @@
#include <string>
#include <vector>
#ifdef __ANDROID__
#ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS
#include <android/asset_manager.h>
#endif
#endif
namespace tinygltf {
#define TINYGLTF_MODE_POINTS (0)
@@ -56,7 +63,6 @@ namespace tinygltf {
#define TINYGLTF_MODE_TRIANGLE_STRIP (5)
#define TINYGLTF_MODE_TRIANGLE_FAN (6)
#define TINYGLTF_COMPONENT_TYPE_INVALID (-1)
#define TINYGLTF_COMPONENT_TYPE_BYTE (5120)
#define TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE (5121)
#define TINYGLTF_COMPONENT_TYPE_SHORT (5122)
@@ -107,7 +113,6 @@ namespace tinygltf {
// End parameter types
#define TINYGLTF_TYPE_INVALID (-1)
#define TINYGLTF_TYPE_VEC2 (2)
#define TINYGLTF_TYPE_VEC3 (3)
#define TINYGLTF_TYPE_VEC4 (4)
@@ -141,6 +146,12 @@ namespace tinygltf {
#define TINYGLTF_DOUBLE_EPS (1.e-12)
#define TINYGLTF_DOUBLE_EQUAL(a, b) (std::fabs((b) - (a)) < TINYGLTF_DOUBLE_EPS)
#ifdef __ANDROID__
#ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS
AAssetManager* asset_manager = nullptr;
#endif
#endif
typedef enum {
NULL_TYPE = 0,
NUMBER_TYPE = 1,
@@ -418,7 +429,6 @@ struct AnimationSampler {
AnimationSampler() : input(-1), output(-1), interpolation("LINEAR") {}
bool operator==(const AnimationSampler &) const;
};
struct Animation {
@@ -467,8 +477,10 @@ struct Image {
std::string name;
int width;
int height;
int component;
std::vector<unsigned char> image;
int component; // channels. e.g. RGB=3, RGBA=4
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; // width * height * component * (bits/8)
int bufferView; // (required if no uri)
std::string mimeType; // (required if no uri) ["image/jpeg", "image/png",
// "image/bmp", "image/gif"]
@@ -489,6 +501,8 @@ struct Image {
width = -1;
height = -1;
component = -1;
bits = -1;
pixel_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE;
}
bool operator==(const Image &) const;
};
@@ -538,11 +552,11 @@ struct Accessor {
int bufferView; // optional in spec but required here since sparse accessor
// are not supported
std::string name;
size_t byteOffset = 0;
bool normalized = false; // optinal.
int componentType = TINYGLTF_COMPONENT_TYPE_INVALID; // (required) One of TINYGLTF_COMPONENT_TYPE_***
size_t count = 0; // required
int type = TINYGLTF_TYPE_INVALID; // (required) One of TINYGLTF_TYPE_*** ..
size_t byteOffset;
bool normalized; // optinal.
int componentType; // (required) One of TINYGLTF_COMPONENT_TYPE_***
size_t count; // required
int type; // (required) One of TINYGLTF_TYPE_*** ..
Value extras;
std::vector<double> minValues; // optional
@@ -591,7 +605,6 @@ struct Accessor {
bool operator==(const tinygltf::Accessor &) const;
};
struct PerspectiveCamera {
double aspectRatio; // min > 0
double yfov; // required. min > 0
@@ -779,14 +792,6 @@ class Model {
Value extras;
};
///
/// Utility function to get an address of underlying buffer for i'th element.
/// Returns nullptr for invalid parameter or invalid data.
/// Assume `buffer` parameter = model.buffers[bufferViewObject.buffer]
///
const uint8_t *GetBufferAddress(const int i, const Accessor &accessor, const BufferView &bufferViewObject, const Buffer &buffer);
enum SectionCheck {
NO_REQUIRE = 0x00,
REQUIRE_SCENE = 0x01,
@@ -801,7 +806,7 @@ enum SectionCheck {
///
/// LoadImageDataFunction type. Signature for custom image loading callbacks.
///
typedef bool (*LoadImageDataFunction)(Image *, std::string *, std::string *,
typedef bool (*LoadImageDataFunction)(Image *, const int, std::string *, std::string *,
int, int, const unsigned char *, int,
void *);
@@ -813,7 +818,7 @@ typedef bool (*WriteImageDataFunction)(const std::string *, const std::string *,
#ifndef TINYGLTF_NO_STB_IMAGE
// Declaration of default image loader callback
bool LoadImageData(Image *image, std::string *err, std::string *warn,
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 *);
#endif
@@ -1070,6 +1075,10 @@ class TinyGLTF {
#include "./stb_image_write.h"
#endif
#if defined(TINYGLTF_USE_LODEPNG)
#include "./lodepng.h"
#endif
#ifdef __clang__
#pragma clang diagnostic pop
#endif
@@ -1203,6 +1212,7 @@ bool Camera::operator==(const Camera &other) const {
bool Image::operator==(const Image &other) const {
return this->bufferView == other.bufferView &&
this->component == other.component && this->extras == other.extras &&
this->bits == other.bits &&
this->height == other.height && this->image == other.image &&
this->mimeType == other.mimeType && this->name == other.name &&
this->uri == other.uri && this->width == other.width;
@@ -1588,9 +1598,9 @@ void TinyGLTF::SetImageLoader(LoadImageDataFunction func, void *user_data) {
}
#ifndef TINYGLTF_NO_STB_IMAGE
bool LoadImageData(Image *image, std::string *err, std::string *warn,
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 *) {
int size, void *user_data) {
(void)warn;
int w, h, comp, req_comp;
@@ -1599,6 +1609,9 @@ bool LoadImageData(Image *image, std::string *err, std::string *warn,
// 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;
// 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
@@ -1608,17 +1621,34 @@ bool LoadImageData(Image *image, std::string *err, std::string *warn,
unsigned char *data =
stbi_load_from_memory(bytes, size, &w, &h, &comp, req_comp);
if (!data) {
#if defined(TINYGLTF_USE_LODEPNG)
// try to load as 16bit PNG RGBA
unsigned ret = lodepng_decode_memory(&data, reinterpret_cast<unsigned *>(&w), reinterpret_cast<unsigned *>(&h), bytes, size, LCT_RGBA, /* bitdepth*/16);
if (ret != 0) {
// NOTE: you can use `warn` instead of `err`
if (err) {
(*err) += "Unknown image format. STB and LodePNG cannot decode image data for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\".\n";
}
return false;
}
bits = 16;
pixel_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT;
#else
// NOTE: you can use `warn` instead of `err`
if (err) {
(*err) += "Unknown image format.\n";
(*err) += "Unknown image format. STB cannot decode image data for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\". Proably 16bit PNG?\n";
}
return false;
#endif
}
if (w < 1 || h < 1) {
free(data);
if (err) {
(*err) += "Invalid image data.\n";
(*err) += "Invalid image data for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n";
}
return false;
}
@@ -1627,7 +1657,7 @@ bool LoadImageData(Image *image, std::string *err, std::string *warn,
if (req_width != w) {
free(data);
if (err) {
(*err) += "Image width mismatch.\n";
(*err) += "Image width mismatch for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n";
}
return false;
}
@@ -1637,7 +1667,7 @@ bool LoadImageData(Image *image, std::string *err, std::string *warn,
if (req_height != h) {
free(data);
if (err) {
(*err) += "Image height mismatch.\n";
(*err) += "Image height mismatch. for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n";
}
return false;
}
@@ -1646,8 +1676,10 @@ bool LoadImageData(Image *image, std::string *err, std::string *warn,
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());
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());
free(data);
@@ -1741,6 +1773,18 @@ void TinyGLTF::SetFsCallbacks(FsCallbacks callbacks) { fs = callbacks; }
bool FileExists(const std::string &abs_filename, void *) {
bool ret;
#ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS
if (asset_manager) {
AAsset* asset = AAssetManager_open(asset_manager, abs_filename.c_str(), AASSET_MODE_STREAMING);
if (!asset) {
return false;
}
AAsset_close(asset);
ret = true;
} else {
return false;
}
#else
#ifdef _WIN32
FILE *fp;
errno_t err = fopen_s(&fp, abs_filename.c_str(), "rb");
@@ -1756,6 +1800,7 @@ bool FileExists(const std::string &abs_filename, void *) {
} else {
ret = false;
}
#endif
return ret;
}
@@ -1809,6 +1854,33 @@ std::string ExpandFilePath(const std::string &filepath, void *) {
bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
const std::string &filepath, void *) {
#ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS
if (asset_manager) {
AAsset* asset = AAssetManager_open(asset_manager, filepath.c_str(), AASSET_MODE_STREAMING);
if (!asset) {
if (err) {
(*err) += "File open error : " + filepath + "\n";
}
return false;
}
size_t size = AAsset_getLength(asset);
if (size <= 0) {
if (err) {
(*err) += "Invalid file size : " + filepath +
" (does the path point to a directory?)";
}
}
out->resize(size);
AAsset_read(asset, reinterpret_cast<char *>(&out->at(0)), size);
AAsset_close(asset);
return true;
} else {
if (err) {
(*err) += "No asset manager specified : " + filepath + "\n";
}
return false;
}
#else
std::ifstream f(filepath.c_str(), std::ifstream::binary);
if (!f) {
if (err) {
@@ -1840,6 +1912,7 @@ bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
f.close();
return true;
#endif
}
bool WriteWholeFile(std::string *err, const std::string &filepath,
@@ -2020,21 +2093,6 @@ bool DecodeDataURI(std::vector<unsigned char> *out, std::string &mime_type,
return true;
}
const uint8_t *GetBufferAddress(const int i, const Accessor &accessor, const BufferView &bufferViewObject, const Buffer &buffer) {
if (i >= int(accessor.count)) return nullptr;
int byte_stride = accessor.ByteStride(bufferViewObject);
if (byte_stride == -1) {
return nullptr;
}
// TODO(syoyo): Bounds check.
const uint8_t *base_addr = buffer.data.data() + bufferViewObject.byteOffset + accessor.byteOffset;
const uint8_t *addr = base_addr + i * byte_stride;
return addr;
}
static bool ParseJsonAsValue(Value *ret, const json &o) {
Value val{};
switch (o.type()) {
@@ -2401,7 +2459,7 @@ static bool ParseAsset(Asset *asset, std::string *err, const json &o) {
return true;
}
static bool ParseImage(Image *image, std::string *err, std::string *warn,
static bool ParseImage(Image *image, const int image_idx, std::string *err, std::string *warn,
const json &o, const std::string &basedir,
FsCallbacks *fs,
LoadImageDataFunction *LoadImageData = nullptr,
@@ -2413,24 +2471,25 @@ static bool ParseImage(Image *image, std::string *err, std::string *warn,
bool hasBufferView = (o.find("bufferView") != o.end());
bool hasURI = (o.find("uri") != o.end());
ParseStringProperty(&image->name, err, o, "name", false);
if (hasBufferView && hasURI) {
// Should not both defined.
if (err) {
(*err) +=
"Only one of `bufferView` or `uri` should be defined, but both are "
"defined for Image.\n";
"defined for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n";
}
return false;
}
if (!hasBufferView && !hasURI) {
if (err) {
(*err) += "Neither required `bufferView` nor `uri` defined for Image.\n";
(*err) += "Neither required `bufferView` nor `uri` defined for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n";
}
return false;
}
ParseStringProperty(&image->name, err, o, "name", false);
ParseExtensionsProperty(&image->extensions, err, o);
ParseExtrasProperty(&image->extras, o);
@@ -2438,7 +2497,7 @@ static bool ParseImage(Image *image, std::string *err, std::string *warn,
double bufferView = -1;
if (!ParseNumberProperty(&bufferView, err, o, "bufferView", true)) {
if (err) {
(*err) += "Failed to parse `bufferView` for Image.\n";
(*err) += "Failed to parse `bufferView` for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n";
}
return false;
}
@@ -2468,7 +2527,7 @@ static bool ParseImage(Image *image, std::string *err, std::string *warn,
std::string tmp_err;
if (!ParseStringProperty(&uri, &tmp_err, o, "uri", true)) {
if (err) {
(*err) += "Failed to parse `uri` for Image.\n";
(*err) += "Failed to parse `uri` for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\".\n";
}
return false;
}
@@ -2478,7 +2537,7 @@ static bool ParseImage(Image *image, std::string *err, std::string *warn,
if (IsDataURI(uri)) {
if (!DecodeDataURI(&img, image->mimeType, uri, 0, false)) {
if (err) {
(*err) += "Failed to decode 'uri' for image parameter.\n";
(*err) += "Failed to decode 'uri' for image[" + std::to_string(image_idx) + "] name = [" + image->name + "]\n";
}
return false;
}
@@ -2487,11 +2546,12 @@ static bool ParseImage(Image *image, std::string *err, std::string *warn,
// Keep texture path (for textures that cannot be decoded)
image->uri = uri;
#ifdef TINYGLTF_NO_EXTERNAL_IMAGE
// TODO(syoyo): Call LoadImageData callback?
return true;
#endif
if (!LoadExternalFile(&img, err, warn, uri, basedir, false, 0, false, fs)) {
if (warn) {
(*warn) += "Failed to load external 'uri' for image parameter\n";
(*warn) += "Failed to load external 'uri' for image[" + std::to_string(image_idx) + "] name = [" + image->name + "]\n";
}
// If the image cannot be loaded, keep uri as image->uri.
return true;
@@ -2499,7 +2559,7 @@ static bool ParseImage(Image *image, std::string *err, std::string *warn,
if (img.empty()) {
if (warn) {
(*warn) += "Image is empty.\n";
(*warn) += "Image data is empty for image[" + std::to_string(image_idx) + "] name = [" + image->name + "] \n";
}
return false;
}
@@ -2511,7 +2571,7 @@ static bool ParseImage(Image *image, std::string *err, std::string *warn,
}
return false;
}
return (*LoadImageData)(image, err, warn, 0, 0, &img.at(0),
return (*LoadImageData)(image, image_idx, err, warn, 0, 0, &img.at(0),
static_cast<int>(img.size()), load_image_user_data);
}
@@ -3515,7 +3575,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
{
if (primitive.indices > -1) // has indices from parsing step, must be Element Array Buffer
{
model->bufferViews[size_t(model->accessors[size_t(primitive.indices)].bufferView)]
model->bufferViews[model->accessors[primitive.indices].bufferView]
.target = TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER;
// we could optionally check if acessors' bufferView type is Scalar, as it should be
}
@@ -3639,15 +3699,16 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
json::const_iterator it(root.begin());
json::const_iterator itEnd(root.end());
for (; it != itEnd; it++) {
int idx = 0;
for (; it != itEnd; it++, idx++) {
if (!it.value().is_object()) {
if (err) {
(*err) += "`images' does not contain an JSON object.";
(*err) += "image[" + std::to_string(idx) + "] is not a JSON object.";
}
return false;
}
Image image;
if (!ParseImage(&image, err, warn, it.value(), base_dir, &fs,
if (!ParseImage(&image, idx, err, warn, it.value(), base_dir, &fs,
&this->LoadImageData, load_image_user_data_)) {
return false;
}
@@ -3657,7 +3718,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
if (size_t(image.bufferView) >= model->bufferViews.size()) {
if (err) {
std::stringstream ss;
ss << "bufferView \"" << image.bufferView
ss << "image[" << idx << "] bufferView \"" << image.bufferView
<< "\" not found in the scene." << std::endl;
(*err) += ss.str();
}
@@ -3674,7 +3735,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
}
return false;
}
bool ret = LoadImageData(&image, err, warn, image.width, image.height,
bool ret = LoadImageData(&image, idx, err, warn, image.width, image.height,
&buffer.data[bufferView.byteOffset],
static_cast<int>(bufferView.byteLength),
load_image_user_data_);
@@ -4602,23 +4663,23 @@ static void WriteBinaryGltfFile(const std::string &output,
const int padding_size = content.size() % 4;
// 12 bytes for header, JSON content length, 8 bytes for JSON chunk info, padding
const int length = 12 + 8 + int(content.size()) + padding_size;
const int length = 12 + 8 + content.size() + padding_size;
gltfFile.write(header.c_str(), std::streamsize(header.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));
// JSON chunk info, then JSON data
const int model_length = int(content.size()) + padding_size;
const int model_length = content.size() + padding_size;
const int model_format = 0x4E4F534A;
gltfFile.write(reinterpret_cast<const char *>(&model_length), sizeof(model_length));
gltfFile.write(reinterpret_cast<const char *>(&model_format), sizeof(model_format));
gltfFile.write(content.c_str(), std::streamsize(content.size()));
gltfFile.write(content.c_str(), content.size());
// Chunk must be multiplies of 4, so pad with spaces
if (padding_size > 0) {
const std::string padding = std::string(size_t(padding_size), ' ');
gltfFile.write(padding.c_str(), std::streamsize(padding.size()));
const std::string padding = std::string(padding_size, ' ');
gltfFile.write(padding.c_str(), padding.size());
}
}

View File

@@ -1,294 +0,0 @@
//
// TinyGLTF utility functions
//
//
// The MIT License (MIT)
//
// Copyright (c) 2015 - 2018 Syoyo Fujita, Aurélien Chatelain and many
// contributors.
//
#include <iostream>
#include "tiny_gltf.h"
namespace tinygltf {
namespace util {
static std::string PrintMode(int mode) {
if (mode == TINYGLTF_MODE_POINTS) {
return "POINTS";
} else if (mode == TINYGLTF_MODE_LINE) {
return "LINE";
} else if (mode == TINYGLTF_MODE_LINE_LOOP) {
return "LINE_LOOP";
} else if (mode == TINYGLTF_MODE_TRIANGLES) {
return "TRIANGLES";
} else if (mode == TINYGLTF_MODE_TRIANGLE_FAN) {
return "TRIANGLE_FAN";
} else if (mode == TINYGLTF_MODE_TRIANGLE_STRIP) {
return "TRIANGLE_STRIP";
}
return "**UNKNOWN**";
}
static std::string PrintTarget(int target) {
if (target == 34962) {
return "GL_ARRAY_BUFFER";
} else if (target == 34963) {
return "GL_ELEMENT_ARRAY_BUFFER";
} else {
return "**UNKNOWN**";
}
}
static std::string PrintType(int ty) {
if (ty == TINYGLTF_TYPE_SCALAR) {
return "SCALAR";
} else if (ty == TINYGLTF_TYPE_VECTOR) {
return "VECTOR";
} else if (ty == TINYGLTF_TYPE_VEC2) {
return "VEC2";
} else if (ty == TINYGLTF_TYPE_VEC3) {
return "VEC3";
} else if (ty == TINYGLTF_TYPE_VEC4) {
return "VEC4";
} else if (ty == TINYGLTF_TYPE_MATRIX) {
return "MATRIX";
} else if (ty == TINYGLTF_TYPE_MAT2) {
return "MAT2";
} else if (ty == TINYGLTF_TYPE_MAT3) {
return "MAT3";
} else if (ty == TINYGLTF_TYPE_MAT4) {
return "MAT4";
}
return "**UNKNOWN**";
}
static std::string PrintComponentType(int ty) {
if (ty == TINYGLTF_COMPONENT_TYPE_BYTE) {
return "BYTE";
} else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
return "UNSIGNED_BYTE";
} else if (ty == TINYGLTF_COMPONENT_TYPE_SHORT) {
return "SHORT";
} else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
return "UNSIGNED_SHORT";
} else if (ty == TINYGLTF_COMPONENT_TYPE_INT) {
return "INT";
} else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) {
return "UNSIGNED_INT";
} else if (ty == TINYGLTF_COMPONENT_TYPE_FLOAT) {
return "FLOAT";
} else if (ty == TINYGLTF_COMPONENT_TYPE_DOUBLE) {
return "DOUBLE";
}
return "**UNKNOWN**";
}
static std::string PrintWrapMode(int mode) {
if (mode == TINYGLTF_TEXTURE_WRAP_REPEAT) {
return "REPEAT";
} else if (mode == TINYGLTF_TEXTURE_WRAP_CLAMP_TO_EDGE) {
return "CLAMP_TO_EDGE";
} else if (mode == TINYGLTF_TEXTURE_WRAP_MIRRORED_REPEAT) {
return "MIRRORED_REPEAT";
}
return "**UNKNOWN**";
}
static std::string PrintFilterMode(int mode) {
if (mode == TINYGLTF_TEXTURE_FILTER_NEAREST) {
return "NEAREST";
} else if (mode == TINYGLTF_TEXTURE_FILTER_LINEAR) {
return "LINEAR";
} else if (mode == TINYGLTF_TEXTURE_FILTER_NEAREST_MIPMAP_NEAREST) {
return "NEAREST_MIPMAP_NEAREST";
} else if (mode == TINYGLTF_TEXTURE_FILTER_NEAREST_MIPMAP_LINEAR) {
return "NEAREST_MIPMAP_LINEAR";
} else if (mode == TINYGLTF_TEXTURE_FILTER_LINEAR_MIPMAP_NEAREST) {
return "LINEAR_MIPMAP_NEAREST";
} else if (mode == TINYGLTF_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR) {
return "LINEAR_MIPMAP_LINEAR";
}
return "**UNKNOWN**";
}
static int GetAnimationSamplerInputCount(const tinygltf::AnimationSampler &sampler, const tinygltf::Model &model)
{
const tinygltf::Accessor &accessor = model.accessors[sampler.input];
return accessor.count;
}
static int GetAnimationSamplerOutputCount(const tinygltf::AnimationSampler &sampler, const tinygltf::Model &model)
{
const tinygltf::Accessor &accessor = model.accessors[sampler.output];
return accessor.count;
}
static bool GetAnimationSamplerInputMinMax(const tinygltf::AnimationSampler &sampler, const tinygltf::Model &model, float *min_value, float *max_value)
{
const tinygltf::Accessor &accessor = model.accessors[sampler.input];
// Assume scalar value.
if ((accessor.minValues.size() > 0) &&
(accessor.maxValues.size() > 0)) {
(*min_value) = accessor.minValues[0];
(*max_value) = accessor.maxValues[0];
return true;
} else {
(*min_value) = 0.0f;
(*max_value) = 0.0f;
return false;
}
}
// Utility function for decoding animation value
static inline float DecodeAnimationChannelValue(int8_t c) {
return std::max(float(c) / 127.0f, -1.0f);
}
static inline float DecodeAnimationChannelValue(uint8_t c) {
return float(c) / 255.0f;
}
static inline float DecodeAnimationChannelValue(int16_t c) {
return std::max(float(c) / 32767.0f, -1.0f);
}
static inline float DecodeAnimationChannelValue(uint16_t c) {
return float(c) / 65525.0f;
}
static bool DecodeScalarAnimationValue(const size_t i, const tinygltf::Accessor &accessor, const tinygltf::Model &model, float *scalar)
{
const BufferView &bufferView = model.bufferViews[accessor.bufferView];
const Buffer &buffer = model.buffers[bufferView.buffer];
const uint8_t *addr = GetBufferAddress(i, accessor, bufferView, buffer);
if (addr == nullptr) {
std::cerr << "Invalid glTF data?" << std::endl;
return false;
}
float value = 0.0f;
if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_BYTE) {
value = DecodeAnimationChannelValue(*(reinterpret_cast<const int8_t*>(addr)));
} else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
value = DecodeAnimationChannelValue(*(reinterpret_cast<const uint8_t*>(addr)));
} else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_SHORT) {
value = DecodeAnimationChannelValue(*(reinterpret_cast<const int16_t*>(addr)));
} else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
value = DecodeAnimationChannelValue(*(reinterpret_cast<const uint16_t*>(addr)));
} else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT) {
value = *(reinterpret_cast<const float*>(addr));
} else {
std::cerr << "??? Unknown componentType : " << PrintComponentType(accessor.componentType) << std::endl;
return false;
}
(*scalar) = value;
return true;
}
static bool DecodeTranslationAnimationValue(const size_t i, const tinygltf::Accessor &accessor, const tinygltf::Model &model, float *xyz)
{
if (accessor.componentType != TINYGLTF_COMPONENT_TYPE_FLOAT) {
std::cerr << "`translation` must be float type." << std::endl;
return false;
}
const BufferView &bufferView = model.bufferViews[accessor.bufferView];
const Buffer &buffer = model.buffers[bufferView.buffer];
const uint8_t *addr = GetBufferAddress(i, accessor, bufferView, buffer);
if (addr == nullptr) {
std::cerr << "Invalid glTF data?" << std::endl;
return 0.0f;
}
const float *ptr = reinterpret_cast<const float*>(addr);
xyz[0] = *(ptr + 0);
xyz[1] = *(ptr + 1);
xyz[2] = *(ptr + 2);
return true;
}
static bool DecodeScaleAnimationValue(const size_t i, const tinygltf::Accessor &accessor, const tinygltf::Model &model, float *xyz)
{
if (accessor.componentType != TINYGLTF_COMPONENT_TYPE_FLOAT) {
std::cerr << "`scale` must be float type." << std::endl;
return false;
}
const BufferView &bufferView = model.bufferViews[accessor.bufferView];
const Buffer &buffer = model.buffers[bufferView.buffer];
const uint8_t *addr = GetBufferAddress(i, accessor, bufferView, buffer);
if (addr == nullptr) {
std::cerr << "Invalid glTF data?" << std::endl;
return 0.0f;
}
const float *ptr = reinterpret_cast<const float*>(addr);
xyz[0] = *(ptr + 0);
xyz[1] = *(ptr + 1);
xyz[2] = *(ptr + 2);
return true;
}
static bool DecodeRotationAnimationValue(const size_t i, const tinygltf::Accessor &accessor, const tinygltf::Model &model, float *xyzw)
{
const BufferView &bufferView = model.bufferViews[accessor.bufferView];
const Buffer &buffer = model.buffers[bufferView.buffer];
const uint8_t *addr = GetBufferAddress(i, accessor, bufferView, buffer);
if (addr == nullptr) {
std::cerr << "Invalid glTF data?" << std::endl;
return false;
}
float value = 0.0f;
if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_BYTE) {
xyzw[0] = DecodeAnimationChannelValue(*(reinterpret_cast<const int8_t*>(addr) + 0));
xyzw[1] = DecodeAnimationChannelValue(*(reinterpret_cast<const int8_t*>(addr) + 1));
xyzw[2] = DecodeAnimationChannelValue(*(reinterpret_cast<const int8_t*>(addr) + 2));
xyzw[3] = DecodeAnimationChannelValue(*(reinterpret_cast<const int8_t*>(addr) + 3));
} else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
xyzw[0] = DecodeAnimationChannelValue(*(reinterpret_cast<const uint8_t*>(addr) + 0));
xyzw[1] = DecodeAnimationChannelValue(*(reinterpret_cast<const uint8_t*>(addr) + 1));
xyzw[2] = DecodeAnimationChannelValue(*(reinterpret_cast<const uint8_t*>(addr) + 2));
xyzw[3] = DecodeAnimationChannelValue(*(reinterpret_cast<const uint8_t*>(addr) + 3));
} else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_SHORT) {
xyzw[0] = DecodeAnimationChannelValue(*(reinterpret_cast<const int16_t*>(addr) + 0));
xyzw[1] = DecodeAnimationChannelValue(*(reinterpret_cast<const int16_t*>(addr) + 1));
xyzw[2] = DecodeAnimationChannelValue(*(reinterpret_cast<const int16_t*>(addr) + 2));
xyzw[3] = DecodeAnimationChannelValue(*(reinterpret_cast<const int16_t*>(addr) + 3));
} else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
xyzw[0] = DecodeAnimationChannelValue(*(reinterpret_cast<const uint16_t*>(addr) + 0));
xyzw[1] = DecodeAnimationChannelValue(*(reinterpret_cast<const uint16_t*>(addr) + 1));
xyzw[2] = DecodeAnimationChannelValue(*(reinterpret_cast<const uint16_t*>(addr) + 2));
xyzw[3] = DecodeAnimationChannelValue(*(reinterpret_cast<const uint16_t*>(addr) + 3));
} else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT) {
xyzw[0] = *(reinterpret_cast<const float*>(addr) + 0);
xyzw[1] = *(reinterpret_cast<const float*>(addr) + 1);
xyzw[2] = *(reinterpret_cast<const float*>(addr) + 2);
xyzw[3] = *(reinterpret_cast<const float*>(addr) + 3);
} else {
std::cerr << "??? Unknown componentType : " << PrintComponentType(accessor.componentType) << std::endl;
return false;
}
return true;
}
} // namespace util
} // namespace tinygltf