tiny_gltf 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
}
|