mirror of
https://git.mirrors.martin98.com/https://github.com/syoyo/tinygltf.git
synced 2025-08-15 09:35:56 +08:00
Merge pull request #160 from jwmcglynn/parse-integer
Parse integers directly instead of casting doubles
This commit is contained in:
commit
d11a4c4d71
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"
|
||||||
|
}
|
||||||
|
}
|
131
tests/tester.cc
131
tests/tester.cc
@ -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"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
423
tiny_gltf.h
423
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,9 +2513,10 @@ 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,
|
||||||
|
bool required,
|
||||||
const std::string &parent = "") {
|
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()) {
|
||||||
@ -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);
|
||||||
ParseNumberProperty(&indices_byte_offset, err, indices_obj, "byteOffset",
|
ParseIntegerProperty(&indices_byte_offset, err, indices_obj, "byteOffset",
|
||||||
|
true);
|
||||||
|
ParseIntegerProperty(&component_type, err, indices_obj, "componentType",
|
||||||
true);
|
true);
|
||||||
ParseNumberProperty(&component_type, err, indices_obj, "componentType", 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,20 +3314,18 @@ 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);
|
|
||||||
primitive->indices = static_cast<int>(indices);
|
|
||||||
if (!ParseStringIntProperty(&primitive->attributes, err, o, "attributes",
|
|
||||||
true, "Primitive")) {
|
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,9 +3490,9 @@ 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