mirror of
https://git.mirrors.martin98.com/https://github.com/syoyo/tinygltf.git
synced 2025-08-13 22:35:53 +08:00
Added filesystem callback support
Now a library like PhysFS can be used to load files by defining custom callbacks and disabling the builtin ones by #define TINYGLTF_NO_FS
This commit is contained in:
parent
90e2c9cc74
commit
e6601bfb4b
507
tiny_gltf.h
507
tiny_gltf.h
@ -754,6 +754,67 @@ bool WriteImageData(const std::string *basepath, const std::string *filename,
|
|||||||
Image *image, bool embedImages, void *);
|
Image *image, bool embedImages, void *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
///
|
||||||
|
/// FilExistsFunction type. Signature for custom filesystem callbacks.
|
||||||
|
///
|
||||||
|
typedef bool (*FileExistsFunction)(const std::string &abs_filename,
|
||||||
|
void *);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// ExpandFilePathFunction type. Signature for custom filesystem callbacks.
|
||||||
|
///
|
||||||
|
typedef std::string (*ExpandFilePathFunction)(const std::string &,
|
||||||
|
void *);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// ReadWholeFileFunction type. Signature for custom filesystem callbacks.
|
||||||
|
///
|
||||||
|
typedef bool (*ReadWholeFileFunction)(std::vector<unsigned char> *,
|
||||||
|
std::string *,
|
||||||
|
const std::string &,
|
||||||
|
void *);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// WriteWholeFileFunction type. Signature for custom filesystem callbacks.
|
||||||
|
///
|
||||||
|
typedef bool (*WriteWholeFileFunction)(std::string *,
|
||||||
|
const std::string &,
|
||||||
|
const std::vector<unsigned char> &,
|
||||||
|
void *);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// A structure containing all required filesystem callbacks and a pointer to
|
||||||
|
/// their user data.
|
||||||
|
///
|
||||||
|
struct FsCallbacks
|
||||||
|
{
|
||||||
|
FileExistsFunction FileExists;
|
||||||
|
ExpandFilePathFunction ExpandFilePath;
|
||||||
|
ReadWholeFileFunction ReadWholeFile;
|
||||||
|
WriteWholeFileFunction WriteWholeFile;
|
||||||
|
|
||||||
|
void* user_data = nullptr; // An argument that is passed to all fs callbacks
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef TINYGLTF_NO_FS
|
||||||
|
// Declaration of default filesystem callbacks
|
||||||
|
|
||||||
|
bool FileExists(const std::string &abs_filename,
|
||||||
|
void *);
|
||||||
|
|
||||||
|
std::string ExpandFilePath(const std::string &filepath,
|
||||||
|
void *);
|
||||||
|
|
||||||
|
bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
|
||||||
|
const std::string &filepath,
|
||||||
|
void *);
|
||||||
|
|
||||||
|
bool WriteWholeFile(std::string *err,
|
||||||
|
const std::string &filepath,
|
||||||
|
const std::vector<unsigned char> &contents,
|
||||||
|
void *);
|
||||||
|
#endif
|
||||||
|
|
||||||
class TinyGLTF {
|
class TinyGLTF {
|
||||||
public:
|
public:
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
@ -823,6 +884,11 @@ class TinyGLTF {
|
|||||||
///
|
///
|
||||||
void SetImageWriter(WriteImageDataFunction WriteImageData, void *user_data);
|
void SetImageWriter(WriteImageDataFunction WriteImageData, void *user_data);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Set callbacks to use for filesystem (fs) access and their user data
|
||||||
|
///
|
||||||
|
void SetFsCallbacks(FsCallbacks callbacks);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
///
|
///
|
||||||
/// Loads glTF asset from string(memory).
|
/// Loads glTF asset from string(memory).
|
||||||
@ -837,21 +903,40 @@ class TinyGLTF {
|
|||||||
size_t bin_size_;
|
size_t bin_size_;
|
||||||
bool is_binary_;
|
bool is_binary_;
|
||||||
|
|
||||||
|
FsCallbacks fs = {
|
||||||
|
#ifndef TINYGLTF_NO_FS
|
||||||
|
&tinygltf::FileExists,
|
||||||
|
&tinygltf::ExpandFilePath,
|
||||||
|
&tinygltf::ReadWholeFile,
|
||||||
|
&tinygltf::WriteWholeFile,
|
||||||
|
|
||||||
|
nullptr // Fs callback user data
|
||||||
|
#else
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
|
||||||
|
nullptr // Fs callback user data
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
LoadImageDataFunction LoadImageData =
|
LoadImageDataFunction LoadImageData =
|
||||||
#ifndef TINYGLTF_NO_STB_IMAGE
|
#ifndef TINYGLTF_NO_STB_IMAGE
|
||||||
&tinygltf::LoadImageData;
|
&tinygltf::LoadImageData;
|
||||||
#else
|
#else
|
||||||
nullptr;
|
nullptr;
|
||||||
#endif
|
#endif
|
||||||
void *load_image_user_data_ = nullptr;
|
void *load_image_user_data_ = reinterpret_cast<void *>(&fs);
|
||||||
|
|
||||||
WriteImageDataFunction WriteImageData =
|
WriteImageDataFunction WriteImageData =
|
||||||
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
|
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
|
||||||
&tinygltf::WriteImageData;
|
&tinygltf::WriteImageData;
|
||||||
#else
|
#else
|
||||||
nullptr;
|
nullptr;
|
||||||
#endif
|
#endif
|
||||||
void *write_image_user_data_ = nullptr;
|
void *write_image_user_data_ = reinterpret_cast<void *>(&fs);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
@ -865,7 +950,9 @@ class TinyGLTF {
|
|||||||
#ifdef TINYGLTF_IMPLEMENTATION
|
#ifdef TINYGLTF_IMPLEMENTATION
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
//#include <cassert>
|
//#include <cassert>
|
||||||
|
#ifndef TINYGLTF_NO_FS
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#endif
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
@ -966,74 +1053,6 @@ static void swap4(unsigned int *val) {
|
|||||||
#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;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
FILE *fp = fopen(abs_filename.c_str(), "rb");
|
|
||||||
#endif
|
|
||||||
if (fp) {
|
|
||||||
ret = true;
|
|
||||||
fclose(fp);
|
|
||||||
} else {
|
|
||||||
ret = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string ExpandFilePath(const std::string &filepath) {
|
|
||||||
#ifdef _WIN32
|
|
||||||
DWORD len = ExpandEnvironmentStringsA(filepath.c_str(), NULL, 0);
|
|
||||||
char *str = new char[len];
|
|
||||||
ExpandEnvironmentStringsA(filepath.c_str(), str, len);
|
|
||||||
|
|
||||||
std::string s(str);
|
|
||||||
|
|
||||||
delete[] str;
|
|
||||||
|
|
||||||
return s;
|
|
||||||
#else
|
|
||||||
|
|
||||||
#if defined(TARGET_OS_IPHONE) || defined(TARGET_IPHONE_SIMULATOR) || \
|
|
||||||
defined(__ANDROID__)
|
|
||||||
// no expansion
|
|
||||||
std::string s = filepath;
|
|
||||||
#else
|
|
||||||
std::string s;
|
|
||||||
wordexp_t p;
|
|
||||||
|
|
||||||
if (filepath.empty()) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// char** w;
|
|
||||||
int ret = wordexp(filepath.c_str(), &p, 0);
|
|
||||||
if (ret) {
|
|
||||||
// err
|
|
||||||
s = filepath;
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use first element only.
|
|
||||||
if (p.we_wordv) {
|
|
||||||
s = std::string(p.we_wordv[0]);
|
|
||||||
wordfree(&p);
|
|
||||||
} else {
|
|
||||||
s = filepath;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return s;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string JoinPath(const std::string &path0,
|
static std::string JoinPath(const std::string &path0,
|
||||||
const std::string &path1) {
|
const std::string &path1) {
|
||||||
if (path0.empty()) {
|
if (path0.empty()) {
|
||||||
@ -1050,10 +1069,20 @@ static std::string JoinPath(const std::string &path0,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static std::string FindFile(const std::vector<std::string> &paths,
|
static std::string FindFile(const std::vector<std::string> &paths,
|
||||||
const std::string &filepath) {
|
const std::string &filepath,
|
||||||
|
FsCallbacks* fs) {
|
||||||
|
|
||||||
|
if (fs == nullptr || fs->ExpandFilePath == nullptr ||
|
||||||
|
fs->FileExists == nullptr) {
|
||||||
|
|
||||||
|
// Error, fs callback[s] missing
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < paths.size(); i++) {
|
for (size_t i = 0; i < paths.size(); i++) {
|
||||||
std::string absPath = ExpandFilePath(JoinPath(paths[i], filepath));
|
std::string absPath = fs->ExpandFilePath(JoinPath(paths[i], filepath),
|
||||||
if (FileExists(absPath)) {
|
fs->user_data);
|
||||||
|
if (fs->FileExists(absPath, fs->user_data)) {
|
||||||
return absPath;
|
return absPath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1216,14 +1245,26 @@ std::string base64_decode(std::string const &encoded_string) {
|
|||||||
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 &filename,
|
||||||
const std::string &basedir, size_t reqBytes,
|
const std::string &basedir, size_t reqBytes,
|
||||||
bool checkSize) {
|
bool checkSize,
|
||||||
|
FsCallbacks *fs) {
|
||||||
|
|
||||||
|
if (fs == nullptr || fs->FileExists == nullptr
|
||||||
|
|| fs->ExpandFilePath == nullptr || fs->ReadWholeFile == nullptr) {
|
||||||
|
|
||||||
|
// This is a developer error, assert() ?
|
||||||
|
if (err) {
|
||||||
|
(*err) += "FS callback[s] not set\n";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
out->clear();
|
out->clear();
|
||||||
|
|
||||||
std::vector<std::string> paths;
|
std::vector<std::string> paths;
|
||||||
paths.push_back(basedir);
|
paths.push_back(basedir);
|
||||||
paths.push_back(".");
|
paths.push_back(".");
|
||||||
|
|
||||||
std::string filepath = FindFile(paths, filename);
|
std::string filepath = FindFile(paths, filename, fs);
|
||||||
if (filepath.empty() || filename.empty()) {
|
if (filepath.empty() || filename.empty()) {
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) += "File not found : " + filename + "\n";
|
(*err) += "File not found : " + filename + "\n";
|
||||||
@ -1231,31 +1272,22 @@ static bool LoadExternalFile(std::vector<unsigned char> *out, std::string *err,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ifstream f(filepath.c_str(), std::ifstream::binary);
|
std::vector<unsigned char> buf;
|
||||||
if (!f) {
|
std::string fileReadErr;
|
||||||
|
bool fileRead = fs->ReadWholeFile(&buf, &fileReadErr, filepath,
|
||||||
|
fs->user_data);
|
||||||
|
if (!fileRead) {
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) += "File open error : " + filepath + "\n";
|
(*err) += "File read error : " + filepath + " : " + fileReadErr + "\n";
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
f.seekg(0, f.end);
|
size_t sz = buf.size();
|
||||||
size_t sz = static_cast<size_t>(f.tellg());
|
|
||||||
if (int(sz) < 0) {
|
|
||||||
// Looks reading directory, not a file.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sz == 0) {
|
if (sz == 0) {
|
||||||
// Invalid file size.
|
(*err) += "File is empty : " + filepath + "\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
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.close();
|
|
||||||
|
|
||||||
if (checkSize) {
|
if (checkSize) {
|
||||||
if (reqBytes == sz) {
|
if (reqBytes == sz) {
|
||||||
@ -1356,30 +1388,34 @@ static void WriteToMemory_stbi(void *context, void *data, int size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool WriteImageData(const std::string *basepath, const std::string *filename,
|
bool WriteImageData(const std::string *basepath, const std::string *filename,
|
||||||
Image *image, bool embedImages, void *) {
|
Image *image, bool embedImages, void *fsPtr) {
|
||||||
const std::string ext = GetFilePathExtension(*filename);
|
const std::string ext = GetFilePathExtension(*filename);
|
||||||
|
|
||||||
if (embedImages) {
|
// Write image to temporary buffer
|
||||||
// Write image to memory and embed in output
|
std::string header;
|
||||||
std::string header;
|
std::vector<unsigned char> data;
|
||||||
std::vector<unsigned char> data;
|
|
||||||
|
|
||||||
if (ext == "png") {
|
if (ext == "png") {
|
||||||
stbi_write_png_to_func(WriteToMemory_stbi, &data, image->width,
|
stbi_write_png_to_func(WriteToMemory_stbi, &data, image->width,
|
||||||
image->height, image->component, &image->image[0],
|
image->height, image->component, &image->image[0],
|
||||||
0);
|
0);
|
||||||
header = "data:image/png;base64,";
|
header = "data:image/png;base64,";
|
||||||
} else if (ext == "jpg") {
|
} else if (ext == "jpg") {
|
||||||
stbi_write_jpg_to_func(WriteToMemory_stbi, &data, image->width,
|
stbi_write_jpg_to_func(WriteToMemory_stbi, &data, image->width,
|
||||||
image->height, image->component, &image->image[0],
|
image->height, image->component, &image->image[0],
|
||||||
100);
|
100);
|
||||||
header = "data:image/jpeg;base64,";
|
header = "data:image/jpeg;base64,";
|
||||||
} else if (ext == "bmp") {
|
} else if (ext == "bmp") {
|
||||||
stbi_write_bmp_to_func(WriteToMemory_stbi, &data, image->width,
|
stbi_write_bmp_to_func(WriteToMemory_stbi, &data, image->width,
|
||||||
image->height, image->component, &image->image[0]);
|
image->height, image->component, &image->image[0]);
|
||||||
header = "data:image/bmp;base64,";
|
header = "data:image/bmp;base64,";
|
||||||
}
|
} else if (!embedImages) {
|
||||||
|
// Error: can't output requested format to file
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(embedImages) {
|
||||||
|
// Embed base64-encoded image into URI
|
||||||
if (data.size()) {
|
if (data.size()) {
|
||||||
image->uri =
|
image->uri =
|
||||||
header +
|
header +
|
||||||
@ -1389,21 +1425,16 @@ bool WriteImageData(const std::string *basepath, const std::string *filename,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Write image to disc
|
// Write image to disc
|
||||||
|
FsCallbacks *fs = reinterpret_cast<FsCallbacks *>(fsPtr);
|
||||||
const std::string imagefilepath = JoinPath(*basepath, *filename);
|
if (fs != nullptr && fs->WriteWholeFile == nullptr)
|
||||||
if (ext == "png") {
|
{
|
||||||
stbi_write_png(imagefilepath.c_str(), image->width, image->height,
|
const std::string imagefilepath = JoinPath(*basepath, *filename);
|
||||||
image->component, &image->image[0], 0);
|
std::string writeError;
|
||||||
} else if (ext == "jpg") {
|
if(!fs->WriteWholeFile(&writeError, imagefilepath, data, fs->user_data)) {
|
||||||
// TODO (Bowald): Give user the option to set output quality?
|
// Could not write image file to disc; Throw error ?
|
||||||
const int quality = 100;
|
}
|
||||||
stbi_write_jpg(imagefilepath.c_str(), image->width, image->height,
|
|
||||||
image->component, &image->image[0], quality);
|
|
||||||
} else if (ext == "bmp") {
|
|
||||||
stbi_write_bmp(imagefilepath.c_str(), image->width, image->height,
|
|
||||||
image->component, &image->image[0]);
|
|
||||||
} else {
|
} else {
|
||||||
// Throw error? Cant output requested format.
|
// Throw error?
|
||||||
}
|
}
|
||||||
image->uri = *filename;
|
image->uri = *filename;
|
||||||
}
|
}
|
||||||
@ -1412,6 +1443,145 @@ bool WriteImageData(const std::string *basepath, const std::string *filename,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void TinyGLTF::SetFsCallbacks(FsCallbacks callbacks)
|
||||||
|
{
|
||||||
|
fs = callbacks;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef TINYGLTF_NO_FS
|
||||||
|
// Default implementations of filesystem functions
|
||||||
|
|
||||||
|
bool FileExists(const std::string &abs_filename, void *) {
|
||||||
|
bool ret;
|
||||||
|
#ifdef _WIN32
|
||||||
|
FILE *fp;
|
||||||
|
errno_t err = fopen_s(&fp, abs_filename.c_str(), "rb");
|
||||||
|
if (err != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
FILE *fp = fopen(abs_filename.c_str(), "rb");
|
||||||
|
#endif
|
||||||
|
if (fp) {
|
||||||
|
ret = true;
|
||||||
|
fclose(fp);
|
||||||
|
} else {
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ExpandFilePath(const std::string &filepath, void *) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
DWORD len = ExpandEnvironmentStringsA(filepath.c_str(), NULL, 0);
|
||||||
|
char *str = new char[len];
|
||||||
|
ExpandEnvironmentStringsA(filepath.c_str(), str, len);
|
||||||
|
|
||||||
|
std::string s(str);
|
||||||
|
|
||||||
|
delete[] str;
|
||||||
|
|
||||||
|
return s;
|
||||||
|
#else
|
||||||
|
|
||||||
|
#if defined(TARGET_OS_IPHONE) || defined(TARGET_IPHONE_SIMULATOR) || \
|
||||||
|
defined(__ANDROID__)
|
||||||
|
// no expansion
|
||||||
|
std::string s = filepath;
|
||||||
|
#else
|
||||||
|
std::string s;
|
||||||
|
wordexp_t p;
|
||||||
|
|
||||||
|
if (filepath.empty()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// char** w;
|
||||||
|
int ret = wordexp(filepath.c_str(), &p, 0);
|
||||||
|
if (ret) {
|
||||||
|
// err
|
||||||
|
s = filepath;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use first element only.
|
||||||
|
if (p.we_wordv) {
|
||||||
|
s = std::string(p.we_wordv[0]);
|
||||||
|
wordfree(&p);
|
||||||
|
} else {
|
||||||
|
s = filepath;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return s;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
|
||||||
|
const std::string &filepath, void *) {
|
||||||
|
|
||||||
|
std::ifstream f(filepath.c_str(), std::ifstream::binary);
|
||||||
|
if (!f) {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "File open error : " + filepath + "\n";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
f.seekg(0, f.end);
|
||||||
|
size_t sz = static_cast<size_t>(f.tellg());
|
||||||
|
f.seekg(0, f.beg);
|
||||||
|
|
||||||
|
if (int(sz) < 0) {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "Invalid file size : " + filepath + " (does the path point to a directory?)";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else if (sz == 0) {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "File is empty : " + filepath + "\n";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->resize(sz);
|
||||||
|
f.read(reinterpret_cast<char *>(&out->at(0)),
|
||||||
|
static_cast<std::streamsize>(sz));
|
||||||
|
f.close();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteWholeFile(std::string *err,
|
||||||
|
const std::string &filepath,
|
||||||
|
const std::vector<unsigned char> &contents,
|
||||||
|
void *) {
|
||||||
|
|
||||||
|
std::ofstream f(filepath.c_str(), std::ofstream::binary);
|
||||||
|
if (!f) {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "File open error for writing : " + filepath + "\n";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
f.write(reinterpret_cast<const char *>(&contents.at(0)),
|
||||||
|
static_cast<std::streamsize>(contents.size()));
|
||||||
|
if (!f) {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "File write error: " + filepath + "\n";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
f.close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // TINYGLTF_NO_FS
|
||||||
|
|
||||||
static std::string MimeToExt(const std::string &mimeType) {
|
static std::string MimeToExt(const std::string &mimeType) {
|
||||||
if (mimeType == "image/jpeg") {
|
if (mimeType == "image/jpeg") {
|
||||||
return "jpg";
|
return "jpg";
|
||||||
@ -1929,8 +2099,9 @@ static bool ParseAsset(Asset *asset, std::string *err, const json &o) {
|
|||||||
|
|
||||||
static bool ParseImage(Image *image, std::string *err, const json &o,
|
static bool ParseImage(Image *image, std::string *err, const json &o,
|
||||||
const std::string &basedir,
|
const std::string &basedir,
|
||||||
|
FsCallbacks* fs,
|
||||||
LoadImageDataFunction *LoadImageData = nullptr,
|
LoadImageDataFunction *LoadImageData = nullptr,
|
||||||
void *user_data = nullptr) {
|
void *load_image_user_data = nullptr) {
|
||||||
// A glTF image must either reference a bufferView or an image uri
|
// A glTF image must either reference a bufferView or an image uri
|
||||||
|
|
||||||
// schema says oneOf [`bufferView`, `uri`]
|
// schema says oneOf [`bufferView`, `uri`]
|
||||||
@ -2012,7 +2183,7 @@ static bool ParseImage(Image *image, std::string *err, const json &o,
|
|||||||
#ifdef TINYGLTF_NO_EXTERNAL_IMAGE
|
#ifdef TINYGLTF_NO_EXTERNAL_IMAGE
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
if (!LoadExternalFile(&img, err, uri, basedir, 0, false)) {
|
if (!LoadExternalFile(&img, err, uri, basedir, 0, false, fs)) {
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) += "Failed to load external 'uri' for image parameter\n";
|
(*err) += "Failed to load external 'uri' for image parameter\n";
|
||||||
}
|
}
|
||||||
@ -2035,7 +2206,7 @@ static bool ParseImage(Image *image, std::string *err, const json &o,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return (*LoadImageData)(image, err, 0, 0, &img.at(0),
|
return (*LoadImageData)(image, err, 0, 0, &img.at(0),
|
||||||
static_cast<int>(img.size()), user_data);
|
static_cast<int>(img.size()), load_image_user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ParseTexture(Texture *texture, std::string *err, const json &o,
|
static bool ParseTexture(Texture *texture, std::string *err, const json &o,
|
||||||
@ -2057,6 +2228,7 @@ static bool ParseTexture(Texture *texture, std::string *err, const json &o,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o,
|
static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o,
|
||||||
|
FsCallbacks* fs,
|
||||||
const std::string &basedir, bool is_binary = false,
|
const std::string &basedir, bool is_binary = false,
|
||||||
const unsigned char *bin_data = nullptr,
|
const unsigned char *bin_data = nullptr,
|
||||||
size_t bin_size = 0) {
|
size_t bin_size = 0) {
|
||||||
@ -2092,7 +2264,7 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o,
|
|||||||
|
|
||||||
if (!buffer->uri.empty()) {
|
if (!buffer->uri.empty()) {
|
||||||
// External .bin file.
|
// External .bin file.
|
||||||
LoadExternalFile(&buffer->data, err, buffer->uri, basedir, bytes, true);
|
LoadExternalFile(&buffer->data, err, buffer->uri, basedir, bytes, true, fs);
|
||||||
} else {
|
} else {
|
||||||
// load data from (embedded) binary data
|
// load data from (embedded) binary data
|
||||||
|
|
||||||
@ -2131,7 +2303,7 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o,
|
|||||||
} else {
|
} else {
|
||||||
// Assume external .bin file.
|
// Assume external .bin file.
|
||||||
if (!LoadExternalFile(&buffer->data, err, buffer->uri, basedir, bytes,
|
if (!LoadExternalFile(&buffer->data, err, buffer->uri, basedir, bytes,
|
||||||
true)) {
|
true, fs)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2925,7 +3097,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
if (!ParseBuffer(&buffer, err, it->get<json>(), base_dir, is_binary_,
|
if (!ParseBuffer(&buffer, err, it->get<json>(),
|
||||||
|
&fs, base_dir, is_binary_,
|
||||||
bin_data_, bin_size_)) {
|
bin_data_, bin_size_)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -3127,7 +3300,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Image image;
|
Image image;
|
||||||
if (!ParseImage(&image, err, it.value(), base_dir, &this->LoadImageData,
|
if (!ParseImage(&image, err, it.value(),
|
||||||
|
base_dir, &fs, &this->LoadImageData,
|
||||||
load_image_user_data_)) {
|
load_image_user_data_)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -3356,19 +3530,28 @@ bool TinyGLTF::LoadASCIIFromFile(Model *model, std::string *err,
|
|||||||
unsigned int check_sections) {
|
unsigned int check_sections) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
std::ifstream f(filename.c_str());
|
if (fs.ReadWholeFile == nullptr) {
|
||||||
if (!f) {
|
// Programmer error, assert() ?
|
||||||
ss << "Failed to open file: " << filename << std::endl;
|
ss << "Failed to read file: " << filename <<
|
||||||
|
": one or more FS callback not set" << std::endl;
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) = ss.str();
|
(*err) = ss.str();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
f.seekg(0, f.end);
|
std::vector<unsigned char> data;
|
||||||
size_t sz = static_cast<size_t>(f.tellg());
|
std::string fileerr;
|
||||||
std::vector<char> buf(sz);
|
bool fileread = fs.ReadWholeFile(&data, &fileerr, filename, fs.user_data);
|
||||||
|
if(!fileread) {
|
||||||
|
ss << "Failed to read file: " << filename << ": " << fileerr << std::endl;
|
||||||
|
if (err) {
|
||||||
|
(*err) = ss.str();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t sz = data.size();
|
||||||
if (sz == 0) {
|
if (sz == 0) {
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) = "Empty file.";
|
(*err) = "Empty file.";
|
||||||
@ -3376,14 +3559,12 @@ bool TinyGLTF::LoadASCIIFromFile(Model *model, std::string *err,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
f.seekg(0, f.beg);
|
|
||||||
f.read(&buf.at(0), static_cast<std::streamsize>(sz));
|
|
||||||
f.close();
|
|
||||||
|
|
||||||
std::string basedir = GetBaseDir(filename);
|
std::string basedir = GetBaseDir(filename);
|
||||||
|
|
||||||
bool ret = LoadASCIIFromString(model, err, &buf.at(0),
|
bool ret = LoadASCIIFromString(model, err,
|
||||||
static_cast<unsigned int>(buf.size()), basedir,
|
reinterpret_cast<const char *>(&data.at(0)),
|
||||||
|
static_cast<unsigned int>(data.size()),
|
||||||
|
basedir,
|
||||||
check_sections);
|
check_sections);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -3462,28 +3643,32 @@ bool TinyGLTF::LoadBinaryFromFile(Model *model, std::string *err,
|
|||||||
unsigned int check_sections) {
|
unsigned int check_sections) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
std::ifstream f(filename.c_str(), std::ios::binary);
|
if (fs.ReadWholeFile == nullptr) {
|
||||||
if (!f) {
|
// Programmer error, assert() ?
|
||||||
ss << "Failed to open file: " << filename << std::endl;
|
ss << "Failed to read file: " << filename <<
|
||||||
|
": one or more FS callback not set" << std::endl;
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) = ss.str();
|
(*err) = ss.str();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
f.seekg(0, f.end);
|
std::vector<unsigned char> data;
|
||||||
size_t sz = static_cast<size_t>(f.tellg());
|
std::string fileerr;
|
||||||
std::vector<char> buf(sz);
|
bool fileread = fs.ReadWholeFile(&data, &fileerr, filename, fs.user_data);
|
||||||
|
if(!fileread) {
|
||||||
f.seekg(0, f.beg);
|
ss << "Failed to read file: " << filename << ": " << fileerr << std::endl;
|
||||||
f.read(&buf.at(0), static_cast<std::streamsize>(sz));
|
if (err) {
|
||||||
f.close();
|
(*err) = ss.str();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::string basedir = GetBaseDir(filename);
|
std::string basedir = GetBaseDir(filename);
|
||||||
|
|
||||||
bool ret = LoadBinaryFromMemory(
|
bool ret = LoadBinaryFromMemory(
|
||||||
model, err, reinterpret_cast<unsigned char *>(&buf.at(0)),
|
model, err, &data.at(0),
|
||||||
static_cast<unsigned int>(buf.size()), basedir, check_sections);
|
static_cast<unsigned int>(data.size()), basedir, check_sections);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user