Compare commits

...
51 Commits
Author SHA1 Message Date
Syoyo Fujita 3c0bcb7d72 Add document on schema validation feature. 2019-06-24 15:30:32 +09:00
Syoyo Fujita d5694dc15d Some pointer variables are not initialized. 2019-06-15 16:22:40 +09:00
Syoyo Fujita ddf0a0e83c Update rapidjson-amalgamation to include error/en.h and cursorstreamwrapper.h.
Now schema validation is getting to work.
2019-06-14 22:03:11 +09:00
Syoyo Fujita f3ee08c595 Merge branch 'rapidjson' of github.com:syoyo/tinygltf into rapidjson 2019-06-14 19:29:26 +09:00
Syoyo Fujita f75327bc5b Fix compilation on MSVC. 2019-06-14 19:29:13 +09:00
Syoyo Fujita 7acc95a2ae Write an array of string to avoid the limit of the character length in MSVC compiler. 2019-06-14 19:28:37 +09:00
Syoyo Fujita 2a6f2cc356 Serializer now started to work. 2019-06-13 20:36:37 +09:00
Syoyo Fujita 0cf2812775 Use rapidjson for serialization(W.I.P. currently segfaults when serialize a scene) 2019-06-12 22:35:28 +09:00
Syoyo Fujita 2673d1d3ef Add C++ string of glTF Schema. 2019-06-11 14:38:01 +09:00
Syoyo Fujita cf8b7cc0a4 Add JSON schema ref resolver. 2019-06-11 14:25:16 +09:00
Syoyo Fujita 93d0e365bb RapidJson version of TinyGLTF.
TODO: Serializer.
2019-06-10 02:39:13 +09:00
Syoyo Fujita b3c1471317 Merge pull request #155 from ffreling/accessor-normalized
Serialize accessor 'normalized' attribute.
2019-03-22 01:32:34 +09:00
Fabien Freling 9056aee823 Serialize accessor 'normalized' attribute. 2019-03-21 17:06:22 +01:00
Syoyo Fujita 29c431b2f2 Add build option with draco in Makefile. 2019-03-08 14:01:06 +09:00
Syoyo Fujita d06b2c2022 Merge pull request #154 from Ybalrid/patch-3
Fix the display of the version history
2019-03-08 13:32:31 +09:00
Arthur Brainville 339c9d578a Fix the display of the version history
Markdown is like HTML: simple line-breaks don't work.

Besides, making a list with dots here looks nicer :)
2019-03-07 19:40:57 +01:00
Syoyo Fujita 7c315fa8a8 Merge pull request #153 from Ybalrid/patch-2
fix a few typos in README.md
2019-03-07 21:30:20 +09:00
Arthur Brainville 0f04ed018a fix a few typos in README.md 2019-03-07 13:23:59 +01:00
Syoyo Fujita ca56f726d6 Merge branch '16bit-lodepng' 2019-03-07 21:04:25 +09:00
Syoyo Fujita e8a46c4e1d Update README.
Check bit depth when saving image as PNG.
2019-03-07 20:50:58 +09:00
Syoyo Fujita 9cd14a461b Update README. 2019-03-07 01:05:02 +09:00
Syoyo Fujita 1ef603ea2a Merge pull request #150 from Ybalrid/sparse_accessor
Sparse accessor
2019-03-07 00:49:29 +09:00
Arthur Brainville (Ybalrid) 14d259f361 glview can now load static geometry modified by sparse accessor 2019-03-06 14:48:44 +00:00
Arthur Brainville (Ybalrid) 9223d3133a Ran clang-format on tiny_gltf.h 2019-03-06 14:00:56 +00:00
Arthur Brainville (Ybalrid) 9b321a8515 clang-format + added sparse accessor in loader_example 2019-03-06 12:39:39 +00:00
Arthur Brainville (Ybalrid) 7e9f734d73 Parse sparse accessors 2019-03-06 12:27:23 +00:00
Arthur Brainville (Ybalrid) 9d86405d3d Fix accessor ctor 2019-03-06 11:33:30 +00:00
Arthur Brainville (Ybalrid) 1ccb4ff580 added sparse structure to accessors 2019-03-06 11:30:00 +01:00
Syoyo Fujita 8fd91aea04 Update TinyEXR. 2019-03-04 02:15:03 +09:00
Syoyo Fujita 8f76d790b8 Merge pull request #148 from Ybalrid/16bit-lodepng-good-byteswap
When writing out a 16bit image with lodepng, simplify the byteswap to big-endian
2019-03-04 01:15:20 +09:00
Arthur Brainville (Ybalrid) 853f6df7b5 Simplify byteswap code to convert to big endian 16bit 2019-03-03 16:26:20 +01:00
Syoyo Fujita 758a1240c9 Reorder 16 bit pixel data to big endian when saving it as 16 png, since lodepng::encode expects image data is in big endian manner.
Add OpenEXR saver for 16bit image as a bonus.
2019-03-03 21:21:18 +09:00
Syoyo Fujita 7bdfed3bec Add lodepng to save 16bit PNG.
Suppress clang/gcc warnings.
2019-03-03 17:04:49 +09:00
Syoyo Fujita bf9c2f4abd Merge pull request #146 from WARP-LAB/master
Fix for when json and stb is aready used in project
2019-03-03 15:31:09 +09:00
kroko fc0116b323 rename TINYGLTF_BYPASS_INCLUDE_x to TINYGLTF_NO_INCLUDE_x 2019-03-03 08:28:49 +02:00
Syoyo Fujita 962552c5c8 Merge pull request #145 from Ybalrid/upgrade_stb_libs
Upgrade the STB libraries, and fix #132
2019-03-03 13:39:10 +09:00
kroko 606e5dde31 be more precise in readme about include bypassing flags 2019-03-03 01:56:34 +02:00
kroko 6a0d4c57b1 Fix for when json and stb is aready used in project v2 2019-03-03 01:28:45 +02:00
kroko f4b6d11abc Fix for when json and stb is aready used in project 2019-03-03 01:11:31 +02:00
Arthur Brainville (Ybalrid) 5a4c898912 Fixed wrong metadata in case 16bit image wasn't actually loaded
The fallback to 8 bit would have been broken.
2019-03-02 22:03:34 +01:00
Arthur Brainville (Ybalrid) f2addc0e44 16bit images are 16bit images: added Image::bits and Image::pixel_type 2019-03-02 22:00:48 +01:00
Arthur Brainville (Ybalrid) 70d16a7b92 Upgrade the STB libraries, and fix #132 2019-03-02 16:10:54 +01:00
Syoyo Fujita 326d7ea310 Merge pull request #144 from SaschaWillems/master
Add direct access to texture coordinate set on texture parameter
2019-02-24 14:42:51 +09:00
Sascha Willems eb011068c0 Added function to easily access texture coordinate set index on a texture parameter 2019-02-23 21:15:45 +01:00
Syoyo Fujita 87be0ce34b Define WIN32_LEAN_AND_MEAN to save the number of including files. 2019-02-19 21:36:32 +09:00
Syoyo Fujita 7d9a0bda3a Define NOMINMAX to avoid defining MIN/MAX macros on Windows. Without defining NOMINMAX, MIN/MAX macro would affect other header/c++ files. Fixes #143 2019-02-19 16:03:23 +09:00
Syoyo Fujita 7ece5c8275 Merge pull request #142 from ebirenbaum/animation-sampler-interpolation
Change AnimationSampler::interpolation to a non-required field.
2019-02-15 14:04:06 +09:00
Evan Birenbaum 6bdffedcbe Change AnimationSampler::interpolation to a non-required field. The spec states to default to LINEAR when not present. 2019-02-14 13:30:57 -08:00
Syoyo Fujita d2fb7dc2af Merge pull request #140 from timmmeh/master
Adding default values for min and mag filter.
2019-02-10 00:01:11 +09:00
timmmeh 62a72c4845 fix compile 2019-01-31 11:46:19 -08:00
timmmeh 73584ba7b7 Adding default values for min and mag filter. 2019-01-30 18:38:46 -08:00
26 changed files with 34349 additions and 3985 deletions
+13
View 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.
+5 -1
View File
@@ -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 -17
View File
@@ -2,12 +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.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
@@ -32,20 +34,24 @@ 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.
* 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
@@ -63,18 +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.
* [ ] 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
@@ -90,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
@@ -99,18 +110,23 @@ 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"
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)
// 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());
@@ -128,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.
+36 -5
View File
@@ -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,14 +321,18 @@ 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);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
#endif
Window window = Window(800, 600, "TinyGLTF basic example");
+21
View 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.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1502 -602
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -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
+1
View File
@@ -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() {
+14 -2
View File
@@ -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);
+115 -14
View File
@@ -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;
}
}
+4
View File
@@ -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);
};
+342 -216
View File
@@ -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;
}
File diff suppressed because one or more lines are too long
+46 -14
View File
@@ -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());
}
File diff suppressed because it is too large Load Diff
+1887 -866
View File
File diff suppressed because it is too large Load Diff
+1211 -1421
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -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"]
# ---------------------------------
+1384 -826
View File
File diff suppressed because it is too large Load Diff
+20
View 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?
@@ -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("};")
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
+82
View 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