Revert "Support simultaneous gltf load/saves (TINYGLTF_USE_RAPIDJSON_CRTALLOCATOR)"

This reverts commit ab63db63188375dfa4f4b70383365c9b3f0a85b4.
This commit is contained in:
jrkoonce 2019-09-04 12:15:51 -05:00
parent ab63db6318
commit 95f05757d6
4 changed files with 69 additions and 6975 deletions

View File

@ -4,7 +4,7 @@
#define TINYGLTF_IMPLEMENTATION #define TINYGLTF_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION #define STB_IMAGE_WRITE_IMPLEMENTATION
#define TINYGLTF_USE_RAPIDJSON //#define TINYGLTF_USE_RAPIDJSON
#include "tiny_gltf.h" #include "tiny_gltf.h"
#include <cstdio> #include <cstdio>

View File

@ -1,35 +1,33 @@
#define TINYGLTF_IMPLEMENTATION #define TINYGLTF_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION #define STB_IMAGE_WRITE_IMPLEMENTATION
#define TINYGLTF_USE_RAPIDJSON
#define TINYGLTF_USE_RAPIDJSON_CRTALLOCATOR
#include "tiny_gltf.h" #include "tiny_gltf.h"
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do #define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
// this in one cpp file
#include "catch.hpp" #include "catch.hpp"
#include <cassert>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <fstream> #include <cassert>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <fstream>
TEST_CASE("parse-error", "[parse]") { TEST_CASE("parse-error", "[parse]") {
tinygltf::Model model; tinygltf::Model model;
tinygltf::TinyGLTF ctx; tinygltf::TinyGLTF ctx;
std::string err; std::string err;
std::string warn; std::string warn;
bool ret = ctx.LoadASCIIFromString(&model, &err, &warn, "bora", bool ret = ctx.LoadASCIIFromString(&model, &err, &warn, "bora", static_cast<int>(strlen("bora")), /* basedir*/ "");
static_cast<int>(strlen("bora")),
/* basedir*/ "");
REQUIRE(false == ret); REQUIRE(false == ret);
} }
TEST_CASE("datauri-in-glb", "[issue-79]") { TEST_CASE("datauri-in-glb", "[issue-79]") {
tinygltf::Model model; tinygltf::Model model;
tinygltf::TinyGLTF ctx; tinygltf::TinyGLTF ctx;
std::string err; std::string err;
@ -44,13 +42,13 @@ TEST_CASE("datauri-in-glb", "[issue-79]") {
} }
TEST_CASE("extension-with-empty-object", "[issue-97]") { TEST_CASE("extension-with-empty-object", "[issue-97]") {
tinygltf::Model model; tinygltf::Model model;
tinygltf::TinyGLTF ctx; tinygltf::TinyGLTF ctx;
std::string err; std::string err;
std::string warn; std::string warn;
bool ret = ctx.LoadASCIIFromFile(&model, &err, &warn, bool ret = ctx.LoadASCIIFromFile(&model, &err, &warn, "../models/Extensions-issue97/test.gltf");
"../models/Extensions-issue97/test.gltf");
if (!err.empty()) { if (!err.empty()) {
std::cerr << err << std::endl; std::cerr << err << std::endl;
} }
@ -84,6 +82,7 @@ TEST_CASE("extension-with-empty-object", "[issue-97]") {
REQUIRE(m.materials[0].extensions.size() == 1); REQUIRE(m.materials[0].extensions.size() == 1);
REQUIRE(m.materials[0].extensions.count("VENDOR_material_some_ext") == 1); REQUIRE(m.materials[0].extensions.count("VENDOR_material_some_ext") == 1);
} }
} }
TEST_CASE("invalid-primitive-indices", "[bounds-checking]") { TEST_CASE("invalid-primitive-indices", "[bounds-checking]") {
@ -138,13 +137,10 @@ TEST_CASE("glb-invalid-length", "[bounds-checking]") {
// This glb has a much longer length than the provided data and should fail // This glb has a much longer length than the provided data and should fail
// initial range checks. // initial range checks.
const unsigned char glb_invalid_length[] = const unsigned char glb_invalid_length[] = "glTF"
"glTF" "\x20\x00\x00\x00" "\x6c\x66\x00\x00" //
"\x20\x00\x00\x00"
"\x6c\x66\x00\x00" //
// | version | length | // | version | length |
"\x02\x00\x00\x00" "\x02\x00\x00\x00" "\x4a\x53\x4f\x4e{}"; //
"\x4a\x53\x4f\x4e{}"; //
// | model length | model format | // | model length | model format |
bool ret = ctx.LoadBinaryFromMemory(&model, &err, &warn, glb_invalid_length, bool ret = ctx.LoadBinaryFromMemory(&model, &err, &warn, glb_invalid_length,
@ -171,13 +167,13 @@ TEST_CASE("parse-integer", "[bounds-checking]") {
SECTION("parses valid numbers") { SECTION("parses valid numbers") {
std::string err; std::string err;
int result = 123; int result = 123;
CHECK(tinygltf::ParseIntegerProperty( CHECK(tinygltf::ParseIntegerProperty(&result, &err, JsonConstruct("{\"zero\" : 0}"), "zero",
&result, &err, JsonConstruct("{\"zero\" : 0}"), "zero", true)); true));
REQUIRE(err == ""); REQUIRE(err == "");
REQUIRE(result == 0); REQUIRE(result == 0);
CHECK(tinygltf::ParseIntegerProperty( CHECK(tinygltf::ParseIntegerProperty(&result, &err, JsonConstruct("{\"int\": -1234}"), "int",
&result, &err, JsonConstruct("{\"int\": -1234}"), "int", true)); true));
REQUIRE(err == ""); REQUIRE(err == "");
REQUIRE(result == -1234); REQUIRE(result == -1234);
} }
@ -185,8 +181,7 @@ TEST_CASE("parse-integer", "[bounds-checking]") {
SECTION("detects missing properties") { SECTION("detects missing properties") {
std::string err; std::string err;
int result = -1; int result = -1;
CHECK_FALSE(tinygltf::ParseIntegerProperty(&result, &err, JsonConstruct(""), CHECK_FALSE(tinygltf::ParseIntegerProperty(&result, &err, JsonConstruct(""), "int", true));
"int", true));
REQUIRE_THAT(err, Catch::Contains("'int' property is missing")); REQUIRE_THAT(err, Catch::Contains("'int' property is missing"));
REQUIRE(result == -1); REQUIRE(result == -1);
} }
@ -194,8 +189,8 @@ TEST_CASE("parse-integer", "[bounds-checking]") {
SECTION("handled missing but not required properties") { SECTION("handled missing but not required properties") {
std::string err; std::string err;
int result = -1; int result = -1;
CHECK_FALSE(tinygltf::ParseIntegerProperty(&result, &err, JsonConstruct(""), CHECK_FALSE(
"int", false)); tinygltf::ParseIntegerProperty(&result, &err, JsonConstruct(""), "int", false));
REQUIRE(err == ""); REQUIRE(err == "");
REQUIRE(result == -1); REQUIRE(result == -1);
} }
@ -204,14 +199,14 @@ TEST_CASE("parse-integer", "[bounds-checking]") {
std::string err; std::string err;
int result = -1; int result = -1;
CHECK_FALSE(tinygltf::ParseIntegerProperty( CHECK_FALSE(tinygltf::ParseIntegerProperty(&result, &err, JsonConstruct("{\"int\": 0.5}"),
&result, &err, JsonConstruct("{\"int\": 0.5}"), "int", true)); "int", true));
REQUIRE_THAT(err, Catch::Contains("not an integer type")); REQUIRE_THAT(err, Catch::Contains("not an integer type"));
// Excessively large values and NaN aren't allowed either. // Excessively large values and NaN aren't allowed either.
err.clear(); err.clear();
CHECK_FALSE(tinygltf::ParseIntegerProperty( CHECK_FALSE(tinygltf::ParseIntegerProperty(&result, &err, JsonConstruct("{\"int\": 1e300}"),
&result, &err, JsonConstruct("{\"int\": 1e300}"), "int", true)); "int", true));
REQUIRE_THAT(err, Catch::Contains("not an integer type")); REQUIRE_THAT(err, Catch::Contains("not an integer type"));
err.clear(); err.clear();
@ -219,8 +214,9 @@ TEST_CASE("parse-integer", "[bounds-checking]") {
JsonDocument o; JsonDocument o;
double nan = std::numeric_limits<double>::quiet_NaN(); double nan = std::numeric_limits<double>::quiet_NaN();
tinygltf::JsonAddMember(o, "int", json(nan)); tinygltf::JsonAddMember(o, "int", json(nan));
CHECK_FALSE( CHECK_FALSE(tinygltf::ParseIntegerProperty(
tinygltf::ParseIntegerProperty(&result, &err, o, "int", true)); &result, &err, o,
"int", true));
REQUIRE_THAT(err, Catch::Contains("not an integer type")); REQUIRE_THAT(err, Catch::Contains("not an integer type"));
} }
} }
@ -244,19 +240,19 @@ TEST_CASE("parse-unsigned", "[bounds-checking]") {
std::string err; std::string err;
size_t result = -1; size_t result = -1;
CHECK_FALSE(tinygltf::ParseUnsignedProperty( CHECK_FALSE(tinygltf::ParseUnsignedProperty(&result, &err, JsonConstruct("{\"int\": -1234}"),
&result, &err, JsonConstruct("{\"int\": -1234}"), "int", true)); "int", true));
REQUIRE_THAT(err, Catch::Contains("not a positive integer")); REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
err.clear(); err.clear();
CHECK_FALSE(tinygltf::ParseUnsignedProperty( CHECK_FALSE(tinygltf::ParseUnsignedProperty(&result, &err, JsonConstruct("{\"int\": 0.5}"),
&result, &err, JsonConstruct("{\"int\": 0.5}"), "int", true)); "int", true));
REQUIRE_THAT(err, Catch::Contains("not a positive integer")); REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
// Excessively large values and NaN aren't allowed either. // Excessively large values and NaN aren't allowed either.
err.clear(); err.clear();
CHECK_FALSE(tinygltf::ParseUnsignedProperty( CHECK_FALSE(tinygltf::ParseUnsignedProperty(&result, &err, JsonConstruct("{\"int\": 1e300}"),
&result, &err, JsonConstruct("{\"int\": 1e300}"), "int", true)); "int", true));
REQUIRE_THAT(err, Catch::Contains("not a positive integer")); REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
err.clear(); err.clear();
@ -264,8 +260,9 @@ TEST_CASE("parse-unsigned", "[bounds-checking]") {
JsonDocument o; JsonDocument o;
double nan = std::numeric_limits<double>::quiet_NaN(); double nan = std::numeric_limits<double>::quiet_NaN();
tinygltf::JsonAddMember(o, "int", json(nan)); tinygltf::JsonAddMember(o, "int", json(nan));
CHECK_FALSE( CHECK_FALSE(tinygltf::ParseUnsignedProperty(
tinygltf::ParseUnsignedProperty(&result, &err, o, "int", true)); &result, &err, o,
"int", true));
REQUIRE_THAT(err, Catch::Contains("not a positive integer")); REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
} }
} }
@ -275,8 +272,8 @@ TEST_CASE("parse-integer-array", "[bounds-checking]") {
SECTION("parses valid integers") { SECTION("parses valid integers") {
std::string err; std::string err;
std::vector<int> result; std::vector<int> result;
CHECK(tinygltf::ParseIntegerArrayProperty( CHECK(tinygltf::ParseIntegerArrayProperty(&result, &err,
&result, &err, JsonConstruct("{\"x\": [-1, 2, 3]}"), "x", true)); JsonConstruct("{\"x\": [-1, 2, 3]}"), "x", true));
REQUIRE(err == ""); REQUIRE(err == "");
REQUIRE(result.size() == 3); REQUIRE(result.size() == 3);
REQUIRE(result[0] == -1); REQUIRE(result[0] == -1);
@ -301,27 +298,22 @@ TEST_CASE("pbr-khr-texture-transform", "[material]") {
// Loading is expected to fail, but not crash. // Loading is expected to fail, but not crash.
bool ret = ctx.LoadASCIIFromFile( bool ret = ctx.LoadASCIIFromFile(
&model, &err, &warn, "../models/Cube-texture-ext/Cube-textransform.gltf"); &model, &err, &warn,
"../models/Cube-texture-ext/Cube-textransform.gltf");
REQUIRE(ret == true); REQUIRE(ret == true);
REQUIRE(model.materials.size() == 2); REQUIRE(model.materials.size() == 2);
REQUIRE(model.materials[0].emissiveTexture.extensions.count( REQUIRE(model.materials[0].emissiveTexture.extensions.count("KHR_texture_transform") == 1);
"KHR_texture_transform") == 1); REQUIRE(model.materials[0].emissiveTexture.extensions["KHR_texture_transform"].IsObject());
REQUIRE(model.materials[0]
.emissiveTexture.extensions["KHR_texture_transform"]
.IsObject());
tinygltf::Value::Object &texform = tinygltf::Value::Object &texform = model.materials[0].emissiveTexture.extensions["KHR_texture_transform"].Get<tinygltf::Value::Object>();
model.materials[0]
.emissiveTexture.extensions["KHR_texture_transform"]
.Get<tinygltf::Value::Object>();
REQUIRE(texform.count("scale")); REQUIRE(texform.count("scale"));
REQUIRE(texform["scale"].IsArray()); REQUIRE(texform["scale"].IsArray());
// Note: It looks json.hpp parse integer JSON number as integer, not floating // Note: It looks json.hpp parse integer JSON number as integer, not floating point.
// point. IsNumber return true either value is int or floating point. // IsNumber return true either value is int or floating point.
REQUIRE(texform["scale"].Get(0).IsNumber()); REQUIRE(texform["scale"].Get(0).IsNumber());
REQUIRE(texform["scale"].Get(1).IsNumber()); REQUIRE(texform["scale"].Get(1).IsNumber());
@ -331,4 +323,5 @@ TEST_CASE("pbr-khr-texture-transform", "[material]") {
REQUIRE(scale[0] == Approx(1.0)); REQUIRE(scale[0] == Approx(1.0));
REQUIRE(scale[1] == Approx(-1.0)); REQUIRE(scale[1] == Approx(-1.0));
} }

File diff suppressed because it is too large Load Diff

View File

@ -1650,52 +1650,33 @@ class TinyGLTF {
namespace namespace
{ {
#ifdef TINYGLTF_USE_RAPIDJSON #ifdef TINYGLTF_USE_RAPIDJSON
#ifdef TINYGLTF_USE_RAPIDJSON_CRTALLOCATOR
// This uses the RapidJSON CRTAllocator. It is thread safe and multiple
// documents may be active at once.
using json = rapidjson::GenericValue<rapidjson::UTF8<>, rapidjson::CrtAllocator>;
using json_const_iterator = json::ConstMemberIterator;
using json_const_array_iterator = json const *;
using JsonDocument =
rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator>;
rapidjson::CrtAllocator s_CrtAllocator; //stateless and thread safe
rapidjson::CrtAllocator &GetAllocator() { return s_CrtAllocator; }
#else
// This uses the default RapidJSON MemoryPoolAllocator. It is very fast, but
// not thread safe. Only a single JsonDocument may be active at any one time,
// meaning only a single gltf load/save can be active any one time.
using json = rapidjson::Value; using json = rapidjson::Value;
using json_const_iterator = json::ConstMemberIterator; using json_const_iterator = json::ConstMemberIterator;
using json_const_array_iterator = json const *; using json_const_array_iterator = json const*;
rapidjson::Document *s_pActiveDocument = nullptr;
rapidjson::Document::AllocatorType &GetAllocator() { rapidjson::Document* s_pActiveDocument = nullptr;
assert(s_pActiveDocument); //Root json node must be JsonDocument type
return s_pActiveDocument->GetAllocator(); struct JsonDocument : public rapidjson::Document
} {
struct JsonDocument : public rapidjson::Document {
JsonDocument() { JsonDocument() {
assert(s_pActiveDocument == assert(s_pActiveDocument == nullptr); //Code assumes only one document is active at a time
nullptr); // When using default allocator, only one document can be active at a time, if you need
// multiple active at once, define TINYGLTF_USE_RAPIDJSON_CRTALLOCATOR
s_pActiveDocument = this; s_pActiveDocument = this;
} }
JsonDocument(const JsonDocument &) = delete; JsonDocument(const JsonDocument&) = delete;
JsonDocument(JsonDocument &&rhs) noexcept JsonDocument(JsonDocument&& rhs) noexcept : rapidjson::Document(std::move(rhs))
: rapidjson::Document(std::move(rhs)) { {
s_pActiveDocument = this; s_pActiveDocument = this;
rhs.isNil = true; rhs.isNil = true;
} }
~JsonDocument() { ~JsonDocument() {
if (!isNil) { if (!isNil)
{
s_pActiveDocument = nullptr; s_pActiveDocument = nullptr;
} }
} }
private: private:
bool isNil = false; bool isNil = false;
}; };
#endif // TINYGLTF_USE_RAPIDJSON_CRTALLOCATOR
#else #else
using nlohmann::json; using nlohmann::json;
using json_const_iterator = json::const_iterator; using json_const_iterator = json::const_iterator;
@ -5693,7 +5674,7 @@ namespace
json JsonFromString(const char* s) json JsonFromString(const char* s)
{ {
#ifdef TINYGLTF_USE_RAPIDJSON #ifdef TINYGLTF_USE_RAPIDJSON
return json(s, GetAllocator()); return json(s, s_pActiveDocument->GetAllocator());
#else #else
return json(s); return json(s);
#endif #endif
@ -5724,7 +5705,7 @@ namespace
void JsonAssign(json& dest, const json& src) void JsonAssign(json& dest, const json& src)
{ {
#ifdef TINYGLTF_USE_RAPIDJSON #ifdef TINYGLTF_USE_RAPIDJSON
dest.CopyFrom(src, GetAllocator()); dest.CopyFrom(src, s_pActiveDocument->GetAllocator());
#else #else
dest = src; dest = src;
#endif #endif
@ -5737,7 +5718,7 @@ namespace
{ {
o.SetObject(); o.SetObject();
} }
o.AddMember(json(key, GetAllocator()), std::move(value), GetAllocator()); o.AddMember(json(key, s_pActiveDocument->GetAllocator()), std::move(value), s_pActiveDocument->GetAllocator());
#else #else
o[key] = std::move(value); o[key] = std::move(value);
#endif #endif
@ -5746,7 +5727,7 @@ namespace
void JsonPushBack(json& o, json&& value) void JsonPushBack(json& o, json&& value)
{ {
#ifdef TINYGLTF_USE_RAPIDJSON #ifdef TINYGLTF_USE_RAPIDJSON
o.PushBack(std::move(value), GetAllocator()); o.PushBack(std::move(value), s_pActiveDocument->GetAllocator());
#else #else
o.push_back(std::move(value)); o.push_back(std::move(value));
#endif #endif
@ -5774,7 +5755,7 @@ namespace
{ {
#ifdef TINYGLTF_USE_RAPIDJSON #ifdef TINYGLTF_USE_RAPIDJSON
o.SetArray(); o.SetArray();
o.Reserve(static_cast<rapidjson::SizeType>(s), GetAllocator()); o.Reserve(static_cast<rapidjson::SizeType>(s), s_pActiveDocument->GetAllocator());
#endif #endif
(void)(o); (void)(o);
(void)(s); (void)(s);
@ -5839,16 +5820,16 @@ static bool ValueToJson(const Value &value, json *ret) {
obj.SetBool(value.Get<bool>()); obj.SetBool(value.Get<bool>());
break; break;
case STRING_TYPE: case STRING_TYPE:
obj.SetString(value.Get<std::string>().c_str(), GetAllocator()); obj.SetString(value.Get<std::string>().c_str(), s_pActiveDocument->GetAllocator());
break; break;
case ARRAY_TYPE: { case ARRAY_TYPE: {
obj.SetArray(); obj.SetArray();
obj.Reserve(static_cast<rapidjson::SizeType>(value.ArrayLen()), GetAllocator()); obj.Reserve(static_cast<rapidjson::SizeType>(value.ArrayLen()), s_pActiveDocument->GetAllocator());
for (unsigned int i = 0; i < value.ArrayLen(); ++i) { for (unsigned int i = 0; i < value.ArrayLen(); ++i) {
Value elementValue = value.Get(int(i)); Value elementValue = value.Get(int(i));
json elementJson; json elementJson;
if (ValueToJson(value.Get(int(i)), &elementJson)) if (ValueToJson(value.Get(int(i)), &elementJson))
obj.PushBack(std::move(elementJson), GetAllocator()); obj.PushBack(std::move(elementJson), s_pActiveDocument->GetAllocator());
} }
break; break;
} }
@ -5863,7 +5844,7 @@ static bool ValueToJson(const Value &value, json *ret) {
for (auto &it : objMap) { for (auto &it : objMap) {
json elementJson; json elementJson;
if (ValueToJson(it.second, &elementJson)) { if (ValueToJson(it.second, &elementJson)) {
obj.AddMember(json(it.first.c_str(), GetAllocator()), std::move(elementJson), GetAllocator()); obj.AddMember(json(it.first.c_str(), s_pActiveDocument->GetAllocator()), std::move(elementJson), s_pActiveDocument->GetAllocator());
} }
} }
break; break;