Compare commits

..

39 Commits

Author SHA1 Message Date
Syoyo Fujita
e8a46c4e1d Update README.
Check bit depth when saving image as PNG.
2019-03-07 20:50:58 +09: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
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
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
Syoyo Fujita
c0d0251e2c Update json.hpp to fix compilation with clang with C++17(-std=c++1z) support. 2019-02-04 16:19:13 +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
Syoyo Fujita
ead876fce9 Merge pull request #138 from dolphineye/dolphineye/add_mode_line_strip
Add line strip primitive mode define
2019-01-30 23:19:30 +09:00
Thomas Tissot
6c4a006496 Add line strip primitive mode define
This small commit adds the `TINYGLTF_MODE_LINE_STRIP` primitive mode
define whose value is set to `3` as per the GLTF 2.0 specification.
2019-01-30 13:10:51 +01:00
Syoyo Fujita
281af41b6c Merge pull request #137 from Ybalrid/pr_fix_glview_no_scene_no_nodes
Fix glView in case there is no default scene
2019-01-28 13:00:26 +09:00
Arthur Brainville (Ybalrid)
215e1fae61 handle not having default scene 2019-01-27 20:52:04 +00:00
Arthur Brainville (Ybalrid)
cba75b9927 fix glview in case gltf asset doesn't have a default scene 2019-01-27 20:52:04 +00:00
Syoyo Fujita
4de57db325 Add TINYGLTF_ENABLE_DRACO flag to README. 2019-01-27 00:43:02 +09:00
Syoyo Fujita
a32fa80102 Add support for building glview with draco.
Fix out-of-bounds access when calling DrawMesh().
Fix potential out-of-bounds access when filling window title string.
2019-01-27 00:38:34 +09:00
Syoyo Fujita
5f34dab548 Merge pull request #136 from abwood/draco
Fixed decoding bugs in draco
2019-01-26 23:22:55 +09:00
Alexander Wood
0d77a291f7 Updates to draco decoding:
- When injecting draco decoded meshes into accessor data, update count to match the optimized and decoded draco mesh
 - accessor.componentType is now used for extraction of decoded draco meshes.

Fixes #135
2019-01-26 08:58:45 -05:00
Syoyo Fujita
b926195ef8 Merge pull request #134 from abwood/draco
Initial support for draco mesh compression
2019-01-25 16:45:33 +09:00
Alex Wood
c8ba17fcab Looks like I'm colliding with work by syoyo. Only difference so far appears to be our macro name. 2019-01-24 15:45:16 -05:00
Alex Wood
df39e04e7b Merge branch 'draco' of https://github.com/abwood/tinygltf into draco 2019-01-24 15:40:28 -05:00
Alex Wood
7319db7a50 Initial support for draco mesh compression. In this PR, we establish that draco is a dependency built external to tinygltf, which breaks from the current tradition of header only dependencies. For that reason, this feature is hidden behind a #define TINYGLTF_ENABLE_DRACO and requires developers to explicitly opt-in for draco support.
In this change, tinygltf any primitive using draco compression will:
If indices are specified
1) Decode the index buffer using draco, creating a new buffer and bufferview, adding to Model::bufferViews and Model::buffer collections
2) Update the primitive's accessor id to reference this new decoded bufferview.
For each attribute semantic specified by the draco extension
1) Decode the vertex buffer using draco, creating a new buffer and bufferview, adding to Model::bufferViews and Model::buffer collections
2) Update the primitive's accessor id to reference this new decoded bufferview.
2019-01-24 15:38:16 -05:00
Syoyo Fujita
7ae7110800 Begin supporting draco. 2019-01-19 03:03:22 +09:00
Syoyo Fujita
b864ea7349 Support macOS + OpenGL 3.3+ GPU 2019-01-14 22:11:11 +09:00
Syoyo Fujita
d6b0b0b990 Convert UTF16 file to UTF8.
Add premake project to build on Linux.
2019-01-14 21:30:53 +09:00
Syoyo Fujita
af3ebb2e76 Show more expressive messages when parsing image. 2019-01-06 18:55:57 +09:00
Syoyo Fujita
105694b468 Merge pull request #129 from SaschaWillems/master
Added new compiler option for loading all gltf related files from android app asset package
2018-12-29 12:33:34 +09:00
Sascha Willems
5f9cb24245 Added new feature for loading all gltf related files (including textures, binaries, etc.) from assets packaged with an Android app 2018-12-28 20:53:41 +01:00
25 changed files with 22282 additions and 6900 deletions

View File

@@ -3,11 +3,13 @@
`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.2.0 release(Support loading 16bit PNG)
v2.1.0 release(Draco support)
v2.0.0 release(22 Aug, 2018)!
## Builds
@@ -38,19 +40,23 @@ 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
* Custom callback handler
* [x] Image load
* [x] Image save
* Extensions
* [x] Draco mesh decoding
## Examples
* [glview](examples/glview) : Simple glTF geometry viewer.
* [validator](examples/validator) : Simple glTF validator with JSON schema.
* [basic](examples/basic) : Basic glTF viewer with texturing support.
## Projects using TinyGLTF
@@ -62,14 +68,16 @@ v2.0.0 release(22 Aug, 2018)!
## TODOs
* [ ] Sparse accesors(e.g. for efficient morph targets)
* [ ] Write C++ code generator which emits C++ code from JSON schema for robust parsing.
* [ ] Mesh Compression/decompression(Open3DGC, etc)
* [ ] Load Draco compressed mesh
* [x] Load Draco compressed mesh
* [x] Save Draco compressed mesh
* [ ] Open3DGC?
* [ ] Support `extensions` and `extras` property
* [ ] HDR image?
* [ ] OpenEXR extension through TinyEXR.
* [ ] Write example and tests for `animation` and `skin`
* [ ] 16bit PNG support in Serialization
* [ ] Write example and tests for `animation` and `skin`
* [ ] Skinning
* [ ] Morph targets
@@ -101,13 +109,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());
@@ -129,6 +137,8 @@ if (!ret) {
* `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_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.
### Saving gltTF 2.0 model
* [ ] Buffers.

View File

@@ -1,6 +0,0 @@
# 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
all:
clang++ -I../../ $(EXTRA_CXXFLAGS) -std=c++11 -g -O0 -o anim-dump anim-dump.cc

View File

@@ -1,2 +0,0 @@
# Simple animation value dumper

View File

@@ -1,178 +0,0 @@
//
// TODO(syoyo): Print extensions and extras for each glTF object.
//
#include "tiny_gltf_util.h"
#define TINYGLTF_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "tiny_gltf.h"
#include <cstdio>
#include <fstream>
#include <iostream>
static std::string GetFilePathExtension(const std::string &FileName) {
if (FileName.find_last_of(".") != std::string::npos)
return FileName.substr(FileName.find_last_of(".") + 1);
return "";
}
static std::string Indent(const int indent) {
std::string s;
for (int i = 0; i < indent; i++) {
s += " ";
}
return s;
}
static void ProcessAnimation(const tinygltf::Animation &animation, const tinygltf::Model &model)
{
#if 0
if (animaton_channel.target_path.compare("translation") == 0) {
} else if (animaton_channel.target_path.compare("rotation") == 0) {
} else if (animaton_channel.target_path.compare("scale") == 0) {
} else if (animaton_channel.target_path.compare("weights") == 0) {
}
#endif
for (size_t j = 0; j < animation.samplers.size(); j++) {
std::cout << "== samplers[" << j << "] ===============" << std::endl;
const tinygltf::AnimationSampler &sampler = animation.samplers[j];
std::cout << Indent(1) << "interpolation = " << sampler.interpolation<< std::endl;
std::cout << Indent(1) << "input = " << sampler.input << std::endl;
std::cout << Indent(1) << "output = " << sampler.output << std::endl;
// input accessor must have min/max property.
const tinygltf::Accessor &accessor = model.accessors[sampler.input];
for (size_t i = 0; i < accessor.minValues.size(); i++) {
std::cout << Indent(1) << "input min[" << i << "] = " << accessor.minValues[i] << std::endl;
}
for (size_t i = 0; i < accessor.maxValues.size(); i++) {
std::cout << Indent(1) << "input max[" << i << "] = " << accessor.maxValues[i] << std::endl;
}
std::cout << Indent(1) << "input count = " << accessor.count << std::endl;
for (size_t i = 0; i < accessor.count; i++) {
if (accessor.type == TINYGLTF_TYPE_SCALAR) {
float v;
if (tinygltf::util::DecodeScalarAnimationValue(i, accessor, model, &v)) {
std::cout << Indent(2) << "input value[" << i << "] = " << v << std::endl;
}
}
}
//const tinygltf::Accessor &accessor = model.accessors[sampler.output];
//std::cout << Indent(2) << "output : " << sampler.output
// << std::endl;
}
}
static void DumpAnim(const tinygltf::Model &model) {
std::cout << "=== Dump glTF ===" << std::endl;
std::cout << "asset.copyright : " << model.asset.copyright
<< std::endl;
std::cout << "asset.generator : " << model.asset.generator
<< std::endl;
std::cout << "asset.version : " << model.asset.version
<< std::endl;
std::cout << "asset.minVersion : " << model.asset.minVersion
<< std::endl;
std::cout << std::endl;
std::cout << "=== Dump scene ===" << std::endl;
std::cout << "defaultScene: " << model.defaultScene << std::endl;
{
std::cout << "animations(items=" << model.animations.size() << ")"
<< std::endl;
for (size_t i = 0; i < model.animations.size(); i++) {
const tinygltf::Animation &animation = model.animations[i];
std::cout << Indent(1) << "name : " << animation.name
<< std::endl;
std::cout << Indent(1) << "channels : [ " << std::endl;
for (size_t j = 0; i < animation.channels.size(); i++) {
std::cout << Indent(2)
<< "sampler : " << animation.channels[j].sampler
<< std::endl;
std::cout << Indent(2)
<< "target.id : " << animation.channels[j].target_node
<< std::endl;
std::cout << Indent(2)
<< "target.path : " << animation.channels[j].target_path
<< std::endl;
std::cout << ((i != (animation.channels.size() - 1)) ? " , " : "");
}
std::cout << " ]" << std::endl;
std::cout << Indent(1) << "samplers(items=" << animation.samplers.size()
<< ")" << std::endl;
for (size_t j = 0; j < animation.samplers.size(); j++) {
const tinygltf::AnimationSampler &sampler = animation.samplers[j];
std::cout << Indent(2) << "input : " << sampler.input
<< std::endl;
std::cout << Indent(2) << "interpolation : " << sampler.interpolation
<< std::endl;
std::cout << Indent(2) << "output : " << sampler.output
<< std::endl;
}
ProcessAnimation(animation, model);
}
}
}
int main(int argc, char **argv) {
if (argc < 2) {
printf("Needs input.gltf\n");
exit(1);
}
tinygltf::Model model;
tinygltf::TinyGLTF gltf_ctx;
std::string err;
std::string warn;
std::string input_filename(argv[1]);
std::string ext = GetFilePathExtension(input_filename);
bool ret = false;
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());
} else {
std::cout << "Reading ASCII glTF" << std::endl;
// assume ascii glTF.
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());
}
if (!ret) {
printf("Failed to parse glTF\n");
return -1;
}
DumpAnim(model);
return 0;
}

21
examples/basic/README.md Normal file
View File

@@ -0,0 +1,21 @@
# Basic glTF viewer
## Requirements
* glew
* glfw3
* premake5(linux)
* OpenGL 3.3+ GPU
## Build on Linux and macOS
```
$ premake5 gmake
$ make
```
## Build on Visual Studio
Plese use solution file located at `basic` folder.

Binary file not shown.

View File

@@ -0,0 +1,44 @@
solution "basic_viewer"
-- location ( "build" )
configurations { "Debug", "Release" }
platforms {"native", "x64", "x32"}
project "basic_viewer"
kind "ConsoleApp"
language "C++"
cppdialect "C++11"
files { "main.cpp", "shaders.cpp", "window.cpp" }
includedirs { "./" }
includedirs { "../../" }
includedirs { "../common/glm" }
configuration { "linux" }
linkoptions { "`pkg-config --libs glfw3`" }
links { "GL", "GLU", "m", "GLEW", "X11", "Xrandr", "Xinerama", "Xi", "Xxf86vm", "Xcursor", "dl" }
configuration { "windows" }
-- Edit path to glew and GLFW3 fit to your environment.
includedirs { "../../../../local/glew-1.13.0/include/" }
includedirs { "../../../../local/glfw-3.2.bin.WIN32/include/" }
libdirs { "../../../../local/glew-1.13.0/lib/Release/Win32/" }
libdirs { "../../../../local/glfw-3.2.bin.WIN32/lib-vc2013/" }
links { "glfw3", "gdi32", "winmm", "user32", "glew32", "glu32","opengl32", "kernel32" }
defines { "_CRT_SECURE_NO_WARNINGS" }
configuration { "macosx" }
includedirs { "/usr/local/include" }
buildoptions { "-Wno-deprecated-declarations" }
libdirs { "/usr/local/lib" }
links { "glfw", "GLEW" }
linkoptions { "-framework OpenGL", "-framework Cocoa", "-framework IOKit", "-framework CoreVideo" }
configuration "Debug"
defines { "DEBUG" }
symbols "On"
warnings "Extra"
configuration "Release"
defines { "NDEBUG" }
optimize "On"
warnings "Extra"

View File

@@ -19,7 +19,7 @@ uniform vec3 sun_color; \n\
out vec4 color;\n\
void main() {\n\
float lum = max(dot(normal, normalize(sun_position)), 0.0);\n\
color = texture2D(tex, texcoord) * vec4((0.3 + 0.7 * lum) * sun_color, 1.0);\n\
color = texture(tex, texcoord) * vec4((0.3 + 0.7 * lum) * sun_color, 1.0);\n\
}\n\
";

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.

5992
examples/common/lodepng.cpp Normal file

File diff suppressed because it is too large Load Diff

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

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

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() {

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);

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;
}
}

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);
};

View File

@@ -1,8 +1,10 @@
cmake_minimum_required(VERSION 3.6)
cmake_minimum_required(VERSION 3.5)
project(glview)
set ( CMAKE_PREFIX_PATH cmake )
set ( DRACO_DIR "" CACHE STRING "Path to draco" )
find_package ( GLEW REQUIRED )
find_package ( GLFW3 REQUIRED )
find_package ( OpenGL REQUIRED )
@@ -21,6 +23,18 @@ endif (APPLE)
set(CMAKE_CXX_STANDARD 11)
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(
../../
../common
@@ -35,6 +49,7 @@ add_executable(glview
)
target_link_libraries ( glview
${DRACO_LIBRARY}
${GLFW3_UNIX_LINK_LIBRARIES}
${GLEW_LIBRARY}
${GLFW3_glfw_LIBRARY}

View File

@@ -27,6 +27,17 @@ Open .sln in Visual Studio 2013
When running .exe, glew and glfw dll must exist in the working directory.
#### Build with Draco(optional)
Assume CMake build.
```
$ mkdir build
$ cd build
$ cmake -DDRACO_DIR=/path/to/draco ../
$ make
```
## TODO
* [ ] PBR Material

View File

@@ -677,10 +677,14 @@ static void DrawNode(tinygltf::Model &model, const tinygltf::Node &node) {
// std::cout << it->first << std::endl;
// FIXME(syoyo): Refactor.
// DrawCurves(scene, it->second);
DrawMesh(model, model.meshes[node.mesh]);
if (node.mesh > -1) {
assert(node.mesh < model.meshes.size());
DrawMesh(model, model.meshes[node.mesh]);
}
// Draw child nodes.
for (size_t i = 0; i < node.children.size(); i++) {
assert(node.children[i] < model.nodes.size());
DrawNode(model, model.nodes[node.children[i]]);
}
@@ -697,10 +701,11 @@ static void DrawModel(tinygltf::Model &model) {
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]]);
}
@@ -779,17 +784,19 @@ 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;
return -1;
}
char title[1024];
sprintf(title, "Simple glTF viewer: %s", input_filename.c_str());
std::stringstream ss;
ss << "Simple glTF viewer: " << input_filename;
window = glfwCreateWindow(width, height, title, NULL, NULL);
std::string title = ss.str();
window = glfwCreateWindow(width, height, title.c_str(), NULL, NULL);
if (window == NULL) {
std::cerr << "Failed to open GLFW window. " << std::endl;
glfwTerminate();

12480
json.hpp

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -26,6 +26,8 @@
// THE SOFTWARE.
// Version:
// - v2.2.0 Add loading 16bit PNG support.
// - v2.1.0 Add draco compression.
// - v2.0.1 Add comparsion feature(Thanks to @Selmar).
// - v2.0.0 glTF 2.0!.
//
@@ -47,16 +49,22 @@
#include <string>
#include <vector>
#ifdef __ANDROID__
#ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS
#include <android/asset_manager.h>
#endif
#endif
namespace tinygltf {
#define TINYGLTF_MODE_POINTS (0)
#define TINYGLTF_MODE_LINE (1)
#define TINYGLTF_MODE_LINE_LOOP (2)
#define TINYGLTF_MODE_LINE_STRIP (3)
#define TINYGLTF_MODE_TRIANGLES (4)
#define TINYGLTF_MODE_TRIANGLE_STRIP (5)
#define TINYGLTF_MODE_TRIANGLE_FAN (6)
#define TINYGLTF_COMPONENT_TYPE_INVALID (-1)
#define TINYGLTF_COMPONENT_TYPE_BYTE (5120)
#define TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE (5121)
#define TINYGLTF_COMPONENT_TYPE_SHORT (5122)
@@ -107,7 +115,6 @@ namespace tinygltf {
// End parameter types
#define TINYGLTF_TYPE_INVALID (-1)
#define TINYGLTF_TYPE_VEC2 (2)
#define TINYGLTF_TYPE_VEC3 (3)
#define TINYGLTF_TYPE_VEC4 (4)
@@ -141,6 +148,12 @@ namespace tinygltf {
#define TINYGLTF_DOUBLE_EPS (1.e-12)
#define TINYGLTF_DOUBLE_EQUAL(a, b) (std::fabs((b) - (a)) < TINYGLTF_DOUBLE_EPS)
#ifdef __ANDROID__
#ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS
AAssetManager* asset_manager = nullptr;
#endif
#endif
typedef enum {
NULL_TYPE = 0,
NUMBER_TYPE = 1,
@@ -368,6 +381,17 @@ struct Parameter {
return -1;
}
/// Return the index of a texture coordinate set if this Parameter is a texture map.
/// Returned value is only valid if the parameter represent a texture from a
/// material
int TextureTexCoord() const {
const auto it = json_double_value.find("texCoord");
if (it != std::end(json_double_value)) {
return int(it->second);
}
return 0;
}
/// Material factor, like the roughness or metalness of a material
/// Returned value is only valid if the parameter represent a texture from a
/// material
@@ -418,7 +442,6 @@ struct AnimationSampler {
AnimationSampler() : input(-1), output(-1), interpolation("LINEAR") {}
bool operator==(const AnimationSampler &) const;
};
struct Animation {
@@ -457,7 +480,9 @@ struct Sampler {
Value extras;
Sampler()
: wrapS(TINYGLTF_TEXTURE_WRAP_REPEAT),
: minFilter(TINYGLTF_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR),
magFilter(TINYGLTF_TEXTURE_FILTER_LINEAR),
wrapS(TINYGLTF_TEXTURE_WRAP_REPEAT),
wrapT(TINYGLTF_TEXTURE_WRAP_REPEAT),
wrapR(TINYGLTF_TEXTURE_WRAP_REPEAT){}
bool operator==(const Sampler &) const;
@@ -468,6 +493,8 @@ struct Image {
int width;
int height;
int component;
int bits; // bit depth per channel. 8(byte), 16 or 32.
int pixel_type; // pixel type(TINYGLTF_COMPONENT_TYPE_***). usually UBYTE(bits = 8) or USHORT(bits = 16)
std::vector<unsigned char> image;
int bufferView; // (required if no uri)
std::string mimeType; // (required if no uri) ["image/jpeg", "image/png",
@@ -529,8 +556,9 @@ struct BufferView {
// understood to be tightly packed
int target; // ["ARRAY_BUFFER", "ELEMENT_ARRAY_BUFFER"]
Value extras;
bool dracoDecoded; // Flag indicating this has been draco decoded
BufferView() : byteOffset(0), byteStride(0) {}
BufferView() : byteOffset(0), byteStride(0), dracoDecoded(false) {}
bool operator==(const BufferView &) const;
};
@@ -538,11 +566,11 @@ struct Accessor {
int bufferView; // optional in spec but required here since sparse accessor
// are not supported
std::string name;
size_t byteOffset = 0;
bool normalized = false; // optinal.
int componentType = TINYGLTF_COMPONENT_TYPE_INVALID; // (required) One of TINYGLTF_COMPONENT_TYPE_***
size_t count = 0; // required
int type = TINYGLTF_TYPE_INVALID; // (required) One of TINYGLTF_TYPE_*** ..
size_t byteOffset;
bool normalized; // optinal.
int componentType; // (required) One of TINYGLTF_COMPONENT_TYPE_***
size_t count; // required
int type; // (required) One of TINYGLTF_TYPE_*** ..
Value extras;
std::vector<double> minValues; // optional
@@ -591,7 +619,6 @@ struct Accessor {
bool operator==(const tinygltf::Accessor &) const;
};
struct PerspectiveCamera {
double aspectRatio; // min > 0
double yfov; // required. min > 0
@@ -650,6 +677,7 @@ struct Primitive {
// where each target is a dict with attribues in ["POSITION, "NORMAL",
// "TANGENT"] pointing
// to their corresponding accessors
ExtensionMap extensions;
Value extras;
Primitive() {
@@ -779,14 +807,6 @@ class Model {
Value extras;
};
///
/// Utility function to get an address of underlying buffer for i'th element.
/// Returns nullptr for invalid parameter or invalid data.
/// Assume `buffer` parameter = model.buffers[bufferViewObject.buffer]
///
const uint8_t *GetBufferAddress(const int i, const Accessor &accessor, const BufferView &bufferViewObject, const Buffer &buffer);
enum SectionCheck {
NO_REQUIRE = 0x00,
REQUIRE_SCENE = 0x01,
@@ -801,7 +821,7 @@ enum SectionCheck {
///
/// LoadImageDataFunction type. Signature for custom image loading callbacks.
///
typedef bool (*LoadImageDataFunction)(Image *, std::string *, std::string *,
typedef bool (*LoadImageDataFunction)(Image *, const int, std::string *, std::string *,
int, int, const unsigned char *, int,
void *);
@@ -813,7 +833,7 @@ typedef bool (*WriteImageDataFunction)(const std::string *, const std::string *,
#ifndef TINYGLTF_NO_STB_IMAGE
// Declaration of default image loader callback
bool LoadImageData(Image *image, std::string *err, std::string *warn,
bool LoadImageData(Image *image, const int image_idx, std::string *err, std::string *warn,
int req_width, int req_height, const unsigned char *bytes,
int size, void *);
#endif
@@ -1058,24 +1078,67 @@ class TinyGLTF {
#if __has_warning("-Wnewline-eof")
#pragma clang diagnostic ignored "-Wnewline-eof"
#endif
#if __has_warning("-Wunused-parameter")
#pragma clang diagnostic ignored "-Wunused-parameter"
#endif
#if __has_warning("-Wmismatched-tags")
#pragma clang diagnostic ignored "-Wmismatched-tags"
#endif
#endif
#include "./json.hpp"
// Disable GCC warnigs
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wtype-limits"
#endif // __GNUC__
#include "json.hpp"
#ifdef TINYGLTF_ENABLE_DRACO
#include "draco/core/decoder_buffer.h"
#include "draco/compression/decode.h"
#endif
#ifndef TINYGLTF_NO_STB_IMAGE
#include "./stb_image.h"
#include "stb_image.h"
#endif
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
#include "./stb_image_write.h"
#include "stb_image_write.h"
#endif
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
#ifdef _WIN32
#include <windows.h>
// issue 143.
// Define NOMINMAX to avoid min/max defines,
// but undef it after included windows.h
#ifndef NOMINMAX
#define TINYGLTF_INTERNAL_NOMINMAX
#define NOMINMAX
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#define TINYGLTF_INTERNAL_WIN32_LEAN_AND_MEAN
#endif
#include <windows.h> // include API for expanding a file path
#ifdef TINYGLTF_INTERNAL_WIN32_LEAN_AND_MEAN
#undef WIN32_LEAN_AND_MEAN
#endif
#if defined(TINYGLTF_INTERNAL_NOMINMAX)
#undef NOMINMAX
#endif
#elif !defined(__ANDROID__)
#include <wordexp.h>
#endif
@@ -1192,7 +1255,8 @@ bool BufferView::operator==(const BufferView &other) const {
return this->buffer == other.buffer && this->byteLength == other.byteLength &&
this->byteOffset == other.byteOffset &&
this->byteStride == other.byteStride && this->name == other.name &&
this->target == other.target && this->extras == other.extras;
this->target == other.target && this->extras == other.extras &&
this->dracoDecoded == other.dracoDecoded;
}
bool Camera::operator==(const Camera &other) const {
return this->name == other.name && this->extensions == other.extensions &&
@@ -1588,46 +1652,73 @@ void TinyGLTF::SetImageLoader(LoadImageDataFunction func, void *user_data) {
}
#ifndef TINYGLTF_NO_STB_IMAGE
bool LoadImageData(Image *image, std::string *err, std::string *warn,
int req_width, int req_height, const unsigned char *bytes,
int size, void *) {
bool LoadImageData(Image *image, const int image_idx, std::string *err,
std::string *warn, int req_width, int req_height,
const unsigned char *bytes, int size, void *user_data) {
(void)user_data;
(void)warn;
int w, h, comp, req_comp;
unsigned char *data = nullptr;
// force 32-bit textures for common Vulkan compatibility. It appears that
// some GPU drivers do not support 24-bit images for Vulkan
req_comp = 4;
int bits = 8;
int pixel_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE;
// It is possible that the image we want to load is a 16bit per channel image
// We are going to attempt to load it as 16bit per channel, and if it worked,
// set the image data accodingly. We are casting the returned pointer into
// unsigned char, because we are representing "bytes". But we are updating
// the Image metadata to signal that this image uses 2 bytes (16bits) per
// channel:
if (stbi_is_16_bit_from_memory(bytes, size)) {
data = (unsigned char *)stbi_load_16_from_memory(bytes, size, &w, &h, &comp,
req_comp);
if (data) {
bits = 16;
pixel_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT;
}
}
// at this point, if data is still NULL, it means that the image wasn't
// 16bit per channel, we are going to load it as a normal 8bit per channel
// mage as we used to do:
// if image cannot be decoded, ignore parsing and keep it by its path
// don't break in this case
// FIXME we should only enter this function if the image is embedded. If
// image->uri references
// an image file, it should be left as it is. Image loading should not be
// mandatory (to support other formats)
unsigned char *data =
stbi_load_from_memory(bytes, size, &w, &h, &comp, req_comp);
if (!data) data = stbi_load_from_memory(bytes, size, &w, &h, &comp, req_comp);
if (!data) {
// NOTE: you can use `warn` instead of `err`
if (err) {
(*err) += "Unknown image format.\n";
(*err) +=
"Unknown image format. STB cannot decode image data for image[" +
std::to_string(image_idx) + "] name = \"" + image->name + "\".\n";
}
return false;
}
if (w < 1 || h < 1) {
free(data);
stbi_image_free(data);
if (err) {
(*err) += "Invalid image data.\n";
(*err) += "Invalid image data for image[" + std::to_string(image_idx) +
"] name = \"" + image->name + "\"\n";
}
return false;
}
if (req_width > 0) {
if (req_width != w) {
free(data);
stbi_image_free(data);
if (err) {
(*err) += "Image width mismatch.\n";
(*err) += "Image width mismatch for image[" +
std::to_string(image_idx) + "] name = \"" + image->name +
"\"\n";
}
return false;
}
@@ -1635,9 +1726,11 @@ bool LoadImageData(Image *image, std::string *err, std::string *warn,
if (req_height > 0) {
if (req_height != h) {
free(data);
stbi_image_free(data);
if (err) {
(*err) += "Image height mismatch.\n";
(*err) += "Image height mismatch. for image[" +
std::to_string(image_idx) + "] name = \"" + image->name +
"\"\n";
}
return false;
}
@@ -1646,10 +1739,11 @@ bool LoadImageData(Image *image, std::string *err, std::string *warn,
image->width = w;
image->height = h;
image->component = req_comp;
image->image.resize(static_cast<size_t>(w * h * req_comp));
std::copy(data, data + w * h * req_comp, image->image.begin());
free(data);
image->bits = bits;
image->pixel_type = pixel_type;
image->image.resize(static_cast<size_t>(w * h * req_comp) * (bits / 8));
std::copy(data, data + w * h * req_comp * (bits / 8), image->image.begin());
stbi_image_free(data);
return true;
}
@@ -1679,6 +1773,11 @@ bool WriteImageData(const std::string *basepath, const std::string *filename,
std::vector<unsigned char> data;
if (ext == "png") {
if ((image->bits != 8) || (image->pixel_type != TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE)) {
// Unsupported pixel format
return false;
}
if (!stbi_write_png_to_func(WriteToMemory_stbi, &data, image->width,
image->height, image->component,
&image->image[0], 0)) {
@@ -1741,6 +1840,18 @@ void TinyGLTF::SetFsCallbacks(FsCallbacks callbacks) { fs = callbacks; }
bool FileExists(const std::string &abs_filename, void *) {
bool ret;
#ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS
if (asset_manager) {
AAsset* asset = AAssetManager_open(asset_manager, abs_filename.c_str(), AASSET_MODE_STREAMING);
if (!asset) {
return false;
}
AAsset_close(asset);
ret = true;
} else {
return false;
}
#else
#ifdef _WIN32
FILE *fp;
errno_t err = fopen_s(&fp, abs_filename.c_str(), "rb");
@@ -1756,6 +1867,7 @@ bool FileExists(const std::string &abs_filename, void *) {
} else {
ret = false;
}
#endif
return ret;
}
@@ -1809,6 +1921,33 @@ std::string ExpandFilePath(const std::string &filepath, void *) {
bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
const std::string &filepath, void *) {
#ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS
if (asset_manager) {
AAsset* asset = AAssetManager_open(asset_manager, filepath.c_str(), AASSET_MODE_STREAMING);
if (!asset) {
if (err) {
(*err) += "File open error : " + filepath + "\n";
}
return false;
}
size_t size = AAsset_getLength(asset);
if (size <= 0) {
if (err) {
(*err) += "Invalid file size : " + filepath +
" (does the path point to a directory?)";
}
}
out->resize(size);
AAsset_read(asset, reinterpret_cast<char *>(&out->at(0)), size);
AAsset_close(asset);
return true;
} else {
if (err) {
(*err) += "No asset manager specified : " + filepath + "\n";
}
return false;
}
#else
std::ifstream f(filepath.c_str(), std::ifstream::binary);
if (!f) {
if (err) {
@@ -1840,6 +1979,7 @@ bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
f.close();
return true;
#endif
}
bool WriteWholeFile(std::string *err, const std::string &filepath,
@@ -2020,21 +2160,6 @@ bool DecodeDataURI(std::vector<unsigned char> *out, std::string &mime_type,
return true;
}
const uint8_t *GetBufferAddress(const int i, const Accessor &accessor, const BufferView &bufferViewObject, const Buffer &buffer) {
if (i >= int(accessor.count)) return nullptr;
int byte_stride = accessor.ByteStride(bufferViewObject);
if (byte_stride == -1) {
return nullptr;
}
// TODO(syoyo): Bounds check.
const uint8_t *base_addr = buffer.data.data() + bufferViewObject.byteOffset + accessor.byteOffset;
const uint8_t *addr = base_addr + i * byte_stride;
return addr;
}
static bool ParseJsonAsValue(Value *ret, const json &o) {
Value val{};
switch (o.type()) {
@@ -2401,7 +2526,7 @@ static bool ParseAsset(Asset *asset, std::string *err, const json &o) {
return true;
}
static bool ParseImage(Image *image, std::string *err, std::string *warn,
static bool ParseImage(Image *image, const int image_idx, std::string *err, std::string *warn,
const json &o, const std::string &basedir,
FsCallbacks *fs,
LoadImageDataFunction *LoadImageData = nullptr,
@@ -2413,24 +2538,25 @@ static bool ParseImage(Image *image, std::string *err, std::string *warn,
bool hasBufferView = (o.find("bufferView") != o.end());
bool hasURI = (o.find("uri") != o.end());
ParseStringProperty(&image->name, err, o, "name", false);
if (hasBufferView && hasURI) {
// Should not both defined.
if (err) {
(*err) +=
"Only one of `bufferView` or `uri` should be defined, but both are "
"defined for Image.\n";
"defined for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n";
}
return false;
}
if (!hasBufferView && !hasURI) {
if (err) {
(*err) += "Neither required `bufferView` nor `uri` defined for Image.\n";
(*err) += "Neither required `bufferView` nor `uri` defined for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n";
}
return false;
}
ParseStringProperty(&image->name, err, o, "name", false);
ParseExtensionsProperty(&image->extensions, err, o);
ParseExtrasProperty(&image->extras, o);
@@ -2438,7 +2564,7 @@ static bool ParseImage(Image *image, std::string *err, std::string *warn,
double bufferView = -1;
if (!ParseNumberProperty(&bufferView, err, o, "bufferView", true)) {
if (err) {
(*err) += "Failed to parse `bufferView` for Image.\n";
(*err) += "Failed to parse `bufferView` for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n";
}
return false;
}
@@ -2468,7 +2594,7 @@ static bool ParseImage(Image *image, std::string *err, std::string *warn,
std::string tmp_err;
if (!ParseStringProperty(&uri, &tmp_err, o, "uri", true)) {
if (err) {
(*err) += "Failed to parse `uri` for Image.\n";
(*err) += "Failed to parse `uri` for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\".\n";
}
return false;
}
@@ -2478,7 +2604,7 @@ static bool ParseImage(Image *image, std::string *err, std::string *warn,
if (IsDataURI(uri)) {
if (!DecodeDataURI(&img, image->mimeType, uri, 0, false)) {
if (err) {
(*err) += "Failed to decode 'uri' for image parameter.\n";
(*err) += "Failed to decode 'uri' for image[" + std::to_string(image_idx) + "] name = [" + image->name + "]\n";
}
return false;
}
@@ -2491,7 +2617,7 @@ static bool ParseImage(Image *image, std::string *err, std::string *warn,
#endif
if (!LoadExternalFile(&img, err, warn, uri, basedir, false, 0, false, fs)) {
if (warn) {
(*warn) += "Failed to load external 'uri' for image parameter\n";
(*warn) += "Failed to load external 'uri' for image[" + std::to_string(image_idx) + "] name = [" + image->name + "]\n";
}
// If the image cannot be loaded, keep uri as image->uri.
return true;
@@ -2499,7 +2625,7 @@ static bool ParseImage(Image *image, std::string *err, std::string *warn,
if (img.empty()) {
if (warn) {
(*warn) += "Image is empty.\n";
(*warn) += "Image data is empty for image[" + std::to_string(image_idx) + "] name = [" + image->name + "] \n";
}
return false;
}
@@ -2511,7 +2637,7 @@ static bool ParseImage(Image *image, std::string *err, std::string *warn,
}
return false;
}
return (*LoadImageData)(image, err, warn, 0, 0, &img.at(0),
return (*LoadImageData)(image, image_idx, err, warn, 0, 0, &img.at(0),
static_cast<int>(img.size()), load_image_user_data);
}
@@ -2701,10 +2827,7 @@ static bool ParseBufferView(BufferView *bufferView, std::string *err,
static bool ParseAccessor(Accessor *accessor, std::string *err, const json &o) {
double bufferView = -1.0;
if (!ParseNumberProperty(&bufferView, err, o, "bufferView", true,
"Accessor")) {
return false;
}
ParseNumberProperty(&bufferView, err, o, "bufferView", false, "Accessor");
double byteOffset = 0.0;
ParseNumberProperty(&byteOffset, err, o, "byteOffset", false, "Accessor");
@@ -2786,7 +2909,184 @@ static bool ParseAccessor(Accessor *accessor, std::string *err, const json &o) {
return true;
}
static bool ParsePrimitive(Primitive *primitive, std::string *err,
#ifdef TINYGLTF_ENABLE_DRACO
static void DecodeIndexBuffer(draco::Mesh* mesh, size_t componentSize, std::vector<uint8_t>& outBuffer)
{
if (componentSize == 4)
{
assert(sizeof(mesh->face(draco::FaceIndex(0))[0]) == componentSize);
memcpy(outBuffer.data(), &mesh->face(draco::FaceIndex(0))[0], outBuffer.size());
}
else
{
size_t faceStride = componentSize * 3;
for (draco::FaceIndex f(0); f < mesh->num_faces(); ++f)
{
const draco::Mesh::Face& face = mesh->face(f);
if (componentSize == 2)
{
uint16_t indices[3] = { (uint16_t)face[0].value(), (uint16_t)face[1].value(), (uint16_t)face[2].value() };
memcpy(outBuffer.data() + f.value() * faceStride, &indices[0], faceStride);
}
else
{
uint8_t indices[3] = { (uint8_t)face[0].value(), (uint8_t)face[1].value(), (uint8_t)face[2].value() };
memcpy(outBuffer.data() + f.value() * faceStride, &indices[0], faceStride);
}
}
}
}
template<typename T>
static bool GetAttributeForAllPoints(draco::Mesh* mesh, const draco::PointAttribute* pAttribute, std::vector<uint8_t>& outBuffer)
{
size_t byteOffset = 0;
T values[4] = { 0, 0, 0, 0 };
for (draco::PointIndex i(0); i < mesh->num_points(); ++i)
{
const draco::AttributeValueIndex val_index = pAttribute->mapped_index(i);
if (!pAttribute->ConvertValue<T>(val_index, pAttribute->num_components(), values))
return false;
memcpy(outBuffer.data() + byteOffset, &values[0], sizeof(T) * pAttribute->num_components());
byteOffset += sizeof(T) * pAttribute->num_components();
}
return true;
}
static bool GetAttributeForAllPoints(uint32_t componentType, draco::Mesh* mesh, const draco::PointAttribute* pAttribute, std::vector<uint8_t>& outBuffer)
{
bool decodeResult = false;
switch (componentType)
{
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
decodeResult = GetAttributeForAllPoints<uint8_t>(mesh, pAttribute, outBuffer);
break;
case TINYGLTF_COMPONENT_TYPE_BYTE:
decodeResult = GetAttributeForAllPoints<int8_t>(mesh, pAttribute, outBuffer);
break;
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
decodeResult = GetAttributeForAllPoints<uint16_t>(mesh, pAttribute, outBuffer);
break;
case TINYGLTF_COMPONENT_TYPE_SHORT:
decodeResult = GetAttributeForAllPoints<int16_t>(mesh, pAttribute, outBuffer);
break;
case TINYGLTF_COMPONENT_TYPE_INT:
decodeResult = GetAttributeForAllPoints<int32_t>(mesh, pAttribute, outBuffer);
break;
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT:
decodeResult = GetAttributeForAllPoints<uint32_t>(mesh, pAttribute, outBuffer);
break;
case TINYGLTF_COMPONENT_TYPE_FLOAT:
decodeResult = GetAttributeForAllPoints<float>(mesh, pAttribute, outBuffer);
break;
case TINYGLTF_COMPONENT_TYPE_DOUBLE:
decodeResult = GetAttributeForAllPoints<double>(mesh, pAttribute, outBuffer);
break;
default:
return false;
}
return decodeResult;
}
static bool ParseDracoExtension(Primitive *primitive, Model *model, std::string *err, const Value &dracoExtensionValue)
{
auto bufferViewValue = dracoExtensionValue.Get("bufferView");
if (!bufferViewValue.IsInt())
return false;
auto attributesValue = dracoExtensionValue.Get("attributes");
if (!attributesValue.IsObject())
return false;
auto attributesObject = attributesValue.Get<Value::Object>();
int bufferView = bufferViewValue.Get<int>();
BufferView& view = model->bufferViews[bufferView];
Buffer& buffer = model->buffers[view.buffer];
// BufferView has already been decoded
if (view.dracoDecoded)
return true;
view.dracoDecoded = true;
const char* bufferViewData = reinterpret_cast<const char*>(buffer.data.data() + view.byteOffset);
size_t bufferViewSize = view.byteLength;
// decode draco
draco::DecoderBuffer decoderBuffer;
decoderBuffer.Init(bufferViewData, bufferViewSize);
draco::Decoder decoder;
auto decodeResult = decoder.DecodeMeshFromBuffer(&decoderBuffer);
if (!decodeResult.ok()) {
return false;
}
const std::unique_ptr<draco::Mesh>& mesh = decodeResult.value();
// create new bufferView for indices
if (primitive->indices >= 0)
{
int32_t componentSize = GetComponentSizeInBytes(model->accessors[primitive->indices].componentType);
Buffer decodedIndexBuffer;
decodedIndexBuffer.data.resize(mesh->num_faces() * 3 * componentSize);
DecodeIndexBuffer(mesh.get(), componentSize, decodedIndexBuffer.data);
model->buffers.emplace_back(std::move(decodedIndexBuffer));
BufferView decodedIndexBufferView;
decodedIndexBufferView.buffer = int(model->buffers.size() - 1);
decodedIndexBufferView.byteLength = int(mesh->num_faces() * 3 * componentSize);
decodedIndexBufferView.byteOffset = 0;
decodedIndexBufferView.byteStride = 0;
decodedIndexBufferView.target = TINYGLTF_TARGET_ARRAY_BUFFER;
model->bufferViews.emplace_back(std::move(decodedIndexBufferView));
model->accessors[primitive->indices].bufferView = int(model->bufferViews.size() - 1);
model->accessors[primitive->indices].count = int(mesh->num_faces() * 3);
}
for (const auto& attribute : attributesObject)
{
if (!attribute.second.IsInt())
return false;
auto primitiveAttribute = primitive->attributes.find(attribute.first);
if (primitiveAttribute == primitive->attributes.end())
return false;
int dracoAttributeIndex = attribute.second.Get<int>();
const auto pAttribute = mesh->GetAttributeByUniqueId(dracoAttributeIndex);
const auto pBuffer = pAttribute->buffer();
const auto componentType = model->accessors[primitiveAttribute->second].componentType;
// Create a new buffer for this decoded buffer
Buffer decodedBuffer;
size_t bufferSize = mesh->num_points() * pAttribute->num_components() * GetComponentSizeInBytes(componentType);
decodedBuffer.data.resize(bufferSize);
if (!GetAttributeForAllPoints(componentType, mesh.get(), pAttribute, decodedBuffer.data))
return false;
model->buffers.emplace_back(std::move(decodedBuffer));
BufferView decodedBufferView;
decodedBufferView.buffer = int(model->buffers.size() - 1);
decodedBufferView.byteLength = bufferSize;
decodedBufferView.byteOffset = pAttribute->byte_offset();
decodedBufferView.byteStride = pAttribute->byte_stride();
decodedBufferView.target = primitive->indices >= 0 ? TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER : TINYGLTF_TARGET_ARRAY_BUFFER;
model->bufferViews.emplace_back(std::move(decodedBufferView));
model->accessors[primitiveAttribute->second].bufferView = int(model->bufferViews.size() - 1);
model->accessors[primitiveAttribute->second].count = int(mesh->num_points());
}
return true;
}
#endif
static bool ParsePrimitive(Primitive *primitive, Model *model, std::string *err,
const json &o) {
double material = -1.0;
ParseNumberProperty(&material, err, o, "material", false);
@@ -2826,10 +3126,22 @@ static bool ParsePrimitive(Primitive *primitive, std::string *err,
ParseExtrasProperty(&(primitive->extras), o);
ParseExtensionsProperty(&primitive->extensions, err, o);
#ifdef TINYGLTF_ENABLE_DRACO
auto dracoExtension = primitive->extensions.find("KHR_draco_mesh_compression");
if (dracoExtension != primitive->extensions.end())
{
ParseDracoExtension(primitive, model, err, dracoExtension->second);
}
#else
(void)model;
#endif
return true;
}
static bool ParseMesh(Mesh *mesh, std::string *err, const json &o) {
static bool ParseMesh(Mesh *mesh, Model *model, std::string *err, const json &o) {
ParseStringProperty(&mesh->name, err, o, "name", false);
mesh->primitives.clear();
@@ -2838,7 +3150,7 @@ static bool ParseMesh(Mesh *mesh, std::string *err, const json &o) {
for (json::const_iterator i = primObject.value().begin();
i != primObject.value().end(); i++) {
Primitive primitive;
if (ParsePrimitive(&primitive, err, i.value())) {
if (ParsePrimitive(&primitive, model, err, i.value())) {
// Only add the primitive if the parsing succeeds.
mesh->primitives.push_back(primitive);
}
@@ -3040,13 +3352,8 @@ static bool ParseAnimation(Animation *animation, std::string *err,
}
return false;
}
if (!ParseStringProperty(&sampler.interpolation, err, s,
"interpolation", true)) {
if (err) {
(*err) += "`interpolation` field is missing in animation.sampler\n";
}
return false;
}
ParseStringProperty(&sampler.interpolation, err, s, "interpolation",
false);
if (!ParseNumberProperty(&outputIndex, err, s, "output", true)) {
if (err) {
(*err) += "`output` field is missing in animation.sampler\n";
@@ -3497,7 +3804,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
return false;
}
Mesh mesh;
if (!ParseMesh(&mesh, err, it->get<json>())) {
if (!ParseMesh(&mesh, model, err, it->get<json>())) {
return false;
}
@@ -3515,7 +3822,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
{
if (primitive.indices > -1) // has indices from parsing step, must be Element Array Buffer
{
model->bufferViews[size_t(model->accessors[size_t(primitive.indices)].bufferView)]
model->bufferViews[model->accessors[primitive.indices].bufferView]
.target = TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER;
// we could optionally check if acessors' bufferView type is Scalar, as it should be
}
@@ -3639,15 +3946,16 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
json::const_iterator it(root.begin());
json::const_iterator itEnd(root.end());
for (; it != itEnd; it++) {
int idx = 0;
for (; it != itEnd; it++, idx++) {
if (!it.value().is_object()) {
if (err) {
(*err) += "`images' does not contain an JSON object.";
(*err) += "image[" + std::to_string(idx) + "] is not a JSON object.";
}
return false;
}
Image image;
if (!ParseImage(&image, err, warn, it.value(), base_dir, &fs,
if (!ParseImage(&image, idx, err, warn, it.value(), base_dir, &fs,
&this->LoadImageData, load_image_user_data_)) {
return false;
}
@@ -3657,7 +3965,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
if (size_t(image.bufferView) >= model->bufferViews.size()) {
if (err) {
std::stringstream ss;
ss << "bufferView \"" << image.bufferView
ss << "image[" << idx << "] bufferView \"" << image.bufferView
<< "\" not found in the scene." << std::endl;
(*err) += ss.str();
}
@@ -3674,7 +3982,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
}
return false;
}
bool ret = LoadImageData(&image, err, warn, image.width, image.height,
bool ret = LoadImageData(&image, idx, err, warn, image.width, image.height,
&buffer.data[bufferView.byteOffset],
static_cast<int>(bufferView.byteLength),
load_image_user_data_);
@@ -4603,8 +4911,8 @@ static void WriteBinaryGltfFile(const std::string &output,
// 12 bytes for header, JSON content length, 8 bytes for JSON chunk info, padding
const int length = 12 + 8 + int(content.size()) + padding_size;
gltfFile.write(header.c_str(), std::streamsize(header.size()));
gltfFile.write(header.c_str(), header.size());
gltfFile.write(reinterpret_cast<const char *>(&version), sizeof(version));
gltfFile.write(reinterpret_cast<const char *>(&length), sizeof(length));
@@ -4613,12 +4921,12 @@ static void WriteBinaryGltfFile(const std::string &output,
const int model_format = 0x4E4F534A;
gltfFile.write(reinterpret_cast<const char *>(&model_length), sizeof(model_length));
gltfFile.write(reinterpret_cast<const char *>(&model_format), sizeof(model_format));
gltfFile.write(content.c_str(), std::streamsize(content.size()));
gltfFile.write(content.c_str(), content.size());
// Chunk must be multiplies of 4, so pad with spaces
if (padding_size > 0) {
const std::string padding = std::string(size_t(padding_size), ' ');
gltfFile.write(padding.c_str(), std::streamsize(padding.size()));
const std::string padding = std::string(padding_size, ' ');
gltfFile.write(padding.c_str(), padding.size());
}
}

View File

@@ -1,294 +0,0 @@
//
// TinyGLTF utility functions
//
//
// The MIT License (MIT)
//
// Copyright (c) 2015 - 2018 Syoyo Fujita, Aurélien Chatelain and many
// contributors.
//
#include <iostream>
#include "tiny_gltf.h"
namespace tinygltf {
namespace util {
static std::string PrintMode(int mode) {
if (mode == TINYGLTF_MODE_POINTS) {
return "POINTS";
} else if (mode == TINYGLTF_MODE_LINE) {
return "LINE";
} else if (mode == TINYGLTF_MODE_LINE_LOOP) {
return "LINE_LOOP";
} else if (mode == TINYGLTF_MODE_TRIANGLES) {
return "TRIANGLES";
} else if (mode == TINYGLTF_MODE_TRIANGLE_FAN) {
return "TRIANGLE_FAN";
} else if (mode == TINYGLTF_MODE_TRIANGLE_STRIP) {
return "TRIANGLE_STRIP";
}
return "**UNKNOWN**";
}
static std::string PrintTarget(int target) {
if (target == 34962) {
return "GL_ARRAY_BUFFER";
} else if (target == 34963) {
return "GL_ELEMENT_ARRAY_BUFFER";
} else {
return "**UNKNOWN**";
}
}
static std::string PrintType(int ty) {
if (ty == TINYGLTF_TYPE_SCALAR) {
return "SCALAR";
} else if (ty == TINYGLTF_TYPE_VECTOR) {
return "VECTOR";
} else if (ty == TINYGLTF_TYPE_VEC2) {
return "VEC2";
} else if (ty == TINYGLTF_TYPE_VEC3) {
return "VEC3";
} else if (ty == TINYGLTF_TYPE_VEC4) {
return "VEC4";
} else if (ty == TINYGLTF_TYPE_MATRIX) {
return "MATRIX";
} else if (ty == TINYGLTF_TYPE_MAT2) {
return "MAT2";
} else if (ty == TINYGLTF_TYPE_MAT3) {
return "MAT3";
} else if (ty == TINYGLTF_TYPE_MAT4) {
return "MAT4";
}
return "**UNKNOWN**";
}
static std::string PrintComponentType(int ty) {
if (ty == TINYGLTF_COMPONENT_TYPE_BYTE) {
return "BYTE";
} else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
return "UNSIGNED_BYTE";
} else if (ty == TINYGLTF_COMPONENT_TYPE_SHORT) {
return "SHORT";
} else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
return "UNSIGNED_SHORT";
} else if (ty == TINYGLTF_COMPONENT_TYPE_INT) {
return "INT";
} else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) {
return "UNSIGNED_INT";
} else if (ty == TINYGLTF_COMPONENT_TYPE_FLOAT) {
return "FLOAT";
} else if (ty == TINYGLTF_COMPONENT_TYPE_DOUBLE) {
return "DOUBLE";
}
return "**UNKNOWN**";
}
static std::string PrintWrapMode(int mode) {
if (mode == TINYGLTF_TEXTURE_WRAP_REPEAT) {
return "REPEAT";
} else if (mode == TINYGLTF_TEXTURE_WRAP_CLAMP_TO_EDGE) {
return "CLAMP_TO_EDGE";
} else if (mode == TINYGLTF_TEXTURE_WRAP_MIRRORED_REPEAT) {
return "MIRRORED_REPEAT";
}
return "**UNKNOWN**";
}
static std::string PrintFilterMode(int mode) {
if (mode == TINYGLTF_TEXTURE_FILTER_NEAREST) {
return "NEAREST";
} else if (mode == TINYGLTF_TEXTURE_FILTER_LINEAR) {
return "LINEAR";
} else if (mode == TINYGLTF_TEXTURE_FILTER_NEAREST_MIPMAP_NEAREST) {
return "NEAREST_MIPMAP_NEAREST";
} else if (mode == TINYGLTF_TEXTURE_FILTER_NEAREST_MIPMAP_LINEAR) {
return "NEAREST_MIPMAP_LINEAR";
} else if (mode == TINYGLTF_TEXTURE_FILTER_LINEAR_MIPMAP_NEAREST) {
return "LINEAR_MIPMAP_NEAREST";
} else if (mode == TINYGLTF_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR) {
return "LINEAR_MIPMAP_LINEAR";
}
return "**UNKNOWN**";
}
static int GetAnimationSamplerInputCount(const tinygltf::AnimationSampler &sampler, const tinygltf::Model &model)
{
const tinygltf::Accessor &accessor = model.accessors[sampler.input];
return accessor.count;
}
static int GetAnimationSamplerOutputCount(const tinygltf::AnimationSampler &sampler, const tinygltf::Model &model)
{
const tinygltf::Accessor &accessor = model.accessors[sampler.output];
return accessor.count;
}
static bool GetAnimationSamplerInputMinMax(const tinygltf::AnimationSampler &sampler, const tinygltf::Model &model, float *min_value, float *max_value)
{
const tinygltf::Accessor &accessor = model.accessors[sampler.input];
// Assume scalar value.
if ((accessor.minValues.size() > 0) &&
(accessor.maxValues.size() > 0)) {
(*min_value) = accessor.minValues[0];
(*max_value) = accessor.maxValues[0];
return true;
} else {
(*min_value) = 0.0f;
(*max_value) = 0.0f;
return false;
}
}
// Utility function for decoding animation value
static inline float DecodeAnimationChannelValue(int8_t c) {
return std::max(float(c) / 127.0f, -1.0f);
}
static inline float DecodeAnimationChannelValue(uint8_t c) {
return float(c) / 255.0f;
}
static inline float DecodeAnimationChannelValue(int16_t c) {
return std::max(float(c) / 32767.0f, -1.0f);
}
static inline float DecodeAnimationChannelValue(uint16_t c) {
return float(c) / 65525.0f;
}
static bool DecodeScalarAnimationValue(const size_t i, const tinygltf::Accessor &accessor, const tinygltf::Model &model, float *scalar)
{
const BufferView &bufferView = model.bufferViews[accessor.bufferView];
const Buffer &buffer = model.buffers[bufferView.buffer];
const uint8_t *addr = GetBufferAddress(i, accessor, bufferView, buffer);
if (addr == nullptr) {
std::cerr << "Invalid glTF data?" << std::endl;
return false;
}
float value = 0.0f;
if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_BYTE) {
value = DecodeAnimationChannelValue(*(reinterpret_cast<const int8_t*>(addr)));
} else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
value = DecodeAnimationChannelValue(*(reinterpret_cast<const uint8_t*>(addr)));
} else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_SHORT) {
value = DecodeAnimationChannelValue(*(reinterpret_cast<const int16_t*>(addr)));
} else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
value = DecodeAnimationChannelValue(*(reinterpret_cast<const uint16_t*>(addr)));
} else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT) {
value = *(reinterpret_cast<const float*>(addr));
} else {
std::cerr << "??? Unknown componentType : " << PrintComponentType(accessor.componentType) << std::endl;
return false;
}
(*scalar) = value;
return true;
}
static bool DecodeTranslationAnimationValue(const size_t i, const tinygltf::Accessor &accessor, const tinygltf::Model &model, float *xyz)
{
if (accessor.componentType != TINYGLTF_COMPONENT_TYPE_FLOAT) {
std::cerr << "`translation` must be float type." << std::endl;
return false;
}
const BufferView &bufferView = model.bufferViews[accessor.bufferView];
const Buffer &buffer = model.buffers[bufferView.buffer];
const uint8_t *addr = GetBufferAddress(i, accessor, bufferView, buffer);
if (addr == nullptr) {
std::cerr << "Invalid glTF data?" << std::endl;
return 0.0f;
}
const float *ptr = reinterpret_cast<const float*>(addr);
xyz[0] = *(ptr + 0);
xyz[1] = *(ptr + 1);
xyz[2] = *(ptr + 2);
return true;
}
static bool DecodeScaleAnimationValue(const size_t i, const tinygltf::Accessor &accessor, const tinygltf::Model &model, float *xyz)
{
if (accessor.componentType != TINYGLTF_COMPONENT_TYPE_FLOAT) {
std::cerr << "`scale` must be float type." << std::endl;
return false;
}
const BufferView &bufferView = model.bufferViews[accessor.bufferView];
const Buffer &buffer = model.buffers[bufferView.buffer];
const uint8_t *addr = GetBufferAddress(i, accessor, bufferView, buffer);
if (addr == nullptr) {
std::cerr << "Invalid glTF data?" << std::endl;
return 0.0f;
}
const float *ptr = reinterpret_cast<const float*>(addr);
xyz[0] = *(ptr + 0);
xyz[1] = *(ptr + 1);
xyz[2] = *(ptr + 2);
return true;
}
static bool DecodeRotationAnimationValue(const size_t i, const tinygltf::Accessor &accessor, const tinygltf::Model &model, float *xyzw)
{
const BufferView &bufferView = model.bufferViews[accessor.bufferView];
const Buffer &buffer = model.buffers[bufferView.buffer];
const uint8_t *addr = GetBufferAddress(i, accessor, bufferView, buffer);
if (addr == nullptr) {
std::cerr << "Invalid glTF data?" << std::endl;
return false;
}
float value = 0.0f;
if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_BYTE) {
xyzw[0] = DecodeAnimationChannelValue(*(reinterpret_cast<const int8_t*>(addr) + 0));
xyzw[1] = DecodeAnimationChannelValue(*(reinterpret_cast<const int8_t*>(addr) + 1));
xyzw[2] = DecodeAnimationChannelValue(*(reinterpret_cast<const int8_t*>(addr) + 2));
xyzw[3] = DecodeAnimationChannelValue(*(reinterpret_cast<const int8_t*>(addr) + 3));
} else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
xyzw[0] = DecodeAnimationChannelValue(*(reinterpret_cast<const uint8_t*>(addr) + 0));
xyzw[1] = DecodeAnimationChannelValue(*(reinterpret_cast<const uint8_t*>(addr) + 1));
xyzw[2] = DecodeAnimationChannelValue(*(reinterpret_cast<const uint8_t*>(addr) + 2));
xyzw[3] = DecodeAnimationChannelValue(*(reinterpret_cast<const uint8_t*>(addr) + 3));
} else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_SHORT) {
xyzw[0] = DecodeAnimationChannelValue(*(reinterpret_cast<const int16_t*>(addr) + 0));
xyzw[1] = DecodeAnimationChannelValue(*(reinterpret_cast<const int16_t*>(addr) + 1));
xyzw[2] = DecodeAnimationChannelValue(*(reinterpret_cast<const int16_t*>(addr) + 2));
xyzw[3] = DecodeAnimationChannelValue(*(reinterpret_cast<const int16_t*>(addr) + 3));
} else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
xyzw[0] = DecodeAnimationChannelValue(*(reinterpret_cast<const uint16_t*>(addr) + 0));
xyzw[1] = DecodeAnimationChannelValue(*(reinterpret_cast<const uint16_t*>(addr) + 1));
xyzw[2] = DecodeAnimationChannelValue(*(reinterpret_cast<const uint16_t*>(addr) + 2));
xyzw[3] = DecodeAnimationChannelValue(*(reinterpret_cast<const uint16_t*>(addr) + 3));
} else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT) {
xyzw[0] = *(reinterpret_cast<const float*>(addr) + 0);
xyzw[1] = *(reinterpret_cast<const float*>(addr) + 1);
xyzw[2] = *(reinterpret_cast<const float*>(addr) + 2);
xyzw[3] = *(reinterpret_cast<const float*>(addr) + 3);
} else {
std::cerr << "??? Unknown componentType : " << PrintComponentType(accessor.componentType) << std::endl;
return false;
}
return true;
}
} // namespace util
} // namespace tinygltf