mirror of
https://git.mirrors.martin98.com/https://github.com/syoyo/tinygltf.git
synced 2025-08-14 04:15:54 +08:00
Initial support of loading binary glTF(.glb).
This commit is contained in:
parent
ec39a523c2
commit
beded611b7
@ -42,5 +42,5 @@ script:
|
|||||||
- export CC="${CC}-${COMPILER_VERSION}"
|
- export CC="${CC}-${COMPILER_VERSION}"
|
||||||
- export CXX="${CXX}-${COMPILER_VERSION}"
|
- export CXX="${CXX}-${COMPILER_VERSION}"
|
||||||
- ${CC} -v
|
- ${CC} -v
|
||||||
- ${CXX} ${EXTRA_CXXFLAGS} -Wall -Werror -g -o loader_test test.cc
|
- ${CXX} ${EXTRA_CXXFLAGS} -Wall -Werror -g -o loader_example loader_example.cc
|
||||||
- ./loader_test box.gltf
|
- ./loader_example box.gltf
|
||||||
|
2
Makefile
2
Makefile
@ -1,5 +1,5 @@
|
|||||||
all:
|
all:
|
||||||
clang++ -fsanitize=address -Wall -Werror -Weverything -Wno-c++11-long-long -g -O0 -o example example.cc
|
clang++ -fsanitize=address -Wall -Werror -Weverything -Wno-c++11-long-long -g -O0 -o loader_example loader_example.cc
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
./cpplint.py tiny_gltf_loader.h
|
./cpplint.py tiny_gltf_loader.h
|
||||||
|
10
README.md
10
README.md
@ -10,9 +10,11 @@
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* Portable C++. C++-98 with STL dependency only.
|
* Portable C++. C++-03 with STL dependency only.
|
||||||
* Moderate parsing time and memory consumption.
|
* Moderate parsing time and memory consumption.
|
||||||
* glTF specification v1.0.0
|
* glTF specification v1.0.0
|
||||||
|
* [x] ASCII glTF
|
||||||
|
* [x] Binary glTF(https://github.com/KhronosGroup/glTF/tree/master/extensions/Khronos/KHR_binary_glTF)
|
||||||
* Buffers
|
* Buffers
|
||||||
* [x] Parse BASE64 encoded embedded buffer fata(DataURI).
|
* [x] Parse BASE64 encoded embedded buffer fata(DataURI).
|
||||||
* [x] Load `.bin` file.
|
* [x] Load `.bin` file.
|
||||||
@ -34,8 +36,7 @@
|
|||||||
* [ ] Parse `animation`, `program`, `sampler`, `shader`, `technique`
|
* [ ] Parse `animation`, `program`, `sampler`, `shader`, `technique`
|
||||||
* [ ] Compression/decompression(Open3DGC, etc)
|
* [ ] Compression/decompression(Open3DGC, etc)
|
||||||
* [ ] Support `extensions` and `extras` property
|
* [ ] Support `extensions` and `extras` property
|
||||||
* [ ] HDR image
|
* [ ] HDR image?
|
||||||
* [ ] Binary glTF.
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
@ -64,7 +65,8 @@ Scene scene;
|
|||||||
TinyGLTFLoader loader;
|
TinyGLTFLoader loader;
|
||||||
std::string err;
|
std::string err;
|
||||||
|
|
||||||
bool ret = loader.LoadFromFile(scene, err, argv[1]);
|
bool ret = loader.LoadASCIIFromFile(scene, err, argv[1]);
|
||||||
|
//bool ret = loader.LoadBinaryFromFile(scene, err, argv[1]); // for binary glTF(.glb)
|
||||||
if (!err.empty()) {
|
if (!err.empty()) {
|
||||||
printf("Err: %s\n", err.c_str());
|
printf("Err: %s\n", err.c_str());
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,12 @@ void CheckErrors(std::string desc) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 "";
|
||||||
|
}
|
||||||
|
|
||||||
bool LoadShader(GLenum shaderType, // GL_VERTEX_SHADER or GL_FRAGMENT_SHADER(or
|
bool LoadShader(GLenum shaderType, // GL_VERTEX_SHADER or GL_FRAGMENT_SHADER(or
|
||||||
// maybe GL_COMPUTE_SHADER)
|
// maybe GL_COMPUTE_SHADER)
|
||||||
GLuint &shader, const char *shaderSourceFilename) {
|
GLuint &shader, const char *shaderSourceFilename) {
|
||||||
@ -264,7 +270,7 @@ static void SetupGLState(tinygltf::Scene &scene, GLuint progId) {
|
|||||||
tinygltf::Material &mat = scene.materials[primitive.material];
|
tinygltf::Material &mat = scene.materials[primitive.material];
|
||||||
printf("material.name = %s\n", mat.name.c_str());
|
printf("material.name = %s\n", mat.name.c_str());
|
||||||
if (mat.values.find("diffuse") != mat.values.end()) {
|
if (mat.values.find("diffuse") != mat.values.end()) {
|
||||||
std::string diffuseTexName = mat.values["diffuse"].stringValue;
|
std::string diffuseTexName = mat.values["diffuse"].string_value;
|
||||||
if (scene.textures.find(diffuseTexName) != scene.textures.end()) {
|
if (scene.textures.find(diffuseTexName) != scene.textures.end()) {
|
||||||
tinygltf::Texture &tex = scene.textures[diffuseTexName];
|
tinygltf::Texture &tex = scene.textures[diffuseTexName];
|
||||||
if (scene.images.find(tex.source) != scene.images.end()) {
|
if (scene.images.find(tex.source) != scene.images.end()) {
|
||||||
@ -435,8 +441,18 @@ int main(int argc, char **argv) {
|
|||||||
tinygltf::Scene scene;
|
tinygltf::Scene scene;
|
||||||
tinygltf::TinyGLTFLoader loader;
|
tinygltf::TinyGLTFLoader loader;
|
||||||
std::string err;
|
std::string err;
|
||||||
|
std::string input_filename(argv[1]);
|
||||||
|
std::string ext = GetFilePathExtension(input_filename);
|
||||||
|
|
||||||
|
bool ret = false;
|
||||||
|
if (ext.compare("glb") == 0) {
|
||||||
|
// assume binary glTF.
|
||||||
|
ret = loader.LoadBinaryFromFile(&scene, &err, input_filename.c_str());
|
||||||
|
} else {
|
||||||
|
// assume ascii glTF.
|
||||||
|
ret = loader.LoadASCIIFromFile(&scene, &err, input_filename.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
bool ret = loader.LoadFromFile(&scene, &err, argv[1]);
|
|
||||||
if (!err.empty()) {
|
if (!err.empty()) {
|
||||||
printf("ERR: %s\n", err.c_str());
|
printf("ERR: %s\n", err.c_str());
|
||||||
}
|
}
|
||||||
@ -452,7 +468,10 @@ int main(int argc, char **argv) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
window = glfwCreateWindow(width, height, "Simple glTF geometry viewer", NULL,
|
char title[1024];
|
||||||
|
sprintf(title, "Simple glTF viewer: %s", input_filename.c_str());
|
||||||
|
|
||||||
|
window = glfwCreateWindow(width, height, title, NULL,
|
||||||
NULL);
|
NULL);
|
||||||
if (window == NULL) {
|
if (window == NULL) {
|
||||||
std::cerr << "Failed to open GLFW window. " << std::endl;
|
std::cerr << "Failed to open GLFW window. " << std::endl;
|
||||||
|
@ -6,7 +6,13 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
std::string PrintMode(int mode) {
|
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 PrintMode(int mode) {
|
||||||
if (mode == TINYGLTF_MODE_POINTS) {
|
if (mode == TINYGLTF_MODE_POINTS) {
|
||||||
return "POINTS";
|
return "POINTS";
|
||||||
} else if (mode == TINYGLTF_MODE_LINE) {
|
} else if (mode == TINYGLTF_MODE_LINE) {
|
||||||
@ -23,7 +29,7 @@ std::string PrintMode(int mode) {
|
|||||||
return "**UNKNOWN**";
|
return "**UNKNOWN**";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string PrintType(int ty) {
|
static std::string PrintType(int ty) {
|
||||||
if (ty == TINYGLTF_TYPE_SCALAR) {
|
if (ty == TINYGLTF_TYPE_SCALAR) {
|
||||||
return "SCALAR";
|
return "SCALAR";
|
||||||
} else if (ty == TINYGLTF_TYPE_VECTOR) {
|
} else if (ty == TINYGLTF_TYPE_VECTOR) {
|
||||||
@ -46,7 +52,7 @@ std::string PrintType(int ty) {
|
|||||||
return "**UNKNOWN**";
|
return "**UNKNOWN**";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string PrintComponentType(int ty) {
|
static std::string PrintComponentType(int ty) {
|
||||||
if (ty == TINYGLTF_COMPONENT_TYPE_BYTE) {
|
if (ty == TINYGLTF_COMPONENT_TYPE_BYTE) {
|
||||||
return "BYTE";
|
return "BYTE";
|
||||||
} else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
|
} else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
|
||||||
@ -68,7 +74,7 @@ std::string PrintComponentType(int ty) {
|
|||||||
return "**UNKNOWN**";
|
return "**UNKNOWN**";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string PrintFloatArray(const std::vector<double> &arr) {
|
static std::string PrintFloatArray(const std::vector<double> &arr) {
|
||||||
if (arr.size() == 0) {
|
if (arr.size() == 0) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@ -83,7 +89,7 @@ std::string PrintFloatArray(const std::vector<double> &arr) {
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string PrintStringArray(const std::vector<std::string> &arr) {
|
static std::string PrintStringArray(const std::vector<std::string> &arr) {
|
||||||
if (arr.size() == 0) {
|
if (arr.size() == 0) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@ -98,7 +104,7 @@ std::string PrintStringArray(const std::vector<std::string> &arr) {
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Indent(int indent) {
|
static std::string Indent(int indent) {
|
||||||
std::string s;
|
std::string s;
|
||||||
for (int i = 0; i < indent; i++) {
|
for (int i = 0; i < indent; i++) {
|
||||||
s += " ";
|
s += " ";
|
||||||
@ -107,7 +113,7 @@ std::string Indent(int indent) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DumpNode(const tinygltf::Node &node, int indent) {
|
static void DumpNode(const tinygltf::Node &node, int indent) {
|
||||||
std::cout << Indent(indent) << "name : " << node.name << std::endl;
|
std::cout << Indent(indent) << "name : " << node.name << std::endl;
|
||||||
std::cout << Indent(indent) << "camera : " << node.camera << std::endl;
|
std::cout << Indent(indent) << "camera : " << node.camera << std::endl;
|
||||||
if (!node.rotation.empty()) {
|
if (!node.rotation.empty()) {
|
||||||
@ -137,7 +143,7 @@ void DumpNode(const tinygltf::Node &node, int indent) {
|
|||||||
<< "children : " << PrintStringArray(node.children) << std::endl;
|
<< "children : " << PrintStringArray(node.children) << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DumpPrimitive(const tinygltf::Primitive &primitive, int indent) {
|
static void DumpPrimitive(const tinygltf::Primitive &primitive, int indent) {
|
||||||
std::cout << Indent(indent) << "material : " << primitive.material
|
std::cout << Indent(indent) << "material : " << primitive.material
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
std::cout << Indent(indent) << "mode : " << PrintMode(primitive.mode)
|
std::cout << Indent(indent) << "mode : " << PrintMode(primitive.mode)
|
||||||
@ -155,7 +161,7 @@ void DumpPrimitive(const tinygltf::Primitive &primitive, int indent) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dump(const tinygltf::Scene &scene) {
|
static void Dump(const tinygltf::Scene &scene) {
|
||||||
std::cout << "=== Dump glTF ===" << std::endl;
|
std::cout << "=== Dump glTF ===" << std::endl;
|
||||||
std::cout << "asset.generator : " << scene.asset.generator
|
std::cout << "asset.generator : " << scene.asset.generator
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
@ -289,12 +295,12 @@ void Dump(const tinygltf::Scene &scene) {
|
|||||||
tinygltf::ParameterMap::const_iterator p(it->second.values.begin());
|
tinygltf::ParameterMap::const_iterator p(it->second.values.begin());
|
||||||
tinygltf::ParameterMap::const_iterator pEnd(it->second.values.end());
|
tinygltf::ParameterMap::const_iterator pEnd(it->second.values.end());
|
||||||
for (; p != pEnd; p++) {
|
for (; p != pEnd; p++) {
|
||||||
if (!p->second.numberArray.empty()) {
|
if (!p->second.number_array.empty()) {
|
||||||
std::cout << Indent(3) << p->first
|
std::cout << Indent(3) << p->first
|
||||||
<< PrintFloatArray(p->second.numberArray) << std::endl;
|
<< PrintFloatArray(p->second.number_array) << std::endl;
|
||||||
}
|
}
|
||||||
if (!p->second.stringValue.empty()) {
|
if (!p->second.string_value.empty()) {
|
||||||
std::cout << Indent(3) << p->first << " : " << p->second.stringValue
|
std::cout << Indent(3) << p->first << " : " << p->second.string_value
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -359,8 +365,17 @@ int main(int argc, char **argv) {
|
|||||||
tinygltf::Scene scene;
|
tinygltf::Scene scene;
|
||||||
tinygltf::TinyGLTFLoader loader;
|
tinygltf::TinyGLTFLoader loader;
|
||||||
std::string err;
|
std::string err;
|
||||||
|
std::string input_filename(argv[1]);
|
||||||
|
std::string ext = GetFilePathExtension(input_filename);
|
||||||
|
|
||||||
bool ret = loader.LoadFromFile(&scene, &err, argv[1]);
|
bool ret = false;
|
||||||
|
if (ext.compare("glb") == 0) {
|
||||||
|
// assume binary glTF.
|
||||||
|
ret = loader.LoadBinaryFromFile(&scene, &err, input_filename.c_str());
|
||||||
|
} else {
|
||||||
|
// assume ascii glTF.
|
||||||
|
ret = loader.LoadASCIIFromFile(&scene, &err, input_filename.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
if (!err.empty()) {
|
if (!err.empty()) {
|
||||||
printf("Err: %s\n", err.c_str());
|
printf("Err: %s\n", err.c_str());
|
@ -1,5 +1,5 @@
|
|||||||
sources = {
|
sources = {
|
||||||
"test.cc",
|
"loader_example.cc",
|
||||||
}
|
}
|
||||||
|
|
||||||
-- premake4.lua
|
-- premake4.lua
|
||||||
@ -21,9 +21,9 @@ solution "TinyGLTFLoaderSolution"
|
|||||||
configuration "Debug"
|
configuration "Debug"
|
||||||
defines { "DEBUG" } -- -DDEBUG
|
defines { "DEBUG" } -- -DDEBUG
|
||||||
flags { "Symbols" }
|
flags { "Symbols" }
|
||||||
targetname "test_tinygltfloader_debug"
|
targetname "loader_example_tinygltfloader_debug"
|
||||||
|
|
||||||
configuration "Release"
|
configuration "Release"
|
||||||
-- defines { "NDEBUG" } -- -NDEBUG
|
-- defines { "NDEBUG" } -- -NDEBUG
|
||||||
flags { "Symbols", "Optimize" }
|
flags { "Symbols", "Optimize" }
|
||||||
targetname "test_tinygltfloader"
|
targetname "loader_example_tinygltfloader"
|
||||||
|
@ -22,7 +22,7 @@ success = []
|
|||||||
def run(filename):
|
def run(filename):
|
||||||
|
|
||||||
print("Testing: " + filename)
|
print("Testing: " + filename)
|
||||||
cmd = ["./loader_test", filename]
|
cmd = ["./example", filename]
|
||||||
try:
|
try:
|
||||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
(stdout, stderr) = p.communicate()
|
(stdout, stderr) = p.communicate()
|
||||||
@ -45,7 +45,7 @@ def test():
|
|||||||
if os.path.isdir(p):
|
if os.path.isdir(p):
|
||||||
for k in kinds:
|
for k in kinds:
|
||||||
targetDir = os.path.join(p, k)
|
targetDir = os.path.join(p, k)
|
||||||
g = glob.glob(targetDir + "/*.gltf")
|
g = glob.glob(targetDir + "/*.gltf") + glob.glob(targetDir + "/*.glb")
|
||||||
for gltf in g:
|
for gltf in g:
|
||||||
run(gltf)
|
run(gltf)
|
||||||
|
|
||||||
|
@ -102,6 +102,9 @@ typedef struct {
|
|||||||
int component;
|
int component;
|
||||||
int pad0;
|
int pad0;
|
||||||
std::vector<unsigned char> image;
|
std::vector<unsigned char> image;
|
||||||
|
|
||||||
|
std::string bufferView; // KHR_binary_glTF extenstion.
|
||||||
|
std::string mimeType; // KHR_binary_glTF extenstion.
|
||||||
} Image;
|
} Image;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -241,7 +244,8 @@ class TinyGLTFLoader {
|
|||||||
/// `length` = strlen(str);
|
/// `length` = strlen(str);
|
||||||
/// Returns false and set error string to `err` if there's an error.
|
/// Returns false and set error string to `err` if there's an error.
|
||||||
bool LoadASCIIFromString(Scene *scene, std::string *err, const char *str,
|
bool LoadASCIIFromString(Scene *scene, std::string *err, const char *str,
|
||||||
const unsigned int length, const std::string &baseDir);
|
const unsigned int length,
|
||||||
|
const std::string &base_dir);
|
||||||
|
|
||||||
/// Loads glTF binary asset from a file.
|
/// Loads glTF binary asset from a file.
|
||||||
/// Returns false and set error string to `err` if there's an error.
|
/// Returns false and set error string to `err` if there's an error.
|
||||||
@ -251,18 +255,19 @@ class TinyGLTFLoader {
|
|||||||
/// Loads glTF binary asset from memory.
|
/// Loads glTF binary asset from memory.
|
||||||
/// `length` = strlen(str);
|
/// `length` = strlen(str);
|
||||||
/// Returns false and set error string to `err` if there's an error.
|
/// Returns false and set error string to `err` if there's an error.
|
||||||
bool LoadBinaryFromMemory(Scene *scene, std::string *err, const unsigned char *bytes,
|
bool LoadBinaryFromMemory(Scene *scene, std::string *err,
|
||||||
const unsigned int length);
|
const unsigned char *bytes,
|
||||||
|
const unsigned int length,
|
||||||
private:
|
const std::string &base_dir = "");
|
||||||
|
|
||||||
|
private:
|
||||||
/// Loads glTF asset from string(memory).
|
/// Loads glTF asset from string(memory).
|
||||||
/// `length` = strlen(str);
|
/// `length` = strlen(str);
|
||||||
/// Returns false and set error string to `err` if there's an error.
|
/// Returns false and set error string to `err` if there's an error.
|
||||||
bool LoadFromString(Scene *scene, std::string *err, const char *str,
|
bool LoadFromString(Scene *scene, std::string *err, const char *str,
|
||||||
const unsigned int length, const std::string &baseDir);
|
const unsigned int length, const std::string &base_dir);
|
||||||
|
|
||||||
const unsigned char* bin_data_;
|
const unsigned char *bin_data_;
|
||||||
size_t bin_size_;
|
size_t bin_size_;
|
||||||
bool is_binary_;
|
bool is_binary_;
|
||||||
char pad[7];
|
char pad[7];
|
||||||
@ -308,21 +313,6 @@ private:
|
|||||||
|
|
||||||
namespace tinygltf {
|
namespace tinygltf {
|
||||||
|
|
||||||
#if 0
|
|
||||||
static void swap2(unsigned short *val) {
|
|
||||||
#ifdef TINYGLTF_LITTLE_ENDIAN
|
|
||||||
(void)val;
|
|
||||||
#else
|
|
||||||
unsigned short tmp = *val;
|
|
||||||
unsigned char *dst = reinterpret_cast<unsigned char *>(val);
|
|
||||||
unsigned char *src = reinterpret_cast<unsigned char *>(&tmp);
|
|
||||||
|
|
||||||
dst[0] = src[1];
|
|
||||||
dst[1] = src[0];
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void swap4(unsigned int *val) {
|
static void swap4(unsigned int *val) {
|
||||||
#ifdef TINYGLTF_LITTLE_ENDIAN
|
#ifdef TINYGLTF_LITTLE_ENDIAN
|
||||||
(void)val;
|
(void)val;
|
||||||
@ -338,27 +328,6 @@ static void swap4(unsigned int *val) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
static void swap8(unsigned long long *val) {
|
|
||||||
#ifdef TINYGLTF_LITTLE_ENDIAN
|
|
||||||
(void)val;
|
|
||||||
#else
|
|
||||||
unsigned long long tmp = (*val);
|
|
||||||
unsigned char *dst = reinterpret_cast<unsigned char *>(val);
|
|
||||||
unsigned char *src = reinterpret_cast<unsigned char *>(&tmp);
|
|
||||||
|
|
||||||
dst[0] = src[7];
|
|
||||||
dst[1] = src[6];
|
|
||||||
dst[2] = src[5];
|
|
||||||
dst[3] = src[4];
|
|
||||||
dst[4] = src[3];
|
|
||||||
dst[5] = src[2];
|
|
||||||
dst[6] = src[1];
|
|
||||||
dst[7] = src[0];
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static bool FileExists(const std::string &abs_filename) {
|
static bool FileExists(const std::string &abs_filename) {
|
||||||
bool ret;
|
bool ret;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -426,7 +395,8 @@ static std::string ExpandFilePath(const std::string &filepath) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string JoinPath(const std::string &path0, const std::string &path1) {
|
static std::string JoinPath(const std::string &path0,
|
||||||
|
const std::string &path1) {
|
||||||
if (path0.empty()) {
|
if (path0.empty()) {
|
||||||
return path1;
|
return path1;
|
||||||
} else {
|
} else {
|
||||||
@ -523,7 +493,8 @@ std::string base64_decode(std::string const &encoded_string) {
|
|||||||
in_++;
|
in_++;
|
||||||
if (i == 4) {
|
if (i == 4) {
|
||||||
for (i = 0; i < 4; i++)
|
for (i = 0; i < 4; i++)
|
||||||
char_array_4[i] = static_cast<unsigned char>(base64_chars.find(char_array_4[i]));
|
char_array_4[i] =
|
||||||
|
static_cast<unsigned char>(base64_chars.find(char_array_4[i]));
|
||||||
|
|
||||||
char_array_3[0] =
|
char_array_3[0] =
|
||||||
(char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
(char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||||
@ -540,7 +511,8 @@ std::string base64_decode(std::string const &encoded_string) {
|
|||||||
for (j = i; j < 4; j++) char_array_4[j] = 0;
|
for (j = i; j < 4; j++) char_array_4[j] = 0;
|
||||||
|
|
||||||
for (j = 0; j < 4; j++)
|
for (j = 0; j < 4; j++)
|
||||||
char_array_4[j] = static_cast<unsigned char>(base64_chars.find(char_array_4[j]));
|
char_array_4[j] =
|
||||||
|
static_cast<unsigned char>(base64_chars.find(char_array_4[j]));
|
||||||
|
|
||||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||||
char_array_3[1] =
|
char_array_3[1] =
|
||||||
@ -555,8 +527,9 @@ std::string base64_decode(std::string const &encoded_string) {
|
|||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
|
|
||||||
static bool LoadExternalFile(std::vector<unsigned char> *out, std::string *err,
|
static bool LoadExternalFile(std::vector<unsigned char> *out, std::string *err,
|
||||||
const std::string &filename, const std::string &basedir,
|
const std::string &filename,
|
||||||
size_t reqBytes, bool checkSize) {
|
const std::string &basedir, size_t reqBytes,
|
||||||
|
bool checkSize) {
|
||||||
out->clear();
|
out->clear();
|
||||||
|
|
||||||
std::vector<std::string> paths;
|
std::vector<std::string> paths;
|
||||||
@ -584,7 +557,8 @@ static bool LoadExternalFile(std::vector<unsigned char> *out, std::string *err,
|
|||||||
std::vector<unsigned char> buf(sz);
|
std::vector<unsigned char> buf(sz);
|
||||||
|
|
||||||
f.seekg(0, f.beg);
|
f.seekg(0, f.beg);
|
||||||
f.read(reinterpret_cast<char *>(&buf.at(0)), static_cast<std::streamsize>(sz));
|
f.read(reinterpret_cast<char *>(&buf.at(0)),
|
||||||
|
static_cast<std::streamsize>(sz));
|
||||||
f.close();
|
f.close();
|
||||||
|
|
||||||
if (checkSize) {
|
if (checkSize) {
|
||||||
@ -606,6 +580,52 @@ static bool LoadExternalFile(std::vector<unsigned char> *out, std::string *err,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool LoadImageData(Image *image, std::string *err, int req_width,
|
||||||
|
int req_height, const unsigned char *bytes,
|
||||||
|
int size) {
|
||||||
|
int w, h, comp;
|
||||||
|
unsigned char *data = stbi_load_from_memory(bytes, size, &w, &h, &comp, 0);
|
||||||
|
if (!data) {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "Unknown image format.\n";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (w < 1 || h < 1) {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "Unknown image format.\n";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req_width > 0) {
|
||||||
|
if (req_width != w) {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "Image width mismatch.\n";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req_height > 0) {
|
||||||
|
if (req_height != h) {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "Image height mismatch.\n";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
image->width = w;
|
||||||
|
image->height = h;
|
||||||
|
image->component = comp;
|
||||||
|
image->image.resize(static_cast<size_t>(w * h * comp));
|
||||||
|
std::copy(data, data + w * h * comp, image->image.begin());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool IsDataURI(const std::string &in) {
|
static bool IsDataURI(const std::string &in) {
|
||||||
std::string header = "data:application/octet-stream;base64,";
|
std::string header = "data:application/octet-stream;base64,";
|
||||||
if (in.find(header) == 0) {
|
if (in.find(header) == 0) {
|
||||||
@ -625,8 +645,9 @@ static bool IsDataURI(const std::string &in) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool DecodeDataURI(std::vector<unsigned char> *out, const std::string &in,
|
static bool DecodeDataURI(std::vector<unsigned char> *out,
|
||||||
size_t reqBytes, bool checkSize) {
|
const std::string &in, size_t reqBytes,
|
||||||
|
bool checkSize) {
|
||||||
std::string header = "data:application/octet-stream;base64,";
|
std::string header = "data:application/octet-stream;base64,";
|
||||||
std::string data;
|
std::string data;
|
||||||
if (in.find(header) == 0) {
|
if (in.find(header) == 0) {
|
||||||
@ -693,8 +714,8 @@ static bool ParseBooleanProperty(bool *ret, std::string *err,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool ParseNumberProperty(double *ret, std::string *err,
|
static bool ParseNumberProperty(double *ret, std::string *err,
|
||||||
const picojson::object &o, const std::string &property,
|
const picojson::object &o,
|
||||||
bool required) {
|
const std::string &property, bool required) {
|
||||||
picojson::object::const_iterator it = o.find(property);
|
picojson::object::const_iterator it = o.find(property);
|
||||||
if (it == o.end()) {
|
if (it == o.end()) {
|
||||||
if (required) {
|
if (required) {
|
||||||
@ -723,7 +744,8 @@ static bool ParseNumberProperty(double *ret, std::string *err,
|
|||||||
|
|
||||||
static bool ParseNumberArrayProperty(std::vector<double> *ret, std::string *err,
|
static bool ParseNumberArrayProperty(std::vector<double> *ret, std::string *err,
|
||||||
const picojson::object &o,
|
const picojson::object &o,
|
||||||
const std::string &property, bool required) {
|
const std::string &property,
|
||||||
|
bool required) {
|
||||||
picojson::object::const_iterator it = o.find(property);
|
picojson::object::const_iterator it = o.find(property);
|
||||||
if (it == o.end()) {
|
if (it == o.end()) {
|
||||||
if (required) {
|
if (required) {
|
||||||
@ -761,8 +783,8 @@ static bool ParseNumberArrayProperty(std::vector<double> *ret, std::string *err,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool ParseStringProperty(std::string *ret, std::string *err,
|
static bool ParseStringProperty(std::string *ret, std::string *err,
|
||||||
const picojson::object &o, const std::string &property,
|
const picojson::object &o,
|
||||||
bool required) {
|
const std::string &property, bool required) {
|
||||||
picojson::object::const_iterator it = o.find(property);
|
picojson::object::const_iterator it = o.find(property);
|
||||||
if (it == o.end()) {
|
if (it == o.end()) {
|
||||||
if (required) {
|
if (required) {
|
||||||
@ -789,9 +811,11 @@ static bool ParseStringProperty(std::string *ret, std::string *err,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ParseStringArrayProperty(std::vector<std::string> *ret, std::string *err,
|
static bool ParseStringArrayProperty(std::vector<std::string> *ret,
|
||||||
|
std::string *err,
|
||||||
const picojson::object &o,
|
const picojson::object &o,
|
||||||
const std::string &property, bool required) {
|
const std::string &property,
|
||||||
|
bool required) {
|
||||||
picojson::object::const_iterator it = o.find(property);
|
picojson::object::const_iterator it = o.find(property);
|
||||||
if (it == o.end()) {
|
if (it == o.end()) {
|
||||||
if (required) {
|
if (required) {
|
||||||
@ -828,7 +852,72 @@ static bool ParseStringArrayProperty(std::vector<std::string> *ret, std::string
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ParseAsset(Asset *asset, std::string *err, const picojson::object &o) {
|
static bool ParseKHRBinaryExtension(const picojson::object &o, std::string *err,
|
||||||
|
std::string *buffer_view,
|
||||||
|
std::string *mime_type, int *image_width,
|
||||||
|
int *image_height) {
|
||||||
|
picojson::object j = o;
|
||||||
|
|
||||||
|
if (j.find("extensions") == j.end()) {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "`extensions' property is missing.\n";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(j["extensions"].is<picojson::object>())) {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "Invalid `extensions' property.\n";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
picojson::object ext = j["extensions"].get<picojson::object>();
|
||||||
|
|
||||||
|
if (ext.find("KHR_binary_glTF") == ext.end()) {
|
||||||
|
if (err) {
|
||||||
|
(*err) +=
|
||||||
|
"`KHR_binary_glTF' property is missing in extension property.\n";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(ext["KHR_binary_glTF"].is<picojson::object>())) {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "Invalid `KHR_binary_glTF' property.\n";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
picojson::object k = ext["KHR_binary_glTF"].get<picojson::object>();
|
||||||
|
|
||||||
|
if (!ParseStringProperty(buffer_view, err, k, "bufferView", true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mime_type) {
|
||||||
|
ParseStringProperty(mime_type, err, k, "mimeType", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image_width) {
|
||||||
|
double width = 0.0;
|
||||||
|
if (ParseNumberProperty(&width, err, k, "width", false)) {
|
||||||
|
(*image_width) = static_cast<int>(width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image_height) {
|
||||||
|
double height = 0.0;
|
||||||
|
if (ParseNumberProperty(&height, err, k, "height", false)) {
|
||||||
|
(*image_height) = static_cast<int>(height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ParseAsset(Asset *asset, std::string *err,
|
||||||
|
const picojson::object &o) {
|
||||||
ParseStringProperty(&asset->generator, err, o, "generator", false);
|
ParseStringProperty(&asset->generator, err, o, "generator", false);
|
||||||
ParseBooleanProperty(&asset->premultipliedAlpha, err, o, "premultipliedAlpha",
|
ParseBooleanProperty(&asset->premultipliedAlpha, err, o, "premultipliedAlpha",
|
||||||
false);
|
false);
|
||||||
@ -849,8 +938,10 @@ static bool ParseAsset(Asset *asset, std::string *err, const picojson::object &o
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ParseImage(Image *image, std::string *err, const picojson::object &o,
|
static bool ParseImage(Image *image, std::string *err,
|
||||||
const std::string &basedir) {
|
const picojson::object &o, const std::string &basedir,
|
||||||
|
bool is_binary, const unsigned char *bin_data,
|
||||||
|
size_t bin_size) {
|
||||||
std::string uri;
|
std::string uri;
|
||||||
if (!ParseStringProperty(&uri, err, o, "uri", true)) {
|
if (!ParseStringProperty(&uri, err, o, "uri", true)) {
|
||||||
return false;
|
return false;
|
||||||
@ -859,6 +950,59 @@ static bool ParseImage(Image *image, std::string *err, const picojson::object &o
|
|||||||
ParseStringProperty(&image->name, err, o, "name", false);
|
ParseStringProperty(&image->name, err, o, "name", false);
|
||||||
|
|
||||||
std::vector<unsigned char> img;
|
std::vector<unsigned char> img;
|
||||||
|
|
||||||
|
if (is_binary) {
|
||||||
|
// Still binary glTF accepts external dataURI. First try external resources.
|
||||||
|
bool loaded = false;
|
||||||
|
if (IsDataURI(uri)) {
|
||||||
|
loaded = DecodeDataURI(&img, uri, 0, false);
|
||||||
|
} else {
|
||||||
|
// Assume external .bin file.
|
||||||
|
loaded = LoadExternalFile(&img, err, uri, basedir, 0, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!loaded) {
|
||||||
|
// load data from (embedded) binary data
|
||||||
|
|
||||||
|
if ((bin_size == 0) || (bin_data == NULL)) {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "Invalid binary data.\n";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// There should be "extensions" property.
|
||||||
|
// "extensions":{"KHR_binary_glTF":{"bufferView": "id", ...
|
||||||
|
|
||||||
|
std::string buffer_view;
|
||||||
|
std::string mime_type;
|
||||||
|
int image_width;
|
||||||
|
int image_height;
|
||||||
|
bool ret = ParseKHRBinaryExtension(o, err, &buffer_view, &mime_type,
|
||||||
|
&image_width, &image_height);
|
||||||
|
if (!ret) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uri.compare("data:,") == 0) {
|
||||||
|
// ok
|
||||||
|
} else {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "Invalid URI for binary data.\n";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just only save some information here. Loading actual image data from
|
||||||
|
// bufferView is done in other place.
|
||||||
|
image->bufferView = buffer_view;
|
||||||
|
image->mimeType = mime_type;
|
||||||
|
image->width = image_width;
|
||||||
|
image->height = image_height;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (IsDataURI(uri)) {
|
if (IsDataURI(uri)) {
|
||||||
if (!DecodeDataURI(&img, uri, 0, false)) {
|
if (!DecodeDataURI(&img, uri, 0, false)) {
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -881,34 +1025,14 @@ static bool ParseImage(Image *image, std::string *err, const picojson::object &o
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int w, h, comp;
|
|
||||||
unsigned char *data =
|
|
||||||
stbi_load_from_memory(&img.at(0), static_cast<int>(img.size()), &w, &h, &comp, 0);
|
|
||||||
if (!data) {
|
|
||||||
if (err) {
|
|
||||||
(*err) += "Unknown image format.\n";
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (w < 1 || h < 1) {
|
return LoadImageData(image, err, 0, 0, &img.at(0),
|
||||||
if (err) {
|
static_cast<int>(img.size()));
|
||||||
(*err) += "Unknown image format.\n";
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
image->width = w;
|
|
||||||
image->height = h;
|
|
||||||
image->component = comp;
|
|
||||||
image->image.resize(static_cast<size_t>(w * h * comp));
|
|
||||||
std::copy(data, data + w * h * comp, image->image.begin());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ParseTexture(Texture *texture, std::string *err, const picojson::object &o,
|
static bool ParseTexture(Texture *texture, std::string *err,
|
||||||
|
const picojson::object &o,
|
||||||
const std::string &basedir) {
|
const std::string &basedir) {
|
||||||
(void)basedir;
|
(void)basedir;
|
||||||
|
|
||||||
@ -942,8 +1066,11 @@ static bool ParseTexture(Texture *texture, std::string *err, const picojson::obj
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ParseBuffer(Buffer *buffer, std::string *err, const picojson::object &o,
|
static bool ParseBuffer(Buffer *buffer, std::string *err,
|
||||||
const std::string &basedir, bool is_binary = false, const unsigned char* bin_data = NULL, size_t bin_size = 0) {
|
const picojson::object &o, const std::string &basedir,
|
||||||
|
bool is_binary = false,
|
||||||
|
const unsigned char *bin_data = NULL,
|
||||||
|
size_t bin_size = 0) {
|
||||||
double byteLength;
|
double byteLength;
|
||||||
if (!ParseNumberProperty(&byteLength, err, o, "byteLength", true)) {
|
if (!ParseNumberProperty(&byteLength, err, o, "byteLength", true)) {
|
||||||
return false;
|
return false;
|
||||||
@ -966,6 +1093,18 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const picojson::object
|
|||||||
|
|
||||||
size_t bytes = static_cast<size_t>(byteLength);
|
size_t bytes = static_cast<size_t>(byteLength);
|
||||||
if (is_binary) {
|
if (is_binary) {
|
||||||
|
// Still binary glTF accepts external dataURI. First try external resources.
|
||||||
|
bool loaded = false;
|
||||||
|
if (IsDataURI(uri)) {
|
||||||
|
loaded = DecodeDataURI(&buffer->data, uri, bytes, true);
|
||||||
|
} else {
|
||||||
|
// Assume external .bin file.
|
||||||
|
loaded = LoadExternalFile(&buffer->data, err, uri, basedir, bytes, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!loaded) {
|
||||||
|
// load data from (embedded) binary data
|
||||||
|
|
||||||
if ((bin_size == 0) || (bin_data == NULL)) {
|
if ((bin_size == 0) || (bin_data == NULL)) {
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) += "Invalid binary data.\n";
|
(*err) += "Invalid binary data.\n";
|
||||||
@ -976,17 +1115,19 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const picojson::object
|
|||||||
if (byteLength > bin_size) {
|
if (byteLength > bin_size) {
|
||||||
if (err) {
|
if (err) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Invalid `byteLength'. Must be equal or less than binary size: `byteLength' = " << byteLength << ", binary size = " << bin_size << std::endl;
|
ss << "Invalid `byteLength'. Must be equal or less than binary size: "
|
||||||
|
"`byteLength' = " << byteLength
|
||||||
|
<< ", binary size = " << bin_size << std::endl;
|
||||||
(*err) += ss.str();
|
(*err) += ss.str();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uri.compare("data:,") == 0) {
|
if (uri.compare("data:,") == 0) {
|
||||||
|
|
||||||
// @todo { check uri }
|
// @todo { check uri }
|
||||||
buffer->data.resize(static_cast<size_t>(byteLength));
|
buffer->data.resize(static_cast<size_t>(byteLength));
|
||||||
memcpy(&(buffer->data.at(0)), bin_data, static_cast<size_t>(byteLength));
|
memcpy(&(buffer->data.at(0)), bin_data,
|
||||||
|
static_cast<size_t>(byteLength));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -994,7 +1135,7 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const picojson::object
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (IsDataURI(uri)) {
|
if (IsDataURI(uri)) {
|
||||||
@ -1248,8 +1389,8 @@ static bool ParseMaterial(Material *material, std::string *err,
|
|||||||
for (; it != itEnd; it++) {
|
for (; it != itEnd; it++) {
|
||||||
// Assume number values.
|
// Assume number values.
|
||||||
Parameter param;
|
Parameter param;
|
||||||
if (ParseStringProperty(¶m.string_value, err, values_object, it->first,
|
if (ParseStringProperty(¶m.string_value, err, values_object,
|
||||||
false)) {
|
it->first, false)) {
|
||||||
// Found string property.
|
// Found string property.
|
||||||
} else if (!ParseNumberArrayProperty(¶m.number_array, err,
|
} else if (!ParseNumberArrayProperty(¶m.number_array, err,
|
||||||
values_object, it->first, false)) {
|
values_object, it->first, false)) {
|
||||||
@ -1269,7 +1410,7 @@ static bool ParseMaterial(Material *material, std::string *err,
|
|||||||
|
|
||||||
bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err,
|
bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err,
|
||||||
const char *str, unsigned int length,
|
const char *str, unsigned int length,
|
||||||
const std::string &baseDir) {
|
const std::string &base_dir) {
|
||||||
picojson::value v;
|
picojson::value v;
|
||||||
std::string perr = picojson::parse(v, str, str + length);
|
std::string perr = picojson::parse(v, str, str + length);
|
||||||
|
|
||||||
@ -1358,7 +1499,7 @@ bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err,
|
|||||||
for (; it != itEnd; it++) {
|
for (; it != itEnd; it++) {
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
if (!ParseBuffer(&buffer, err, (it->second).get<picojson::object>(),
|
if (!ParseBuffer(&buffer, err, (it->second).get<picojson::object>(),
|
||||||
baseDir, is_binary_, bin_data_, bin_size_)) {
|
base_dir, is_binary_, bin_data_, bin_size_)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1483,10 +1624,34 @@ bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err,
|
|||||||
for (; it != itEnd; it++) {
|
for (; it != itEnd; it++) {
|
||||||
Image image;
|
Image image;
|
||||||
if (!ParseImage(&image, err, (it->second).get<picojson::object>(),
|
if (!ParseImage(&image, err, (it->second).get<picojson::object>(),
|
||||||
baseDir)) {
|
base_dir, is_binary_, bin_data_, bin_size_)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!image.bufferView.empty()) {
|
||||||
|
// Load image from the buffer view.
|
||||||
|
if (scene->bufferViews.find(image.bufferView) ==
|
||||||
|
scene->bufferViews.end()) {
|
||||||
|
if (err) {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "bufferView \"" << image.bufferView
|
||||||
|
<< "\" not found in the scene." << std::endl;
|
||||||
|
(*err) += ss.str();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const BufferView &bufferView = scene->bufferViews[image.bufferView];
|
||||||
|
const Buffer &buffer = scene->buffers[bufferView.buffer];
|
||||||
|
|
||||||
|
bool ret = LoadImageData(&image, err, image.width, image.height,
|
||||||
|
&buffer.data[bufferView.byteOffset],
|
||||||
|
static_cast<int>(bufferView.byteLength));
|
||||||
|
if (!ret) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
scene->images[it->first] = image;
|
scene->images[it->first] = image;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1500,7 +1665,7 @@ bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err,
|
|||||||
for (; it != itEnd; it++) {
|
for (; it != itEnd; it++) {
|
||||||
Texture texture;
|
Texture texture;
|
||||||
if (!ParseTexture(&texture, err, (it->second).get<picojson::object>(),
|
if (!ParseTexture(&texture, err, (it->second).get<picojson::object>(),
|
||||||
baseDir)) {
|
base_dir)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1513,12 +1678,12 @@ bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err,
|
|||||||
|
|
||||||
bool TinyGLTFLoader::LoadASCIIFromString(Scene *scene, std::string *err,
|
bool TinyGLTFLoader::LoadASCIIFromString(Scene *scene, std::string *err,
|
||||||
const char *str, unsigned int length,
|
const char *str, unsigned int length,
|
||||||
const std::string &baseDir) {
|
const std::string &base_dir) {
|
||||||
is_binary_ = false;
|
is_binary_ = false;
|
||||||
bin_data_ = NULL;
|
bin_data_ = NULL;
|
||||||
bin_size_ = 0;
|
bin_size_ = 0;
|
||||||
|
|
||||||
return LoadFromString(scene, err, str, length, baseDir);
|
return LoadFromString(scene, err, str, length, base_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TinyGLTFLoader::LoadASCIIFromFile(Scene *scene, std::string *err,
|
bool TinyGLTFLoader::LoadASCIIFromFile(Scene *scene, std::string *err,
|
||||||
@ -1544,14 +1709,16 @@ bool TinyGLTFLoader::LoadASCIIFromFile(Scene *scene, std::string *err,
|
|||||||
|
|
||||||
std::string basedir = GetBaseDir(filename);
|
std::string basedir = GetBaseDir(filename);
|
||||||
|
|
||||||
bool ret = LoadASCIIFromString(scene, err, &buf.at(0), static_cast<unsigned int>(buf.size()), basedir);
|
bool ret = LoadASCIIFromString(
|
||||||
|
scene, err, &buf.at(0), static_cast<unsigned int>(buf.size()), basedir);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TinyGLTFLoader::LoadBinaryFromMemory(Scene *scene, std::string *err,
|
bool TinyGLTFLoader::LoadBinaryFromMemory(Scene *scene, std::string *err,
|
||||||
const unsigned char* bytes, unsigned int size) {
|
const unsigned char *bytes,
|
||||||
|
unsigned int size,
|
||||||
|
const std::string &base_dir) {
|
||||||
if (size < 20) {
|
if (size < 20) {
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) = "Too short data size for glTF Binary.";
|
(*err) = "Too short data size for glTF Binary.";
|
||||||
@ -1559,7 +1726,8 @@ bool TinyGLTFLoader::LoadBinaryFromMemory(Scene *scene, std::string *err,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytes[0] == 'g' && bytes[1] == 'l' && bytes[2] == 'T' && bytes[3] == 'F') {
|
if (bytes[0] == 'g' && bytes[1] == 'l' && bytes[2] == 'T' &&
|
||||||
|
bytes[3] == 'F') {
|
||||||
// ok
|
// ok
|
||||||
} else {
|
} else {
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -1574,13 +1742,16 @@ bool TinyGLTFLoader::LoadBinaryFromMemory(Scene *scene, std::string *err,
|
|||||||
unsigned int scene_format; // 4 bytes;
|
unsigned int scene_format; // 4 bytes;
|
||||||
|
|
||||||
// @todo { Endian swap for big endian machine. }
|
// @todo { Endian swap for big endian machine. }
|
||||||
memcpy(&version, bytes + 4, 4); swap4(&version);
|
memcpy(&version, bytes + 4, 4);
|
||||||
memcpy(&length, bytes + 8, 4); swap4(&length);
|
swap4(&version);
|
||||||
memcpy(&scene_length, bytes + 12, 4); swap4(&scene_length);
|
memcpy(&length, bytes + 8, 4);
|
||||||
memcpy(&scene_format, bytes + 16, 4); swap4(&scene_format);
|
swap4(&length);
|
||||||
|
memcpy(&scene_length, bytes + 12, 4);
|
||||||
|
swap4(&scene_length);
|
||||||
|
memcpy(&scene_format, bytes + 16, 4);
|
||||||
|
swap4(&scene_format);
|
||||||
|
|
||||||
if ((20 + scene_length >= size) ||
|
if ((20 + scene_length >= size) || (scene_length < 1) ||
|
||||||
(scene_length < 1) ||
|
|
||||||
(scene_format != 0)) { // 0 = JSON format.
|
(scene_format != 0)) { // 0 = JSON format.
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) = "Invalid glTF binary.";
|
(*err) = "Invalid glTF binary.";
|
||||||
@ -1589,13 +1760,17 @@ bool TinyGLTFLoader::LoadBinaryFromMemory(Scene *scene, std::string *err,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Extract JSON string.
|
// Extract JSON string.
|
||||||
std::string jsonString(reinterpret_cast<const char*>(&bytes[20]), scene_length);
|
std::string jsonString(reinterpret_cast<const char *>(&bytes[20]),
|
||||||
|
scene_length);
|
||||||
|
|
||||||
is_binary_ = true;
|
is_binary_ = true;
|
||||||
bin_data_ = bytes + 20 + scene_length;
|
bin_data_ = bytes + 20 + scene_length;
|
||||||
bin_size_ = length - (20 + scene_length); // extract header + JSON scene data.
|
bin_size_ =
|
||||||
|
length - (20 + scene_length); // extract header + JSON scene data.
|
||||||
|
|
||||||
bool ret = LoadFromString(scene, err, reinterpret_cast<const char*>(&bytes[20]), scene_length, "");
|
bool ret =
|
||||||
|
LoadFromString(scene, err, reinterpret_cast<const char *>(&bytes[20]),
|
||||||
|
scene_length, base_dir);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -1624,7 +1799,11 @@ bool TinyGLTFLoader::LoadBinaryFromFile(Scene *scene, std::string *err,
|
|||||||
f.read(&buf.at(0), static_cast<std::streamsize>(sz));
|
f.read(&buf.at(0), static_cast<std::streamsize>(sz));
|
||||||
f.close();
|
f.close();
|
||||||
|
|
||||||
bool ret = LoadBinaryFromMemory(scene, err, reinterpret_cast<unsigned char*>(&buf.at(0)), static_cast<unsigned int>(buf.size()));
|
std::string basedir = GetBaseDir(filename);
|
||||||
|
|
||||||
|
bool ret = LoadBinaryFromMemory(
|
||||||
|
scene, err, reinterpret_cast<unsigned char *>(&buf.at(0)),
|
||||||
|
static_cast<unsigned int>(buf.size()), basedir);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user