tiny_gltf 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +6 -6
- data/ext/tiny_gltf/json.hpp +11842 -6158
- data/ext/tiny_gltf/rb_tiny_gltf.h +1 -2
- data/ext/tiny_gltf/tiny_gltf.h +396 -176
- data/lib/tiny_gltf/version.rb +1 -1
- data/tiny_gltf.gemspec +1 -1
- metadata +9 -9
@@ -7,6 +7,7 @@
|
|
7
7
|
#endif
|
8
8
|
|
9
9
|
#include <time.h> // work around C++/C linkage error on some platforms
|
10
|
+
#include "ruby.h"
|
10
11
|
|
11
12
|
#if __cplusplus
|
12
13
|
#include <algorithm>
|
@@ -15,8 +16,6 @@
|
|
15
16
|
extern "C" {
|
16
17
|
#endif
|
17
18
|
|
18
|
-
#include "ruby.h"
|
19
|
-
|
20
19
|
void Init_tiny_gltf(void);
|
21
20
|
VALUE rb_tgltf_load(int argc, VALUE *argv, VALUE self);
|
22
21
|
|
data/ext/tiny_gltf/tiny_gltf.h
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
//
|
5
5
|
// The MIT License (MIT)
|
6
6
|
//
|
7
|
-
// Copyright (c) 2015 -
|
7
|
+
// Copyright (c) 2015 - 2020 Syoyo Fujita, Aurélien Chatelain and many
|
8
8
|
// contributors.
|
9
9
|
//
|
10
10
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -26,6 +26,7 @@
|
|
26
26
|
// THE SOFTWARE.
|
27
27
|
|
28
28
|
// Version:
|
29
|
+
// - v2.4.2 Decode percent-encoded URI.
|
29
30
|
// - v2.4.1 Fix some glTF object class does not have `extensions` and/or
|
30
31
|
// `extras` property.
|
31
32
|
// - v2.4.0 Experimental RapidJSON and C++14 support(Thanks to @jrkoone).
|
@@ -51,6 +52,7 @@
|
|
51
52
|
|
52
53
|
#include <array>
|
53
54
|
#include <cassert>
|
55
|
+
#include <cmath> // std::fabs
|
54
56
|
#include <cstdint>
|
55
57
|
#include <cstdlib>
|
56
58
|
#include <cstring>
|
@@ -321,7 +323,8 @@ class Value {
|
|
321
323
|
}
|
322
324
|
|
323
325
|
// Use this function if you want to have number value as int.
|
324
|
-
|
326
|
+
// TODO(syoyo): Support int value larger than 32 bits
|
327
|
+
int GetNumberAsInt() const {
|
325
328
|
if (type_ == REAL_TYPE) {
|
326
329
|
return int(real_value_);
|
327
330
|
} else {
|
@@ -526,10 +529,12 @@ struct AnimationChannel {
|
|
526
529
|
// "weights"]
|
527
530
|
Value extras;
|
528
531
|
ExtensionMap extensions;
|
532
|
+
ExtensionMap target_extensions;
|
529
533
|
|
530
534
|
// Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
|
531
535
|
std::string extras_json_string;
|
532
536
|
std::string extensions_json_string;
|
537
|
+
std::string target_extensions_json_string;
|
533
538
|
|
534
539
|
AnimationChannel() : sampler(-1), target_node(-1) {}
|
535
540
|
DEFAULT_METHODS(AnimationChannel)
|
@@ -637,7 +642,8 @@ struct Image {
|
|
637
642
|
int bufferView; // (required if no uri)
|
638
643
|
std::string mimeType; // (required if no uri) ["image/jpeg", "image/png",
|
639
644
|
// "image/bmp", "image/gif"]
|
640
|
-
std::string uri; // (required if no mimeType)
|
645
|
+
std::string uri; // (required if no mimeType) uri is not decoded(e.g.
|
646
|
+
// whitespace may be represented as %20)
|
641
647
|
Value extras;
|
642
648
|
ExtensionMap extensions;
|
643
649
|
|
@@ -658,6 +664,8 @@ struct Image {
|
|
658
664
|
width = -1;
|
659
665
|
height = -1;
|
660
666
|
component = -1;
|
667
|
+
bits = -1;
|
668
|
+
pixel_type = -1;
|
661
669
|
}
|
662
670
|
DEFAULT_METHODS(Image)
|
663
671
|
|
@@ -797,12 +805,13 @@ struct Material {
|
|
797
805
|
|
798
806
|
struct BufferView {
|
799
807
|
std::string name;
|
800
|
-
int buffer;
|
801
|
-
size_t byteOffset; // minimum 0, default 0
|
802
|
-
size_t byteLength; // required, minimum 1
|
803
|
-
size_t byteStride; // minimum 4, maximum 252 (multiple of 4), default 0 =
|
804
|
-
|
805
|
-
int target;
|
808
|
+
int buffer{-1}; // Required
|
809
|
+
size_t byteOffset{0}; // minimum 0, default 0
|
810
|
+
size_t byteLength{0}; // required, minimum 1. 0 = invalid
|
811
|
+
size_t byteStride{0}; // minimum 4, maximum 252 (multiple of 4), default 0 =
|
812
|
+
// understood to be tightly packed
|
813
|
+
int target{0}; // ["ARRAY_BUFFER", "ELEMENT_ARRAY_BUFFER"] for vertex indices
|
814
|
+
// or atttribs. Could be 0 for other data
|
806
815
|
Value extras;
|
807
816
|
ExtensionMap extensions;
|
808
817
|
|
@@ -810,9 +819,15 @@ struct BufferView {
|
|
810
819
|
std::string extras_json_string;
|
811
820
|
std::string extensions_json_string;
|
812
821
|
|
813
|
-
bool dracoDecoded; // Flag indicating this has been draco decoded
|
822
|
+
bool dracoDecoded{false}; // Flag indicating this has been draco decoded
|
814
823
|
|
815
|
-
BufferView()
|
824
|
+
BufferView()
|
825
|
+
: buffer(-1),
|
826
|
+
byteOffset(0),
|
827
|
+
byteLength(0),
|
828
|
+
byteStride(0),
|
829
|
+
target(0),
|
830
|
+
dracoDecoded(false) {}
|
816
831
|
DEFAULT_METHODS(BufferView)
|
817
832
|
bool operator==(const BufferView &) const;
|
818
833
|
};
|
@@ -887,13 +902,13 @@ struct Accessor {
|
|
887
902
|
// unreachable return 0;
|
888
903
|
}
|
889
904
|
|
890
|
-
Accessor()
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
905
|
+
Accessor()
|
906
|
+
: bufferView(-1),
|
907
|
+
byteOffset(0),
|
908
|
+
normalized(false),
|
909
|
+
componentType(-1),
|
910
|
+
count(0),
|
911
|
+
type(-1) {
|
897
912
|
sparse.isSparse = false;
|
898
913
|
}
|
899
914
|
DEFAULT_METHODS(Accessor)
|
@@ -983,6 +998,7 @@ struct Primitive {
|
|
983
998
|
Primitive() {
|
984
999
|
material = -1;
|
985
1000
|
indices = -1;
|
1001
|
+
mode = -1;
|
986
1002
|
}
|
987
1003
|
DEFAULT_METHODS(Primitive)
|
988
1004
|
bool operator==(const Primitive &) const;
|
@@ -1037,6 +1053,7 @@ struct Buffer {
|
|
1037
1053
|
std::vector<unsigned char> data;
|
1038
1054
|
std::string
|
1039
1055
|
uri; // considered as required here but not in the spec (need to clarify)
|
1056
|
+
// uri is not decoded(e.g. whitespace may be represented as %20)
|
1040
1057
|
Value extras;
|
1041
1058
|
ExtensionMap extensions;
|
1042
1059
|
|
@@ -1101,9 +1118,9 @@ struct SpotLight {
|
|
1101
1118
|
struct Light {
|
1102
1119
|
std::string name;
|
1103
1120
|
std::vector<double> color;
|
1104
|
-
double intensity;
|
1121
|
+
double intensity{1.0};
|
1105
1122
|
std::string type;
|
1106
|
-
double range;
|
1123
|
+
double range{0.0}; // 0.0 = inifinite
|
1107
1124
|
SpotLight spot;
|
1108
1125
|
|
1109
1126
|
Light() : intensity(1.0), range(0.0) {}
|
@@ -1141,7 +1158,7 @@ class Model {
|
|
1141
1158
|
std::vector<Scene> scenes;
|
1142
1159
|
std::vector<Light> lights;
|
1143
1160
|
|
1144
|
-
int defaultScene;
|
1161
|
+
int defaultScene = -1;
|
1145
1162
|
std::vector<std::string> extensionsUsed;
|
1146
1163
|
std::vector<std::string> extensionsRequired;
|
1147
1164
|
|
@@ -1235,7 +1252,14 @@ struct FsCallbacks {
|
|
1235
1252
|
|
1236
1253
|
bool FileExists(const std::string &abs_filename, void *);
|
1237
1254
|
|
1238
|
-
|
1255
|
+
///
|
1256
|
+
/// Expand file path(e.g. `~` to home directory on posix, `%APPDATA%` to
|
1257
|
+
/// `C:\Users\tinygltf\AppData`)
|
1258
|
+
///
|
1259
|
+
/// @param[in] filepath File path string. Assume UTF-8
|
1260
|
+
/// @param[in] userdata User data. Set to `nullptr` if you don't need it.
|
1261
|
+
///
|
1262
|
+
std::string ExpandFilePath(const std::string &filepath, void *userdata);
|
1239
1263
|
|
1240
1264
|
bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
|
1241
1265
|
const std::string &filepath, void *);
|
@@ -1547,11 +1571,12 @@ class TinyGLTF {
|
|
1547
1571
|
#undef NOMINMAX
|
1548
1572
|
#endif
|
1549
1573
|
|
1550
|
-
#if defined(__GLIBCXX__)
|
1574
|
+
#if defined(__GLIBCXX__) // mingw
|
1551
1575
|
|
1552
|
-
#include <ext/stdio_filebuf.h> // fstream (all sorts of IO stuff) + stdio_filebuf (=streambuf)
|
1553
1576
|
#include <fcntl.h> // _O_RDONLY
|
1554
1577
|
|
1578
|
+
#include <ext/stdio_filebuf.h> // fstream (all sorts of IO stuff) + stdio_filebuf (=streambuf)
|
1579
|
+
|
1555
1580
|
#endif
|
1556
1581
|
|
1557
1582
|
#elif !defined(__ANDROID__)
|
@@ -2119,6 +2144,88 @@ std::string base64_decode(std::string const &encoded_string) {
|
|
2119
2144
|
#pragma clang diagnostic pop
|
2120
2145
|
#endif
|
2121
2146
|
|
2147
|
+
// https://github.com/syoyo/tinygltf/issues/228
|
2148
|
+
// TODO(syoyo): Use uriparser https://uriparser.github.io/ for stricter Uri
|
2149
|
+
// decoding?
|
2150
|
+
//
|
2151
|
+
// https://stackoverflow.com/questions/18307429/encode-decode-url-in-c
|
2152
|
+
// http://dlib.net/dlib/server/server_http.cpp.html
|
2153
|
+
|
2154
|
+
// --- dlib beign ------------------------------------------------------------
|
2155
|
+
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
|
2156
|
+
// License: Boost Software License See LICENSE.txt for the full license.
|
2157
|
+
|
2158
|
+
namespace dlib {
|
2159
|
+
|
2160
|
+
#if 0
|
2161
|
+
inline unsigned char to_hex( unsigned char x )
|
2162
|
+
{
|
2163
|
+
return x + (x > 9 ? ('A'-10) : '0');
|
2164
|
+
}
|
2165
|
+
|
2166
|
+
const std::string urlencode( const std::string& s )
|
2167
|
+
{
|
2168
|
+
std::ostringstream os;
|
2169
|
+
|
2170
|
+
for ( std::string::const_iterator ci = s.begin(); ci != s.end(); ++ci )
|
2171
|
+
{
|
2172
|
+
if ( (*ci >= 'a' && *ci <= 'z') ||
|
2173
|
+
(*ci >= 'A' && *ci <= 'Z') ||
|
2174
|
+
(*ci >= '0' && *ci <= '9') )
|
2175
|
+
{ // allowed
|
2176
|
+
os << *ci;
|
2177
|
+
}
|
2178
|
+
else if ( *ci == ' ')
|
2179
|
+
{
|
2180
|
+
os << '+';
|
2181
|
+
}
|
2182
|
+
else
|
2183
|
+
{
|
2184
|
+
os << '%' << to_hex(static_cast<unsigned char>(*ci >> 4)) << to_hex(static_cast<unsigned char>(*ci % 16));
|
2185
|
+
}
|
2186
|
+
}
|
2187
|
+
|
2188
|
+
return os.str();
|
2189
|
+
}
|
2190
|
+
#endif
|
2191
|
+
|
2192
|
+
inline unsigned char from_hex(unsigned char ch) {
|
2193
|
+
if (ch <= '9' && ch >= '0')
|
2194
|
+
ch -= '0';
|
2195
|
+
else if (ch <= 'f' && ch >= 'a')
|
2196
|
+
ch -= 'a' - 10;
|
2197
|
+
else if (ch <= 'F' && ch >= 'A')
|
2198
|
+
ch -= 'A' - 10;
|
2199
|
+
else
|
2200
|
+
ch = 0;
|
2201
|
+
return ch;
|
2202
|
+
}
|
2203
|
+
|
2204
|
+
static const std::string urldecode(const std::string &str) {
|
2205
|
+
using namespace std;
|
2206
|
+
string result;
|
2207
|
+
string::size_type i;
|
2208
|
+
for (i = 0; i < str.size(); ++i) {
|
2209
|
+
if (str[i] == '+') {
|
2210
|
+
result += ' ';
|
2211
|
+
} else if (str[i] == '%' && str.size() > i + 2) {
|
2212
|
+
const unsigned char ch1 =
|
2213
|
+
from_hex(static_cast<unsigned char>(str[i + 1]));
|
2214
|
+
const unsigned char ch2 =
|
2215
|
+
from_hex(static_cast<unsigned char>(str[i + 2]));
|
2216
|
+
const unsigned char ch = static_cast<unsigned char>((ch1 << 4) | ch2);
|
2217
|
+
result += static_cast<char>(ch);
|
2218
|
+
i += 2;
|
2219
|
+
} else {
|
2220
|
+
result += str[i];
|
2221
|
+
}
|
2222
|
+
}
|
2223
|
+
return result;
|
2224
|
+
}
|
2225
|
+
|
2226
|
+
} // namespace dlib
|
2227
|
+
// --- dlib end --------------------------------------------------------------
|
2228
|
+
|
2122
2229
|
static bool LoadExternalFile(std::vector<unsigned char> *out, std::string *err,
|
2123
2230
|
std::string *warn, const std::string &filename,
|
2124
2231
|
const std::string &basedir, bool required,
|
@@ -2379,11 +2486,22 @@ void TinyGLTF::SetFsCallbacks(FsCallbacks callbacks) { fs = callbacks; }
|
|
2379
2486
|
|
2380
2487
|
#ifdef _WIN32
|
2381
2488
|
static inline std::wstring UTF8ToWchar(const std::string &str) {
|
2382
|
-
int wstr_size =
|
2489
|
+
int wstr_size =
|
2490
|
+
MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), nullptr, 0);
|
2383
2491
|
std::wstring wstr(wstr_size, 0);
|
2384
|
-
MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), &wstr[0],
|
2492
|
+
MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), &wstr[0],
|
2493
|
+
(int)wstr.size());
|
2385
2494
|
return wstr;
|
2386
2495
|
}
|
2496
|
+
|
2497
|
+
static inline std::string WcharToUTF8(const std::wstring &wstr) {
|
2498
|
+
int str_size = WideCharToMultiByte(CP_UTF8, 0, wstr.data(), (int)wstr.size(),
|
2499
|
+
nullptr, 0, NULL, NULL);
|
2500
|
+
std::string str(str_size, 0);
|
2501
|
+
WideCharToMultiByte(CP_UTF8, 0, wstr.data(), (int)wstr.size(), &str[0],
|
2502
|
+
(int)str.size(), NULL, NULL);
|
2503
|
+
return str;
|
2504
|
+
}
|
2387
2505
|
#endif
|
2388
2506
|
|
2389
2507
|
#ifndef TINYGLTF_NO_FS
|
@@ -2435,15 +2553,16 @@ bool FileExists(const std::string &abs_filename, void *) {
|
|
2435
2553
|
|
2436
2554
|
std::string ExpandFilePath(const std::string &filepath, void *) {
|
2437
2555
|
#ifdef _WIN32
|
2438
|
-
|
2439
|
-
|
2440
|
-
|
2556
|
+
// Assume input `filepath` is encoded in UTF-8
|
2557
|
+
std::wstring wfilepath = UTF8ToWchar(filepath);
|
2558
|
+
DWORD wlen = ExpandEnvironmentStringsW(wfilepath.c_str(), nullptr, 0);
|
2559
|
+
wchar_t *wstr = new wchar_t[wlen];
|
2560
|
+
ExpandEnvironmentStringsW(wfilepath.c_str(), wstr, wlen);
|
2441
2561
|
|
2442
|
-
std::
|
2562
|
+
std::wstring ws(wstr);
|
2563
|
+
delete[] wstr;
|
2564
|
+
return WcharToUTF8(ws);
|
2443
2565
|
|
2444
|
-
delete[] str;
|
2445
|
-
|
2446
|
-
return s;
|
2447
2566
|
#else
|
2448
2567
|
|
2449
2568
|
#if defined(TARGET_OS_IPHONE) || defined(TARGET_IPHONE_SIMULATOR) || \
|
@@ -2458,8 +2577,10 @@ std::string ExpandFilePath(const std::string &filepath, void *) {
|
|
2458
2577
|
return "";
|
2459
2578
|
}
|
2460
2579
|
|
2580
|
+
// Quote the string to keep any spaces in filepath intact.
|
2581
|
+
std::string quoted_path = "\"" + filepath + "\"";
|
2461
2582
|
// char** w;
|
2462
|
-
int ret = wordexp(
|
2583
|
+
int ret = wordexp(quoted_path.c_str(), &p, 0);
|
2463
2584
|
if (ret) {
|
2464
2585
|
// err
|
2465
2586
|
s = filepath;
|
@@ -2493,11 +2614,12 @@ bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
|
|
2493
2614
|
return false;
|
2494
2615
|
}
|
2495
2616
|
size_t size = AAsset_getLength(asset);
|
2496
|
-
if (size
|
2617
|
+
if (size == 0) {
|
2497
2618
|
if (err) {
|
2498
2619
|
(*err) += "Invalid file size : " + filepath +
|
2499
2620
|
" (does the path point to a directory?)";
|
2500
2621
|
}
|
2622
|
+
return false;
|
2501
2623
|
}
|
2502
2624
|
out->resize(size);
|
2503
2625
|
AAsset_read(asset, reinterpret_cast<char *>(&out->at(0)), size);
|
@@ -2511,13 +2633,17 @@ bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
|
|
2511
2633
|
}
|
2512
2634
|
#else
|
2513
2635
|
#ifdef _WIN32
|
2514
|
-
#if defined(__GLIBCXX__)
|
2515
|
-
int file_descriptor =
|
2636
|
+
#if defined(__GLIBCXX__) // mingw
|
2637
|
+
int file_descriptor =
|
2638
|
+
_wopen(UTF8ToWchar(filepath).c_str(), _O_RDONLY | _O_BINARY);
|
2516
2639
|
__gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor, std::ios_base::in);
|
2517
2640
|
std::istream f(&wfile_buf);
|
2518
|
-
#elif defined(_MSC_VER)
|
2641
|
+
#elif defined(_MSC_VER) || defined(_LIBCPP_VERSION)
|
2642
|
+
// For libcxx, assume _LIBCPP_HAS_OPEN_WITH_WCHAR is defined to accept
|
2643
|
+
// `wchar_t *`
|
2519
2644
|
std::ifstream f(UTF8ToWchar(filepath).c_str(), std::ifstream::binary);
|
2520
|
-
#else
|
2645
|
+
#else
|
2646
|
+
// Unknown compiler/runtime
|
2521
2647
|
std::ifstream f(filepath.c_str(), std::ifstream::binary);
|
2522
2648
|
#endif
|
2523
2649
|
#else
|
@@ -2558,13 +2684,15 @@ bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
|
|
2558
2684
|
bool WriteWholeFile(std::string *err, const std::string &filepath,
|
2559
2685
|
const std::vector<unsigned char> &contents, void *) {
|
2560
2686
|
#ifdef _WIN32
|
2561
|
-
#if defined(__GLIBCXX__)
|
2562
|
-
int file_descriptor = _wopen(UTF8ToWchar(filepath).c_str(),
|
2563
|
-
|
2687
|
+
#if defined(__GLIBCXX__) // mingw
|
2688
|
+
int file_descriptor = _wopen(UTF8ToWchar(filepath).c_str(),
|
2689
|
+
_O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY);
|
2690
|
+
__gnu_cxx::stdio_filebuf<char> wfile_buf(
|
2691
|
+
file_descriptor, std::ios_base::out | std::ios_base::binary);
|
2564
2692
|
std::ostream f(&wfile_buf);
|
2565
2693
|
#elif defined(_MSC_VER)
|
2566
2694
|
std::ofstream f(UTF8ToWchar(filepath).c_str(), std::ofstream::binary);
|
2567
|
-
#else
|
2695
|
+
#else // clang?
|
2568
2696
|
std::ofstream f(filepath.c_str(), std::ofstream::binary);
|
2569
2697
|
#endif
|
2570
2698
|
#else
|
@@ -2611,12 +2739,13 @@ static void UpdateImageObject(Image &image, std::string &baseDir, int index,
|
|
2611
2739
|
void *user_data = nullptr) {
|
2612
2740
|
std::string filename;
|
2613
2741
|
std::string ext;
|
2614
|
-
|
2615
|
-
// If image have uri. Use it it as a filename
|
2742
|
+
// If image has uri, use it it as a filename
|
2616
2743
|
if (image.uri.size()) {
|
2617
2744
|
filename = GetBaseFilename(image.uri);
|
2618
2745
|
ext = GetFilePathExtension(filename);
|
2619
|
-
|
2746
|
+
} else if (image.bufferView != -1) {
|
2747
|
+
// If there's no URI and the data exists in a buffer,
|
2748
|
+
// don't change properties or write images
|
2620
2749
|
} else if (image.name.size()) {
|
2621
2750
|
ext = MimeToExt(image.mimeType);
|
2622
2751
|
// Otherwise use name as filename
|
@@ -2628,7 +2757,7 @@ static void UpdateImageObject(Image &image, std::string &baseDir, int index,
|
|
2628
2757
|
}
|
2629
2758
|
|
2630
2759
|
// If callback is set, modify image data object
|
2631
|
-
if (*WriteImageData != nullptr) {
|
2760
|
+
if (*WriteImageData != nullptr && !filename.empty()) {
|
2632
2761
|
std::string uri;
|
2633
2762
|
(*WriteImageData)(&baseDir, &filename, &image, embedImages, user_data);
|
2634
2763
|
}
|
@@ -2728,6 +2857,7 @@ bool DecodeDataURI(std::vector<unsigned char> *out, std::string &mime_type,
|
|
2728
2857
|
}
|
2729
2858
|
}
|
2730
2859
|
|
2860
|
+
// TODO(syoyo): Allow empty buffer? #229
|
2731
2861
|
if (data.empty()) {
|
2732
2862
|
return false;
|
2733
2863
|
}
|
@@ -2872,7 +3002,9 @@ json_const_iterator ObjectEnd(const json &o) {
|
|
2872
3002
|
#endif
|
2873
3003
|
}
|
2874
3004
|
|
2875
|
-
const char
|
3005
|
+
// Making this a const char* results in a pointer to a temporary when
|
3006
|
+
// TINYGLTF_USE_RAPIDJSON is off.
|
3007
|
+
std::string GetKey(json_const_iterator &it) {
|
2876
3008
|
#ifdef TINYGLTF_USE_RAPIDJSON
|
2877
3009
|
return it->name.GetString();
|
2878
3010
|
#else
|
@@ -3508,6 +3640,7 @@ static bool ParseAsset(Asset *asset, std::string *err, const json &o,
|
|
3508
3640
|
ParseStringProperty(&asset->version, err, o, "version", true, "Asset");
|
3509
3641
|
ParseStringProperty(&asset->generator, err, o, "generator", false, "Asset");
|
3510
3642
|
ParseStringProperty(&asset->minVersion, err, o, "minVersion", false, "Asset");
|
3643
|
+
ParseStringProperty(&asset->copyright, err, o, "copyright", false, "Asset");
|
3511
3644
|
|
3512
3645
|
ParseExtensionsProperty(&asset->extensions, err, o);
|
3513
3646
|
|
@@ -3646,7 +3779,10 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err,
|
|
3646
3779
|
#ifdef TINYGLTF_NO_EXTERNAL_IMAGE
|
3647
3780
|
return true;
|
3648
3781
|
#endif
|
3649
|
-
|
3782
|
+
std::string decoded_uri = dlib::urldecode(uri);
|
3783
|
+
if (!LoadExternalFile(&img, err, warn, decoded_uri, basedir,
|
3784
|
+
/* required */ false, /* required bytes */ 0,
|
3785
|
+
/* checksize */ false, fs)) {
|
3650
3786
|
if (warn) {
|
3651
3787
|
(*warn) += "Failed to load external 'uri' for image[" +
|
3652
3788
|
std::to_string(image_idx) + "] name = [" + image->name +
|
@@ -3868,9 +4004,10 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o,
|
|
3868
4004
|
}
|
3869
4005
|
} else {
|
3870
4006
|
// External .bin file.
|
4007
|
+
std::string decoded_uri = dlib::urldecode(buffer->uri);
|
3871
4008
|
if (!LoadExternalFile(&buffer->data, err, /* warn */ nullptr,
|
3872
|
-
|
3873
|
-
fs)) {
|
4009
|
+
decoded_uri, basedir, /* required */ true,
|
4010
|
+
byteLength, /* checkSize */ true, fs)) {
|
3874
4011
|
return false;
|
3875
4012
|
}
|
3876
4013
|
}
|
@@ -3912,8 +4049,10 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o,
|
|
3912
4049
|
}
|
3913
4050
|
} else {
|
3914
4051
|
// Assume external .bin file.
|
3915
|
-
|
3916
|
-
|
4052
|
+
std::string decoded_uri = dlib::urldecode(buffer->uri);
|
4053
|
+
if (!LoadExternalFile(&buffer->data, err, /* warn */ nullptr, decoded_uri,
|
4054
|
+
basedir, /* required */ true, byteLength,
|
4055
|
+
/* checkSize */ true, fs)) {
|
3917
4056
|
return false;
|
3918
4057
|
}
|
3919
4058
|
}
|
@@ -4751,6 +4890,13 @@ static bool ParseAnimationChannel(
|
|
4751
4890
|
}
|
4752
4891
|
return false;
|
4753
4892
|
}
|
4893
|
+
ParseExtensionsProperty(&channel->target_extensions, err, target_object);
|
4894
|
+
if (store_original_json_for_extras_and_extensions) {
|
4895
|
+
json_const_iterator it;
|
4896
|
+
if (FindMember(target_object, "extensions", it)) {
|
4897
|
+
channel->target_extensions_json_string = JsonToString(GetValue(it));
|
4898
|
+
}
|
4899
|
+
}
|
4754
4900
|
}
|
4755
4901
|
|
4756
4902
|
channel->sampler = samplerIndex;
|
@@ -5252,7 +5398,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
|
|
5252
5398
|
|
5253
5399
|
#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || \
|
5254
5400
|
defined(_CPPUNWIND)) && \
|
5255
|
-
|
5401
|
+
!defined(TINYGLTF_NOEXCEPTION)
|
5256
5402
|
try {
|
5257
5403
|
JsonParse(v, json_str, json_str_length, true);
|
5258
5404
|
|
@@ -5525,7 +5671,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
|
|
5525
5671
|
|
5526
5672
|
// Assign missing bufferView target types
|
5527
5673
|
// - Look for missing Mesh indices
|
5528
|
-
// - Look for missing
|
5674
|
+
// - Look for missing Mesh attributes
|
5529
5675
|
for (auto &mesh : model->meshes) {
|
5530
5676
|
for (auto &primitive : mesh.primitives) {
|
5531
5677
|
if (primitive.indices >
|
@@ -5553,14 +5699,25 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
|
|
5553
5699
|
// we could optionally check if acessors' bufferView type is Scalar, as
|
5554
5700
|
// it should be
|
5555
5701
|
}
|
5556
|
-
|
5557
|
-
|
5558
|
-
|
5559
|
-
|
5560
|
-
|
5561
|
-
|
5562
|
-
|
5563
|
-
|
5702
|
+
|
5703
|
+
for (auto &attribute : primitive.attributes) {
|
5704
|
+
model
|
5705
|
+
->bufferViews[size_t(
|
5706
|
+
model->accessors[size_t(attribute.second)].bufferView)]
|
5707
|
+
.target = TINYGLTF_TARGET_ARRAY_BUFFER;
|
5708
|
+
}
|
5709
|
+
|
5710
|
+
for (auto &target : primitive.targets) {
|
5711
|
+
for (auto &attribute : target) {
|
5712
|
+
auto bufferView =
|
5713
|
+
model->accessors[size_t(attribute.second)].bufferView;
|
5714
|
+
// bufferView could be null(-1) for sparse morph target
|
5715
|
+
if (bufferView >= 0) {
|
5716
|
+
model->bufferViews[size_t(bufferView)].target =
|
5717
|
+
TINYGLTF_TARGET_ARRAY_BUFFER;
|
5718
|
+
}
|
5719
|
+
}
|
5720
|
+
}
|
5564
5721
|
}
|
5565
5722
|
}
|
5566
5723
|
|
@@ -6143,6 +6300,13 @@ static void SerializeNumberProperty(const std::string &key, T number,
|
|
6143
6300
|
JsonAddMember(obj, key.c_str(), json(number));
|
6144
6301
|
}
|
6145
6302
|
|
6303
|
+
#ifdef TINYGLTF_USE_RAPIDJSON
|
6304
|
+
template <>
|
6305
|
+
void SerializeNumberProperty(const std::string &key, size_t number, json &obj) {
|
6306
|
+
JsonAddMember(obj, key.c_str(), json(static_cast<uint64_t>(number)));
|
6307
|
+
}
|
6308
|
+
#endif
|
6309
|
+
|
6146
6310
|
template <typename T>
|
6147
6311
|
static void SerializeNumberArrayProperty(const std::string &key,
|
6148
6312
|
const std::vector<T> &value,
|
@@ -6278,17 +6442,25 @@ static void SerializeValue(const std::string &key, const Value &value,
|
|
6278
6442
|
static void SerializeGltfBufferData(const std::vector<unsigned char> &data,
|
6279
6443
|
json &o) {
|
6280
6444
|
std::string header = "data:application/octet-stream;base64,";
|
6281
|
-
|
6282
|
-
|
6283
|
-
|
6445
|
+
if (data.size() > 0) {
|
6446
|
+
std::string encodedData =
|
6447
|
+
base64_encode(&data[0], static_cast<unsigned int>(data.size()));
|
6448
|
+
SerializeStringProperty("uri", header + encodedData, o);
|
6449
|
+
} else {
|
6450
|
+
// Issue #229
|
6451
|
+
// size 0 is allowd. Just emit mime header.
|
6452
|
+
SerializeStringProperty("uri", header, o);
|
6453
|
+
}
|
6284
6454
|
}
|
6285
6455
|
|
6286
6456
|
static bool SerializeGltfBufferData(const std::vector<unsigned char> &data,
|
6287
6457
|
const std::string &binFilename) {
|
6288
6458
|
#ifdef _WIN32
|
6289
|
-
#if defined(__GLIBCXX__)
|
6290
|
-
|
6291
|
-
|
6459
|
+
#if defined(__GLIBCXX__) // mingw
|
6460
|
+
int file_descriptor = _wopen(UTF8ToWchar(binFilename).c_str(),
|
6461
|
+
_O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY);
|
6462
|
+
__gnu_cxx::stdio_filebuf<char> wfile_buf(
|
6463
|
+
file_descriptor, std::ios_base::out | std::ios_base::binary);
|
6292
6464
|
std::ostream output(&wfile_buf);
|
6293
6465
|
if (!wfile_buf.is_open()) return false;
|
6294
6466
|
#elif defined(_MSC_VER)
|
@@ -6302,8 +6474,14 @@ static bool SerializeGltfBufferData(const std::vector<unsigned char> &data,
|
|
6302
6474
|
std::ofstream output(binFilename.c_str(), std::ofstream::binary);
|
6303
6475
|
if (!output.is_open()) return false;
|
6304
6476
|
#endif
|
6305
|
-
|
6306
|
-
|
6477
|
+
if (data.size() > 0) {
|
6478
|
+
output.write(reinterpret_cast<const char *>(&data[0]),
|
6479
|
+
std::streamsize(data.size()));
|
6480
|
+
} else {
|
6481
|
+
// Issue #229
|
6482
|
+
// size 0 will be still valid buffer data.
|
6483
|
+
// write empty file.
|
6484
|
+
}
|
6307
6485
|
return true;
|
6308
6486
|
}
|
6309
6487
|
|
@@ -6365,9 +6543,10 @@ static void SerializeExtensionMap(const ExtensionMap &extensions, json &o) {
|
|
6365
6543
|
}
|
6366
6544
|
|
6367
6545
|
static void SerializeGltfAccessor(Accessor &accessor, json &o) {
|
6368
|
-
|
6546
|
+
if (accessor.bufferView >= 0)
|
6547
|
+
SerializeNumberProperty<int>("bufferView", accessor.bufferView, o);
|
6369
6548
|
|
6370
|
-
if (accessor.byteOffset != 0
|
6549
|
+
if (accessor.byteOffset != 0)
|
6371
6550
|
SerializeNumberProperty<int>("byteOffset", int(accessor.byteOffset), o);
|
6372
6551
|
|
6373
6552
|
SerializeNumberProperty<int>("componentType", accessor.componentType, o);
|
@@ -6416,6 +6595,8 @@ static void SerializeGltfAnimationChannel(AnimationChannel &channel, json &o) {
|
|
6416
6595
|
SerializeNumberProperty("node", channel.target_node, target);
|
6417
6596
|
SerializeStringProperty("path", channel.target_path, target);
|
6418
6597
|
|
6598
|
+
SerializeExtensionMap(channel.target_extensions, target);
|
6599
|
+
|
6419
6600
|
JsonAddMember(o, "target", std::move(target));
|
6420
6601
|
}
|
6421
6602
|
|
@@ -6455,6 +6636,7 @@ static void SerializeGltfAnimation(Animation &animation, json &o) {
|
|
6455
6636
|
|
6456
6637
|
{
|
6457
6638
|
json samplers;
|
6639
|
+
JsonReserveArray(samplers, animation.samplers.size());
|
6458
6640
|
for (unsigned int i = 0; i < animation.samplers.size(); ++i) {
|
6459
6641
|
json sampler;
|
6460
6642
|
AnimationSampler gltfSampler = animation.samplers[i];
|
@@ -6491,10 +6673,10 @@ static void SerializeGltfAsset(Asset &asset, json &o) {
|
|
6491
6673
|
SerializeExtensionMap(asset.extensions, o);
|
6492
6674
|
}
|
6493
6675
|
|
6494
|
-
|
6495
|
-
|
6676
|
+
static void SerializeGltfBufferBin(Buffer &buffer, json &o,
|
6677
|
+
std::vector<unsigned char> &binBuffer) {
|
6496
6678
|
SerializeNumberProperty("byteLength", buffer.data.size(), o);
|
6497
|
-
binBuffer=buffer.data;
|
6679
|
+
binBuffer = buffer.data;
|
6498
6680
|
|
6499
6681
|
if (buffer.name.size()) SerializeStringProperty("name", buffer.name, o);
|
6500
6682
|
|
@@ -6561,6 +6743,7 @@ static void SerializeGltfImage(Image &image, json &o) {
|
|
6561
6743
|
SerializeStringProperty("mimeType", image.mimeType, o);
|
6562
6744
|
SerializeNumberProperty<int>("bufferView", image.bufferView, o);
|
6563
6745
|
} else {
|
6746
|
+
// TODO(syoyo): dlib::urilencode?
|
6564
6747
|
SerializeStringProperty("uri", image.uri, o);
|
6565
6748
|
}
|
6566
6749
|
|
@@ -6677,8 +6860,8 @@ static void SerializeGltfMaterial(Material &material, json &o) {
|
|
6677
6860
|
SerializeStringProperty("alphaMode", material.alphaMode, o);
|
6678
6861
|
}
|
6679
6862
|
|
6680
|
-
if(material.doubleSided != false)
|
6681
|
-
|
6863
|
+
if (material.doubleSided != false)
|
6864
|
+
JsonAddMember(o, "doubleSided", json(material.doubleSided));
|
6682
6865
|
|
6683
6866
|
if (material.normalTexture.index > -1) {
|
6684
6867
|
json texinfo;
|
@@ -6782,7 +6965,7 @@ static void SerializeGltfMesh(Mesh &mesh, json &o) {
|
|
6782
6965
|
JsonAddMember(primitive, "targets", std::move(targets));
|
6783
6966
|
}
|
6784
6967
|
|
6785
|
-
SerializeExtensionMap(gltfPrimitive.extensions,
|
6968
|
+
SerializeExtensionMap(gltfPrimitive.extensions, primitive);
|
6786
6969
|
|
6787
6970
|
if (gltfPrimitive.extras.Type() != NULL_TYPE) {
|
6788
6971
|
SerializeValue("extras", gltfPrimitive.extras, primitive);
|
@@ -6819,7 +7002,9 @@ static void SerializeSpotLight(SpotLight &spot, json &o) {
|
|
6819
7002
|
static void SerializeGltfLight(Light &light, json &o) {
|
6820
7003
|
if (!light.name.empty()) SerializeStringProperty("name", light.name, o);
|
6821
7004
|
SerializeNumberProperty("intensity", light.intensity, o);
|
6822
|
-
|
7005
|
+
if (light.range > 0.0) {
|
7006
|
+
SerializeNumberProperty("range", light.range, o);
|
7007
|
+
}
|
6823
7008
|
SerializeNumberArrayProperty("color", light.color, o);
|
6824
7009
|
SerializeStringProperty("type", light.type, o);
|
6825
7010
|
if (light.type == "spot") {
|
@@ -6933,6 +7118,11 @@ static void SerializeGltfCamera(const Camera &camera, json &o) {
|
|
6933
7118
|
} else {
|
6934
7119
|
// ???
|
6935
7120
|
}
|
7121
|
+
|
7122
|
+
if (camera.extras.Type() != NULL_TYPE) {
|
7123
|
+
SerializeValue("extras", camera.extras, o);
|
7124
|
+
}
|
7125
|
+
SerializeExtensionMap(camera.extensions, o);
|
6936
7126
|
}
|
6937
7127
|
|
6938
7128
|
static void SerializeGltfScene(Scene &scene, json &o) {
|
@@ -6979,14 +7169,16 @@ static void SerializeGltfTexture(Texture &texture, json &o) {
|
|
6979
7169
|
///
|
6980
7170
|
static void SerializeGltfModel(Model *model, json &o) {
|
6981
7171
|
// ACCESSORS
|
6982
|
-
|
6983
|
-
|
6984
|
-
|
6985
|
-
|
6986
|
-
|
6987
|
-
|
7172
|
+
if (model->accessors.size()) {
|
7173
|
+
json accessors;
|
7174
|
+
JsonReserveArray(accessors, model->accessors.size());
|
7175
|
+
for (unsigned int i = 0; i < model->accessors.size(); ++i) {
|
7176
|
+
json accessor;
|
7177
|
+
SerializeGltfAccessor(model->accessors[i], accessor);
|
7178
|
+
JsonPushBack(accessors, std::move(accessor));
|
7179
|
+
}
|
7180
|
+
JsonAddMember(o, "accessors", std::move(accessors));
|
6988
7181
|
}
|
6989
|
-
JsonAddMember(o, "accessors", std::move(accessors));
|
6990
7182
|
|
6991
7183
|
// ANIMATIONS
|
6992
7184
|
if (model->animations.size()) {
|
@@ -7009,18 +7201,15 @@ static void SerializeGltfModel(Model *model, json &o) {
|
|
7009
7201
|
JsonAddMember(o, "asset", std::move(asset));
|
7010
7202
|
|
7011
7203
|
// BUFFERVIEWS
|
7012
|
-
|
7013
|
-
|
7014
|
-
|
7015
|
-
|
7016
|
-
|
7017
|
-
|
7018
|
-
|
7019
|
-
|
7020
|
-
|
7021
|
-
// Extensions used
|
7022
|
-
if (model->extensionsUsed.size()) {
|
7023
|
-
SerializeStringArrayProperty("extensionsUsed", model->extensionsUsed, o);
|
7204
|
+
if (model->bufferViews.size()) {
|
7205
|
+
json bufferViews;
|
7206
|
+
JsonReserveArray(bufferViews, model->bufferViews.size());
|
7207
|
+
for (unsigned int i = 0; i < model->bufferViews.size(); ++i) {
|
7208
|
+
json bufferView;
|
7209
|
+
SerializeGltfBufferView(model->bufferViews[i], bufferView);
|
7210
|
+
JsonPushBack(bufferViews, std::move(bufferView));
|
7211
|
+
}
|
7212
|
+
JsonAddMember(o, "bufferViews", std::move(bufferViews));
|
7024
7213
|
}
|
7025
7214
|
|
7026
7215
|
// Extensions required
|
@@ -7133,7 +7322,9 @@ static void SerializeGltfModel(Model *model, json &o) {
|
|
7133
7322
|
// EXTENSIONS
|
7134
7323
|
SerializeExtensionMap(model->extensions, o);
|
7135
7324
|
|
7136
|
-
|
7325
|
+
auto extensionsUsed = model->extensionsUsed;
|
7326
|
+
|
7327
|
+
// LIGHTS as KHR_lights_punctual
|
7137
7328
|
if (model->lights.size()) {
|
7138
7329
|
json lights;
|
7139
7330
|
JsonReserveArray(lights, model->lights.size());
|
@@ -7148,7 +7339,7 @@ static void SerializeGltfModel(Model *model, json &o) {
|
|
7148
7339
|
|
7149
7340
|
{
|
7150
7341
|
json_const_iterator it;
|
7151
|
-
if (
|
7342
|
+
if (FindMember(o, "extensions", it)) {
|
7152
7343
|
JsonAssign(ext_j, GetValue(it));
|
7153
7344
|
}
|
7154
7345
|
}
|
@@ -7156,6 +7347,24 @@ static void SerializeGltfModel(Model *model, json &o) {
|
|
7156
7347
|
JsonAddMember(ext_j, "KHR_lights_punctual", std::move(khr_lights_cmn));
|
7157
7348
|
|
7158
7349
|
JsonAddMember(o, "extensions", std::move(ext_j));
|
7350
|
+
|
7351
|
+
// Also add "KHR_lights_punctual" to `extensionsUsed`
|
7352
|
+
{
|
7353
|
+
auto has_khr_lights_punctual =
|
7354
|
+
std::find_if(extensionsUsed.begin(), extensionsUsed.end(),
|
7355
|
+
[](const std::string &s) {
|
7356
|
+
return (s.compare("KHR_lights_punctual") == 0);
|
7357
|
+
});
|
7358
|
+
|
7359
|
+
if (has_khr_lights_punctual == extensionsUsed.end()) {
|
7360
|
+
extensionsUsed.push_back("KHR_lights_punctual");
|
7361
|
+
}
|
7362
|
+
}
|
7363
|
+
}
|
7364
|
+
|
7365
|
+
// Extensions used
|
7366
|
+
if (model->extensionsUsed.size()) {
|
7367
|
+
SerializeStringArrayProperty("extensionsUsed", extensionsUsed, o);
|
7159
7368
|
}
|
7160
7369
|
|
7161
7370
|
// EXTRAS
|
@@ -7175,8 +7384,10 @@ static bool WriteGltfFile(const std::string &output,
|
|
7175
7384
|
#if defined(_MSC_VER)
|
7176
7385
|
std::ofstream gltfFile(UTF8ToWchar(output).c_str());
|
7177
7386
|
#elif defined(__GLIBCXX__)
|
7178
|
-
int file_descriptor = _wopen(UTF8ToWchar(output).c_str(),
|
7179
|
-
|
7387
|
+
int file_descriptor = _wopen(UTF8ToWchar(output).c_str(),
|
7388
|
+
_O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY);
|
7389
|
+
__gnu_cxx::stdio_filebuf<char> wfile_buf(
|
7390
|
+
file_descriptor, std::ios_base::out | std::ios_base::binary);
|
7180
7391
|
std::ostream gltfFile(&wfile_buf);
|
7181
7392
|
if (!wfile_buf.is_open()) return false;
|
7182
7393
|
#else
|
@@ -7197,32 +7408,31 @@ static void WriteBinaryGltfStream(std::ostream &stream,
|
|
7197
7408
|
const int version = 2;
|
7198
7409
|
|
7199
7410
|
// https://stackoverflow.com/questions/3407012/c-rounding-up-to-the-nearest-multiple-of-a-number
|
7200
|
-
auto roundUp = [](uint32_t numToRound, uint32_t multiple)
|
7201
|
-
|
7202
|
-
if (multiple == 0)
|
7203
|
-
return numToRound;
|
7411
|
+
auto roundUp = [](uint32_t numToRound, uint32_t multiple) {
|
7412
|
+
if (multiple == 0) return numToRound;
|
7204
7413
|
|
7205
|
-
|
7206
|
-
|
7207
|
-
return numToRound;
|
7414
|
+
uint32_t remainder = numToRound % multiple;
|
7415
|
+
if (remainder == 0) return numToRound;
|
7208
7416
|
|
7209
|
-
|
7417
|
+
return numToRound + multiple - remainder;
|
7210
7418
|
};
|
7211
7419
|
|
7212
|
-
const uint32_t padding_size =
|
7420
|
+
const uint32_t padding_size =
|
7421
|
+
roundUp(uint32_t(content.size()), 4) - uint32_t(content.size());
|
7213
7422
|
|
7214
7423
|
// 12 bytes for header, JSON content length, 8 bytes for JSON chunk info.
|
7215
7424
|
// Chunk data must be located at 4-byte boundary.
|
7216
|
-
const
|
7217
|
-
|
7425
|
+
const uint32_t length =
|
7426
|
+
12 + 8 + roundUp(uint32_t(content.size()), 4) +
|
7427
|
+
(binBuffer.size() ? (8 + roundUp(uint32_t(binBuffer.size()), 4)) : 0);
|
7218
7428
|
|
7219
7429
|
stream.write(header.c_str(), std::streamsize(header.size()));
|
7220
7430
|
stream.write(reinterpret_cast<const char *>(&version), sizeof(version));
|
7221
7431
|
stream.write(reinterpret_cast<const char *>(&length), sizeof(length));
|
7222
7432
|
|
7223
7433
|
// JSON chunk info, then JSON data
|
7224
|
-
const
|
7225
|
-
const
|
7434
|
+
const uint32_t model_length = uint32_t(content.size()) + padding_size;
|
7435
|
+
const uint32_t model_format = 0x4E4F534A;
|
7226
7436
|
stream.write(reinterpret_cast<const char *>(&model_length),
|
7227
7437
|
sizeof(model_length));
|
7228
7438
|
stream.write(reinterpret_cast<const char *>(&model_format),
|
@@ -7234,20 +7444,24 @@ static void WriteBinaryGltfStream(std::ostream &stream,
|
|
7234
7444
|
const std::string padding = std::string(size_t(padding_size), ' ');
|
7235
7445
|
stream.write(padding.c_str(), std::streamsize(padding.size()));
|
7236
7446
|
}
|
7237
|
-
if (binBuffer.size() > 0){
|
7238
|
-
const uint32_t bin_padding_size =
|
7447
|
+
if (binBuffer.size() > 0) {
|
7448
|
+
const uint32_t bin_padding_size =
|
7449
|
+
roundUp(uint32_t(binBuffer.size()), 4) - uint32_t(binBuffer.size());
|
7239
7450
|
// BIN chunk info, then BIN data
|
7240
|
-
const
|
7241
|
-
const
|
7451
|
+
const uint32_t bin_length = uint32_t(binBuffer.size()) + bin_padding_size;
|
7452
|
+
const uint32_t bin_format = 0x004e4942;
|
7242
7453
|
stream.write(reinterpret_cast<const char *>(&bin_length),
|
7243
|
-
|
7454
|
+
sizeof(bin_length));
|
7244
7455
|
stream.write(reinterpret_cast<const char *>(&bin_format),
|
7245
|
-
|
7246
|
-
stream.write(
|
7456
|
+
sizeof(bin_format));
|
7457
|
+
stream.write(reinterpret_cast<const char *>(binBuffer.data()),
|
7458
|
+
std::streamsize(binBuffer.size()));
|
7247
7459
|
// Chunksize must be multiplies of 4, so pad with zeroes
|
7248
7460
|
if (bin_padding_size > 0) {
|
7249
|
-
const std::vector<unsigned char> padding =
|
7250
|
-
|
7461
|
+
const std::vector<unsigned char> padding =
|
7462
|
+
std::vector<unsigned char>(size_t(bin_padding_size), 0);
|
7463
|
+
stream.write(reinterpret_cast<const char *>(padding.data()),
|
7464
|
+
std::streamsize(padding.size()));
|
7251
7465
|
}
|
7252
7466
|
}
|
7253
7467
|
}
|
@@ -7259,8 +7473,10 @@ static void WriteBinaryGltfFile(const std::string &output,
|
|
7259
7473
|
#if defined(_MSC_VER)
|
7260
7474
|
std::ofstream gltfFile(UTF8ToWchar(output).c_str(), std::ios::binary);
|
7261
7475
|
#elif defined(__GLIBCXX__)
|
7262
|
-
int file_descriptor = _wopen(UTF8ToWchar(output).c_str(),
|
7263
|
-
|
7476
|
+
int file_descriptor = _wopen(UTF8ToWchar(output).c_str(),
|
7477
|
+
_O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY);
|
7478
|
+
__gnu_cxx::stdio_filebuf<char> wfile_buf(
|
7479
|
+
file_descriptor, std::ios_base::out | std::ios_base::binary);
|
7264
7480
|
std::ostream gltfFile(&wfile_buf);
|
7265
7481
|
#else
|
7266
7482
|
std::ofstream gltfFile(output.c_str(), std::ios::binary);
|
@@ -7268,7 +7484,7 @@ static void WriteBinaryGltfFile(const std::string &output,
|
|
7268
7484
|
#else
|
7269
7485
|
std::ofstream gltfFile(output.c_str(), std::ios::binary);
|
7270
7486
|
#endif
|
7271
|
-
WriteBinaryGltfStream(gltfFile, content,binBuffer);
|
7487
|
+
WriteBinaryGltfStream(gltfFile, content, binBuffer);
|
7272
7488
|
}
|
7273
7489
|
|
7274
7490
|
bool TinyGLTF::WriteGltfSceneToStream(Model *model, std::ostream &stream,
|
@@ -7280,20 +7496,21 @@ bool TinyGLTF::WriteGltfSceneToStream(Model *model, std::ostream &stream,
|
|
7280
7496
|
SerializeGltfModel(model, output);
|
7281
7497
|
|
7282
7498
|
// BUFFERS
|
7283
|
-
std::vector<std::string> usedUris;
|
7284
7499
|
std::vector<unsigned char> binBuffer;
|
7285
|
-
|
7286
|
-
|
7287
|
-
|
7288
|
-
|
7289
|
-
|
7290
|
-
|
7291
|
-
|
7292
|
-
|
7500
|
+
if (model->buffers.size()) {
|
7501
|
+
json buffers;
|
7502
|
+
JsonReserveArray(buffers, model->buffers.size());
|
7503
|
+
for (unsigned int i = 0; i < model->buffers.size(); ++i) {
|
7504
|
+
json buffer;
|
7505
|
+
if (writeBinary && i == 0 && model->buffers[i].uri.empty()) {
|
7506
|
+
SerializeGltfBufferBin(model->buffers[i], buffer, binBuffer);
|
7507
|
+
} else {
|
7508
|
+
SerializeGltfBuffer(model->buffers[i], buffer);
|
7509
|
+
}
|
7510
|
+
JsonPushBack(buffers, std::move(buffer));
|
7293
7511
|
}
|
7294
|
-
|
7512
|
+
JsonAddMember(output, "buffers", std::move(buffers));
|
7295
7513
|
}
|
7296
|
-
JsonAddMember(output, "buffers", std::move(buffers));
|
7297
7514
|
|
7298
7515
|
// IMAGES
|
7299
7516
|
if (model->images.size()) {
|
@@ -7303,9 +7520,9 @@ bool TinyGLTF::WriteGltfSceneToStream(Model *model, std::ostream &stream,
|
|
7303
7520
|
json image;
|
7304
7521
|
|
7305
7522
|
std::string dummystring = "";
|
7306
|
-
// UpdateImageObject need baseDir but only uses it if
|
7307
|
-
//
|
7308
|
-
//
|
7523
|
+
// UpdateImageObject need baseDir but only uses it if embeddedImages is
|
7524
|
+
// enabled, since we won't write separate images when writing to a stream
|
7525
|
+
// we
|
7309
7526
|
UpdateImageObject(model->images[i], dummystring, int(i), false,
|
7310
7527
|
&this->WriteImageData, this->write_image_user_data_);
|
7311
7528
|
SerializeGltfImage(model->images[i], image);
|
@@ -7315,7 +7532,7 @@ bool TinyGLTF::WriteGltfSceneToStream(Model *model, std::ostream &stream,
|
|
7315
7532
|
}
|
7316
7533
|
|
7317
7534
|
if (writeBinary) {
|
7318
|
-
WriteBinaryGltfStream(stream, JsonToString(output),binBuffer);
|
7535
|
+
WriteBinaryGltfStream(stream, JsonToString(output), binBuffer);
|
7319
7536
|
} else {
|
7320
7537
|
WriteGltfStream(stream, JsonToString(output, prettyPrint ? 2 : -1));
|
7321
7538
|
}
|
@@ -7347,44 +7564,47 @@ bool TinyGLTF::WriteGltfSceneToFile(Model *model, const std::string &filename,
|
|
7347
7564
|
// BUFFERS
|
7348
7565
|
std::vector<std::string> usedUris;
|
7349
7566
|
std::vector<unsigned char> binBuffer;
|
7350
|
-
|
7351
|
-
|
7352
|
-
|
7353
|
-
|
7354
|
-
|
7355
|
-
|
7356
|
-
|
7357
|
-
|
7358
|
-
|
7359
|
-
std::string binSavePath;
|
7360
|
-
std::string binUri;
|
7361
|
-
if (!model->buffers[i].uri.empty() && !IsDataURI(model->buffers[i].uri)) {
|
7362
|
-
binUri = model->buffers[i].uri;
|
7567
|
+
if (model->buffers.size()) {
|
7568
|
+
json buffers;
|
7569
|
+
JsonReserveArray(buffers, model->buffers.size());
|
7570
|
+
for (unsigned int i = 0; i < model->buffers.size(); ++i) {
|
7571
|
+
json buffer;
|
7572
|
+
if (writeBinary && i == 0 && model->buffers[i].uri.empty()) {
|
7573
|
+
SerializeGltfBufferBin(model->buffers[i], buffer, binBuffer);
|
7574
|
+
} else if (embedBuffers) {
|
7575
|
+
SerializeGltfBuffer(model->buffers[i], buffer);
|
7363
7576
|
} else {
|
7364
|
-
|
7365
|
-
|
7366
|
-
|
7367
|
-
|
7368
|
-
|
7369
|
-
|
7370
|
-
|
7371
|
-
|
7372
|
-
|
7373
|
-
|
7374
|
-
|
7577
|
+
std::string binSavePath;
|
7578
|
+
std::string binUri;
|
7579
|
+
if (!model->buffers[i].uri.empty() &&
|
7580
|
+
!IsDataURI(model->buffers[i].uri)) {
|
7581
|
+
binUri = model->buffers[i].uri;
|
7582
|
+
} else {
|
7583
|
+
binUri = defaultBinFilename + defaultBinFileExt;
|
7584
|
+
bool inUse = true;
|
7585
|
+
int numUsed = 0;
|
7586
|
+
while (inUse) {
|
7587
|
+
inUse = false;
|
7588
|
+
for (const std::string &usedName : usedUris) {
|
7589
|
+
if (binUri.compare(usedName) != 0) continue;
|
7590
|
+
inUse = true;
|
7591
|
+
binUri = defaultBinFilename + std::to_string(numUsed++) +
|
7592
|
+
defaultBinFileExt;
|
7593
|
+
break;
|
7594
|
+
}
|
7375
7595
|
}
|
7376
7596
|
}
|
7597
|
+
usedUris.push_back(binUri);
|
7598
|
+
binSavePath = JoinPath(baseDir, binUri);
|
7599
|
+
if (!SerializeGltfBuffer(model->buffers[i], buffer, binSavePath,
|
7600
|
+
binUri)) {
|
7601
|
+
return false;
|
7602
|
+
}
|
7377
7603
|
}
|
7378
|
-
|
7379
|
-
binSavePath = JoinPath(baseDir, binUri);
|
7380
|
-
if (!SerializeGltfBuffer(model->buffers[i], buffer, binSavePath,
|
7381
|
-
binUri)) {
|
7382
|
-
return false;
|
7383
|
-
}
|
7604
|
+
JsonPushBack(buffers, std::move(buffer));
|
7384
7605
|
}
|
7385
|
-
|
7606
|
+
JsonAddMember(output, "buffers", std::move(buffers));
|
7386
7607
|
}
|
7387
|
-
JsonAddMember(output, "buffers", std::move(buffers));
|
7388
7608
|
|
7389
7609
|
// IMAGES
|
7390
7610
|
if (model->images.size()) {
|
@@ -7402,7 +7622,7 @@ bool TinyGLTF::WriteGltfSceneToFile(Model *model, const std::string &filename,
|
|
7402
7622
|
}
|
7403
7623
|
|
7404
7624
|
if (writeBinary) {
|
7405
|
-
WriteBinaryGltfFile(filename, JsonToString(output),binBuffer);
|
7625
|
+
WriteBinaryGltfFile(filename, JsonToString(output), binBuffer);
|
7406
7626
|
} else {
|
7407
7627
|
WriteGltfFile(filename, JsonToString(output, (prettyPrint ? 2 : -1)));
|
7408
7628
|
}
|