mirror of
https://git.mirrors.martin98.com/https://github.com/syoyo/tinygltf.git
synced 2025-08-02 23:50:42 +08:00
Parse integers directly instead of casting doubles
When parsing numeric values as doubles, its possible for users to specify values that cannot be converted to integers, such as Inf, NaN, and extremes such as 1e100. If this value is received, and then cast to an int, it is undefined behavior, which trips ubsan when running tinygltf under a fuzzer. Instead of parsing integral values as doubles, use nlohmann/json's built-in support to parse integer and unsigned values directly, with .is_number_integer() and .is_number_unsigned(). Add ParseIntegerProperty, ParseUnsignedProperty, and ParseIntegerArrayProperty helpers that allow parsing directly to int/uint values and update code to use them when appropriate.
This commit is contained in:
parent
e0ab69cb31
commit
19b806e052
67
models/BoundsChecking/integer-out-of-bounds.gltf
Normal file
67
models/BoundsChecking/integer-out-of-bounds.gltf
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
{
|
||||||
|
"scenes": [
|
||||||
|
{
|
||||||
|
"nodes": [0]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"mesh": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meshes": [
|
||||||
|
{
|
||||||
|
"primitives": [
|
||||||
|
{
|
||||||
|
"attributes": {
|
||||||
|
"POSITION": 1
|
||||||
|
},
|
||||||
|
"indices": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"buffers": [
|
||||||
|
{
|
||||||
|
"uri": "simpleTriangle.bin",
|
||||||
|
"byteLength": 44
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"bufferViews": [
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"byteLength": 1e300,
|
||||||
|
"target": 34963
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteOffset": 8,
|
||||||
|
"byteLength": 36,
|
||||||
|
"target": 34962
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accessors": [
|
||||||
|
{
|
||||||
|
"bufferView": 0,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"componentType": 5123,
|
||||||
|
"count": 3,
|
||||||
|
"type": "SCALAR",
|
||||||
|
"max": [2],
|
||||||
|
"min": [0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 1,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 3,
|
||||||
|
"type": "VEC3",
|
||||||
|
"max": [1, 1, 0],
|
||||||
|
"min": [0, 0, 0]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"asset": {
|
||||||
|
"version": "2.0"
|
||||||
|
}
|
||||||
|
}
|
133
tests/tester.cc
133
tests/tester.cc
@ -37,7 +37,7 @@ TEST_CASE("datauri-in-glb", "[issue-79]") {
|
|||||||
if (!err.empty()) {
|
if (!err.empty()) {
|
||||||
std::cerr << err << std::endl;
|
std::cerr << err << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
REQUIRE(true == ret);
|
REQUIRE(true == ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,3 +148,134 @@ TEST_CASE("glb-invalid-length", "[bounds-checking]") {
|
|||||||
REQUIRE_THAT(err, Catch::Contains("Invalid glTF binary."));
|
REQUIRE_THAT(err, Catch::Contains("Invalid glTF binary."));
|
||||||
REQUIRE_FALSE(ret);
|
REQUIRE_FALSE(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("integer-out-of-bounds", "[bounds-checking]") {
|
||||||
|
tinygltf::Model model;
|
||||||
|
tinygltf::TinyGLTF ctx;
|
||||||
|
std::string err;
|
||||||
|
std::string warn;
|
||||||
|
|
||||||
|
// Loading is expected to fail, but not crash.
|
||||||
|
bool ret = ctx.LoadASCIIFromFile(
|
||||||
|
&model, &err, &warn,
|
||||||
|
"../models/BoundsChecking/integer-out-of-bounds.gltf");
|
||||||
|
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
|
||||||
|
REQUIRE_FALSE(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("parse-integer", "[bounds-checking]") {
|
||||||
|
SECTION("parses valid numbers") {
|
||||||
|
std::string err;
|
||||||
|
int result = 123;
|
||||||
|
CHECK(tinygltf::ParseIntegerProperty(&result, &err, {{"zero", 0}}, "zero",
|
||||||
|
true));
|
||||||
|
REQUIRE(err == "");
|
||||||
|
REQUIRE(result == 0);
|
||||||
|
|
||||||
|
CHECK(tinygltf::ParseIntegerProperty(&result, &err, {{"int", -1234}}, "int",
|
||||||
|
true));
|
||||||
|
REQUIRE(err == "");
|
||||||
|
REQUIRE(result == -1234);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("detects missing properties") {
|
||||||
|
std::string err;
|
||||||
|
int result = -1;
|
||||||
|
CHECK_FALSE(tinygltf::ParseIntegerProperty(&result, &err, {}, "int", true));
|
||||||
|
REQUIRE_THAT(err, Catch::Contains("'int' property is missing"));
|
||||||
|
REQUIRE(result == -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("handled missing but not required properties") {
|
||||||
|
std::string err;
|
||||||
|
int result = -1;
|
||||||
|
CHECK_FALSE(
|
||||||
|
tinygltf::ParseIntegerProperty(&result, &err, {}, "int", false));
|
||||||
|
REQUIRE(err == "");
|
||||||
|
REQUIRE(result == -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("invalid integers") {
|
||||||
|
std::string err;
|
||||||
|
int result = -1;
|
||||||
|
|
||||||
|
CHECK_FALSE(tinygltf::ParseIntegerProperty(&result, &err, {{"int", 0.5}},
|
||||||
|
"int", true));
|
||||||
|
REQUIRE_THAT(err, Catch::Contains("not an integer type"));
|
||||||
|
|
||||||
|
// Excessively large values and NaN aren't allowed either.
|
||||||
|
err.clear();
|
||||||
|
CHECK_FALSE(tinygltf::ParseIntegerProperty(&result, &err, {{"int", 1e300}},
|
||||||
|
"int", true));
|
||||||
|
REQUIRE_THAT(err, Catch::Contains("not an integer type"));
|
||||||
|
|
||||||
|
err.clear();
|
||||||
|
CHECK_FALSE(tinygltf::ParseIntegerProperty(
|
||||||
|
&result, &err, {{"int", std::numeric_limits<double>::quiet_NaN()}},
|
||||||
|
"int", true));
|
||||||
|
REQUIRE_THAT(err, Catch::Contains("not an integer type"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("parse-unsigned", "[bounds-checking]") {
|
||||||
|
SECTION("parses valid unsigned integers") {
|
||||||
|
// Use string-based parsing here, using the initializer list syntax doesn't
|
||||||
|
// parse 0 as unsigned.
|
||||||
|
json zero_obj = json::parse("{\"zero\": 0}");
|
||||||
|
|
||||||
|
std::string err;
|
||||||
|
size_t result = 123;
|
||||||
|
CHECK(
|
||||||
|
tinygltf::ParseUnsignedProperty(&result, &err, zero_obj, "zero", true));
|
||||||
|
REQUIRE(err == "");
|
||||||
|
REQUIRE(result == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("invalid integers") {
|
||||||
|
std::string err;
|
||||||
|
size_t result = -1;
|
||||||
|
|
||||||
|
CHECK_FALSE(tinygltf::ParseUnsignedProperty(&result, &err, {{"int", -1234}},
|
||||||
|
"int", true));
|
||||||
|
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
|
||||||
|
|
||||||
|
err.clear();
|
||||||
|
CHECK_FALSE(tinygltf::ParseUnsignedProperty(&result, &err, {{"int", 0.5}},
|
||||||
|
"int", true));
|
||||||
|
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
|
||||||
|
|
||||||
|
// Excessively large values and NaN aren't allowed either.
|
||||||
|
err.clear();
|
||||||
|
CHECK_FALSE(tinygltf::ParseUnsignedProperty(&result, &err, {{"int", 1e300}},
|
||||||
|
"int", true));
|
||||||
|
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
|
||||||
|
|
||||||
|
err.clear();
|
||||||
|
CHECK_FALSE(tinygltf::ParseUnsignedProperty(
|
||||||
|
&result, &err, {{"int", std::numeric_limits<double>::quiet_NaN()}},
|
||||||
|
"int", true));
|
||||||
|
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("parse-integer-array", "[bounds-checking]") {
|
||||||
|
SECTION("parses valid integers") {
|
||||||
|
std::string err;
|
||||||
|
std::vector<int> result;
|
||||||
|
CHECK(tinygltf::ParseIntegerArrayProperty(&result, &err,
|
||||||
|
{{"x", {-1, 2, 3}}}, "x", true));
|
||||||
|
REQUIRE(err == "");
|
||||||
|
REQUIRE(result.size() == 3);
|
||||||
|
REQUIRE(result[0] == -1);
|
||||||
|
REQUIRE(result[1] == 2);
|
||||||
|
REQUIRE(result[2] == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("invalid integers") {
|
||||||
|
std::string err;
|
||||||
|
std::vector<int> result;
|
||||||
|
CHECK_FALSE(tinygltf::ParseIntegerArrayProperty(
|
||||||
|
&result, &err, {{"x", {-1, 1e300, 3}}}, "x", true));
|
||||||
|
REQUIRE_THAT(err, Catch::Contains("not an integer type"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
439
tiny_gltf.h
439
tiny_gltf.h
@ -2271,6 +2271,74 @@ static bool ParseBooleanProperty(bool *ret, std::string *err, const json &o,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ParseIntegerProperty(int *ret, std::string *err, const json &o,
|
||||||
|
const std::string &property,
|
||||||
|
const bool required,
|
||||||
|
const std::string &parent_node = "") {
|
||||||
|
json::const_iterator it = o.find(property);
|
||||||
|
if (it == o.end()) {
|
||||||
|
if (required) {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "'" + property + "' property is missing";
|
||||||
|
if (!parent_node.empty()) {
|
||||||
|
(*err) += " in " + parent_node;
|
||||||
|
}
|
||||||
|
(*err) += ".\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!it.value().is_number_integer()) {
|
||||||
|
if (required) {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "'" + property + "' property is not an integer type.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
(*ret) = it.value().get<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ParseUnsignedProperty(size_t *ret, std::string *err, const json &o,
|
||||||
|
const std::string &property,
|
||||||
|
const bool required,
|
||||||
|
const std::string &parent_node = "") {
|
||||||
|
json::const_iterator it = o.find(property);
|
||||||
|
if (it == o.end()) {
|
||||||
|
if (required) {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "'" + property + "' property is missing";
|
||||||
|
if (!parent_node.empty()) {
|
||||||
|
(*err) += " in " + parent_node;
|
||||||
|
}
|
||||||
|
(*err) += ".\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!it.value().is_number_unsigned()) {
|
||||||
|
if (required) {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "'" + property + "' property is not a positive integer.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
(*ret) = it.value().get<size_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool ParseNumberProperty(double *ret, std::string *err, const json &o,
|
static bool ParseNumberProperty(double *ret, std::string *err, const json &o,
|
||||||
const std::string &property,
|
const std::string &property,
|
||||||
const bool required,
|
const bool required,
|
||||||
@ -2357,6 +2425,59 @@ static bool ParseNumberArrayProperty(std::vector<double> *ret, std::string *err,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ParseIntegerArrayProperty(std::vector<int> *ret, std::string *err,
|
||||||
|
const json &o,
|
||||||
|
const std::string &property,
|
||||||
|
bool required,
|
||||||
|
const std::string &parent_node = "") {
|
||||||
|
json::const_iterator it = o.find(property);
|
||||||
|
if (it == o.end()) {
|
||||||
|
if (required) {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "'" + property + "' property is missing";
|
||||||
|
if (!parent_node.empty()) {
|
||||||
|
(*err) += " in " + parent_node;
|
||||||
|
}
|
||||||
|
(*err) += ".\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!it.value().is_array()) {
|
||||||
|
if (required) {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "'" + property + "' property is not an array";
|
||||||
|
if (!parent_node.empty()) {
|
||||||
|
(*err) += " in " + parent_node;
|
||||||
|
}
|
||||||
|
(*err) += ".\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret->clear();
|
||||||
|
for (json::const_iterator i = it.value().begin(); i != it.value().end();
|
||||||
|
i++) {
|
||||||
|
if (!i.value().is_number_integer()) {
|
||||||
|
if (required) {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "'" + property + "' property is not an integer type.\n";
|
||||||
|
if (!parent_node.empty()) {
|
||||||
|
(*err) += " in " + parent_node;
|
||||||
|
}
|
||||||
|
(*err) += ".\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ret->push_back(i.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool ParseStringProperty(
|
static bool ParseStringProperty(
|
||||||
std::string *ret, std::string *err, const json &o,
|
std::string *ret, std::string *err, const json &o,
|
||||||
const std::string &property, bool required,
|
const std::string &property, bool required,
|
||||||
@ -2392,10 +2513,11 @@ static bool ParseStringProperty(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ParseStringIntProperty(std::map<std::string, int> *ret,
|
static bool ParseStringIntegerProperty(std::map<std::string, int> *ret,
|
||||||
std::string *err, const json &o,
|
std::string *err, const json &o,
|
||||||
const std::string &property, bool required,
|
const std::string &property,
|
||||||
const std::string &parent = "") {
|
bool required,
|
||||||
|
const std::string &parent = "") {
|
||||||
json::const_iterator it = o.find(property);
|
json::const_iterator it = o.find(property);
|
||||||
if (it == o.end()) {
|
if (it == o.end()) {
|
||||||
if (required) {
|
if (required) {
|
||||||
@ -2428,17 +2550,17 @@ static bool ParseStringIntProperty(std::map<std::string, int> *ret,
|
|||||||
json::const_iterator dictItEnd(dict.end());
|
json::const_iterator dictItEnd(dict.end());
|
||||||
|
|
||||||
for (; dictIt != dictItEnd; ++dictIt) {
|
for (; dictIt != dictItEnd; ++dictIt) {
|
||||||
if (!dictIt.value().is_number()) {
|
if (!dictIt.value().is_number_integer()) {
|
||||||
if (required) {
|
if (required) {
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) += "'" + property + "' value is not an int.\n";
|
(*err) += "'" + property + "' value is not an integer type.\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert into the list.
|
// Insert into the list.
|
||||||
(*ret)[dictIt.key()] = static_cast<int>(dictIt.value());
|
(*ret)[dictIt.key()] = dictIt.value();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2589,8 +2711,8 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err,
|
|||||||
ParseExtrasProperty(&image->extras, o);
|
ParseExtrasProperty(&image->extras, o);
|
||||||
|
|
||||||
if (hasBufferView) {
|
if (hasBufferView) {
|
||||||
double bufferView = -1;
|
int bufferView = -1;
|
||||||
if (!ParseNumberProperty(&bufferView, err, o, "bufferView", true)) {
|
if (!ParseIntegerProperty(&bufferView, err, o, "bufferView", true)) {
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) += "Failed to parse `bufferView` for image[" +
|
(*err) += "Failed to parse `bufferView` for image[" +
|
||||||
std::to_string(image_idx) + "] name = \"" + image->name +
|
std::to_string(image_idx) + "] name = \"" + image->name +
|
||||||
@ -2602,18 +2724,18 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err,
|
|||||||
std::string mime_type;
|
std::string mime_type;
|
||||||
ParseStringProperty(&mime_type, err, o, "mimeType", false);
|
ParseStringProperty(&mime_type, err, o, "mimeType", false);
|
||||||
|
|
||||||
double width = 0.0;
|
int width = 0;
|
||||||
ParseNumberProperty(&width, err, o, "width", false);
|
ParseIntegerProperty(&width, err, o, "width", false);
|
||||||
|
|
||||||
double height = 0.0;
|
int height = 0;
|
||||||
ParseNumberProperty(&height, err, o, "height", false);
|
ParseIntegerProperty(&height, err, o, "height", false);
|
||||||
|
|
||||||
// Just only save some information here. Loading actual image data from
|
// Just only save some information here. Loading actual image data from
|
||||||
// bufferView is done after this `ParseImage` function.
|
// bufferView is done after this `ParseImage` function.
|
||||||
image->bufferView = static_cast<int>(bufferView);
|
image->bufferView = bufferView;
|
||||||
image->mimeType = mime_type;
|
image->mimeType = mime_type;
|
||||||
image->width = static_cast<int>(width);
|
image->width = width;
|
||||||
image->height = static_cast<int>(height);
|
image->height = height;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2681,14 +2803,14 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err,
|
|||||||
static bool ParseTexture(Texture *texture, std::string *err, const json &o,
|
static bool ParseTexture(Texture *texture, std::string *err, const json &o,
|
||||||
const std::string &basedir) {
|
const std::string &basedir) {
|
||||||
(void)basedir;
|
(void)basedir;
|
||||||
double sampler = -1.0;
|
int sampler = -1;
|
||||||
double source = -1.0;
|
int source = -1;
|
||||||
ParseNumberProperty(&sampler, err, o, "sampler", false);
|
ParseIntegerProperty(&sampler, err, o, "sampler", false);
|
||||||
|
|
||||||
ParseNumberProperty(&source, err, o, "source", false);
|
ParseIntegerProperty(&source, err, o, "source", false);
|
||||||
|
|
||||||
texture->sampler = static_cast<int>(sampler);
|
texture->sampler = sampler;
|
||||||
texture->source = static_cast<int>(source);
|
texture->source = source;
|
||||||
|
|
||||||
ParseExtensionsProperty(&texture->extensions, err, o);
|
ParseExtensionsProperty(&texture->extensions, err, o);
|
||||||
ParseExtrasProperty(&texture->extras, o);
|
ParseExtrasProperty(&texture->extras, o);
|
||||||
@ -2703,8 +2825,9 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o,
|
|||||||
bool is_binary = false,
|
bool is_binary = false,
|
||||||
const unsigned char *bin_data = nullptr,
|
const unsigned char *bin_data = nullptr,
|
||||||
size_t bin_size = 0) {
|
size_t bin_size = 0) {
|
||||||
double byteLength;
|
size_t byteLength;
|
||||||
if (!ParseNumberProperty(&byteLength, err, o, "byteLength", true, "Buffer")) {
|
if (!ParseUnsignedProperty(&byteLength, err, o, "byteLength", true,
|
||||||
|
"Buffer")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2729,14 +2852,13 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t bytes = static_cast<size_t>(byteLength);
|
|
||||||
if (is_binary) {
|
if (is_binary) {
|
||||||
// Still binary glTF accepts external dataURI.
|
// Still binary glTF accepts external dataURI.
|
||||||
if (!buffer->uri.empty()) {
|
if (!buffer->uri.empty()) {
|
||||||
// First try embedded data URI.
|
// First try embedded data URI.
|
||||||
if (IsDataURI(buffer->uri)) {
|
if (IsDataURI(buffer->uri)) {
|
||||||
std::string mime_type;
|
std::string mime_type;
|
||||||
if (!DecodeDataURI(&buffer->data, mime_type, buffer->uri, bytes,
|
if (!DecodeDataURI(&buffer->data, mime_type, buffer->uri, byteLength,
|
||||||
true)) {
|
true)) {
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) +=
|
(*err) +=
|
||||||
@ -2747,7 +2869,8 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o,
|
|||||||
} else {
|
} else {
|
||||||
// External .bin file.
|
// External .bin file.
|
||||||
if (!LoadExternalFile(&buffer->data, err, /* warn */ nullptr,
|
if (!LoadExternalFile(&buffer->data, err, /* warn */ nullptr,
|
||||||
buffer->uri, basedir, true, bytes, true, fs)) {
|
buffer->uri, basedir, true, byteLength, true,
|
||||||
|
fs)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2780,7 +2903,8 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o,
|
|||||||
} else {
|
} else {
|
||||||
if (IsDataURI(buffer->uri)) {
|
if (IsDataURI(buffer->uri)) {
|
||||||
std::string mime_type;
|
std::string mime_type;
|
||||||
if (!DecodeDataURI(&buffer->data, mime_type, buffer->uri, bytes, true)) {
|
if (!DecodeDataURI(&buffer->data, mime_type, buffer->uri, byteLength,
|
||||||
|
true)) {
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) += "Failed to decode 'uri' : " + buffer->uri + " in Buffer\n";
|
(*err) += "Failed to decode 'uri' : " + buffer->uri + " in Buffer\n";
|
||||||
}
|
}
|
||||||
@ -2789,7 +2913,7 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o,
|
|||||||
} else {
|
} else {
|
||||||
// Assume external .bin file.
|
// Assume external .bin file.
|
||||||
if (!LoadExternalFile(&buffer->data, err, /* warn */ nullptr, buffer->uri,
|
if (!LoadExternalFile(&buffer->data, err, /* warn */ nullptr, buffer->uri,
|
||||||
basedir, true, bytes, true, fs)) {
|
basedir, true, byteLength, true, fs)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2802,31 +2926,28 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o,
|
|||||||
|
|
||||||
static bool ParseBufferView(BufferView *bufferView, std::string *err,
|
static bool ParseBufferView(BufferView *bufferView, std::string *err,
|
||||||
const json &o) {
|
const json &o) {
|
||||||
double buffer = -1.0;
|
int buffer = -1;
|
||||||
if (!ParseNumberProperty(&buffer, err, o, "buffer", true, "BufferView")) {
|
if (!ParseIntegerProperty(&buffer, err, o, "buffer", true, "BufferView")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
double byteOffset = 0.0;
|
size_t byteOffset = 0;
|
||||||
ParseNumberProperty(&byteOffset, err, o, "byteOffset", false);
|
ParseUnsignedProperty(&byteOffset, err, o, "byteOffset", false);
|
||||||
|
|
||||||
double byteLength = 1.0;
|
size_t byteLength = 1;
|
||||||
if (!ParseNumberProperty(&byteLength, err, o, "byteLength", true,
|
if (!ParseUnsignedProperty(&byteLength, err, o, "byteLength", true,
|
||||||
"BufferView")) {
|
"BufferView")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t byteStride = 0;
|
size_t byteStride = 0;
|
||||||
double byteStrideValue = 0.0;
|
if (!ParseUnsignedProperty(&byteStride, err, o, "byteStride", false)) {
|
||||||
if (!ParseNumberProperty(&byteStrideValue, err, o, "byteStride", false)) {
|
|
||||||
// Spec says: When byteStride of referenced bufferView is not defined, it
|
// Spec says: When byteStride of referenced bufferView is not defined, it
|
||||||
// means that accessor elements are tightly packed, i.e., effective stride
|
// means that accessor elements are tightly packed, i.e., effective stride
|
||||||
// equals the size of the element.
|
// equals the size of the element.
|
||||||
// We cannot determine the actual byteStride until Accessor are parsed, thus
|
// We cannot determine the actual byteStride until Accessor are parsed, thus
|
||||||
// set 0(= tightly packed) here(as done in OpenGL's VertexAttribPoiner)
|
// set 0(= tightly packed) here(as done in OpenGL's VertexAttribPoiner)
|
||||||
byteStride = 0;
|
byteStride = 0;
|
||||||
} else {
|
|
||||||
byteStride = static_cast<size_t>(byteStrideValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((byteStride > 252) || ((byteStride % 4) != 0)) {
|
if ((byteStride > 252) || ((byteStride % 4) != 0)) {
|
||||||
@ -2841,23 +2962,22 @@ static bool ParseBufferView(BufferView *bufferView, std::string *err,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
double target = 0.0;
|
int target = 0;
|
||||||
ParseNumberProperty(&target, err, o, "target", false);
|
ParseIntegerProperty(&target, err, o, "target", false);
|
||||||
int targetValue = static_cast<int>(target);
|
if ((target == TINYGLTF_TARGET_ARRAY_BUFFER) ||
|
||||||
if ((targetValue == TINYGLTF_TARGET_ARRAY_BUFFER) ||
|
(target == TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER)) {
|
||||||
(targetValue == TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER)) {
|
|
||||||
// OK
|
// OK
|
||||||
} else {
|
} else {
|
||||||
targetValue = 0;
|
target = 0;
|
||||||
}
|
}
|
||||||
bufferView->target = targetValue;
|
bufferView->target = target;
|
||||||
|
|
||||||
ParseStringProperty(&bufferView->name, err, o, "name", false);
|
ParseStringProperty(&bufferView->name, err, o, "name", false);
|
||||||
|
|
||||||
bufferView->buffer = static_cast<int>(buffer);
|
bufferView->buffer = buffer;
|
||||||
bufferView->byteOffset = static_cast<size_t>(byteOffset);
|
bufferView->byteOffset = byteOffset;
|
||||||
bufferView->byteLength = static_cast<size_t>(byteLength);
|
bufferView->byteLength = byteLength;
|
||||||
bufferView->byteStride = static_cast<size_t>(byteStride);
|
bufferView->byteStride = byteStride;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2865,8 +2985,8 @@ static bool ParseSparseAccessor(Accessor *accessor, std::string *err,
|
|||||||
const json &o) {
|
const json &o) {
|
||||||
accessor->sparse.isSparse = true;
|
accessor->sparse.isSparse = true;
|
||||||
|
|
||||||
double count = 0.0;
|
int count = 0;
|
||||||
ParseNumberProperty(&count, err, o, "count", true);
|
ParseIntegerProperty(&count, err, o, "count", true);
|
||||||
|
|
||||||
const auto indices_iterator = o.find("indices");
|
const auto indices_iterator = o.find("indices");
|
||||||
const auto values_iterator = o.find("values");
|
const auto values_iterator = o.find("values");
|
||||||
@ -2883,24 +3003,26 @@ static bool ParseSparseAccessor(Accessor *accessor, std::string *err,
|
|||||||
const json &indices_obj = *indices_iterator;
|
const json &indices_obj = *indices_iterator;
|
||||||
const json &values_obj = *values_iterator;
|
const json &values_obj = *values_iterator;
|
||||||
|
|
||||||
double indices_buffer_view = 0.0, indices_byte_offset = 0.0,
|
int indices_buffer_view = 0, indices_byte_offset = 0, component_type = 0;
|
||||||
component_type = 0.0;
|
ParseIntegerProperty(&indices_buffer_view, err, indices_obj, "bufferView",
|
||||||
ParseNumberProperty(&indices_buffer_view, err, indices_obj, "bufferView",
|
true);
|
||||||
true);
|
ParseIntegerProperty(&indices_byte_offset, err, indices_obj, "byteOffset",
|
||||||
ParseNumberProperty(&indices_byte_offset, err, indices_obj, "byteOffset",
|
true);
|
||||||
true);
|
ParseIntegerProperty(&component_type, err, indices_obj, "componentType",
|
||||||
ParseNumberProperty(&component_type, err, indices_obj, "componentType", true);
|
true);
|
||||||
|
|
||||||
double values_buffer_view = 0.0, values_byte_offset = 0.0;
|
int values_buffer_view = 0, values_byte_offset = 0;
|
||||||
ParseNumberProperty(&values_buffer_view, err, values_obj, "bufferView", true);
|
ParseIntegerProperty(&values_buffer_view, err, values_obj, "bufferView",
|
||||||
ParseNumberProperty(&values_byte_offset, err, values_obj, "byteOffset", true);
|
true);
|
||||||
|
ParseIntegerProperty(&values_byte_offset, err, values_obj, "byteOffset",
|
||||||
|
true);
|
||||||
|
|
||||||
accessor->sparse.count = static_cast<int>(count);
|
accessor->sparse.count = count;
|
||||||
accessor->sparse.indices.bufferView = static_cast<int>(indices_buffer_view);
|
accessor->sparse.indices.bufferView = indices_buffer_view;
|
||||||
accessor->sparse.indices.byteOffset = static_cast<int>(indices_byte_offset);
|
accessor->sparse.indices.byteOffset = indices_byte_offset;
|
||||||
accessor->sparse.indices.componentType = static_cast<int>(component_type);
|
accessor->sparse.indices.componentType = component_type;
|
||||||
accessor->sparse.values.bufferView = static_cast<int>(values_buffer_view);
|
accessor->sparse.values.bufferView = values_buffer_view;
|
||||||
accessor->sparse.values.byteOffset = static_cast<int>(values_byte_offset);
|
accessor->sparse.values.byteOffset = values_byte_offset;
|
||||||
|
|
||||||
// todo check theses values
|
// todo check theses values
|
||||||
|
|
||||||
@ -2908,23 +3030,23 @@ static bool ParseSparseAccessor(Accessor *accessor, std::string *err,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool ParseAccessor(Accessor *accessor, std::string *err, const json &o) {
|
static bool ParseAccessor(Accessor *accessor, std::string *err, const json &o) {
|
||||||
double bufferView = -1.0;
|
int bufferView = -1;
|
||||||
ParseNumberProperty(&bufferView, err, o, "bufferView", false, "Accessor");
|
ParseIntegerProperty(&bufferView, err, o, "bufferView", false, "Accessor");
|
||||||
|
|
||||||
double byteOffset = 0.0;
|
size_t byteOffset = 0;
|
||||||
ParseNumberProperty(&byteOffset, err, o, "byteOffset", false, "Accessor");
|
ParseUnsignedProperty(&byteOffset, err, o, "byteOffset", false, "Accessor");
|
||||||
|
|
||||||
bool normalized = false;
|
bool normalized = false;
|
||||||
ParseBooleanProperty(&normalized, err, o, "normalized", false, "Accessor");
|
ParseBooleanProperty(&normalized, err, o, "normalized", false, "Accessor");
|
||||||
|
|
||||||
double componentType = 0.0;
|
size_t componentType = 0;
|
||||||
if (!ParseNumberProperty(&componentType, err, o, "componentType", true,
|
if (!ParseUnsignedProperty(&componentType, err, o, "componentType", true,
|
||||||
"Accessor")) {
|
"Accessor")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
double count = 0.0;
|
size_t count = 0;
|
||||||
if (!ParseNumberProperty(&count, err, o, "count", true, "Accessor")) {
|
if (!ParseUnsignedProperty(&count, err, o, "count", true, "Accessor")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2966,19 +3088,19 @@ static bool ParseAccessor(Accessor *accessor, std::string *err, const json &o) {
|
|||||||
ParseNumberArrayProperty(&accessor->maxValues, err, o, "max", false,
|
ParseNumberArrayProperty(&accessor->maxValues, err, o, "max", false,
|
||||||
"Accessor");
|
"Accessor");
|
||||||
|
|
||||||
accessor->count = static_cast<size_t>(count);
|
accessor->count = count;
|
||||||
accessor->bufferView = static_cast<int>(bufferView);
|
accessor->bufferView = bufferView;
|
||||||
accessor->byteOffset = static_cast<size_t>(byteOffset);
|
accessor->byteOffset = byteOffset;
|
||||||
accessor->normalized = normalized;
|
accessor->normalized = normalized;
|
||||||
{
|
{
|
||||||
int comp = static_cast<int>(componentType);
|
if (componentType >= TINYGLTF_COMPONENT_TYPE_BYTE &&
|
||||||
if (comp >= TINYGLTF_COMPONENT_TYPE_BYTE &&
|
componentType <= TINYGLTF_COMPONENT_TYPE_DOUBLE) {
|
||||||
comp <= TINYGLTF_COMPONENT_TYPE_DOUBLE) {
|
|
||||||
// OK
|
// OK
|
||||||
accessor->componentType = comp;
|
accessor->componentType = componentType;
|
||||||
} else {
|
} else {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Invalid `componentType` in accessor. Got " << comp << "\n";
|
ss << "Invalid `componentType` in accessor. Got " << componentType
|
||||||
|
<< "\n";
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) += ss.str();
|
(*err) += ss.str();
|
||||||
}
|
}
|
||||||
@ -3192,21 +3314,19 @@ static bool ParseDracoExtension(Primitive *primitive, Model *model,
|
|||||||
|
|
||||||
static bool ParsePrimitive(Primitive *primitive, Model *model, std::string *err,
|
static bool ParsePrimitive(Primitive *primitive, Model *model, std::string *err,
|
||||||
const json &o) {
|
const json &o) {
|
||||||
double material = -1.0;
|
int material = -1;
|
||||||
ParseNumberProperty(&material, err, o, "material", false);
|
ParseIntegerProperty(&material, err, o, "material", false);
|
||||||
primitive->material = static_cast<int>(material);
|
primitive->material = material;
|
||||||
|
|
||||||
double mode = static_cast<double>(TINYGLTF_MODE_TRIANGLES);
|
int mode = TINYGLTF_MODE_TRIANGLES;
|
||||||
ParseNumberProperty(&mode, err, o, "mode", false);
|
ParseIntegerProperty(&mode, err, o, "mode", false);
|
||||||
|
primitive->mode = mode; // Why only triangled were supported ?
|
||||||
|
|
||||||
int primMode = static_cast<int>(mode);
|
int indices = -1;
|
||||||
primitive->mode = primMode; // Why only triangled were supported ?
|
ParseIntegerProperty(&indices, err, o, "indices", false);
|
||||||
|
primitive->indices = indices;
|
||||||
double indices = -1.0;
|
if (!ParseStringIntegerProperty(&primitive->attributes, err, o, "attributes",
|
||||||
ParseNumberProperty(&indices, err, o, "indices", false);
|
true, "Primitive")) {
|
||||||
primitive->indices = static_cast<int>(indices);
|
|
||||||
if (!ParseStringIntProperty(&primitive->attributes, err, o, "attributes",
|
|
||||||
true, "Primitive")) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3299,9 +3419,9 @@ static bool ParseLight(Light *light, std::string *err, const json &o) {
|
|||||||
static bool ParseNode(Node *node, std::string *err, const json &o) {
|
static bool ParseNode(Node *node, std::string *err, const json &o) {
|
||||||
ParseStringProperty(&node->name, err, o, "name", false);
|
ParseStringProperty(&node->name, err, o, "name", false);
|
||||||
|
|
||||||
double skin = -1.0;
|
int skin = -1;
|
||||||
ParseNumberProperty(&skin, err, o, "skin", false);
|
ParseIntegerProperty(&skin, err, o, "skin", false);
|
||||||
node->skin = static_cast<int>(skin);
|
node->skin = skin;
|
||||||
|
|
||||||
// Matrix and T/R/S are exclusive
|
// Matrix and T/R/S are exclusive
|
||||||
if (!ParseNumberArrayProperty(&node->matrix, err, o, "matrix", false)) {
|
if (!ParseNumberArrayProperty(&node->matrix, err, o, "matrix", false)) {
|
||||||
@ -3310,29 +3430,16 @@ static bool ParseNode(Node *node, std::string *err, const json &o) {
|
|||||||
ParseNumberArrayProperty(&node->translation, err, o, "translation", false);
|
ParseNumberArrayProperty(&node->translation, err, o, "translation", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
double camera = -1.0;
|
int camera = -1;
|
||||||
ParseNumberProperty(&camera, err, o, "camera", false);
|
ParseIntegerProperty(&camera, err, o, "camera", false);
|
||||||
node->camera = static_cast<int>(camera);
|
node->camera = camera;
|
||||||
|
|
||||||
double mesh = -1.0;
|
int mesh = -1;
|
||||||
ParseNumberProperty(&mesh, err, o, "mesh", false);
|
ParseIntegerProperty(&mesh, err, o, "mesh", false);
|
||||||
node->mesh = int(mesh);
|
node->mesh = mesh;
|
||||||
|
|
||||||
node->children.clear();
|
node->children.clear();
|
||||||
json::const_iterator childrenObject = o.find("children");
|
ParseIntegerArrayProperty(&node->children, err, o, "children", false);
|
||||||
if ((childrenObject != o.end()) && childrenObject.value().is_array()) {
|
|
||||||
for (json::const_iterator i = childrenObject.value().begin();
|
|
||||||
i != childrenObject.value().end(); i++) {
|
|
||||||
if (!i.value().is_number()) {
|
|
||||||
if (err) {
|
|
||||||
(*err) += "Invalid `children` array.\n";
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const int &childrenNode = static_cast<int>(i.value());
|
|
||||||
node->children.push_back(childrenNode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ParseExtensionsProperty(&node->extensions, err, o);
|
ParseExtensionsProperty(&node->extensions, err, o);
|
||||||
ParseExtrasProperty(&(node->extras), o);
|
ParseExtrasProperty(&(node->extras), o);
|
||||||
@ -3383,10 +3490,10 @@ static bool ParseMaterial(Material *material, std::string *err, const json &o) {
|
|||||||
|
|
||||||
static bool ParseAnimationChannel(AnimationChannel *channel, std::string *err,
|
static bool ParseAnimationChannel(AnimationChannel *channel, std::string *err,
|
||||||
const json &o) {
|
const json &o) {
|
||||||
double samplerIndex = -1.0;
|
int samplerIndex = -1;
|
||||||
double targetIndex = -1.0;
|
int targetIndex = -1;
|
||||||
if (!ParseNumberProperty(&samplerIndex, err, o, "sampler", true,
|
if (!ParseIntegerProperty(&samplerIndex, err, o, "sampler", true,
|
||||||
"AnimationChannel")) {
|
"AnimationChannel")) {
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) += "`sampler` field is missing in animation channels\n";
|
(*err) += "`sampler` field is missing in animation channels\n";
|
||||||
}
|
}
|
||||||
@ -3397,7 +3504,7 @@ static bool ParseAnimationChannel(AnimationChannel *channel, std::string *err,
|
|||||||
if ((targetIt != o.end()) && targetIt.value().is_object()) {
|
if ((targetIt != o.end()) && targetIt.value().is_object()) {
|
||||||
const json &target_object = targetIt.value();
|
const json &target_object = targetIt.value();
|
||||||
|
|
||||||
if (!ParseNumberProperty(&targetIndex, err, target_object, "node", true)) {
|
if (!ParseIntegerProperty(&targetIndex, err, target_object, "node", true)) {
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) += "`node` field is missing in animation.channels.target\n";
|
(*err) += "`node` field is missing in animation.channels.target\n";
|
||||||
}
|
}
|
||||||
@ -3413,8 +3520,8 @@ static bool ParseAnimationChannel(AnimationChannel *channel, std::string *err,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
channel->sampler = static_cast<int>(samplerIndex);
|
channel->sampler = samplerIndex;
|
||||||
channel->target_node = static_cast<int>(targetIndex);
|
channel->target_node = targetIndex;
|
||||||
|
|
||||||
ParseExtrasProperty(&(channel->extras), o);
|
ParseExtrasProperty(&(channel->extras), o);
|
||||||
|
|
||||||
@ -3449,9 +3556,9 @@ static bool ParseAnimation(Animation *animation, std::string *err,
|
|||||||
const json &s = it->get<json>();
|
const json &s = it->get<json>();
|
||||||
|
|
||||||
AnimationSampler sampler;
|
AnimationSampler sampler;
|
||||||
double inputIndex = -1.0;
|
int inputIndex = -1;
|
||||||
double outputIndex = -1.0;
|
int outputIndex = -1;
|
||||||
if (!ParseNumberProperty(&inputIndex, err, s, "input", true)) {
|
if (!ParseIntegerProperty(&inputIndex, err, s, "input", true)) {
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) += "`input` field is missing in animation.sampler\n";
|
(*err) += "`input` field is missing in animation.sampler\n";
|
||||||
}
|
}
|
||||||
@ -3459,14 +3566,14 @@ static bool ParseAnimation(Animation *animation, std::string *err,
|
|||||||
}
|
}
|
||||||
ParseStringProperty(&sampler.interpolation, err, s, "interpolation",
|
ParseStringProperty(&sampler.interpolation, err, s, "interpolation",
|
||||||
false);
|
false);
|
||||||
if (!ParseNumberProperty(&outputIndex, err, s, "output", true)) {
|
if (!ParseIntegerProperty(&outputIndex, err, s, "output", true)) {
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) += "`output` field is missing in animation.sampler\n";
|
(*err) += "`output` field is missing in animation.sampler\n";
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
sampler.input = static_cast<int>(inputIndex);
|
sampler.input = inputIndex;
|
||||||
sampler.output = static_cast<int>(outputIndex);
|
sampler.output = outputIndex;
|
||||||
ParseExtrasProperty(&(sampler.extras), s);
|
ParseExtrasProperty(&(sampler.extras), s);
|
||||||
animation->samplers.push_back(sampler);
|
animation->samplers.push_back(sampler);
|
||||||
}
|
}
|
||||||
@ -3483,20 +3590,19 @@ static bool ParseAnimation(Animation *animation, std::string *err,
|
|||||||
static bool ParseSampler(Sampler *sampler, std::string *err, const json &o) {
|
static bool ParseSampler(Sampler *sampler, std::string *err, const json &o) {
|
||||||
ParseStringProperty(&sampler->name, err, o, "name", false);
|
ParseStringProperty(&sampler->name, err, o, "name", false);
|
||||||
|
|
||||||
double minFilter =
|
int minFilter = TINYGLTF_TEXTURE_FILTER_NEAREST_MIPMAP_LINEAR;
|
||||||
static_cast<double>(TINYGLTF_TEXTURE_FILTER_NEAREST_MIPMAP_LINEAR);
|
int magFilter = TINYGLTF_TEXTURE_FILTER_LINEAR;
|
||||||
double magFilter = static_cast<double>(TINYGLTF_TEXTURE_FILTER_LINEAR);
|
int wrapS = TINYGLTF_TEXTURE_WRAP_REPEAT;
|
||||||
double wrapS = static_cast<double>(TINYGLTF_TEXTURE_WRAP_REPEAT);
|
int wrapT = TINYGLTF_TEXTURE_WRAP_REPEAT;
|
||||||
double wrapT = static_cast<double>(TINYGLTF_TEXTURE_WRAP_REPEAT);
|
ParseIntegerProperty(&minFilter, err, o, "minFilter", false);
|
||||||
ParseNumberProperty(&minFilter, err, o, "minFilter", false);
|
ParseIntegerProperty(&magFilter, err, o, "magFilter", false);
|
||||||
ParseNumberProperty(&magFilter, err, o, "magFilter", false);
|
ParseIntegerProperty(&wrapS, err, o, "wrapS", false);
|
||||||
ParseNumberProperty(&wrapS, err, o, "wrapS", false);
|
ParseIntegerProperty(&wrapT, err, o, "wrapT", false);
|
||||||
ParseNumberProperty(&wrapT, err, o, "wrapT", false);
|
|
||||||
|
|
||||||
sampler->minFilter = static_cast<int>(minFilter);
|
sampler->minFilter = minFilter;
|
||||||
sampler->magFilter = static_cast<int>(magFilter);
|
sampler->magFilter = magFilter;
|
||||||
sampler->wrapS = static_cast<int>(wrapS);
|
sampler->wrapS = wrapS;
|
||||||
sampler->wrapT = static_cast<int>(wrapT);
|
sampler->wrapT = wrapT;
|
||||||
|
|
||||||
ParseExtrasProperty(&(sampler->extras), o);
|
ParseExtrasProperty(&(sampler->extras), o);
|
||||||
|
|
||||||
@ -3506,23 +3612,19 @@ static bool ParseSampler(Sampler *sampler, std::string *err, const json &o) {
|
|||||||
static bool ParseSkin(Skin *skin, std::string *err, const json &o) {
|
static bool ParseSkin(Skin *skin, std::string *err, const json &o) {
|
||||||
ParseStringProperty(&skin->name, err, o, "name", false, "Skin");
|
ParseStringProperty(&skin->name, err, o, "name", false, "Skin");
|
||||||
|
|
||||||
std::vector<double> joints;
|
std::vector<int> joints;
|
||||||
if (!ParseNumberArrayProperty(&joints, err, o, "joints", false, "Skin")) {
|
if (!ParseIntegerArrayProperty(&joints, err, o, "joints", false, "Skin")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
skin->joints = std::move(joints);
|
||||||
|
|
||||||
double skeleton = -1.0;
|
int skeleton = -1;
|
||||||
ParseNumberProperty(&skeleton, err, o, "skeleton", false, "Skin");
|
ParseIntegerProperty(&skeleton, err, o, "skeleton", false, "Skin");
|
||||||
skin->skeleton = static_cast<int>(skeleton);
|
skin->skeleton = skeleton;
|
||||||
|
|
||||||
skin->joints.resize(joints.size());
|
int invBind = -1;
|
||||||
for (size_t i = 0; i < joints.size(); i++) {
|
ParseIntegerProperty(&invBind, err, o, "inverseBindMatrices", true, "Skin");
|
||||||
skin->joints[i] = static_cast<int>(joints[i]);
|
skin->inverseBindMatrices = invBind;
|
||||||
}
|
|
||||||
|
|
||||||
double invBind = -1.0;
|
|
||||||
ParseNumberProperty(&invBind, err, o, "inverseBindMatrices", true, "Skin");
|
|
||||||
skin->inverseBindMatrices = static_cast<int>(invBind);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -3999,18 +4101,15 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const json &o = it->get<json>();
|
const json &o = it->get<json>();
|
||||||
std::vector<double> nodes;
|
std::vector<int> nodes;
|
||||||
if (!ParseNumberArrayProperty(&nodes, err, o, "nodes", false)) {
|
if (!ParseIntegerArrayProperty(&nodes, err, o, "nodes", false)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Scene scene;
|
Scene scene;
|
||||||
|
scene.nodes = std::move(nodes);
|
||||||
|
|
||||||
ParseStringProperty(&scene.name, err, o, "name", false);
|
ParseStringProperty(&scene.name, err, o, "name", false);
|
||||||
std::vector<int> nodesIds;
|
|
||||||
for (size_t i = 0; i < nodes.size(); i++) {
|
|
||||||
nodesIds.push_back(static_cast<int>(nodes[i]));
|
|
||||||
}
|
|
||||||
scene.nodes = nodesIds;
|
|
||||||
|
|
||||||
ParseExtensionsProperty(&scene.extensions, err, o);
|
ParseExtensionsProperty(&scene.extensions, err, o);
|
||||||
ParseExtrasProperty(&scene.extras, o);
|
ParseExtrasProperty(&scene.extras, o);
|
||||||
@ -4023,10 +4122,10 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
|
|||||||
// 9. Parse default scenes.
|
// 9. Parse default scenes.
|
||||||
{
|
{
|
||||||
json::const_iterator rootIt = v.find("scene");
|
json::const_iterator rootIt = v.find("scene");
|
||||||
if ((rootIt != v.end()) && rootIt.value().is_number()) {
|
if ((rootIt != v.end()) && rootIt.value().is_number_integer()) {
|
||||||
const int defaultScene = rootIt.value();
|
const int defaultScene = rootIt.value();
|
||||||
|
|
||||||
model->defaultScene = static_cast<int>(defaultScene);
|
model->defaultScene = defaultScene;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user