Compare commits

..

2 Commits

Author SHA1 Message Date
Syoyo Fujita
94c47b15c3 Introduce tiny_gltf_util.h header file which contains some useful helper/util functions. 2018-12-29 18:28:35 +09:00
Syoyo Fujita
48b3422925 Initial addition of animation data dumper.
Add an utility function to get buffer byte address.
2018-12-28 22:26:47 +09:00
13 changed files with 561 additions and 402 deletions

View File

@@ -46,14 +46,11 @@ v2.0.0 release(22 Aug, 2018)!
* Load from memory
* Custom callback handler
* [x] Image load
* 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
@@ -65,10 +62,10 @@ 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)
* [x] Load Draco compressed mesh
* [x] Save Draco compressed mesh
* [ ] Load Draco compressed mesh
* [ ] Support `extensions` and `extras` property
* [ ] HDR image?
* [ ] OpenEXR extension through TinyEXR.
@@ -132,8 +129,6 @@ 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

@@ -0,0 +1,6 @@
# 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

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

View File

@@ -0,0 +1,178 @@
//
// 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;
}

View File

@@ -1,21 +0,0 @@
# 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

@@ -1,44 +0,0 @@
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 = texture(tex, texcoord) * vec4((0.3 + 0.7 * lum) * sun_color, 1.0);\n\
color = texture2D(tex, texcoord) * vec4((0.3 + 0.7 * lum) * sun_color, 1.0);\n\
}\n\
";

View File

@@ -1,10 +1,8 @@
cmake_minimum_required(VERSION 3.5)
cmake_minimum_required(VERSION 3.6)
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 )
@@ -23,16 +21,6 @@ endif (APPLE)
set(CMAKE_CXX_STANDARD 11)
if (${DRACO_DIR} STREQUAL "")
else ()
# TODO(syoyo): better CMake script for draco
add_definitions(-DTINYGLTF_ENABLE_DRACO)
include_directories(${DRACO_DIR}/include)
link_directories(${DRACO_DIR}/lib)
set(DRACO_LIBRARY draco)
endif ()
include_directories(
../../
../common
@@ -47,7 +35,6 @@ add_executable(glview
)
target_link_libraries ( glview
${DRACO_LIBRARY}
${GLFW3_UNIX_LINK_LIBRARIES}
${GLEW_LIBRARY}
${GLFW3_glfw_LIBRARY}

View File

@@ -27,17 +27,6 @@ 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,14 +677,10 @@ static void DrawNode(tinygltf::Model &model, const tinygltf::Node &node) {
// std::cout << it->first << std::endl;
// FIXME(syoyo): Refactor.
// DrawCurves(scene, it->second);
if (node.mesh > -1) {
assert(node.mesh < model.meshes.size());
DrawMesh(model, model.meshes[node.mesh]);
}
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]]);
}
@@ -790,12 +786,10 @@ int main(int argc, char **argv) {
return -1;
}
std::stringstream ss;
ss << "Simple glTF viewer: " << input_filename;
char title[1024];
sprintf(title, "Simple glTF viewer: %s", input_filename.c_str());
std::string title = ss.str();
window = glfwCreateWindow(width, height, title.c_str(), NULL, NULL);
window = glfwCreateWindow(width, height, title, NULL, NULL);
if (window == NULL) {
std::cerr << "Failed to open GLFW window. " << std::endl;
glfwTerminate();

View File

@@ -26,7 +26,6 @@
// THE SOFTWARE.
// Version:
// - v2.1.0 Add draco compression.
// - v2.0.1 Add comparsion feature(Thanks to @Selmar).
// - v2.0.0 glTF 2.0!.
//
@@ -48,12 +47,6 @@
#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)
@@ -63,6 +56,7 @@ namespace tinygltf {
#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)
@@ -113,6 +107,7 @@ 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)
@@ -146,12 +141,6 @@ 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,
@@ -429,6 +418,7 @@ struct AnimationSampler {
AnimationSampler() : input(-1), output(-1), interpolation("LINEAR") {}
bool operator==(const AnimationSampler &) const;
};
struct Animation {
@@ -539,9 +529,8 @@ 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), dracoDecoded(false) {}
BufferView() : byteOffset(0), byteStride(0) {}
bool operator==(const BufferView &) const;
};
@@ -549,11 +538,11 @@ struct Accessor {
int bufferView; // optional in spec but required here since sparse accessor
// are not supported
std::string name;
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_*** ..
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_*** ..
Value extras;
std::vector<double> minValues; // optional
@@ -602,6 +591,7 @@ struct Accessor {
bool operator==(const tinygltf::Accessor &) const;
};
struct PerspectiveCamera {
double aspectRatio; // min > 0
double yfov; // required. min > 0
@@ -660,7 +650,6 @@ struct Primitive {
// where each target is a dict with attribues in ["POSITION, "NORMAL",
// "TANGENT"] pointing
// to their corresponding accessors
ExtensionMap extensions;
Value extras;
Primitive() {
@@ -790,6 +779,14 @@ 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,
@@ -804,7 +801,7 @@ enum SectionCheck {
///
/// LoadImageDataFunction type. Signature for custom image loading callbacks.
///
typedef bool (*LoadImageDataFunction)(Image *, const int, std::string *, std::string *,
typedef bool (*LoadImageDataFunction)(Image *, std::string *, std::string *,
int, int, const unsigned char *, int,
void *);
@@ -816,7 +813,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, const int image_idx, std::string *err, std::string *warn,
bool LoadImageData(Image *image, std::string *err, std::string *warn,
int req_width, int req_height, const unsigned char *bytes,
int size, void *);
#endif
@@ -1063,19 +1060,14 @@ class TinyGLTF {
#endif
#endif
#include "json.hpp"
#ifdef TINYGLTF_ENABLE_DRACO
#include "draco/core/decoder_buffer.h"
#include "draco/compression/decode.h"
#endif
#include "./json.hpp"
#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__
@@ -1200,8 +1192,7 @@ 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->dracoDecoded == other.dracoDecoded;
this->target == other.target && this->extras == other.extras;
}
bool Camera::operator==(const Camera &other) const {
return this->name == other.name && this->extensions == other.extensions &&
@@ -1597,9 +1588,9 @@ void TinyGLTF::SetImageLoader(LoadImageDataFunction func, void *user_data) {
}
#ifndef TINYGLTF_NO_STB_IMAGE
bool LoadImageData(Image *image, const int image_idx, std::string *err, std::string *warn,
bool LoadImageData(Image *image, std::string *err, std::string *warn,
int req_width, int req_height, const unsigned char *bytes,
int size, void *user_data) {
int size, void *) {
(void)warn;
int w, h, comp, req_comp;
@@ -1619,7 +1610,7 @@ bool LoadImageData(Image *image, const int image_idx, std::string *err, std::str
if (!data) {
// NOTE: you can use `warn` instead of `err`
if (err) {
(*err) += "Unknown image format. STB cannot decode image data for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\". Proably 16bit PNG?\n";
(*err) += "Unknown image format.\n";
}
return false;
}
@@ -1627,7 +1618,7 @@ bool LoadImageData(Image *image, const int image_idx, std::string *err, std::str
if (w < 1 || h < 1) {
free(data);
if (err) {
(*err) += "Invalid image data for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n";
(*err) += "Invalid image data.\n";
}
return false;
}
@@ -1636,7 +1627,7 @@ bool LoadImageData(Image *image, const int image_idx, std::string *err, std::str
if (req_width != w) {
free(data);
if (err) {
(*err) += "Image width mismatch for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n";
(*err) += "Image width mismatch.\n";
}
return false;
}
@@ -1646,7 +1637,7 @@ bool LoadImageData(Image *image, const int image_idx, std::string *err, std::str
if (req_height != h) {
free(data);
if (err) {
(*err) += "Image height mismatch. for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n";
(*err) += "Image height mismatch.\n";
}
return false;
}
@@ -1750,18 +1741,6 @@ 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");
@@ -1777,7 +1756,6 @@ bool FileExists(const std::string &abs_filename, void *) {
} else {
ret = false;
}
#endif
return ret;
}
@@ -1831,33 +1809,6 @@ 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) {
@@ -1889,7 +1840,6 @@ bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
f.close();
return true;
#endif
}
bool WriteWholeFile(std::string *err, const std::string &filepath,
@@ -2070,6 +2020,21 @@ 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()) {
@@ -2436,7 +2401,7 @@ static bool ParseAsset(Asset *asset, std::string *err, const json &o) {
return true;
}
static bool ParseImage(Image *image, const int image_idx, std::string *err, std::string *warn,
static bool ParseImage(Image *image, std::string *err, std::string *warn,
const json &o, const std::string &basedir,
FsCallbacks *fs,
LoadImageDataFunction *LoadImageData = nullptr,
@@ -2448,25 +2413,24 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err, std:
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[" + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n";
"defined for Image.\n";
}
return false;
}
if (!hasBufferView && !hasURI) {
if (err) {
(*err) += "Neither required `bufferView` nor `uri` defined for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n";
(*err) += "Neither required `bufferView` nor `uri` defined for Image.\n";
}
return false;
}
ParseStringProperty(&image->name, err, o, "name", false);
ParseExtensionsProperty(&image->extensions, err, o);
ParseExtrasProperty(&image->extras, o);
@@ -2474,7 +2438,7 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err, std:
double bufferView = -1;
if (!ParseNumberProperty(&bufferView, err, o, "bufferView", true)) {
if (err) {
(*err) += "Failed to parse `bufferView` for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n";
(*err) += "Failed to parse `bufferView` for Image.\n";
}
return false;
}
@@ -2504,7 +2468,7 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err, std:
std::string tmp_err;
if (!ParseStringProperty(&uri, &tmp_err, o, "uri", true)) {
if (err) {
(*err) += "Failed to parse `uri` for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\".\n";
(*err) += "Failed to parse `uri` for Image.\n";
}
return false;
}
@@ -2514,7 +2478,7 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err, std:
if (IsDataURI(uri)) {
if (!DecodeDataURI(&img, image->mimeType, uri, 0, false)) {
if (err) {
(*err) += "Failed to decode 'uri' for image[" + std::to_string(image_idx) + "] name = [" + image->name + "]\n";
(*err) += "Failed to decode 'uri' for image parameter.\n";
}
return false;
}
@@ -2527,7 +2491,7 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err, std:
#endif
if (!LoadExternalFile(&img, err, warn, uri, basedir, false, 0, false, fs)) {
if (warn) {
(*warn) += "Failed to load external 'uri' for image[" + std::to_string(image_idx) + "] name = [" + image->name + "]\n";
(*warn) += "Failed to load external 'uri' for image parameter\n";
}
// If the image cannot be loaded, keep uri as image->uri.
return true;
@@ -2535,7 +2499,7 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err, std:
if (img.empty()) {
if (warn) {
(*warn) += "Image data is empty for image[" + std::to_string(image_idx) + "] name = [" + image->name + "] \n";
(*warn) += "Image is empty.\n";
}
return false;
}
@@ -2547,7 +2511,7 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err, std:
}
return false;
}
return (*LoadImageData)(image, image_idx, err, warn, 0, 0, &img.at(0),
return (*LoadImageData)(image, err, warn, 0, 0, &img.at(0),
static_cast<int>(img.size()), load_image_user_data);
}
@@ -2737,7 +2701,10 @@ static bool ParseBufferView(BufferView *bufferView, std::string *err,
static bool ParseAccessor(Accessor *accessor, std::string *err, const json &o) {
double bufferView = -1.0;
ParseNumberProperty(&bufferView, err, o, "bufferView", false, "Accessor");
if (!ParseNumberProperty(&bufferView, err, o, "bufferView", true,
"Accessor")) {
return false;
}
double byteOffset = 0.0;
ParseNumberProperty(&byteOffset, err, o, "byteOffset", false, "Accessor");
@@ -2819,184 +2786,7 @@ static bool ParseAccessor(Accessor *accessor, std::string *err, const json &o) {
return true;
}
#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,
static bool ParsePrimitive(Primitive *primitive, std::string *err,
const json &o) {
double material = -1.0;
ParseNumberProperty(&material, err, o, "material", false);
@@ -3036,20 +2826,10 @@ static bool ParsePrimitive(Primitive *primitive, Model *model, 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);
}
#endif
return true;
}
static bool ParseMesh(Mesh *mesh, Model *model, std::string *err, const json &o) {
static bool ParseMesh(Mesh *mesh, std::string *err, const json &o) {
ParseStringProperty(&mesh->name, err, o, "name", false);
mesh->primitives.clear();
@@ -3058,7 +2838,7 @@ static bool ParseMesh(Mesh *mesh, Model *model, std::string *err, const json &o)
for (json::const_iterator i = primObject.value().begin();
i != primObject.value().end(); i++) {
Primitive primitive;
if (ParsePrimitive(&primitive, model, err, i.value())) {
if (ParsePrimitive(&primitive, err, i.value())) {
// Only add the primitive if the parsing succeeds.
mesh->primitives.push_back(primitive);
}
@@ -3717,7 +3497,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
return false;
}
Mesh mesh;
if (!ParseMesh(&mesh, model, err, it->get<json>())) {
if (!ParseMesh(&mesh, err, it->get<json>())) {
return false;
}
@@ -3735,7 +3515,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[model->accessors[primitive.indices].bufferView]
model->bufferViews[size_t(model->accessors[size_t(primitive.indices)].bufferView)]
.target = TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER;
// we could optionally check if acessors' bufferView type is Scalar, as it should be
}
@@ -3859,16 +3639,15 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
json::const_iterator it(root.begin());
json::const_iterator itEnd(root.end());
int idx = 0;
for (; it != itEnd; it++, idx++) {
for (; it != itEnd; it++) {
if (!it.value().is_object()) {
if (err) {
(*err) += "image[" + std::to_string(idx) + "] is not a JSON object.";
(*err) += "`images' does not contain an JSON object.";
}
return false;
}
Image image;
if (!ParseImage(&image, idx, err, warn, it.value(), base_dir, &fs,
if (!ParseImage(&image, err, warn, it.value(), base_dir, &fs,
&this->LoadImageData, load_image_user_data_)) {
return false;
}
@@ -3878,7 +3657,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 << "image[" << idx << "] bufferView \"" << image.bufferView
ss << "bufferView \"" << image.bufferView
<< "\" not found in the scene." << std::endl;
(*err) += ss.str();
}
@@ -3895,7 +3674,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
}
return false;
}
bool ret = LoadImageData(&image, idx, err, warn, image.width, image.height,
bool ret = LoadImageData(&image, err, warn, image.width, image.height,
&buffer.data[bufferView.byteOffset],
static_cast<int>(bufferView.byteLength),
load_image_user_data_);
@@ -4825,7 +4604,7 @@ 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(), header.size());
gltfFile.write(header.c_str(), std::streamsize(header.size()));
gltfFile.write(reinterpret_cast<const char *>(&version), sizeof(version));
gltfFile.write(reinterpret_cast<const char *>(&length), sizeof(length));
@@ -4834,12 +4613,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(), content.size());
gltfFile.write(content.c_str(), std::streamsize(content.size()));
// Chunk must be multiplies of 4, so pad with spaces
if (padding_size > 0) {
const std::string padding = std::string(padding_size, ' ');
gltfFile.write(padding.c_str(), padding.size());
const std::string padding = std::string(size_t(padding_size), ' ');
gltfFile.write(padding.c_str(), std::streamsize(padding.size()));
}
}

294
tiny_gltf_util.h Normal file
View File

@@ -0,0 +1,294 @@
//
// 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