Compare commits

..

2 Commits

Author SHA1 Message Date
Syoyo Fujita
098dfee982 Merge pull request #92 from walf443/respect_stb_image_write_error
handling stbi_write_xxx_to_func return code
2018-08-28 21:33:07 +09:00
Keiji Yoshimi
c0cfc1ed95 handling stbi_write_xxx_to_func return code 2018-08-28 21:13:03 +09:00
23 changed files with 77 additions and 4409 deletions

View File

@@ -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

View File

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

View File

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

View File

@@ -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 //

View File

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

View File

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

View File

@@ -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" }

View File

@@ -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

View File

@@ -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

View File

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

View File

@@ -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"

View File

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

View File

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

View File

@@ -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"
}
}

View File

@@ -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

View File

@@ -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_

View File

@@ -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
```

View File

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

View File

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

View File

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

View File

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