mirror of
https://github.com/syoyo/tinygltf.git
synced 2026-06-29 18:48:50 +00:00
Compare commits
32 Commits
16bit-lode
...
rapidjson
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c0bcb7d72 | ||
|
|
d5694dc15d | ||
|
|
ddf0a0e83c | ||
|
|
f3ee08c595 | ||
|
|
f75327bc5b | ||
|
|
7acc95a2ae | ||
|
|
2a6f2cc356 | ||
|
|
0cf2812775 | ||
|
|
2673d1d3ef | ||
|
|
cf8b7cc0a4 | ||
|
|
93d0e365bb | ||
|
|
b3c1471317 | ||
|
|
9056aee823 | ||
|
|
29c431b2f2 | ||
|
|
d06b2c2022 | ||
|
|
339c9d578a | ||
|
|
7c315fa8a8 | ||
|
|
0f04ed018a | ||
|
|
ca56f726d6 | ||
|
|
9cd14a461b | ||
|
|
1ef603ea2a | ||
|
|
14d259f361 | ||
|
|
9223d3133a | ||
|
|
9b321a8515 | ||
|
|
7e9f734d73 | ||
|
|
9d86405d3d | ||
|
|
1ccb4ff580 | ||
|
|
bf9c2f4abd | ||
|
|
fc0116b323 | ||
|
|
606e5dde31 | ||
|
|
6a0d4c57b1 | ||
|
|
f4b6d11abc |
13
LICENSE.rapidjson.txt
Normal file
13
LICENSE.rapidjson.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// 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.
|
||||
6
Makefile
6
Makefile
@@ -2,8 +2,12 @@
|
||||
# Use this for strict compilation check(will work on clang 3.8+)
|
||||
#EXTRA_CXXFLAGS := -fsanitize=address -Wall -Werror -Weverything -Wno-c++11-long-long -Wno-c++98-compat
|
||||
|
||||
# With draco
|
||||
# EXTRA_CXXFLAGS := -I../draco/src/ -I../draco/build -DTINYGLTF_ENABLE_DRACO -L../draco/build
|
||||
# EXTRA_LINKFLAGS := -L../draco/build/ -ldracodec -ldraco
|
||||
|
||||
all:
|
||||
clang++ $(EXTRA_CXXFLAGS) -std=c++11 -g -O0 -o loader_example loader_example.cc
|
||||
clang++ $(EXTRA_CXXFLAGS) -std=c++11 -g -O0 -o loader_example loader_example.cc $(EXTRA_LINKFLAGS)
|
||||
|
||||
lint:
|
||||
deps/cpplint.py tiny_gltf.h
|
||||
|
||||
38
README.md
38
README.md
@@ -2,14 +2,14 @@
|
||||
|
||||
`TinyGLTF` is a header only C++11 glTF 2.0 https://github.com/KhronosGroup/glTF library.
|
||||
|
||||
`TinyGLTF` uses Niels Lohmann's json library(https://github.com/nlohmann/json), so now it requires C++11 compiler.
|
||||
If you are looking for old, C++03 version, please use `devel-picojson` branch.
|
||||
`TinyGLTF` uses single-header version of RapidJson(https://github.com/Tencent/rapidjson) as a JSON parser.
|
||||
|
||||
## Status
|
||||
|
||||
v2.2.0 release(Support loading 16bit PNG)
|
||||
v2.1.0 release(Draco support)
|
||||
v2.0.0 release(22 Aug, 2018)!
|
||||
- v2.3.0 release(Support built-in schema validation)
|
||||
- v2.2.0 release(Support loading 16bit PNG. Sparse accessor support)
|
||||
- v2.1.0 release(Draco support)
|
||||
- v2.0.0 release(22 Aug, 2018)!
|
||||
|
||||
## Builds
|
||||
|
||||
@@ -34,6 +34,7 @@ v2.0.0 release(22 Aug, 2018)!
|
||||
* [x] ASCII glTF
|
||||
* [x] Binary glTF(GLB)
|
||||
* [x] PBR material description
|
||||
* [x] Validate inpit glTF JSON with schema
|
||||
* Buffers
|
||||
* [x] Parse BASE64 encoded embedded buffer data(DataURI).
|
||||
* [x] Load `.bin` file.
|
||||
@@ -45,7 +46,9 @@ v2.0.0 release(22 Aug, 2018)!
|
||||
* [x] Load BMP
|
||||
* [x] Load GIF
|
||||
* [x] Custom Image decoder callback(e.g. for decoding OpenEXR image)
|
||||
* Load from memory
|
||||
* Morph traget
|
||||
* [x] Sparse accessor
|
||||
* Load glTF from memory
|
||||
* Custom callback handler
|
||||
* [x] Image load
|
||||
* [x] Image save
|
||||
@@ -66,20 +69,23 @@ v2.0.0 release(22 Aug, 2018)!
|
||||
* [TinyGltfImporter](http://doc.magnum.graphics/magnum/classMagnum_1_1Trade_1_1TinyGltfImporter.html) plugin for [Magnum](https://github.com/mosra/magnum), a lightweight and modular C++11/C++14 graphics middleware for games and data visualization.
|
||||
* Your projects here! (Please send PR)
|
||||
|
||||
## For developer
|
||||
|
||||
Generate single rapidjson file using this node.js script: https://github.com/Tencent/rapidjson/issues/863
|
||||
Add `cursorstreamwrapper.h` and `error/en.h` inclusion in `rapidjson-all.h` before running merge script.
|
||||
|
||||
## TODOs
|
||||
|
||||
* [ ] Write C++ code generator which emits C++ code from JSON schema for robust parsing.
|
||||
* [ ] Mesh Compression/decompression(Open3DGC, etc)
|
||||
* [x] Load Draco compressed mesh
|
||||
* [x] Save Draco compressed mesh
|
||||
* [ ] Save Draco compressed mesh
|
||||
* [ ] Open3DGC?
|
||||
* [ ] Support `extensions` and `extras` property
|
||||
* [ ] HDR image?
|
||||
* [ ] OpenEXR extension through TinyEXR.
|
||||
* [ ] 16bit PNG support in Serialization
|
||||
* [ ] Write example and tests for `animation` and `skin`
|
||||
* [ ] Skinning
|
||||
* [ ] Morph targets
|
||||
|
||||
## Licenses
|
||||
|
||||
@@ -95,7 +101,7 @@ TinyGLTF uses the following third party libraries.
|
||||
|
||||
## Build and example
|
||||
|
||||
Copy `stb_image.h`, `stb_image_write.h`, `json.hpp` and `tiny_gltf.h` to your project.
|
||||
Copy `stb_image.h`, `stb_image_write.h`, `rapidjson-amalgamation.h` and `tiny_gltf.h` to your project.
|
||||
|
||||
### Loading glTF 2.0 model
|
||||
|
||||
@@ -104,6 +110,7 @@ Copy `stb_image.h`, `stb_image_write.h`, `json.hpp` and `tiny_gltf.h` to your pr
|
||||
#define TINYGLTF_IMPLEMENTATION
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
// #define TINYGLTF_ENABLE_SCHEMA_VALIDATOR // optional. enable schema validation API.
|
||||
// #define TINYGLTF_NOEXCEPTION // optional. disable exception handling.
|
||||
#include "tiny_gltf.h"
|
||||
|
||||
@@ -116,6 +123,10 @@ std::string warn;
|
||||
|
||||
bool ret = loader.LoadASCIIFromFile(&model, &err, &warn, argv[1]);
|
||||
//bool ret = loader.LoadBinaryFromFile(&model, &err, &warn, argv[1]); // for binary glTF(.glb)
|
||||
// Validate with glTF Schema
|
||||
// #if defined(TINYGLTF_ENABLE_SCHEMA_VALIDATOR)
|
||||
// bool ret = loader.LoadASCIIFromFileWithValidation(&model, &err, &warn, argv[1]);
|
||||
// #endif
|
||||
|
||||
if (!warn.empty()) {
|
||||
printf("Warn: %s\n", warn.c_str());
|
||||
@@ -133,12 +144,17 @@ if (!ret) {
|
||||
|
||||
## Compile options
|
||||
|
||||
* `TINYGLTF_ENABLE_SCHEMA_VALIDATOR` : Enable API with schema validation. glTF Schema JSON(`gltf.schema.resolved.inc`) are embeded into application binary, thus no need to read glTF Schema file at a runtime.
|
||||
* `TINYGLTF_NOEXCEPTION` : Disable C++ exception in JSON parsing. You can use `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION` and `TINYGLTF_NOEXCEPTION` to fully remove C++ exception codes when compiling TinyGLTF.
|
||||
* `TINYGLTF_NO_STB_IMAGE` : Do not load images with stb_image. Instead use `TinyGLTF::SetImageLoader(LoadimageDataFunction LoadImageData, void *user_data)` to set a callback for loading images.
|
||||
* `TINYGLTF_NO_STB_IMAGE_WRITE` : Do not write images with stb_image_write. Instead use `TinyGLTF::SetImageWriter(WriteimageDataFunction WriteImageData, void *user_data)` to set a callback for writing images.
|
||||
* `TINYGLTF_NO_EXTERNAL_IMAGE` : Do not try to load external image file. This option woulde be helpful if you do not want load image file during glTF parsing.
|
||||
* `TINYGLTF_NO_EXTERNAL_IMAGE` : Do not try to load external image file. This option would be helpful if you do not want to load image files during glTF parsing.
|
||||
* `TINYGLTF_ANDROID_LOAD_FROM_ASSETS`: Load all files from packaged app assets instead of the regular file system. **Note:** You must pass a valid asset manager from your android app to `tinygltf::asset_manager` beforehand.
|
||||
* `TINYGLTF_ENABLE_DRACO`: Enable Draco compression. User must provide include path and link correspnding libraries in your project file.
|
||||
* `TINYGLTF_NO_INCLUDE_JSON `: Disable including `json.hpp` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
|
||||
* `TINYGLTF_NO_INCLUDE_STB_IMAGE `: Disable including `stb_image.h` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
|
||||
* `TINYGLTF_NO_INCLUDE_STB_IMAGE_WRITE `: Disable including `stb_image_write.h` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
|
||||
|
||||
|
||||
### Saving gltTF 2.0 model
|
||||
* [ ] Buffers.
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include "tiny_gltf.h"
|
||||
#endif
|
||||
|
||||
|
||||
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
|
||||
|
||||
#define CheckGLErrors(desc) \
|
||||
@@ -55,7 +54,9 @@ float eye[3], lookat[3], up[3];
|
||||
|
||||
GLFWwindow *window;
|
||||
|
||||
typedef struct { GLuint vb; } GLBufferState;
|
||||
typedef struct {
|
||||
GLuint vb;
|
||||
} GLBufferState;
|
||||
|
||||
typedef struct {
|
||||
std::vector<GLuint> diffuseTex; // for each primitive in mesh
|
||||
@@ -254,6 +255,26 @@ void motionFunc(GLFWwindow *window, double mouse_x, double mouse_y) {
|
||||
prevMouseY = mouse_y;
|
||||
}
|
||||
|
||||
static size_t ComponentTypeByteSize(int type) {
|
||||
switch (type) {
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
|
||||
case TINYGLTF_COMPONENT_TYPE_BYTE:
|
||||
return sizeof(char);
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
|
||||
case TINYGLTF_COMPONENT_TYPE_SHORT:
|
||||
return sizeof(short);
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT:
|
||||
case TINYGLTF_COMPONENT_TYPE_INT:
|
||||
return sizeof(int);
|
||||
case TINYGLTF_COMPONENT_TYPE_FLOAT:
|
||||
return sizeof(float);
|
||||
case TINYGLTF_COMPONENT_TYPE_DOUBLE:
|
||||
return sizeof(double);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void SetupMeshState(tinygltf::Model &model, GLuint progId) {
|
||||
// Buffer
|
||||
{
|
||||
@@ -264,14 +285,117 @@ static void SetupMeshState(tinygltf::Model &model, GLuint progId) {
|
||||
continue; // Unsupported bufferView.
|
||||
}
|
||||
|
||||
int sparse_accessor = -1;
|
||||
for (size_t a_i = 0; a_i < model.accessors.size(); ++a_i) {
|
||||
const auto &accessor = model.accessors[a_i];
|
||||
if (accessor.bufferView == i) {
|
||||
std::cout << i << " is used by accessor " << a_i << std::endl;
|
||||
if (accessor.sparse.isSparse) {
|
||||
std::cout
|
||||
<< "WARN: this bufferView has at least one sparse accessor to "
|
||||
"it. We are going to load the data as patched by this "
|
||||
"sparse accessor, not the original data"
|
||||
<< std::endl;
|
||||
sparse_accessor = a_i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const tinygltf::Buffer &buffer = model.buffers[bufferView.buffer];
|
||||
GLBufferState state;
|
||||
glGenBuffers(1, &state.vb);
|
||||
glBindBuffer(bufferView.target, state.vb);
|
||||
std::cout << "buffer.size= " << buffer.data.size()
|
||||
<< ", byteOffset = " << bufferView.byteOffset << std::endl;
|
||||
glBufferData(bufferView.target, bufferView.byteLength,
|
||||
&buffer.data.at(0) + bufferView.byteOffset, GL_STATIC_DRAW);
|
||||
|
||||
if (sparse_accessor < 0)
|
||||
glBufferData(bufferView.target, bufferView.byteLength,
|
||||
&buffer.data.at(0) + bufferView.byteOffset,
|
||||
GL_STATIC_DRAW);
|
||||
else {
|
||||
const auto accessor = model.accessors[sparse_accessor];
|
||||
// copy the buffer to a temporary one for sparse patching
|
||||
unsigned char *tmp_buffer = new unsigned char[bufferView.byteLength];
|
||||
memcpy(tmp_buffer, buffer.data.data() + bufferView.byteOffset,
|
||||
bufferView.byteLength);
|
||||
|
||||
const size_t size_of_object_in_buffer =
|
||||
ComponentTypeByteSize(accessor.componentType);
|
||||
const size_t size_of_sparse_indices =
|
||||
ComponentTypeByteSize(accessor.sparse.indices.componentType);
|
||||
|
||||
const auto &indices_buffer_view =
|
||||
model.bufferViews[accessor.sparse.indices.bufferView];
|
||||
const auto &indices_buffer = model.buffers[indices_buffer_view.buffer];
|
||||
|
||||
const auto &values_buffer_view =
|
||||
model.bufferViews[accessor.sparse.values.bufferView];
|
||||
const auto &values_buffer = model.buffers[values_buffer_view.buffer];
|
||||
|
||||
for (size_t sparse_index = 0; sparse_index < accessor.sparse.count;
|
||||
++sparse_index) {
|
||||
int index = 0;
|
||||
// std::cout << "accessor.sparse.indices.componentType = " <<
|
||||
// accessor.sparse.indices.componentType << std::endl;
|
||||
switch (accessor.sparse.indices.componentType) {
|
||||
case TINYGLTF_COMPONENT_TYPE_BYTE:
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
|
||||
index = (int)*(
|
||||
unsigned char *)(indices_buffer.data.data() +
|
||||
indices_buffer_view.byteOffset +
|
||||
accessor.sparse.indices.byteOffset +
|
||||
(sparse_index * size_of_sparse_indices));
|
||||
break;
|
||||
case TINYGLTF_COMPONENT_TYPE_SHORT:
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
|
||||
index = (int)*(
|
||||
unsigned short *)(indices_buffer.data.data() +
|
||||
indices_buffer_view.byteOffset +
|
||||
accessor.sparse.indices.byteOffset +
|
||||
(sparse_index * size_of_sparse_indices));
|
||||
break;
|
||||
case TINYGLTF_COMPONENT_TYPE_INT:
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT:
|
||||
index = (int)*(
|
||||
unsigned int *)(indices_buffer.data.data() +
|
||||
indices_buffer_view.byteOffset +
|
||||
accessor.sparse.indices.byteOffset +
|
||||
(sparse_index * size_of_sparse_indices));
|
||||
break;
|
||||
}
|
||||
std::cout << "updating sparse data at index : " << index
|
||||
<< std::endl;
|
||||
// index is now the target of the sparse index to patch in
|
||||
const unsigned char *read_from =
|
||||
values_buffer.data.data() +
|
||||
(values_buffer_view.byteOffset +
|
||||
accessor.sparse.values.byteOffset) +
|
||||
(sparse_index * (size_of_object_in_buffer * accessor.type));
|
||||
|
||||
/*
|
||||
std::cout << ((float*)read_from)[0] << "\n";
|
||||
std::cout << ((float*)read_from)[1] << "\n";
|
||||
std::cout << ((float*)read_from)[2] << "\n";
|
||||
*/
|
||||
|
||||
unsigned char *write_to =
|
||||
tmp_buffer + index * (size_of_object_in_buffer * accessor.type);
|
||||
|
||||
memcpy(write_to, read_from, size_of_object_in_buffer * accessor.type);
|
||||
}
|
||||
|
||||
// debug:
|
||||
/*for(size_t p = 0; p < bufferView.byteLength/sizeof(float); p++)
|
||||
{
|
||||
float* b = (float*)tmp_buffer;
|
||||
std::cout << "modified_buffer [" << p << "] = " << b[p] << '\n';
|
||||
}*/
|
||||
|
||||
glBufferData(bufferView.target, bufferView.byteLength, tmp_buffer,
|
||||
GL_STATIC_DRAW);
|
||||
delete[] tmp_buffer;
|
||||
}
|
||||
glBindBuffer(bufferView.target, 0);
|
||||
|
||||
gBufferState[i] = state;
|
||||
@@ -279,55 +403,55 @@ static void SetupMeshState(tinygltf::Model &model, GLuint progId) {
|
||||
}
|
||||
|
||||
#if 0 // TODO(syoyo): Implement
|
||||
// Texture
|
||||
{
|
||||
for (size_t i = 0; i < model.meshes.size(); i++) {
|
||||
const tinygltf::Mesh &mesh = model.meshes[i];
|
||||
// Texture
|
||||
{
|
||||
for (size_t i = 0; i < model.meshes.size(); i++) {
|
||||
const tinygltf::Mesh &mesh = model.meshes[i];
|
||||
|
||||
gMeshState[mesh.name].diffuseTex.resize(mesh.primitives.size());
|
||||
for (size_t primId = 0; primId < mesh.primitives.size(); primId++) {
|
||||
const tinygltf::Primitive &primitive = mesh.primitives[primId];
|
||||
gMeshState[mesh.name].diffuseTex.resize(mesh.primitives.size());
|
||||
for (size_t primId = 0; primId < mesh.primitives.size(); primId++) {
|
||||
const tinygltf::Primitive &primitive = mesh.primitives[primId];
|
||||
|
||||
gMeshState[mesh.name].diffuseTex[primId] = 0;
|
||||
gMeshState[mesh.name].diffuseTex[primId] = 0;
|
||||
|
||||
if (primitive.material < 0) {
|
||||
continue;
|
||||
}
|
||||
tinygltf::Material &mat = model.materials[primitive.material];
|
||||
// printf("material.name = %s\n", mat.name.c_str());
|
||||
if (mat.values.find("diffuse") != mat.values.end()) {
|
||||
std::string diffuseTexName = mat.values["diffuse"].string_value;
|
||||
if (model.textures.find(diffuseTexName) != model.textures.end()) {
|
||||
tinygltf::Texture &tex = model.textures[diffuseTexName];
|
||||
if (scene.images.find(tex.source) != model.images.end()) {
|
||||
tinygltf::Image &image = model.images[tex.source];
|
||||
GLuint texId;
|
||||
glGenTextures(1, &texId);
|
||||
glBindTexture(tex.target, texId);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
if (primitive.material < 0) {
|
||||
continue;
|
||||
}
|
||||
tinygltf::Material &mat = model.materials[primitive.material];
|
||||
// printf("material.name = %s\n", mat.name.c_str());
|
||||
if (mat.values.find("diffuse") != mat.values.end()) {
|
||||
std::string diffuseTexName = mat.values["diffuse"].string_value;
|
||||
if (model.textures.find(diffuseTexName) != model.textures.end()) {
|
||||
tinygltf::Texture &tex = model.textures[diffuseTexName];
|
||||
if (scene.images.find(tex.source) != model.images.end()) {
|
||||
tinygltf::Image &image = model.images[tex.source];
|
||||
GLuint texId;
|
||||
glGenTextures(1, &texId);
|
||||
glBindTexture(tex.target, texId);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
// Ignore Texture.fomat.
|
||||
GLenum format = GL_RGBA;
|
||||
if (image.component == 3) {
|
||||
format = GL_RGB;
|
||||
}
|
||||
glTexImage2D(tex.target, 0, tex.internalFormat, image.width,
|
||||
image.height, 0, format, tex.type,
|
||||
&image.image.at(0));
|
||||
// Ignore Texture.fomat.
|
||||
GLenum format = GL_RGBA;
|
||||
if (image.component == 3) {
|
||||
format = GL_RGB;
|
||||
}
|
||||
glTexImage2D(tex.target, 0, tex.internalFormat, image.width,
|
||||
image.height, 0, format, tex.type,
|
||||
&image.image.at(0));
|
||||
|
||||
CheckErrors("texImage2D");
|
||||
glBindTexture(tex.target, 0);
|
||||
CheckErrors("texImage2D");
|
||||
glBindTexture(tex.target, 0);
|
||||
|
||||
printf("TexId = %d\n", texId);
|
||||
gMeshState[mesh.name].diffuseTex[primId] = texId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("TexId = %d\n", texId);
|
||||
gMeshState[mesh.name].diffuseTex[primId] = texId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
glUseProgram(progId);
|
||||
@@ -348,164 +472,164 @@ static void SetupMeshState(tinygltf::Model &model, GLuint progId) {
|
||||
#if 0 // TODO(syoyo): Implement
|
||||
// Setup curves geometry extension
|
||||
static void SetupCurvesState(tinygltf::Scene &scene, GLuint progId) {
|
||||
// Find curves primitive.
|
||||
{
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator it(
|
||||
scene.meshes.begin());
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(
|
||||
scene.meshes.end());
|
||||
// Find curves primitive.
|
||||
{
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator it(
|
||||
scene.meshes.begin());
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(
|
||||
scene.meshes.end());
|
||||
|
||||
for (; it != itEnd; it++) {
|
||||
const tinygltf::Mesh &mesh = it->second;
|
||||
for (; it != itEnd; it++) {
|
||||
const tinygltf::Mesh &mesh = it->second;
|
||||
|
||||
// Currently we only support one primitive per mesh.
|
||||
if (mesh.primitives.size() > 1) {
|
||||
continue;
|
||||
}
|
||||
// Currently we only support one primitive per mesh.
|
||||
if (mesh.primitives.size() > 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (size_t primId = 0; primId < mesh.primitives.size(); primId++) {
|
||||
const tinygltf::Primitive &primitive = mesh.primitives[primId];
|
||||
for (size_t primId = 0; primId < mesh.primitives.size(); primId++) {
|
||||
const tinygltf::Primitive &primitive = mesh.primitives[primId];
|
||||
|
||||
gMeshState[mesh.name].diffuseTex[primId] = 0;
|
||||
gMeshState[mesh.name].diffuseTex[primId] = 0;
|
||||
|
||||
if (primitive.material.empty()) {
|
||||
continue;
|
||||
}
|
||||
if (primitive.material.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool has_curves = false;
|
||||
if (primitive.extras.IsObject()) {
|
||||
if (primitive.extras.Has("ext_mode")) {
|
||||
const tinygltf::Value::Object &o =
|
||||
primitive.extras.Get<tinygltf::Value::Object>();
|
||||
const tinygltf::Value &ext_mode = o.find("ext_mode")->second;
|
||||
bool has_curves = false;
|
||||
if (primitive.extras.IsObject()) {
|
||||
if (primitive.extras.Has("ext_mode")) {
|
||||
const tinygltf::Value::Object &o =
|
||||
primitive.extras.Get<tinygltf::Value::Object>();
|
||||
const tinygltf::Value &ext_mode = o.find("ext_mode")->second;
|
||||
|
||||
if (ext_mode.IsString()) {
|
||||
const std::string &str = ext_mode.Get<std::string>();
|
||||
if (str.compare("curves") == 0) {
|
||||
has_curves = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ext_mode.IsString()) {
|
||||
const std::string &str = ext_mode.Get<std::string>();
|
||||
if (str.compare("curves") == 0) {
|
||||
has_curves = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_curves) {
|
||||
continue;
|
||||
}
|
||||
if (!has_curves) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Construct curves buffer
|
||||
const tinygltf::Accessor &vtx_accessor =
|
||||
scene.accessors[primitive.attributes.find("POSITION")->second];
|
||||
const tinygltf::Accessor &nverts_accessor =
|
||||
scene.accessors[primitive.attributes.find("NVERTS")->second];
|
||||
const tinygltf::BufferView &vtx_bufferView =
|
||||
scene.bufferViews[vtx_accessor.bufferView];
|
||||
const tinygltf::BufferView &nverts_bufferView =
|
||||
scene.bufferViews[nverts_accessor.bufferView];
|
||||
const tinygltf::Buffer &vtx_buffer =
|
||||
scene.buffers[vtx_bufferView.buffer];
|
||||
const tinygltf::Buffer &nverts_buffer =
|
||||
scene.buffers[nverts_bufferView.buffer];
|
||||
// Construct curves buffer
|
||||
const tinygltf::Accessor &vtx_accessor =
|
||||
scene.accessors[primitive.attributes.find("POSITION")->second];
|
||||
const tinygltf::Accessor &nverts_accessor =
|
||||
scene.accessors[primitive.attributes.find("NVERTS")->second];
|
||||
const tinygltf::BufferView &vtx_bufferView =
|
||||
scene.bufferViews[vtx_accessor.bufferView];
|
||||
const tinygltf::BufferView &nverts_bufferView =
|
||||
scene.bufferViews[nverts_accessor.bufferView];
|
||||
const tinygltf::Buffer &vtx_buffer =
|
||||
scene.buffers[vtx_bufferView.buffer];
|
||||
const tinygltf::Buffer &nverts_buffer =
|
||||
scene.buffers[nverts_bufferView.buffer];
|
||||
|
||||
// std::cout << "vtx_bufferView = " << vtx_accessor.bufferView <<
|
||||
// std::endl;
|
||||
// std::cout << "nverts_bufferView = " << nverts_accessor.bufferView <<
|
||||
// std::endl;
|
||||
// std::cout << "vtx_buffer.size = " << vtx_buffer.data.size() <<
|
||||
// std::endl;
|
||||
// std::cout << "nverts_buffer.size = " << nverts_buffer.data.size() <<
|
||||
// std::endl;
|
||||
// std::cout << "vtx_bufferView = " << vtx_accessor.bufferView <<
|
||||
// std::endl;
|
||||
// std::cout << "nverts_bufferView = " << nverts_accessor.bufferView <<
|
||||
// std::endl;
|
||||
// std::cout << "vtx_buffer.size = " << vtx_buffer.data.size() <<
|
||||
// std::endl;
|
||||
// std::cout << "nverts_buffer.size = " << nverts_buffer.data.size() <<
|
||||
// std::endl;
|
||||
|
||||
const int *nverts =
|
||||
reinterpret_cast<const int *>(nverts_buffer.data.data());
|
||||
const float *vtx =
|
||||
reinterpret_cast<const float *>(vtx_buffer.data.data());
|
||||
const int *nverts =
|
||||
reinterpret_cast<const int *>(nverts_buffer.data.data());
|
||||
const float *vtx =
|
||||
reinterpret_cast<const float *>(vtx_buffer.data.data());
|
||||
|
||||
// Convert to GL_LINES data.
|
||||
std::vector<float> line_pts;
|
||||
size_t vtx_offset = 0;
|
||||
for (int k = 0; k < static_cast<int>(nverts_accessor.count); k++) {
|
||||
for (int n = 0; n < nverts[k] - 1; n++) {
|
||||
// Convert to GL_LINES data.
|
||||
std::vector<float> line_pts;
|
||||
size_t vtx_offset = 0;
|
||||
for (int k = 0; k < static_cast<int>(nverts_accessor.count); k++) {
|
||||
for (int n = 0; n < nverts[k] - 1; n++) {
|
||||
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n) + 0]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n) + 1]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n) + 2]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n) + 0]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n) + 1]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n) + 2]);
|
||||
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 0]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 1]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 2]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 0]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 1]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 2]);
|
||||
|
||||
// std::cout << "p0 " << vtx[3 * (vtx_offset + n) + 0] << ", "
|
||||
// << vtx[3 * (vtx_offset + n) + 1] << ", "
|
||||
// << vtx[3 * (vtx_offset + n) + 2] << std::endl;
|
||||
// std::cout << "p0 " << vtx[3 * (vtx_offset + n) + 0] << ", "
|
||||
// << vtx[3 * (vtx_offset + n) + 1] << ", "
|
||||
// << vtx[3 * (vtx_offset + n) + 2] << std::endl;
|
||||
|
||||
// std::cout << "p1 " << vtx[3 * (vtx_offset + n+1) + 0] << ", "
|
||||
// << vtx[3 * (vtx_offset + n+1) + 1] << ", "
|
||||
// << vtx[3 * (vtx_offset + n+1) + 2] << std::endl;
|
||||
}
|
||||
// std::cout << "p1 " << vtx[3 * (vtx_offset + n+1) + 0] << ", "
|
||||
// << vtx[3 * (vtx_offset + n+1) + 1] << ", "
|
||||
// << vtx[3 * (vtx_offset + n+1) + 2] << std::endl;
|
||||
}
|
||||
|
||||
vtx_offset += nverts[k];
|
||||
}
|
||||
vtx_offset += nverts[k];
|
||||
}
|
||||
|
||||
GLCurvesState state;
|
||||
glGenBuffers(1, &state.vb);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, state.vb);
|
||||
glBufferData(GL_ARRAY_BUFFER, line_pts.size() * sizeof(float),
|
||||
line_pts.data(), GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
GLCurvesState state;
|
||||
glGenBuffers(1, &state.vb);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, state.vb);
|
||||
glBufferData(GL_ARRAY_BUFFER, line_pts.size() * sizeof(float),
|
||||
line_pts.data(), GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
state.count = line_pts.size() / 3;
|
||||
gCurvesMesh[mesh.name] = state;
|
||||
state.count = line_pts.size() / 3;
|
||||
gCurvesMesh[mesh.name] = state;
|
||||
|
||||
// Material
|
||||
tinygltf::Material &mat = scene.materials[primitive.material];
|
||||
// printf("material.name = %s\n", mat.name.c_str());
|
||||
if (mat.values.find("diffuse") != mat.values.end()) {
|
||||
std::string diffuseTexName = mat.values["diffuse"].string_value;
|
||||
if (scene.textures.find(diffuseTexName) != scene.textures.end()) {
|
||||
tinygltf::Texture &tex = scene.textures[diffuseTexName];
|
||||
if (scene.images.find(tex.source) != scene.images.end()) {
|
||||
tinygltf::Image &image = scene.images[tex.source];
|
||||
GLuint texId;
|
||||
glGenTextures(1, &texId);
|
||||
glBindTexture(tex.target, texId);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
// Material
|
||||
tinygltf::Material &mat = scene.materials[primitive.material];
|
||||
// printf("material.name = %s\n", mat.name.c_str());
|
||||
if (mat.values.find("diffuse") != mat.values.end()) {
|
||||
std::string diffuseTexName = mat.values["diffuse"].string_value;
|
||||
if (scene.textures.find(diffuseTexName) != scene.textures.end()) {
|
||||
tinygltf::Texture &tex = scene.textures[diffuseTexName];
|
||||
if (scene.images.find(tex.source) != scene.images.end()) {
|
||||
tinygltf::Image &image = scene.images[tex.source];
|
||||
GLuint texId;
|
||||
glGenTextures(1, &texId);
|
||||
glBindTexture(tex.target, texId);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
// Ignore Texture.fomat.
|
||||
GLenum format = GL_RGBA;
|
||||
if (image.component == 3) {
|
||||
format = GL_RGB;
|
||||
}
|
||||
glTexImage2D(tex.target, 0, tex.internalFormat, image.width,
|
||||
image.height, 0, format, tex.type,
|
||||
&image.image.at(0));
|
||||
// Ignore Texture.fomat.
|
||||
GLenum format = GL_RGBA;
|
||||
if (image.component == 3) {
|
||||
format = GL_RGB;
|
||||
}
|
||||
glTexImage2D(tex.target, 0, tex.internalFormat, image.width,
|
||||
image.height, 0, format, tex.type,
|
||||
&image.image.at(0));
|
||||
|
||||
CheckErrors("texImage2D");
|
||||
glBindTexture(tex.target, 0);
|
||||
CheckErrors("texImage2D");
|
||||
glBindTexture(tex.target, 0);
|
||||
|
||||
printf("TexId = %d\n", texId);
|
||||
gMeshState[mesh.name].diffuseTex[primId] = texId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("TexId = %d\n", texId);
|
||||
gMeshState[mesh.name].diffuseTex[primId] = texId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glUseProgram(progId);
|
||||
GLint vtloc = glGetAttribLocation(progId, "in_vertex");
|
||||
GLint nrmloc = glGetAttribLocation(progId, "in_normal");
|
||||
GLint uvloc = glGetAttribLocation(progId, "in_texcoord");
|
||||
glUseProgram(progId);
|
||||
GLint vtloc = glGetAttribLocation(progId, "in_vertex");
|
||||
GLint nrmloc = glGetAttribLocation(progId, "in_normal");
|
||||
GLint uvloc = glGetAttribLocation(progId, "in_texcoord");
|
||||
|
||||
GLint diffuseTexLoc = glGetUniformLocation(progId, "diffuseTex");
|
||||
GLint isCurvesLoc = glGetUniformLocation(progId, "uIsCurves");
|
||||
GLint diffuseTexLoc = glGetUniformLocation(progId, "diffuseTex");
|
||||
GLint isCurvesLoc = glGetUniformLocation(progId, "uIsCurves");
|
||||
|
||||
gGLProgramState.attribs["POSITION"] = vtloc;
|
||||
gGLProgramState.attribs["NORMAL"] = nrmloc;
|
||||
gGLProgramState.attribs["TEXCOORD_0"] = uvloc;
|
||||
gGLProgramState.uniforms["diffuseTex"] = diffuseTexLoc;
|
||||
gGLProgramState.uniforms["uIsCurves"] = isCurvesLoc;
|
||||
gGLProgramState.attribs["POSITION"] = vtloc;
|
||||
gGLProgramState.attribs["NORMAL"] = nrmloc;
|
||||
gGLProgramState.attribs["TEXCOORD_0"] = uvloc;
|
||||
gGLProgramState.uniforms["diffuseTex"] = diffuseTexLoc;
|
||||
gGLProgramState.uniforms["uIsCurves"] = isCurvesLoc;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -558,12 +682,13 @@ static void DrawMesh(tinygltf::Model &model, const tinygltf::Mesh &mesh) {
|
||||
(it->first.compare("TEXCOORD_0") == 0)) {
|
||||
if (gGLProgramState.attribs[it->first] >= 0) {
|
||||
// Compute byteStride from Accessor + BufferView combination.
|
||||
int byteStride = accessor.ByteStride(model.bufferViews[accessor.bufferView]);
|
||||
int byteStride =
|
||||
accessor.ByteStride(model.bufferViews[accessor.bufferView]);
|
||||
assert(byteStride != -1);
|
||||
glVertexAttribPointer(gGLProgramState.attribs[it->first], size,
|
||||
accessor.componentType, accessor.normalized ? GL_TRUE : GL_FALSE,
|
||||
byteStride,
|
||||
BUFFER_OFFSET(accessor.byteOffset));
|
||||
accessor.componentType,
|
||||
accessor.normalized ? GL_TRUE : GL_FALSE,
|
||||
byteStride, BUFFER_OFFSET(accessor.byteOffset));
|
||||
CheckErrors("vertex attrib pointer");
|
||||
glEnableVertexAttribArray(gGLProgramState.attribs[it->first]);
|
||||
CheckErrors("enable vertex attrib array");
|
||||
@@ -617,32 +742,32 @@ static void DrawMesh(tinygltf::Model &model, const tinygltf::Mesh &mesh) {
|
||||
|
||||
#if 0 // TODO(syoyo): Implement
|
||||
static void DrawCurves(tinygltf::Scene &scene, const tinygltf::Mesh &mesh) {
|
||||
(void)scene;
|
||||
(void)scene;
|
||||
|
||||
if (gCurvesMesh.find(mesh.name) == gCurvesMesh.end()) {
|
||||
return;
|
||||
}
|
||||
if (gCurvesMesh.find(mesh.name) == gCurvesMesh.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gGLProgramState.uniforms["isCurvesLoc"] >= 0) {
|
||||
glUniform1i(gGLProgramState.uniforms["isCurvesLoc"], 1);
|
||||
}
|
||||
if (gGLProgramState.uniforms["isCurvesLoc"] >= 0) {
|
||||
glUniform1i(gGLProgramState.uniforms["isCurvesLoc"], 1);
|
||||
}
|
||||
|
||||
GLCurvesState &state = gCurvesMesh[mesh.name];
|
||||
GLCurvesState &state = gCurvesMesh[mesh.name];
|
||||
|
||||
if (gGLProgramState.attribs["POSITION"] >= 0) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, state.vb);
|
||||
glVertexAttribPointer(gGLProgramState.attribs["POSITION"], 3, GL_FLOAT,
|
||||
GL_FALSE, /* stride */ 0, BUFFER_OFFSET(0));
|
||||
CheckErrors("curve: vertex attrib pointer");
|
||||
glEnableVertexAttribArray(gGLProgramState.attribs["POSITION"]);
|
||||
CheckErrors("curve: enable vertex attrib array");
|
||||
}
|
||||
if (gGLProgramState.attribs["POSITION"] >= 0) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, state.vb);
|
||||
glVertexAttribPointer(gGLProgramState.attribs["POSITION"], 3, GL_FLOAT,
|
||||
GL_FALSE, /* stride */ 0, BUFFER_OFFSET(0));
|
||||
CheckErrors("curve: vertex attrib pointer");
|
||||
glEnableVertexAttribArray(gGLProgramState.attribs["POSITION"]);
|
||||
CheckErrors("curve: enable vertex attrib array");
|
||||
}
|
||||
|
||||
glDrawArrays(GL_LINES, 0, state.count);
|
||||
glDrawArrays(GL_LINES, 0, state.count);
|
||||
|
||||
if (gGLProgramState.attribs["POSITION"] >= 0) {
|
||||
glDisableVertexAttribArray(gGLProgramState.attribs["POSITION"]);
|
||||
}
|
||||
if (gGLProgramState.attribs["POSITION"] >= 0) {
|
||||
glDisableVertexAttribArray(gGLProgramState.attribs["POSITION"]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -693,16 +818,16 @@ static void DrawNode(tinygltf::Model &model, const tinygltf::Node &node) {
|
||||
|
||||
static void DrawModel(tinygltf::Model &model) {
|
||||
#if 0
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator it(scene.meshes.begin());
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(scene.meshes.end());
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator it(scene.meshes.begin());
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(scene.meshes.end());
|
||||
|
||||
for (; it != itEnd; it++) {
|
||||
DrawMesh(scene, it->second);
|
||||
DrawCurves(scene, it->second);
|
||||
}
|
||||
for (; it != itEnd; it++) {
|
||||
DrawMesh(scene, it->second);
|
||||
DrawCurves(scene, it->second);
|
||||
}
|
||||
#else
|
||||
//If the glTF asset has at least one scene, and doesn't define a default one
|
||||
//just show the first one we can find
|
||||
// If the glTF asset has at least one scene, and doesn't define a default one
|
||||
// just show the first one we can find
|
||||
assert(model.scenes.size() > 0);
|
||||
int scene_to_display = model.defaultScene > -1 ? model.defaultScene : 0;
|
||||
const tinygltf::Scene &scene = model.scenes[scene_to_display];
|
||||
@@ -752,7 +877,8 @@ int main(int argc, char **argv) {
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _DEBUG
|
||||
std::string input_filename(argv[1] ? argv[1] : "../../../models/Cube/Cube.gltf");
|
||||
std::string input_filename(argv[1] ? argv[1]
|
||||
: "../../../models/Cube/Cube.gltf");
|
||||
#endif
|
||||
#else
|
||||
std::string input_filename(argv[1] ? argv[1] : "../../models/Cube/Cube.gltf");
|
||||
@@ -763,7 +889,8 @@ int main(int argc, char **argv) {
|
||||
bool ret = false;
|
||||
if (ext.compare("glb") == 0) {
|
||||
// assume binary glTF.
|
||||
ret = loader.LoadBinaryFromFile(&model, &err, &warn, input_filename.c_str());
|
||||
ret =
|
||||
loader.LoadBinaryFromFile(&model, &err, &warn, input_filename.c_str());
|
||||
} else {
|
||||
// assume ascii glTF.
|
||||
ret = loader.LoadASCIIFromFile(&model, &err, &warn, input_filename.c_str());
|
||||
@@ -825,15 +952,14 @@ int main(int argc, char **argv) {
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _DEBUG
|
||||
const char *shader_frag_filename = "../shader.frag";
|
||||
const char *shader_vert_filename = "../shader.vert";
|
||||
const char *shader_frag_filename = "../shader.frag";
|
||||
const char *shader_vert_filename = "../shader.vert";
|
||||
#endif
|
||||
#else
|
||||
const char *shader_frag_filename = "shader.frag";
|
||||
const char *shader_vert_filename = "shader.vert";
|
||||
#endif
|
||||
|
||||
|
||||
if (false == LoadShader(GL_VERTEX_SHADER, vertId, shader_vert_filename)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
16
gltf.schema.resolved.inc
Normal file
16
gltf.schema.resolved.inc
Normal file
File diff suppressed because one or more lines are too long
@@ -2,6 +2,7 @@
|
||||
// TODO(syoyo): Print extensions and extras for each glTF object.
|
||||
//
|
||||
#define TINYGLTF_IMPLEMENTATION
|
||||
#define TINYGLTF_ENABLE_SCHEMA_VALIDATOR
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include "tiny_gltf.h"
|
||||
@@ -228,7 +229,8 @@ static std::string PrintParameterMap(const tinygltf::ParameterMap &pmap) {
|
||||
#endif
|
||||
|
||||
static std::string PrintValue(const std::string &name,
|
||||
const tinygltf::Value &value, const int indent, const bool tag = true) {
|
||||
const tinygltf::Value &value, const int indent,
|
||||
const bool tag = true) {
|
||||
std::stringstream ss;
|
||||
|
||||
if (value.IsObject()) {
|
||||
@@ -265,11 +267,10 @@ static std::string PrintValue(const std::string &name,
|
||||
} else if (value.IsArray()) {
|
||||
ss << Indent(indent) << name << " [ ";
|
||||
for (size_t i = 0; i < value.Size(); i++) {
|
||||
ss << PrintValue("", value.Get(int(i)), indent + 1, /* tag */false);
|
||||
if (i != (value.ArrayLen()-1)) {
|
||||
ss << PrintValue("", value.Get(int(i)), indent + 1, /* tag */ false);
|
||||
if (i != (value.ArrayLen() - 1)) {
|
||||
ss << ", ";
|
||||
}
|
||||
|
||||
}
|
||||
ss << Indent(indent) << "] ";
|
||||
}
|
||||
@@ -330,13 +331,13 @@ static void DumpPrimitive(const tinygltf::Primitive &primitive, int indent) {
|
||||
<< PrintValue("extras", primitive.extras, indent + 1) << std::endl;
|
||||
}
|
||||
|
||||
static void DumpExtensions(const tinygltf::ExtensionMap &extension, const int indent)
|
||||
{
|
||||
static void DumpExtensions(const tinygltf::ExtensionMap &extension,
|
||||
const int indent) {
|
||||
// TODO(syoyo): pritty print Value
|
||||
for (auto &e : extension) {
|
||||
std::cout << Indent(indent) << e.first << std::endl;
|
||||
std::cout << PrintValue("extensions", e.second, indent+1) << std::endl;
|
||||
}
|
||||
std::cout << PrintValue("extensions", e.second, indent + 1) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
static void Dump(const tinygltf::Model &model) {
|
||||
@@ -409,6 +410,30 @@ static void Dump(const tinygltf::Model &model) {
|
||||
}
|
||||
std::cout << "]" << std::endl;
|
||||
}
|
||||
|
||||
if (accessor.sparse.isSparse) {
|
||||
std::cout << Indent(2) << "sparse:" << std::endl;
|
||||
std::cout << Indent(3) << "count : " << accessor.sparse.count
|
||||
<< std::endl;
|
||||
std::cout << Indent(3) << "indices: " << std::endl;
|
||||
std::cout << Indent(4)
|
||||
<< "bufferView : " << accessor.sparse.indices.bufferView
|
||||
<< std::endl;
|
||||
std::cout << Indent(4)
|
||||
<< "byteOffset : " << accessor.sparse.indices.byteOffset
|
||||
<< std::endl;
|
||||
std::cout << Indent(4) << "componentType: "
|
||||
<< PrintComponentType(accessor.sparse.indices.componentType)
|
||||
<< "(" << accessor.sparse.indices.componentType << ")"
|
||||
<< std::endl;
|
||||
std::cout << Indent(3) << "values : " << std::endl;
|
||||
std::cout << Indent(4)
|
||||
<< "bufferView : " << accessor.sparse.values.bufferView
|
||||
<< std::endl;
|
||||
std::cout << Indent(4)
|
||||
<< "byteOffset : " << accessor.sparse.values.byteOffset
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -585,10 +610,11 @@ static void Dump(const tinygltf::Model &model) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// toplevel extensions
|
||||
{
|
||||
std::cout << "extensions(items=" << model.extensions.size() << ")" << std::endl;
|
||||
std::cout << "extensions(items=" << model.extensions.size() << ")"
|
||||
<< std::endl;
|
||||
DumpExtensions(model.extensions, 1);
|
||||
}
|
||||
}
|
||||
@@ -602,7 +628,7 @@ int main(int argc, char **argv) {
|
||||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTF gltf_ctx;
|
||||
std::string err;
|
||||
std::string warn;
|
||||
std::string warn;
|
||||
std::string input_filename(argv[1]);
|
||||
std::string ext = GetFilePathExtension(input_filename);
|
||||
|
||||
@@ -610,18 +636,24 @@ int main(int argc, char **argv) {
|
||||
if (ext.compare("glb") == 0) {
|
||||
std::cout << "Reading binary glTF" << std::endl;
|
||||
// assume binary glTF.
|
||||
ret = gltf_ctx.LoadBinaryFromFile(&model, &err, &warn, input_filename.c_str());
|
||||
ret = gltf_ctx.LoadBinaryFromFile(&model, &err, &warn,
|
||||
input_filename.c_str());
|
||||
} else {
|
||||
std::cout << "Reading ASCII glTF" << std::endl;
|
||||
// assume ascii glTF.
|
||||
ret = gltf_ctx.LoadASCIIFromFile(&model, &err, &warn, input_filename.c_str());
|
||||
#if defined(TINYGLTF_ENABLE_SCHEMA_VALIDATOR)
|
||||
ret =
|
||||
gltf_ctx.LoadASCIIFromFileWithValidation(&model, &err, &warn, input_filename.c_str());
|
||||
#else
|
||||
ret =
|
||||
gltf_ctx.LoadASCIIFromFile(&model, &err, &warn, input_filename.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!warn.empty()) {
|
||||
printf("Warn: %s\n", warn.c_str());
|
||||
}
|
||||
|
||||
|
||||
if (!err.empty()) {
|
||||
printf("Err: %s\n", err.c_str());
|
||||
}
|
||||
|
||||
16906
rapidjson-amalgamation.h
Normal file
16906
rapidjson-amalgamation.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -14,6 +14,7 @@ import subprocess
|
||||
sample_model_dir = "/home/syoyo/work/glTF-Sample-Models"
|
||||
base_model_dir = os.path.join(sample_model_dir, "2.0")
|
||||
|
||||
# Include `glTF-Draco` when you build `loader_example` with draco support.
|
||||
kinds = [ "glTF", "glTF-Binary", "glTF-Embedded", "glTF-MaterialsCommon"]
|
||||
# ---------------------------------
|
||||
|
||||
|
||||
2100
tiny_gltf.h
2100
tiny_gltf.h
File diff suppressed because it is too large
Load Diff
20
tools/schema_ref_resolver/README.md
Normal file
20
tools/schema_ref_resolver/README.md
Normal file
@@ -0,0 +1,20 @@
|
||||
Create single schema string by deferencing $ref in glTF schema JSON for embedding JSON scheme string in C++.
|
||||
|
||||
## Setup
|
||||
|
||||
Use python2
|
||||
|
||||
```
|
||||
$ pip2 install jsonpath-rw
|
||||
$ pip2 install simplejson
|
||||
```
|
||||
|
||||
Put `ref_resolver.py` and `generate_single_schema_doc.py` to glTF schema direcotry(i.e. `$glTF/specification/2.0/schema`)
|
||||
|
||||
## Generate
|
||||
|
||||
Run `generate_single_schema_doc.py`
|
||||
|
||||
## TODO
|
||||
|
||||
* [ ] Print date and git commit id?
|
||||
37
tools/schema_ref_resolver/generate_single_schema_doc.py
Normal file
37
tools/schema_ref_resolver/generate_single_schema_doc.py
Normal file
@@ -0,0 +1,37 @@
|
||||
# for print with `end` parameter
|
||||
from __future__ import print_function
|
||||
|
||||
import json
|
||||
from ref_resolver import RefResolver
|
||||
import base64
|
||||
|
||||
f = open("glTF.schema.json")
|
||||
j = json.loads(f.read())
|
||||
|
||||
# call to API resolve method
|
||||
RefResolver("glTF.schema.json").resolve(j)
|
||||
|
||||
j_str = json.dumps(j, indent=2)
|
||||
|
||||
|
||||
# Run json.dumps twice to get escaped string
|
||||
escaped_str = json.dumps(j_str)
|
||||
|
||||
# MSVC does not accept string larger than 16K.
|
||||
# https://docs.microsoft.com/en-us/cpp/error-messages/compiler-errors-1/compiler-error-c2026?view=vs-2019
|
||||
# Also, it has a hard limit of 65,535 bytes even splitting a string with double quotation.
|
||||
# So, we write string as an array of string(then application must concatenate it)
|
||||
|
||||
# https://stackoverflow.com/questions/9475241/split-string-every-nth-character
|
||||
n = 8000 # Conservative number
|
||||
|
||||
splitted_string = [escaped_str[i:i+n] for i in range(0, len(escaped_str), n)]
|
||||
#print(len(splitted_string))
|
||||
|
||||
print("const char *kglTFSchemaStrings[] = {", end='')
|
||||
for (i, s) in enumerate(splitted_string):
|
||||
print(s, end='')
|
||||
if i != (len(splitted_string) - 1):
|
||||
print('",\n"', end='')
|
||||
|
||||
print("};")
|
||||
16
tools/schema_ref_resolver/glTF.schema.resolved.inc
Normal file
16
tools/schema_ref_resolver/glTF.schema.resolved.inc
Normal file
File diff suppressed because one or more lines are too long
2739
tools/schema_ref_resolver/glTF.schema.resolved.json
Normal file
2739
tools/schema_ref_resolver/glTF.schema.resolved.json
Normal file
File diff suppressed because it is too large
Load Diff
82
tools/schema_ref_resolver/ref_resolver.py
Normal file
82
tools/schema_ref_resolver/ref_resolver.py
Normal file
@@ -0,0 +1,82 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
from urlparse import urlparse, urljoin
|
||||
import simplejson as json
|
||||
from os.path import isfile
|
||||
import jsonpath_rw
|
||||
import requests
|
||||
|
||||
|
||||
cache = {}
|
||||
|
||||
class RefResolver:
|
||||
|
||||
def __init__(self):
|
||||
self.url_fragments = None
|
||||
|
||||
def __init__(self, id):
|
||||
self.id = id
|
||||
if id is not None:
|
||||
self.url_fragments = urlparse(id)
|
||||
else:
|
||||
self.url_fragments = None
|
||||
|
||||
|
||||
|
||||
def resolve(self, json_obj):
|
||||
if isinstance(json_obj, dict):
|
||||
for key, value in json_obj.items():
|
||||
if key == "$ref":
|
||||
ref_frag = urlparse(value)
|
||||
ref_file = ref_frag.netloc + ref_frag.path
|
||||
json_dump = {}
|
||||
if ref_file in cache:
|
||||
json_dump = cache[ref_file]
|
||||
else:
|
||||
if self.url_fragments.scheme in ['http', 'https']:
|
||||
ref_url = urljoin(self.id, ref_file)
|
||||
if callable(requests.Response.json):
|
||||
json_dump = requests.get(ref_url).json()
|
||||
else:
|
||||
json_dump = requests.get(ref_url).json
|
||||
ref_id = None
|
||||
if 'tilte' in json_dump:
|
||||
ref_id = json_dump['title']
|
||||
cache[ref_file] = json_dump
|
||||
RefResolver(ref_id).resolve(json_dump)
|
||||
cache[ref_file] = json_dump
|
||||
#elif self.url_fragments.scheme == 'file':
|
||||
else:
|
||||
if isfile(ref_file):
|
||||
# if the ref is another file -> go there and get it
|
||||
json_dump = json.load(open(ref_file))
|
||||
ref_id = None
|
||||
if 'title' in json_dump:
|
||||
ref_id = json_dump['title']
|
||||
cache[ref_file] = json_dump
|
||||
RefResolver(ref_id).resolve(json_dump)
|
||||
cache[ref_file] = json_dump
|
||||
else:
|
||||
# if the ref is in the same file grab it from the same file
|
||||
json_dump = json.load(open(self.url_fragments.netloc+self.url_fragments.path))
|
||||
cache[ref_file] = json_dump
|
||||
|
||||
ref_path_expr = "$" + ".".join(ref_frag.fragment.split("/"))
|
||||
path_expression = jsonpath_rw.parse(ref_path_expr)
|
||||
list_of_values = [match.value for match in path_expression.find(json_dump)]
|
||||
|
||||
if len(list_of_values) > 0:
|
||||
resolution = list_of_values[0]
|
||||
return resolution
|
||||
|
||||
resolved = self.resolve(value)
|
||||
if resolved is not None:
|
||||
json_obj[key] = resolved
|
||||
elif isinstance(json_obj, list):
|
||||
for (key, value) in enumerate(json_obj):
|
||||
resolved = self.resolve(value)
|
||||
if resolved is not None:
|
||||
json_obj[key] = resolved
|
||||
return None
|
||||
Reference in New Issue
Block a user