mirror of
https://github.com/syoyo/tinygltf.git
synced 2026-06-09 11:43:49 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
098dfee982 | ||
|
|
c0cfc1ed95 |
10
.travis.yml
10
.travis.yml
@@ -7,15 +7,15 @@ matrix:
|
||||
sources:
|
||||
- george-edison55-precise-backports
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-3.9
|
||||
- llvm-toolchain-precise-3.7
|
||||
packages:
|
||||
- g++-4.9
|
||||
- clang-3.9
|
||||
- clang-3.7
|
||||
compiler: clang
|
||||
env: COMPILER_VERSION=3.9 BUILD_TYPE=Debug
|
||||
env: COMPILER_VERSION=3.7 BUILD_TYPE=Debug
|
||||
- addons: *1
|
||||
compiler: clang
|
||||
env: COMPILER_VERSION=3.9 BUILD_TYPE=Release
|
||||
env: COMPILER_VERSION=3.7 BUILD_TYPE=Release
|
||||
- addons: &2
|
||||
apt:
|
||||
sources:
|
||||
@@ -30,7 +30,7 @@ matrix:
|
||||
env: COMPILER_VERSION=4.9 BUILD_TYPE=Release EXTRA_CXXFLAGS="-fsanitize=address"
|
||||
- addons: *1
|
||||
compiler: clang
|
||||
env: COMPILER_VERSION=3.9 BUILD_TYPE=Debug CFLAGS="-O0" CXXFLAGS="-O0"
|
||||
env: COMPILER_VERSION=3.7 BUILD_TYPE=Debug CFLAGS="-O0" CXXFLAGS="-O0"
|
||||
|
||||
before_install:
|
||||
- ./.travis-before-install.sh
|
||||
|
||||
18
README.md
18
README.md
@@ -2,12 +2,12 @@
|
||||
|
||||
`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.
|
||||
|
||||
## Status
|
||||
|
||||
v2.0.0 release(22 Aug, 2018)!
|
||||
Work in process(`devel` branch). Very near to release, but need more tests and examples.
|
||||
|
||||
`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.
|
||||
|
||||
## Builds
|
||||
|
||||
@@ -96,15 +96,9 @@ using namespace tinygltf;
|
||||
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)
|
||||
|
||||
if (!warn.empty()) {
|
||||
printf("Warn: %s\n", warn.c_str());
|
||||
}
|
||||
|
||||
bool ret = loader.LoadASCIIFromFile(&model, &err, argv[1]);
|
||||
//bool ret = loader.LoadBinaryFromFile(&model, &err, argv[1]); // for binary glTF(.glb)
|
||||
if (!err.empty()) {
|
||||
printf("Err: %s\n", err.c_str());
|
||||
}
|
||||
|
||||
@@ -99,28 +99,6 @@ void Matrix::LookAt(float m[4][4], float eye[3], float lookat[3],
|
||||
#endif
|
||||
}
|
||||
|
||||
void Matrix::Identity(float m[4][4]) {
|
||||
m[0][0] = 1.0f;
|
||||
m[0][1] = 0.0f;
|
||||
m[0][2] = 0.0f;
|
||||
m[0][3] = 0.0f;
|
||||
|
||||
m[1][0] = 0.0f;
|
||||
m[1][1] = 1.0f;
|
||||
m[1][2] = 0.0f;
|
||||
m[1][3] = 0.0f;
|
||||
|
||||
m[2][0] = 0.0f;
|
||||
m[2][1] = 0.0f;
|
||||
m[2][2] = 1.0f;
|
||||
m[2][3] = 0.0f;
|
||||
|
||||
m[3][0] = 0.0f;
|
||||
m[3][1] = 0.0f;
|
||||
m[3][2] = 0.0f;
|
||||
m[3][3] = 1.0f;
|
||||
}
|
||||
|
||||
void Matrix::Inverse(float m[4][4]) {
|
||||
/*
|
||||
* codes from intel web
|
||||
@@ -217,16 +195,7 @@ void Matrix::Inverse(float m[4][4]) {
|
||||
}
|
||||
}
|
||||
|
||||
void Matrix::Add(float dst[4][4], const float m0[4][4], const float m1[4][4]) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
dst[i][j] += m0[i][j] + m1[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Matrix::Mult(float dst[4][4], const float m0[4][4], const float m1[4][4]) {
|
||||
void Matrix::Mult(float dst[4][4], float m0[4][4], float m1[4][4]) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
dst[i][j] = 0;
|
||||
@@ -237,7 +206,7 @@ void Matrix::Mult(float dst[4][4], const float m0[4][4], const float m1[4][4]) {
|
||||
}
|
||||
}
|
||||
|
||||
void Matrix::MultV(float dst[3], const float m[4][4], const float v[3]) {
|
||||
void Matrix::MultV(float dst[3], float m[4][4], float v[3]) {
|
||||
// printf("v = %f, %f, %f\n", v[0], v[1], v[2]);
|
||||
dst[0] = m[0][0] * v[0] + m[1][0] * v[1] + m[2][0] * v[2] + m[3][0];
|
||||
dst[1] = m[0][1] * v[0] + m[1][1] * v[1] + m[2][1] * v[2] + m[3][1];
|
||||
@@ -245,10 +214,3 @@ void Matrix::MultV(float dst[3], const float m[4][4], const float v[3]) {
|
||||
// printf("m = %f, %f, %f\n", m[3][0], m[3][1], m[3][2]);
|
||||
// printf("dst = %f, %f, %f\n", dst[0], dst[1], dst[2]);
|
||||
}
|
||||
|
||||
void Matrix::MultV4(float dst[4], const float m[4][4], const float v[4]) {
|
||||
dst[0] = m[0][0] * v[0] + m[1][0] * v[1] + m[2][0] * v[2] + m[3][0] * v[3];
|
||||
dst[1] = m[0][1] * v[0] + m[1][1] * v[1] + m[2][1] * v[2] + m[3][1] * v[3];
|
||||
dst[2] = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2] + m[3][2] * v[3];
|
||||
dst[3] = m[0][3] * v[0] + m[1][3] * v[1] + m[2][3] * v[2] + m[3][3] * v[3];
|
||||
}
|
||||
|
||||
@@ -10,11 +10,8 @@ public:
|
||||
static void LookAt(float m[4][4], float eye[3], float lookat[3],
|
||||
float up[3]);
|
||||
static void Inverse(float m[4][4]);
|
||||
static void Identity(float m[4][4]);
|
||||
static void Add(float dst[4][4], const float m0[4][4], const float m1[4][4]);
|
||||
static void Mult(float dst[4][4], const float m0[4][4], const float m1[4][4]);
|
||||
static void MultV(float dst[3], const float m[4][4], const float v[3]);
|
||||
static void MultV4(float dst[4], const float m[4][4], const float v[4]);
|
||||
static void Mult(float dst[4][4], float m0[4][4], float m1[4][4]);
|
||||
static void MultV(float dst[3], float m[4][4], float v[3]);
|
||||
};
|
||||
|
||||
#endif //
|
||||
|
||||
@@ -52,6 +52,11 @@
|
||||
#include <math.h>
|
||||
#include "trackball.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4244)
|
||||
#pragma warning(disable : 4305)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This size should really be based on the distance from the center of
|
||||
* rotation to the point on the object underneath the mouse. That
|
||||
@@ -168,11 +173,11 @@ void trackball(float q[4], float p1x, float p1y, float p2x, float p2y) {
|
||||
/*
|
||||
* Avoid problems with out-of-control values...
|
||||
*/
|
||||
if (t > 1.0)
|
||||
t = 1.0;
|
||||
if (t < -1.0)
|
||||
t = -1.0;
|
||||
phi = 2.0 * asin(t);
|
||||
if (t > 1.0f)
|
||||
t = 1.0f;
|
||||
if (t < -1.0f)
|
||||
t = -1.0f;
|
||||
phi = 2.0f * asinf(t);
|
||||
|
||||
axis_to_quat(a, phi, q);
|
||||
}
|
||||
|
||||
@@ -19,8 +19,7 @@
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include "tiny_gltf.h"
|
||||
|
||||
//#define BUFFER_OFFSET(i) ((char *)NULL + (i))
|
||||
#define BUFFER_OFFSET(i) (reinterpret_cast<void *>(i))
|
||||
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
|
||||
|
||||
#define CheckGLErrors(desc) \
|
||||
{ \
|
||||
@@ -252,7 +251,7 @@ static void SetupMeshState(tinygltf::Model &model, GLuint progId) {
|
||||
const tinygltf::BufferView &bufferView = model.bufferViews[i];
|
||||
if (bufferView.target == 0) {
|
||||
std::cout << "WARN: bufferView.target is zero" << std::endl;
|
||||
continue; // Unsupported or not directly used bufferView.
|
||||
continue; // Unsupported bufferView.
|
||||
}
|
||||
|
||||
const tinygltf::Buffer &buffer = model.buffers[bufferView.buffer];
|
||||
@@ -529,13 +528,6 @@ static void DrawMesh(tinygltf::Model &model, const tinygltf::Mesh &mesh) {
|
||||
for (; it != itEnd; it++) {
|
||||
assert(it->second >= 0);
|
||||
const tinygltf::Accessor &accessor = model.accessors[it->second];
|
||||
const tinygltf::BufferView &bufferView = model.bufferViews[accessor.bufferView];
|
||||
|
||||
if (bufferView.target == 0) {
|
||||
// Unsupported or not directly used buffer
|
||||
continue;
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, gBufferState[accessor.bufferView].vb);
|
||||
CheckErrors("bind buffer");
|
||||
int size = 1;
|
||||
@@ -675,10 +667,7 @@ 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 >= 0) && (node.mesh < int(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++) {
|
||||
@@ -688,7 +677,7 @@ static void DrawNode(tinygltf::Model &model, const tinygltf::Node &node) {
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
static void DrawModel(tinygltf::Model &model, size_t scene_idx) {
|
||||
static void DrawModel(tinygltf::Model &model) {
|
||||
#if 0
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator it(scene.meshes.begin());
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(scene.meshes.end());
|
||||
@@ -699,8 +688,9 @@ static void DrawModel(tinygltf::Model &model, size_t scene_idx) {
|
||||
}
|
||||
#else
|
||||
|
||||
assert(scene_idx < model.scenes.size());
|
||||
const tinygltf::Scene &scene = model.scenes[scene_idx];
|
||||
// TODO(syoyo): Support non-default scenes.
|
||||
assert(model.defaultScene >= 0);
|
||||
const tinygltf::Scene &scene = model.scenes[model.defaultScene];
|
||||
for (size_t i = 0; i < scene.nodes.size(); i++) {
|
||||
DrawNode(model, model.nodes[scene.nodes[i]]);
|
||||
}
|
||||
@@ -770,18 +760,8 @@ int main(int argc, char **argv) {
|
||||
|
||||
Init();
|
||||
|
||||
if (model.scenes.empty()) {
|
||||
std::cerr << "glTF model does not have scenes" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// DBG
|
||||
size_t scene_idx = size_t(model.defaultScene);
|
||||
if (model.defaultScene == -1) {
|
||||
scene_idx = 0;
|
||||
}
|
||||
|
||||
PrintNodes(model.scenes[scene_idx]);
|
||||
PrintNodes(model.scenes[model.defaultScene]);
|
||||
|
||||
if (!glfwInit()) {
|
||||
std::cerr << "Failed to initialize GLFW." << std::endl;
|
||||
@@ -873,7 +853,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
glScalef(scale, scale, scale);
|
||||
|
||||
DrawModel(model, scene_idx);
|
||||
DrawModel(model);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
|
||||
@@ -1,20 +1,10 @@
|
||||
newoption {
|
||||
trigger = "asan",
|
||||
description = "Enable Address Sanitizer(gcc5+ ang clang only)"
|
||||
}
|
||||
|
||||
solution "glview"
|
||||
-- location ( "build" )
|
||||
configurations { "Debug", "Release" }
|
||||
platforms {"native", "x64", "x32"}
|
||||
|
||||
|
||||
project "glview"
|
||||
|
||||
-- Use clang for better asan expericen
|
||||
if _OPTIONS["asan"] then
|
||||
toolset "clang"
|
||||
end
|
||||
|
||||
kind "ConsoleApp"
|
||||
language "C++"
|
||||
cppdialect "C++11"
|
||||
@@ -23,12 +13,6 @@ solution "glview"
|
||||
includedirs { "../../" }
|
||||
|
||||
configuration { "linux" }
|
||||
|
||||
if _OPTIONS["asan"] then
|
||||
buildoptions { "-fsanitize=address,undefined" }
|
||||
linkoptions { "-fsanitize=address,undefined" }
|
||||
end
|
||||
|
||||
linkoptions { "`pkg-config --libs glfw3`" }
|
||||
links { "GL", "GLU", "m", "GLEW", "X11", "Xrandr", "Xinerama", "Xi", "Xxf86vm", "Xcursor", "dl" }
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ static void vsub(const float *src1, const float *src2, float *dst) {
|
||||
}
|
||||
|
||||
static void vcopy(const float *v1, float *v2) {
|
||||
int i;
|
||||
register int i;
|
||||
for (i = 0; i < 3; i++)
|
||||
v2[i] = v1[i];
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,19 +0,0 @@
|
||||
# Simple glTF skinning sample with CPU skinning implementation.
|
||||
|
||||
Example use CPU implementation of skinning for the explanation of how to process skin property in glTF format.
|
||||
|
||||
Animation and skinning code is based on SacchaWillems' Vulkan-glTF-PBR: https://github.com/SaschaWillems/Vulkan-glTF-PBR
|
||||
|
||||
OpenGL is still used to display renderings.
|
||||
|
||||
## Build on Linux and macOS
|
||||
|
||||
```
|
||||
$ premake5 gmake
|
||||
$ make
|
||||
$ ./bin/native/Debug/skinning simple-skin.gltf
|
||||
```
|
||||
|
||||
## Note on asset
|
||||
|
||||
`simple-skin.gltf` is grabbed from gltfTutorial https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_019_SimpleSkin.md
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,22 +0,0 @@
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
|
||||
void MorthTargets(std::vector<float> &weights,
|
||||
std::vector<std::vector<float>> &targets,
|
||||
std::vector<float> *output)
|
||||
{
|
||||
assert(weights.size() > 0);
|
||||
assert(targets.size() > 0);
|
||||
assert(weights.size() == targets.size());
|
||||
|
||||
// Assume all position has same number of vertices;
|
||||
|
||||
// TODO(parallelize)
|
||||
for (size_t v = 0; v < targets[0].size(); v++) { // for each vertex
|
||||
(*output)[v] = 0.0f;
|
||||
for (size_t i = 0; i < weights.size(); i++) {
|
||||
(*output)[v] += weights[i] * targets[i][v];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
newoption {
|
||||
trigger = "asan",
|
||||
description = "Enable Address Sanitizer(gcc5+ ang clang only)"
|
||||
}
|
||||
|
||||
solution "skinning"
|
||||
-- location ( "build" )
|
||||
configurations { "Debug", "Release" }
|
||||
platforms {"native", "x64", "x32"}
|
||||
|
||||
project "skinning"
|
||||
|
||||
-- Use clang for better asan expericen
|
||||
if _OPTIONS["asan"] then
|
||||
toolset "clang"
|
||||
end
|
||||
|
||||
kind "ConsoleApp"
|
||||
language "C++"
|
||||
cppdialect "C++11"
|
||||
files { "main.cc", "skinning.cc", "morph-targets.cc", "../common/trackball.cc", "../common/matrix.cc" }
|
||||
includedirs { "./" }
|
||||
includedirs { "../../" }
|
||||
|
||||
configuration { "linux" }
|
||||
|
||||
if _OPTIONS["asan"] then
|
||||
buildoptions { "-fsanitize=address" }
|
||||
linkoptions { "-fsanitize=address" }
|
||||
end
|
||||
|
||||
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"
|
||||
@@ -1,16 +0,0 @@
|
||||
uniform sampler2D diffuseTex;
|
||||
uniform int uIsCurve;
|
||||
|
||||
varying vec3 normal;
|
||||
varying vec2 texcoord;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
//gl_FragColor = vec4(0.5 * normalize(normal) + 0.5, 1.0);
|
||||
//gl_FragColor = vec4(texcoord, 0.0, 1.0);
|
||||
if (uIsCurve > 0) {
|
||||
gl_FragColor = texture2D(diffuseTex, texcoord);
|
||||
} else {
|
||||
gl_FragColor = vec4(0.5 * normalize(normal) + 0.5, 1.0);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
attribute vec3 in_vertex;
|
||||
attribute vec3 in_normal;
|
||||
attribute vec2 in_texcoord;
|
||||
|
||||
varying vec3 normal;
|
||||
varying vec2 texcoord;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
vec4 p = gl_ModelViewProjectionMatrix * vec4(in_vertex, 1);
|
||||
gl_Position = p;
|
||||
vec4 nn = gl_ModelViewMatrixInverseTranspose * vec4(normalize(in_normal), 0);
|
||||
normal = nn.xyz;
|
||||
|
||||
texcoord = in_texcoord;
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
{
|
||||
"scenes" : [ {
|
||||
"nodes" : [ 0 ]
|
||||
} ],
|
||||
|
||||
"nodes" : [ {
|
||||
"skin" : 0,
|
||||
"mesh" : 0,
|
||||
"children" : [ 1 ]
|
||||
}, {
|
||||
"children" : [ 2 ],
|
||||
"translation" : [ 0.0, 1.0, 0.0 ]
|
||||
}, {
|
||||
"rotation" : [ 0.0, 0.0, 0.0, 1.0 ]
|
||||
} ],
|
||||
|
||||
"meshes" : [ {
|
||||
"primitives" : [ {
|
||||
"attributes" : {
|
||||
"POSITION" : 1,
|
||||
"JOINTS_0" : 2,
|
||||
"WEIGHTS_0" : 3
|
||||
},
|
||||
"indices" : 0
|
||||
} ]
|
||||
} ],
|
||||
|
||||
"skins" : [ {
|
||||
"inverseBindMatrices" : 4,
|
||||
"joints" : [ 1, 2 ]
|
||||
} ],
|
||||
|
||||
"animations" : [ {
|
||||
"channels" : [ {
|
||||
"sampler" : 0,
|
||||
"target" : {
|
||||
"node" : 2,
|
||||
"path" : "rotation"
|
||||
}
|
||||
} ],
|
||||
"samplers" : [ {
|
||||
"input" : 5,
|
||||
"interpolation" : "LINEAR",
|
||||
"output" : 6
|
||||
} ]
|
||||
} ],
|
||||
|
||||
"buffers" : [ {
|
||||
"uri" : "data:application/gltf-buffer;base64,AAABAAMAAAADAAIAAgADAAUAAgAFAAQABAAFAAcABAAHAAYABgAHAAkABgAJAAgAAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAAD8AAAAAAACAPwAAAD8AAAAAAAAAAAAAgD8AAAAAAACAPwAAgD8AAAAAAAAAAAAAwD8AAAAAAACAPwAAwD8AAAAAAAAAAAAAAEAAAAAAAACAPwAAAEAAAAAA",
|
||||
"byteLength" : 168
|
||||
}, {
|
||||
"uri" : "data:application/gltf-buffer;base64,AAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAABAPwAAgD4AAAAAAAAAAAAAQD8AAIA+AAAAAAAAAAAAAAA/AAAAPwAAAAAAAAAAAAAAPwAAAD8AAAAAAAAAAAAAgD4AAEA/AAAAAAAAAAAAAIA+AABAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAA=",
|
||||
"byteLength" : 320
|
||||
}, {
|
||||
"uri" : "data:application/gltf-buffer;base64,AACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAvwAAgL8AAAAAAACAPwAAgD8AAAAAAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAL8AAIC/AAAAAAAAgD8=",
|
||||
"byteLength" : 128
|
||||
}, {
|
||||
"uri" : "data:application/gltf-buffer;base64,AAAAAAAAAD8AAIA/AADAPwAAAEAAACBAAABAQAAAYEAAAIBAAACQQAAAoEAAALBAAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAkxjEPkSLbD8AAAAAAAAAAPT9ND/0/TQ/AAAAAAAAAAD0/TQ/9P00PwAAAAAAAAAAkxjEPkSLbD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAkxjEvkSLbD8AAAAAAAAAAPT9NL/0/TQ/AAAAAAAAAAD0/TS/9P00PwAAAAAAAAAAkxjEvkSLbD8AAAAAAAAAAAAAAAAAAIA/",
|
||||
"byteLength" : 240
|
||||
} ],
|
||||
|
||||
"bufferViews" : [ {
|
||||
"buffer" : 0,
|
||||
"byteOffset" : 0,
|
||||
"byteLength" : 48,
|
||||
"target" : 34963
|
||||
}, {
|
||||
"buffer" : 0,
|
||||
"byteOffset" : 48,
|
||||
"byteLength" : 120,
|
||||
"target" : 34962
|
||||
}, {
|
||||
"buffer" : 1,
|
||||
"byteOffset" : 0,
|
||||
"byteLength" : 320,
|
||||
"byteStride" : 16
|
||||
}, {
|
||||
"buffer" : 2,
|
||||
"byteOffset" : 0,
|
||||
"byteLength" : 128
|
||||
}, {
|
||||
"buffer" : 3,
|
||||
"byteOffset" : 0,
|
||||
"byteLength" : 240
|
||||
} ],
|
||||
|
||||
"accessors" : [ {
|
||||
"bufferView" : 0,
|
||||
"byteOffset" : 0,
|
||||
"componentType" : 5123,
|
||||
"count" : 24,
|
||||
"type" : "SCALAR",
|
||||
"max" : [ 9 ],
|
||||
"min" : [ 0 ]
|
||||
}, {
|
||||
"bufferView" : 1,
|
||||
"byteOffset" : 0,
|
||||
"componentType" : 5126,
|
||||
"count" : 10,
|
||||
"type" : "VEC3",
|
||||
"max" : [ 1.0, 2.0, 0.0 ],
|
||||
"min" : [ 0.0, 0.0, 0.0 ]
|
||||
}, {
|
||||
"bufferView" : 2,
|
||||
"byteOffset" : 0,
|
||||
"componentType" : 5123,
|
||||
"count" : 10,
|
||||
"type" : "VEC4",
|
||||
"max" : [ 0, 1, 0, 0 ],
|
||||
"min" : [ 0, 1, 0, 0 ]
|
||||
}, {
|
||||
"bufferView" : 2,
|
||||
"byteOffset" : 160,
|
||||
"componentType" : 5126,
|
||||
"count" : 10,
|
||||
"type" : "VEC4",
|
||||
"max" : [ 1.0, 1.0, 0.0, 0.0 ],
|
||||
"min" : [ 0.0, 0.0, 0.0, 0.0 ]
|
||||
}, {
|
||||
"bufferView" : 3,
|
||||
"byteOffset" : 0,
|
||||
"componentType" : 5126,
|
||||
"count" : 2,
|
||||
"type" : "MAT4",
|
||||
"max" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -0.5, -1.0, 0.0, 1.0 ],
|
||||
"min" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -0.5, -1.0, 0.0, 1.0 ]
|
||||
}, {
|
||||
"bufferView" : 4,
|
||||
"byteOffset" : 0,
|
||||
"componentType" : 5126,
|
||||
"count" : 12,
|
||||
"type" : "SCALAR",
|
||||
"max" : [ 5.5 ],
|
||||
"min" : [ 0.0 ]
|
||||
}, {
|
||||
"bufferView" : 4,
|
||||
"byteOffset" : 48,
|
||||
"componentType" : 5126,
|
||||
"count" : 12,
|
||||
"type" : "VEC4",
|
||||
"max" : [ 0.0, 0.0, 0.707, 1.0 ],
|
||||
"min" : [ 0.0, 0.0, -0.707, 0.707 ]
|
||||
} ],
|
||||
|
||||
"asset" : {
|
||||
"version" : "2.0"
|
||||
}
|
||||
}
|
||||
@@ -1,252 +0,0 @@
|
||||
#include "skinning.h"
|
||||
|
||||
#include "../common/matrix.h"
|
||||
#include "../common/trackball.h" // for quaternion
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Weverything"
|
||||
#endif
|
||||
|
||||
#define HANDMADE_MATH_IMPLEMENTATION
|
||||
#include "HandmadeMath.h"
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
namespace example {
|
||||
|
||||
struct Node {
|
||||
|
||||
float translation[3] = {0.0f, 0.0f, 0.0f};
|
||||
float scale[4] = {1.0f, 1.0f, 1.0f};
|
||||
float rotation[4] = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
|
||||
|
||||
void update() {
|
||||
}
|
||||
};
|
||||
|
||||
static inline vec4 mix(vec4 x, vec4 y, float a) {
|
||||
vec4 v;
|
||||
v.f[0] = (1.0f - a) * x.f[0] + a * y.f[0];
|
||||
v.f[1] = (1.0f - a) * x.f[1] + a * y.f[1];
|
||||
v.f[2] = (1.0f - a) * x.f[2] + a * y.f[2];
|
||||
v.f[3] = (1.0f - a) * x.f[3] + a * y.f[3];
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
void BuildTransofrmMatrix(const float translate[3],
|
||||
const float rotation[4], // as quaternion in glTF
|
||||
const float scale[3], mat4 *transform_matrix) {
|
||||
float T[4][4];
|
||||
T[0][0] = 1.0f;
|
||||
T[0][1] = 0.0f;
|
||||
T[0][2] = 0.0f;
|
||||
T[0][3] = 0.0f;
|
||||
|
||||
T[1][0] = 0.0f;
|
||||
T[1][1] = 1.0f;
|
||||
T[1][2] = 0.0f;
|
||||
T[1][3] = 0.0f;
|
||||
|
||||
T[2][0] = 0.0f;
|
||||
T[2][1] = 0.0f;
|
||||
T[2][2] = 1.0f;
|
||||
T[2][3] = 0.0f;
|
||||
|
||||
T[3][0] = translate[0];
|
||||
T[3][1] = translate[1];
|
||||
T[3][2] = translate[2];
|
||||
T[3][3] = 1.0f;
|
||||
|
||||
float R[4][4];
|
||||
|
||||
build_rotmatrix(R, rotation);
|
||||
|
||||
float S[4][4];
|
||||
S[0][0] = scale[0];
|
||||
S[0][1] = 0.0f;
|
||||
S[0][2] = 0.0f;
|
||||
S[0][3] = 0.0f;
|
||||
|
||||
S[1][0] = 0.0f;
|
||||
S[1][1] = scale[1];
|
||||
S[1][2] = 0.0f;
|
||||
S[1][3] = 0.0f;
|
||||
|
||||
S[2][0] = 0.0f;
|
||||
S[2][1] = 0.0f;
|
||||
S[2][2] = scale[2];
|
||||
S[2][3] = 0.0f;
|
||||
|
||||
S[3][0] = 0.0f;
|
||||
S[3][1] = 0.0f;
|
||||
S[3][2] = 0.0f;
|
||||
S[3][3] = 1.0f;
|
||||
|
||||
float RS[4][4];
|
||||
|
||||
Matrix::Mult(RS, R, S);
|
||||
|
||||
Matrix::Mult(transform_matrix->m, T, RS);
|
||||
}
|
||||
|
||||
void ComputeJointMatrices(
|
||||
const std::vector<mat4> global_transform_of_nodes,
|
||||
const std::vector<mat4> global_transform_of_joint_nodes,
|
||||
const std::vector<mat4> inverse_bind_matrix_for_joints,
|
||||
std::vector<mat4> *output_joint_matrices) {
|
||||
const size_t n = global_transform_of_nodes.size();
|
||||
|
||||
output_joint_matrices->resize(n);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
mat4 g_inv = global_transform_of_nodes[i];
|
||||
Matrix::Inverse(g_inv.m);
|
||||
|
||||
mat4 g_joint = global_transform_of_joint_nodes[i];
|
||||
mat4 inverse_bind_matrix = inverse_bind_matrix_for_joints[i];
|
||||
|
||||
float a[4][4]; // temp matrix
|
||||
Matrix::Mult(a, g_joint.m, inverse_bind_matrix.m);
|
||||
|
||||
Matrix::Mult((*output_joint_matrices)[i].m, g_inv.m, a);
|
||||
}
|
||||
}
|
||||
|
||||
void Skining(const std::vector<float> vertices,
|
||||
const std::vector<float> weights, const std::vector<size_t> joints,
|
||||
const size_t num_skinning_weights,
|
||||
const std::vector<mat4> joint_matrices, const float t,
|
||||
std::vector<float> *skinned_vertices) {
|
||||
assert((vertices.size() % 4) == 0);
|
||||
const size_t num_vertices = vertices.size() / 4;
|
||||
|
||||
skinned_vertices->resize(vertices.size());
|
||||
|
||||
// TODO(syoyo): Ensure sum(weights) = 1.0;
|
||||
|
||||
for (size_t v = 0; v < num_vertices; v++) {
|
||||
const float *w_p = weights.data() + v * num_skinning_weights;
|
||||
const size_t *j_p = joints.data() + v * num_skinning_weights;
|
||||
|
||||
mat4 skin_mat;
|
||||
memset(skin_mat.m, 0, sizeof(float) * 4 * 4);
|
||||
|
||||
for (size_t k = 0; k < num_skinning_weights; k++) {
|
||||
const float w = w_p[k];
|
||||
const mat4 &m = joint_matrices[j_p[k]];
|
||||
|
||||
for (size_t j = 0; j < 4; j++) {
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
skin_mat.m[j][i] += w * m.m[j][i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// M = lerp I and skin_mat
|
||||
mat4 M;
|
||||
|
||||
mat4 I;
|
||||
Matrix::Identity(I.m);
|
||||
|
||||
for (size_t j = 0; j < 4; j++) {
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
M.m[j][i] = I.m[j][i] * t + (1.0f - t) * skin_mat.m[j][i];
|
||||
}
|
||||
}
|
||||
|
||||
float vtx[4];
|
||||
vtx[0] = vertices[4 * v + 0];
|
||||
vtx[1] = vertices[4 * v + 1];
|
||||
vtx[2] = vertices[4 * v + 2];
|
||||
vtx[3] = vertices[4 * v + 3];
|
||||
|
||||
float ret[4];
|
||||
Matrix::MultV4(ret, M.m, vtx);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAnimation(std::vector<Animation> &animations, uint32_t index,
|
||||
float time, std::vector<Node*> &nodes) {
|
||||
if (index > uint32_t(animations.size() - 1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Animation &animation = animations[index];
|
||||
|
||||
bool updated = false;
|
||||
for (auto &channel : animation.channels) {
|
||||
const AnimationSampler &sampler = animation.samplers[channel.samplerIndex];
|
||||
if (sampler.inputs.size() > sampler.outputsVec4.size()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO(LTE): support interpolation other than LINEAR
|
||||
for (size_t i = 0; i < sampler.inputs.size() - 1; i++) {
|
||||
if ((time >= sampler.inputs[i]) && (time <= sampler.inputs[i + 1])) {
|
||||
float u = std::max(0.0f, time - sampler.inputs[i]) /
|
||||
(sampler.inputs[i + 1] - sampler.inputs[i]);
|
||||
if (u <= 1.0f) {
|
||||
switch (channel.path) {
|
||||
case AnimationChannel::PathType::TRANSLATION: {
|
||||
example::vec4 trans =
|
||||
mix(sampler.outputsVec4[i], sampler.outputsVec4[i + 1], u);
|
||||
channel.node->translation[0] = trans.f[0];
|
||||
channel.node->translation[1] = trans.f[1];
|
||||
channel.node->translation[2] = trans.f[2];
|
||||
// drop w
|
||||
break;
|
||||
}
|
||||
case AnimationChannel::PathType::SCALE: {
|
||||
example::vec4 scale =
|
||||
mix(sampler.outputsVec4[i], sampler.outputsVec4[i + 1], u);
|
||||
channel.node->scale[0] = scale.f[0];
|
||||
channel.node->scale[1] = scale.f[1];
|
||||
channel.node->scale[2] = scale.f[2];
|
||||
break;
|
||||
}
|
||||
case AnimationChannel::PathType::ROTATION: {
|
||||
|
||||
hmm_quaternion q1 = HMM_Quaternion(
|
||||
sampler.outputsVec4[i].f[0],
|
||||
sampler.outputsVec4[i].f[1],
|
||||
sampler.outputsVec4[i].f[2],
|
||||
sampler.outputsVec4[i].f[3]);
|
||||
|
||||
hmm_quaternion q2 = HMM_Quaternion(
|
||||
sampler.outputsVec4[i + 1].f[0],
|
||||
sampler.outputsVec4[i + 1].f[1],
|
||||
sampler.outputsVec4[i + 1].f[2],
|
||||
sampler.outputsVec4[i + 1].f[3]);
|
||||
|
||||
hmm_quaternion q = HMM_NormalizeQuaternion(HMM_Slerp(q1, u, q2));
|
||||
|
||||
channel.node->rotation[0] = q.Elements[0];
|
||||
channel.node->rotation[1] = q.Elements[1];
|
||||
channel.node->rotation[2] = q.Elements[2];
|
||||
channel.node->rotation[3] = q.Elements[3];
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (updated) {
|
||||
for (auto &node : nodes) {
|
||||
node->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace example
|
||||
@@ -1,95 +0,0 @@
|
||||
#ifndef EXAMPLE_SKINNING_H_
|
||||
#define EXAMPLE_SKINNING_H_
|
||||
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <limits>
|
||||
|
||||
namespace example {
|
||||
|
||||
struct mat4 {
|
||||
float m[4][4];
|
||||
};
|
||||
|
||||
struct vec4 {
|
||||
float f[4];
|
||||
};
|
||||
|
||||
// glTF node
|
||||
struct Node;
|
||||
|
||||
|
||||
struct AnimationChannel {
|
||||
enum PathType { TRANSLATION, ROTATION, SCALE };
|
||||
PathType path;
|
||||
Node *node;
|
||||
uint32_t samplerIndex;
|
||||
};
|
||||
|
||||
struct AnimationSampler {
|
||||
enum InterpolationType { LINEAR, STEP, CUBICSPLINE };
|
||||
InterpolationType interpolation;
|
||||
std::vector<float> inputs;
|
||||
std::vector<example::vec4> outputsVec4;
|
||||
};
|
||||
|
||||
struct Animation {
|
||||
std::string name;
|
||||
std::vector<AnimationSampler> samplers;
|
||||
std::vector<AnimationChannel> channels;
|
||||
float start = std::numeric_limits<float>::max();
|
||||
float end = std::numeric_limits<float>::min();
|
||||
};
|
||||
|
||||
///
|
||||
/// Utility function to build transformation matrix from translate/rotation/scale
|
||||
///
|
||||
/// https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_004_ScenesNodes.md
|
||||
///
|
||||
/// M = T * R * S
|
||||
///
|
||||
void BuildTransofrmMatrix(
|
||||
const float translate[3],
|
||||
const float rotation[4], // as quaternion in glTF
|
||||
const float scale[3],
|
||||
mat4 *transform_matrix);
|
||||
|
||||
|
||||
///
|
||||
/// Compute joint matrices.
|
||||
///
|
||||
/// jointMatrix(j) =
|
||||
/// globalTransformOfNodeThatTheMeshIsAttachedTo^-1 *
|
||||
/// globalTransformOfJointNode(j) *
|
||||
/// inverseBindMatrixForJoint(j);
|
||||
///
|
||||
|
||||
void ComputeJointMatrices(
|
||||
const std::vector<mat4> global_transform_of_nodes,
|
||||
const std::vector<mat4> global_transform_of_joint_nodes,
|
||||
const std::vector<mat4> inverse_bind_matrix_for_joints,
|
||||
std::vector<mat4> output_joint_matrices);
|
||||
|
||||
|
||||
///
|
||||
///
|
||||
/// @param[in] vertices Input vertices(# of elements = num_vertices * 4(xyzw))
|
||||
/// @param[in] weights Linearized weights(# of elements = num_vertices * num_skinning_weights)
|
||||
/// @param[in] weights Linearized weights(# of elements = num_vertices * num_skinning_weights)
|
||||
/// @param[in] num_weights Linearized weights(# of elements = num_vertices *
|
||||
/// @param[in] joint_matrices Array of joint matricies.
|
||||
/// @param[in] t Interpolator. [0.0, 1.0]
|
||||
/// @param[in] skinned_vertices Resulting skinned vertices
|
||||
///
|
||||
void Skining(const std::vector<float> vertices,
|
||||
const std::vector<float> weights, const std::vector<size_t> joints,
|
||||
const size_t num_skinning_weights,
|
||||
const std::vector<mat4> joint_matrices,
|
||||
const float t,
|
||||
std::vector<float> *skinned_vertices);
|
||||
|
||||
} // namespace example
|
||||
|
||||
#endif // EXAMPLE_SKINNING_H_
|
||||
@@ -1,15 +0,0 @@
|
||||
# Python script which generates C++11 code from JSON schema.
|
||||
|
||||
## Requirements
|
||||
|
||||
* python3
|
||||
* jsonref
|
||||
|
||||
## Generate
|
||||
|
||||
Run `gen.py` by specifing the path to glTF schema directory(from https://github.com/KhronosGroup/glTF.git)
|
||||
|
||||
```
|
||||
$ python gen.py /path/to/glTF/specification/2.0/schema
|
||||
```
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys, os
|
||||
import subprocess
|
||||
import json
|
||||
from pprint import pprint
|
||||
import jsonref
|
||||
|
||||
# glTF 2.0
|
||||
schema_files = [
|
||||
"glTF.schema.json"
|
||||
]
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Requires path to glTF scheme directory.")
|
||||
sys.exit(-1)
|
||||
|
||||
gltf_schema_dir = sys.argv[1]
|
||||
|
||||
gltf_schema_filepath = os.path.join(gltf_schema_dir, schema_files[0])
|
||||
if not os.path.exists(gltf_schema_filepath):
|
||||
print("File not found: {}".format(gltf_schema_filepath))
|
||||
sys.exit(-1)
|
||||
|
||||
gltf_schema_uri = 'file://{}/'.format(gltf_schema_dir)
|
||||
with open(gltf_schema_filepath) as schema_file:
|
||||
j = jsonref.loads(schema_file.read(), base_uri=gltf_schema_uri, jsonschema=True)
|
||||
pprint(j)
|
||||
|
||||
|
||||
|
||||
main()
|
||||
@@ -1,6 +1,3 @@
|
||||
//
|
||||
// TODO(syoyo): Print extensions and extras for each glTF object.
|
||||
//
|
||||
#define TINYGLTF_IMPLEMENTATION
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
@@ -30,8 +27,7 @@ static std::string PrintMode(int mode) {
|
||||
} else if (mode == TINYGLTF_MODE_TRIANGLE_STRIP) {
|
||||
return "TRIANGLE_STRIP";
|
||||
}
|
||||
|
||||
return "**UNKNOWN**(" + std::to_string(mode) + ")";
|
||||
return "**UNKNOWN**";
|
||||
}
|
||||
|
||||
static std::string PrintTarget(int target) {
|
||||
@@ -40,7 +36,7 @@ static std::string PrintTarget(int target) {
|
||||
} else if (target == 34963) {
|
||||
return "GL_ELEMENT_ARRAY_BUFFER";
|
||||
} else {
|
||||
return "**UNKNOWN**(" + std::to_string(target) + ")";
|
||||
return "**UNKNOWN**";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +60,7 @@ static std::string PrintType(int ty) {
|
||||
} else if (ty == TINYGLTF_TYPE_MAT4) {
|
||||
return "MAT4";
|
||||
}
|
||||
return "**UNKNOWN**(" + std::to_string(ty) + ")";
|
||||
return "**UNKNOWN**";
|
||||
}
|
||||
|
||||
static std::string PrintComponentType(int ty) {
|
||||
@@ -86,7 +82,7 @@ static std::string PrintComponentType(int ty) {
|
||||
return "DOUBLE";
|
||||
}
|
||||
|
||||
return "**UNKNOWN**(" + std::to_string(ty) + ")";
|
||||
return "**UNKNOWN**";
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -148,7 +144,7 @@ static std::string PrintWrapMode(int mode) {
|
||||
return "MIRRORED_REPEAT";
|
||||
}
|
||||
|
||||
return "**UNKNOWN**(" + std::to_string(mode) + ")";
|
||||
return "**UNKNOWN**";
|
||||
}
|
||||
|
||||
static std::string PrintFilterMode(int mode) {
|
||||
@@ -165,7 +161,7 @@ static std::string PrintFilterMode(int mode) {
|
||||
} else if (mode == TINYGLTF_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR) {
|
||||
return "LINEAR_MIPMAP_LINEAR";
|
||||
}
|
||||
return "**UNKNOWN**(" + std::to_string(mode) + ")";
|
||||
return "**UNKNOWN**";
|
||||
}
|
||||
|
||||
static std::string PrintIntArray(const std::vector<int> &arr) {
|
||||
@@ -518,7 +514,6 @@ static void Dump(const tinygltf::Model &model) {
|
||||
std::cout << Indent(2) << "width : " << image.width << std::endl;
|
||||
std::cout << Indent(2) << "height : " << image.height << std::endl;
|
||||
std::cout << Indent(2) << "component : " << image.component << std::endl;
|
||||
DumpExtensions(image.extensions, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -530,7 +525,6 @@ static void Dump(const tinygltf::Model &model) {
|
||||
<< std::endl;
|
||||
std::cout << Indent(1) << "source : " << texture.source
|
||||
<< std::endl;
|
||||
DumpExtensions(texture.extensions, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,9 +18,8 @@ TEST_CASE("parse-error", "[parse]") {
|
||||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTF ctx;
|
||||
std::string err;
|
||||
std::string warn;
|
||||
|
||||
bool ret = ctx.LoadASCIIFromString(&model, &err, &warn, "bora", strlen("bora"), /* basedir*/ "");
|
||||
bool ret = ctx.LoadASCIIFromString(&model, &err, "bora", strlen("bora"), /* basedir*/ "");
|
||||
|
||||
REQUIRE(false == ret);
|
||||
|
||||
@@ -31,9 +30,8 @@ TEST_CASE("datauri-in-glb", "[issue-79]") {
|
||||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTF ctx;
|
||||
std::string err;
|
||||
std::string warn;
|
||||
|
||||
bool ret = ctx.LoadBinaryFromFile(&model, &err, &warn, "../models/box01.glb");
|
||||
bool ret = ctx.LoadBinaryFromFile(&model, &err, "../models/box01.glb");
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
|
||||
86
tiny_gltf.h
86
tiny_gltf.h
@@ -189,11 +189,6 @@ static inline int32_t GetTypeSizeInBytes(uint32_t ty) {
|
||||
}
|
||||
}
|
||||
|
||||
bool IsDataURI(const std::string &in);
|
||||
bool DecodeDataURI(std::vector<unsigned char> *out,
|
||||
std::string &mime_type, const std::string &in,
|
||||
size_t reqBytes, bool checkSize);
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
// Suppress warning for : static Value null_value
|
||||
@@ -456,16 +451,8 @@ struct Image {
|
||||
// "image/bmp", "image/gif"]
|
||||
std::string uri; // (required if no mimeType)
|
||||
Value extras;
|
||||
ExtensionMap extensions;
|
||||
|
||||
// When this flag is true, data is stored to `image` in as-is format(e.g. jpeg compressed for "image/jpeg" mime)
|
||||
// This feature is good if you use custom image loader function.
|
||||
// (e.g. delayed decoding of images for faster glTF parsing)
|
||||
// Default parser for Image does not provide as-is loading feature at the moment.
|
||||
// (You can manipulate this by providing your own LoadImageData function)
|
||||
bool as_is;
|
||||
|
||||
Image() : as_is(false) { bufferView = -1; }
|
||||
Image() { bufferView = -1; }
|
||||
};
|
||||
|
||||
struct Texture {
|
||||
@@ -967,6 +954,7 @@ class TinyGLTF {
|
||||
#pragma clang diagnostic ignored "-Wexit-time-destructors"
|
||||
#pragma clang diagnostic ignored "-Wconversion"
|
||||
#pragma clang diagnostic ignored "-Wold-style-cast"
|
||||
#pragma clang diagnostic ignored "-Wdouble-promotion"
|
||||
#pragma clang diagnostic ignored "-Wglobal-constructors"
|
||||
#pragma clang diagnostic ignored "-Wreserved-id-macro"
|
||||
#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
|
||||
@@ -978,9 +966,6 @@ class TinyGLTF {
|
||||
#pragma clang diagnostic ignored "-Wimplicit-fallthrough"
|
||||
#pragma clang diagnostic ignored "-Wweak-vtables"
|
||||
#pragma clang diagnostic ignored "-Wcovered-switch-default"
|
||||
#if __has_warning("-Wdouble-promotion")
|
||||
#pragma clang diagnostic ignored "-Wdouble-promotion"
|
||||
#endif
|
||||
#if __has_warning("-Wcomma")
|
||||
#pragma clang diagnostic ignored "-Wcomma"
|
||||
#endif
|
||||
@@ -1248,7 +1233,7 @@ std::string base64_decode(std::string const &encoded_string) {
|
||||
|
||||
static bool LoadExternalFile(std::vector<unsigned char> *out, std::string *err,
|
||||
std::string *warn, const std::string &filename,
|
||||
const std::string &basedir, bool required, size_t reqBytes,
|
||||
const std::string &basedir, size_t reqBytes,
|
||||
bool checkSize, FsCallbacks *fs) {
|
||||
if (fs == nullptr || fs->FileExists == nullptr ||
|
||||
fs->ExpandFilePath == nullptr || fs->ReadWholeFile == nullptr) {
|
||||
@@ -1259,8 +1244,6 @@ static bool LoadExternalFile(std::vector<unsigned char> *out, std::string *err,
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string* failMsgOut = required ? err : warn;
|
||||
|
||||
out->clear();
|
||||
|
||||
std::vector<std::string> paths;
|
||||
@@ -1269,8 +1252,8 @@ static bool LoadExternalFile(std::vector<unsigned char> *out, std::string *err,
|
||||
|
||||
std::string filepath = FindFile(paths, filename, fs);
|
||||
if (filepath.empty() || filename.empty()) {
|
||||
if (failMsgOut) {
|
||||
(*failMsgOut) += "File not found : " + filename + "\n";
|
||||
if (warn) {
|
||||
(*warn) += "File not found : " + filename + "\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1280,17 +1263,15 @@ static bool LoadExternalFile(std::vector<unsigned char> *out, std::string *err,
|
||||
bool fileRead =
|
||||
fs->ReadWholeFile(&buf, &fileReadErr, filepath, fs->user_data);
|
||||
if (!fileRead) {
|
||||
if (failMsgOut) {
|
||||
(*failMsgOut) += "File read error : " + filepath + " : " + fileReadErr + "\n";
|
||||
if (err) {
|
||||
(*err) += "File read error : " + filepath + " : " + fileReadErr + "\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t sz = buf.size();
|
||||
if (sz == 0) {
|
||||
if(failMsgOut) {
|
||||
(*failMsgOut) += "File is empty : " + filepath + "\n";
|
||||
}
|
||||
(*err) += "File is empty : " + filepath + "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1302,8 +1283,8 @@ static bool LoadExternalFile(std::vector<unsigned char> *out, std::string *err,
|
||||
std::stringstream ss;
|
||||
ss << "File size mismatch : " << filepath << ", requestedBytes "
|
||||
<< reqBytes << ", but got " << sz << std::endl;
|
||||
if (failMsgOut) {
|
||||
(*failMsgOut) += ss.str();
|
||||
if (err) {
|
||||
(*err) += ss.str();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1324,19 +1305,14 @@ bool LoadImageData(Image *image, std::string *err, std::string *warn,
|
||||
int size, void *) {
|
||||
(void)warn;
|
||||
|
||||
int w, h, comp, req_comp;
|
||||
|
||||
// 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 w, h, comp;
|
||||
// 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);
|
||||
unsigned char *data = stbi_load_from_memory(bytes, size, &w, &h, &comp, 0);
|
||||
if (!data) {
|
||||
// NOTE: you can use `warn` instead of `err`
|
||||
if (err) {
|
||||
@@ -1375,9 +1351,9 @@ 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());
|
||||
image->component = comp;
|
||||
image->image.resize(static_cast<size_t>(w * h * comp));
|
||||
std::copy(data, data + w * h * comp, image->image.begin());
|
||||
|
||||
free(data);
|
||||
|
||||
@@ -1409,18 +1385,24 @@ bool WriteImageData(const std::string *basepath, const std::string *filename,
|
||||
std::vector<unsigned char> data;
|
||||
|
||||
if (ext == "png") {
|
||||
stbi_write_png_to_func(WriteToMemory_stbi, &data, image->width,
|
||||
if (!stbi_write_png_to_func(WriteToMemory_stbi, &data, image->width,
|
||||
image->height, image->component, &image->image[0],
|
||||
0);
|
||||
0)) {
|
||||
return false;
|
||||
}
|
||||
header = "data:image/png;base64,";
|
||||
} else if (ext == "jpg") {
|
||||
stbi_write_jpg_to_func(WriteToMemory_stbi, &data, image->width,
|
||||
if (!stbi_write_jpg_to_func(WriteToMemory_stbi, &data, image->width,
|
||||
image->height, image->component, &image->image[0],
|
||||
100);
|
||||
100)) {
|
||||
return false;
|
||||
}
|
||||
header = "data:image/jpeg;base64,";
|
||||
} else if (ext == "bmp") {
|
||||
stbi_write_bmp_to_func(WriteToMemory_stbi, &data, image->width,
|
||||
image->height, image->component, &image->image[0]);
|
||||
if (!stbi_write_bmp_to_func(WriteToMemory_stbi, &data, image->width,
|
||||
image->height, image->component, &image->image[0])) {
|
||||
return false;
|
||||
}
|
||||
header = "data:image/bmp;base64,";
|
||||
} else if (!embedImages) {
|
||||
// Error: can't output requested format to file
|
||||
@@ -1445,6 +1427,7 @@ bool WriteImageData(const std::string *basepath, const std::string *filename,
|
||||
if (!fs->WriteWholeFile(&writeError, imagefilepath, data,
|
||||
fs->user_data)) {
|
||||
// Could not write image file to disc; Throw error ?
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Throw error?
|
||||
@@ -1632,7 +1615,7 @@ static void UpdateImageObject(Image &image, std::string &baseDir, int index,
|
||||
}
|
||||
}
|
||||
|
||||
bool IsDataURI(const std::string &in) {
|
||||
static bool IsDataURI(const std::string &in) {
|
||||
std::string header = "data:application/octet-stream;base64,";
|
||||
if (in.find(header) == 0) {
|
||||
return true;
|
||||
@@ -1671,7 +1654,7 @@ bool IsDataURI(const std::string &in) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DecodeDataURI(std::vector<unsigned char> *out,
|
||||
static bool DecodeDataURI(std::vector<unsigned char> *out,
|
||||
std::string &mime_type, const std::string &in,
|
||||
size_t reqBytes, bool checkSize) {
|
||||
std::string header = "data:application/octet-stream;base64,";
|
||||
@@ -2134,7 +2117,6 @@ static bool ParseImage(Image *image, std::string *err, std::string *warn,
|
||||
}
|
||||
|
||||
ParseStringProperty(&image->name, err, o, "name", false);
|
||||
ParseExtensionsProperty(&image->extensions, err, o);
|
||||
|
||||
if (hasBufferView) {
|
||||
double bufferView = -1;
|
||||
@@ -2191,7 +2173,7 @@ static bool ParseImage(Image *image, std::string *err, std::string *warn,
|
||||
#ifdef TINYGLTF_NO_EXTERNAL_IMAGE
|
||||
return true;
|
||||
#endif
|
||||
if (!LoadExternalFile(&img, err, warn, uri, basedir, false, 0, false, fs)) {
|
||||
if (!LoadExternalFile(&img, err, warn, uri, basedir, 0, false, fs)) {
|
||||
if (warn) {
|
||||
(*warn) += "Failed to load external 'uri' for image parameter\n";
|
||||
}
|
||||
@@ -2286,7 +2268,7 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o,
|
||||
} else {
|
||||
// External .bin file.
|
||||
if (!LoadExternalFile(&buffer->data, err, /* warn */ nullptr, buffer->uri,
|
||||
basedir, true, bytes, true, fs)) {
|
||||
basedir, bytes, true, fs)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -2328,7 +2310,7 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o,
|
||||
} else {
|
||||
// Assume external .bin file.
|
||||
if (!LoadExternalFile(&buffer->data, err, /* warn */ nullptr, buffer->uri,
|
||||
basedir, true, bytes, true, fs)) {
|
||||
basedir, bytes, true, fs)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -4023,8 +4005,6 @@ static void SerializeGltfImage(Image &image, json &o) {
|
||||
if (image.extras.Type() != NULL_TYPE) {
|
||||
SerializeValue("extras", image.extras, o);
|
||||
}
|
||||
|
||||
SerializeExtensionMap(image.extensions, o);
|
||||
}
|
||||
|
||||
static void SerializeGltfMaterial(Material &material, json &o) {
|
||||
|
||||
Reference in New Issue
Block a user