mirror of
https://github.com/syoyo/tinygltf.git
synced 2026-06-08 11:13:50 +00:00
Compare commits
117 Commits
draco
...
DingboDing
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
81d75df48a | ||
|
|
83ccb9f28d | ||
|
|
ff51570c26 | ||
|
|
a472a3fa0f | ||
|
|
1f160d5b8f | ||
|
|
5150a46072 | ||
|
|
cea69e37a5 | ||
|
|
8b56c016ab | ||
|
|
c7e205be87 | ||
|
|
6dba6c6aac | ||
|
|
6df800d2b6 | ||
|
|
2f044e77f1 | ||
|
|
af5a5ef026 | ||
|
|
6591ba4461 | ||
|
|
74c3c10121 | ||
|
|
ad63bf748b | ||
|
|
5d43cf8e64 | ||
|
|
4e2988eebd | ||
|
|
ee179b2cb6 | ||
|
|
4ebd6368fb | ||
|
|
67d3d2504d | ||
|
|
d9a468bbb4 | ||
|
|
c7bae71f7f | ||
|
|
f93642c196 | ||
|
|
f68d5e1f2a | ||
|
|
1c84fc22a5 | ||
|
|
150f243b1b | ||
|
|
0ee273fdfa | ||
|
|
046400b17f | ||
|
|
89fd93f815 | ||
|
|
e940337796 | ||
|
|
1b5f476d95 | ||
|
|
52936a00e0 | ||
|
|
f3ef880029 | ||
|
|
1af7c1d784 | ||
|
|
c0b79afecc | ||
|
|
c49461b7c2 | ||
|
|
051f4be2f1 | ||
|
|
4557b6aa22 | ||
|
|
b2d7d88dbc | ||
|
|
b7ca7c9381 | ||
|
|
0ffedcbe79 | ||
|
|
80faac5238 | ||
|
|
2a9d9deb67 | ||
|
|
8a98d98cd9 | ||
|
|
689edcbef6 | ||
|
|
820ede87db | ||
|
|
d6b0d0a61f | ||
|
|
5f180aaf74 | ||
|
|
dab0daaedf | ||
|
|
0ccc8dc262 | ||
|
|
811e1d3899 | ||
|
|
f65e06c5ca | ||
|
|
f29ae1a653 | ||
|
|
3bf16e4be5 | ||
|
|
fbc4295770 | ||
|
|
edf8d5cae1 | ||
|
|
b7f2473225 | ||
|
|
ed7bf66255 | ||
|
|
caa36dd050 | ||
|
|
389d5016ad | ||
|
|
d02ad0dede | ||
|
|
8f67121deb | ||
|
|
62be8d04cf | ||
|
|
d11a4c4d71 | ||
|
|
19b806e052 | ||
|
|
e0ab69cb31 | ||
|
|
8915252407 | ||
|
|
9446f65667 | ||
|
|
fb9f709166 | ||
|
|
a63cc6373d | ||
|
|
b3c1471317 | ||
|
|
9056aee823 | ||
|
|
29c431b2f2 | ||
|
|
d06b2c2022 | ||
|
|
339c9d578a | ||
|
|
7c315fa8a8 | ||
|
|
0f04ed018a | ||
|
|
ca56f726d6 | ||
|
|
e8a46c4e1d | ||
|
|
9cd14a461b | ||
|
|
1ef603ea2a | ||
|
|
14d259f361 | ||
|
|
9223d3133a | ||
|
|
9b321a8515 | ||
|
|
7e9f734d73 | ||
|
|
9d86405d3d | ||
|
|
1ccb4ff580 | ||
|
|
8fd91aea04 | ||
|
|
8f76d790b8 | ||
|
|
853f6df7b5 | ||
|
|
758a1240c9 | ||
|
|
7bdfed3bec | ||
|
|
bf9c2f4abd | ||
|
|
fc0116b323 | ||
|
|
962552c5c8 | ||
|
|
606e5dde31 | ||
|
|
6a0d4c57b1 | ||
|
|
f4b6d11abc | ||
|
|
5a4c898912 | ||
|
|
f2addc0e44 | ||
|
|
70d16a7b92 | ||
|
|
326d7ea310 | ||
|
|
eb011068c0 | ||
|
|
87be0ce34b | ||
|
|
7d9a0bda3a | ||
|
|
7ece5c8275 | ||
|
|
6bdffedcbe | ||
|
|
d2fb7dc2af | ||
|
|
c0d0251e2c | ||
|
|
62a72c4845 | ||
|
|
73584ba7b7 | ||
|
|
ead876fce9 | ||
|
|
6c4a006496 | ||
|
|
281af41b6c | ||
|
|
215e1fae61 | ||
|
|
cba75b9927 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -67,4 +67,5 @@ imgui.ini
|
||||
loader_example
|
||||
tests/tester
|
||||
tests/tester_noexcept
|
||||
tests/issue-97.gltf
|
||||
|
||||
|
||||
@@ -42,6 +42,10 @@ script:
|
||||
- ${CC} -v
|
||||
- ${CXX} ${EXTRA_CXXFLAGS} -std=c++11 -Wall -g -o loader_example loader_example.cc
|
||||
- ./loader_example ./models/Cube/Cube.gltf
|
||||
- cd examples/raytrace
|
||||
- cd tests
|
||||
- make
|
||||
- ./tester
|
||||
- ./tester_noexcept
|
||||
- cd ../examples/raytrace
|
||||
- ../../premake5 gmake
|
||||
- make
|
||||
|
||||
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
|
||||
|
||||
49
README.md
49
README.md
@@ -3,11 +3,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.
|
||||
If you are looking for old, C++03 version, please use `devel-picojson` branch.
|
||||
|
||||
## Status
|
||||
|
||||
v2.0.0 release(22 Aug, 2018)!
|
||||
- v2.3.0 Modified Material representation according to glTF 2.0 schema(and introduced TextureInfo class)
|
||||
- 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
|
||||
|
||||
@@ -38,17 +41,26 @@ v2.0.0 release(22 Aug, 2018)!
|
||||
* Image(Using stb_image)
|
||||
* [x] Parse BASE64 encoded embedded image data(DataURI).
|
||||
* [x] Load external image file.
|
||||
* [x] PNG(8bit only)
|
||||
* [x] JPEG(8bit only)
|
||||
* [x] BMP
|
||||
* [x] GIF
|
||||
* [x] Load PNG(8bit and 16bit)
|
||||
* [x] Load JPEG(8bit only)
|
||||
* [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
|
||||
* Extensions
|
||||
* [x] Draco mesh decoding
|
||||
|
||||
## Note on extension property
|
||||
|
||||
In extension(`ExtensionMap`), JSON number value is parsed as int or float(number) and stored as `tinygltf::Value` object. If you want a floating point value from `tinygltf::Value`, use `GetNumberAsDouble()` method.
|
||||
|
||||
`IsNumber()` returns true if the underlying value is an int value or a floating point value.
|
||||
|
||||
## Examples
|
||||
|
||||
* [glview](examples/glview) : Simple glTF geometry viewer.
|
||||
@@ -61,6 +73,7 @@ v2.0.0 release(22 Aug, 2018)!
|
||||
* Physical based rendering with Vulkan using glTF 2.0 models https://github.com/SaschaWillems/Vulkan-glTF-PBR
|
||||
* GLTF loader plugin for OGRE 2.1. Support for PBR materials via HLMS/PBS https://github.com/Ybalrid/Ogre_glTF
|
||||
* [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.
|
||||
* [Diligent Engine](https://github.com/DiligentGraphics/DiligentEngine) - A modern cross-platform low-level graphics library and rendering framework
|
||||
* Your projects here! (Please send PR)
|
||||
|
||||
## TODOs
|
||||
@@ -68,13 +81,13 @@ v2.0.0 release(22 Aug, 2018)!
|
||||
* [ ] 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
|
||||
* [ ] Support `extensions` and `extras` property
|
||||
* [ ] Save Draco compressed mesh
|
||||
* [ ] Open3DGC?
|
||||
* [x] Support `extensions` and `extras` property
|
||||
* [ ] HDR image?
|
||||
* [ ] OpenEXR extension through TinyEXR.
|
||||
* [ ] Write example and tests for `animation` and `skin`
|
||||
* [ ] Skinning
|
||||
* [ ] Morph targets
|
||||
* [ ] 16bit PNG support in Serialization
|
||||
* [ ] Write example and tests for `animation` and `skin`
|
||||
|
||||
## Licenses
|
||||
|
||||
@@ -104,13 +117,13 @@ Copy `stb_image.h`, `stb_image_write.h`, `json.hpp` and `tiny_gltf.h` to your pr
|
||||
|
||||
using namespace tinygltf;
|
||||
|
||||
Model model;
|
||||
Model model;
|
||||
TinyGLTF loader;
|
||||
std::string err;
|
||||
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)
|
||||
//bool ret = loader.LoadBinaryFromFile(&model, &err, &warn, argv[1]); // for binary glTF(.glb)
|
||||
|
||||
if (!warn.empty()) {
|
||||
printf("Warn: %s\n", warn.c_str());
|
||||
@@ -131,9 +144,13 @@ if (!ret) {
|
||||
* `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.
|
||||
|
||||
@@ -50,8 +50,9 @@ std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos,
|
||||
From spec2.0 readme:
|
||||
https://github.com/KhronosGroup/glTF/tree/master/specification/2.0
|
||||
... drawArrays function should be used with a count equal to
|
||||
the count property of any of the accessors referenced by the attributes
|
||||
property (they are all equal for a given primitive).
|
||||
the count property of any of the accessors referenced by the
|
||||
attributes property (they are all equal for a given
|
||||
primitive).
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -112,8 +113,29 @@ std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos,
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
|
||||
GLenum format = GL_RGBA;
|
||||
|
||||
if (image.component == 1) {
|
||||
format = GL_RED;
|
||||
} else if (image.component == 2) {
|
||||
format = GL_RG;
|
||||
} else if (image.component == 3) {
|
||||
format = GL_RGB;
|
||||
} else {
|
||||
// ???
|
||||
}
|
||||
|
||||
GLenum type = GL_UNSIGNED_BYTE;
|
||||
if (image.bits == 8) {
|
||||
// ok
|
||||
} else if (image.bits == 16) {
|
||||
type = GL_UNSIGNED_SHORT;
|
||||
} else {
|
||||
// ???
|
||||
}
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, &image.image.at(0));
|
||||
format, type, &image.image.at(0));
|
||||
}
|
||||
|
||||
return vbos;
|
||||
@@ -255,7 +277,7 @@ void displayLoop(Window &window, const std::string &filename) {
|
||||
glm::vec3 model_pos = glm::vec3(-3, 0, -3);
|
||||
|
||||
// generate a camera view, based on eye-position and lookAt world-position
|
||||
glm::mat4 view_mat = genView(glm::vec3(2, 2, 2), model_pos);
|
||||
glm::mat4 view_mat = genView(glm::vec3(2, 2, 20), model_pos);
|
||||
|
||||
glm::vec3 sun_position = glm::vec3(3.0, 10.0, -5.0);
|
||||
glm::vec3 sun_color = glm::vec3(1.0);
|
||||
@@ -287,6 +309,11 @@ void displayLoop(Window &window, const std::string &filename) {
|
||||
}
|
||||
}
|
||||
|
||||
static void error_callback(int error, const char *description) {
|
||||
(void)error;
|
||||
fprintf(stderr, "Error: %s\n", description);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
std::string filename = "../../models/Cube/Cube.gltf";
|
||||
|
||||
@@ -294,9 +321,12 @@ int main(int argc, char **argv) {
|
||||
filename = argv[1];
|
||||
}
|
||||
|
||||
glfwSetErrorCallback(error_callback);
|
||||
|
||||
if (!glfwInit()) return -1;
|
||||
|
||||
// Force create 3.3 profile.
|
||||
// Force create OpenGL 3.3
|
||||
// NOTE(syoyo): Linux + NVIDIA driver segfaults for some reason? commenting out glfwWindowHint will work.
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
|
||||
21
examples/common/LICENSE.lodepng
Normal file
21
examples/common/LICENSE.lodepng
Normal file
@@ -0,0 +1,21 @@
|
||||
Copyright (c) 2005-2018 Lode Vandevenne
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors 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 software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
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 software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
|
||||
5992
examples/common/lodepng.cpp
Normal file
5992
examples/common/lodepng.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1919
examples/common/lodepng.h
Normal file
1919
examples/common/lodepng.h
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -4,9 +4,10 @@ project(gltfutil)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
include_directories(../../)
|
||||
include_directories(../common/)
|
||||
|
||||
file(GLOB gltfutil_sources *.cc *.h)
|
||||
add_executable(gltfutil ${gltfutil_sources})
|
||||
add_executable(gltfutil ${gltfutil_sources} ../common/lodepng.cpp)
|
||||
|
||||
install ( TARGETS
|
||||
gltfutil
|
||||
|
||||
@@ -49,6 +49,7 @@ struct configuration {
|
||||
cli_action action = cli_action::not_set;
|
||||
texture_dumper::texture_output_format requested_format =
|
||||
texture_dumper::texture_output_format::not_specified;
|
||||
bool use_exr = false;
|
||||
|
||||
bool has_output_dir;
|
||||
bool is_valid() {
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include "stb_image_write.h"
|
||||
|
||||
#define TINYEXR_IMPLEMENTATION
|
||||
#include "tinyexr.h"
|
||||
|
||||
namespace gltfutil {
|
||||
int usage(int ret = 0) {
|
||||
using std::cout;
|
||||
@@ -20,8 +23,9 @@ int usage(int ret = 0) {
|
||||
"[path to output directory])\n\n"
|
||||
//<< "\t\t -i: start in interactive mode\n"
|
||||
<< "\t\t -d: dump enclosed content (image assets)\n"
|
||||
<< "\t\t -f: file format for image output"
|
||||
<< "\t\t -o: ouptput directory path"
|
||||
<< "\t\t -f: file format for image output\n"
|
||||
<< "\t\t -o: ouptput directory path\n"
|
||||
<< "\t\t -e: Use OpenEXR format for 16bit image\n"
|
||||
<< "\t\t -h: print this help\n";
|
||||
return ret;
|
||||
}
|
||||
@@ -44,6 +48,9 @@ int parse_args(int argc, char** argv) {
|
||||
config.mode = ui_mode::cli;
|
||||
config.action = cli_action::dump;
|
||||
break;
|
||||
case 'e':
|
||||
config.use_exr = true;
|
||||
break;
|
||||
case 'i':
|
||||
config.mode = ui_mode::interactive;
|
||||
break;
|
||||
@@ -97,6 +104,11 @@ int parse_args(int argc, char** argv) {
|
||||
|
||||
case cli_action::dump: {
|
||||
texture_dumper dumper(model);
|
||||
|
||||
if (config.use_exr) {
|
||||
dumper.set_use_exr(true);
|
||||
}
|
||||
|
||||
if (config.requested_format !=
|
||||
texture_dumper::texture_output_format::not_specified)
|
||||
dumper.set_output_format(config.requested_format);
|
||||
|
||||
@@ -1,15 +1,84 @@
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
#include "stb_image_write.h"
|
||||
#include "texture_dumper.h"
|
||||
|
||||
#include "lodepng.h" // ../common
|
||||
|
||||
#include "tinyexr.h"
|
||||
|
||||
#include <tiny_gltf.h>
|
||||
|
||||
using namespace gltfutil;
|
||||
using namespace tinygltf;
|
||||
using std::cout;
|
||||
|
||||
static LodePNGColorType GetLodePNGColorType(int channels) {
|
||||
if (channels == 1) {
|
||||
return LodePNGColorType::LCT_GREY;
|
||||
} else if (channels == 2) {
|
||||
return LodePNGColorType::LCT_GREY_ALPHA;
|
||||
} else if (channels == 3) {
|
||||
return LodePNGColorType::LCT_RGB;
|
||||
} else if (channels == 4) {
|
||||
return LodePNGColorType::LCT_RGBA;
|
||||
} else {
|
||||
std::cerr << "??? unsupported channels " << channels << "\n";
|
||||
return LodePNGColorType::LCT_RGB; // FIXME(syoyo): Raise error
|
||||
}
|
||||
}
|
||||
|
||||
static void ToBigEndian(std::vector<uint8_t>* image) {
|
||||
|
||||
assert(image->size() % 2 == 0);
|
||||
|
||||
union {
|
||||
unsigned int i;
|
||||
char c[4];
|
||||
} bint = {0x01020304};
|
||||
|
||||
bool is_big_endian = (bint.c[0] == 1);
|
||||
|
||||
if (is_big_endian) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t *ptr = reinterpret_cast<uint16_t *>(image->data());
|
||||
size_t n = image->size() / 2;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
ptr[i] = ((0xFF00 & ptr[i]) >> 8) | ((0x00FF & ptr[i]) << 8);
|
||||
}
|
||||
}
|
||||
|
||||
static bool Save16bitImageAsEXR(const std::string& filename,
|
||||
const tinygltf::Image& image) {
|
||||
assert(image.bits == 16);
|
||||
|
||||
std::vector<float> buf(image.width * image.height * image.component);
|
||||
|
||||
// widen to float image.
|
||||
// Store as is(i.e, pixel value range is [0.0, 65535.0])
|
||||
const unsigned short* ptr =
|
||||
reinterpret_cast<const unsigned short*>(image.image.data());
|
||||
for (size_t i = 0; i < image.width * image.height * image.component; i++) {
|
||||
buf[i] = float(ptr[i]);
|
||||
}
|
||||
|
||||
const char* err = nullptr;
|
||||
int ret = SaveEXR(buf.data(), image.width, image.height, image.component,
|
||||
/* save_as_fp16 */ 0, filename.c_str(), &err);
|
||||
|
||||
if (err) {
|
||||
std::cerr << "EXR err: " << err << std::endl;
|
||||
FreeEXRErrorMessage(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
return (ret == TINYEXR_SUCCESS);
|
||||
}
|
||||
|
||||
texture_dumper::texture_dumper(const Model& input)
|
||||
: model(input), configured_format(texture_output_format::png) {
|
||||
cout << "Texture dumper\n";
|
||||
@@ -26,26 +95,58 @@ void texture_dumper::dump_to_folder(const std::string& path) {
|
||||
cout << "image name is: \"" << image.name << "\"\n";
|
||||
cout << "image size is: " << image.width << 'x' << image.height << '\n';
|
||||
cout << "pixel channel count :" << image.component << '\n';
|
||||
std::string name = image.name.empty() ? std::to_string(index) : image.name;
|
||||
cout << "pixel bit depth :" << image.bits << '\n';
|
||||
std::string basename =
|
||||
image.name.empty() ? std::to_string(index) : image.name;
|
||||
|
||||
unsigned char* bytes_to_write =
|
||||
const_cast<unsigned char*>(image.image.data());
|
||||
|
||||
std::string filename;
|
||||
switch (configured_format) {
|
||||
case texture_output_format::png:
|
||||
name = path + "/" + name + ".png";
|
||||
std::cout << "Image will be written to " << name << '\n';
|
||||
stbi_write_png(name.c_str(), image.width, image.height, image.component,
|
||||
image.image.data(), 0);
|
||||
filename = path + "/" + basename + ".png";
|
||||
|
||||
if (this->use_exr) {
|
||||
if (image.pixel_type == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
|
||||
filename = path + "/" + basename + ".exr";
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Image will be written to " << filename << '\n';
|
||||
|
||||
if (image.pixel_type == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
|
||||
if (this->use_exr) {
|
||||
bool ret = Save16bitImageAsEXR(filename, image);
|
||||
assert(ret);
|
||||
} else {
|
||||
// Use lodepng to save 16bit PNG.
|
||||
// NOTE(syoyo): `loadpng::encode` requires image data must be stored in big endian.
|
||||
std::vector<uint8_t> tmp = image.image; // copy
|
||||
ToBigEndian(&tmp);
|
||||
|
||||
unsigned ret = lodepng::encode(
|
||||
filename, tmp.data(), image.width, image.height,
|
||||
GetLodePNGColorType(image.component), /* bits */ 16);
|
||||
assert(ret == 0); // 0 = no err.
|
||||
}
|
||||
} else {
|
||||
// TODO(syoyo): check status
|
||||
stbi_write_png(filename.c_str(), image.width, image.height,
|
||||
image.component, bytes_to_write, 0);
|
||||
}
|
||||
break;
|
||||
case texture_output_format::bmp:
|
||||
std::cout << "Image will be written to " << name << '\n';
|
||||
name = path + "/" + name + ".bmp";
|
||||
stbi_write_bmp(name.c_str(), image.width, image.height, image.component,
|
||||
image.image.data());
|
||||
filename = path + "/" + basename + ".bmp";
|
||||
std::cout << "Image will be written to " << filename << '\n';
|
||||
stbi_write_bmp(filename.c_str(), image.width, image.height,
|
||||
image.component, bytes_to_write);
|
||||
break;
|
||||
case texture_output_format::tga:
|
||||
std::cout << "Image will be written to " << name << '\n';
|
||||
name = path + "/" + name + ".tga";
|
||||
stbi_write_tga(name.c_str(), image.width, image.height, image.component,
|
||||
image.image.data());
|
||||
filename = path + "/" + basename + ".tga";
|
||||
std::cout << "Image will be written to " << filename << '\n';
|
||||
stbi_write_tga(filename.c_str(), image.width, image.height,
|
||||
image.component, bytes_to_write);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,15 @@ class texture_dumper {
|
||||
private:
|
||||
const tinygltf::Model& model;
|
||||
texture_output_format configured_format;
|
||||
bool use_exr = false; // Use EXR for 16bit image?
|
||||
|
||||
public:
|
||||
texture_dumper(const tinygltf::Model& inputModel);
|
||||
void dump_to_folder(const std::string& path = "./");
|
||||
void set_output_format(texture_output_format format);
|
||||
void set_use_exr(const bool value) {
|
||||
use_exr = value;
|
||||
}
|
||||
|
||||
static texture_output_format get_fromat_from_string(const std::string& str);
|
||||
};
|
||||
|
||||
@@ -23,15 +23,17 @@ endif (APPLE)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
if (${DRACO_DIR} STREQUAL "")
|
||||
else ()
|
||||
# TODO(syoyo): better CMake script for draco
|
||||
add_definitions(-DTINYGLTF_ENABLE_DRACO)
|
||||
include_directories(${DRACO_DIR}/include)
|
||||
|
||||
link_directories(${DRACO_DIR}/lib)
|
||||
set(DRACO_LIBRARY draco)
|
||||
endif ()
|
||||
if (DEFINED DRACO_DIR)
|
||||
if (DRACO_DIR STREQUAL "")
|
||||
else ()
|
||||
# TODO(syoyo): better CMake script for draco
|
||||
add_definitions(-DTINYGLTF_ENABLE_DRACO)
|
||||
include_directories(${DRACO_DIR}/include)
|
||||
|
||||
link_directories(${DRACO_DIR}/lib)
|
||||
set(DRACO_LIBRARY draco)
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
include_directories(
|
||||
../../
|
||||
|
||||
@@ -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,18 +818,19 @@ 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
|
||||
|
||||
// TODO(syoyo): Support non-default scenes.
|
||||
assert(model.defaultScene >= 0);
|
||||
const tinygltf::Scene &scene = model.scenes[model.defaultScene];
|
||||
// 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];
|
||||
for (size_t i = 0; i < scene.nodes.size(); i++) {
|
||||
DrawNode(model, model.nodes[scene.nodes[i]]);
|
||||
}
|
||||
@@ -751,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");
|
||||
@@ -762,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());
|
||||
@@ -783,7 +911,7 @@ int main(int argc, char **argv) {
|
||||
Init();
|
||||
|
||||
// DBG
|
||||
PrintNodes(model.scenes[model.defaultScene]);
|
||||
PrintNodes(model.scenes[model.defaultScene > -1 ? model.defaultScene : 0]);
|
||||
|
||||
if (!glfwInit()) {
|
||||
std::cerr << "Failed to initialize GLFW." << std::endl;
|
||||
@@ -824,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;
|
||||
}
|
||||
|
||||
@@ -175,7 +175,10 @@ static std::string PrintIntArray(const std::vector<int> &arr) {
|
||||
std::stringstream ss;
|
||||
ss << "[ ";
|
||||
for (size_t i = 0; i < arr.size(); i++) {
|
||||
ss << arr[i] << ((i != arr.size() - 1) ? ", " : "");
|
||||
ss << arr[i];
|
||||
if (i != arr.size() - 1) {
|
||||
ss << ", ";
|
||||
}
|
||||
}
|
||||
ss << " ]";
|
||||
|
||||
@@ -190,7 +193,10 @@ static std::string PrintFloatArray(const std::vector<double> &arr) {
|
||||
std::stringstream ss;
|
||||
ss << "[ ";
|
||||
for (size_t i = 0; i < arr.size(); i++) {
|
||||
ss << arr[i] << ((i != arr.size() - 1) ? ", " : "");
|
||||
ss << arr[i];
|
||||
if (i != arr.size() - 1) {
|
||||
ss << ", ";
|
||||
}
|
||||
}
|
||||
ss << " ]";
|
||||
|
||||
@@ -228,7 +234,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()) {
|
||||
@@ -242,36 +249,36 @@ static std::string PrintValue(const std::string &name,
|
||||
if (tag) {
|
||||
ss << Indent(indent) << name << " : " << value.Get<std::string>();
|
||||
} else {
|
||||
ss << " " << value.Get<std::string>() << " ";
|
||||
ss << Indent(indent) << value.Get<std::string>() << " ";
|
||||
}
|
||||
} else if (value.IsBool()) {
|
||||
if (tag) {
|
||||
ss << Indent(indent) << name << " : " << value.Get<bool>();
|
||||
} else {
|
||||
ss << " " << value.Get<bool>() << " ";
|
||||
ss << Indent(indent) << value.Get<bool>() << " ";
|
||||
}
|
||||
} else if (value.IsNumber()) {
|
||||
if (tag) {
|
||||
ss << Indent(indent) << name << " : " << value.Get<double>();
|
||||
} else {
|
||||
ss << " " << value.Get<double>() << " ";
|
||||
ss << Indent(indent) << value.Get<double>() << " ";
|
||||
}
|
||||
} else if (value.IsInt()) {
|
||||
if (tag) {
|
||||
ss << Indent(indent) << name << " : " << value.Get<int>();
|
||||
} else {
|
||||
ss << " " << value.Get<int>() << " ";
|
||||
ss << Indent(indent) << value.Get<int>() << " ";
|
||||
}
|
||||
} else if (value.IsArray()) {
|
||||
ss << Indent(indent) << name << " [ ";
|
||||
// TODO(syoyo): Better pretty printing of array item
|
||||
ss << Indent(indent) << name << " [ \n";
|
||||
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 << ", ";
|
||||
ss << PrintValue("", value.Get(int(i)), indent + 1, /* tag */ false);
|
||||
if (i != (value.ArrayLen() - 1)) {
|
||||
ss << ", \n";
|
||||
}
|
||||
|
||||
}
|
||||
ss << Indent(indent) << "] ";
|
||||
ss << "\n" << Indent(indent) << "] ";
|
||||
}
|
||||
|
||||
// @todo { binary }
|
||||
@@ -330,13 +337,61 @@ 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 DumpTextureInfo(const tinygltf::TextureInfo &texinfo,
|
||||
const int indent) {
|
||||
std::cout << Indent(indent) << "index : " << texinfo.index << "\n";
|
||||
std::cout << Indent(indent) << "texCoord : TEXCOORD_" << texinfo.texCoord
|
||||
<< "\n";
|
||||
DumpExtensions(texinfo.extensions, indent + 1);
|
||||
std::cout << PrintValue("extras", texinfo.extras, indent + 1) << "\n";
|
||||
}
|
||||
|
||||
static void DumpNormalTextureInfo(const tinygltf::NormalTextureInfo &texinfo,
|
||||
const int indent) {
|
||||
std::cout << Indent(indent) << "index : " << texinfo.index << "\n";
|
||||
std::cout << Indent(indent) << "texCoord : TEXCOORD_" << texinfo.texCoord
|
||||
<< "\n";
|
||||
std::cout << Indent(indent) << "scale : " << texinfo.scale << "\n";
|
||||
DumpExtensions(texinfo.extensions, indent + 1);
|
||||
std::cout << PrintValue("extras", texinfo.extras, indent + 1) << "\n";
|
||||
}
|
||||
|
||||
static void DumpOcclusionTextureInfo(
|
||||
const tinygltf::OcclusionTextureInfo &texinfo, const int indent) {
|
||||
std::cout << Indent(indent) << "index : " << texinfo.index << "\n";
|
||||
std::cout << Indent(indent) << "texCoord : TEXCOORD_" << texinfo.texCoord
|
||||
<< "\n";
|
||||
std::cout << Indent(indent) << "strength : " << texinfo.strength << "\n";
|
||||
DumpExtensions(texinfo.extensions, indent + 1);
|
||||
std::cout << PrintValue("extras", texinfo.extras, indent + 1) << "\n";
|
||||
}
|
||||
|
||||
static void DumpPbrMetallicRoughness(const tinygltf::PbrMetallicRoughness &pbr,
|
||||
const int indent) {
|
||||
std::cout << Indent(indent)
|
||||
<< "baseColorFactor : " << PrintFloatArray(pbr.baseColorFactor)
|
||||
<< "\n";
|
||||
std::cout << Indent(indent) << "baseColorTexture :\n";
|
||||
DumpTextureInfo(pbr.baseColorTexture, indent + 1);
|
||||
|
||||
std::cout << Indent(indent) << "metallicFactor : " << pbr.metallicFactor
|
||||
<< "\n";
|
||||
std::cout << Indent(indent) << "roughnessFactor : " << pbr.roughnessFactor
|
||||
<< "\n";
|
||||
|
||||
std::cout << Indent(indent) << "metallicRoughnessTexture :\n";
|
||||
DumpTextureInfo(pbr.metallicRoughnessTexture, indent + 1);
|
||||
DumpExtensions(pbr.extensions, indent + 1);
|
||||
std::cout << PrintValue("extras", pbr.extras, indent + 1) << "\n";
|
||||
}
|
||||
|
||||
static void Dump(const tinygltf::Model &model) {
|
||||
@@ -409,6 +464,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -485,16 +564,44 @@ static void Dump(const tinygltf::Model &model) {
|
||||
<< std::endl;
|
||||
for (size_t i = 0; i < model.materials.size(); i++) {
|
||||
const tinygltf::Material &material = model.materials[i];
|
||||
std::cout << Indent(1) << "name : " << material.name << std::endl;
|
||||
std::cout << Indent(1) << "values(items=" << material.values.size() << ")"
|
||||
std::cout << Indent(1) << "name : " << material.name
|
||||
<< std::endl;
|
||||
|
||||
std::cout << Indent(1) << "alphaMode : " << material.alphaMode
|
||||
<< std::endl;
|
||||
std::cout << Indent(1)
|
||||
<< "alphaCutoff : " << material.alphaCutoff
|
||||
<< std::endl;
|
||||
std::cout << Indent(1) << "doubleSided : "
|
||||
<< (material.doubleSided ? "true" : "false") << std::endl;
|
||||
std::cout << Indent(1) << "emissiveFactor : "
|
||||
<< PrintFloatArray(material.emissiveFactor) << std::endl;
|
||||
|
||||
std::cout << Indent(1) << "pbrMetallicRoughness :\n";
|
||||
DumpPbrMetallicRoughness(material.pbrMetallicRoughness, 2);
|
||||
|
||||
std::cout << Indent(1) << "normalTexture :\n";
|
||||
DumpNormalTextureInfo(material.normalTexture, 2);
|
||||
|
||||
std::cout << Indent(1) << "occlusionTexture :\n";
|
||||
DumpOcclusionTextureInfo(material.occlusionTexture, 2);
|
||||
|
||||
std::cout << Indent(1) << "emissiveTexture :\n";
|
||||
DumpTextureInfo(material.emissiveTexture, 2);
|
||||
|
||||
std::cout << Indent(1) << "---- legacy material parameter ----\n";
|
||||
std::cout << Indent(1) << "values(items=" << material.values.size() << ")"
|
||||
<< std::endl;
|
||||
tinygltf::ParameterMap::const_iterator p(material.values.begin());
|
||||
tinygltf::ParameterMap::const_iterator pEnd(material.values.end());
|
||||
for (; p != pEnd; p++) {
|
||||
std::cout << Indent(2) << p->first << ": "
|
||||
<< PrintParameterValue(p->second) << std::endl;
|
||||
}
|
||||
std::cout << Indent(1) << "-------------------------------------\n";
|
||||
|
||||
DumpExtensions(material.extensions, 1);
|
||||
std::cout << PrintValue("extras", material.extras, 2) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -585,10 +692,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 +710,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 +718,19 @@ 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());
|
||||
ret =
|
||||
gltf_ctx.LoadASCIIFromFile(&model, &err, &warn, input_filename.c_str());
|
||||
}
|
||||
|
||||
if (!warn.empty()) {
|
||||
printf("Warn: %s\n", warn.c_str());
|
||||
}
|
||||
|
||||
|
||||
if (!err.empty()) {
|
||||
printf("Err: %s\n", err.c_str());
|
||||
}
|
||||
|
||||
67
models/BoundsChecking/integer-out-of-bounds.gltf
Normal file
67
models/BoundsChecking/integer-out-of-bounds.gltf
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"scenes": [
|
||||
{
|
||||
"nodes": [0]
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"mesh": 0
|
||||
}
|
||||
],
|
||||
"meshes": [
|
||||
{
|
||||
"primitives": [
|
||||
{
|
||||
"attributes": {
|
||||
"POSITION": 1
|
||||
},
|
||||
"indices": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"buffers": [
|
||||
{
|
||||
"uri": "simpleTriangle.bin",
|
||||
"byteLength": 44
|
||||
}
|
||||
],
|
||||
"bufferViews": [
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 0,
|
||||
"byteLength": 1e300,
|
||||
"target": 34963
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 8,
|
||||
"byteLength": 36,
|
||||
"target": 34962
|
||||
}
|
||||
],
|
||||
"accessors": [
|
||||
{
|
||||
"bufferView": 0,
|
||||
"byteOffset": 0,
|
||||
"componentType": 5123,
|
||||
"count": 3,
|
||||
"type": "SCALAR",
|
||||
"max": [2],
|
||||
"min": [0]
|
||||
},
|
||||
{
|
||||
"bufferView": 1,
|
||||
"byteOffset": 0,
|
||||
"componentType": 5126,
|
||||
"count": 3,
|
||||
"type": "VEC3",
|
||||
"max": [1, 1, 0],
|
||||
"min": [0, 0, 0]
|
||||
}
|
||||
],
|
||||
"asset": {
|
||||
"version": "2.0"
|
||||
}
|
||||
}
|
||||
53
models/BoundsChecking/invalid-buffer-index.gltf
Normal file
53
models/BoundsChecking/invalid-buffer-index.gltf
Normal file
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"scenes": [],
|
||||
"nodes": [],
|
||||
"meshes": [
|
||||
{
|
||||
"primitives": [
|
||||
{
|
||||
"attributes": {},
|
||||
"indices": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"buffers": [
|
||||
{
|
||||
"uri": "simpleTriangle.bin",
|
||||
"byteLength": 44
|
||||
}
|
||||
],
|
||||
"bufferViews": [
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 0,
|
||||
"byteLength": 6,
|
||||
"target": 34963
|
||||
},
|
||||
{
|
||||
"buffer": 1,
|
||||
"byteOffset": 0,
|
||||
"byteLength": 6,
|
||||
"target": 34963
|
||||
}
|
||||
],
|
||||
"images": [
|
||||
{
|
||||
"bufferView": 1,
|
||||
"mimeType": "image/png"
|
||||
}
|
||||
],
|
||||
"accessors": [
|
||||
{
|
||||
"bufferView": 0,
|
||||
"componentType": 5123,
|
||||
"count": 3,
|
||||
"type": "SCALAR",
|
||||
"max": [2],
|
||||
"min": [0]
|
||||
}
|
||||
],
|
||||
"asset": {
|
||||
"version": "2.0"
|
||||
}
|
||||
}
|
||||
36
models/BoundsChecking/invalid-buffer-view-index.gltf
Normal file
36
models/BoundsChecking/invalid-buffer-view-index.gltf
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"scenes": [],
|
||||
"nodes": [],
|
||||
"buffers": [],
|
||||
"meshes": [
|
||||
{
|
||||
"primitives": [
|
||||
{
|
||||
"attributes": {},
|
||||
"indices": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"bufferViews": [
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 0,
|
||||
"byteLength": 6,
|
||||
"target": 34963
|
||||
}
|
||||
],
|
||||
"accessors": [
|
||||
{
|
||||
"bufferView": 1,
|
||||
"componentType": 5123,
|
||||
"count": 3,
|
||||
"type": "SCALAR",
|
||||
"max": [2],
|
||||
"min": [0]
|
||||
}
|
||||
],
|
||||
"asset": {
|
||||
"version": "2.0"
|
||||
}
|
||||
}
|
||||
36
models/BoundsChecking/invalid-primitive-indices.gltf
Normal file
36
models/BoundsChecking/invalid-primitive-indices.gltf
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"scenes": [],
|
||||
"nodes": [],
|
||||
"buffers": [],
|
||||
"meshes": [
|
||||
{
|
||||
"primitives": [
|
||||
{
|
||||
"attributes": {},
|
||||
"indices": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"bufferViews": [
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 0,
|
||||
"byteLength": 6,
|
||||
"target": 34963
|
||||
}
|
||||
],
|
||||
"accessors": [
|
||||
{
|
||||
"bufferView": 1,
|
||||
"componentType": 5123,
|
||||
"count": 3,
|
||||
"type": "SCALAR",
|
||||
"max": [2],
|
||||
"min": [0]
|
||||
}
|
||||
],
|
||||
"asset": {
|
||||
"version": "2.0"
|
||||
}
|
||||
}
|
||||
BIN
models/BoundsChecking/simpleTriangle.bin
Normal file
BIN
models/BoundsChecking/simpleTriangle.bin
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 44 B |
224
models/Cube-texture-ext/Cube-textransform.gltf
Normal file
224
models/Cube-texture-ext/Cube-textransform.gltf
Normal file
@@ -0,0 +1,224 @@
|
||||
{
|
||||
"accessors": [
|
||||
{
|
||||
"bufferView": 0,
|
||||
"byteOffset": 0,
|
||||
"componentType": 5123,
|
||||
"count": 36,
|
||||
"max": [
|
||||
35
|
||||
],
|
||||
"min": [
|
||||
0
|
||||
],
|
||||
"type": "SCALAR"
|
||||
},
|
||||
{
|
||||
"bufferView": 1,
|
||||
"byteOffset": 0,
|
||||
"componentType": 5126,
|
||||
"count": 36,
|
||||
"max": [
|
||||
1,
|
||||
1,
|
||||
1.000001
|
||||
],
|
||||
"min": [
|
||||
-1,
|
||||
-1,
|
||||
-1
|
||||
],
|
||||
"type": "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView": 2,
|
||||
"byteOffset": 0,
|
||||
"componentType": 5126,
|
||||
"count": 36,
|
||||
"max": [
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"min": [
|
||||
-1,
|
||||
-1,
|
||||
-1
|
||||
],
|
||||
"type": "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView": 3,
|
||||
"byteOffset": 0,
|
||||
"componentType": 5126,
|
||||
"count": 36,
|
||||
"max": [
|
||||
1,
|
||||
-0,
|
||||
-0,
|
||||
1
|
||||
],
|
||||
"min": [
|
||||
0,
|
||||
-0,
|
||||
-1,
|
||||
-1
|
||||
],
|
||||
"type": "VEC4"
|
||||
},
|
||||
{
|
||||
"bufferView": 4,
|
||||
"byteOffset": 0,
|
||||
"componentType": 5126,
|
||||
"count": 36,
|
||||
"max": [
|
||||
1,
|
||||
1
|
||||
],
|
||||
"min": [
|
||||
-1,
|
||||
-1
|
||||
],
|
||||
"type": "VEC2"
|
||||
}
|
||||
],
|
||||
"asset": {
|
||||
"generator": "VKTS glTF 2.0 exporter",
|
||||
"version": "2.0"
|
||||
},
|
||||
"bufferViews": [
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteLength": 72,
|
||||
"byteOffset": 0,
|
||||
"target": 34963
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteLength": 432,
|
||||
"byteOffset": 72,
|
||||
"target": 34962
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteLength": 432,
|
||||
"byteOffset": 504,
|
||||
"target": 34962
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteLength": 576,
|
||||
"byteOffset": 936,
|
||||
"target": 34962
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteLength": 288,
|
||||
"byteOffset": 1512,
|
||||
"target": 34962
|
||||
}
|
||||
],
|
||||
"buffers": [
|
||||
{
|
||||
"byteLength": 1800,
|
||||
"uri": "Cube.bin"
|
||||
}
|
||||
],
|
||||
"images": [
|
||||
{
|
||||
"0comment": "Use Cube_MetallicRoughness.png to reduce scene filesize",
|
||||
"uri": "Cube_MetallicRoughness.png"
|
||||
},
|
||||
{
|
||||
"uri": "Cube_MetallicRoughness.png"
|
||||
}
|
||||
],
|
||||
"materials": [
|
||||
{
|
||||
"emissiveTexture": {
|
||||
"index": 0,
|
||||
"extensions": {
|
||||
"KHR_texture_transform": {
|
||||
"offset": [
|
||||
0,
|
||||
1
|
||||
],
|
||||
"scale": [
|
||||
1,
|
||||
-1
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Cube",
|
||||
"pbrMetallicRoughness": {
|
||||
"baseColorTexture": {
|
||||
"index": 0
|
||||
},
|
||||
"metallicRoughnessTexture": {
|
||||
"index": 1,
|
||||
"extensions": {
|
||||
"KHR_texture_transform": {
|
||||
"offset": [
|
||||
0,
|
||||
1
|
||||
],
|
||||
"rotation": 1.57079632679,
|
||||
"scale": [
|
||||
0.5,
|
||||
0.5
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"meshes": [
|
||||
{
|
||||
"name": "Cube",
|
||||
"primitives": [
|
||||
{
|
||||
"attributes": {
|
||||
"NORMAL": 2,
|
||||
"POSITION": 1,
|
||||
"TANGENT": 3,
|
||||
"TEXCOORD_0": 4
|
||||
},
|
||||
"indices": 0,
|
||||
"material": 0,
|
||||
"mode": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"mesh": 0,
|
||||
"name": "Cube"
|
||||
}
|
||||
],
|
||||
"samplers": [
|
||||
{}
|
||||
],
|
||||
"scene": 0,
|
||||
"scenes": [
|
||||
{
|
||||
"nodes": [
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"textures": [
|
||||
{
|
||||
"sampler": 0,
|
||||
"source": 0
|
||||
},
|
||||
{
|
||||
"sampler": 0,
|
||||
"source": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
models/Cube-texture-ext/Cube.bin
Normal file
BIN
models/Cube-texture-ext/Cube.bin
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
BIN
models/Cube-texture-ext/Cube_MetallicRoughness.png
Normal file
BIN
models/Cube-texture-ext/Cube_MetallicRoughness.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 319 B |
6
models/Cube-texture-ext/README.md
Normal file
6
models/Cube-texture-ext/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
Added KHR_texture_transform property to Cube scene.
|
||||
|
||||
License: Donated by Norbert Nopper for glTF testing.
|
||||
|
||||
https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Cube
|
||||
|
||||
2753
stb_image.h
2753
stb_image.h
File diff suppressed because it is too large
Load Diff
2632
stb_image_write.h
2632
stb_image_write.h
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"]
|
||||
# ---------------------------------
|
||||
|
||||
|
||||
233
tests/tester.cc
233
tests/tester.cc
@@ -37,7 +37,7 @@ TEST_CASE("datauri-in-glb", "[issue-79]") {
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
|
||||
|
||||
REQUIRE(true == ret);
|
||||
}
|
||||
|
||||
@@ -82,7 +82,236 @@ TEST_CASE("extension-with-empty-object", "[issue-97]") {
|
||||
REQUIRE(m.materials[0].extensions.size() == 1);
|
||||
REQUIRE(m.materials[0].extensions.count("VENDOR_material_some_ext") == 1);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("invalid-primitive-indices", "[bounds-checking]") {
|
||||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTF ctx;
|
||||
std::string err;
|
||||
std::string warn;
|
||||
|
||||
// Loading is expected to fail, but not crash.
|
||||
bool ret = ctx.LoadASCIIFromFile(
|
||||
&model, &err, &warn,
|
||||
"../models/BoundsChecking/invalid-primitive-indices.gltf");
|
||||
REQUIRE_THAT(err,
|
||||
Catch::Contains("primitive indices accessor out of bounds"));
|
||||
REQUIRE_FALSE(ret);
|
||||
}
|
||||
|
||||
TEST_CASE("invalid-buffer-view-index", "[bounds-checking]") {
|
||||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTF ctx;
|
||||
std::string err;
|
||||
std::string warn;
|
||||
|
||||
// Loading is expected to fail, but not crash.
|
||||
bool ret = ctx.LoadASCIIFromFile(
|
||||
&model, &err, &warn,
|
||||
"../models/BoundsChecking/invalid-buffer-view-index.gltf");
|
||||
REQUIRE_THAT(err, Catch::Contains("accessor[0] invalid bufferView"));
|
||||
REQUIRE_FALSE(ret);
|
||||
}
|
||||
|
||||
TEST_CASE("invalid-buffer-index", "[bounds-checking]") {
|
||||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTF ctx;
|
||||
std::string err;
|
||||
std::string warn;
|
||||
|
||||
// Loading is expected to fail, but not crash.
|
||||
bool ret = ctx.LoadASCIIFromFile(
|
||||
&model, &err, &warn,
|
||||
"../models/BoundsChecking/invalid-buffer-index.gltf");
|
||||
REQUIRE_THAT(
|
||||
err, Catch::Contains("image[0] buffer \"1\" not found in the scene."));
|
||||
REQUIRE_FALSE(ret);
|
||||
}
|
||||
|
||||
TEST_CASE("glb-invalid-length", "[bounds-checking]") {
|
||||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTF ctx;
|
||||
std::string err;
|
||||
std::string warn;
|
||||
|
||||
// This glb has a much longer length than the provided data and should fail
|
||||
// initial range checks.
|
||||
const unsigned char glb_invalid_length[] = "glTF"
|
||||
"\x20\x00\x00\x00" "\x6c\x66\x00\x00" //
|
||||
// | version | length |
|
||||
"\x02\x00\x00\x00" "\x4a\x53\x4f\x4e{}"; //
|
||||
// | model length | model format |
|
||||
|
||||
bool ret = ctx.LoadBinaryFromMemory(&model, &err, &warn, glb_invalid_length,
|
||||
sizeof(glb_invalid_length));
|
||||
REQUIRE_THAT(err, Catch::Contains("Invalid glTF binary."));
|
||||
REQUIRE_FALSE(ret);
|
||||
}
|
||||
|
||||
TEST_CASE("integer-out-of-bounds", "[bounds-checking]") {
|
||||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTF ctx;
|
||||
std::string err;
|
||||
std::string warn;
|
||||
|
||||
// Loading is expected to fail, but not crash.
|
||||
bool ret = ctx.LoadASCIIFromFile(
|
||||
&model, &err, &warn,
|
||||
"../models/BoundsChecking/integer-out-of-bounds.gltf");
|
||||
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
|
||||
REQUIRE_FALSE(ret);
|
||||
}
|
||||
|
||||
TEST_CASE("parse-integer", "[bounds-checking]") {
|
||||
SECTION("parses valid numbers") {
|
||||
std::string err;
|
||||
int result = 123;
|
||||
CHECK(tinygltf::ParseIntegerProperty(&result, &err, {{"zero", 0}}, "zero",
|
||||
true));
|
||||
REQUIRE(err == "");
|
||||
REQUIRE(result == 0);
|
||||
|
||||
CHECK(tinygltf::ParseIntegerProperty(&result, &err, {{"int", -1234}}, "int",
|
||||
true));
|
||||
REQUIRE(err == "");
|
||||
REQUIRE(result == -1234);
|
||||
}
|
||||
|
||||
SECTION("detects missing properties") {
|
||||
std::string err;
|
||||
int result = -1;
|
||||
CHECK_FALSE(tinygltf::ParseIntegerProperty(&result, &err, {}, "int", true));
|
||||
REQUIRE_THAT(err, Catch::Contains("'int' property is missing"));
|
||||
REQUIRE(result == -1);
|
||||
}
|
||||
|
||||
SECTION("handled missing but not required properties") {
|
||||
std::string err;
|
||||
int result = -1;
|
||||
CHECK_FALSE(
|
||||
tinygltf::ParseIntegerProperty(&result, &err, {}, "int", false));
|
||||
REQUIRE(err == "");
|
||||
REQUIRE(result == -1);
|
||||
}
|
||||
|
||||
SECTION("invalid integers") {
|
||||
std::string err;
|
||||
int result = -1;
|
||||
|
||||
CHECK_FALSE(tinygltf::ParseIntegerProperty(&result, &err, {{"int", 0.5}},
|
||||
"int", true));
|
||||
REQUIRE_THAT(err, Catch::Contains("not an integer type"));
|
||||
|
||||
// Excessively large values and NaN aren't allowed either.
|
||||
err.clear();
|
||||
CHECK_FALSE(tinygltf::ParseIntegerProperty(&result, &err, {{"int", 1e300}},
|
||||
"int", true));
|
||||
REQUIRE_THAT(err, Catch::Contains("not an integer type"));
|
||||
|
||||
err.clear();
|
||||
CHECK_FALSE(tinygltf::ParseIntegerProperty(
|
||||
&result, &err, {{"int", std::numeric_limits<double>::quiet_NaN()}},
|
||||
"int", true));
|
||||
REQUIRE_THAT(err, Catch::Contains("not an integer type"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("parse-unsigned", "[bounds-checking]") {
|
||||
SECTION("parses valid unsigned integers") {
|
||||
// Use string-based parsing here, using the initializer list syntax doesn't
|
||||
// parse 0 as unsigned.
|
||||
json zero_obj = json::parse("{\"zero\": 0}");
|
||||
|
||||
std::string err;
|
||||
size_t result = 123;
|
||||
CHECK(
|
||||
tinygltf::ParseUnsignedProperty(&result, &err, zero_obj, "zero", true));
|
||||
REQUIRE(err == "");
|
||||
REQUIRE(result == 0);
|
||||
}
|
||||
|
||||
SECTION("invalid integers") {
|
||||
std::string err;
|
||||
size_t result = -1;
|
||||
|
||||
CHECK_FALSE(tinygltf::ParseUnsignedProperty(&result, &err, {{"int", -1234}},
|
||||
"int", true));
|
||||
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
|
||||
|
||||
err.clear();
|
||||
CHECK_FALSE(tinygltf::ParseUnsignedProperty(&result, &err, {{"int", 0.5}},
|
||||
"int", true));
|
||||
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
|
||||
|
||||
// Excessively large values and NaN aren't allowed either.
|
||||
err.clear();
|
||||
CHECK_FALSE(tinygltf::ParseUnsignedProperty(&result, &err, {{"int", 1e300}},
|
||||
"int", true));
|
||||
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
|
||||
|
||||
err.clear();
|
||||
CHECK_FALSE(tinygltf::ParseUnsignedProperty(
|
||||
&result, &err, {{"int", std::numeric_limits<double>::quiet_NaN()}},
|
||||
"int", true));
|
||||
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("parse-integer-array", "[bounds-checking]") {
|
||||
SECTION("parses valid integers") {
|
||||
std::string err;
|
||||
std::vector<int> result;
|
||||
CHECK(tinygltf::ParseIntegerArrayProperty(&result, &err,
|
||||
{{"x", {-1, 2, 3}}}, "x", true));
|
||||
REQUIRE(err == "");
|
||||
REQUIRE(result.size() == 3);
|
||||
REQUIRE(result[0] == -1);
|
||||
REQUIRE(result[1] == 2);
|
||||
REQUIRE(result[2] == 3);
|
||||
}
|
||||
|
||||
SECTION("invalid integers") {
|
||||
std::string err;
|
||||
std::vector<int> result;
|
||||
CHECK_FALSE(tinygltf::ParseIntegerArrayProperty(
|
||||
&result, &err, {{"x", {-1, 1e300, 3}}}, "x", true));
|
||||
REQUIRE_THAT(err, Catch::Contains("not an integer type"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("pbr-khr-texture-transform", "[material]") {
|
||||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTF ctx;
|
||||
std::string err;
|
||||
std::string warn;
|
||||
|
||||
// Loading is expected to fail, but not crash.
|
||||
bool ret = ctx.LoadASCIIFromFile(
|
||||
&model, &err, &warn,
|
||||
"../models/Cube-texture-ext/Cube-textransform.gltf");
|
||||
REQUIRE(ret == true);
|
||||
|
||||
REQUIRE(model.materials.size() == 2);
|
||||
REQUIRE(model.materials[0].emissiveTexture.extensions.count("KHR_texture_transform") == 1);
|
||||
REQUIRE(model.materials[0].emissiveTexture.extensions["KHR_texture_transform"].IsObject());
|
||||
|
||||
tinygltf::Value::Object &texform = model.materials[0].emissiveTexture.extensions["KHR_texture_transform"].Get<tinygltf::Value::Object>();
|
||||
|
||||
REQUIRE(texform.count("scale"));
|
||||
|
||||
REQUIRE(texform["scale"].IsArray());
|
||||
|
||||
// Note: It looks json.hpp parse integer JSON number as integer, not floating point.
|
||||
// IsNumber return true either value is int or floating point.
|
||||
REQUIRE(texform["scale"].Get(0).IsNumber());
|
||||
REQUIRE(texform["scale"].Get(1).IsNumber());
|
||||
|
||||
double scale[2];
|
||||
scale[0] = texform["scale"].Get(0).GetNumberAsDouble();
|
||||
scale[1] = texform["scale"].Get(1).GetNumberAsDouble();
|
||||
|
||||
REQUIRE(scale[0] == Approx(1.0));
|
||||
REQUIRE(scale[1] == Approx(-1.0));
|
||||
|
||||
}
|
||||
|
||||
2142
tiny_gltf.h
2142
tiny_gltf.h
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user