tiny_gltf 1.0.2 → 2.5.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +9 -7
- data/ext/tiny_gltf/json.hpp +17300 -10953
- data/ext/tiny_gltf/rb_tiny_gltf_mesh.cpp +1 -1
- data/ext/tiny_gltf/rb_tiny_gltf_sampler.cpp +3 -1
- data/ext/tiny_gltf/tiny_gltf.h +229 -120
- data/lib/tiny_gltf/version.rb +1 -1
- metadata +3 -3
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 - Present 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,9 @@
|
|
26
26
|
// THE SOFTWARE.
|
27
27
|
|
28
28
|
// Version:
|
29
|
+
// - v2.5.0 Add SetPreserveImageChannels() option to load image data as is.
|
30
|
+
// - v2.4.3 Fix null object output when when material has all default
|
31
|
+
// parameters.
|
29
32
|
// - v2.4.2 Decode percent-encoded URI.
|
30
33
|
// - v2.4.1 Fix some glTF object class does not have `extensions` and/or
|
31
34
|
// `extras` property.
|
@@ -105,7 +108,7 @@ namespace tinygltf {
|
|
105
108
|
#define TINYGLTF_COMPONENT_TYPE_INT (5124)
|
106
109
|
#define TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT (5125)
|
107
110
|
#define TINYGLTF_COMPONENT_TYPE_FLOAT (5126)
|
108
|
-
#define TINYGLTF_COMPONENT_TYPE_DOUBLE (5130)
|
111
|
+
#define TINYGLTF_COMPONENT_TYPE_DOUBLE (5130) // OpenGL double type. Note that some of glTF 2.0 validator does not support double type even the schema seems allow any value of integer: https://github.com/KhronosGroup/glTF/blob/b9884a2fd45130b4d673dd6c8a706ee21ee5c5f7/specification/2.0/schema/accessor.schema.json#L22
|
109
112
|
|
110
113
|
#define TINYGLTF_TEXTURE_FILTER_NEAREST (9728)
|
111
114
|
#define TINYGLTF_TEXTURE_FILTER_LINEAR (9729)
|
@@ -188,14 +191,14 @@ AAssetManager *asset_manager = nullptr;
|
|
188
191
|
#endif
|
189
192
|
|
190
193
|
typedef enum {
|
191
|
-
NULL_TYPE
|
192
|
-
REAL_TYPE
|
193
|
-
INT_TYPE
|
194
|
-
BOOL_TYPE
|
195
|
-
STRING_TYPE
|
196
|
-
ARRAY_TYPE
|
197
|
-
BINARY_TYPE
|
198
|
-
OBJECT_TYPE
|
194
|
+
NULL_TYPE,
|
195
|
+
REAL_TYPE,
|
196
|
+
INT_TYPE,
|
197
|
+
BOOL_TYPE,
|
198
|
+
STRING_TYPE,
|
199
|
+
ARRAY_TYPE,
|
200
|
+
BINARY_TYPE,
|
201
|
+
OBJECT_TYPE
|
199
202
|
} Type;
|
200
203
|
|
201
204
|
static inline int32_t GetComponentSizeInBytes(uint32_t componentType) {
|
@@ -250,7 +253,6 @@ bool DecodeDataURI(std::vector<unsigned char> *out, std::string &mime_type,
|
|
250
253
|
#ifdef __clang__
|
251
254
|
#pragma clang diagnostic push
|
252
255
|
// Suppress warning for : static Value null_value
|
253
|
-
// https://stackoverflow.com/questions/15708411/how-to-deal-with-global-constructor-warning-in-clang
|
254
256
|
#pragma clang diagnostic ignored "-Wexit-time-destructors"
|
255
257
|
#pragma clang diagnostic ignored "-Wpadded"
|
256
258
|
#endif
|
@@ -295,7 +297,7 @@ class Value {
|
|
295
297
|
|
296
298
|
DEFAULT_METHODS(Value)
|
297
299
|
|
298
|
-
char Type() const { return static_cast<
|
300
|
+
char Type() const { return static_cast<char>(type_); }
|
299
301
|
|
300
302
|
bool IsBool() const { return (type_ == BOOL_TYPE); }
|
301
303
|
|
@@ -601,7 +603,7 @@ struct Sampler {
|
|
601
603
|
// `magFilter`. Set -1 in TinyGLTF(issue #186)
|
602
604
|
int minFilter =
|
603
605
|
-1; // optional. -1 = no filter defined. ["NEAREST", "LINEAR",
|
604
|
-
// "
|
606
|
+
// "NEAREST_MIPMAP_NEAREST", "LINEAR_MIPMAP_NEAREST",
|
605
607
|
// "NEAREST_MIPMAP_LINEAR", "LINEAR_MIPMAP_LINEAR"]
|
606
608
|
int magFilter =
|
607
609
|
-1; // optional. -1 = no filter defined. ["NEAREST", "LINEAR"]
|
@@ -611,7 +613,7 @@ struct Sampler {
|
|
611
613
|
int wrapT =
|
612
614
|
TINYGLTF_TEXTURE_WRAP_REPEAT; // ["CLAMP_TO_EDGE", "MIRRORED_REPEAT",
|
613
615
|
// "REPEAT"], default "REPEAT"
|
614
|
-
int wrapR = TINYGLTF_TEXTURE_WRAP_REPEAT; // TinyGLTF extension
|
616
|
+
//int wrapR = TINYGLTF_TEXTURE_WRAP_REPEAT; // TinyGLTF extension. currently not used.
|
615
617
|
|
616
618
|
Value extras;
|
617
619
|
ExtensionMap extensions;
|
@@ -624,8 +626,7 @@ struct Sampler {
|
|
624
626
|
: minFilter(-1),
|
625
627
|
magFilter(-1),
|
626
628
|
wrapS(TINYGLTF_TEXTURE_WRAP_REPEAT),
|
627
|
-
wrapT(TINYGLTF_TEXTURE_WRAP_REPEAT)
|
628
|
-
wrapR(TINYGLTF_TEXTURE_WRAP_REPEAT) {}
|
629
|
+
wrapT(TINYGLTF_TEXTURE_WRAP_REPEAT) {}
|
629
630
|
DEFAULT_METHODS(Sampler)
|
630
631
|
bool operator==(const Sampler &) const;
|
631
632
|
};
|
@@ -848,8 +849,10 @@ struct Accessor {
|
|
848
849
|
std::string extras_json_string;
|
849
850
|
std::string extensions_json_string;
|
850
851
|
|
851
|
-
std::vector<double>
|
852
|
-
|
852
|
+
std::vector<double>
|
853
|
+
minValues; // optional. integer value is promoted to double
|
854
|
+
std::vector<double>
|
855
|
+
maxValues; // optional. integer value is promoted to double
|
853
856
|
|
854
857
|
struct {
|
855
858
|
int count;
|
@@ -1067,7 +1070,7 @@ struct Buffer {
|
|
1067
1070
|
};
|
1068
1071
|
|
1069
1072
|
struct Asset {
|
1070
|
-
std::string version; // required
|
1073
|
+
std::string version = "2.0"; // required
|
1071
1074
|
std::string generator;
|
1072
1075
|
std::string minVersion;
|
1073
1076
|
std::string copyright;
|
@@ -1189,7 +1192,8 @@ enum SectionCheck {
|
|
1189
1192
|
///
|
1190
1193
|
typedef bool (*LoadImageDataFunction)(Image *, const int, std::string *,
|
1191
1194
|
std::string *, int, int,
|
1192
|
-
const unsigned char *, int,
|
1195
|
+
const unsigned char *, int,
|
1196
|
+
void *user_pointer);
|
1193
1197
|
|
1194
1198
|
///
|
1195
1199
|
/// WriteImageDataFunction type. Signature for custom image writing callbacks.
|
@@ -1254,7 +1258,7 @@ bool FileExists(const std::string &abs_filename, void *);
|
|
1254
1258
|
|
1255
1259
|
///
|
1256
1260
|
/// Expand file path(e.g. `~` to home directory on posix, `%APPDATA%` to
|
1257
|
-
/// `C
|
1261
|
+
/// `C:\\Users\\tinygltf\\AppData`)
|
1258
1262
|
///
|
1259
1263
|
/// @param[in] filepath File path string. Assume UTF-8
|
1260
1264
|
/// @param[in] userdata User data. Set to `nullptr` if you don't need it.
|
@@ -1345,6 +1349,11 @@ class TinyGLTF {
|
|
1345
1349
|
///
|
1346
1350
|
void SetImageLoader(LoadImageDataFunction LoadImageData, void *user_data);
|
1347
1351
|
|
1352
|
+
///
|
1353
|
+
/// Unset(remove) callback of loading image data
|
1354
|
+
///
|
1355
|
+
void RemoveImageLoader();
|
1356
|
+
|
1348
1357
|
///
|
1349
1358
|
/// Set callback to use for writing image data
|
1350
1359
|
///
|
@@ -1383,6 +1392,16 @@ class TinyGLTF {
|
|
1383
1392
|
return store_original_json_for_extras_and_extensions_;
|
1384
1393
|
}
|
1385
1394
|
|
1395
|
+
///
|
1396
|
+
/// Specify whether preserve image channales when loading images or not.
|
1397
|
+
/// (Not effective when the user suppy their own LoadImageData callbacks)
|
1398
|
+
///
|
1399
|
+
void SetPreserveImageChannels(bool onoff) {
|
1400
|
+
preserve_image_channels_ = onoff;
|
1401
|
+
}
|
1402
|
+
|
1403
|
+
bool GetPreserveImageChannels() const { return preserve_image_channels_; }
|
1404
|
+
|
1386
1405
|
private:
|
1387
1406
|
///
|
1388
1407
|
/// Loads glTF asset from string(memory).
|
@@ -1402,6 +1421,9 @@ class TinyGLTF {
|
|
1402
1421
|
|
1403
1422
|
bool store_original_json_for_extras_and_extensions_ = false;
|
1404
1423
|
|
1424
|
+
bool preserve_image_channels_ = false; /// Default false(expand channels to
|
1425
|
+
/// RGBA) for backward compatibility.
|
1426
|
+
|
1405
1427
|
FsCallbacks fs = {
|
1406
1428
|
#ifndef TINYGLTF_NO_FS
|
1407
1429
|
&tinygltf::FileExists, &tinygltf::ExpandFilePath,
|
@@ -1421,7 +1443,8 @@ class TinyGLTF {
|
|
1421
1443
|
#else
|
1422
1444
|
nullptr;
|
1423
1445
|
#endif
|
1424
|
-
void *load_image_user_data_
|
1446
|
+
void *load_image_user_data_{nullptr};
|
1447
|
+
bool user_image_loader_{false};
|
1425
1448
|
|
1426
1449
|
WriteImageDataFunction WriteImageData =
|
1427
1450
|
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
|
@@ -1429,7 +1452,7 @@ class TinyGLTF {
|
|
1429
1452
|
#else
|
1430
1453
|
nullptr;
|
1431
1454
|
#endif
|
1432
|
-
void *write_image_user_data_
|
1455
|
+
void *write_image_user_data_{nullptr};
|
1433
1456
|
};
|
1434
1457
|
|
1435
1458
|
#ifdef __clang__
|
@@ -1514,6 +1537,7 @@ class TinyGLTF {
|
|
1514
1537
|
#ifndef TINYGLTF_USE_RAPIDJSON
|
1515
1538
|
#include "json.hpp"
|
1516
1539
|
#else
|
1540
|
+
#ifndef TINYGLTF_NO_INCLUDE_RAPIDJSON
|
1517
1541
|
#include "document.h"
|
1518
1542
|
#include "prettywriter.h"
|
1519
1543
|
#include "rapidjson.h"
|
@@ -1521,6 +1545,7 @@ class TinyGLTF {
|
|
1521
1545
|
#include "writer.h"
|
1522
1546
|
#endif
|
1523
1547
|
#endif
|
1548
|
+
#endif
|
1524
1549
|
|
1525
1550
|
#ifdef TINYGLTF_ENABLE_DRACO
|
1526
1551
|
#include "draco/compression/decode.h"
|
@@ -1579,7 +1604,7 @@ class TinyGLTF {
|
|
1579
1604
|
|
1580
1605
|
#endif
|
1581
1606
|
|
1582
|
-
#elif !defined(__ANDROID__)
|
1607
|
+
#elif !defined(__ANDROID__) && !defined(__OpenBSD__)
|
1583
1608
|
#include <wordexp.h>
|
1584
1609
|
#endif
|
1585
1610
|
|
@@ -1683,6 +1708,19 @@ void JsonParse(JsonDocument &doc, const char *str, size_t length,
|
|
1683
1708
|
|
1684
1709
|
namespace tinygltf {
|
1685
1710
|
|
1711
|
+
///
|
1712
|
+
/// Internal LoadImageDataOption struct.
|
1713
|
+
/// This struct is passed through `user_pointer` in LoadImageData.
|
1714
|
+
/// The struct is not passed when the user supply their own LoadImageData
|
1715
|
+
/// callbacks.
|
1716
|
+
///
|
1717
|
+
struct LoadImageDataOption {
|
1718
|
+
// true: preserve image channels(e.g. load as RGB image if the image has RGB
|
1719
|
+
// channels) default `false`(channels are expanded to RGBA for backward
|
1720
|
+
// compatiblity).
|
1721
|
+
bool preserve_channels{false};
|
1722
|
+
};
|
1723
|
+
|
1686
1724
|
// Equals function for Value, for recursivity
|
1687
1725
|
static bool Equals(const tinygltf::Value &one, const tinygltf::Value &other) {
|
1688
1726
|
if (one.Type() != other.Type()) return false;
|
@@ -1895,8 +1933,10 @@ bool Sampler::operator==(const Sampler &other) const {
|
|
1895
1933
|
return this->extensions == other.extensions && this->extras == other.extras &&
|
1896
1934
|
this->magFilter == other.magFilter &&
|
1897
1935
|
this->minFilter == other.minFilter && this->name == other.name &&
|
1898
|
-
this->
|
1936
|
+
this->wrapS == other.wrapS &&
|
1899
1937
|
this->wrapT == other.wrapT;
|
1938
|
+
|
1939
|
+
//this->wrapR == other.wrapR
|
1900
1940
|
}
|
1901
1941
|
bool Scene::operator==(const Scene &other) const {
|
1902
1942
|
return this->extensions == other.extensions && this->extras == other.extras &&
|
@@ -2000,9 +2040,11 @@ static std::string GetBaseDir(const std::string &filepath) {
|
|
2000
2040
|
return "";
|
2001
2041
|
}
|
2002
2042
|
|
2003
|
-
// https://stackoverflow.com/questions/8520560/get-a-file-name-from-a-path
|
2004
2043
|
static std::string GetBaseFilename(const std::string &filepath) {
|
2005
|
-
|
2044
|
+
auto idx = filepath.find_last_of("/\\");
|
2045
|
+
if (idx != std::string::npos)
|
2046
|
+
return filepath.substr(idx + 1);
|
2047
|
+
return filepath;
|
2006
2048
|
}
|
2007
2049
|
|
2008
2050
|
std::string base64_encode(unsigned char const *, unsigned int len);
|
@@ -2148,47 +2190,35 @@ std::string base64_decode(std::string const &encoded_string) {
|
|
2148
2190
|
// TODO(syoyo): Use uriparser https://uriparser.github.io/ for stricter Uri
|
2149
2191
|
// decoding?
|
2150
2192
|
//
|
2151
|
-
//
|
2193
|
+
// Uri Decoding from DLIB
|
2152
2194
|
// http://dlib.net/dlib/server/server_http.cpp.html
|
2153
|
-
|
2154
|
-
// --- dlib beign ------------------------------------------------------------
|
2195
|
+
// --- dlib begin ------------------------------------------------------------
|
2155
2196
|
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
|
2156
|
-
// License: Boost Software License
|
2157
|
-
|
2197
|
+
// License: Boost Software License
|
2198
|
+
// Boost Software License - Version 1.0 - August 17th, 2003
|
2199
|
+
|
2200
|
+
// Permission is hereby granted, free of charge, to any person or organization
|
2201
|
+
// obtaining a copy of the software and accompanying documentation covered by
|
2202
|
+
// this license (the "Software") to use, reproduce, display, distribute,
|
2203
|
+
// execute, and transmit the Software, and to prepare derivative works of the
|
2204
|
+
// Software, and to permit third-parties to whom the Software is furnished to
|
2205
|
+
// do so, all subject to the following:
|
2206
|
+
// The copyright notices in the Software and this entire statement, including
|
2207
|
+
// the above license grant, this restriction and the following disclaimer,
|
2208
|
+
// must be included in all copies of the Software, in whole or in part, and
|
2209
|
+
// all derivative works of the Software, unless such copies or derivative
|
2210
|
+
// works are solely in the form of machine-executable object code generated by
|
2211
|
+
// a source language processor.
|
2212
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
2213
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
2214
|
+
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
2215
|
+
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
2216
|
+
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
2217
|
+
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
2218
|
+
// DEALINGS IN THE SOFTWARE.
|
2219
|
+
//
|
2158
2220
|
namespace dlib {
|
2159
2221
|
|
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
2222
|
inline unsigned char from_hex(unsigned char ch) {
|
2193
2223
|
if (ch <= '9' && ch >= '0')
|
2194
2224
|
ch -= '0';
|
@@ -2297,22 +2327,40 @@ static bool LoadExternalFile(std::vector<unsigned char> *out, std::string *err,
|
|
2297
2327
|
void TinyGLTF::SetImageLoader(LoadImageDataFunction func, void *user_data) {
|
2298
2328
|
LoadImageData = func;
|
2299
2329
|
load_image_user_data_ = user_data;
|
2330
|
+
user_image_loader_ = true;
|
2331
|
+
}
|
2332
|
+
|
2333
|
+
void TinyGLTF::RemoveImageLoader() {
|
2334
|
+
LoadImageData =
|
2335
|
+
#ifndef TINYGLTF_NO_STB_IMAGE
|
2336
|
+
&tinygltf::LoadImageData;
|
2337
|
+
#else
|
2338
|
+
nullptr;
|
2339
|
+
#endif
|
2340
|
+
|
2341
|
+
load_image_user_data_ = nullptr;
|
2342
|
+
user_image_loader_ = false;
|
2300
2343
|
}
|
2301
2344
|
|
2302
2345
|
#ifndef TINYGLTF_NO_STB_IMAGE
|
2303
2346
|
bool LoadImageData(Image *image, const int image_idx, std::string *err,
|
2304
2347
|
std::string *warn, int req_width, int req_height,
|
2305
2348
|
const unsigned char *bytes, int size, void *user_data) {
|
2306
|
-
(void)user_data;
|
2307
2349
|
(void)warn;
|
2308
2350
|
|
2351
|
+
LoadImageDataOption option;
|
2352
|
+
if (user_data) {
|
2353
|
+
option = *reinterpret_cast<LoadImageDataOption *>(user_data);
|
2354
|
+
}
|
2355
|
+
|
2309
2356
|
int w = 0, h = 0, comp = 0, req_comp = 0;
|
2310
2357
|
|
2311
2358
|
unsigned char *data = nullptr;
|
2312
2359
|
|
2313
|
-
//
|
2314
|
-
//
|
2315
|
-
|
2360
|
+
// preserve_channels true: Use channels stored in the image file.
|
2361
|
+
// false: force 32-bit textures for common Vulkan compatibility. It appears
|
2362
|
+
// that some GPU drivers do not support 24-bit images for Vulkan
|
2363
|
+
req_comp = option.preserve_channels ? 0 : 4;
|
2316
2364
|
int bits = 8;
|
2317
2365
|
int pixel_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE;
|
2318
2366
|
|
@@ -2384,13 +2432,18 @@ bool LoadImageData(Image *image, const int image_idx, std::string *err,
|
|
2384
2432
|
}
|
2385
2433
|
}
|
2386
2434
|
|
2435
|
+
if (req_comp != 0) {
|
2436
|
+
// loaded data has `req_comp` channels(components)
|
2437
|
+
comp = req_comp;
|
2438
|
+
}
|
2439
|
+
|
2387
2440
|
image->width = w;
|
2388
2441
|
image->height = h;
|
2389
|
-
image->component =
|
2442
|
+
image->component = comp;
|
2390
2443
|
image->bits = bits;
|
2391
2444
|
image->pixel_type = pixel_type;
|
2392
|
-
image->image.resize(static_cast<size_t>(w * h *
|
2393
|
-
std::copy(data, data + w * h *
|
2445
|
+
image->image.resize(static_cast<size_t>(w * h * comp) * size_t(bits / 8));
|
2446
|
+
std::copy(data, data + w * h * comp * (bits / 8), image->image.begin());
|
2394
2447
|
stbi_image_free(data);
|
2395
2448
|
|
2396
2449
|
return true;
|
@@ -2566,7 +2619,7 @@ std::string ExpandFilePath(const std::string &filepath, void *) {
|
|
2566
2619
|
#else
|
2567
2620
|
|
2568
2621
|
#if defined(TARGET_OS_IPHONE) || defined(TARGET_IPHONE_SIMULATOR) || \
|
2569
|
-
defined(__ANDROID__) || defined(__EMSCRIPTEN__)
|
2622
|
+
defined(__ANDROID__) || defined(__EMSCRIPTEN__) || defined(__OpenBSD__)
|
2570
2623
|
// no expansion
|
2571
2624
|
std::string s = filepath;
|
2572
2625
|
#else
|
@@ -3139,6 +3192,7 @@ static bool ParseJsonAsValue(Value *ret, const json &o) {
|
|
3139
3192
|
break;
|
3140
3193
|
case json::value_t::null:
|
3141
3194
|
case json::value_t::discarded:
|
3195
|
+
case json::value_t::binary:
|
3142
3196
|
// default:
|
3143
3197
|
break;
|
3144
3198
|
}
|
@@ -4162,7 +4216,9 @@ static bool ParseSparseAccessor(Accessor *accessor, std::string *err,
|
|
4162
4216
|
accessor->sparse.isSparse = true;
|
4163
4217
|
|
4164
4218
|
int count = 0;
|
4165
|
-
ParseIntegerProperty(&count, err, o, "count", true)
|
4219
|
+
if (!ParseIntegerProperty(&count, err, o, "count", true, "SparseAccessor")) {
|
4220
|
+
return false;
|
4221
|
+
}
|
4166
4222
|
|
4167
4223
|
json_const_iterator indices_iterator;
|
4168
4224
|
json_const_iterator values_iterator;
|
@@ -4180,18 +4236,24 @@ static bool ParseSparseAccessor(Accessor *accessor, std::string *err,
|
|
4180
4236
|
const json &values_obj = GetValue(values_iterator);
|
4181
4237
|
|
4182
4238
|
int indices_buffer_view = 0, indices_byte_offset = 0, component_type = 0;
|
4183
|
-
ParseIntegerProperty(&indices_buffer_view, err, indices_obj, "bufferView",
|
4184
|
-
true)
|
4239
|
+
if (!ParseIntegerProperty(&indices_buffer_view, err, indices_obj, "bufferView",
|
4240
|
+
true, "SparseAccessor")) {
|
4241
|
+
return false;
|
4242
|
+
}
|
4185
4243
|
ParseIntegerProperty(&indices_byte_offset, err, indices_obj, "byteOffset",
|
4186
|
-
|
4187
|
-
ParseIntegerProperty(&component_type, err, indices_obj, "componentType",
|
4188
|
-
true)
|
4244
|
+
false);
|
4245
|
+
if (!ParseIntegerProperty(&component_type, err, indices_obj, "componentType",
|
4246
|
+
true, "SparseAccessor")) {
|
4247
|
+
return false;
|
4248
|
+
}
|
4189
4249
|
|
4190
4250
|
int values_buffer_view = 0, values_byte_offset = 0;
|
4191
|
-
ParseIntegerProperty(&values_buffer_view, err, values_obj, "bufferView",
|
4192
|
-
true)
|
4251
|
+
if (!ParseIntegerProperty(&values_buffer_view, err, values_obj, "bufferView",
|
4252
|
+
true, "SparseAccessor")) {
|
4253
|
+
return false;
|
4254
|
+
}
|
4193
4255
|
ParseIntegerProperty(&values_byte_offset, err, values_obj, "byteOffset",
|
4194
|
-
|
4256
|
+
false);
|
4195
4257
|
|
4196
4258
|
accessor->sparse.count = count;
|
4197
4259
|
accessor->sparse.indices.bufferView = indices_buffer_view;
|
@@ -4200,8 +4262,6 @@ static bool ParseSparseAccessor(Accessor *accessor, std::string *err,
|
|
4200
4262
|
accessor->sparse.values.bufferView = values_buffer_view;
|
4201
4263
|
accessor->sparse.values.byteOffset = values_byte_offset;
|
4202
4264
|
|
4203
|
-
// todo check theses values
|
4204
|
-
|
4205
4265
|
return true;
|
4206
4266
|
}
|
4207
4267
|
|
@@ -4409,6 +4469,7 @@ static bool GetAttributeForAllPoints(uint32_t componentType, draco::Mesh *mesh,
|
|
4409
4469
|
static bool ParseDracoExtension(Primitive *primitive, Model *model,
|
4410
4470
|
std::string *err,
|
4411
4471
|
const Value &dracoExtensionValue) {
|
4472
|
+
(void)err;
|
4412
4473
|
auto bufferViewValue = dracoExtensionValue.Get("bufferView");
|
4413
4474
|
if (!bufferViewValue.IsInt()) return false;
|
4414
4475
|
auto attributesValue = dracoExtensionValue.Get("attributes");
|
@@ -4469,7 +4530,6 @@ static bool ParseDracoExtension(Primitive *primitive, Model *model,
|
|
4469
4530
|
|
4470
4531
|
int dracoAttributeIndex = attribute.second.Get<int>();
|
4471
4532
|
const auto pAttribute = mesh->GetAttributeByUniqueId(dracoAttributeIndex);
|
4472
|
-
const auto pBuffer = pAttribute->buffer();
|
4473
4533
|
const auto componentType =
|
4474
4534
|
model->accessors[primitiveAttribute->second].componentType;
|
4475
4535
|
|
@@ -5028,12 +5088,12 @@ static bool ParseSampler(Sampler *sampler, std::string *err, const json &o,
|
|
5028
5088
|
int magFilter = -1;
|
5029
5089
|
int wrapS = TINYGLTF_TEXTURE_WRAP_REPEAT;
|
5030
5090
|
int wrapT = TINYGLTF_TEXTURE_WRAP_REPEAT;
|
5031
|
-
int wrapR = TINYGLTF_TEXTURE_WRAP_REPEAT;
|
5091
|
+
//int wrapR = TINYGLTF_TEXTURE_WRAP_REPEAT;
|
5032
5092
|
ParseIntegerProperty(&minFilter, err, o, "minFilter", false);
|
5033
5093
|
ParseIntegerProperty(&magFilter, err, o, "magFilter", false);
|
5034
5094
|
ParseIntegerProperty(&wrapS, err, o, "wrapS", false);
|
5035
5095
|
ParseIntegerProperty(&wrapT, err, o, "wrapT", false);
|
5036
|
-
ParseIntegerProperty(&wrapR, err, o, "wrapR", false); // tinygltf extension
|
5096
|
+
//ParseIntegerProperty(&wrapR, err, o, "wrapR", false); // tinygltf extension
|
5037
5097
|
|
5038
5098
|
// TODO(syoyo): Check the value is alloed one.
|
5039
5099
|
// (e.g. we allow 9728(NEAREST), but don't allow 9727)
|
@@ -5042,7 +5102,7 @@ static bool ParseSampler(Sampler *sampler, std::string *err, const json &o,
|
|
5042
5102
|
sampler->magFilter = magFilter;
|
5043
5103
|
sampler->wrapS = wrapS;
|
5044
5104
|
sampler->wrapT = wrapT;
|
5045
|
-
sampler->wrapR = wrapR;
|
5105
|
+
//sampler->wrapR = wrapR;
|
5046
5106
|
|
5047
5107
|
ParseExtensionsProperty(&(sampler->extensions), err, o);
|
5048
5108
|
ParseExtrasProperty(&(sampler->extras), o);
|
@@ -5769,13 +5829,13 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
|
|
5769
5829
|
{
|
5770
5830
|
json_const_iterator it;
|
5771
5831
|
if (FindMember(o, "extensions", it)) {
|
5772
|
-
|
5832
|
+
scene.extensions_json_string = JsonToString(GetValue(it));
|
5773
5833
|
}
|
5774
5834
|
}
|
5775
5835
|
{
|
5776
5836
|
json_const_iterator it;
|
5777
5837
|
if (FindMember(o, "extras", it)) {
|
5778
|
-
|
5838
|
+
scene.extras_json_string = JsonToString(GetValue(it));
|
5779
5839
|
}
|
5780
5840
|
}
|
5781
5841
|
}
|
@@ -5825,6 +5885,18 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
|
|
5825
5885
|
}
|
5826
5886
|
|
5827
5887
|
// 11. Parse Image
|
5888
|
+
void *load_image_user_data{nullptr};
|
5889
|
+
|
5890
|
+
LoadImageDataOption load_image_option;
|
5891
|
+
|
5892
|
+
if (user_image_loader_) {
|
5893
|
+
// Use user supplied pointer
|
5894
|
+
load_image_user_data = load_image_user_data_;
|
5895
|
+
} else {
|
5896
|
+
load_image_option.preserve_channels = preserve_image_channels_;
|
5897
|
+
load_image_user_data = reinterpret_cast<void *>(&load_image_option);
|
5898
|
+
}
|
5899
|
+
|
5828
5900
|
{
|
5829
5901
|
int idx = 0;
|
5830
5902
|
bool success = ForEachInArray(v, "images", [&](const json &o) {
|
@@ -5837,7 +5909,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
|
|
5837
5909
|
Image image;
|
5838
5910
|
if (!ParseImage(&image, idx, err, warn, o,
|
5839
5911
|
store_original_json_for_extras_and_extensions_, base_dir,
|
5840
|
-
&fs, &this->LoadImageData,
|
5912
|
+
&fs, &this->LoadImageData, load_image_user_data)) {
|
5841
5913
|
return false;
|
5842
5914
|
}
|
5843
5915
|
|
@@ -5875,7 +5947,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
|
|
5875
5947
|
bool ret = LoadImageData(
|
5876
5948
|
&image, idx, err, warn, image.width, image.height,
|
5877
5949
|
&buffer.data[bufferView.byteOffset],
|
5878
|
-
static_cast<int>(bufferView.byteLength),
|
5950
|
+
static_cast<int>(bufferView.byteLength), load_image_user_data);
|
5879
5951
|
if (!ret) {
|
5880
5952
|
return false;
|
5881
5953
|
}
|
@@ -6551,8 +6623,33 @@ static void SerializeGltfAccessor(Accessor &accessor, json &o) {
|
|
6551
6623
|
|
6552
6624
|
SerializeNumberProperty<int>("componentType", accessor.componentType, o);
|
6553
6625
|
SerializeNumberProperty<size_t>("count", accessor.count, o);
|
6554
|
-
|
6555
|
-
|
6626
|
+
|
6627
|
+
if ((accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT) ||
|
6628
|
+
(accessor.componentType == TINYGLTF_COMPONENT_TYPE_DOUBLE)) {
|
6629
|
+
SerializeNumberArrayProperty<double>("min", accessor.minValues, o);
|
6630
|
+
SerializeNumberArrayProperty<double>("max", accessor.maxValues, o);
|
6631
|
+
} else {
|
6632
|
+
// Issue #301. Serialize as integer.
|
6633
|
+
// Assume int value is within [-2**31-1, 2**31-1]
|
6634
|
+
{
|
6635
|
+
std::vector<int> values;
|
6636
|
+
std::transform(accessor.minValues.begin(), accessor.minValues.end(),
|
6637
|
+
std::back_inserter(values),
|
6638
|
+
[](double v) { return static_cast<int>(v); });
|
6639
|
+
|
6640
|
+
SerializeNumberArrayProperty<int>("min", values, o);
|
6641
|
+
}
|
6642
|
+
|
6643
|
+
{
|
6644
|
+
std::vector<int> values;
|
6645
|
+
std::transform(accessor.maxValues.begin(), accessor.maxValues.end(),
|
6646
|
+
std::back_inserter(values),
|
6647
|
+
[](double v) { return static_cast<int>(v); });
|
6648
|
+
|
6649
|
+
SerializeNumberArrayProperty<int>("max", values, o);
|
6650
|
+
}
|
6651
|
+
}
|
6652
|
+
|
6556
6653
|
if (accessor.normalized)
|
6557
6654
|
SerializeValue("normalized", Value(accessor.normalized), o);
|
6558
6655
|
std::string type;
|
@@ -6662,10 +6759,15 @@ static void SerializeGltfAsset(Asset &asset, json &o) {
|
|
6662
6759
|
SerializeStringProperty("copyright", asset.copyright, o);
|
6663
6760
|
}
|
6664
6761
|
|
6665
|
-
if (
|
6666
|
-
|
6762
|
+
if (asset.version.empty()) {
|
6763
|
+
// Just in case
|
6764
|
+
// `version` must be defined
|
6765
|
+
asset.version = "2.0";
|
6667
6766
|
}
|
6668
6767
|
|
6768
|
+
// TODO(syoyo): Do we need to check if `version` is greater or equal to 2.0?
|
6769
|
+
SerializeStringProperty("version", asset.version, o);
|
6770
|
+
|
6669
6771
|
if (asset.extras.Keys().size()) {
|
6670
6772
|
SerializeValue("extras", asset.extras, o);
|
6671
6773
|
}
|
@@ -7063,7 +7165,7 @@ static void SerializeGltfSampler(Sampler &sampler, json &o) {
|
|
7063
7165
|
if (sampler.minFilter != -1) {
|
7064
7166
|
SerializeNumberProperty("minFilter", sampler.minFilter, o);
|
7065
7167
|
}
|
7066
|
-
SerializeNumberProperty("wrapR", sampler.wrapR, o);
|
7168
|
+
//SerializeNumberProperty("wrapR", sampler.wrapR, o);
|
7067
7169
|
SerializeNumberProperty("wrapS", sampler.wrapS, o);
|
7068
7170
|
SerializeNumberProperty("wrapT", sampler.wrapT, o);
|
7069
7171
|
|
@@ -7138,11 +7240,17 @@ static void SerializeGltfScene(Scene &scene, json &o) {
|
|
7138
7240
|
}
|
7139
7241
|
|
7140
7242
|
static void SerializeGltfSkin(Skin &skin, json &o) {
|
7141
|
-
|
7243
|
+
// required
|
7244
|
+
SerializeNumberArrayProperty<int>("joints", skin.joints, o);
|
7245
|
+
|
7246
|
+
if (skin.inverseBindMatrices >= 0) {
|
7142
7247
|
SerializeNumberProperty("inverseBindMatrices", skin.inverseBindMatrices, o);
|
7248
|
+
}
|
7249
|
+
|
7250
|
+
if (skin.skeleton >= 0) {
|
7251
|
+
SerializeNumberProperty("skeleton", skin.skeleton, o);
|
7252
|
+
}
|
7143
7253
|
|
7144
|
-
SerializeNumberArrayProperty<int>("joints", skin.joints, o);
|
7145
|
-
SerializeNumberProperty("skeleton", skin.skeleton, o);
|
7146
7254
|
if (skin.name.size()) {
|
7147
7255
|
SerializeStringProperty("name", skin.name, o);
|
7148
7256
|
}
|
@@ -7225,6 +7333,16 @@ static void SerializeGltfModel(Model *model, json &o) {
|
|
7225
7333
|
for (unsigned int i = 0; i < model->materials.size(); ++i) {
|
7226
7334
|
json material;
|
7227
7335
|
SerializeGltfMaterial(model->materials[i], material);
|
7336
|
+
|
7337
|
+
if (JsonIsNull(material)) {
|
7338
|
+
// Issue 294.
|
7339
|
+
// `material` does not have any required parameters
|
7340
|
+
// so the result may be null(unmodified) when all material parameters
|
7341
|
+
// have default value.
|
7342
|
+
//
|
7343
|
+
// null is not allowed thus we create an empty JSON object.
|
7344
|
+
JsonSetObject(material);
|
7345
|
+
}
|
7228
7346
|
JsonPushBack(materials, std::move(material));
|
7229
7347
|
}
|
7230
7348
|
JsonAddMember(o, "materials", std::move(materials));
|
@@ -7363,7 +7481,7 @@ static void SerializeGltfModel(Model *model, json &o) {
|
|
7363
7481
|
}
|
7364
7482
|
|
7365
7483
|
// Extensions used
|
7366
|
-
if (
|
7484
|
+
if (extensionsUsed.size()) {
|
7367
7485
|
SerializeStringArrayProperty("extensionsUsed", extensionsUsed, o);
|
7368
7486
|
}
|
7369
7487
|
|
@@ -7407,31 +7525,24 @@ static void WriteBinaryGltfStream(std::ostream &stream,
|
|
7407
7525
|
const std::string header = "glTF";
|
7408
7526
|
const int version = 2;
|
7409
7527
|
|
7410
|
-
|
7411
|
-
|
7412
|
-
|
7413
|
-
|
7414
|
-
|
7415
|
-
if (remainder == 0) return numToRound;
|
7416
|
-
|
7417
|
-
return numToRound + multiple - remainder;
|
7418
|
-
};
|
7419
|
-
|
7420
|
-
const uint32_t padding_size =
|
7421
|
-
roundUp(uint32_t(content.size()), 4) - uint32_t(content.size());
|
7528
|
+
const uint32_t content_size = uint32_t(content.size());
|
7529
|
+
const uint32_t binBuffer_size = uint32_t(binBuffer.size());
|
7530
|
+
// determine number of padding bytes required to ensure 4 byte alignment
|
7531
|
+
const uint32_t content_padding_size = content_size % 4 == 0 ? 0 : 4 - content_size % 4;
|
7532
|
+
const uint32_t bin_padding_size = binBuffer_size % 4 == 0 ? 0 : 4 - binBuffer_size % 4;
|
7422
7533
|
|
7423
7534
|
// 12 bytes for header, JSON content length, 8 bytes for JSON chunk info.
|
7424
|
-
// Chunk data must be located at 4-byte boundary
|
7535
|
+
// Chunk data must be located at 4-byte boundary, which may require padding
|
7425
7536
|
const uint32_t length =
|
7426
|
-
12 + 8 +
|
7427
|
-
(
|
7537
|
+
12 + 8 + content_size + content_padding_size +
|
7538
|
+
(binBuffer_size ? (8 + binBuffer_size + bin_padding_size) : 0);
|
7428
7539
|
|
7429
7540
|
stream.write(header.c_str(), std::streamsize(header.size()));
|
7430
7541
|
stream.write(reinterpret_cast<const char *>(&version), sizeof(version));
|
7431
7542
|
stream.write(reinterpret_cast<const char *>(&length), sizeof(length));
|
7432
7543
|
|
7433
7544
|
// JSON chunk info, then JSON data
|
7434
|
-
const uint32_t model_length = uint32_t(content.size()) +
|
7545
|
+
const uint32_t model_length = uint32_t(content.size()) + content_padding_size;
|
7435
7546
|
const uint32_t model_format = 0x4E4F534A;
|
7436
7547
|
stream.write(reinterpret_cast<const char *>(&model_length),
|
7437
7548
|
sizeof(model_length));
|
@@ -7440,13 +7551,11 @@ static void WriteBinaryGltfStream(std::ostream &stream,
|
|
7440
7551
|
stream.write(content.c_str(), std::streamsize(content.size()));
|
7441
7552
|
|
7442
7553
|
// Chunk must be multiplies of 4, so pad with spaces
|
7443
|
-
if (
|
7444
|
-
const std::string padding = std::string(size_t(
|
7554
|
+
if (content_padding_size > 0) {
|
7555
|
+
const std::string padding = std::string(size_t(content_padding_size), ' ');
|
7445
7556
|
stream.write(padding.c_str(), std::streamsize(padding.size()));
|
7446
7557
|
}
|
7447
7558
|
if (binBuffer.size() > 0) {
|
7448
|
-
const uint32_t bin_padding_size =
|
7449
|
-
roundUp(uint32_t(binBuffer.size()), 4) - uint32_t(binBuffer.size());
|
7450
7559
|
// BIN chunk info, then BIN data
|
7451
7560
|
const uint32_t bin_length = uint32_t(binBuffer.size()) + bin_padding_size;
|
7452
7561
|
const uint32_t bin_format = 0x004e4942;
|