in SpatialInput/External/tiny_gltf.h [2339:2789]
bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
unsigned int length, const std::string &base_dir,
unsigned int check_sections) {
if (length < 4) {
if (err) {
(*err) = "JSON string too short.\n";
}
return false;
}
// TODO(syoyo): Add feature not using exception handling.
picojson::value v;
try {
std::string perr = picojson::parse(v, str, str + length);
if (!perr.empty()) {
if (err) {
(*err) = "JSON parsing error: " + perr;
}
return false;
}
} catch (std::exception e) {
if (err) {
(*err) = e.what();
}
return false;
}
if (!v.is<picojson::object>()) {
// root is not an object.
if (err) {
(*err) = "Root element is not a JSON object\n";
}
return false;
}
// scene is not mandatory.
// FIXME Maybe a better way to handle it than removing the code
if (v.contains("scenes") && v.get("scenes").is<picojson::array>()) {
// OK
} else if (check_sections & REQUIRE_SCENES) {
if (err) {
(*err) += "\"scenes\" object not found in .gltf\n";
}
return false;
}
if (v.contains("nodes") && v.get("nodes").is<picojson::array>()) {
// OK
} else if (check_sections & REQUIRE_NODES) {
if (err) {
(*err) += "\"nodes\" object not found in .gltf\n";
}
return false;
}
if (v.contains("accessors") && v.get("accessors").is<picojson::array>()) {
// OK
} else if (check_sections & REQUIRE_ACCESSORS) {
if (err) {
(*err) += "\"accessors\" object not found in .gltf\n";
}
return false;
}
if (v.contains("buffers") && v.get("buffers").is<picojson::array>()) {
// OK
} else if (check_sections & REQUIRE_BUFFERS) {
if (err) {
(*err) += "\"buffers\" object not found in .gltf\n";
}
return false;
}
if (v.contains("bufferViews") && v.get("bufferViews").is<picojson::array>()) {
// OK
} else if (check_sections & REQUIRE_BUFFER_VIEWS) {
if (err) {
(*err) += "\"bufferViews\" object not found in .gltf\n";
}
return false;
}
model->buffers.clear();
model->bufferViews.clear();
model->accessors.clear();
model->meshes.clear();
model->cameras.clear();
model->nodes.clear();
model->extensionsUsed.clear();
model->extensionsRequired.clear();
model->defaultScene = -1;
// 0. Parse Asset
if (v.contains("asset") && v.get("asset").is<picojson::object>()) {
const picojson::object &root = v.get("asset").get<picojson::object>();
ParseAsset(&model->asset, err, root);
}
// 0. Parse extensionUsed
if (v.contains("extensionsUsed") &&
v.get("extensionsUsed").is<picojson::array>()) {
const picojson::array &root =
v.get("extensionsUsed").get<picojson::array>();
for (unsigned int i = 0; i < root.size(); ++i) {
model->extensionsUsed.push_back(root[i].get<std::string>());
}
}
if (v.contains("extensionsRequired") &&
v.get("extensionsRequired").is<picojson::array>()) {
const picojson::array &root =
v.get("extensionsRequired").get<picojson::array>();
for (unsigned int i = 0; i < root.size(); ++i) {
model->extensionsRequired.push_back(root[i].get<std::string>());
}
}
// 1. Parse Buffer
if (v.contains("buffers") && v.get("buffers").is<picojson::array>()) {
const picojson::array &root = v.get("buffers").get<picojson::array>();
picojson::array::const_iterator it(root.begin());
picojson::array::const_iterator itEnd(root.end());
for (; it != itEnd; it++) {
if (!it->is<picojson::object>()) {
if (err) {
(*err) += "`buffers' does not contain an JSON object.";
}
return false;
}
Buffer buffer;
if (!ParseBuffer(&buffer, err, it->get<picojson::object>(), base_dir,
is_binary_, bin_data_, bin_size_)) {
return false;
}
model->buffers.push_back(buffer);
}
}
// 2. Parse BufferView
if (v.contains("bufferViews") && v.get("bufferViews").is<picojson::array>()) {
const picojson::array &root = v.get("bufferViews").get<picojson::array>();
picojson::array::const_iterator it(root.begin());
picojson::array::const_iterator itEnd(root.end());
for (; it != itEnd; it++) {
if (!it->is<picojson::object>()) {
if (err) {
(*err) += "`bufferViews' does not contain an JSON object.";
}
return false;
}
BufferView bufferView;
if (!ParseBufferView(&bufferView, err, it->get<picojson::object>())) {
return false;
}
model->bufferViews.push_back(bufferView);
}
}
// 3. Parse Accessor
if (v.contains("accessors") && v.get("accessors").is<picojson::array>()) {
const picojson::array &root = v.get("accessors").get<picojson::array>();
picojson::array::const_iterator it(root.begin());
picojson::array::const_iterator itEnd(root.end());
for (; it != itEnd; it++) {
if (!it->is<picojson::object>()) {
if (err) {
(*err) += "`accessors' does not contain an JSON object.";
}
return false;
}
Accessor accessor;
if (!ParseAccessor(&accessor, err, it->get<picojson::object>())) {
return false;
}
model->accessors.push_back(accessor);
}
}
// 4. Parse Mesh
if (v.contains("meshes") && v.get("meshes").is<picojson::array>()) {
const picojson::array &root = v.get("meshes").get<picojson::array>();
picojson::array::const_iterator it(root.begin());
picojson::array::const_iterator itEnd(root.end());
for (; it != itEnd; it++) {
if (!it->is<picojson::object>()) {
if (err) {
(*err) += "`meshes' does not contain an JSON object.";
}
return false;
}
Mesh mesh;
if (!ParseMesh(&mesh, err, it->get<picojson::object>())) {
return false;
}
model->meshes.push_back(mesh);
}
}
// 5. Parse Node
if (v.contains("nodes") && v.get("nodes").is<picojson::array>()) {
const picojson::array &root = v.get("nodes").get<picojson::array>();
picojson::array::const_iterator it(root.begin());
picojson::array::const_iterator itEnd(root.end());
for (; it != itEnd; it++) {
if (!it->is<picojson::object>()) {
if (err) {
(*err) += "`nodes' does not contain an JSON object.";
}
return false;
}
Node node;
if (!ParseNode(&node, err, it->get<picojson::object>())) {
return false;
}
model->nodes.push_back(node);
}
}
// 6. Parse scenes.
if (v.contains("scenes") && v.get("scenes").is<picojson::array>()) {
const picojson::array &root = v.get("scenes").get<picojson::array>();
picojson::array::const_iterator it(root.begin());
picojson::array::const_iterator itEnd(root.end());
for (; it != itEnd; it++) {
if (!(it->is<picojson::object>())) {
if (err) {
(*err) += "`scenes' does not contain an JSON object.";
}
return false;
}
const picojson::object &o = it->get<picojson::object>();
std::vector<double> nodes;
if (!ParseNumberArrayProperty(&nodes, err, o, "nodes", false)) {
return false;
}
Scene scene;
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;
model->scenes.push_back(scene);
}
}
// 7. Parse default scenes.
if (v.contains("scene") && v.get("scene").is<double>()) {
const int defaultScene = int(v.get("scene").get<double>());
model->defaultScene = static_cast<int>(defaultScene);
}
// 8. Parse Material
if (v.contains("materials") && v.get("materials").is<picojson::array>()) {
const picojson::array &root = v.get("materials").get<picojson::array>();
picojson::array::const_iterator it(root.begin());
picojson::array::const_iterator itEnd(root.end());
for (; it != itEnd; it++) {
if (!it->is<picojson::object>()) {
if (err) {
(*err) += "`materials' does not contain an JSON object.";
}
return false;
}
picojson::object jsonMaterial = it->get<picojson::object>();
Material material;
ParseStringProperty(&material.name, err, jsonMaterial, "name", false);
if (!ParseMaterial(&material, err, jsonMaterial)) {
return false;
}
model->materials.push_back(material);
}
}
// 9. Parse Image
if (v.contains("images") && v.get("images").is<picojson::array>()) {
const picojson::array &root = v.get("images").get<picojson::array>();
picojson::array::const_iterator it(root.begin());
picojson::array::const_iterator itEnd(root.end());
for (; it != itEnd; it++) {
if (!it->is<picojson::object>()) {
if (err) {
(*err) += "`images' does not contain an JSON object.";
}
return false;
}
Image image;
if (!ParseImage(&image, err, it->get<picojson::object>(), base_dir,
is_binary_, bin_data_, bin_size_)) {
return false;
}
if (image.bufferView != -1) {
// Load image from the buffer view.
if (size_t(image.bufferView) >= model->bufferViews.size()) {
if (err) {
std::stringstream ss;
ss << "bufferView \"" << image.bufferView
<< "\" not found in the scene." << std::endl;
(*err) += ss.str();
}
return false;
}
const BufferView &bufferView =
model->bufferViews[size_t(image.bufferView)];
const Buffer &buffer = model->buffers[size_t(bufferView.buffer)];
bool ret = LoadImageData(&image, err, image.width, image.height,
&buffer.data[bufferView.byteOffset],
static_cast<int>(bufferView.byteLength));
if (!ret) {
return false;
}
}
model->images.push_back(image);
}
}
// 10. Parse Texture
if (v.contains("textures") && v.get("textures").is<picojson::array>()) {
const picojson::array &root = v.get("textures").get<picojson::array>();
picojson::array::const_iterator it(root.begin());
picojson::array::const_iterator itEnd(root.end());
for (; it != itEnd; it++) {
if (!it->is<picojson::object>()) {
if (err) {
(*err) += "`textures' does not contain an JSON object.";
}
return false;
}
Texture texture;
if (!ParseTexture(&texture, err, it->get<picojson::object>(), base_dir)) {
return false;
}
model->textures.push_back(texture);
}
}
// 11. Parse Animation
if (v.contains("animations") && v.get("animations").is<picojson::array>()) {
const picojson::array &root = v.get("animations").get<picojson::array>();
picojson::array::const_iterator it(root.begin());
picojson::array::const_iterator itEnd(root.end());
for (; it != itEnd; ++it) {
if (!it->is<picojson::object>()) {
if (err) {
(*err) += "`animations' does not contain an JSON object.";
}
return false;
}
Animation animation;
if (!ParseAnimation(&animation, err, it->get<picojson::object>())) {
return false;
}
model->animations.push_back(animation);
}
}
// 12. Parse Skin
if (v.contains("skins") && v.get("skins").is<picojson::array>()) {
const picojson::array &root = v.get("skins").get<picojson::array>();
picojson::array::const_iterator it(root.begin());
picojson::array::const_iterator itEnd(root.end());
for (; it != itEnd; ++it) {
if (!it->is<picojson::object>()) {
if (err) {
(*err) += "`skins' does not contain an JSON object.";
}
return false;
}
Skin skin;
if (!ParseSkin(&skin, err, it->get<picojson::object>())) {
return false;
}
model->skins.push_back(skin);
}
}
// 13. Parse Sampler
if (v.contains("samplers") && v.get("samplers").is<picojson::array>()) {
const picojson::array &root = v.get("samplers").get<picojson::array>();
picojson::array::const_iterator it(root.begin());
picojson::array::const_iterator itEnd(root.end());
for (; it != itEnd; ++it) {
if (!it->is<picojson::object>()) {
if (err) {
(*err) += "`samplers' does not contain an JSON object.";
}
return false;
}
Sampler sampler;
if (!ParseSampler(&sampler, err, it->get<picojson::object>())) {
return false;
}
model->samplers.push_back(sampler);
}
}
// 14. Parse Camera
if (v.contains("cameras") && v.get("cameras").is<picojson::array>()) {
const picojson::array &root = v.get("cameras").get<picojson::array>();
picojson::array::const_iterator it(root.begin());
picojson::array::const_iterator itEnd(root.end());
for (; it != itEnd; ++it) {
if (!it->is<picojson::object>()) {
if (err) {
(*err) += "`cameras' does not contain an JSON object.";
}
return false;
}
Camera camera;
if (!ParseCamera(&camera, err, it->get<picojson::object>())) {
return false;
}
model->cameras.push_back(camera);
}
}
return true;
}