mirror of
https://git.mirrors.martin98.com/https://github.com/syoyo/tinygltf.git
synced 2025-08-11 01:19:01 +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 CXX="${CXX}-${COMPILER_VERSION}"
|
||||
- ${CC} -v
|
||||
- ${CXX} ${EXTRA_CXXFLAGS} -Wall -Werror -g -o loader_test test.cc
|
||||
- ./loader_test box.gltf
|
||||
- ${CXX} ${EXTRA_CXXFLAGS} -Wall -Werror -g -o loader_example loader_example.cc
|
||||
- ./loader_example box.gltf
|
||||
|
2
Makefile
2
Makefile
@ -1,5 +1,5 @@
|
||||
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:
|
||||
./cpplint.py tiny_gltf_loader.h
|
||||
|
10
README.md
10
README.md
@ -10,9 +10,11 @@
|
||||
|
||||
## Features
|
||||
|
||||
* Portable C++. C++-98 with STL dependency only.
|
||||
* Portable C++. C++-03 with STL dependency only.
|
||||
* Moderate parsing time and memory consumption.
|
||||
* glTF specification v1.0.0
|
||||
* [x] ASCII glTF
|
||||
* [x] Binary glTF(https://github.com/KhronosGroup/glTF/tree/master/extensions/Khronos/KHR_binary_glTF)
|
||||
* Buffers
|
||||
* [x] Parse BASE64 encoded embedded buffer fata(DataURI).
|
||||
* [x] Load `.bin` file.
|
||||
@ -34,8 +36,7 @@
|
||||
* [ ] Parse `animation`, `program`, `sampler`, `shader`, `technique`
|
||||
* [ ] Compression/decompression(Open3DGC, etc)
|
||||
* [ ] Support `extensions` and `extras` property
|
||||
* [ ] HDR image
|
||||
* [ ] Binary glTF.
|
||||
* [ ] HDR image?
|
||||
|
||||
## License
|
||||
|
||||
@ -64,7 +65,8 @@ Scene scene;
|
||||
TinyGLTFLoader loader;
|
||||
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()) {
|
||||
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
|
||||
// maybe GL_COMPUTE_SHADER)
|
||||
GLuint &shader, const char *shaderSourceFilename) {
|
||||
@ -264,7 +270,7 @@ static void SetupGLState(tinygltf::Scene &scene, GLuint progId) {
|
||||
tinygltf::Material &mat = scene.materials[primitive.material];
|
||||
printf("material.name = %s\n", mat.name.c_str());
|
||||
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()) {
|
||||
tinygltf::Texture &tex = scene.textures[diffuseTexName];
|
||||
if (scene.images.find(tex.source) != scene.images.end()) {
|
||||
@ -435,8 +441,18 @@ int main(int argc, char **argv) {
|
||||
tinygltf::Scene scene;
|
||||
tinygltf::TinyGLTFLoader loader;
|
||||
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()) {
|
||||
printf("ERR: %s\n", err.c_str());
|
||||
}
|
||||
@ -452,7 +468,10 @@ int main(int argc, char **argv) {
|
||||
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);
|
||||
if (window == NULL) {
|
||||
std::cerr << "Failed to open GLFW window. " << std::endl;
|
||||
|
@ -6,7 +6,13 @@
|
||||
#include <cstdio>
|
||||
#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) {
|
||||
return "POINTS";
|
||||
} else if (mode == TINYGLTF_MODE_LINE) {
|
||||
@ -23,7 +29,7 @@ std::string PrintMode(int mode) {
|
||||
return "**UNKNOWN**";
|
||||
}
|
||||
|
||||
std::string PrintType(int ty) {
|
||||
static std::string PrintType(int ty) {
|
||||
if (ty == TINYGLTF_TYPE_SCALAR) {
|
||||
return "SCALAR";
|
||||
} else if (ty == TINYGLTF_TYPE_VECTOR) {
|
||||
@ -46,7 +52,7 @@ std::string PrintType(int ty) {
|
||||
return "**UNKNOWN**";
|
||||
}
|
||||
|
||||
std::string PrintComponentType(int ty) {
|
||||
static std::string PrintComponentType(int ty) {
|
||||
if (ty == TINYGLTF_COMPONENT_TYPE_BYTE) {
|
||||
return "BYTE";
|
||||
} else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
|
||||
@ -68,7 +74,7 @@ std::string PrintComponentType(int ty) {
|
||||
return "**UNKNOWN**";
|
||||
}
|
||||
|
||||
std::string PrintFloatArray(const std::vector<double> &arr) {
|
||||
static std::string PrintFloatArray(const std::vector<double> &arr) {
|
||||
if (arr.size() == 0) {
|
||||
return "";
|
||||
}
|
||||
@ -83,7 +89,7 @@ std::string PrintFloatArray(const std::vector<double> &arr) {
|
||||
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) {
|
||||
return "";
|
||||
}
|
||||
@ -98,7 +104,7 @@ std::string PrintStringArray(const std::vector<std::string> &arr) {
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string Indent(int indent) {
|
||||
static std::string Indent(int indent) {
|
||||
std::string s;
|
||||
for (int i = 0; i < indent; i++) {
|
||||
s += " ";
|
||||
@ -107,7 +113,7 @@ std::string Indent(int indent) {
|
||||
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) << "camera : " << node.camera << std::endl;
|
||||
if (!node.rotation.empty()) {
|
||||
@ -137,7 +143,7 @@ void DumpNode(const tinygltf::Node &node, int indent) {
|
||||
<< "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::endl;
|
||||
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 << "asset.generator : " << scene.asset.generator
|
||||
<< 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 pEnd(it->second.values.end());
|
||||
for (; p != pEnd; p++) {
|
||||
if (!p->second.numberArray.empty()) {
|
||||
if (!p->second.number_array.empty()) {
|
||||
std::cout << Indent(3) << p->first
|
||||
<< PrintFloatArray(p->second.numberArray) << std::endl;
|
||||
<< PrintFloatArray(p->second.number_array) << std::endl;
|
||||
}
|
||||
if (!p->second.stringValue.empty()) {
|
||||
std::cout << Indent(3) << p->first << " : " << p->second.stringValue
|
||||
if (!p->second.string_value.empty()) {
|
||||
std::cout << Indent(3) << p->first << " : " << p->second.string_value
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
@ -359,8 +365,17 @@ int main(int argc, char **argv) {
|
||||
tinygltf::Scene scene;
|
||||
tinygltf::TinyGLTFLoader loader;
|
||||
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()) {
|
||||
printf("Err: %s\n", err.c_str());
|
@ -1,5 +1,5 @@
|
||||
sources = {
|
||||
"test.cc",
|
||||
"loader_example.cc",
|
||||
}
|
||||
|
||||
-- premake4.lua
|
||||
@ -21,9 +21,9 @@ solution "TinyGLTFLoaderSolution"
|
||||
configuration "Debug"
|
||||
defines { "DEBUG" } -- -DDEBUG
|
||||
flags { "Symbols" }
|
||||
targetname "test_tinygltfloader_debug"
|
||||
targetname "loader_example_tinygltfloader_debug"
|
||||
|
||||
configuration "Release"
|
||||
-- defines { "NDEBUG" } -- -NDEBUG
|
||||
flags { "Symbols", "Optimize" }
|
||||
targetname "test_tinygltfloader"
|
||||
targetname "loader_example_tinygltfloader"
|
||||
|
@ -22,7 +22,7 @@ success = []
|
||||
def run(filename):
|
||||
|
||||
print("Testing: " + filename)
|
||||
cmd = ["./loader_test", filename]
|
||||
cmd = ["./example", filename]
|
||||
try:
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
(stdout, stderr) = p.communicate()
|
||||
@ -45,7 +45,7 @@ def test():
|
||||
if os.path.isdir(p):
|
||||
for k in kinds:
|
||||
targetDir = os.path.join(p, k)
|
||||
g = glob.glob(targetDir + "/*.gltf")
|
||||
g = glob.glob(targetDir + "/*.gltf") + glob.glob(targetDir + "/*.glb")
|
||||
for gltf in g:
|
||||
run(gltf)
|
||||
|
||||
|
@ -102,6 +102,9 @@ typedef struct {
|
||||
int component;
|
||||
int pad0;
|
||||
std::vector<unsigned char> image;
|
||||
|
||||
std::string bufferView; // KHR_binary_glTF extenstion.
|
||||
std::string mimeType; // KHR_binary_glTF extenstion.
|
||||
} Image;
|
||||
|
||||
typedef struct {
|
||||
@ -137,7 +140,7 @@ typedef struct {
|
||||
int componentType; // One of TINYGLTF_COMPONENT_TYPE_***
|
||||
int pad0;
|
||||
size_t count;
|
||||
int type; // One of TINYGLTF_TYPE_***
|
||||
int type; // One of TINYGLTF_TYPE_***
|
||||
int pad1;
|
||||
std::vector<double> minValues; // Optional
|
||||
std::vector<double> maxValues; // Optional
|
||||
@ -235,34 +238,36 @@ class TinyGLTFLoader {
|
||||
/// Loads glTF ASCII asset from a file.
|
||||
/// Returns false and set error string to `err` if there's an error.
|
||||
bool LoadASCIIFromFile(Scene *scene, std::string *err,
|
||||
const std::string &filename);
|
||||
const std::string &filename);
|
||||
|
||||
/// Loads glTF ASCII asset from string(memory).
|
||||
/// `length` = strlen(str);
|
||||
/// Returns false and set error string to `err` if there's an error.
|
||||
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.
|
||||
/// Returns false and set error string to `err` if there's an error.
|
||||
bool LoadBinaryFromFile(Scene *scene, std::string *err,
|
||||
const std::string &filename);
|
||||
const std::string &filename);
|
||||
|
||||
/// Loads glTF binary asset from memory.
|
||||
/// `length` = strlen(str);
|
||||
/// Returns false and set error string to `err` if there's an error.
|
||||
bool LoadBinaryFromMemory(Scene *scene, std::string *err, const unsigned char *bytes,
|
||||
const unsigned int length);
|
||||
|
||||
private:
|
||||
bool LoadBinaryFromMemory(Scene *scene, std::string *err,
|
||||
const unsigned char *bytes,
|
||||
const unsigned int length,
|
||||
const std::string &base_dir = "");
|
||||
|
||||
private:
|
||||
/// Loads glTF asset from string(memory).
|
||||
/// `length` = strlen(str);
|
||||
/// Returns false and set error string to `err` if there's an error.
|
||||
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_;
|
||||
bool is_binary_;
|
||||
char pad[7];
|
||||
@ -275,7 +280,7 @@ private:
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
// Disable some warnings for external files.
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wfloat-equal"
|
||||
@ -308,21 +313,6 @@ private:
|
||||
|
||||
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) {
|
||||
#ifdef TINYGLTF_LITTLE_ENDIAN
|
||||
(void)val;
|
||||
@ -338,34 +328,13 @@ static void swap4(unsigned int *val) {
|
||||
#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) {
|
||||
bool ret;
|
||||
#ifdef _WIN32
|
||||
FILE *fp;
|
||||
errno_t err = fopen_s(&fp, abs_filename.c_str(), "rb");
|
||||
if (err != 0) {
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
FILE *fp = fopen(abs_filename.c_str(), "rb");
|
||||
@ -426,7 +395,8 @@ static std::string ExpandFilePath(const std::string &filepath) {
|
||||
#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()) {
|
||||
return path1;
|
||||
} else {
|
||||
@ -441,7 +411,7 @@ static std::string JoinPath(const std::string &path0, const std::string &path1)
|
||||
}
|
||||
|
||||
static std::string FindFile(const std::vector<std::string> &paths,
|
||||
const std::string &filepath) {
|
||||
const std::string &filepath) {
|
||||
for (size_t i = 0; i < paths.size(); i++) {
|
||||
std::string absPath = ExpandFilePath(JoinPath(paths[i], filepath));
|
||||
if (FileExists(absPath)) {
|
||||
@ -523,7 +493,8 @@ std::string base64_decode(std::string const &encoded_string) {
|
||||
in_++;
|
||||
if (i == 4) {
|
||||
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_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 = 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[1] =
|
||||
@ -555,8 +527,9 @@ std::string base64_decode(std::string const &encoded_string) {
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
static bool LoadExternalFile(std::vector<unsigned char> *out, std::string *err,
|
||||
const std::string &filename, const std::string &basedir,
|
||||
size_t reqBytes, bool checkSize) {
|
||||
const std::string &filename,
|
||||
const std::string &basedir, size_t reqBytes,
|
||||
bool checkSize) {
|
||||
out->clear();
|
||||
|
||||
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);
|
||||
|
||||
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();
|
||||
|
||||
if (checkSize) {
|
||||
@ -606,6 +580,52 @@ static bool LoadExternalFile(std::vector<unsigned char> *out, std::string *err,
|
||||
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) {
|
||||
std::string header = "data:application/octet-stream;base64,";
|
||||
if (in.find(header) == 0) {
|
||||
@ -625,8 +645,9 @@ static bool IsDataURI(const std::string &in) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool DecodeDataURI(std::vector<unsigned char> *out, const std::string &in,
|
||||
size_t reqBytes, bool checkSize) {
|
||||
static bool DecodeDataURI(std::vector<unsigned char> *out,
|
||||
const std::string &in, size_t reqBytes,
|
||||
bool checkSize) {
|
||||
std::string header = "data:application/octet-stream;base64,";
|
||||
std::string data;
|
||||
if (in.find(header) == 0) {
|
||||
@ -664,8 +685,8 @@ static bool DecodeDataURI(std::vector<unsigned char> *out, const std::string &in
|
||||
}
|
||||
|
||||
static bool ParseBooleanProperty(bool *ret, std::string *err,
|
||||
const picojson::object &o,
|
||||
const std::string &property, bool required) {
|
||||
const picojson::object &o,
|
||||
const std::string &property, bool required) {
|
||||
picojson::object::const_iterator it = o.find(property);
|
||||
if (it == o.end()) {
|
||||
if (required) {
|
||||
@ -693,8 +714,8 @@ static bool ParseBooleanProperty(bool *ret, std::string *err,
|
||||
}
|
||||
|
||||
static bool ParseNumberProperty(double *ret, std::string *err,
|
||||
const picojson::object &o, const std::string &property,
|
||||
bool required) {
|
||||
const picojson::object &o,
|
||||
const std::string &property, bool required) {
|
||||
picojson::object::const_iterator it = o.find(property);
|
||||
if (it == o.end()) {
|
||||
if (required) {
|
||||
@ -722,8 +743,9 @@ static bool ParseNumberProperty(double *ret, std::string *err,
|
||||
}
|
||||
|
||||
static bool ParseNumberArrayProperty(std::vector<double> *ret, std::string *err,
|
||||
const picojson::object &o,
|
||||
const std::string &property, bool required) {
|
||||
const picojson::object &o,
|
||||
const std::string &property,
|
||||
bool required) {
|
||||
picojson::object::const_iterator it = o.find(property);
|
||||
if (it == o.end()) {
|
||||
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,
|
||||
const picojson::object &o, const std::string &property,
|
||||
bool required) {
|
||||
const picojson::object &o,
|
||||
const std::string &property, bool required) {
|
||||
picojson::object::const_iterator it = o.find(property);
|
||||
if (it == o.end()) {
|
||||
if (required) {
|
||||
@ -789,9 +811,11 @@ static bool ParseStringProperty(std::string *ret, std::string *err,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ParseStringArrayProperty(std::vector<std::string> *ret, std::string *err,
|
||||
const picojson::object &o,
|
||||
const std::string &property, bool required) {
|
||||
static bool ParseStringArrayProperty(std::vector<std::string> *ret,
|
||||
std::string *err,
|
||||
const picojson::object &o,
|
||||
const std::string &property,
|
||||
bool required) {
|
||||
picojson::object::const_iterator it = o.find(property);
|
||||
if (it == o.end()) {
|
||||
if (required) {
|
||||
@ -828,7 +852,72 @@ static bool ParseStringArrayProperty(std::vector<std::string> *ret, std::string
|
||||
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);
|
||||
ParseBooleanProperty(&asset->premultipliedAlpha, err, o, "premultipliedAlpha",
|
||||
false);
|
||||
@ -849,8 +938,10 @@ static bool ParseAsset(Asset *asset, std::string *err, const picojson::object &o
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ParseImage(Image *image, std::string *err, const picojson::object &o,
|
||||
const std::string &basedir) {
|
||||
static bool ParseImage(Image *image, std::string *err,
|
||||
const picojson::object &o, const std::string &basedir,
|
||||
bool is_binary, const unsigned char *bin_data,
|
||||
size_t bin_size) {
|
||||
std::string uri;
|
||||
if (!ParseStringProperty(&uri, err, o, "uri", true)) {
|
||||
return false;
|
||||
@ -859,57 +950,90 @@ static bool ParseImage(Image *image, std::string *err, const picojson::object &o
|
||||
ParseStringProperty(&image->name, err, o, "name", false);
|
||||
|
||||
std::vector<unsigned char> img;
|
||||
if (IsDataURI(uri)) {
|
||||
if (!DecodeDataURI(&img, uri, 0, false)) {
|
||||
if (err) {
|
||||
(*err) += "Failed to decode 'uri'.\n";
|
||||
|
||||
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;
|
||||
}
|
||||
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 {
|
||||
// Assume external file
|
||||
if (!LoadExternalFile(&img, err, uri, basedir, 0, false)) {
|
||||
if (err) {
|
||||
(*err) += "Failed to load external 'uri'.\n";
|
||||
if (IsDataURI(uri)) {
|
||||
if (!DecodeDataURI(&img, uri, 0, false)) {
|
||||
if (err) {
|
||||
(*err) += "Failed to decode 'uri'.\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (img.empty()) {
|
||||
if (err) {
|
||||
(*err) += "File is empty.\n";
|
||||
} else {
|
||||
// Assume external file
|
||||
if (!LoadExternalFile(&img, err, uri, basedir, 0, false)) {
|
||||
if (err) {
|
||||
(*err) += "Failed to load external 'uri'.\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (img.empty()) {
|
||||
if (err) {
|
||||
(*err) += "File is empty.\n";
|
||||
}
|
||||
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) {
|
||||
if (err) {
|
||||
(*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;
|
||||
return LoadImageData(image, err, 0, 0, &img.at(0),
|
||||
static_cast<int>(img.size()));
|
||||
}
|
||||
|
||||
static bool ParseTexture(Texture *texture, std::string *err, const picojson::object &o,
|
||||
const std::string &basedir) {
|
||||
static bool ParseTexture(Texture *texture, std::string *err,
|
||||
const picojson::object &o,
|
||||
const std::string &basedir) {
|
||||
(void)basedir;
|
||||
|
||||
if (!ParseStringProperty(&texture->sampler, err, o, "sampler", true)) {
|
||||
@ -942,8 +1066,11 @@ static bool ParseTexture(Texture *texture, std::string *err, const picojson::obj
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ParseBuffer(Buffer *buffer, std::string *err, const picojson::object &o,
|
||||
const std::string &basedir, bool is_binary = false, const unsigned char* bin_data = NULL, size_t bin_size = 0) {
|
||||
static bool ParseBuffer(Buffer *buffer, std::string *err,
|
||||
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;
|
||||
if (!ParseNumberProperty(&byteLength, err, o, "byteLength", true)) {
|
||||
return false;
|
||||
@ -966,35 +1093,49 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const picojson::object
|
||||
|
||||
size_t bytes = static_cast<size_t>(byteLength);
|
||||
if (is_binary) {
|
||||
if ((bin_size == 0) || (bin_data == NULL)) {
|
||||
if (err) {
|
||||
(*err) += "Invalid binary data.\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (byteLength > bin_size) {
|
||||
if (err) {
|
||||
std::stringstream ss;
|
||||
ss << "Invalid `byteLength'. Must be equal or less than binary size: `byteLength' = " << byteLength << ", binary size = " << bin_size << std::endl;
|
||||
(*err) += ss.str();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (uri.compare("data:,") == 0) {
|
||||
|
||||
// @todo { check uri }
|
||||
buffer->data.resize(static_cast<size_t>(byteLength));
|
||||
memcpy(&(buffer->data.at(0)), bin_data, static_cast<size_t>(byteLength));
|
||||
|
||||
// Still binary glTF accepts external dataURI. First try external resources.
|
||||
bool loaded = false;
|
||||
if (IsDataURI(uri)) {
|
||||
loaded = DecodeDataURI(&buffer->data, uri, bytes, true);
|
||||
} else {
|
||||
if (err) {
|
||||
(*err) += "Invalid URI for binary data.\n";
|
||||
}
|
||||
return false;
|
||||
// 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 (err) {
|
||||
(*err) += "Invalid binary data.\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (byteLength > bin_size) {
|
||||
if (err) {
|
||||
std::stringstream ss;
|
||||
ss << "Invalid `byteLength'. Must be equal or less than binary size: "
|
||||
"`byteLength' = " << byteLength
|
||||
<< ", binary size = " << bin_size << std::endl;
|
||||
(*err) += ss.str();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (uri.compare("data:,") == 0) {
|
||||
// @todo { check uri }
|
||||
buffer->data.resize(static_cast<size_t>(byteLength));
|
||||
memcpy(&(buffer->data.at(0)), bin_data,
|
||||
static_cast<size_t>(byteLength));
|
||||
|
||||
} else {
|
||||
if (err) {
|
||||
(*err) += "Invalid URI for binary data.\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (IsDataURI(uri)) {
|
||||
@ -1018,7 +1159,7 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const picojson::object
|
||||
}
|
||||
|
||||
static bool ParseBufferView(BufferView *bufferView, std::string *err,
|
||||
const picojson::object &o) {
|
||||
const picojson::object &o) {
|
||||
std::string buffer;
|
||||
if (!ParseStringProperty(&buffer, err, o, "buffer", true)) {
|
||||
return false;
|
||||
@ -1053,7 +1194,7 @@ static bool ParseBufferView(BufferView *bufferView, std::string *err,
|
||||
}
|
||||
|
||||
static bool ParseAccessor(Accessor *accessor, std::string *err,
|
||||
const picojson::object &o) {
|
||||
const picojson::object &o) {
|
||||
std::string bufferView;
|
||||
if (!ParseStringProperty(&bufferView, err, o, "bufferView", true)) {
|
||||
return false;
|
||||
@ -1137,7 +1278,7 @@ static bool ParseAccessor(Accessor *accessor, std::string *err,
|
||||
}
|
||||
|
||||
static bool ParsePrimitive(Primitive *primitive, std::string *err,
|
||||
const picojson::object &o) {
|
||||
const picojson::object &o) {
|
||||
if (!ParseStringProperty(&primitive->material, err, o, "material", true)) {
|
||||
return false;
|
||||
}
|
||||
@ -1233,7 +1374,7 @@ static bool ParseNode(Node *node, std::string *err, const picojson::object &o) {
|
||||
}
|
||||
|
||||
static bool ParseMaterial(Material *material, std::string *err,
|
||||
const picojson::object &o) {
|
||||
const picojson::object &o) {
|
||||
ParseStringProperty(&material->name, err, o, "name", false);
|
||||
ParseStringProperty(&material->technique, err, o, "technique", false);
|
||||
|
||||
@ -1248,8 +1389,8 @@ static bool ParseMaterial(Material *material, std::string *err,
|
||||
for (; it != itEnd; it++) {
|
||||
// Assume number values.
|
||||
Parameter param;
|
||||
if (ParseStringProperty(¶m.string_value, err, values_object, it->first,
|
||||
false)) {
|
||||
if (ParseStringProperty(¶m.string_value, err, values_object,
|
||||
it->first, false)) {
|
||||
// Found string property.
|
||||
} else if (!ParseNumberArrayProperty(¶m.number_array, err,
|
||||
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,
|
||||
const char *str, unsigned int length,
|
||||
const std::string &baseDir) {
|
||||
const std::string &base_dir) {
|
||||
picojson::value v;
|
||||
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++) {
|
||||
Buffer buffer;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1483,10 +1624,34 @@ bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err,
|
||||
for (; it != itEnd; it++) {
|
||||
Image image;
|
||||
if (!ParseImage(&image, err, (it->second).get<picojson::object>(),
|
||||
baseDir)) {
|
||||
base_dir, is_binary_, bin_data_, bin_size_)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -1500,7 +1665,7 @@ bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err,
|
||||
for (; it != itEnd; it++) {
|
||||
Texture texture;
|
||||
if (!ParseTexture(&texture, err, (it->second).get<picojson::object>(),
|
||||
baseDir)) {
|
||||
base_dir)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1512,17 +1677,17 @@ bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err,
|
||||
}
|
||||
|
||||
bool TinyGLTFLoader::LoadASCIIFromString(Scene *scene, std::string *err,
|
||||
const char *str, unsigned int length,
|
||||
const std::string &baseDir) {
|
||||
const char *str, unsigned int length,
|
||||
const std::string &base_dir) {
|
||||
is_binary_ = false;
|
||||
bin_data_ = NULL;
|
||||
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,
|
||||
const std::string &filename) {
|
||||
const std::string &filename) {
|
||||
std::stringstream ss;
|
||||
|
||||
std::ifstream f(filename.c_str());
|
||||
@ -1544,14 +1709,16 @@ bool TinyGLTFLoader::LoadASCIIFromFile(Scene *scene, std::string *err,
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 (err) {
|
||||
(*err) = "Too short data size for glTF Binary.";
|
||||
@ -1559,7 +1726,8 @@ bool TinyGLTFLoader::LoadBinaryFromMemory(Scene *scene, std::string *err,
|
||||
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
|
||||
} else {
|
||||
if (err) {
|
||||
@ -1568,20 +1736,23 @@ bool TinyGLTFLoader::LoadBinaryFromMemory(Scene *scene, std::string *err,
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int version; // 4 bytes
|
||||
unsigned int length; // 4 bytes
|
||||
unsigned int scene_length; // 4 bytes
|
||||
unsigned int scene_format; // 4 bytes;
|
||||
unsigned int version; // 4 bytes
|
||||
unsigned int length; // 4 bytes
|
||||
unsigned int scene_length; // 4 bytes
|
||||
unsigned int scene_format; // 4 bytes;
|
||||
|
||||
// @todo { Endian swap for big endian machine. }
|
||||
memcpy(&version, bytes + 4, 4); swap4(&version);
|
||||
memcpy(&length, bytes + 8, 4); swap4(&length);
|
||||
memcpy(&scene_length, bytes + 12, 4); swap4(&scene_length);
|
||||
memcpy(&scene_format, bytes + 16, 4); swap4(&scene_format);
|
||||
memcpy(&version, bytes + 4, 4);
|
||||
swap4(&version);
|
||||
memcpy(&length, bytes + 8, 4);
|
||||
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) ||
|
||||
(scene_length < 1) ||
|
||||
(scene_format != 0)) { // 0 = JSON format.
|
||||
if ((20 + scene_length >= size) || (scene_length < 1) ||
|
||||
(scene_format != 0)) { // 0 = JSON format.
|
||||
if (err) {
|
||||
(*err) = "Invalid glTF binary.";
|
||||
}
|
||||
@ -1589,13 +1760,17 @@ bool TinyGLTFLoader::LoadBinaryFromMemory(Scene *scene, std::string *err,
|
||||
}
|
||||
|
||||
// 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;
|
||||
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) {
|
||||
return ret;
|
||||
}
|
||||
@ -1604,7 +1779,7 @@ bool TinyGLTFLoader::LoadBinaryFromMemory(Scene *scene, std::string *err,
|
||||
}
|
||||
|
||||
bool TinyGLTFLoader::LoadBinaryFromFile(Scene *scene, std::string *err,
|
||||
const std::string &filename) {
|
||||
const std::string &filename) {
|
||||
std::stringstream ss;
|
||||
|
||||
std::ifstream f(filename.c_str());
|
||||
@ -1624,7 +1799,11 @@ bool TinyGLTFLoader::LoadBinaryFromFile(Scene *scene, std::string *err,
|
||||
f.read(&buf.at(0), static_cast<std::streamsize>(sz));
|
||||
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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user