Remove glTFViewer from samples

Bug: dawn:152
Change-Id: I5bd36f4ae56889bf12652f8a201a7f7be5e2d25d
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/7360
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index fe7e68a..14e7cbb 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -762,17 +762,6 @@
     ]
   }
 
-  dawn_sample("glTFViewer") {
-    sources = [
-      "examples/glTFViewer/Camera.inc",
-      "examples/glTFViewer/glTFViewer.cpp",
-    ]
-    deps = [
-      "third_party:glm",
-      "third_party:tiny_gltf_loader",
-    ]
-  }
-
   group("dawn_samples") {
     deps = [
       ":Animometer",
@@ -780,7 +769,6 @@
       ":ComputeBoids",
       ":CppHelloTriangle",
       ":CubeReflection",
-      ":glTFViewer",
     ]
   }
 }
diff --git a/DEPS b/DEPS
index ebc5bbb..741f57b 100644
--- a/DEPS
+++ b/DEPS
@@ -78,11 +78,7 @@
     'condition': 'dawn_standalone',
   },
 
-  # Dependencies for samples: stb and GLM
-  'third_party/stb': {
-    'url': '{github_git}/nothings/stb.git@c7110588a4d24c4bb5155c184fbb77dd90b3116e',
-    'condition': 'dawn_standalone',
-  },
+  # Dependencies for samples: GLM
   'third_party/glm': {
     'url': '{github_git}/g-truc/glm.git@06f084063fd6d9aa2ef6904517650700ae47b63d',
     'condition': 'dawn_standalone',
diff --git a/examples/glTFViewer/Camera.inc b/examples/glTFViewer/Camera.inc
deleted file mode 100644
index 530e8b1..0000000
--- a/examples/glTFViewer/Camera.inc
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2017 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-class Camera {
-    public:
-        Camera()
-            : _azimuth(glm::radians(45.f)),
-              _altitude(glm::radians(30.f)),
-              _radius(10.f),
-              _center(0, 0, 0),
-              _dirty(true) {
-            recalculate();
-        }
-
-        void rotate(float dAzimuth, float dAltitude) {
-            _dirty = true;
-            _azimuth = glm::mod(_azimuth + dAzimuth, glm::radians(360.f));
-            _altitude = glm::clamp(_altitude + dAltitude, glm::radians(-89.f), glm::radians(89.f));
-        }
-
-        void pan(float dX, float dY) {
-            recalculate();
-            glm::vec3 vX = glm::normalize(glm::cross(-_eyeDir, glm::vec3(0, 1, 0)));
-            glm::vec3 vY = glm::normalize(glm::cross(_eyeDir, vX));
-            _center += vX * dX * _radius + vY * dY * _radius;
-        }
-
-        void zoom(float factor) {
-            _dirty = true;
-            _radius = _radius * glm::exp(-factor);
-        }
-
-        glm::mat4 view() {
-            if (_dirty) {
-                recalculate();
-            }
-            return _view;
-        }
-    private:
-        void recalculate() {
-            glm::vec4 eye4 = glm::vec4(1, 0, 0, 1);
-            eye4 = glm::rotate(glm::mat4(), _altitude, glm::vec3(0, 0, 1)) * eye4;
-            eye4 = glm::rotate(glm::mat4(), _azimuth, glm::vec3(0, 1, 0)) * eye4;
-            _eyeDir = glm::vec3(eye4);
-
-            _view = glm::lookAt(_center + _eyeDir * _radius, _center, glm::vec3(0, -1, 0));
-            _dirty = false;
-        }
-        float _azimuth;
-        float _altitude;
-        float _radius;
-        glm::vec3 _center;
-        glm::vec3 _eyeDir;
-        bool _dirty;
-        glm::mat4 _view;
-};
diff --git a/examples/glTFViewer/README.md b/examples/glTFViewer/README.md
deleted file mode 100644
index d1ddf6b..0000000
--- a/examples/glTFViewer/README.md
+++ /dev/null
@@ -1,30 +0,0 @@
-# Dawn glTF Viewer
-
-This is a barebones glTF model viewer using the Dawn API. It is intended as a
-proof of concept for the API and is not a robust model viewer. It can load
-basic mesh/texture data from a few
-[glTF sample models](https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/1.0),
-such as:
-
-* 2CylinderEngine
-* BoxWithoutIndices
-* Cesium Man
-* Duck
-* Monster
-* VC (Virtual City)
-
-## Usage
-
-`build/examples/glTFViewer/glTFViewer path/to/Duck.gltf`
-
-`build/examples/glTFViewer/glTFViewer path/to/Duck.gltf --backend metal`
-
-## Screenshots
-
-Duck:
-
-![Duck](img/nxt-gltf-duck.jpg)
-
-VC (Virtual City):
-
-![Virtual City](img/nxt-gltf-vc.jpg)
diff --git a/examples/glTFViewer/glTFViewer.cpp b/examples/glTFViewer/glTFViewer.cpp
deleted file mode 100644
index 5dc6d09..0000000
--- a/examples/glTFViewer/glTFViewer.cpp
+++ /dev/null
@@ -1,686 +0,0 @@
-// Copyright 2017 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Enable this before including any headers as we want inttypes.h to define
-// format macros such as PRId64 that are used in picojson.
-#ifndef __STDC_FORMAT_MACROS
-#define __STDC_FORMAT_MACROS
-#endif
-
-#include "../SampleUtils.h"
-
-#include "common/Assert.h"
-#include "common/Math.h"
-#include "common/Constants.h"
-#include "utils/ComboRenderPipelineDescriptor.h"
-#include "utils/DawnHelpers.h"
-#include "utils/SystemUtils.h"
-
-#include <bitset>
-#define GLM_FORCE_DEPTH_ZERO_TO_ONE
-#include <glm/mat4x4.hpp>
-#include <glm/gtc/matrix_inverse.hpp>
-#include <glm/gtc/matrix_transform.hpp>
-#include <glm/gtc/type_ptr.hpp>
-
-#define TINYGLTF_LOADER_IMPLEMENTATION
-#define STB_IMAGE_IMPLEMENTATION
-#define PICOJSON_ASSERT ASSERT
-#undef __STDC_FORMAT_MACROS
-#include <tinygltfloader/tiny_gltf_loader.h>
-
-#include "GLFW/glfw3.h"
-
-#include "Camera.inc"
-
-namespace gl {
-    enum {
-        Triangles = 0x0004,
-        UnsignedShort = 0x1403,
-        UnsignedInt = 0x1405,
-        Float = 0x1406,
-        RGBA = 0x1908,
-        Nearest = 0x2600,
-        Linear = 0x2601,
-        NearestMipmapNearest = 0x2700,
-        LinearMipmapNearest = 0x2701,
-        NearestMipmapLinear = 0x2702,
-        LinearMipmapLinear = 0x2703,
-        ArrayBuffer = 0x8892,
-        ElementArrayBuffer = 0x8893,
-        FragmentShader = 0x8B30,
-        VertexShader = 0x8B31,
-        FloatVec2 = 0x8B50,
-        FloatVec3 = 0x8B51,
-        FloatVec4 = 0x8B52,
-    };
-}
-
-struct MaterialInfo {
-    dawn::RenderPipeline pipeline;
-    dawn::BindGroup bindGroup0;
-    std::map<uint32_t, std::string> slotSemantics;
-};
-
-struct u_transform_block {
-    glm::mat4 modelViewProj;
-    glm::mat4 modelInvTr;
-};
-
-dawn::Device device;
-dawn::Queue queue;
-dawn::SwapChain swapchain;
-dawn::TextureView depthStencilView;
-
-dawn::Buffer defaultBuffer;
-std::map<std::string, dawn::Buffer> buffers;
-std::map<std::string, dawn::CommandBuffer> commandBuffers;
-std::map<uint32_t, std::string> slotSemantics = {{0, "POSITION"}, {1, "NORMAL"}, {2, "TEXCOORD_0"}};
-
-std::map<std::string, dawn::Sampler> samplers;
-std::map<std::string, dawn::TextureView> textures;
-
-tinygltf::Scene scene;
-glm::mat4 projection = glm::perspective(glm::radians(60.f), 640.f/480, 0.1f, 2000.f);
-Camera camera;
-
-// Helpers
-namespace {
-    std::string getFilePathExtension(const std::string &FileName) {
-        if (FileName.find_last_of(".") != std::string::npos) {
-            return FileName.substr(FileName.find_last_of(".") + 1);
-        }
-        return "";
-    }
-
-    bool techniqueParameterTypeToVertexFormat(int type, dawn::VertexFormat *format) {
-        switch (type) {
-            case gl::FloatVec2:
-                *format = dawn::VertexFormat::Float2;
-                return true;
-            case gl::FloatVec3:
-                *format = dawn::VertexFormat::Float3;
-                return true;
-            case gl::FloatVec4:
-                *format = dawn::VertexFormat::Float4;
-                return true;
-            default:
-                return false;
-        }
-    }
-}
-
-// Initialization
-namespace {
-    void initBuffers() {
-        dawn::BufferDescriptor descriptor;
-        descriptor.size = 256;
-        descriptor.usage = dawn::BufferUsageBit::Vertex | dawn::BufferUsageBit::Index;
-        defaultBuffer = device.CreateBuffer(&descriptor);
-
-        for (const auto& bv : scene.bufferViews) {
-            const auto& iBufferViewID = bv.first;
-            const auto& iBufferView = bv.second;
-
-            dawn::BufferUsageBit usage = dawn::BufferUsageBit::None;
-            switch (iBufferView.target) {
-                case gl::ArrayBuffer:
-                    usage |= dawn::BufferUsageBit::Vertex;
-                    break;
-                case gl::ElementArrayBuffer:
-                    usage |= dawn::BufferUsageBit::Index;
-                    break;
-                case 0:
-                    fprintf(stderr, "TODO: buffer view has no target; skipping\n");
-                    continue;
-                default:
-                    fprintf(stderr, "unsupported buffer view target %d\n", iBufferView.target);
-                    continue;
-            }
-            const auto& iBuffer = scene.buffers.at(iBufferView.buffer);
-
-            size_t iBufferViewSize =
-                iBufferView.byteLength ? iBufferView.byteLength :
-                (iBuffer.data.size() - iBufferView.byteOffset);
-            auto oBuffer = utils::CreateBufferFromData(device, &iBuffer.data.at(iBufferView.byteOffset), static_cast<uint32_t>(iBufferViewSize), usage);
-            buffers[iBufferViewID] = std::move(oBuffer);
-        }
-    }
-
-    const MaterialInfo& getMaterial(const std::string& iMaterialID, size_t stridePos, size_t strideNor, size_t strideTxc) {
-        static std::map<std::tuple<std::string, size_t, size_t, size_t>, MaterialInfo> materials;
-        auto key = make_tuple(iMaterialID, stridePos, strideNor, strideTxc);
-        auto materialIterator = materials.find(key);
-        if (materialIterator != materials.end()) {
-            return materialIterator->second;
-        }
-
-        const auto& iMaterial = scene.materials.at(iMaterialID);
-        const auto& iTechnique = scene.techniques.at(iMaterial.technique);
-
-        bool hasTexture = false;
-        std::string iTextureID;
-        {
-            auto it = iMaterial.values.find("diffuse");
-            if (it != iMaterial.values.end() && !it->second.string_value.empty()) {
-                hasTexture = true;
-                iTextureID = it->second.string_value;
-            }
-        }
-
-        auto oVSModule = utils::CreateShaderModule(device, dawn::ShaderStage::Vertex, R"(
-            #version 450
-
-            layout(push_constant) uniform u_transform_block {
-                mat4 modelViewProj;
-                mat4 modelInvTr;
-            } u_transform;
-
-            layout(location = 0) in vec4 a_position;
-            layout(location = 1) in vec3 a_normal;
-            layout(location = 2) in vec2 a_texcoord;
-
-            layout(location = 0) out vec3 v_normal;
-            layout(location = 1) out vec2 v_texcoord;
-
-            void main() {
-                v_normal = (u_transform.modelInvTr * vec4(normalize(a_normal), 0)).rgb;
-                v_texcoord = a_texcoord;
-                gl_Position = u_transform.modelViewProj * a_position;
-            })");
-
-        auto oFSSourceTextured = R"(
-            #version 450
-
-            layout(set = 0, binding = 0) uniform sampler u_samp;
-            layout(set = 0, binding = 1) uniform texture2D u_tex;
-
-            layout(location = 0) in vec3 v_normal;
-            layout(location = 1) in vec2 v_texcoord;
-
-            layout(location = 0) out vec4 fragcolor;
-
-            void main() {
-                const vec3 lightdir = normalize(vec3(-1, -2, 3));
-                vec3 normal = normalize(v_normal);
-                float diffuse = abs(dot(lightdir, normal));
-                float diffamb = diffuse * 0.85 + 0.15;
-                vec3 albedo = texture(sampler2D(u_tex, u_samp), v_texcoord).rgb;
-                fragcolor = vec4(diffamb * albedo, 1);
-            })";
-        auto oFSSourceUntextured = R"(
-            #version 450
-
-            layout(location = 0) in vec3 v_normal;
-            layout(location = 1) in vec2 v_texcoord;
-
-            layout(location = 0) out vec4 fragcolor;
-
-            void main() {
-                const vec3 lightdir = normalize(vec3(-1, -2, 3));
-                vec3 normal = normalize(v_normal);
-                float diffuse = abs(dot(lightdir, normal));
-                float diffamb = diffuse * 0.85 + 0.15;
-                fragcolor = vec4(vec3(diffamb), 1);
-            })";
-
-        auto oFSModule = utils::CreateShaderModule(device, dawn::ShaderStage::Fragment, hasTexture ? oFSSourceTextured : oFSSourceUntextured);
-
-        utils::ComboRenderPipelineDescriptor descriptor(device);
-        descriptor.cInputState.indexFormat = dawn::IndexFormat::Uint16;
-        uint32_t numAttributes = 0;
-        uint32_t numInputs = 0;
-        std::bitset<3> slotsSet;
-        for (const auto& a : iTechnique.attributes) {
-            const auto iAttributeName = a.first;
-            const auto iParameter = iTechnique.parameters.at(a.second);
-            dawn::VertexFormat format;
-            if (!techniqueParameterTypeToVertexFormat(iParameter.type, &format)) {
-                fprintf(stderr, "unsupported technique parameter type %d\n", iParameter.type);
-                continue;
-            }
-            descriptor.cInputState.cAttributes[numAttributes].format = format;
-
-            if (iParameter.semantic == "POSITION") {
-                descriptor.cInputState.cInputs[numInputs].stride = static_cast<uint32_t>(stridePos);
-                numAttributes++;
-                numInputs++;
-                slotsSet.set(0);
-            } else if (iParameter.semantic == "NORMAL") {
-                descriptor.cInputState.cAttributes[numAttributes].shaderLocation = 1;
-                descriptor.cInputState.cAttributes[numAttributes].inputSlot = 1;
-                descriptor.cInputState.cInputs[numInputs].inputSlot = 1;
-                descriptor.cInputState.cInputs[numInputs].stride = static_cast<uint32_t>(strideNor);
-                numAttributes++;
-                numInputs++;
-                slotsSet.set(1);
-            } else if (iParameter.semantic == "TEXCOORD_0") {
-                descriptor.cInputState.cAttributes[numAttributes].shaderLocation = 2;
-                descriptor.cInputState.cAttributes[numAttributes].inputSlot = 2;
-                descriptor.cInputState.cInputs[numInputs].inputSlot = 2;
-                descriptor.cInputState.cInputs[numInputs].stride = static_cast<uint32_t>(strideTxc);
-                numAttributes++;
-                numInputs++;
-                slotsSet.set(2);
-            } else {
-                fprintf(stderr, "unsupported technique attribute semantic %s\n", iParameter.semantic.c_str());
-            }
-        }
-        for (uint32_t i = 0; i < slotsSet.size(); i++) {
-            if (slotsSet[i]) {
-                continue;
-            }
-            descriptor.cInputState.cAttributes[numAttributes].shaderLocation = i;
-            descriptor.cInputState.cAttributes[numAttributes].inputSlot = i;
-            descriptor.cInputState.cAttributes[numAttributes].format = dawn::VertexFormat::Float4;
-
-            descriptor.cInputState.cInputs[numInputs].inputSlot = i;
-
-            numAttributes++;
-            numInputs++;
-        }
-        descriptor.cInputState.numAttributes = numAttributes;
-        descriptor.cInputState.numInputs = numInputs;
-
-        constexpr dawn::ShaderStageBit kNoStages{};
-        dawn::BindGroupLayout bindGroupLayout = utils::MakeBindGroupLayout(
-            device, {
-                        {0, hasTexture ? dawn::ShaderStageBit::Fragment : kNoStages,
-                         dawn::BindingType::Sampler},
-                        {1, hasTexture ? dawn::ShaderStageBit::Fragment : kNoStages,
-                         dawn::BindingType::SampledTexture},
-                    });
-
-        auto pipelineLayout = utils::MakeBasicPipelineLayout(device, &bindGroupLayout);
-
-        descriptor.layout = pipelineLayout;
-        descriptor.cVertexStage.module = oVSModule;
-        descriptor.cFragmentStage.module = oFSModule;
-        descriptor.depthStencilState = &descriptor.cDepthStencilState;
-        descriptor.cDepthStencilState.format = dawn::TextureFormat::D32FloatS8Uint;
-        descriptor.cColorStates[0]->format = GetPreferredSwapChainTextureFormat();
-        descriptor.cDepthStencilState.depthWriteEnabled = true;
-        descriptor.cDepthStencilState.depthCompare = dawn::CompareFunction::Less;
-
-        dawn::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
-
-        dawn::BindGroup bindGroup;
-
-        if (hasTexture) {
-            const auto& textureView = textures[iTextureID];
-            const auto& iSamplerID = scene.textures[iTextureID].sampler;
-            bindGroup = utils::MakeBindGroup(device, bindGroupLayout, {
-                {0, samplers[iSamplerID]},
-                {1, textureView}
-            });
-        } else {
-            bindGroup = utils::MakeBindGroup(device, bindGroupLayout, {});
-        }
-
-        MaterialInfo material = {
-            pipeline,
-            bindGroup,
-            std::map<uint32_t, std::string>(),
-        };
-        materials[key] = std::move(material);
-        return materials.at(key);
-    }
-
-    void initSamplers() {
-        for (const auto& s : scene.samplers) {
-            const auto& iSamplerID = s.first;
-            const auto& iSampler = s.second;
-
-            dawn::SamplerDescriptor desc = utils::GetDefaultSamplerDescriptor();
-            // TODO: wrap modes
-
-            switch (iSampler.magFilter) {
-                case gl::Nearest:
-                    desc.magFilter = dawn::FilterMode::Nearest;
-                    break;
-                case gl::Linear:
-                    desc.magFilter = dawn::FilterMode::Linear;
-                    break;
-                default:
-                    fprintf(stderr, "unsupported magFilter %d\n", iSampler.magFilter);
-                    break;
-            }
-            switch (iSampler.minFilter) {
-                case gl::Nearest:
-                case gl::NearestMipmapNearest:
-                case gl::NearestMipmapLinear:
-                    desc.minFilter = dawn::FilterMode::Nearest;
-                    break;
-                case gl::Linear:
-                case gl::LinearMipmapNearest:
-                case gl::LinearMipmapLinear:
-                    desc.minFilter = dawn::FilterMode::Linear;
-                    break;
-                default:
-                    fprintf(stderr, "unsupported minFilter %d\n", iSampler.magFilter);
-                    break;
-            }
-            switch (iSampler.minFilter) {
-                case gl::NearestMipmapNearest:
-                case gl::LinearMipmapNearest:
-                    desc.mipmapFilter = dawn::FilterMode::Nearest;
-                    break;
-                case gl::NearestMipmapLinear:
-                case gl::LinearMipmapLinear:
-                    desc.mipmapFilter = dawn::FilterMode::Linear;
-                    break;
-            }
-
-            samplers[iSamplerID] = device.CreateSampler(&desc);
-        }
-    }
-
-    void initTextures() {
-        for (const auto& t : scene.textures) {
-            const auto& iTextureID = t.first;
-            const auto& iTexture = t.second;
-            const auto& iImage = scene.images[iTexture.source];
-
-            dawn::TextureFormat format = dawn::TextureFormat::R8G8B8A8Unorm;
-            switch (iTexture.format) {
-                case gl::RGBA:
-                    format = dawn::TextureFormat::R8G8B8A8Unorm;
-                    break;
-                default:
-                    fprintf(stderr, "unsupported texture format %d\n", iTexture.format);
-                    continue;
-            }
-
-            dawn::TextureDescriptor descriptor;
-            descriptor.dimension = dawn::TextureDimension::e2D;
-            descriptor.size.width = iImage.width;
-            descriptor.size.height = iImage.height;
-            descriptor.size.depth = 1;
-            descriptor.arrayLayerCount = 1;
-            descriptor.sampleCount = 1;
-            descriptor.format = format;
-            descriptor.mipLevelCount = 1;
-            descriptor.usage = dawn::TextureUsageBit::TransferDst | dawn::TextureUsageBit::Sampled;
-            auto oTexture = device.CreateTexture(&descriptor);
-                // TODO: release this texture
-
-            const uint8_t* origData = iImage.image.data();
-            const uint8_t* data = nullptr;
-            std::vector<uint8_t> newData;
-
-            uint32_t width = static_cast<uint32_t>(iImage.width);
-            uint32_t height = static_cast<uint32_t>(iImage.height);
-            uint32_t rowSize = width * 4;
-            uint32_t rowPitch = Align(rowSize, kTextureRowPitchAlignment);
-
-            if (iImage.component == 3 || iImage.component == 4) {
-                if (rowSize != rowPitch || iImage.component == 3) {
-                    newData.resize(rowPitch * height);
-                    uint32_t pixelsPerRow = rowPitch / 4;
-                    for (uint32_t y = 0; y < height; ++y) {
-                        for (uint32_t x = 0; x < width; ++x) {
-                            size_t oldIndex = x + y * height;
-                            size_t newIndex = x + y * pixelsPerRow;
-                            if (iImage.component == 4) {
-                                newData[4 * newIndex + 0] = origData[4 * oldIndex + 0];
-                                newData[4 * newIndex + 1] = origData[4 * oldIndex + 1];
-                                newData[4 * newIndex + 2] = origData[4 * oldIndex + 2];
-                                newData[4 * newIndex + 3] = origData[4 * oldIndex + 3];
-                            } else if (iImage.component == 3) {
-                                newData[4 * newIndex + 0] = origData[3 * oldIndex + 0];
-                                newData[4 * newIndex + 1] = origData[3 * oldIndex + 1];
-                                newData[4 * newIndex + 2] = origData[3 * oldIndex + 2];
-                                newData[4 * newIndex + 3] = 255;
-                            }
-                        }
-                    }
-                    data = newData.data();
-                } else {
-                    data = origData;
-                }
-            } else {
-                fprintf(stderr, "unsupported image.component %d\n", iImage.component);
-            }
-
-            dawn::Buffer staging = utils::CreateBufferFromData(device, data, rowPitch * iImage.height, dawn::BufferUsageBit::TransferSrc);
-            dawn::BufferCopyView bufferCopyView =
-                utils::CreateBufferCopyView(staging, 0, rowPitch, 0);
-            dawn::TextureCopyView textureCopyView =
-                utils::CreateTextureCopyView(oTexture, 0, 0, {0, 0, 0});
-            dawn::Extent3D copySize = {iImage.width, iImage.height, 1};
-
-            dawn::CommandEncoder encoder = device.CreateCommandEncoder();
-            encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, &copySize);
-
-            dawn::CommandBuffer cmdbuf = encoder.Finish();
-            queue.Submit(1, &cmdbuf);
-
-            textures[iTextureID] = oTexture.CreateDefaultView();
-        }
-    }
-
-    void init() {
-        device = CreateCppDawnDevice();
-
-        queue = device.CreateQueue();
-        swapchain = GetSwapChain(device);
-        swapchain.Configure(GetPreferredSwapChainTextureFormat(),
-                            dawn::TextureUsageBit::OutputAttachment, 640, 480);
-
-        depthStencilView = CreateDefaultDepthStencilView(device);
-
-        initBuffers();
-        initSamplers();
-        initTextures();
-    }
-}
-
-// Drawing
-namespace {
-    void drawMesh(dawn::RenderPassEncoder& pass, const tinygltf::Mesh& iMesh, const glm::mat4& model) {
-        for (const auto& iPrim : iMesh.primitives) {
-            if (iPrim.mode != gl::Triangles) {
-                fprintf(stderr, "unsupported primitive mode %d\n", iPrim.mode);
-                continue;
-            }
-
-            u_transform_block transforms = {
-                (projection * camera.view() * model),
-                glm::inverseTranspose(model),
-            };
-
-            size_t strides[3] = {0};
-            for (const auto& s : slotSemantics) {
-                if (s.first < 3) {
-                    auto it = iPrim.attributes.find(s.second);
-                    if (it == iPrim.attributes.end()) {
-                        continue;
-                    }
-                    const auto& iAccessorName = it->second;
-                    strides[s.first] = scene.accessors.at(iAccessorName).byteStride;
-                }
-            }
-            const MaterialInfo& material = getMaterial(iPrim.material, strides[0], strides[1], strides[2]);
-            pass.SetPipeline(material.pipeline);
-            pass.SetBindGroup(0, material.bindGroup0, 0, nullptr);
-            pass.SetPushConstants(dawn::ShaderStageBit::Vertex,
-                    0, sizeof(u_transform_block) / sizeof(uint32_t),
-                    reinterpret_cast<const uint32_t*>(&transforms));
-
-            uint32_t vertexCount = 0;
-            for (const auto& s : slotSemantics) {
-                uint32_t slot = s.first;
-                auto it = iPrim.attributes.find(s.second);
-                if (it == iPrim.attributes.end()) {
-                    uint64_t zero = 0;
-                    pass.SetVertexBuffers(slot, 1, &defaultBuffer, &zero);
-                    continue;
-                }
-                const auto& iAccessor = scene.accessors.at(it->second);
-                if (iAccessor.componentType != gl::Float ||
-                        (iAccessor.type != TINYGLTF_TYPE_VEC4 && iAccessor.type != TINYGLTF_TYPE_VEC3 && iAccessor.type != TINYGLTF_TYPE_VEC2)) {
-                    fprintf(stderr, "unsupported vertex accessor component type %d and type %d\n", iAccessor.componentType, iAccessor.type);
-                    continue;
-                }
-
-                if (vertexCount == 0) {
-                    vertexCount = static_cast<uint32_t>(iAccessor.count);
-                }
-                const auto& oBuffer = buffers.at(iAccessor.bufferView);
-                uint64_t iBufferOffset = static_cast<uint64_t>(iAccessor.byteOffset);
-                pass.SetVertexBuffers(slot, 1, &oBuffer, &iBufferOffset);
-            }
-
-            if (!iPrim.indices.empty()) {
-                const auto& iIndices = scene.accessors.at(iPrim.indices);
-                // DrawElements
-                if (iIndices.componentType != gl::UnsignedShort || iIndices.type != TINYGLTF_TYPE_SCALAR) {
-                    fprintf(stderr, "unsupported index accessor component type %d and type %d\n", iIndices.componentType, iIndices.type);
-                    continue;
-                }
-                const auto& oIndicesBuffer = buffers.at(iIndices.bufferView);
-                pass.SetIndexBuffer(oIndicesBuffer, static_cast<uint32_t>(iIndices.byteOffset));
-                pass.DrawIndexed(static_cast<uint32_t>(iIndices.count), 1, 0, 0, 0);
-            } else {
-                // DrawArrays
-                pass.Draw(vertexCount, 1, 0, 0);
-            }
-        }
-    }
-
-    void drawNode(dawn::RenderPassEncoder& pass, const tinygltf::Node& node, const glm::mat4& parent = glm::mat4()) {
-        glm::mat4 model;
-        if (node.matrix.size() == 16) {
-            model = glm::make_mat4(node.matrix.data());
-        } else {
-            if (node.scale.size() == 3) {
-                glm::vec3 scale = glm::make_vec3(node.scale.data());
-                model = glm::scale(model, scale);
-            }
-            if (node.rotation.size() == 4) {
-                glm::quat rotation = glm::make_quat(node.rotation.data());
-                model = glm::mat4_cast(rotation) * model;
-            }
-            if (node.translation.size() == 3) {
-                glm::vec3 translation = glm::make_vec3(node.translation.data());
-                model = glm::translate(model, translation);
-            }
-        }
-        model = parent * model;
-
-        for (const auto& meshID : node.meshes) {
-            drawMesh(pass, scene.meshes[meshID], model);
-        }
-        for (const auto& child : node.children) {
-            drawNode(pass, scene.nodes.at(child), model);
-        }
-    }
-
-    void frame() {
-        dawn::Texture backbuffer = swapchain.GetNextTexture();
-
-        const auto& defaultSceneNodes = scene.scenes.at(scene.defaultScene);
-        dawn::CommandEncoder encoder = device.CreateCommandEncoder();
-        {
-            utils::ComboRenderPassDescriptor renderPass({backbuffer.CreateDefaultView()},
-                                                        depthStencilView);
-            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
-            for (const auto& n : defaultSceneNodes) {
-                const auto& node = scene.nodes.at(n);
-                drawNode(pass, node);
-            }
-            pass.EndPass();
-        }
-
-        dawn::CommandBuffer commands = encoder.Finish();
-        queue.Submit(1, &commands);
-
-        swapchain.Present(backbuffer);
-        DoFlush();
-    }
-}
-
-// Mouse camera control
-namespace {
-    bool buttons[GLFW_MOUSE_BUTTON_LAST + 1] = {0};
-
-    void mouseButtonCallback(GLFWwindow*, int button, int action, int) {
-        buttons[button] = (action == GLFW_PRESS);
-    }
-
-    void cursorPosCallback(GLFWwindow*, double mouseX, double mouseY) {
-        static double oldX, oldY;
-        float dX = static_cast<float>(mouseX - oldX);
-        float dY = static_cast<float>(mouseY - oldY);
-        oldX = mouseX;
-        oldY = mouseY;
-
-        if (buttons[2] || (buttons[0] && buttons[1])) {
-            camera.pan(-dX * 0.002f, dY * 0.002f);
-        } else if (buttons[0]) {
-            camera.rotate(dX * 0.01f, dY * 0.01f);
-        } else if (buttons[1]) {
-            camera.zoom(dY * -0.005f);
-        }
-    }
-
-    void scrollCallback(GLFWwindow*, double, double yoffset) {
-        camera.zoom(static_cast<float>(yoffset) * 0.04f);
-    }
-}
-
-int main(int argc, const char* argv[]) {
-    if (!InitSample(argc, argv)) {
-        return 1;
-    }
-    if (argc < 2) {
-        fprintf(stderr, "Usage: %s model.gltf [... Dawn Options]\n", argv[0]);
-        return 1;
-    }
-
-    tinygltf::TinyGLTFLoader loader;
-    std::string err;
-    std::string input_filename(argv[1]);
-    std::string ext = getFilePathExtension(input_filename);
-
-    bool ret = false;
-    if (ext.compare("glb") == 0) {
-        // assume binary glTF.
-        ret = loader.LoadBinaryFromFile(&scene, &err, input_filename.c_str());
-    } else {
-        // assume ascii glTF.
-        ret = loader.LoadASCIIFromFile(&scene, &err, input_filename.c_str());
-    }
-    if (!err.empty()) {
-        fprintf(stderr, "ERR: %s\n", err.c_str());
-    }
-    if (!ret) {
-        fprintf(stderr, "Failed to load .glTF : %s\n", argv[1]);
-        exit(-1);
-    }
-
-    init();
-
-    GLFWwindow* window = GetGLFWWindow();
-    glfwSetMouseButtonCallback(window, mouseButtonCallback);
-    glfwSetCursorPosCallback(window, cursorPosCallback);
-    glfwSetScrollCallback(window, scrollCallback);
-
-    while (!ShouldQuit()) {
-        frame();
-        utils::USleep(16000);
-    }
-
-    // TODO release stuff
-}
diff --git a/examples/glTFViewer/img/nxt-gltf-duck.jpg b/examples/glTFViewer/img/nxt-gltf-duck.jpg
deleted file mode 100644
index da78162..0000000
--- a/examples/glTFViewer/img/nxt-gltf-duck.jpg
+++ /dev/null
Binary files differ
diff --git a/examples/glTFViewer/img/nxt-gltf-vc.jpg b/examples/glTFViewer/img/nxt-gltf-vc.jpg
deleted file mode 100644
index 29f9694..0000000
--- a/examples/glTFViewer/img/nxt-gltf-vc.jpg
+++ /dev/null
Binary files differ
diff --git a/third_party/BUILD.gn b/third_party/BUILD.gn
index 319a3dc..c17a3f0 100644
--- a/third_party/BUILD.gn
+++ b/third_party/BUILD.gn
@@ -353,45 +353,4 @@
 
     # GLM is header only but has too many files to list them.
   }
-
-  # STB
-  config("stb_public_config") {
-    include_dirs = [ "stb" ]
-
-    if (!is_msvc) {
-      cflags_cc = [ "-Wno-implicit-fallthrough" ]
-    }
-  }
-  source_set("stb") {
-    public_configs = [ ":stb_public_config" ]
-    sources = [
-      "stb/stb_image.h",
-    ]
-  }
-
-  # PicoJSON
-  config("picojson_public_config") {
-    include_dirs = [ "." ]
-  }
-  source_set("picojson") {
-    public_configs = [ ":picojson_public_config" ]
-    sources = [
-      "picojson/picojson.h",
-    ]
-  }
-
-  # Tiny glTF Loader
-  config("tiny_gltf_loader_public_config") {
-    include_dirs = [ "." ]
-  }
-  source_set("tiny_gltf_loader") {
-    public_configs = [ ":tiny_gltf_loader_public_config" ]
-    public_deps = [
-      ":picojson",
-      ":stb",
-    ]
-    sources = [
-      "tinygltfloader/tiny_gltf_loader.h",
-    ]
-  }
 }
diff --git a/third_party/picojson/picojson.h b/third_party/picojson/picojson.h
deleted file mode 100644
index 2180497..0000000
--- a/third_party/picojson/picojson.h
+++ /dev/null
@@ -1,1040 +0,0 @@
-/*
- * Copyright 2009-2010 Cybozu Labs, Inc.
- * Copyright 2011-2014 Kazuho Oku
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- *    this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- *    this list of conditions and the following disclaimer in the documentation
- *    and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-#ifndef picojson_h
-#define picojson_h
-
-#include <algorithm>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <cstddef>
-#include <iostream>
-#include <iterator>
-#include <limits>
-#include <map>
-#include <stdexcept>
-#include <string>
-#include <vector>
-
-// for isnan/isinf
-#if __cplusplus>=201103L
-# include <cmath>
-#else
-extern "C" {
-# ifdef _MSC_VER
-#  include <float.h>
-# elif defined(__INTEL_COMPILER)
-#  include <mathimf.h>
-# else
-#  include <math.h>
-# endif
-}
-#endif
-
-#ifndef PICOJSON_USE_RVALUE_REFERENCE
-# if (defined(__cpp_rvalue_references) && __cpp_rvalue_references >= 200610) || (defined(_MSC_VER) && _MSC_VER >= 1600)
-#  define PICOJSON_USE_RVALUE_REFERENCE 1
-# else
-#  define PICOJSON_USE_RVALUE_REFERENCE 0
-# endif
-#endif//PICOJSON_USE_RVALUE_REFERENCE
-
-
-// experimental support for int64_t (see README.mkdn for detail)
-#ifdef PICOJSON_USE_INT64
-# define __STDC_FORMAT_MACROS
-# include <errno.h>
-# include <inttypes.h>
-#endif
-
-// to disable the use of localeconv(3), set PICOJSON_USE_LOCALE to 0
-#ifndef PICOJSON_USE_LOCALE
-# define PICOJSON_USE_LOCALE 1
-#endif
-#if PICOJSON_USE_LOCALE
-extern "C" {
-# include <locale.h>
-}
-#endif
-
-#ifndef PICOJSON_ASSERT
-# define PICOJSON_ASSERT(e) do { if (! (e)) throw std::runtime_error(#e); } while (0)
-#endif
-
-#ifdef _MSC_VER
-    #define SNPRINTF _snprintf_s
-    #pragma warning(push)
-    #pragma warning(disable : 4244) // conversion from int to char
-    #pragma warning(disable : 4127) // conditional expression is constant
-    #pragma warning(disable : 4702) // unreachable code
-#else
-    #define SNPRINTF snprintf
-#endif
-
-namespace picojson {
-  
-  enum {
-    null_type,
-    boolean_type,
-    number_type,
-    string_type,
-    array_type,
-    object_type
-#ifdef PICOJSON_USE_INT64
-    , int64_type
-#endif
-  };
-  
-  enum {
-    INDENT_WIDTH = 2
-  };
-
-  struct null {};
-  
-  class value {
-  public:
-    typedef std::vector<value> array;
-    typedef std::map<std::string, value> object;
-    union _storage {
-      bool boolean_;
-      double number_;
-#ifdef PICOJSON_USE_INT64
-      int64_t int64_;
-#endif
-      std::string* string_;
-      array* array_;
-      object* object_;
-    };
-  protected:
-    int type_;
-    _storage u_;
-  public:
-    value();
-    value(int type, bool);
-    explicit value(bool b);
-#ifdef PICOJSON_USE_INT64
-    explicit value(int64_t i);
-#endif
-    explicit value(double n);
-    explicit value(const std::string& s);
-    explicit value(const array& a);
-    explicit value(const object& o);
-    explicit value(const char* s);
-    value(const char* s, size_t len);
-    ~value();
-    value(const value& x);
-    value& operator=(const value& x);
-#if PICOJSON_USE_RVALUE_REFERENCE 
-    value(value&& x)throw();
-    value& operator=(value&& x)throw();
-#endif
-    void swap(value& x)throw();
-    template <typename T> bool is() const;
-    template <typename T> const T& get() const;
-    template <typename T> T& get();
-    bool evaluate_as_boolean() const;
-    const value& get(size_t idx) const;
-    const value& get(const std::string& key) const;
-    value& get(size_t idx);
-    value& get(const std::string& key);
-
-    bool contains(size_t idx) const;
-    bool contains(const std::string& key) const;
-    std::string to_str() const;
-    template <typename Iter> void serialize(Iter os, bool prettify = false) const;
-    std::string serialize(bool prettify = false) const;
-  private:
-    template <typename T> value(const T*); // intentionally defined to block implicit conversion of pointer to bool
-    template <typename Iter> static void _indent(Iter os, int indent);
-    template <typename Iter> void _serialize(Iter os, int indent) const;
-    std::string _serialize(int indent) const;
-  };
-  
-  typedef value::array array;
-  typedef value::object object;
-  
-  inline value::value() : type_(null_type) {}
-  
-  inline value::value(int type, bool) : type_(type) {
-    switch (type) {
-#define INIT(p, v) case p##type: u_.p = v; break
-      INIT(boolean_, false);
-      INIT(number_, 0.0);
-#ifdef PICOJSON_USE_INT64
-      INIT(int64_, 0);
-#endif
-      INIT(string_, new std::string());
-      INIT(array_, new array());
-      INIT(object_, new object());
-#undef INIT
-    default: break;
-    }
-  }
-  
-  inline value::value(bool b) : type_(boolean_type) {
-    u_.boolean_ = b;
-  }
-
-#ifdef PICOJSON_USE_INT64
-  inline value::value(int64_t i) : type_(int64_type) {
-    u_.int64_ = i;
-  }
-#endif
-
-  inline value::value(double n) : type_(number_type) {
-    if (
-#ifdef _MSC_VER
-        ! _finite(n)
-#elif __cplusplus>=201103L || !(defined(isnan) && defined(isinf))
-		std::isnan(n) || std::isinf(n)
-#else
-        isnan(n) || isinf(n)
-#endif
-        ) {
-      // throw std::overflow_error("");
-      PICOJSON_ASSERT(false);
-    }
-    u_.number_ = n;
-  }
-  
-  inline value::value(const std::string& s) : type_(string_type) {
-    u_.string_ = new std::string(s);
-  }
-  
-  inline value::value(const array& a) : type_(array_type) {
-    u_.array_ = new array(a);
-  }
-  
-  inline value::value(const object& o) : type_(object_type) {
-    u_.object_ = new object(o);
-  }
-  
-  inline value::value(const char* s) : type_(string_type) {
-    u_.string_ = new std::string(s);
-  }
-  
-  inline value::value(const char* s, size_t len) : type_(string_type) {
-    u_.string_ = new std::string(s, len);
-  }
-  
-  inline value::~value() {
-    switch (type_) {
-#define DEINIT(p) case p##type: delete u_.p; break
-      DEINIT(string_);
-      DEINIT(array_);
-      DEINIT(object_);
-#undef DEINIT
-    default: break;
-    }
-  }
-  
-  inline value::value(const value& x) : type_(x.type_) {
-    switch (type_) {
-#define INIT(p, v) case p##type: u_.p = v; break
-      INIT(string_, new std::string(*x.u_.string_));
-      INIT(array_, new array(*x.u_.array_));
-      INIT(object_, new object(*x.u_.object_));
-#undef INIT
-    default:
-      u_ = x.u_;
-      break;
-    }
-  }
-  
-  inline value& value::operator=(const value& x) {
-    if (this != &x) {
-      value t(x);
-      swap(t);
-    }
-    return *this;
-  }
-
-#if PICOJSON_USE_RVALUE_REFERENCE 
-  inline value::value(value&& x)throw() : type_(null_type) {
-    swap(x);
-  }
-  inline value& value::operator=(value&& x)throw() {
-    swap(x);
-    return *this;
-  }
-#endif
-  inline void value::swap(value& x)throw() {
-    std::swap(type_, x.type_);
-    std::swap(u_, x.u_);
-  }
-  
-#define IS(ctype, jtype)			     \
-  template <> inline bool value::is<ctype>() const { \
-    return type_ == jtype##_type;		     \
-  }
-  IS(null, null)
-  IS(bool, boolean)
-#ifdef PICOJSON_USE_INT64
-  IS(int64_t, int64)
-#endif
-  IS(std::string, string)
-  IS(array, array)
-  IS(object, object)
-#undef IS
-  template <> inline bool value::is<double>() const {
-    return type_ == number_type
-#ifdef PICOJSON_USE_INT64
-      || type_ == int64_type
-#endif
-      ;
-  }
-  
-#define GET(ctype, var)						\
-  template <> inline const ctype& value::get<ctype>() const {	\
-    PICOJSON_ASSERT("type mismatch! call is<type>() before get<type>()" \
-	   && is<ctype>());				        \
-    return var;							\
-  }								\
-  template <> inline ctype& value::get<ctype>() {		\
-    PICOJSON_ASSERT("type mismatch! call is<type>() before get<type>()"	\
-	   && is<ctype>());					\
-    return var;							\
-  }
-  GET(bool, u_.boolean_)
-  GET(std::string, *u_.string_)
-  GET(array, *u_.array_)
-  GET(object, *u_.object_)
-#ifdef PICOJSON_USE_INT64
-  GET(double, (type_ == int64_type && (const_cast<value*>(this)->type_ = number_type, const_cast<value*>(this)->u_.number_ = u_.int64_), u_.number_))
-  GET(int64_t, u_.int64_)
-#else
-  GET(double, u_.number_)
-#endif
-#undef GET
-  
-  inline bool value::evaluate_as_boolean() const {
-    switch (type_) {
-    case null_type:
-      return false;
-    case boolean_type:
-      return u_.boolean_;
-    case number_type:
-      return u_.number_ != 0;
-#ifdef PICOJSON_USE_INT64
-    case int64_type:
-      return u_.int64_ != 0;
-#endif
-    case string_type:
-      return ! u_.string_->empty();
-    default:
-      return true;
-    }
-  }
-  
-  inline const value& value::get(size_t idx) const {
-    static value s_null;
-    PICOJSON_ASSERT(is<array>());
-    return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null;
-  }
-
-  inline value& value::get(size_t idx) {
-    static value s_null;
-    PICOJSON_ASSERT(is<array>());
-    return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null;
-  }
-
-  inline const value& value::get(const std::string& key) const {
-    static value s_null;
-    PICOJSON_ASSERT(is<object>());
-    object::const_iterator i = u_.object_->find(key);
-    return i != u_.object_->end() ? i->second : s_null;
-  }
-
-  inline value& value::get(const std::string& key) {
-    static value s_null;
-    PICOJSON_ASSERT(is<object>());
-    object::iterator i = u_.object_->find(key);
-    return i != u_.object_->end() ? i->second : s_null;
-  }
-
-  inline bool value::contains(size_t idx) const {
-    PICOJSON_ASSERT(is<array>());
-    return idx < u_.array_->size();
-  }
-
-  inline bool value::contains(const std::string& key) const {
-    PICOJSON_ASSERT(is<object>());
-    object::const_iterator i = u_.object_->find(key);
-    return i != u_.object_->end();
-  }
-  
-  inline std::string value::to_str() const {
-    switch (type_) {
-    case null_type:      return "null";
-    case boolean_type:   return u_.boolean_ ? "true" : "false";
-#ifdef PICOJSON_USE_INT64
-    case int64_type: {
-      char buf[sizeof("-9223372036854775808")];
-      SNPRINTF(buf, sizeof(buf), "%" PRId64, u_.int64_);
-      return buf;
-    }
-#endif
-    case number_type:    {
-      char buf[256];
-      double tmp;
-      SNPRINTF(buf, sizeof(buf), fabs(u_.number_) < (1ULL << 53) && modf(u_.number_, &tmp) == 0 ? "%.f" : "%.17g", u_.number_);
-#if PICOJSON_USE_LOCALE
-      char *decimal_point = localeconv()->decimal_point;
-      if (strcmp(decimal_point, ".") != 0) {
-        size_t decimal_point_len = strlen(decimal_point);
-        for (char *p = buf; *p != '\0'; ++p) {
-          if (strncmp(p, decimal_point, decimal_point_len) == 0) {
-            return std::string(buf, p) + "." + (p + decimal_point_len);
-          }
-        }
-      }
-#endif
-      return buf;
-    }
-    case string_type:    return *u_.string_;
-    case array_type:     return "array";
-    case object_type:    return "object";
-    default:             PICOJSON_ASSERT(0);
-#ifdef _MSC_VER
-      __assume(0);
-#endif
-    }
-    return std::string();
-  }
-  
-  template <typename Iter> void copy(const std::string& s, Iter oi) {
-    std::copy(s.begin(), s.end(), oi);
-  }
-  
-  template <typename Iter> void serialize_str(const std::string& s, Iter oi) {
-    *oi++ = '"';
-    for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) {
-      switch (*i) {
-#define MAP(val, sym) case val: copy(sym, oi); break
-	MAP('"', "\\\"");
-	MAP('\\', "\\\\");
-	MAP('/', "\\/");
-	MAP('\b', "\\b");
-	MAP('\f', "\\f");
-	MAP('\n', "\\n");
-	MAP('\r', "\\r");
-	MAP('\t', "\\t");
-#undef MAP
-      default:
-	if (static_cast<unsigned char>(*i) < 0x20 || *i == 0x7f) {
-	  char buf[7];
-	  SNPRINTF(buf, sizeof(buf), "\\u%04x", *i & 0xff);
-	  copy(buf, buf + 6, oi);
-	  } else {
-	  *oi++ = *i;
-	}
-	break;
-      }
-    }
-    *oi++ = '"';
-  }
-
-  template <typename Iter> void value::serialize(Iter oi, bool prettify) const {
-    return _serialize(oi, prettify ? 0 : -1);
-  }
-  
-  inline std::string value::serialize(bool prettify) const {
-    return _serialize(prettify ? 0 : -1);
-  }
-
-  template <typename Iter> void value::_indent(Iter oi, int indent) {
-    *oi++ = '\n';
-    for (int i = 0; i < indent * INDENT_WIDTH; ++i) {
-      *oi++ = ' ';
-    }
-  }
-
-  template <typename Iter> void value::_serialize(Iter oi, int indent) const {
-    switch (type_) {
-    case string_type:
-      serialize_str(*u_.string_, oi);
-      break;
-    case array_type: {
-      *oi++ = '[';
-      if (indent != -1) {
-        ++indent;
-      }
-      for (array::const_iterator i = u_.array_->begin();
-           i != u_.array_->end();
-           ++i) {
-	if (i != u_.array_->begin()) {
-	  *oi++ = ',';
-	}
-        if (indent != -1) {
-          _indent(oi, indent);
-        }
-	i->_serialize(oi, indent);
-      }
-      if (indent != -1) {
-        --indent;
-        if (! u_.array_->empty()) {
-          _indent(oi, indent);
-        }
-      }
-      *oi++ = ']';
-      break;
-    }
-    case object_type: {
-      *oi++ = '{';
-      if (indent != -1) {
-        ++indent;
-      }
-      for (object::const_iterator i = u_.object_->begin();
-	   i != u_.object_->end();
-	   ++i) {
-	if (i != u_.object_->begin()) {
-	  *oi++ = ',';
-	}
-        if (indent != -1) {
-          _indent(oi, indent);
-        }
-	serialize_str(i->first, oi);
-	*oi++ = ':';
-        if (indent != -1) {
-          *oi++ = ' ';
-        }
-        i->second._serialize(oi, indent);
-      }
-      if (indent != -1) {
-        --indent;
-        if (! u_.object_->empty()) {
-          _indent(oi, indent);
-        }
-      }
-      *oi++ = '}';
-      break;
-    }
-    default:
-      copy(to_str(), oi);
-      break;
-    }
-    if (indent == 0) {
-      *oi++ = '\n';
-    }
-  }
-  
-  inline std::string value::_serialize(int indent) const {
-    std::string s;
-    _serialize(std::back_inserter(s), indent);
-    return s;
-  }
-  
-  template <typename Iter> class input {
-  protected:
-    Iter cur_, end_;
-    int last_ch_;
-    bool ungot_;
-    int line_;
-  public:
-    input(const Iter& first, const Iter& last) : cur_(first), end_(last), last_ch_(-1), ungot_(false), line_(1) {}
-    int getc() {
-      if (ungot_) {
-	ungot_ = false;
-	return last_ch_;
-      }
-      if (cur_ == end_) {
-	last_ch_ = -1;
-	return -1;
-      }
-      if (last_ch_ == '\n') {
-	line_++;
-      }
-      last_ch_ = *cur_ & 0xff;
-      ++cur_;
-      return last_ch_;
-    }
-    void ungetc() {
-      if (last_ch_ != -1) {
-	PICOJSON_ASSERT(! ungot_);
-	ungot_ = true;
-      }
-    }
-    Iter cur() const { return cur_; }
-    int line() const { return line_; }
-    void skip_ws() {
-      while (1) {
-	int ch = getc();
-	if (! (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) {
-	  ungetc();
-	  break;
-	}
-      }
-    }
-    bool expect(int expect) {
-      skip_ws();
-      if (getc() != expect) {
-	ungetc();
-	return false;
-      }
-      return true;
-    }
-    bool match(const std::string& pattern) {
-      for (std::string::const_iterator pi(pattern.begin());
-	   pi != pattern.end();
-	   ++pi) {
-	if (getc() != *pi) {
-	  ungetc();
-	  return false;
-	}
-      }
-      return true;
-    }
-  };
-  
-  template<typename Iter> inline int _parse_quadhex(input<Iter> &in) {
-    int uni_ch = 0, hex;
-    for (int i = 0; i < 4; i++) {
-      if ((hex = in.getc()) == -1) {
-	return -1;
-      }
-      if ('0' <= hex && hex <= '9') {
-	hex -= '0';
-      } else if ('A' <= hex && hex <= 'F') {
-	hex -= 'A' - 0xa;
-      } else if ('a' <= hex && hex <= 'f') {
-	hex -= 'a' - 0xa;
-      } else {
-	in.ungetc();
-	return -1;
-      }
-      uni_ch = uni_ch * 16 + hex;
-    }
-    return uni_ch;
-  }
-  
-  template<typename String, typename Iter> inline bool _parse_codepoint(String& out, input<Iter>& in) {
-    int uni_ch;
-    if ((uni_ch = _parse_quadhex(in)) == -1) {
-      return false;
-    }
-    if (0xd800 <= uni_ch && uni_ch <= 0xdfff) {
-      if (0xdc00 <= uni_ch) {
-	// a second 16-bit of a surrogate pair appeared
-	return false;
-      }
-      // first 16-bit of surrogate pair, get the next one
-      if (in.getc() != '\\' || in.getc() != 'u') {
-	in.ungetc();
-	return false;
-      }
-      int second = _parse_quadhex(in);
-      if (! (0xdc00 <= second && second <= 0xdfff)) {
-	return false;
-      }
-      uni_ch = ((uni_ch - 0xd800) << 10) | ((second - 0xdc00) & 0x3ff);
-      uni_ch += 0x10000;
-    }
-    if (uni_ch < 0x80) {
-      out.push_back(uni_ch);
-    } else {
-      if (uni_ch < 0x800) {
-	out.push_back(0xc0 | (uni_ch >> 6));
-      } else {
-	if (uni_ch < 0x10000) {
-	  out.push_back(0xe0 | (uni_ch >> 12));
-	} else {
-	  out.push_back(0xf0 | (uni_ch >> 18));
-	  out.push_back(0x80 | ((uni_ch >> 12) & 0x3f));
-	}
-	out.push_back(0x80 | ((uni_ch >> 6) & 0x3f));
-      }
-      out.push_back(0x80 | (uni_ch & 0x3f));
-    }
-    return true;
-  }
-  
-  template<typename String, typename Iter> inline bool _parse_string(String& out, input<Iter>& in) {
-    while (1) {
-      int ch = in.getc();
-      if (ch < ' ') {
-	in.ungetc();
-	return false;
-      } else if (ch == '"') {
-	return true;
-      } else if (ch == '\\') {
-	if ((ch = in.getc()) == -1) {
-	  return false;
-	}
-	switch (ch) {
-#define MAP(sym, val) case sym: out.push_back(val); break
-	  MAP('"', '\"');
-	  MAP('\\', '\\');
-	  MAP('/', '/');
-	  MAP('b', '\b');
-	  MAP('f', '\f');
-	  MAP('n', '\n');
-	  MAP('r', '\r');
-	  MAP('t', '\t');
-#undef MAP
-	case 'u':
-	  if (! _parse_codepoint(out, in)) {
-	    return false;
-	  }
-	  break;
-	default:
-	  return false;
-	}
-      } else {
-	out.push_back(ch);
-      }
-    }
-    return false;
-  }
-  
-  template <typename Context, typename Iter> inline bool _parse_array(Context& ctx, input<Iter>& in) {
-    if (! ctx.parse_array_start()) {
-      return false;
-    }
-    size_t idx = 0;
-    if (in.expect(']')) {
-      return ctx.parse_array_stop(idx);
-    }
-    do {
-      if (! ctx.parse_array_item(in, idx)) {
-	return false;
-      }
-      idx++;
-    } while (in.expect(','));
-    return in.expect(']') && ctx.parse_array_stop(idx);
-  }
-  
-  template <typename Context, typename Iter> inline bool _parse_object(Context& ctx, input<Iter>& in) {
-    if (! ctx.parse_object_start()) {
-      return false;
-    }
-    if (in.expect('}')) {
-      return true;
-    }
-    do {
-      std::string key;
-      if (! in.expect('"')
-	  || ! _parse_string(key, in)
-	  || ! in.expect(':')) {
-	return false;
-      }
-      if (! ctx.parse_object_item(in, key)) {
-	return false;
-      }
-    } while (in.expect(','));
-    return in.expect('}');
-  }
-  
-  template <typename Iter> inline std::string _parse_number(input<Iter>& in) {
-    std::string num_str;
-    while (1) {
-      int ch = in.getc();
-      if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-'
-          || ch == 'e' || ch == 'E') {
-        num_str.push_back(ch);
-      } else if (ch == '.') {
-#if PICOJSON_USE_LOCALE
-        num_str += localeconv()->decimal_point;
-#else
-        num_str.push_back('.');
-#endif
-      } else {
-	in.ungetc();
-	break;
-      }
-    }
-    return num_str;
-  }
-  
-  template <typename Context, typename Iter> inline bool _parse(Context& ctx, input<Iter>& in) {
-    in.skip_ws();
-    int ch = in.getc();
-    switch (ch) {
-#define IS(ch, text, op) case ch: \
-      if (in.match(text) && op) { \
-	return true; \
-      } else { \
-	return false; \
-      }
-      IS('n', "ull", ctx.set_null());
-      IS('f', "alse", ctx.set_bool(false));
-      IS('t', "rue", ctx.set_bool(true));
-#undef IS
-    case '"':
-      return ctx.parse_string(in);
-    case '[':
-      return _parse_array(ctx, in);
-    case '{':
-      return _parse_object(ctx, in);
-    default:
-      if (('0' <= ch && ch <= '9') || ch == '-') {
-        double f;
-        char *endp;
-	in.ungetc();
-        std::string num_str = _parse_number(in);
-        if (num_str.empty()) {
-          return false;
-        }
-#ifdef PICOJSON_USE_INT64
-        {
-          errno = 0;
-          intmax_t ival = strtoimax(num_str.c_str(), &endp, 10);
-          if (errno == 0
-              && std::numeric_limits<int64_t>::min() <= ival
-              && ival <= std::numeric_limits<int64_t>::max()
-              && endp == num_str.c_str() + num_str.size()) {
-            ctx.set_int64(ival);
-            return true;
-          }
-        }
-#endif
-        f = strtod(num_str.c_str(), &endp);
-        if (endp == num_str.c_str() + num_str.size()) {
-          ctx.set_number(f);
-          return true;
-        }
-        return false;
-      }
-      break;
-    }
-    in.ungetc();
-    return false;
-  }
-  
-  class deny_parse_context {
-  public:
-    bool set_null() { return false; }
-    bool set_bool(bool) { return false; }
-#ifdef PICOJSON_USE_INT64
-    bool set_int64(int64_t) { return false; }
-#endif
-    bool set_number(double) { return false; }
-    template <typename Iter> bool parse_string(input<Iter>&) { return false; }
-    bool parse_array_start() { return false; }
-    template <typename Iter> bool parse_array_item(input<Iter>&, size_t) {
-      return false;
-    }
-    bool parse_array_stop(size_t) { return false; }
-    bool parse_object_start() { return false; }
-    template <typename Iter> bool parse_object_item(input<Iter>&, const std::string&) {
-      return false;
-    }
-  };
-  
-  class default_parse_context {
-  protected:
-    value* out_;
-  public:
-    default_parse_context(value* out) : out_(out) {}
-    bool set_null() {
-      *out_ = value();
-      return true;
-    }
-    bool set_bool(bool b) {
-      *out_ = value(b);
-      return true;
-    }
-#ifdef PICOJSON_USE_INT64
-    bool set_int64(int64_t i) {
-      *out_ = value(i);
-      return true;
-    }
-#endif
-    bool set_number(double f) {
-      *out_ = value(f);
-      return true;
-    }
-    template<typename Iter> bool parse_string(input<Iter>& in) {
-      *out_ = value(string_type, false);
-      return _parse_string(out_->get<std::string>(), in);
-    }
-    bool parse_array_start() {
-      *out_ = value(array_type, false);
-      return true;
-    }
-    template <typename Iter> bool parse_array_item(input<Iter>& in, size_t) {
-      array& a = out_->get<array>();
-      a.push_back(value());
-      default_parse_context ctx(&a.back());
-      return _parse(ctx, in);
-    }
-    bool parse_array_stop(size_t) { return true; }
-    bool parse_object_start() {
-      *out_ = value(object_type, false);
-      return true;
-    }
-    template <typename Iter> bool parse_object_item(input<Iter>& in, const std::string& key) {
-      object& o = out_->get<object>();
-      default_parse_context ctx(&o[key]);
-      return _parse(ctx, in);
-    }
-  private:
-    default_parse_context(const default_parse_context&);
-    default_parse_context& operator=(const default_parse_context&);
-  };
-
-  class null_parse_context {
-  public:
-    struct dummy_str {
-      void push_back(int) {}
-    };
-  public:
-    null_parse_context() {}
-    bool set_null() { return true; }
-    bool set_bool(bool) { return true; }
-#ifdef PICOJSON_USE_INT64
-    bool set_int64(int64_t) { return true; }
-#endif
-    bool set_number(double) { return true; }
-    template <typename Iter> bool parse_string(input<Iter>& in) {
-      dummy_str s;
-      return _parse_string(s, in);
-    }
-    bool parse_array_start() { return true; }
-    template <typename Iter> bool parse_array_item(input<Iter>& in, size_t) {
-      return _parse(*this, in);
-    }
-    bool parse_array_stop(size_t) { return true; }
-    bool parse_object_start() { return true; }
-    template <typename Iter> bool parse_object_item(input<Iter>& in, const std::string&) {
-      return _parse(*this, in);
-    }
-  private:
-    null_parse_context(const null_parse_context&);
-    null_parse_context& operator=(const null_parse_context&);
-  };
-  
-  // obsolete, use the version below
-  template <typename Iter> inline std::string parse(value& out, Iter& pos, const Iter& last) {
-    std::string err;
-    pos = parse(out, pos, last, &err);
-    return err;
-  }
-  
-  template <typename Context, typename Iter> inline Iter _parse(Context& ctx, const Iter& first, const Iter& last, std::string* err) {
-    input<Iter> in(first, last);
-    if (! _parse(ctx, in) && err != NULL) {
-      char buf[64];
-      SNPRINTF(buf, sizeof(buf), "syntax error at line %d near: ", in.line());
-      *err = buf;
-      while (1) {
-	int ch = in.getc();
-	if (ch == -1 || ch == '\n') {
-	  break;
-	} else if (ch >= ' ') {
-	  err->push_back(ch);
-	}
-      }
-    }
-    return in.cur();
-  }
-  
-  template <typename Iter> inline Iter parse(value& out, const Iter& first, const Iter& last, std::string* err) {
-    default_parse_context ctx(&out);
-    return _parse(ctx, first, last, err);
-  }
-  
-  inline std::string parse(value& out, const std::string& s) {
-    std::string err;
-    parse(out, s.begin(), s.end(), &err);
-    return err;
-  }
-
-  inline std::string parse(value& out, std::istream& is) {
-    std::string err;
-    parse(out, std::istreambuf_iterator<char>(is.rdbuf()),
-	  std::istreambuf_iterator<char>(), &err);
-    return err;
-  }
-  
-  template <typename T> struct last_error_t {
-    static std::string s;
-  };
-  template <typename T> std::string last_error_t<T>::s;
-  
-  inline void set_last_error(const std::string& s) {
-    last_error_t<bool>::s = s;
-  }
-  
-  inline const std::string& get_last_error() {
-    return last_error_t<bool>::s;
-  }
-
-  inline bool operator==(const value& x, const value& y) {
-    if (x.is<null>())
-      return y.is<null>();
-#define PICOJSON_CMP(type)					\
-    if (x.is<type>())						\
-      return y.is<type>() && x.get<type>() == y.get<type>()
-    PICOJSON_CMP(bool);
-    PICOJSON_CMP(double);
-    PICOJSON_CMP(std::string);
-    PICOJSON_CMP(array);
-    PICOJSON_CMP(object);
-#undef PICOJSON_CMP
-    PICOJSON_ASSERT(0);
-#ifdef _MSC_VER
-    __assume(0);
-#endif
-    return false;
-  }
-  
-  inline bool operator!=(const value& x, const value& y) {
-    return ! (x == y);
-  }
-}
-
-#if !PICOJSON_USE_RVALUE_REFERENCE 
-namespace std {
-  template<> inline void swap(picojson::value& x, picojson::value& y)
-    {
-      x.swap(y);
-    }
-}
-#endif
-
-inline std::istream& operator>>(std::istream& is, picojson::value& x)
-{
-  picojson::set_last_error(std::string());
-  std::string err = picojson::parse(x, is);
-  if (! err.empty()) {
-    picojson::set_last_error(err);
-    is.setstate(std::ios::failbit);
-  }
-  return is;
-}
-
-inline std::ostream& operator<<(std::ostream& os, const picojson::value& x)
-{
-  x.serialize(std::ostream_iterator<char>(os));
-  return os;
-}
-#ifdef _MSC_VER
-    #pragma warning(pop)
-#endif
-
-#endif
diff --git a/third_party/tinygltfloader/tiny_gltf_loader.h b/third_party/tinygltfloader/tiny_gltf_loader.h
deleted file mode 100644
index 4792721..0000000
--- a/third_party/tinygltfloader/tiny_gltf_loader.h
+++ /dev/null
@@ -1,2656 +0,0 @@
-//
-// Tiny glTF loader.
-//
-//
-// The MIT License (MIT)
-//
-// Copyright (c) 2015 - 2016 Syoyo Fujita and many contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-// Version:
-//  - v0.9.5 Support parsing `extras` parameter.
-//  - v0.9.4 Support parsing `shader`, `program` and `tecnique` thanks to
-//  @lukesanantonio
-//  - v0.9.3 Support binary glTF
-//  - v0.9.2 Support parsing `texture`
-//  - v0.9.1 Support loading glTF asset from memory
-//  - v0.9.0 Initial
-//
-// Tiny glTF loader is using following third party libraries:
-//
-//  - picojson: C++ JSON library.
-//  - base64: base64 decode/encode library.
-//  - stb_image: Image loading library.
-//
-#ifndef TINY_GLTF_LOADER_H_
-#define TINY_GLTF_LOADER_H_
-
-#include <cassert>
-#include <cstring>
-#include <map>
-#include <string>
-#include <vector>
-
-namespace tinygltf {
-
-#define TINYGLTF_MODE_POINTS (0)
-#define TINYGLTF_MODE_LINE (1)
-#define TINYGLTF_MODE_LINE_LOOP (2)
-#define TINYGLTF_MODE_TRIANGLES (4)
-#define TINYGLTF_MODE_TRIANGLE_STRIP (5)
-#define TINYGLTF_MODE_TRIANGLE_FAN (6)
-
-#define TINYGLTF_COMPONENT_TYPE_BYTE (5120)
-#define TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE (5121)
-#define TINYGLTF_COMPONENT_TYPE_SHORT (5122)
-#define TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT (5123)
-#define TINYGLTF_COMPONENT_TYPE_INT (5124)
-#define TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT (5125)
-#define TINYGLTF_COMPONENT_TYPE_FLOAT (5126)
-#define TINYGLTF_COMPONENT_TYPE_DOUBLE (5127)
-
-#define TINYGLTF_TEXTURE_FILTER_NEAREST (9728)
-#define TINYGLTF_TEXTURE_FILTER_LINEAR (9729)
-#define TINYGLTF_TEXTURE_FILTER_NEAREST_MIPMAP_NEAREST (9984)
-#define TINYGLTF_TEXTURE_FILTER_LINEAR_MIPMAP_NEAREST (9985)
-#define TINYGLTF_TEXTURE_FILTER_NEAREST_MIPMAP_LINEAR (9986)
-#define TINYGLTF_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR (9987)
-
-#define TINYGLTF_TEXTURE_WRAP_RPEAT (10497)
-#define TINYGLTF_TEXTURE_WRAP_CLAMP_TO_EDGE (33071)
-#define TINYGLTF_TEXTURE_WRAP_MIRRORED_REPEAT (33648)
-
-// Redeclarations of the above for technique.parameters.
-#define TINYGLTF_PARAMETER_TYPE_BYTE (5120)
-#define TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE (5121)
-#define TINYGLTF_PARAMETER_TYPE_SHORT (5122)
-#define TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT (5123)
-#define TINYGLTF_PARAMETER_TYPE_INT (5124)
-#define TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT (5125)
-#define TINYGLTF_PARAMETER_TYPE_FLOAT (5126)
-
-#define TINYGLTF_PARAMETER_TYPE_FLOAT_VEC2 (35664)
-#define TINYGLTF_PARAMETER_TYPE_FLOAT_VEC3 (35665)
-#define TINYGLTF_PARAMETER_TYPE_FLOAT_VEC4 (35666)
-
-#define TINYGLTF_PARAMETER_TYPE_INT_VEC2 (35667)
-#define TINYGLTF_PARAMETER_TYPE_INT_VEC3 (35668)
-#define TINYGLTF_PARAMETER_TYPE_INT_VEC4 (35669)
-
-#define TINYGLTF_PARAMETER_TYPE_BOOL (35670)
-#define TINYGLTF_PARAMETER_TYPE_BOOL_VEC2 (35671)
-#define TINYGLTF_PARAMETER_TYPE_BOOL_VEC3 (35672)
-#define TINYGLTF_PARAMETER_TYPE_BOOL_VEC4 (35673)
-
-#define TINYGLTF_PARAMETER_TYPE_FLOAT_MAT2 (35674)
-#define TINYGLTF_PARAMETER_TYPE_FLOAT_MAT3 (35675)
-#define TINYGLTF_PARAMETER_TYPE_FLOAT_MAT4 (35676)
-
-#define TINYGLTF_PARAMETER_TYPE_SAMPLER_2D (35678)
-
-// End parameter types
-
-#define TINYGLTF_TYPE_VEC2 (2)
-#define TINYGLTF_TYPE_VEC3 (3)
-#define TINYGLTF_TYPE_VEC4 (4)
-#define TINYGLTF_TYPE_MAT2 (32 + 2)
-#define TINYGLTF_TYPE_MAT3 (32 + 3)
-#define TINYGLTF_TYPE_MAT4 (32 + 4)
-#define TINYGLTF_TYPE_SCALAR (64 + 1)
-#define TINYGLTF_TYPE_VECTOR (64 + 4)
-#define TINYGLTF_TYPE_MATRIX (64 + 16)
-
-#define TINYGLTF_IMAGE_FORMAT_JPEG (0)
-#define TINYGLTF_IMAGE_FORMAT_PNG (1)
-#define TINYGLTF_IMAGE_FORMAT_BMP (2)
-#define TINYGLTF_IMAGE_FORMAT_GIF (3)
-
-#define TINYGLTF_TEXTURE_FORMAT_ALPHA (6406)
-#define TINYGLTF_TEXTURE_FORMAT_RGB (6407)
-#define TINYGLTF_TEXTURE_FORMAT_RGBA (6408)
-#define TINYGLTF_TEXTURE_FORMAT_LUMINANCE (6409)
-#define TINYGLTF_TEXTURE_FORMAT_LUMINANCE_ALPHA (6410)
-
-#define TINYGLTF_TEXTURE_TARGET_TEXTURE2D (3553)
-#define TINYGLTF_TEXTURE_TYPE_UNSIGNED_BYTE (5121)
-
-#define TINYGLTF_TARGET_ARRAY_BUFFER (34962)
-#define TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER (34963)
-
-#define TINYGLTF_SHADER_TYPE_VERTEX_SHADER (35633)
-#define TINYGLTF_SHADER_TYPE_FRAGMENT_SHADER (35632)
-
-typedef enum {
-  NULL_TYPE = 0,
-  NUMBER_TYPE = 1,
-  INT_TYPE = 2,
-  BOOL_TYPE = 3,
-  STRING_TYPE = 4,
-  ARRAY_TYPE = 5,
-  BINARY_TYPE = 6,
-  OBJECT_TYPE = 7
-} Type;
-
-// Simple class to represent JSON object
-class Value {
- public:
-  typedef std::vector<Value> Array;
-  typedef std::map<std::string, Value> Object;
-
-  Value() : type_(NULL_TYPE) {}
-
-  explicit Value(bool b) : type_(BOOL_TYPE) { boolean_value_ = b; }
-  explicit Value(int i) : type_(INT_TYPE) { int_value_ = i; }
-  explicit Value(double n) : type_(NUMBER_TYPE) { number_value_ = n; }
-  explicit Value(const std::string &s) : type_(STRING_TYPE) {
-    string_value_ = s;
-  }
-  explicit Value(const unsigned char *p, size_t n) : type_(BINARY_TYPE) {
-    binary_value_.resize(n);
-    memcpy(binary_value_.data(), p, n);
-  }
-  explicit Value(const Array &a) : type_(ARRAY_TYPE) {
-    array_value_ = Array(a);
-  }
-  explicit Value(const Object &o) : type_(OBJECT_TYPE) {
-    object_value_ = Object(o);
-  }
-
-  char Type() const { return static_cast<const char>(type_); }
-
-  bool IsBool() const { return (type_ == BOOL_TYPE); }
-
-  bool IsInt() const { return (type_ == INT_TYPE); }
-
-  bool IsNumber() const { return (type_ == NUMBER_TYPE); }
-
-  bool IsString() const { return (type_ == STRING_TYPE); }
-
-  bool IsBinary() const { return (type_ == BINARY_TYPE); }
-
-  bool IsArray() const { return (type_ == ARRAY_TYPE); }
-
-  bool IsObject() const { return (type_ == OBJECT_TYPE); }
-
-  // Accessor
-  template <typename T>
-  const T &Get() const;
-  template <typename T>
-  T &Get();
-
-  // Lookup value from an array
-  const Value &Get(int idx) const {
-    static Value &null_value = *(new Value());
-    assert(IsArray());
-    assert(idx >= 0);
-    return (static_cast<size_t>(idx) < array_value_.size())
-               ? array_value_[static_cast<size_t>(idx)]
-               : null_value;
-  }
-
-  // Lookup value from a key-value pair
-  const Value &Get(const std::string &key) const {
-    static Value &null_value = *(new Value());
-    assert(IsObject());
-    Object::const_iterator it = object_value_.find(key);
-    return (it != object_value_.end()) ? it->second : null_value;
-  }
-
-  size_t ArrayLen() const {
-    if (!IsArray()) return 0;
-    return array_value_.size();
-  }
-
-  // Valid only for object type.
-  bool Has(const std::string &key) const {
-    if (!IsObject()) return false;
-    Object::const_iterator it = object_value_.find(key);
-    return (it != object_value_.end()) ? true : false;
-  }
-
-  // List keys
-  std::vector<std::string> Keys() const {
-    std::vector<std::string> keys;
-    if (!IsObject()) return keys;  // empty
-
-    for (Object::const_iterator it = object_value_.begin();
-         it != object_value_.end(); ++it) {
-      keys.push_back(it->first);
-    }
-
-    return keys;
-  }
-
- protected:
-  int type_;
-
-  int int_value_;
-  double number_value_;
-  std::string string_value_;
-  std::vector<unsigned char> binary_value_;
-  Array array_value_;
-  Object object_value_;
-  bool boolean_value_;
-  char pad[3];
-
-  int pad0;
-};
-
-#define TINYGLTF_VALUE_GET(ctype, var)            \
-  template <>                                     \
-  inline const ctype &Value::Get<ctype>() const { \
-    return var;                                   \
-  }                                               \
-  template <>                                     \
-  inline ctype &Value::Get<ctype>() {             \
-    return var;                                   \
-  }
-TINYGLTF_VALUE_GET(bool, boolean_value_)
-TINYGLTF_VALUE_GET(double, number_value_)
-TINYGLTF_VALUE_GET(int, int_value_)
-TINYGLTF_VALUE_GET(std::string, string_value_)
-TINYGLTF_VALUE_GET(std::vector<unsigned char>, binary_value_)
-TINYGLTF_VALUE_GET(Value::Array, array_value_)
-TINYGLTF_VALUE_GET(Value::Object, object_value_)
-#undef TINYGLTF_VALUE_GET
-
-typedef struct {
-  std::string string_value;
-  std::vector<double> number_array;
-} Parameter;
-
-typedef std::map<std::string, Parameter> ParameterMap;
-
-typedef struct {
-  std::string sampler;
-  std::string target_id;
-  std::string target_path;
-  Value extras;
-} AnimationChannel;
-
-typedef struct {
-  std::string input;
-  std::string interpolation;
-  std::string output;
-  Value extras;
-} AnimationSampler;
-
-typedef struct {
-  std::string name;
-  std::vector<AnimationChannel> channels;
-  std::map<std::string, AnimationSampler> samplers;
-  ParameterMap parameters;
-  Value extras;
-} Animation;
-
-typedef struct {
-  std::string name;
-  int minFilter;
-  int magFilter;
-  int wrapS;
-  int wrapT;
-  int wrapR;  // TinyGLTF extension
-  int pad0;
-  Value extras;
-} Sampler;
-
-typedef struct {
-  std::string name;
-  int width;
-  int height;
-  int component;
-  int pad0;
-  std::vector<unsigned char> image;
-
-  std::string bufferView;  // KHR_binary_glTF extenstion.
-  std::string mimeType;    // KHR_binary_glTF extenstion.
-
-  Value extras;
-} Image;
-
-typedef struct {
-  int format;
-  int internalFormat;
-  std::string sampler;  // Required
-  std::string source;   // Required
-  int target;
-  int type;
-  std::string name;
-  Value extras;
-} Texture;
-
-typedef struct {
-  std::string name;
-  std::string technique;
-  ParameterMap values;
-
-  Value extras;
-} Material;
-
-typedef struct {
-  std::string name;
-  std::string buffer;  // Required
-  size_t byteOffset;   // Required
-  size_t byteLength;   // default: 0
-  int target;
-  int pad0;
-  Value extras;
-} BufferView;
-
-typedef struct {
-  std::string bufferView;
-  std::string name;
-  size_t byteOffset;
-  size_t byteStride;
-  int componentType;  // One of TINYGLTF_COMPONENT_TYPE_***
-  int pad0;
-  size_t count;
-  int type;  // One of TINYGLTF_TYPE_***
-  int pad1;
-  std::vector<double> minValues;  // Optional
-  std::vector<double> maxValues;  // Optional
-  Value extras;
-} Accessor;
-
-class Camera {
- public:
-  Camera() {}
-  ~Camera() {}
-
-  std::string name;
-  bool isOrthographic;  // false = perspective.
-
-  // Some common properties.
-  float aspectRatio;
-  float yFov;
-  float zFar;
-  float zNear;
-};
-
-typedef struct {
-  std::map<std::string, std::string> attributes;  // A dictionary object of
-                                                  // strings, where each string
-                                                  // is the ID of the accessor
-                                                  // containing an attribute.
-  std::string material;  // The ID of the material to apply to this primitive
-                         // when rendering.
-  std::string indices;   // The ID of the accessor that contains the indices.
-  int mode;              // one of TINYGLTF_MODE_***
-  int pad0;
-
-  Value extras;  // "extra" property
-} Primitive;
-
-typedef struct {
-  std::string name;
-  std::vector<Primitive> primitives;
-  Value extras;
-} Mesh;
-
-class Node {
- public:
-  Node() {}
-  ~Node() {}
-
-  std::string camera;  // camera object referenced by this node.
-
-  std::string name;
-  std::vector<std::string> children;
-  std::vector<double> rotation;     // length must be 0 or 4
-  std::vector<double> scale;        // length must be 0 or 3
-  std::vector<double> translation;  // length must be 0 or 3
-  std::vector<double> matrix;       // length must be 0 or 16
-  std::vector<std::string> meshes;
-
-  Value extras;
-};
-
-typedef struct {
-  std::string name;
-  std::vector<unsigned char> data;
-  Value extras;
-} Buffer;
-
-typedef struct {
-  std::string name;
-  int type;
-  int pad0;
-  std::vector<unsigned char> source;
-
-  Value extras;
-} Shader;
-
-typedef struct {
-  std::string name;
-  std::string vertexShader;
-  std::string fragmentShader;
-  std::vector<std::string> attributes;
-
-  Value extras;
-} Program;
-
-typedef struct {
-  int count;
-  int pad0;
-  std::string node;
-  std::string semantic;
-  int type;
-  int pad1;
-  Parameter value;
-} TechniqueParameter;
-
-typedef struct {
-  std::string name;
-  std::string program;
-  std::map<std::string, TechniqueParameter> parameters;
-  std::map<std::string, std::string> attributes;
-  std::map<std::string, std::string> uniforms;
-
-  Value extras;
-} Technique;
-
-typedef struct {
-  std::string generator;
-  std::string version;
-  std::string profile_api;
-  std::string profile_version;
-  bool premultipliedAlpha;
-  char pad[7];
-  Value extras;
-} Asset;
-
-class Scene {
- public:
-  Scene() {}
-  ~Scene() {}
-
-  std::map<std::string, Accessor> accessors;
-  std::map<std::string, Animation> animations;
-  std::map<std::string, Buffer> buffers;
-  std::map<std::string, BufferView> bufferViews;
-  std::map<std::string, Material> materials;
-  std::map<std::string, Mesh> meshes;
-  std::map<std::string, Node> nodes;
-  std::map<std::string, Texture> textures;
-  std::map<std::string, Image> images;
-  std::map<std::string, Shader> shaders;
-  std::map<std::string, Program> programs;
-  std::map<std::string, Technique> techniques;
-  std::map<std::string, Sampler> samplers;
-  std::map<std::string, std::vector<std::string> > scenes;  // list of nodes
-
-  std::string defaultScene;
-
-  Asset asset;
-
-  Value extras;
-};
-
-enum SectionCheck {
-  NO_REQUIRE = 0x00,
-  REQUIRE_SCENE = 0x01,
-  REQUIRE_SCENES = 0x02,
-  REQUIRE_NODES = 0x04,
-  REQUIRE_ACCESSORS = 0x08,
-  REQUIRE_BUFFERS = 0x10,
-  REQUIRE_BUFFER_VIEWS = 0x20,
-  REQUIRE_ALL = 0x3f
-};
-
-class TinyGLTFLoader {
- public:
-  TinyGLTFLoader() : bin_data_(NULL), bin_size_(0), is_binary_(false) {
-    pad[0] = pad[1] = pad[2] = pad[3] = pad[4] = pad[5] = pad[6] = 0;
-  }
-  ~TinyGLTFLoader() {}
-
-  /// Loads glTF ASCII asset from a file.
-  /// Returns false and set error string to `err` if there's an error.
-  bool LoadASCIIFromFile(Scene *scene, std::string *err,
-                         const std::string &filename,
-                         unsigned int check_sections = REQUIRE_ALL);
-
-  /// Loads glTF ASCII asset from string(memory).
-  /// `length` = strlen(str);
-  /// Returns false and set error string to `err` if there's an error.
-  bool LoadASCIIFromString(Scene *scene, std::string *err, const char *str,
-                           const unsigned int length,
-                           const std::string &base_dir,
-                           unsigned int check_sections = REQUIRE_ALL);
-
-  /// Loads glTF binary asset from a file.
-  /// Returns false and set error string to `err` if there's an error.
-  bool LoadBinaryFromFile(Scene *scene, std::string *err,
-                          const std::string &filename,
-                          unsigned int check_sections = REQUIRE_ALL);
-
-  /// Loads glTF binary asset from memory.
-  /// `length` = strlen(str);
-  /// Returns false and set error string to `err` if there's an error.
-  bool LoadBinaryFromMemory(Scene *scene, std::string *err,
-                            const unsigned char *bytes,
-                            const unsigned int length,
-                            const std::string &base_dir = "",
-                            unsigned int check_sections = REQUIRE_ALL);
-
- private:
-  /// Loads glTF asset from string(memory).
-  /// `length` = strlen(str);
-  /// Returns false and set error string to `err` if there's an error.
-  bool LoadFromString(Scene *scene, std::string *err, const char *str,
-                      const unsigned int length, const std::string &base_dir,
-                      unsigned int check_sections);
-
-  const unsigned char *bin_data_;
-  size_t bin_size_;
-  bool is_binary_;
-  char pad[7];
-};
-
-}  // namespace tinygltf
-
-#ifdef TINYGLTF_LOADER_IMPLEMENTATION
-#include <algorithm>
-//#include <cassert>
-#include <fstream>
-#include <sstream>
-
-#ifdef __clang__
-// Disable some warnings for external files.
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wfloat-equal"
-#pragma clang diagnostic ignored "-Wexit-time-destructors"
-#pragma clang diagnostic ignored "-Wconversion"
-#pragma clang diagnostic ignored "-Wold-style-cast"
-#pragma clang diagnostic ignored "-Wdouble-promotion"
-#pragma clang diagnostic ignored "-Wglobal-constructors"
-#pragma clang diagnostic ignored "-Wreserved-id-macro"
-#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
-#pragma clang diagnostic ignored "-Wpadded"
-#endif
-
-#define PICOJSON_USE_INT64
-#include "picojson/picojson.h"
-#include "stb/stb_image.h"
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
-#ifdef _WIN32
-#include <Windows.h>
-#else
-#include <wordexp.h>
-#endif
-
-#if defined(__sparcv9)
-// Big endian
-#else
-#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU
-#define TINYGLTF_LITTLE_ENDIAN 1
-#endif
-#endif
-
-namespace tinygltf {
-
-static void swap4(unsigned int *val) {
-#ifdef TINYGLTF_LITTLE_ENDIAN
-  (void)val;
-#else
-  unsigned int tmp = *val;
-  unsigned char *dst = reinterpret_cast<unsigned char *>(val);
-  unsigned char *src = reinterpret_cast<unsigned char *>(&tmp);
-
-  dst[0] = src[3];
-  dst[1] = src[2];
-  dst[2] = src[1];
-  dst[3] = src[0];
-#endif
-}
-
-static bool FileExists(const std::string &abs_filename) {
-  bool ret;
-#ifdef _WIN32
-  FILE *fp;
-  errno_t err = fopen_s(&fp, abs_filename.c_str(), "rb");
-  if (err != 0) {
-    return false;
-  }
-#else
-  FILE *fp = fopen(abs_filename.c_str(), "rb");
-#endif
-  if (fp) {
-    ret = true;
-    fclose(fp);
-  } else {
-    ret = false;
-  }
-
-  return ret;
-}
-
-static std::string ExpandFilePath(const std::string &filepath) {
-#ifdef _WIN32
-  DWORD len = ExpandEnvironmentStringsA(filepath.c_str(), NULL, 0);
-  char *str = new char[len];
-  ExpandEnvironmentStringsA(filepath.c_str(), str, len);
-
-  std::string s(str);
-
-  delete[] str;
-
-  return s;
-#else
-
-#if defined(TARGET_OS_IPHONE) || defined(TARGET_IPHONE_SIMULATOR)
-  // no expansion
-  std::string s = filepath;
-#else
-  std::string s;
-  wordexp_t p;
-
-  if (filepath.empty()) {
-    return "";
-  }
-
-  // char** w;
-  int ret = wordexp(filepath.c_str(), &p, 0);
-  if (ret) {
-    // err
-    s = filepath;
-    return s;
-  }
-
-  // Use first element only.
-  if (p.we_wordv) {
-    s = std::string(p.we_wordv[0]);
-    wordfree(&p);
-  } else {
-    s = filepath;
-  }
-
-#endif
-
-  return s;
-#endif
-}
-
-static std::string JoinPath(const std::string &path0,
-                            const std::string &path1) {
-  if (path0.empty()) {
-    return path1;
-  } else {
-    // check '/'
-    char lastChar = *path0.rbegin();
-    if (lastChar != '/') {
-      return path0 + std::string("/") + path1;
-    } else {
-      return path0 + path1;
-    }
-  }
-}
-
-static std::string FindFile(const std::vector<std::string> &paths,
-                            const std::string &filepath) {
-  for (size_t i = 0; i < paths.size(); i++) {
-    std::string absPath = ExpandFilePath(JoinPath(paths[i], filepath));
-    if (FileExists(absPath)) {
-      return absPath;
-    }
-  }
-
-  return std::string();
-}
-
-// std::string GetFilePathExtension(const std::string& FileName)
-//{
-//    if(FileName.find_last_of(".") != std::string::npos)
-//        return FileName.substr(FileName.find_last_of(".")+1);
-//    return "";
-//}
-
-static std::string GetBaseDir(const std::string &filepath) {
-  if (filepath.find_last_of("/\\") != std::string::npos)
-    return filepath.substr(0, filepath.find_last_of("/\\"));
-  return "";
-}
-
-// std::string base64_encode(unsigned char const* , unsigned int len);
-std::string base64_decode(std::string const &s);
-
-/*
-   base64.cpp and base64.h
-
-   Copyright (C) 2004-2008 René Nyffenegger
-
-   This source code is provided 'as-is', without any express or implied
-   warranty. In no event will the author be held liable for any damages
-   arising from the use of this software.
-
-   Permission is granted to anyone to use this software for any purpose,
-   including commercial applications, and to alter it and redistribute it
-   freely, subject to the following restrictions:
-
-   1. The origin of this source code must not be misrepresented; you must not
-      claim that you wrote the original source code. If you use this source code
-      in a product, an acknowledgment in the product documentation would be
-      appreciated but is not required.
-
-   2. Altered source versions must be plainly marked as such, and must not be
-      misrepresented as being the original source code.
-
-   3. This notice may not be removed or altered from any source distribution.
-
-   René Nyffenegger rene.nyffenegger@adp-gmbh.ch
-
-*/
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wexit-time-destructors"
-#pragma clang diagnostic ignored "-Wglobal-constructors"
-#pragma clang diagnostic ignored "-Wsign-conversion"
-#pragma clang diagnostic ignored "-Wconversion"
-#endif
-static const std::string base64_chars =
-    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-    "abcdefghijklmnopqrstuvwxyz"
-    "0123456789+/";
-
-static inline bool is_base64(unsigned char c) {
-  return (isalnum(c) || (c == '+') || (c == '/'));
-}
-
-std::string base64_decode(std::string const &encoded_string) {
-  int in_len = static_cast<int>(encoded_string.size());
-  int i = 0;
-  int j = 0;
-  int in_ = 0;
-  unsigned char char_array_4[4], char_array_3[3];
-  std::string ret;
-
-  while (in_len-- && (encoded_string[in_] != '=') &&
-         is_base64(encoded_string[in_])) {
-    char_array_4[i++] = encoded_string[in_];
-    in_++;
-    if (i == 4) {
-      for (i = 0; i < 4; i++)
-        char_array_4[i] =
-            static_cast<unsigned char>(base64_chars.find(char_array_4[i]));
-
-      char_array_3[0] =
-          (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
-      char_array_3[1] =
-          ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
-      char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
-
-      for (i = 0; (i < 3); i++) ret += char_array_3[i];
-      i = 0;
-    }
-  }
-
-  if (i) {
-    for (j = i; j < 4; j++) char_array_4[j] = 0;
-
-    for (j = 0; j < 4; j++)
-      char_array_4[j] =
-          static_cast<unsigned char>(base64_chars.find(char_array_4[j]));
-
-    char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
-    char_array_3[1] =
-        ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
-    char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
-
-    for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
-  }
-
-  return ret;
-}
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
-static bool LoadExternalFile(std::vector<unsigned char> *out, std::string *err,
-                             const std::string &filename,
-                             const std::string &basedir, size_t reqBytes,
-                             bool checkSize) {
-  out->clear();
-
-  std::vector<std::string> paths;
-  paths.push_back(basedir);
-  paths.push_back(".");
-
-  std::string filepath = FindFile(paths, filename);
-  if (filepath.empty()) {
-    if (err) {
-      (*err) += "File not found : " + filename + "\n";
-    }
-    return false;
-  }
-
-  std::ifstream f(filepath.c_str(), std::ifstream::binary);
-  if (!f) {
-    if (err) {
-      (*err) += "File open error : " + filepath + "\n";
-    }
-    return false;
-  }
-
-  f.seekg(0, f.end);
-  size_t sz = static_cast<size_t>(f.tellg());
-  std::vector<unsigned char> buf(sz);
-
-  f.seekg(0, f.beg);
-  f.read(reinterpret_cast<char *>(&buf.at(0)),
-         static_cast<std::streamsize>(sz));
-  f.close();
-
-  if (checkSize) {
-    if (reqBytes == sz) {
-      out->swap(buf);
-      return true;
-    } else {
-      std::stringstream ss;
-      ss << "File size mismatch : " << filepath << ", requestedBytes "
-         << reqBytes << ", but got " << sz << std::endl;
-      if (err) {
-        (*err) += ss.str();
-      }
-      return false;
-    }
-  }
-
-  out->swap(buf);
-  return true;
-}
-
-static bool LoadImageData(Image *image, std::string *err, int req_width,
-                          int req_height, const unsigned char *bytes,
-                          int size) {
-  int w, h, comp;
-  unsigned char *data = stbi_load_from_memory(bytes, size, &w, &h, &comp, 0);
-  if (!data) {
-    if (err) {
-      (*err) += "Unknown image format.\n";
-    }
-    return false;
-  }
-
-  if (w < 1 || h < 1) {
-    free(data);
-    if (err) {
-      (*err) += "Unknown image format.\n";
-    }
-    return false;
-  }
-
-  if (req_width > 0) {
-    if (req_width != w) {
-      free(data);
-      if (err) {
-        (*err) += "Image width mismatch.\n";
-      }
-      return false;
-    }
-  }
-
-  if (req_height > 0) {
-    if (req_height != h) {
-      free(data);
-      if (err) {
-        (*err) += "Image height mismatch.\n";
-      }
-      return false;
-    }
-  }
-
-  image->width = w;
-  image->height = h;
-  image->component = comp;
-  image->image.resize(static_cast<size_t>(w * h * comp));
-  std::copy(data, data + w * h * comp, image->image.begin());
-
-  free(data);
-
-  return true;
-}
-
-static bool IsDataURI(const std::string &in) {
-  std::string header = "data:application/octet-stream;base64,";
-  if (in.find(header) == 0) {
-    return true;
-  }
-
-  header = "data:image/png;base64,";
-  if (in.find(header) == 0) {
-    return true;
-  }
-
-  header = "data:image/jpeg;base64,";
-  if (in.find(header) == 0) {
-    return true;
-  }
-
-  header = "data:text/plain;base64,";
-  if (in.find(header) == 0) {
-    return true;
-  }
-
-  return false;
-}
-
-static bool DecodeDataURI(std::vector<unsigned char> *out,
-                          const std::string &in, size_t reqBytes,
-                          bool checkSize) {
-  std::string header = "data:application/octet-stream;base64,";
-  std::string data;
-  if (in.find(header) == 0) {
-    data = base64_decode(in.substr(header.size()));  // cut mime string.
-  }
-
-  if (data.empty()) {
-    header = "data:image/jpeg;base64,";
-    if (in.find(header) == 0) {
-      data = base64_decode(in.substr(header.size()));  // cut mime string.
-    }
-  }
-
-  if (data.empty()) {
-    header = "data:image/png;base64,";
-    if (in.find(header) == 0) {
-      data = base64_decode(in.substr(header.size()));  // cut mime string.
-    }
-  }
-
-  if (data.empty()) {
-    header = "data:text/plain;base64,";
-    if (in.find(header) == 0) {
-      data = base64_decode(in.substr(header.size()));
-    }
-  }
-
-  if (data.empty()) {
-    return false;
-  }
-
-  if (checkSize) {
-    if (data.size() != reqBytes) {
-      return false;
-    }
-    out->resize(reqBytes);
-  } else {
-    out->resize(data.size());
-  }
-  std::copy(data.begin(), data.end(), out->begin());
-  return true;
-}
-
-static void ParseObjectProperty(Value *ret, const picojson::object &o) {
-  tinygltf::Value::Object vo;
-  picojson::object::const_iterator it(o.begin());
-  picojson::object::const_iterator itEnd(o.end());
-
-  for (; it != itEnd; it++) {
-    picojson::value v = it->second;
-
-    if (v.is<bool>()) {
-      vo[it->first] = tinygltf::Value(v.get<bool>());
-    } else if (v.is<double>()) {
-      vo[it->first] = tinygltf::Value(v.get<double>());
-    } else if (v.is<int64_t>()) {
-      vo[it->first] =
-          tinygltf::Value(static_cast<int>(v.get<int64_t>()));  // truncate
-    } else if (v.is<std::string>()) {
-      vo[it->first] = tinygltf::Value(v.get<std::string>());
-    } else if (v.is<picojson::object>()) {
-      tinygltf::Value child_value;
-      ParseObjectProperty(&child_value, v.get<picojson::object>());
-    }
-    // TODO(syoyo) binary, array
-  }
-
-  (*ret) = tinygltf::Value(vo);
-}
-
-static bool ParseExtrasProperty(Value *ret, const picojson::object &o) {
-  picojson::object::const_iterator it = o.find("extras");
-  if (it == o.end()) {
-    return false;
-  }
-
-  // FIXME(syoyo) Currently we only support `object` type for extras property.
-  if (!it->second.is<picojson::object>()) {
-    return false;
-  }
-
-  ParseObjectProperty(ret, it->second.get<picojson::object>());
-
-  return true;
-}
-
-static bool ParseBooleanProperty(bool *ret, std::string *err,
-                                 const picojson::object &o,
-                                 const std::string &property, bool required) {
-  picojson::object::const_iterator it = o.find(property);
-  if (it == o.end()) {
-    if (required) {
-      if (err) {
-        (*err) += "'" + property + "' property is missing.\n";
-      }
-    }
-    return false;
-  }
-
-  if (!it->second.is<bool>()) {
-    if (required) {
-      if (err) {
-        (*err) += "'" + property + "' property is not a bool type.\n";
-      }
-    }
-    return false;
-  }
-
-  if (ret) {
-    (*ret) = it->second.get<bool>();
-  }
-
-  return true;
-}
-
-static bool ParseNumberProperty(double *ret, std::string *err,
-                                const picojson::object &o,
-                                const std::string &property, bool required) {
-  picojson::object::const_iterator it = o.find(property);
-  if (it == o.end()) {
-    if (required) {
-      if (err) {
-        (*err) += "'" + property + "' property is missing.\n";
-      }
-    }
-    return false;
-  }
-
-  if (!it->second.is<double>()) {
-    if (required) {
-      if (err) {
-        (*err) += "'" + property + "' property is not a number type.\n";
-      }
-    }
-    return false;
-  }
-
-  if (ret) {
-    (*ret) = it->second.get<double>();
-  }
-
-  return true;
-}
-
-static bool ParseNumberArrayProperty(std::vector<double> *ret, std::string *err,
-                                     const picojson::object &o,
-                                     const std::string &property,
-                                     bool required) {
-  picojson::object::const_iterator it = o.find(property);
-  if (it == o.end()) {
-    if (required) {
-      if (err) {
-        (*err) += "'" + property + "' property is missing.\n";
-      }
-    }
-    return false;
-  }
-
-  if (!it->second.is<picojson::array>()) {
-    if (required) {
-      if (err) {
-        (*err) += "'" + property + "' property is not an array.\n";
-      }
-    }
-    return false;
-  }
-
-  ret->clear();
-  const picojson::array &arr = it->second.get<picojson::array>();
-  for (size_t i = 0; i < arr.size(); i++) {
-    if (!arr[i].is<double>()) {
-      if (required) {
-        if (err) {
-          (*err) += "'" + property + "' property is not a number.\n";
-        }
-      }
-      return false;
-    }
-    ret->push_back(arr[i].get<double>());
-  }
-
-  return true;
-}
-
-static bool ParseStringProperty(
-    std::string *ret, std::string *err, const picojson::object &o,
-    const std::string &property, bool required,
-    const std::string &parent_node = std::string()) {
-  picojson::object::const_iterator it = o.find(property);
-  if (it == o.end()) {
-    if (required) {
-      if (err) {
-        (*err) += "'" + property + "' property is missing";
-        if (parent_node.empty()) {
-          (*err) += ".\n";
-        } else {
-          (*err) += " in `" + parent_node + "'.\n";
-        }
-      }
-    }
-    return false;
-  }
-
-  if (!it->second.is<std::string>()) {
-    if (required) {
-      if (err) {
-        (*err) += "'" + property + "' property is not a string type.\n";
-      }
-    }
-    return false;
-  }
-
-  if (ret) {
-    (*ret) = it->second.get<std::string>();
-  }
-
-  return true;
-}
-
-static bool ParseStringArrayProperty(std::vector<std::string> *ret,
-                                     std::string *err,
-                                     const picojson::object &o,
-                                     const std::string &property,
-                                     bool required) {
-  picojson::object::const_iterator it = o.find(property);
-  if (it == o.end()) {
-    if (required) {
-      if (err) {
-        (*err) += "'" + property + "' property is missing.\n";
-      }
-    }
-    return false;
-  }
-
-  if (!it->second.is<picojson::array>()) {
-    if (required) {
-      if (err) {
-        (*err) += "'" + property + "' property is not an array.\n";
-      }
-    }
-    return false;
-  }
-
-  ret->clear();
-  const picojson::array &arr = it->second.get<picojson::array>();
-  for (size_t i = 0; i < arr.size(); i++) {
-    if (!arr[i].is<std::string>()) {
-      if (required) {
-        if (err) {
-          (*err) += "'" + property + "' property is not a string.\n";
-        }
-      }
-      return false;
-    }
-    ret->push_back(arr[i].get<std::string>());
-  }
-
-  return true;
-}
-
-static bool ParseStringMapProperty(std::map<std::string, std::string> *ret,
-                                   std::string *err, const picojson::object &o,
-                                   const std::string &property, bool required) {
-  picojson::object::const_iterator it = o.find(property);
-  if (it == o.end()) {
-    if (required) {
-      if (err) {
-        (*err) += "'" + property + "' property is missing.\n";
-      }
-    }
-    return false;
-  }
-
-  // Make sure we are dealing with an object / dictionary.
-  if (!it->second.is<picojson::object>()) {
-    if (required) {
-      if (err) {
-        (*err) += "'" + property + "' property is not an object.\n";
-      }
-    }
-    return false;
-  }
-
-  ret->clear();
-  const picojson::object &dict = it->second.get<picojson::object>();
-
-  picojson::object::const_iterator dictIt(dict.begin());
-  picojson::object::const_iterator dictItEnd(dict.end());
-
-  for (; dictIt != dictItEnd; ++dictIt) {
-    // Check that the value is a string.
-    if (!dictIt->second.is<std::string>()) {
-      if (required) {
-        if (err) {
-          (*err) += "'" + property + "' value is not a string.\n";
-        }
-      }
-      return false;
-    }
-
-    // Insert into the list.
-    (*ret)[dictIt->first] = dictIt->second.get<std::string>();
-  }
-  return true;
-}
-
-static bool ParseKHRBinaryExtension(const picojson::object &o, std::string *err,
-                                    std::string *buffer_view,
-                                    std::string *mime_type, int *image_width,
-                                    int *image_height) {
-  picojson::object j = o;
-
-  if (j.find("extensions") == j.end()) {
-    if (err) {
-      (*err) += "`extensions' property is missing.\n";
-    }
-    return false;
-  }
-
-  if (!(j["extensions"].is<picojson::object>())) {
-    if (err) {
-      (*err) += "Invalid `extensions' property.\n";
-    }
-    return false;
-  }
-
-  picojson::object ext = j["extensions"].get<picojson::object>();
-
-  if (ext.find("KHR_binary_glTF") == ext.end()) {
-    if (err) {
-      (*err) +=
-          "`KHR_binary_glTF' property is missing in extension property.\n";
-    }
-    return false;
-  }
-
-  if (!(ext["KHR_binary_glTF"].is<picojson::object>())) {
-    if (err) {
-      (*err) += "Invalid `KHR_binary_glTF' property.\n";
-    }
-    return false;
-  }
-
-  picojson::object k = ext["KHR_binary_glTF"].get<picojson::object>();
-
-  if (!ParseStringProperty(buffer_view, err, k, "bufferView", true)) {
-    return false;
-  }
-
-  if (mime_type) {
-    ParseStringProperty(mime_type, err, k, "mimeType", false);
-  }
-
-  if (image_width) {
-    double width = 0.0;
-    if (ParseNumberProperty(&width, err, k, "width", false)) {
-      (*image_width) = static_cast<int>(width);
-    }
-  }
-
-  if (image_height) {
-    double height = 0.0;
-    if (ParseNumberProperty(&height, err, k, "height", false)) {
-      (*image_height) = static_cast<int>(height);
-    }
-  }
-
-  return true;
-}
-
-static bool ParseAsset(Asset *asset, std::string *err,
-                       const picojson::object &o) {
-  ParseStringProperty(&asset->generator, err, o, "generator", false);
-  ParseBooleanProperty(&asset->premultipliedAlpha, err, o, "premultipliedAlpha",
-                       false);
-
-  ParseStringProperty(&asset->version, err, o, "version", false);
-
-  picojson::object::const_iterator profile = o.find("profile");
-  if (profile != o.end()) {
-    const picojson::value &v = profile->second;
-    if (v.contains("api") & v.get("api").is<std::string>()) {
-      asset->profile_api = v.get("api").get<std::string>();
-    }
-    if (v.contains("version") & v.get("version").is<std::string>()) {
-      asset->profile_version = v.get("version").get<std::string>();
-    }
-  }
-
-  return true;
-}
-
-static bool ParseImage(Image *image, std::string *err,
-                       const picojson::object &o, const std::string &basedir,
-                       bool is_binary, const unsigned char *bin_data,
-                       size_t bin_size) {
-  std::string uri;
-  if (!ParseStringProperty(&uri, err, o, "uri", true)) {
-    return false;
-  }
-
-  ParseStringProperty(&image->name, err, o, "name", false);
-
-  std::vector<unsigned char> img;
-
-  if (is_binary) {
-    // Still binary glTF accepts external dataURI. First try external resources.
-    bool loaded = false;
-    if (IsDataURI(uri)) {
-      loaded = DecodeDataURI(&img, uri, 0, false);
-    } else {
-      // Assume external .bin file.
-      loaded = LoadExternalFile(&img, err, uri, basedir, 0, false);
-    }
-
-    if (!loaded) {
-      // load data from (embedded) binary data
-
-      if ((bin_size == 0) || (bin_data == NULL)) {
-        if (err) {
-          (*err) += "Invalid binary data.\n";
-        }
-        return false;
-      }
-
-      // There should be "extensions" property.
-      // "extensions":{"KHR_binary_glTF":{"bufferView": "id", ...
-
-      std::string buffer_view;
-      std::string mime_type;
-      int image_width;
-      int image_height;
-      bool ret = ParseKHRBinaryExtension(o, err, &buffer_view, &mime_type,
-                                         &image_width, &image_height);
-      if (!ret) {
-        return false;
-      }
-
-      if (uri.compare("data:,") == 0) {
-        // ok
-      } else {
-        if (err) {
-          (*err) += "Invalid URI for binary data.\n";
-        }
-        return false;
-      }
-
-      // Just only save some information here. Loading actual image data from
-      // bufferView is done in other place.
-      image->bufferView = buffer_view;
-      image->mimeType = mime_type;
-      image->width = image_width;
-      image->height = image_height;
-
-      return true;
-    }
-  } else {
-    if (IsDataURI(uri)) {
-      if (!DecodeDataURI(&img, uri, 0, false)) {
-        if (err) {
-          (*err) += "Failed to decode 'uri' for image parameter.\n";
-        }
-        return false;
-      }
-    } else {
-      // Assume external file
-      if (!LoadExternalFile(&img, err, uri, basedir, 0, false)) {
-        if (err) {
-          (*err) += "Failed to load external 'uri'. for image parameter\n";
-        }
-        return false;
-      }
-      if (img.empty()) {
-        if (err) {
-          (*err) += "Image is empty.\n";
-        }
-        return false;
-      }
-    }
-  }
-
-  return LoadImageData(image, err, 0, 0, &img.at(0),
-                       static_cast<int>(img.size()));
-}
-
-static bool ParseTexture(Texture *texture, std::string *err,
-                         const picojson::object &o,
-                         const std::string &basedir) {
-  (void)basedir;
-
-  if (!ParseStringProperty(&texture->sampler, err, o, "sampler", true)) {
-    return false;
-  }
-
-  if (!ParseStringProperty(&texture->source, err, o, "source", true)) {
-    return false;
-  }
-
-  ParseStringProperty(&texture->name, err, o, "name", false);
-
-  double format = TINYGLTF_TEXTURE_FORMAT_RGBA;
-  ParseNumberProperty(&format, err, o, "format", false);
-
-  double internalFormat = TINYGLTF_TEXTURE_FORMAT_RGBA;
-  ParseNumberProperty(&internalFormat, err, o, "internalFormat", false);
-
-  double target = TINYGLTF_TEXTURE_TARGET_TEXTURE2D;
-  ParseNumberProperty(&target, err, o, "target", false);
-
-  double type = TINYGLTF_TEXTURE_TYPE_UNSIGNED_BYTE;
-  ParseNumberProperty(&type, err, o, "type", false);
-
-  texture->format = static_cast<int>(format);
-  texture->internalFormat = static_cast<int>(internalFormat);
-  texture->target = static_cast<int>(target);
-  texture->type = static_cast<int>(type);
-
-  return true;
-}
-
-static bool ParseBuffer(Buffer *buffer, std::string *err,
-                        const picojson::object &o, const std::string &basedir,
-                        bool is_binary = false,
-                        const unsigned char *bin_data = NULL,
-                        size_t bin_size = 0) {
-  double byteLength;
-  if (!ParseNumberProperty(&byteLength, err, o, "byteLength", true)) {
-    return false;
-  }
-
-  std::string uri;
-  if (!ParseStringProperty(&uri, err, o, "uri", true)) {
-    return false;
-  }
-
-  picojson::object::const_iterator type = o.find("type");
-  if (type != o.end()) {
-    if (type->second.is<std::string>()) {
-      const std::string &ty = (type->second).get<std::string>();
-      if (ty.compare("arraybuffer") == 0) {
-        // buffer.type = "arraybuffer";
-      }
-    }
-  }
-
-  size_t bytes = static_cast<size_t>(byteLength);
-  if (is_binary) {
-    // Still binary glTF accepts external dataURI. First try external resources.
-    bool loaded = false;
-    if (IsDataURI(uri)) {
-      loaded = DecodeDataURI(&buffer->data, uri, bytes, true);
-    } else {
-      // Assume external .bin file.
-      loaded = LoadExternalFile(&buffer->data, err, uri, basedir, bytes, true);
-    }
-
-    if (!loaded) {
-      // load data from (embedded) binary data
-
-      if ((bin_size == 0) || (bin_data == NULL)) {
-        if (err) {
-          (*err) += "Invalid binary data.\n";
-        }
-        return false;
-      }
-
-      if (byteLength > bin_size) {
-        if (err) {
-          std::stringstream ss;
-          ss << "Invalid `byteLength'. Must be equal or less than binary size: "
-                "`byteLength' = "
-             << byteLength << ", binary size = " << bin_size << std::endl;
-          (*err) += ss.str();
-        }
-        return false;
-      }
-
-      if (uri.compare("data:,") == 0) {
-        // @todo { check uri }
-        buffer->data.resize(static_cast<size_t>(byteLength));
-        memcpy(&(buffer->data.at(0)), bin_data,
-               static_cast<size_t>(byteLength));
-
-      } else {
-        if (err) {
-          (*err) += "Invalid URI for binary data.\n";
-        }
-        return false;
-      }
-    }
-
-  } else {
-    if (IsDataURI(uri)) {
-      if (!DecodeDataURI(&buffer->data, uri, bytes, true)) {
-        if (err) {
-          (*err) += "Failed to decode 'uri'.\n";
-        }
-        return false;
-      }
-    } else {
-      // Assume external .bin file.
-      if (!LoadExternalFile(&buffer->data, err, uri, basedir, bytes, true)) {
-        return false;
-      }
-    }
-  }
-
-  ParseStringProperty(&buffer->name, err, o, "name", false);
-
-  return true;
-}
-
-static bool ParseBufferView(BufferView *bufferView, std::string *err,
-                            const picojson::object &o) {
-  std::string buffer;
-  if (!ParseStringProperty(&buffer, err, o, "buffer", true)) {
-    return false;
-  }
-
-  double byteOffset;
-  if (!ParseNumberProperty(&byteOffset, err, o, "byteOffset", true)) {
-    return false;
-  }
-
-  double byteLength = 0.0;
-  ParseNumberProperty(&byteLength, err, o, "byteLength", false);
-
-  double target = 0.0;
-  ParseNumberProperty(&target, err, o, "target", false);
-  int targetValue = static_cast<int>(target);
-  if ((targetValue == TINYGLTF_TARGET_ARRAY_BUFFER) ||
-      (targetValue == TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER)) {
-    // OK
-  } else {
-    targetValue = 0;
-  }
-  bufferView->target = targetValue;
-
-  ParseStringProperty(&bufferView->name, err, o, "name", false);
-
-  bufferView->buffer = buffer;
-  bufferView->byteOffset = static_cast<size_t>(byteOffset);
-  bufferView->byteLength = static_cast<size_t>(byteLength);
-
-  return true;
-}
-
-static bool ParseAccessor(Accessor *accessor, std::string *err,
-                          const picojson::object &o) {
-  std::string bufferView;
-  if (!ParseStringProperty(&bufferView, err, o, "bufferView", true)) {
-    return false;
-  }
-
-  double byteOffset;
-  if (!ParseNumberProperty(&byteOffset, err, o, "byteOffset", true)) {
-    return false;
-  }
-
-  double componentType;
-  if (!ParseNumberProperty(&componentType, err, o, "componentType", true)) {
-    return false;
-  }
-
-  double count = 0.0;
-  if (!ParseNumberProperty(&count, err, o, "count", true)) {
-    return false;
-  }
-
-  std::string type;
-  if (!ParseStringProperty(&type, err, o, "type", true)) {
-    return false;
-  }
-
-  if (type.compare("SCALAR") == 0) {
-    accessor->type = TINYGLTF_TYPE_SCALAR;
-  } else if (type.compare("VEC2") == 0) {
-    accessor->type = TINYGLTF_TYPE_VEC2;
-  } else if (type.compare("VEC3") == 0) {
-    accessor->type = TINYGLTF_TYPE_VEC3;
-  } else if (type.compare("VEC4") == 0) {
-    accessor->type = TINYGLTF_TYPE_VEC4;
-  } else if (type.compare("MAT2") == 0) {
-    accessor->type = TINYGLTF_TYPE_MAT2;
-  } else if (type.compare("MAT3") == 0) {
-    accessor->type = TINYGLTF_TYPE_MAT3;
-  } else if (type.compare("MAT4") == 0) {
-    accessor->type = TINYGLTF_TYPE_MAT4;
-  } else {
-    std::stringstream ss;
-    ss << "Unsupported `type` for accessor object. Got \"" << type << "\"\n";
-    if (err) {
-      (*err) += ss.str();
-    }
-    return false;
-  }
-
-  double byteStride = 0.0;
-  ParseNumberProperty(&byteStride, err, o, "byteStride", false);
-
-  ParseStringProperty(&accessor->name, err, o, "name", false);
-
-  accessor->minValues.clear();
-  accessor->maxValues.clear();
-  ParseNumberArrayProperty(&accessor->minValues, err, o, "min", false);
-  ParseNumberArrayProperty(&accessor->maxValues, err, o, "max", false);
-
-  accessor->count = static_cast<size_t>(count);
-  accessor->bufferView = bufferView;
-  accessor->byteOffset = static_cast<size_t>(byteOffset);
-  accessor->byteStride = static_cast<size_t>(byteStride);
-
-  {
-    int comp = static_cast<int>(componentType);
-    if (comp >= TINYGLTF_COMPONENT_TYPE_BYTE &&
-        comp <= TINYGLTF_COMPONENT_TYPE_DOUBLE) {
-      // OK
-      accessor->componentType = comp;
-    } else {
-      std::stringstream ss;
-      ss << "Invalid `componentType` in accessor. Got " << comp << "\n";
-      if (err) {
-        (*err) += ss.str();
-      }
-      return false;
-    }
-  }
-
-  ParseExtrasProperty(&(accessor->extras), o);
-
-  return true;
-}
-
-static bool ParsePrimitive(Primitive *primitive, std::string *err,
-                           const picojson::object &o) {
-  if (!ParseStringProperty(&primitive->material, err, o, "material", true,
-                           "mesh.primitive")) {
-    return false;
-  }
-
-  double mode = static_cast<double>(TINYGLTF_MODE_TRIANGLES);
-  ParseNumberProperty(&mode, err, o, "mode", false);
-
-  int primMode = static_cast<int>(mode);
-  primitive->mode = primMode;
-
-  primitive->indices = "";
-  ParseStringProperty(&primitive->indices, err, o, "indices", false);
-
-  ParseStringMapProperty(&primitive->attributes, err, o, "attributes", false);
-
-  ParseExtrasProperty(&(primitive->extras), o);
-
-  return true;
-}
-
-static bool ParseMesh(Mesh *mesh, std::string *err, const picojson::object &o) {
-  ParseStringProperty(&mesh->name, err, o, "name", false);
-
-  mesh->primitives.clear();
-  picojson::object::const_iterator primObject = o.find("primitives");
-  if ((primObject != o.end()) && (primObject->second).is<picojson::array>()) {
-    const picojson::array &primArray =
-        (primObject->second).get<picojson::array>();
-    for (size_t i = 0; i < primArray.size(); i++) {
-      Primitive primitive;
-      if (ParsePrimitive(&primitive, err,
-                         primArray[i].get<picojson::object>())) {
-        // Only add the primitive if the parsing succeeds.
-        mesh->primitives.push_back(primitive);
-      }
-    }
-  }
-
-  ParseExtrasProperty(&(mesh->extras), o);
-
-  return true;
-}
-
-static bool ParseNode(Node *node, std::string *err, const picojson::object &o) {
-  ParseStringProperty(&node->name, err, o, "name", false);
-
-  ParseNumberArrayProperty(&node->rotation, err, o, "rotation", false);
-  ParseNumberArrayProperty(&node->scale, err, o, "scale", false);
-  ParseNumberArrayProperty(&node->translation, err, o, "translation", false);
-  ParseNumberArrayProperty(&node->matrix, err, o, "matrix", false);
-  ParseStringArrayProperty(&node->meshes, err, o, "meshes", false);
-
-  node->children.clear();
-  picojson::object::const_iterator childrenObject = o.find("children");
-  if ((childrenObject != o.end()) &&
-      (childrenObject->second).is<picojson::array>()) {
-    const picojson::array &childrenArray =
-        (childrenObject->second).get<picojson::array>();
-    for (size_t i = 0; i < childrenArray.size(); i++) {
-      if (!childrenArray[i].is<std::string>()) {
-        if (err) {
-          (*err) += "Invalid `children` array.\n";
-        }
-        return false;
-      }
-      const std::string &childrenNode = childrenArray[i].get<std::string>();
-      node->children.push_back(childrenNode);
-    }
-  }
-
-  ParseExtrasProperty(&(node->extras), o);
-
-  return true;
-}
-
-static bool ParseParameterProperty(Parameter *param, std::string *err,
-                                   const picojson::object &o,
-                                   const std::string &prop, bool required) {
-  double num_val;
-
-  // A parameter value can either be a string or an array of either a boolean or
-  // a number. Booleans of any kind aren't supported here. Granted, it
-  // complicates the Parameter structure and breaks it semantically in the sense
-  // that the client probably works off the assumption that if the string is
-  // empty the vector is used, etc. Would a tagged union work?
-  if (ParseStringProperty(&param->string_value, err, o, prop, false)) {
-    // Found string property.
-    return true;
-  } else if (ParseNumberArrayProperty(&param->number_array, err, o, prop,
-                                      false)) {
-    // Found a number array.
-    return true;
-  } else if (ParseNumberProperty(&num_val, err, o, prop, false)) {
-    param->number_array.push_back(num_val);
-    return true;
-  } else {
-    if (required) {
-      if (err) {
-        (*err) += "parameter must be a string or number / number array.\n";
-      }
-    }
-    return false;
-  }
-}
-
-static bool ParseMaterial(Material *material, std::string *err,
-                          const picojson::object &o) {
-  ParseStringProperty(&material->name, err, o, "name", false);
-  ParseStringProperty(&material->technique, err, o, "technique", false);
-
-  material->values.clear();
-  picojson::object::const_iterator valuesIt = o.find("values");
-
-  if ((valuesIt != o.end()) && (valuesIt->second).is<picojson::object>()) {
-    const picojson::object &values_object =
-        (valuesIt->second).get<picojson::object>();
-
-    picojson::object::const_iterator it(values_object.begin());
-    picojson::object::const_iterator itEnd(values_object.end());
-
-    for (; it != itEnd; it++) {
-      Parameter param;
-      if (ParseParameterProperty(&param, err, values_object, it->first,
-                                 false)) {
-        material->values[it->first] = param;
-      }
-    }
-  }
-
-  ParseExtrasProperty(&(material->extras), o);
-
-  return true;
-}
-
-static bool ParseShader(Shader *shader, std::string *err,
-                        const picojson::object &o, const std::string &basedir,
-                        bool is_binary = false,
-                        const unsigned char *bin_data = NULL,
-                        size_t bin_size = 0) {
-  std::string uri;
-  if (!ParseStringProperty(&uri, err, o, "uri", true)) {
-    return false;
-  }
-
-  if (is_binary) {
-    // Still binary glTF accepts external dataURI. First try external resources.
-    bool loaded = false;
-    if (IsDataURI(uri)) {
-      loaded = DecodeDataURI(&shader->source, uri, 0, false);
-    } else {
-      // Assume external .bin file.
-      loaded = LoadExternalFile(&shader->source, err, uri, basedir, 0, false);
-    }
-
-    if (!loaded) {
-      // load data from (embedded) binary data
-
-      if ((bin_size == 0) || (bin_data == NULL)) {
-        if (err) {
-          (*err) += "Invalid binary data.\n";
-        }
-        return false;
-      }
-
-      // There should be "extensions" property.
-      // "extensions":{"KHR_binary_glTF":{"bufferView": "id", ...
-
-      std::string buffer_view;
-      std::string mime_type;
-      int image_width;
-      int image_height;
-      bool ret = ParseKHRBinaryExtension(o, err, &buffer_view, &mime_type,
-                                         &image_width, &image_height);
-      if (!ret) {
-        return false;
-      }
-
-      if (uri.compare("data:,") == 0) {
-        // ok
-      } else {
-        if (err) {
-          (*err) += "Invalid URI for binary data.\n";
-        }
-        return false;
-      }
-    }
-  } else {
-    // Load shader source from data uri
-    // TODO(syoyo): Support ascii or utf-8 data uris.
-    if (IsDataURI(uri)) {
-      if (!DecodeDataURI(&shader->source, uri, 0, false)) {
-        if (err) {
-          (*err) += "Failed to decode 'uri' for shader parameter.\n";
-        }
-        return false;
-      }
-    } else {
-      // Assume external file
-      if (!LoadExternalFile(&shader->source, err, uri, basedir, 0, false)) {
-        if (err) {
-          (*err) += "Failed to load external 'uri' for shader parameter.\n";
-        }
-        return false;
-      }
-      if (shader->source.empty()) {
-        if (err) {
-          (*err) += "shader is empty.\n";  // This may be OK?
-        }
-        return false;
-      }
-    }
-  }
-
-  double type;
-  if (!ParseNumberProperty(&type, err, o, "type", true)) {
-    return false;
-  }
-
-  shader->type = static_cast<int>(type);
-
-  ParseExtrasProperty(&(shader->extras), o);
-
-  return true;
-}
-
-static bool ParseProgram(Program *program, std::string *err,
-                         const picojson::object &o) {
-  ParseStringProperty(&program->name, err, o, "name", false);
-
-  if (!ParseStringProperty(&program->vertexShader, err, o, "vertexShader",
-                           true)) {
-    return false;
-  }
-  if (!ParseStringProperty(&program->fragmentShader, err, o, "fragmentShader",
-                           true)) {
-    return false;
-  }
-
-  // I suppose the list of attributes isn't needed, but a technique doesn't
-  // really make sense without it.
-  ParseStringArrayProperty(&program->attributes, err, o, "attributes", false);
-
-  ParseExtrasProperty(&(program->extras), o);
-
-  return true;
-}
-
-static bool ParseTechniqueParameter(TechniqueParameter *param, std::string *err,
-                                    const picojson::object &o) {
-  double count = 1;
-  ParseNumberProperty(&count, err, o, "count", false);
-
-  double type;
-  if (!ParseNumberProperty(&type, err, o, "type", true)) {
-    return false;
-  }
-
-  ParseStringProperty(&param->node, err, o, "node", false);
-  ParseStringProperty(&param->semantic, err, o, "semantic", false);
-
-  ParseParameterProperty(&param->value, err, o, "value", false);
-
-  param->count = static_cast<int>(count);
-  param->type = static_cast<int>(type);
-
-  return true;
-}
-
-static bool ParseTechnique(Technique *technique, std::string *err,
-                           const picojson::object &o) {
-  ParseStringProperty(&technique->name, err, o, "name", false);
-
-  if (!ParseStringProperty(&technique->program, err, o, "program", true)) {
-    return false;
-  }
-
-  ParseStringMapProperty(&technique->attributes, err, o, "attributes", false);
-  ParseStringMapProperty(&technique->uniforms, err, o, "uniforms", false);
-
-  technique->parameters.clear();
-  picojson::object::const_iterator paramsIt = o.find("parameters");
-
-  // Verify parameters is an object
-  if ((paramsIt != o.end()) && (paramsIt->second).is<picojson::object>()) {
-    // For each parameter in params_object.
-    const picojson::object &params_object =
-        (paramsIt->second).get<picojson::object>();
-
-    picojson::object::const_iterator it(params_object.begin());
-    picojson::object::const_iterator itEnd(params_object.end());
-
-    for (; it != itEnd; it++) {
-      TechniqueParameter param;
-
-      // Skip non-objects
-      if (!it->second.is<picojson::object>()) continue;
-
-      // Parse the technique parameter
-      const picojson::object &param_obj = it->second.get<picojson::object>();
-      if (ParseTechniqueParameter(&param, err, param_obj)) {
-        // Add if successful
-        technique->parameters[it->first] = param;
-      }
-    }
-  }
-
-  ParseExtrasProperty(&(technique->extras), o);
-
-  return true;
-}
-
-static bool ParseAnimationChannel(AnimationChannel *channel, std::string *err,
-                                  const picojson::object &o) {
-  if (!ParseStringProperty(&channel->sampler, err, o, "sampler", true)) {
-    if (err) {
-      (*err) += "`sampler` field is missing in animation channels\n";
-    }
-    return false;
-  }
-
-  picojson::object::const_iterator targetIt = o.find("target");
-  if ((targetIt != o.end()) && (targetIt->second).is<picojson::object>()) {
-    const picojson::object &target_object =
-        (targetIt->second).get<picojson::object>();
-
-    if (!ParseStringProperty(&channel->target_id, err, target_object, "id",
-                             true)) {
-      if (err) {
-        (*err) += "`id` field is missing in animation.channels.target\n";
-      }
-      return false;
-    }
-
-    if (!ParseStringProperty(&channel->target_path, err, target_object, "path",
-                             true)) {
-      if (err) {
-        (*err) += "`path` field is missing in animation.channels.target\n";
-      }
-      return false;
-    }
-  }
-
-  ParseExtrasProperty(&(channel->extras), o);
-
-  return true;
-}
-
-static bool ParseAnimation(Animation *animation, std::string *err,
-                           const picojson::object &o) {
-  {
-    picojson::object::const_iterator channelsIt = o.find("channels");
-    if ((channelsIt != o.end()) && (channelsIt->second).is<picojson::array>()) {
-      const picojson::array &channelArray =
-          (channelsIt->second).get<picojson::array>();
-      for (size_t i = 0; i < channelArray.size(); i++) {
-        AnimationChannel channel;
-        if (ParseAnimationChannel(&channel, err,
-                                  channelArray[i].get<picojson::object>())) {
-          // Only add the channel if the parsing succeeds.
-          animation->channels.push_back(channel);
-        }
-      }
-    }
-  }
-
-  {
-    picojson::object::const_iterator samplerIt = o.find("samplers");
-    if ((samplerIt != o.end()) && (samplerIt->second).is<picojson::object>()) {
-      const picojson::object &sampler_object =
-          (samplerIt->second).get<picojson::object>();
-
-      picojson::object::const_iterator it = sampler_object.begin();
-      picojson::object::const_iterator itEnd = sampler_object.end();
-
-      for (; it != itEnd; it++) {
-        // Skip non-objects
-        if (!it->second.is<picojson::object>()) continue;
-
-        const picojson::object &s = it->second.get<picojson::object>();
-
-        AnimationSampler sampler;
-        if (!ParseStringProperty(&sampler.input, err, s, "input", true)) {
-          if (err) {
-            (*err) += "`input` field is missing in animation.sampler\n";
-          }
-          return false;
-        }
-        if (!ParseStringProperty(&sampler.interpolation, err, s,
-                                 "interpolation", true)) {
-          if (err) {
-            (*err) += "`interpolation` field is missing in animation.sampler\n";
-          }
-          return false;
-        }
-        if (!ParseStringProperty(&sampler.output, err, s, "output", true)) {
-          if (err) {
-            (*err) += "`output` field is missing in animation.sampler\n";
-          }
-          return false;
-        }
-
-        animation->samplers[it->first] = sampler;
-      }
-    }
-  }
-
-  picojson::object::const_iterator parametersIt = o.find("parameters");
-  if ((parametersIt != o.end()) &&
-      (parametersIt->second).is<picojson::object>()) {
-    const picojson::object &parameters_object =
-        (parametersIt->second).get<picojson::object>();
-
-    picojson::object::const_iterator it(parameters_object.begin());
-    picojson::object::const_iterator itEnd(parameters_object.end());
-
-    for (; it != itEnd; it++) {
-      Parameter param;
-      if (ParseParameterProperty(&param, err, parameters_object, it->first,
-                                 false)) {
-        animation->parameters[it->first] = param;
-      }
-    }
-  }
-  ParseStringProperty(&animation->name, err, o, "name", false);
-
-  ParseExtrasProperty(&(animation->extras), o);
-
-  return true;
-}
-
-static bool ParseSampler(Sampler *sampler, std::string *err,
-                         const picojson::object &o) {
-  ParseStringProperty(&sampler->name, err, o, "name", false);
-
-  double minFilter =
-      static_cast<double>(TINYGLTF_TEXTURE_FILTER_NEAREST_MIPMAP_LINEAR);
-  double magFilter = static_cast<double>(TINYGLTF_TEXTURE_FILTER_LINEAR);
-  double wrapS = static_cast<double>(TINYGLTF_TEXTURE_WRAP_RPEAT);
-  double wrapT = static_cast<double>(TINYGLTF_TEXTURE_WRAP_RPEAT);
-  ParseNumberProperty(&minFilter, err, o, "minFilter", false);
-  ParseNumberProperty(&magFilter, err, o, "magFilter", false);
-  ParseNumberProperty(&wrapS, err, o, "wrapS", false);
-  ParseNumberProperty(&wrapT, err, o, "wrapT", false);
-
-  sampler->minFilter = static_cast<int>(minFilter);
-  sampler->magFilter = static_cast<int>(magFilter);
-  sampler->wrapS = static_cast<int>(wrapS);
-  sampler->wrapT = static_cast<int>(wrapT);
-
-  ParseExtrasProperty(&(sampler->extras), o);
-
-  return true;
-}
-
-bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err,
-                                    const char *str, unsigned int length,
-                                    const std::string &base_dir,
-                                    unsigned int check_sections) {
-  picojson::value v;
-  std::string perr = picojson::parse(v, str, str + length);
-
-  if (!perr.empty()) {
-    if (err) {
-      (*err) = perr;
-    }
-    return false;
-  }
-
-  if (v.contains("scene") && v.get("scene").is<std::string>()) {
-    // OK
-  } else if (check_sections & REQUIRE_SCENE) {
-    if (err) {
-      (*err) += "\"scene\" object not found in .gltf\n";
-    }
-    return false;
-  }
-
-  if (v.contains("scenes") && v.get("scenes").is<picojson::object>()) {
-    // 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::object>()) {
-    // 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::object>()) {
-    // 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::object>()) {
-    // 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::object>()) {
-    // OK
-  } else if (check_sections & REQUIRE_BUFFER_VIEWS) {
-    if (err) {
-      (*err) += "\"bufferViews\" object not found in .gltf\n";
-    }
-    return false;
-  }
-
-  scene->buffers.clear();
-  scene->bufferViews.clear();
-  scene->accessors.clear();
-  scene->meshes.clear();
-  scene->nodes.clear();
-  scene->defaultScene = "";
-
-  // 0. Parse Asset
-  if (v.contains("asset") && v.get("asset").is<picojson::object>()) {
-    const picojson::object &root = v.get("asset").get<picojson::object>();
-
-    ParseAsset(&scene->asset, err, root);
-  }
-
-  // 1. Parse Buffer
-  if (v.contains("buffers") && v.get("buffers").is<picojson::object>()) {
-    const picojson::object &root = v.get("buffers").get<picojson::object>();
-
-    picojson::object::const_iterator it(root.begin());
-    picojson::object::const_iterator itEnd(root.end());
-    for (; it != itEnd; it++) {
-      Buffer buffer;
-      if (!ParseBuffer(&buffer, err, (it->second).get<picojson::object>(),
-                       base_dir, is_binary_, bin_data_, bin_size_)) {
-        return false;
-      }
-
-      scene->buffers[it->first] = buffer;
-    }
-  }
-
-  // 2. Parse BufferView
-  if (v.contains("bufferViews") &&
-      v.get("bufferViews").is<picojson::object>()) {
-    const picojson::object &root = v.get("bufferViews").get<picojson::object>();
-
-    picojson::object::const_iterator it(root.begin());
-    picojson::object::const_iterator itEnd(root.end());
-    for (; it != itEnd; it++) {
-      BufferView bufferView;
-      if (!ParseBufferView(&bufferView, err,
-                           (it->second).get<picojson::object>())) {
-        return false;
-      }
-
-      scene->bufferViews[it->first] = bufferView;
-    }
-  }
-
-  // 3. Parse Accessor
-  if (v.contains("accessors") && v.get("accessors").is<picojson::object>()) {
-    const picojson::object &root = v.get("accessors").get<picojson::object>();
-
-    picojson::object::const_iterator it(root.begin());
-    picojson::object::const_iterator itEnd(root.end());
-    for (; it != itEnd; it++) {
-      Accessor accessor;
-      if (!ParseAccessor(&accessor, err,
-                         (it->second).get<picojson::object>())) {
-        return false;
-      }
-
-      scene->accessors[it->first] = accessor;
-    }
-  }
-
-  // 4. Parse Mesh
-  if (v.contains("meshes") && v.get("meshes").is<picojson::object>()) {
-    const picojson::object &root = v.get("meshes").get<picojson::object>();
-
-    picojson::object::const_iterator it(root.begin());
-    picojson::object::const_iterator itEnd(root.end());
-    for (; it != itEnd; it++) {
-      Mesh mesh;
-      if (!ParseMesh(&mesh, err, (it->second).get<picojson::object>())) {
-        return false;
-      }
-
-      scene->meshes[it->first] = mesh;
-    }
-  }
-
-  // 5. Parse Node
-  if (v.contains("nodes") && v.get("nodes").is<picojson::object>()) {
-    const picojson::object &root = v.get("nodes").get<picojson::object>();
-
-    picojson::object::const_iterator it(root.begin());
-    picojson::object::const_iterator itEnd(root.end());
-    for (; it != itEnd; it++) {
-      Node node;
-      if (!ParseNode(&node, err, (it->second).get<picojson::object>())) {
-        return false;
-      }
-
-      scene->nodes[it->first] = node;
-    }
-  }
-
-  // 6. Parse scenes.
-  if (v.contains("scenes") && v.get("scenes").is<picojson::object>()) {
-    const picojson::object &root = v.get("scenes").get<picojson::object>();
-
-    picojson::object::const_iterator it(root.begin());
-    picojson::object::const_iterator itEnd(root.end());
-    for (; it != itEnd; it++) {
-      if (!((it->second).is<picojson::object>())) {
-        if (err) {
-          (*err) += "`scenes' does not contain an object.";
-        }
-        return false;
-      }
-      const picojson::object &o = (it->second).get<picojson::object>();
-      std::vector<std::string> nodes;
-      if (!ParseStringArrayProperty(&nodes, err, o, "nodes", false)) {
-        return false;
-      }
-
-      scene->scenes[it->first] = nodes;
-    }
-  }
-
-  // 7. Parse default scenes.
-  if (v.contains("scene") && v.get("scene").is<std::string>()) {
-    const std::string defaultScene = v.get("scene").get<std::string>();
-
-    scene->defaultScene = defaultScene;
-  }
-
-  // 8. Parse Material
-  if (v.contains("materials") && v.get("materials").is<picojson::object>()) {
-    const picojson::object &root = v.get("materials").get<picojson::object>();
-
-    picojson::object::const_iterator it(root.begin());
-    picojson::object::const_iterator itEnd(root.end());
-    for (; it != itEnd; it++) {
-      Material material;
-      if (!ParseMaterial(&material, err,
-                         (it->second).get<picojson::object>())) {
-        return false;
-      }
-
-      scene->materials[it->first] = material;
-    }
-  }
-
-  // 9. Parse Image
-  if (v.contains("images") && v.get("images").is<picojson::object>()) {
-    const picojson::object &root = v.get("images").get<picojson::object>();
-
-    picojson::object::const_iterator it(root.begin());
-    picojson::object::const_iterator itEnd(root.end());
-    for (; it != itEnd; it++) {
-      Image image;
-      if (!ParseImage(&image, err, (it->second).get<picojson::object>(),
-                      base_dir, is_binary_, bin_data_, bin_size_)) {
-        return false;
-      }
-
-      if (!image.bufferView.empty()) {
-        // Load image from the buffer view.
-        if (scene->bufferViews.find(image.bufferView) ==
-            scene->bufferViews.end()) {
-          if (err) {
-            std::stringstream ss;
-            ss << "bufferView \"" << image.bufferView
-               << "\" not found in the scene." << std::endl;
-            (*err) += ss.str();
-          }
-          return false;
-        }
-
-        const BufferView &bufferView = scene->bufferViews[image.bufferView];
-        const Buffer &buffer = scene->buffers[bufferView.buffer];
-
-        bool ret = LoadImageData(&image, err, image.width, image.height,
-                                 &buffer.data[bufferView.byteOffset],
-                                 static_cast<int>(bufferView.byteLength));
-        if (!ret) {
-          return false;
-        }
-      }
-
-      scene->images[it->first] = image;
-    }
-  }
-
-  // 10. Parse Texture
-  if (v.contains("textures") && v.get("textures").is<picojson::object>()) {
-    const picojson::object &root = v.get("textures").get<picojson::object>();
-
-    picojson::object::const_iterator it(root.begin());
-    picojson::object::const_iterator itEnd(root.end());
-    for (; it != itEnd; it++) {
-      Texture texture;
-      if (!ParseTexture(&texture, err, (it->second).get<picojson::object>(),
-                        base_dir)) {
-        return false;
-      }
-
-      scene->textures[it->first] = texture;
-    }
-  }
-
-  // 11. Parse Shader
-  if (v.contains("shaders") && v.get("shaders").is<picojson::object>()) {
-    const picojson::object &root = v.get("shaders").get<picojson::object>();
-
-    picojson::object::const_iterator it(root.begin());
-    picojson::object::const_iterator itEnd(root.end());
-    for (; it != itEnd; ++it) {
-      Shader shader;
-      if (!ParseShader(&shader, err, (it->second).get<picojson::object>(),
-                       base_dir, is_binary_, bin_data_, bin_size_)) {
-        return false;
-      }
-
-      scene->shaders[it->first] = shader;
-    }
-  }
-
-  // 12. Parse Program
-  if (v.contains("programs") && v.get("programs").is<picojson::object>()) {
-    const picojson::object &root = v.get("programs").get<picojson::object>();
-
-    picojson::object::const_iterator it(root.begin());
-    picojson::object::const_iterator itEnd(root.end());
-    for (; it != itEnd; ++it) {
-      Program program;
-      if (!ParseProgram(&program, err, (it->second).get<picojson::object>())) {
-        return false;
-      }
-
-      scene->programs[it->first] = program;
-    }
-  }
-
-  // 13. Parse Technique
-  if (v.contains("techniques") && v.get("techniques").is<picojson::object>()) {
-    const picojson::object &root = v.get("techniques").get<picojson::object>();
-
-    picojson::object::const_iterator it(root.begin());
-    picojson::object::const_iterator itEnd(root.end());
-    for (; it != itEnd; ++it) {
-      Technique technique;
-      if (!ParseTechnique(&technique, err,
-                          (it->second).get<picojson::object>())) {
-        return false;
-      }
-
-      scene->techniques[it->first] = technique;
-    }
-  }
-
-  // 14. Parse Animation
-  if (v.contains("animations") && v.get("animations").is<picojson::object>()) {
-    const picojson::object &root = v.get("animations").get<picojson::object>();
-
-    picojson::object::const_iterator it(root.begin());
-    picojson::object::const_iterator itEnd(root.end());
-    for (; it != itEnd; ++it) {
-      Animation animation;
-      if (!ParseAnimation(&animation, err,
-                          (it->second).get<picojson::object>())) {
-        return false;
-      }
-
-      scene->animations[it->first] = animation;
-    }
-  }
-
-  // 15. Parse Sampler
-  if (v.contains("samplers") && v.get("samplers").is<picojson::object>()) {
-    const picojson::object &root = v.get("samplers").get<picojson::object>();
-
-    picojson::object::const_iterator it(root.begin());
-    picojson::object::const_iterator itEnd(root.end());
-    for (; it != itEnd; ++it) {
-      Sampler sampler;
-      if (!ParseSampler(&sampler, err, (it->second).get<picojson::object>())) {
-        return false;
-      }
-
-      scene->samplers[it->first] = sampler;
-    }
-  }
-  return true;
-}
-
-bool TinyGLTFLoader::LoadASCIIFromString(Scene *scene, std::string *err,
-                                         const char *str, unsigned int length,
-                                         const std::string &base_dir,
-                                         unsigned int check_sections) {
-  is_binary_ = false;
-  bin_data_ = NULL;
-  bin_size_ = 0;
-
-  return LoadFromString(scene, err, str, length, base_dir, check_sections);
-}
-
-bool TinyGLTFLoader::LoadASCIIFromFile(Scene *scene, std::string *err,
-                                       const std::string &filename,
-                                       unsigned int check_sections) {
-  std::stringstream ss;
-
-  std::ifstream f(filename.c_str());
-  if (!f) {
-    ss << "Failed to open file: " << filename << std::endl;
-    if (err) {
-      (*err) = ss.str();
-    }
-    return false;
-  }
-
-  f.seekg(0, f.end);
-  size_t sz = static_cast<size_t>(f.tellg());
-  std::vector<char> buf(sz);
-
-  if (sz == 0) {
-    if (err) {
-      (*err) = "Empty file.";
-    }
-    return false;
-  }
-
-  f.seekg(0, f.beg);
-  f.read(&buf.at(0), static_cast<std::streamsize>(sz));
-  f.close();
-
-  std::string basedir = GetBaseDir(filename);
-
-  bool ret = LoadASCIIFromString(scene, err, &buf.at(0),
-                                 static_cast<unsigned int>(buf.size()), basedir,
-                                 check_sections);
-
-  return ret;
-}
-
-bool TinyGLTFLoader::LoadBinaryFromMemory(Scene *scene, std::string *err,
-                                          const unsigned char *bytes,
-                                          unsigned int size,
-                                          const std::string &base_dir,
-                                          unsigned int check_sections) {
-  if (size < 20) {
-    if (err) {
-      (*err) = "Too short data size for glTF Binary.";
-    }
-    return false;
-  }
-
-  if (bytes[0] == 'g' && bytes[1] == 'l' && bytes[2] == 'T' &&
-      bytes[3] == 'F') {
-    // ok
-  } else {
-    if (err) {
-      (*err) = "Invalid magic.";
-    }
-    return false;
-  }
-
-  unsigned int version;       // 4 bytes
-  unsigned int length;        // 4 bytes
-  unsigned int scene_length;  // 4 bytes
-  unsigned int scene_format;  // 4 bytes;
-
-  // @todo { Endian swap for big endian machine. }
-  memcpy(&version, bytes + 4, 4);
-  swap4(&version);
-  memcpy(&length, bytes + 8, 4);
-  swap4(&length);
-  memcpy(&scene_length, bytes + 12, 4);
-  swap4(&scene_length);
-  memcpy(&scene_format, bytes + 16, 4);
-  swap4(&scene_format);
-
-  if ((20 + scene_length >= size) || (scene_length < 1) ||
-      (scene_format != 0)) {  // 0 = JSON format.
-    if (err) {
-      (*err) = "Invalid glTF binary.";
-    }
-    return false;
-  }
-
-  // Extract JSON string.
-  std::string jsonString(reinterpret_cast<const char *>(&bytes[20]),
-                         scene_length);
-
-  is_binary_ = true;
-  bin_data_ = bytes + 20 + scene_length;
-  bin_size_ =
-      length - (20 + scene_length);  // extract header + JSON scene data.
-
-  bool ret =
-      LoadFromString(scene, err, reinterpret_cast<const char *>(&bytes[20]),
-                     scene_length, base_dir, check_sections);
-  if (!ret) {
-    return ret;
-  }
-
-  return true;
-}
-
-bool TinyGLTFLoader::LoadBinaryFromFile(Scene *scene, std::string *err,
-                                        const std::string &filename,
-                                        unsigned int check_sections) {
-  std::stringstream ss;
-
-  std::ifstream f(filename.c_str(), std::ios::binary);
-  if (!f) {
-    ss << "Failed to open file: " << filename << std::endl;
-    if (err) {
-      (*err) = ss.str();
-    }
-    return false;
-  }
-
-  f.seekg(0, f.end);
-  size_t sz = static_cast<size_t>(f.tellg());
-  std::vector<char> buf(sz);
-
-  f.seekg(0, f.beg);
-  f.read(&buf.at(0), static_cast<std::streamsize>(sz));
-  f.close();
-
-  std::string basedir = GetBaseDir(filename);
-
-  bool ret = LoadBinaryFromMemory(
-      scene, err, reinterpret_cast<unsigned char *>(&buf.at(0)),
-      static_cast<unsigned int>(buf.size()), basedir, check_sections);
-
-  return ret;
-}
-
-}  // namespace tinygltf
-
-#endif  // TINYGLTF_LOADER_IMPLEMENTATION
-
-#endif  // TINY_GLTF_LOADER_H_