mirror of
https://github.com/syoyo/tinygltf.git
synced 2026-06-13 18:58:53 +00:00
Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fed3f31e95 | ||
|
|
6fcee26d0f | ||
|
|
bafde6a53e | ||
|
|
3d939fd3ee | ||
|
|
fbbeb4d6a9 | ||
|
|
cef1787ef8 | ||
|
|
2f5aa9f13b | ||
|
|
28bafe4b11 | ||
|
|
34894a6325 | ||
|
|
2e7006797b | ||
|
|
d9c03d041a | ||
|
|
50a3061ddf | ||
|
|
014dce27f4 | ||
|
|
c046769054 | ||
|
|
c43266fdc9 | ||
|
|
aca196e8d3 | ||
|
|
b48c027c9a | ||
|
|
db5c3bea45 | ||
|
|
ddfa1f2f0b | ||
|
|
7b69c778fe | ||
|
|
73e73bf3c1 | ||
|
|
35d664e417 | ||
|
|
272a9dfa5f | ||
|
|
f3bf6ee78e | ||
|
|
aba57bb907 | ||
|
|
6fad7adb9c | ||
|
|
3dad303bea | ||
|
|
ff0a2e9fb4 | ||
|
|
fe77cc5cdd | ||
|
|
b8c04b0a9d | ||
|
|
18f0e20a11 | ||
|
|
978adee547 | ||
|
|
73c4cce303 | ||
|
|
925b83627a | ||
|
|
92c23725ae | ||
|
|
af750a5104 | ||
|
|
ff48fa0ff4 | ||
|
|
ec45334d3d | ||
|
|
5f603c56dc | ||
|
|
063b8586f1 | ||
|
|
db855c6794 | ||
|
|
e391f6b03e | ||
|
|
5ecede71f0 |
165
.github/workflows/c-cpp.yml
vendored
Normal file
165
.github/workflows/c-cpp.yml
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
name: C/C++ CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
|
||||
# compile with older gcc4.8
|
||||
build-gcc48:
|
||||
|
||||
runs-on: ubuntu-18.04
|
||||
name: Build with gcc 4.8
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y build-essential
|
||||
sudo apt-get install -y gcc-4.8 g++-4.8
|
||||
g++-4.8 -std=c++11 -o loader_example loader_example.cc
|
||||
|
||||
- name: NoexceptBuild
|
||||
run: |
|
||||
g++-4.8 -DTINYGLTF_NOEXCEPTION -std=c++11 -o loader_example loader_example.cc
|
||||
|
||||
- name: RapidjsonBuild
|
||||
run: |
|
||||
git clone https://github.com/Tencent/rapidjson
|
||||
g++-4.8 -DTINYGLTF_USE_RAPIDJSON -I./rapidjson/include/rapidjson -std=c++11 -o loader_example loader_example.cc
|
||||
|
||||
# compile with mingw gcc cross
|
||||
build-mingw-cross:
|
||||
|
||||
runs-on: ubuntu-18.04
|
||||
name: Build with MinGW gcc cross
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y build-essential
|
||||
sudo apt-get install -y mingw-w64
|
||||
x86_64-w64-mingw32-g++ -std=c++11 -o loader_example loader_example.cc
|
||||
|
||||
# Windows(x64) + Visual Studio 2019 build
|
||||
build-windows-msvc:
|
||||
|
||||
runs-on: windows-latest
|
||||
name: Build for Windows(x64, MSVC)
|
||||
|
||||
# Use system installed cmake
|
||||
# https://help.github.com/en/actions/reference/software-installed-on-github-hosted-runners
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
- name: Configure
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -G "Visual Studio 16 2019" -DTINYGLTF_BUILD_LOADER_EXAMPLE=On -DTINYGLTF_BUILD_GL_EXAMPLES=Off -DTINYGLTF_BUILD_VALIDATOR_EXAMPLE=On ..
|
||||
cd ..
|
||||
- name: Build
|
||||
run: cmake --build build --config Release
|
||||
|
||||
|
||||
build-linux:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
name: Buld with gcc
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: build
|
||||
run: |
|
||||
g++ -std=c++11 -o loader_example loader_example.cc
|
||||
- name: test
|
||||
run: |
|
||||
./loader_example models/Cube/Cube.gltf
|
||||
|
||||
- name: tests
|
||||
run: |
|
||||
cd tests
|
||||
g++ -I../ -std=c++11 -g -O0 -o tester tester.cc
|
||||
./tester
|
||||
cd ..
|
||||
|
||||
- name: noexcept_tests
|
||||
run: |
|
||||
cd tests
|
||||
g++ -DTINYGLTF_NOEXCEPTION -I../ -std=c++11 -g -O0 -o tester_noexcept tester.cc
|
||||
./tester_noexcept
|
||||
cd ..
|
||||
|
||||
|
||||
build-rapidjson-linux:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
name: Buld with gcc + rapidjson
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: build
|
||||
run: |
|
||||
git clone https://github.com/Tencent/rapidjson
|
||||
g++ -v
|
||||
g++ -DTINYGLTF_USE_RAPIDJSON -I./rapidjson/include/rapidjson -std=c++11 -o loader_example loader_example.cc
|
||||
|
||||
- name: loader_example_test
|
||||
run: |
|
||||
./loader_example models/Cube/Cube.gltf
|
||||
|
||||
- name: tests
|
||||
run: |
|
||||
cd tests
|
||||
g++ -DTINYGLTF_USE_RAPIDJSON -I../rapidjson/include/rapidjson -I../ -std=c++11 -g -O0 -o tester tester.cc
|
||||
./tester
|
||||
cd ..
|
||||
|
||||
- name: noexcept_tests
|
||||
run: |
|
||||
cd tests
|
||||
g++ -DTINYGLTF_USE_RAPIDJSON -I../rapidjson/include/rapidjson -DTINYGLTF_NOEXCEPTION -I../ -std=c++11 -g -O0 -o tester_noexcept tester.cc
|
||||
./tester_noexcept
|
||||
cd ..
|
||||
|
||||
# Cross-compile for aarch64 linux target
|
||||
build-cross-aarch64:
|
||||
|
||||
runs-on: ubuntu-18.04
|
||||
name: Build on cross aarch64
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
- name: Build
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y build-essential
|
||||
sudo apt-get install -y gcc-8-aarch64-linux-gnu g++-8-aarch64-linux-gnu
|
||||
|
||||
git clone https://github.com/Tencent/rapidjson
|
||||
aarch64-linux-gnu-g++-8 -DTINYGLTF_USE_RAPIDJSON -I./rapidjson/include/rapidjson -std=c++11 -g -O0 -o loader_example loader_example.cc
|
||||
|
||||
# macOS clang
|
||||
build-macos:
|
||||
|
||||
runs-on: macos-latest
|
||||
name: Build on macOS
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
- name: Build
|
||||
run: |
|
||||
clang++ -std=c++11 -g -O0 -o loader_example loader_example.cc
|
||||
./loader_example models/Cube/Cube.gltf
|
||||
|
||||
git clone https://github.com/Tencent/rapidjson
|
||||
clang++ -DTINYGLTF_USE_RAPIDJSON -I./rapidjson/include/rapidjson -std=c++11 -g -O0 -o loader_example loader_example.cc
|
||||
|
||||
@@ -4,18 +4,24 @@ PROJECT (tinygltf)
|
||||
|
||||
SET(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
option(TINYGLTF_BUILD_EXAMPLES "Build examples" ON)
|
||||
option(TINYGLTF_BUILD_LOADER_EXAMPLE "Build loader_example" ON)
|
||||
option(TINYGLTF_BUILD_GL_EXAMPLES "Build GL exampels(requires glfw, OpenGL, etc)" OFF)
|
||||
option(TINYGLTF_BUILD_VALIDATOR_EXAMPLE "Build validator exampe" OFF)
|
||||
|
||||
if (TINYGLTF_BUILD_EXAMPLES)
|
||||
if (TINYGLTF_BUILD_LOADER_EXAMPLE)
|
||||
ADD_EXECUTABLE ( loader_example
|
||||
loader_example.cc
|
||||
)
|
||||
endif (TINYGLTF_BUILD_LOADER_EXAMPLE)
|
||||
|
||||
if (TINYGLTF_BUILD_GL_EXAMPLES)
|
||||
ADD_SUBDIRECTORY ( examples/gltfutil )
|
||||
ADD_SUBDIRECTORY ( examples/glview )
|
||||
ADD_SUBDIRECTORY ( examples/validator )
|
||||
endif (TINYGLTF_BUILD_EXAMPLES)
|
||||
endif (TINYGLTF_BUILD_GL_EXAMPLES)
|
||||
|
||||
if (TINYGLTF_BUILD_VALIDATOR_EXAMPLE)
|
||||
ADD_SUBDIRECTORY ( examples/validator )
|
||||
endif (TINYGLTF_BUILD_VALIDATOR_EXAMPLE)
|
||||
#
|
||||
# TinuGLTF is a header-only library, so no library build. just install header files.
|
||||
#
|
||||
|
||||
@@ -19,6 +19,8 @@ If you are looking for old, C++03 version, please use `devel-picojson` branch.
|
||||
|
||||
[](https://ci.appveyor.com/project/syoyo/tinygltf)
|
||||
|
||||

|
||||
|
||||
## Features
|
||||
|
||||
* Written in portable C++. C++-11 with STL dependency only.
|
||||
@@ -83,6 +85,7 @@ In extension(`ExtensionMap`), JSON number value is parsed as int or float(number
|
||||
* [QuickLook GLTF](https://github.com/toshiks/glTF-quicklook) - quicklook plugin for macos. Also SceneKit wrapper for tinygltf.
|
||||
* [GlslViewer](https://github.com/patriciogonzalezvivo/glslViewer) - live GLSL coding for MacOS and Linux
|
||||
* [Vulkan-Samples](https://github.com/KhronosGroup/Vulkan-Samples) - The Vulkan Samples is collection of resources to help you develop optimized Vulkan applications.
|
||||
* [TDME2](https://github.com/andreasdr/tdme2) - TDME2 - ThreeDeeMiniEngine2 is a lightweight 3D engine including tools suited for 3D game development using C++11
|
||||
* Your projects here! (Please send PR)
|
||||
|
||||
## TODOs
|
||||
@@ -150,6 +153,7 @@ if (!ret) {
|
||||
|
||||
## Compile options
|
||||
|
||||
* `TINYGLTF_ENABLE_SERIALIZER` : Enable glTF serialization feature.
|
||||
* `TINYGLTF_NOEXCEPTION` : Disable C++ exception in JSON parsing. You can use `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION` and `TINYGLTF_NOEXCEPTION` to fully remove C++ exception codes when compiling TinyGLTF.
|
||||
* `TINYGLTF_NO_STB_IMAGE` : Do not load images with stb_image. Instead use `TinyGLTF::SetImageLoader(LoadimageDataFunction LoadImageData, void *user_data)` to set a callback for loading images.
|
||||
* `TINYGLTF_NO_STB_IMAGE_WRITE` : Do not write images with stb_image_write. Instead use `TinyGLTF::SetImageWriter(WriteimageDataFunction WriteImageData, void *user_data)` to set a callback for writing images.
|
||||
|
||||
@@ -19,3 +19,7 @@ $ make
|
||||
Plese use solution file located at `basic` folder.
|
||||
|
||||
|
||||
## Limitation
|
||||
|
||||
There are so many limitations in this example(e.g. no PBR shader. the shader only shows texture of textures[0] if available).
|
||||
|
||||
|
||||
@@ -100,42 +100,49 @@ std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos,
|
||||
std::cout << "vaa missing: " << attrib.first << std::endl;
|
||||
}
|
||||
|
||||
GLuint texid;
|
||||
glGenTextures(1, &texid);
|
||||
if (model.textures.size() > 0) {
|
||||
// fixme: Use material's baseColor
|
||||
tinygltf::Texture &tex = model.textures[0];
|
||||
|
||||
tinygltf::Texture &tex = model.textures[0];
|
||||
tinygltf::Image &image = model.images[tex.source];
|
||||
if (tex.source > -1) {
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texid);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
GLuint texid;
|
||||
glGenTextures(1, &texid);
|
||||
|
||||
GLenum format = GL_RGBA;
|
||||
tinygltf::Image &image = model.images[tex.source];
|
||||
|
||||
if (image.component == 1) {
|
||||
format = GL_RED;
|
||||
} else if (image.component == 2) {
|
||||
format = GL_RG;
|
||||
} else if (image.component == 3) {
|
||||
format = GL_RGB;
|
||||
} else {
|
||||
// ???
|
||||
glBindTexture(GL_TEXTURE_2D, texid);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
|
||||
GLenum format = GL_RGBA;
|
||||
|
||||
if (image.component == 1) {
|
||||
format = GL_RED;
|
||||
} else if (image.component == 2) {
|
||||
format = GL_RG;
|
||||
} else if (image.component == 3) {
|
||||
format = GL_RGB;
|
||||
} else {
|
||||
// ???
|
||||
}
|
||||
|
||||
GLenum type = GL_UNSIGNED_BYTE;
|
||||
if (image.bits == 8) {
|
||||
// ok
|
||||
} else if (image.bits == 16) {
|
||||
type = GL_UNSIGNED_SHORT;
|
||||
} else {
|
||||
// ???
|
||||
}
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0,
|
||||
format, type, &image.image.at(0));
|
||||
}
|
||||
}
|
||||
|
||||
GLenum type = GL_UNSIGNED_BYTE;
|
||||
if (image.bits == 8) {
|
||||
// ok
|
||||
} else if (image.bits == 16) {
|
||||
type = GL_UNSIGNED_SHORT;
|
||||
} else {
|
||||
// ???
|
||||
}
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0,
|
||||
format, type, &image.image.at(0));
|
||||
}
|
||||
|
||||
return vbos;
|
||||
@@ -144,8 +151,12 @@ std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos,
|
||||
// bind models
|
||||
void bindModelNodes(std::map<int, GLuint> vbos, tinygltf::Model &model,
|
||||
tinygltf::Node &node) {
|
||||
bindMesh(vbos, model, model.meshes[node.mesh]);
|
||||
if ((node.mesh >= 0) && (node.mesh < model.meshes.size())) {
|
||||
bindMesh(vbos, model, model.meshes[node.mesh]);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < node.children.size(); i++) {
|
||||
assert((node.children[i] >= 0) && (node.children[i] < model.nodes.size()));
|
||||
bindModelNodes(vbos, model, model.nodes[node.children[i]]);
|
||||
}
|
||||
}
|
||||
@@ -157,6 +168,7 @@ GLuint bindModel(tinygltf::Model &model) {
|
||||
|
||||
const tinygltf::Scene &scene = model.scenes[model.defaultScene];
|
||||
for (size_t i = 0; i < scene.nodes.size(); ++i) {
|
||||
assert((scene.nodes[i] >= 0) && (scene.nodes[i] < model.nodes.size()));
|
||||
bindModelNodes(vbos, model, model.nodes[scene.nodes[i]]);
|
||||
}
|
||||
|
||||
@@ -182,7 +194,9 @@ void drawMesh(tinygltf::Model &model, tinygltf::Mesh &mesh) {
|
||||
|
||||
// recursively draw node and children nodes of model
|
||||
void drawModelNodes(tinygltf::Model &model, tinygltf::Node &node) {
|
||||
drawMesh(model, model.meshes[node.mesh]);
|
||||
if ((node.mesh >= 0) && (node.mesh < model.meshes.size())) {
|
||||
drawMesh(model, model.meshes[node.mesh]);
|
||||
}
|
||||
for (size_t i = 0; i < node.children.size(); i++) {
|
||||
drawModelNodes(model, model.nodes[node.children[i]]);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +0,0 @@
|
||||
#EXTRA_CXXFLAGS := -fsanitize=address -fno-omit-frame-pointer -Wall -Werror -Weverything -Wno-c++11-long-long -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded
|
||||
EXTRA_CXXFLAGS :=
|
||||
|
||||
all:
|
||||
clang++ -std=c++11 -g -O1 -I../../ -I../common $(EXTRA_CXXFLAGS) -o mesh-modify mesh-modify.cc mesh-util.cc tinygltf_impl.cc
|
||||
@@ -1,13 +0,0 @@
|
||||
# Mesh modify experiment
|
||||
|
||||
Sometimes we want to tweak mesh attributes(e.g. vertex position, uv coord, etc).
|
||||
glTF itself does not allow ASCII representation of such data.
|
||||
|
||||
This example show how to
|
||||
|
||||
- Export mesh data from .bin to .obj
|
||||
- Import mesh data to .bin(update corresponding buffer data) from .obj
|
||||
|
||||
## Requirement
|
||||
|
||||
Assume Buffer is stored as external file(`.bin`)
|
||||
@@ -1,760 +0,0 @@
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
|
||||
#if !defined(__ANDROID__) && !defined(_WIN32)
|
||||
#include <wordexp.h>
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Weverything"
|
||||
#endif
|
||||
|
||||
#include "../../json.hpp"
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "../../tiny_gltf.h"
|
||||
#else
|
||||
#include "tiny_gltf.h"
|
||||
#endif
|
||||
|
||||
#include "mesh-util.hh"
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic ignored "-Wunused-function"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
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**";
|
||||
}
|
||||
|
||||
#if 0
|
||||
// TODO(syoyo): Support sparse accessor(sparse vertex attribute).
|
||||
// TODO(syoyo): Support more data type
|
||||
struct VertexAttrib {
|
||||
std::string name;
|
||||
|
||||
// Value are converted to float type.
|
||||
std::vector<float> data;
|
||||
|
||||
// Corresponding info in binary data
|
||||
int data_type; // e.g. TINYGLTF_TYPE_VEC2
|
||||
int component_type; // storage type. e.g.
|
||||
// TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT
|
||||
uint64_t buffer_offset{0};
|
||||
size_t buffer_length{0};
|
||||
};
|
||||
|
||||
struct MeshPrim {
|
||||
std::string name;
|
||||
int32_t id{-1};
|
||||
|
||||
int mode{TINYGLTF_MODE_TRIANGLES};
|
||||
|
||||
VertexAttrib position; // vec3
|
||||
VertexAttrib normal; // vec3
|
||||
VertexAttrib tangent; // vec4
|
||||
VertexAttrib color; // vec3 or vec4
|
||||
std::map<int, VertexAttrib> texcoords; // <slot, attrib> vec2
|
||||
std::map<int, VertexAttrib> weights; // <slot, attrib>
|
||||
std::map<int, VertexAttrib>
|
||||
joints; // <slot, attrib> store data as float type
|
||||
|
||||
int indices_type{-1}; // storage type(componentType) of `indices`.
|
||||
std::vector<uint32_t> indices; // vertex indices
|
||||
};
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
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 "";
|
||||
}
|
||||
#endif
|
||||
|
||||
static size_t ComponentTypeByteSize(int type) {
|
||||
switch (type) {
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
|
||||
case TINYGLTF_COMPONENT_TYPE_BYTE:
|
||||
return sizeof(char);
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
|
||||
case TINYGLTF_COMPONENT_TYPE_SHORT:
|
||||
return sizeof(short);
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT:
|
||||
case TINYGLTF_COMPONENT_TYPE_INT:
|
||||
return sizeof(int);
|
||||
case TINYGLTF_COMPONENT_TYPE_FLOAT:
|
||||
return sizeof(float);
|
||||
case TINYGLTF_COMPONENT_TYPE_DOUBLE:
|
||||
return sizeof(double);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> LoadBin(const std::string &filename) {
|
||||
std::vector<uint8_t> data;
|
||||
|
||||
std::ifstream is(filename, std::ios::binary | std::ios::in | std::ios::ate);
|
||||
|
||||
if (is.is_open()) {
|
||||
size_t size = size_t(is.tellg());
|
||||
is.seekg(0, std::ios::beg);
|
||||
if (size < 4) {
|
||||
std::cerr << "File size is zero or too short: " << size << "\n";
|
||||
return data;
|
||||
}
|
||||
|
||||
data.resize(size);
|
||||
is.read(reinterpret_cast<char *>(data.data()), std::streamsize(size));
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
// TODO(syoyo): Use C++17 like filesystem library
|
||||
|
||||
bool FileExists(const std::string &abs_filename) {
|
||||
bool ret;
|
||||
#ifdef _WIN32
|
||||
// TODO(syoyo): Support utf8 filepath
|
||||
FILE *fp = nullptr;
|
||||
errno_t err = fopen_s(&fp, abs_filename.c_str(), "rb");
|
||||
if (err != 0) {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
FILE *fp = fopen(abs_filename.c_str(), "rb");
|
||||
#endif
|
||||
if (fp) {
|
||||
ret = true;
|
||||
fclose(fp);
|
||||
} else {
|
||||
ret = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static std::string JoinPath(const std::string &path0,
|
||||
const std::string &path1) {
|
||||
if (path0.empty()) {
|
||||
return path1;
|
||||
} else {
|
||||
// check '/'
|
||||
char lastChar = *path0.rbegin();
|
||||
if (lastChar != '/') {
|
||||
return path0 + std::string("/") + path1;
|
||||
} else {
|
||||
return path0 + path1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string ExpandFilePath(const std::string &filepath) {
|
||||
#ifdef _WIN32
|
||||
DWORD len = ExpandEnvironmentStringsA(filepath.c_str(), NULL, 0);
|
||||
char *str = new char[len];
|
||||
ExpandEnvironmentStringsA(filepath.c_str(), str, len);
|
||||
|
||||
std::string s(str);
|
||||
|
||||
delete[] str;
|
||||
|
||||
return s;
|
||||
#else
|
||||
|
||||
#if defined(TARGET_OS_IPHONE) || defined(TARGET_IPHONE_SIMULATOR) || \
|
||||
defined(__ANDROID__) || defined(__EMSCRIPTEN__)
|
||||
// no expansion
|
||||
std::string s = filepath;
|
||||
#else
|
||||
std::string s;
|
||||
wordexp_t p;
|
||||
|
||||
if (filepath.empty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Quote the string to keep any spaces in filepath intact.
|
||||
std::string quoted_path = "\"" + filepath + "\"";
|
||||
// char** w;
|
||||
int ret = wordexp(quoted_path.c_str(), &p, 0);
|
||||
if (ret) {
|
||||
// err
|
||||
s = filepath;
|
||||
return s;
|
||||
}
|
||||
|
||||
// Use first element only.
|
||||
if (p.we_wordv) {
|
||||
s = std::string(p.we_wordv[0]);
|
||||
wordfree(&p);
|
||||
} else {
|
||||
s = filepath;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return s;
|
||||
#endif
|
||||
}
|
||||
|
||||
static std::string FindFile(const std::vector<std::string> &paths,
|
||||
const std::string &filepath) {
|
||||
for (size_t i = 0; i < paths.size(); i++) {
|
||||
std::string absPath = ExpandFilePath(JoinPath(paths[i], filepath));
|
||||
if (FileExists(absPath)) {
|
||||
return absPath;
|
||||
}
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
#if 0
|
||||
static std::string GetBaseDir(const std::string &filepath) {
|
||||
if (filepath.find_last_of("/\\") != std::string::npos)
|
||||
return filepath.substr(0, filepath.find_last_of("/\\"));
|
||||
return "";
|
||||
}
|
||||
#endif
|
||||
|
||||
static int GetSlotId(const std::string &name) {
|
||||
if (name.rfind("TEXCOORD_", 0) == 0) {
|
||||
int id = 0;
|
||||
sscanf(name.c_str(), "TEXCOORD_%d", &id);
|
||||
return id;
|
||||
} else if (name.rfind("WEIGHTS_", 0) == 0) {
|
||||
int id = 0;
|
||||
sscanf(name.c_str(), "WEIGHTS_%d", &id);
|
||||
return id;
|
||||
} else if (name.rfind("JOINTS_", 0) == 0) {
|
||||
int id = 0;
|
||||
sscanf(name.c_str(), "JOINTS_%d", &id);
|
||||
return id;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static bool IsAttributeSupported(const std::string &name) {
|
||||
constexpr int max_slots = 8;
|
||||
|
||||
if (name.compare("POSITION") == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name.compare("NORMAL") == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name.compare("TANGENT") == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < max_slots; i++) {
|
||||
std::string n = "TEXCOORD_" + std::to_string(i);
|
||||
if (n.compare(name) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < max_slots; i++) {
|
||||
std::string n = "WEIGHTS_" + std::to_string(i);
|
||||
if (n.compare(name) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < max_slots; i++) {
|
||||
std::string n = "JOINTS_" + std::to_string(i);
|
||||
if (n.compare(name) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static float Unpack(const unsigned char *ptr, int type) {
|
||||
if (type == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
|
||||
unsigned char data = *ptr;
|
||||
return float(data);
|
||||
} else if (type == TINYGLTF_COMPONENT_TYPE_BYTE) {
|
||||
char data = static_cast<char>(*ptr);
|
||||
return float(data);
|
||||
} else if (type == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
|
||||
uint16_t data = *reinterpret_cast<const uint16_t *>(ptr);
|
||||
return float(data);
|
||||
} else if (type == TINYGLTF_COMPONENT_TYPE_SHORT) {
|
||||
int16_t data = *reinterpret_cast<const int16_t *>(ptr);
|
||||
return float(data);
|
||||
} else if (type == TINYGLTF_COMPONENT_TYPE_FLOAT) {
|
||||
float data = *reinterpret_cast<const float *>(ptr);
|
||||
return data;
|
||||
} else {
|
||||
std::cerr << "???: Unsupported type: " << PrintComponentType(type) << "\n";
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t UnpackIndex(const unsigned char *ptr, int type) {
|
||||
if (type == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
|
||||
unsigned char data = *ptr;
|
||||
return uint32_t(data);
|
||||
} else if (type == TINYGLTF_COMPONENT_TYPE_BYTE) {
|
||||
char data = static_cast<char>(*ptr);
|
||||
return uint32_t(data);
|
||||
} else if (type == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
|
||||
uint16_t data = *reinterpret_cast<const uint16_t *>(ptr);
|
||||
return uint32_t(data);
|
||||
} else if (type == TINYGLTF_COMPONENT_TYPE_SHORT) {
|
||||
int16_t data = *reinterpret_cast<const int16_t *>(ptr);
|
||||
return uint32_t(data);
|
||||
} else if (type == TINYGLTF_COMPONENT_TYPE_INT) {
|
||||
// TODO(syoyo): Check overflow(2G+ index)
|
||||
int32_t data = *reinterpret_cast<const int32_t *>(ptr);
|
||||
return uint32_t(data);
|
||||
} else if (type == TINYGLTF_COMPONENT_TYPE_SHORT) {
|
||||
uint32_t data = *reinterpret_cast<const uint32_t *>(ptr);
|
||||
return data;
|
||||
} else {
|
||||
std::cerr << "???: Unsupported type: " << PrintComponentType(type) << "\n";
|
||||
return static_cast<uint32_t>(-1);
|
||||
}
|
||||
}
|
||||
|
||||
static bool DumpMesh(const tinygltf::Model &model, const tinygltf::Mesh &mesh,
|
||||
example::MeshPrim *out) {
|
||||
for (size_t i = 0; i < mesh.primitives.size(); i++) {
|
||||
const tinygltf::Primitive &primitive = mesh.primitives[i];
|
||||
|
||||
if (primitive.indices < 0) {
|
||||
std::cerr << "Primitive indices must be provided\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// indices.
|
||||
{
|
||||
const tinygltf::Accessor &indexAccessor =
|
||||
model.accessors[size_t(primitive.indices)];
|
||||
|
||||
size_t num_elements = indexAccessor.count;
|
||||
std::cout << "index.elements = " << num_elements << "\n";
|
||||
|
||||
size_t byte_stride = ComponentTypeByteSize(indexAccessor.componentType);
|
||||
|
||||
const tinygltf::BufferView &indexBufferView =
|
||||
model.bufferViews[size_t(indexAccessor.bufferView)];
|
||||
|
||||
// should be 34963(ELEMENT_ARRAY_BUFFER)
|
||||
std::cout << "index.target = " << PrintTarget(indexBufferView.target) << "\n";
|
||||
if (indexBufferView.target != TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER) {
|
||||
std::cerr << "indexBufferView.target must be ELEMENT_ARRAY_BUFFER\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
const tinygltf::Buffer &indexBuffer =
|
||||
model.buffers[size_t(indexBufferView.buffer)];
|
||||
|
||||
std::vector<uint32_t> indices;
|
||||
|
||||
for (size_t k = 0; k < num_elements; k++) {
|
||||
|
||||
// TODO(syoyo): out-of-bounds check.
|
||||
const unsigned char *ptr = indexBuffer.data.data() +
|
||||
indexBufferView.byteOffset + (k * byte_stride) +
|
||||
indexAccessor.byteOffset;
|
||||
|
||||
uint32_t idx = UnpackIndex(ptr, indexAccessor.componentType);
|
||||
|
||||
std::cout << "vertex_index[" << k << "] = " << idx << "\n";
|
||||
|
||||
indices.push_back(idx);
|
||||
}
|
||||
|
||||
out->indices = indices;
|
||||
out->indices_type = indexAccessor.componentType;
|
||||
}
|
||||
|
||||
// attributes
|
||||
{
|
||||
std::map<std::string, int>::const_iterator it(
|
||||
primitive.attributes.begin());
|
||||
std::map<std::string, int>::const_iterator itEnd(
|
||||
primitive.attributes.end());
|
||||
|
||||
for (; it != itEnd; it++) {
|
||||
// it->first would be "POSITION", "NORMAL", "TEXCOORD_0", ...
|
||||
if (!IsAttributeSupported(it->first)) {
|
||||
std::cout << "Unsupported attribute: " << it->first << "\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (size_t(it->second) >= model.accessors.size()) {
|
||||
std::cerr << "Invalid accessor id: " << it->second << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
const tinygltf::Accessor &accessor =
|
||||
model.accessors[size_t(it->second)];
|
||||
|
||||
size_t elem_size = 1;
|
||||
if (accessor.type == TINYGLTF_TYPE_SCALAR) {
|
||||
elem_size = 1;
|
||||
} else if (accessor.type == TINYGLTF_TYPE_VEC2) {
|
||||
elem_size = 2;
|
||||
} else if (accessor.type == TINYGLTF_TYPE_VEC3) {
|
||||
elem_size = 3;
|
||||
} else if (accessor.type == TINYGLTF_TYPE_VEC4) {
|
||||
elem_size = 4;
|
||||
} else {
|
||||
std::cerr << "Invalid or unsupported accessor type: "
|
||||
<< PrintType(accessor.type) << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << PrintComponentType(accessor.componentType) << "\n";
|
||||
|
||||
size_t byte_stride = ComponentTypeByteSize(accessor.componentType);
|
||||
|
||||
std::cout << "attribute: " << it->first << "\n";
|
||||
// if (gGLProgramState.attribs[it->first] >= 0) {
|
||||
// Compute byteStride from Accessor + BufferView combination.
|
||||
int byteStride =
|
||||
accessor.ByteStride(model.bufferViews[size_t(accessor.bufferView)]);
|
||||
assert(byteStride != -1);
|
||||
|
||||
std::cout << "byteOffset: " << accessor.byteOffset << "\n";
|
||||
|
||||
const tinygltf::BufferView &bufferView =
|
||||
model.bufferViews[size_t(accessor.bufferView)];
|
||||
const tinygltf::Buffer &buffer =
|
||||
model.buffers[size_t(bufferView.buffer)];
|
||||
|
||||
size_t num_elems = accessor.count * elem_size;
|
||||
|
||||
example::VertexAttrib attrib;
|
||||
for (size_t k = 0; k < num_elems; k++) {
|
||||
// TODO(syoyo): out-of-bounds check.
|
||||
const unsigned char *ptr = buffer.data.data() +
|
||||
bufferView.byteOffset + (k * byte_stride) +
|
||||
accessor.byteOffset;
|
||||
float value = Unpack(ptr, accessor.componentType);
|
||||
std::cout << "[" << k << "] value = " << value << "\n";
|
||||
attrib.data.push_back(value);
|
||||
}
|
||||
attrib.component_type = accessor.componentType;
|
||||
attrib.data_type = accessor.type;
|
||||
attrib.name = it->first;
|
||||
|
||||
if (attrib.name.compare("POSITION") == 0) {
|
||||
out->position = attrib;
|
||||
} else if (attrib.name.compare("NORMAL") == 0) {
|
||||
out->normal = attrib;
|
||||
} else if (attrib.name.compare("TANGENT") == 0) {
|
||||
out->tangent = attrib;
|
||||
} else if (attrib.name.rfind("TEXCOORD_", 0) == 0) {
|
||||
int id = GetSlotId(attrib.name);
|
||||
std::cout << "texcoord[" << id << "]\n";
|
||||
out->texcoords[id] = attrib;
|
||||
} else if (attrib.name.rfind("JOINTS_", 0) == 0) {
|
||||
int id = GetSlotId(attrib.name);
|
||||
std::cout << "joints[" << id << "]\n";
|
||||
out->joints[id] = attrib;
|
||||
} else if (attrib.name.rfind("WEIGHTS_", 0) == 0) {
|
||||
int id = GetSlotId(attrib.name);
|
||||
std::cout << "weights[" << id << "]\n";
|
||||
out->weights[id] = attrib;
|
||||
} else {
|
||||
std::cerr << "???: attrib.name = " << attrib.name << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const tinygltf::Accessor &indexAccessor =
|
||||
model.accessors[size_t(primitive.indices)];
|
||||
(void)indexAccessor;
|
||||
PrintMode(primitive.mode);
|
||||
if (primitive.mode != TINYGLTF_MODE_TRIANGLES) {
|
||||
std::cerr << "Supported Primitive mode is TRIANGLES only at the moment\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
out->mode = primitive.mode;
|
||||
out->name = mesh.name;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static bool ExtractMesh(const std::string &asset_path, tinygltf::Model &model,
|
||||
std::vector<example::MeshPrim> *outs) {
|
||||
// Get .bin data
|
||||
{
|
||||
if (model.buffers.size() != 1) {
|
||||
std::cerr << "Single element of `buffers` is supported at the moment.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
const tinygltf::Buffer &buffer = model.buffers[0];
|
||||
if (buffer.uri.empty()) {
|
||||
std::cerr << "buffer.uri must be a filepath.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buffer.data.size() < 4) {
|
||||
std::cerr << "Invalid buffer.byteLength.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::string> search_paths;
|
||||
search_paths.push_back(asset_path);
|
||||
|
||||
std::string abs_filepath = FindFile(search_paths, buffer.uri);
|
||||
std::vector<uint8_t> bin = LoadBin(buffer.uri);
|
||||
if (bin.size() != buffer.data.size()) {
|
||||
std::cerr << "Byte size mismatch. Failed to load file: " << buffer.uri
|
||||
<< "\n";
|
||||
std::cerr << " .bin size = " << bin.size() << ", size in 'buffer.uri' = " << buffer.data.size() << "\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &mesh : model.meshes) {
|
||||
std::cout << "mesh.name: " << mesh.name << "\n";
|
||||
|
||||
example::MeshPrim output;
|
||||
bool ret = DumpMesh(model, mesh, &output);
|
||||
if (!ret) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outs->push_back(output);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 2) {
|
||||
std::cout << "mesh-dump input.gltf" << std::endl;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTF loader;
|
||||
std::string err;
|
||||
std::string warn;
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string input_filename(argv[1] ? argv[1]
|
||||
: "../../../models/Cube/Cube.gltf");
|
||||
#else
|
||||
std::string input_filename(argv[1] ? argv[1] : "../../models/Cube/Cube.gltf");
|
||||
#endif
|
||||
|
||||
std::string ext = GetFilePathExtension(input_filename);
|
||||
|
||||
{
|
||||
bool ret = false;
|
||||
if (ext.compare("glb") == 0) {
|
||||
// assume binary glTF.
|
||||
ret = loader.LoadBinaryFromFile(&model, &err, &warn,
|
||||
input_filename.c_str());
|
||||
} else {
|
||||
// assume ascii glTF.
|
||||
ret =
|
||||
loader.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 load .glTF : %s\n", argv[1]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
json j;
|
||||
{
|
||||
std::ifstream i(input_filename);
|
||||
i >> j;
|
||||
}
|
||||
std::cout << "j = " << j << "\n";
|
||||
|
||||
json j_patch = R"([
|
||||
{ "op": "add", "path": "/buffers/-", "value": {
|
||||
"name": "plane/data",
|
||||
"byteLength": 480,
|
||||
"uri": "plane1.bin"
|
||||
} }
|
||||
])"_json;
|
||||
|
||||
// a JSON value
|
||||
json j_original = R"({
|
||||
"baz": ["one", "two", "three"],
|
||||
"foo": "bar"
|
||||
})"_json;
|
||||
|
||||
//json j_patch = R"([
|
||||
// { "op": "remove", "path": "/buffers" }
|
||||
//])"_json;
|
||||
|
||||
std::cout << "patch = " << j_patch.dump(2) << "\n";
|
||||
|
||||
json j_ret = j.patch(j_patch);
|
||||
std::cout << "patched = " << j_ret.dump(2) << "\n";
|
||||
|
||||
std::string basedir = GetBaseDir(input_filename);
|
||||
std::vector<example::MeshPrim> meshes;
|
||||
bool ret = ExtractMesh(basedir, model, &meshes);
|
||||
|
||||
size_t n = 0;
|
||||
for (const auto &mesh : meshes) {
|
||||
// Assume no duplicated name in .glTF data
|
||||
std::string filename;
|
||||
if (mesh.name.empty()) {
|
||||
filename = "untitled-" + std::to_string(n) + ".obj";
|
||||
} else {
|
||||
filename = mesh.name + ".obj";
|
||||
}
|
||||
|
||||
bool flip_y = true; // flip texcoord Y?
|
||||
bool ok = example::SaveAsObjMesh(filename, mesh,);
|
||||
if (!ok) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
|
||||
return ret ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
#else
|
||||
|
||||
{
|
||||
std::string input_filename(argv[1]);
|
||||
|
||||
// Require facevarying layout?
|
||||
// false = try to keep GL-like mesh data as much as possible.
|
||||
// true = reorder vertex data and re-assign vertex indices.
|
||||
bool facevarying = false;
|
||||
|
||||
example::MeshPrim mesh;
|
||||
bool ok = example::LoadObjMesh(input_filename, facevarying, &mesh);
|
||||
if (!ok) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
PrintMeshPrim(mesh);
|
||||
|
||||
std::string output_filename("output.gltf");
|
||||
|
||||
ok = example::SaveAsGLTFMesh(output_filename, mesh);
|
||||
if (!ok) {
|
||||
std::cerr << "Failed to save mesh as glTF\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
std::cout << "Write glTF: " << output_filename << "\n";
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
#endif
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,76 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace example {
|
||||
|
||||
// TODO(syoyo): Support sparse accessor(sparse vertex attribute).
|
||||
// TODO(syoyo): Support more data type
|
||||
struct VertexAttrib {
|
||||
std::string name;
|
||||
|
||||
// Value are converted to float type.
|
||||
std::vector<float> data;
|
||||
|
||||
// Corresponding info in binary data
|
||||
int data_type; // e.g. TINYGLTF_TYPE_VEC2
|
||||
int component_type; // storage type. e.g.
|
||||
// TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT
|
||||
uint64_t buffer_offset{0};
|
||||
size_t buffer_length{0};
|
||||
|
||||
// Optional.
|
||||
std::vector<double> minValues;
|
||||
std::vector<double> maxValues;
|
||||
|
||||
size_t numElements() const;
|
||||
|
||||
};
|
||||
|
||||
struct MeshPrim {
|
||||
std::string name;
|
||||
int32_t id{-1};
|
||||
|
||||
int mode; // e.g. TRIANGLES
|
||||
|
||||
VertexAttrib position; // vec3
|
||||
VertexAttrib normal; // vec3
|
||||
VertexAttrib tangent; // vec4
|
||||
VertexAttrib color; // vec3 or vec4
|
||||
std::map<int, VertexAttrib> texcoords; // <slot, attrib> vec2
|
||||
std::map<int, VertexAttrib> weights; // <slot, attrib> vec4
|
||||
std::map<int, VertexAttrib>
|
||||
joints; // <slot, attrib> store data as float type
|
||||
|
||||
|
||||
// min/max of index value. -1 = undef
|
||||
int indices_min{-1};
|
||||
int indices_max{-1};
|
||||
int indices_type{-1}; // storage type(componentType) of `indices`.
|
||||
std::vector<uint32_t> indices; // vertex indices
|
||||
};
|
||||
|
||||
///
|
||||
/// Save MeshPrim as wavefront .obj
|
||||
///
|
||||
bool SaveAsObjMesh(const std::string &filename, const MeshPrim &mesh);
|
||||
|
||||
///
|
||||
/// Save MeshPrim as glTF mesh
|
||||
///
|
||||
bool SaveAsGLTFMesh(const std::string &filename, const MeshPrim &mesh);
|
||||
|
||||
///
|
||||
/// Loads .obj and convert to MeshPrim
|
||||
///
|
||||
/// @param[in] facevarying Construct mesh with facevarying vertex layout(default false)
|
||||
///
|
||||
bool LoadObjMesh(const std::string &filename, bool facevarying, MeshPrim *mesh);
|
||||
|
||||
///
|
||||
/// Print MeshPrim datra
|
||||
///
|
||||
void PrintMeshPrim(const MeshPrim &mesh);
|
||||
|
||||
} // namespace example
|
||||
@@ -1,7 +0,0 @@
|
||||
project('mesh-modify', 'cpp', default_options : ['cpp_std=c++11'])
|
||||
|
||||
thread_dep = dependency('threads')
|
||||
|
||||
incdir = include_directories(['../../', '../common'])
|
||||
|
||||
executable('mesh-modify', ['mesh-modify.cc', 'mesh-util.cc', 'tinygltf_impl.cc'], include_directories : incdir, dependencies : thread_dep)
|
||||
@@ -150,7 +150,6 @@ bool LoadObj(const std::string &filename, float scale,
|
||||
tinyobj::attrib_t attrib;
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
std::string warn;
|
||||
std::string err;
|
||||
|
||||
std::string basedir = GetBaseDir(filename) + "/";
|
||||
@@ -159,16 +158,12 @@ bool LoadObj(const std::string &filename, float scale,
|
||||
// auto t_start = std::chrono::system_clock::now();
|
||||
|
||||
bool ret =
|
||||
tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, filename.c_str(),
|
||||
tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename.c_str(),
|
||||
basepath, /* triangulate */ true);
|
||||
|
||||
// auto t_end = std::chrono::system_clock::now();
|
||||
// std::chrono::duration<double, std::milli> ms = t_end - t_start;
|
||||
|
||||
if (!warn.empty()) {
|
||||
std::cout << warn << std::endl;
|
||||
}
|
||||
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
|
||||
BIN
models/Extensions-overwrite-issue261/issue-261.bin
Normal file
BIN
models/Extensions-overwrite-issue261/issue-261.bin
Normal file
Binary file not shown.
376
models/Extensions-overwrite-issue261/issue-261.gltf
Normal file
376
models/Extensions-overwrite-issue261/issue-261.gltf
Normal file
@@ -0,0 +1,376 @@
|
||||
{
|
||||
"accessors": [
|
||||
{
|
||||
"bufferView": 0,
|
||||
"componentType": 5126,
|
||||
"count": 8,
|
||||
"max": [
|
||||
0.5,
|
||||
0.5,
|
||||
0.5
|
||||
],
|
||||
"min": [
|
||||
-0.5,
|
||||
-0.5,
|
||||
-0.5
|
||||
],
|
||||
"type": "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView": 1,
|
||||
"componentType": 5125,
|
||||
"count": 36,
|
||||
"type": "SCALAR"
|
||||
}
|
||||
],
|
||||
"asset": {
|
||||
"copyright": "NVIDIA Corporation",
|
||||
"generator": "Iray glTF plugin",
|
||||
"version": "2.0"
|
||||
},
|
||||
"bufferViews": [
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteLength": 96,
|
||||
"byteStride": 12
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteLength": 144,
|
||||
"byteOffset": 96
|
||||
}
|
||||
],
|
||||
"buffers": [
|
||||
{
|
||||
"byteLength": 240,
|
||||
"uri": "issue-261.bin"
|
||||
}
|
||||
],
|
||||
"cameras": [
|
||||
{
|
||||
"extensions": {
|
||||
"NV_Iray": {
|
||||
"mip_burn_highlights": 0.699999988079071,
|
||||
"mip_burn_highlights_per_component": false,
|
||||
"mip_camera_shutter": 4.0,
|
||||
"mip_cm2_factor": 1.0,
|
||||
"mip_crush_blacks": 0.5,
|
||||
"mip_f_number": 1.0,
|
||||
"mip_film_iso": 100.0,
|
||||
"mip_gamma": 2.200000047683716,
|
||||
"mip_saturation": 1.0,
|
||||
"mip_vignetting": 0.00019999999494757503,
|
||||
"mip_whitepoint": [
|
||||
1.0,
|
||||
1.0,
|
||||
1.0,
|
||||
1.0
|
||||
],
|
||||
"tm_enable_tonemapper": true,
|
||||
"tm_tonemapper": "mia_exposure_photographic"
|
||||
}
|
||||
},
|
||||
"extras": {
|
||||
"resolution": [
|
||||
640,
|
||||
480
|
||||
]
|
||||
},
|
||||
"name": "default",
|
||||
"perspective": {
|
||||
"aspectRatio": 1.3333333730697632,
|
||||
"yfov": 0.9272952079772949,
|
||||
"zfar": 1000.0,
|
||||
"znear": 0.1
|
||||
},
|
||||
"type": "perspective"
|
||||
}
|
||||
],
|
||||
"extensions": {
|
||||
"KHR_lights_punctual": {
|
||||
"lights": [
|
||||
{
|
||||
"color": [
|
||||
1.0,
|
||||
1.0,
|
||||
1.0
|
||||
],
|
||||
"intensity": 1000.0,
|
||||
"name": "light",
|
||||
"type": "point"
|
||||
}
|
||||
]
|
||||
},
|
||||
"NV_MDL": {
|
||||
"modules": [
|
||||
"mdl::base",
|
||||
"mdl::nvidia::core_definitions",
|
||||
"mdl::state"
|
||||
],
|
||||
"shaders": [
|
||||
{
|
||||
"definition": "mdl::base::environment_spherical(texture_2d)",
|
||||
"name": "env_shd"
|
||||
},
|
||||
{
|
||||
"arguments": {
|
||||
"base_color": [
|
||||
0.0055217444896698,
|
||||
0.36859095096588135,
|
||||
0.0041161770932376385
|
||||
],
|
||||
"normal=": 2
|
||||
},
|
||||
"definition": "mdl::nvidia::core_definitions::flex_material",
|
||||
"name": "cube_instance_material"
|
||||
},
|
||||
{
|
||||
"definition": "mdl::state::normal()",
|
||||
"name": "mdl::state::normal_341"
|
||||
},
|
||||
{
|
||||
"arguments": {
|
||||
"base_color": [
|
||||
0.0055217444896698,
|
||||
0.36859095096588135,
|
||||
0.0041161770932376385
|
||||
],
|
||||
"normal=": 4
|
||||
},
|
||||
"definition": "mdl::nvidia::core_definitions::flex_material",
|
||||
"name": "cube_instance_material"
|
||||
},
|
||||
{
|
||||
"definition": "mdl::state::normal()",
|
||||
"name": "mdl::state::normal_341"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"extensionsUsed": [
|
||||
"NV_MDL",
|
||||
"NV_Iray",
|
||||
"KHR_lights_punctual"
|
||||
],
|
||||
"materials": [
|
||||
{
|
||||
"doubleSided": true,
|
||||
"extras": {
|
||||
"mdl_shader": 1
|
||||
},
|
||||
"name": "cube_instance_material",
|
||||
"pbrMetallicRoughness": {
|
||||
"baseColorFactor": [
|
||||
0.0055217444896698,
|
||||
0.36859095096588135,
|
||||
0.0041161770932376385,
|
||||
1.0
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"meshes": [
|
||||
{
|
||||
"name": "cube",
|
||||
"primitives": [
|
||||
{
|
||||
"attributes": {
|
||||
"POSITION": 0
|
||||
},
|
||||
"indices": 1,
|
||||
"material": 0,
|
||||
"mode": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"camera": 0,
|
||||
"extensions": {
|
||||
"NV_Iray": {
|
||||
"iview:fkey": -1,
|
||||
"iview:fov": 53.130104064941406,
|
||||
"iview:interest": [
|
||||
0.1342654824256897,
|
||||
-0.14356137812137604,
|
||||
0.037264324724674225
|
||||
],
|
||||
"iview:position": [
|
||||
0.9729073643684387,
|
||||
1.2592438459396362,
|
||||
2.4199187755584717
|
||||
],
|
||||
"iview:roll": 0.0,
|
||||
"iview:up": [
|
||||
0.0,
|
||||
1.0,
|
||||
0.0
|
||||
]
|
||||
}
|
||||
},
|
||||
"matrix": [
|
||||
0.9432751389105357,
|
||||
-1.1769874756875739e-16,
|
||||
-0.3320120665176343,
|
||||
0.0,
|
||||
-0.16119596696756341,
|
||||
0.8742297945345237,
|
||||
-0.45797175303889276,
|
||||
0.0,
|
||||
0.290254840694694,
|
||||
0.48551237507207207,
|
||||
0.8246392308792816,
|
||||
0.0,
|
||||
0.9729073377709113,
|
||||
1.2592438262175363,
|
||||
2.419918748461627,
|
||||
1.0
|
||||
],
|
||||
"name": "CamInst"
|
||||
},
|
||||
{
|
||||
"extensions": {
|
||||
"NV_Iray": {
|
||||
"caustic": true,
|
||||
"caustic_cast": true,
|
||||
"caustic_recv": true,
|
||||
"face_back": true,
|
||||
"face_front": true,
|
||||
"finalgather": true,
|
||||
"finalgather_cast": true,
|
||||
"finalgather_recv": true,
|
||||
"globillum": true,
|
||||
"globillum_cast": true,
|
||||
"globillum_recv": true,
|
||||
"material=": 3,
|
||||
"pickable": true,
|
||||
"reflection_cast": true,
|
||||
"reflection_recv": true,
|
||||
"refraction_cast": true,
|
||||
"refraction_recv": true,
|
||||
"shadow_cast": true,
|
||||
"shadow_recv": true,
|
||||
"transparency_cast": true,
|
||||
"transparency_recv": true,
|
||||
"visible": true
|
||||
}
|
||||
},
|
||||
"mesh": 0,
|
||||
"name": "cube_instance"
|
||||
},
|
||||
{
|
||||
"extensions": {
|
||||
"KHR_lights_punctual": {
|
||||
"light": 0
|
||||
},
|
||||
"NV_Iray": {
|
||||
"shadow_cast": true,
|
||||
"visible": false
|
||||
}
|
||||
},
|
||||
"matrix": [
|
||||
0.6988062355563571,
|
||||
-7.76042172309776e-17,
|
||||
-0.7153110128800992,
|
||||
-0.0,
|
||||
-0.4276881690736487,
|
||||
0.8015668284138362,
|
||||
-0.41781987700564616,
|
||||
-0.0,
|
||||
0.57336957992379,
|
||||
0.5979051928078428,
|
||||
0.5601398979107212,
|
||||
0.0,
|
||||
2.3640632834071384,
|
||||
2.465226204472449,
|
||||
2.309515908392224,
|
||||
1.0
|
||||
],
|
||||
"name": "light_inst"
|
||||
}
|
||||
],
|
||||
"scene": 0,
|
||||
"scenes": [
|
||||
{
|
||||
"extensions": {
|
||||
"NV_Iray": {
|
||||
"CP_canny_threshold1": 40,
|
||||
"CP_canny_threshold2": 120,
|
||||
"CP_color_quantization": 8,
|
||||
"IVP_color": [
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0
|
||||
],
|
||||
"TM_drago_bias": 0.8500000238418579,
|
||||
"TM_drago_gamma2": 2.200000047683716,
|
||||
"TM_drago_saturation": 1.0,
|
||||
"TM_durand_contrast": 4.0,
|
||||
"TM_durand_gamma": 2.200000047683716,
|
||||
"TM_durand_saturation": 1.0,
|
||||
"TM_durand_sigma_color": 2.0,
|
||||
"TM_durand_sigma_space": 2.0,
|
||||
"TM_linear_gamma": 2.200000047683716,
|
||||
"TM_reinhard_color_adapt": 0.8999999761581421,
|
||||
"TM_reinhard_gamma": 1.0,
|
||||
"TM_reinhard_intensity": 0.0,
|
||||
"TM_reinhard_light_adapt": 1.0,
|
||||
"TM_reye_Ywhite": 1000000.0,
|
||||
"TM_reye_bsize": 2,
|
||||
"TM_reye_bthres": 3.0,
|
||||
"TM_reye_gamma": 2.200000047683716,
|
||||
"TM_reye_key": 0.5,
|
||||
"TM_reye_saturation": 1.0,
|
||||
"TM_reye_whitebalance": [
|
||||
1.0,
|
||||
0.9965101480484009,
|
||||
0.9805564880371094,
|
||||
0.0
|
||||
],
|
||||
"environment_dome_depth": 200.0,
|
||||
"environment_dome_height": 200.0,
|
||||
"environment_dome_mode": "infinite",
|
||||
"environment_dome_position": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"environment_dome_radius": 100.0,
|
||||
"environment_dome_rotation_angle": 0.0,
|
||||
"environment_dome_width": 200.0,
|
||||
"environment_function=": 0,
|
||||
"environment_function_intensity": 1.9900000095367432,
|
||||
"iray_instancing": "off",
|
||||
"iview::inline_color": [
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0
|
||||
],
|
||||
"iview::inline_width": 1.0,
|
||||
"iview::magnifier_size": 300,
|
||||
"iview::offset": 10.0,
|
||||
"iview::outline_color": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0
|
||||
],
|
||||
"iview::outline_width": 2.0,
|
||||
"iview::overview": true,
|
||||
"iview::zoom_factor": 1.0,
|
||||
"samples": 4.0,
|
||||
"shadow_cast": true,
|
||||
"shadow_recv": true
|
||||
}
|
||||
},
|
||||
"nodes": [
|
||||
0,
|
||||
1,
|
||||
2
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -93,6 +93,59 @@ TEST_CASE("extension-with-empty-object", "[issue-97]") {
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("extension-overwrite", "[issue-261]") {
|
||||
|
||||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTF ctx;
|
||||
std::string err;
|
||||
std::string warn;
|
||||
|
||||
bool ret = ctx.LoadASCIIFromFile(&model, &err, &warn, "../models/Extensions-overwrite-issue261/issue-261.gltf");
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
REQUIRE(true == ret);
|
||||
|
||||
REQUIRE(model.extensionsUsed.size() == 3);
|
||||
{
|
||||
bool has_ext_lights = false;
|
||||
has_ext_lights |= (model.extensionsUsed[0].compare("KHR_lights_punctual") == 0);
|
||||
has_ext_lights |= (model.extensionsUsed[1].compare("KHR_lights_punctual") == 0);
|
||||
has_ext_lights |= (model.extensionsUsed[2].compare("KHR_lights_punctual") == 0);
|
||||
|
||||
REQUIRE(true == has_ext_lights);
|
||||
}
|
||||
|
||||
{
|
||||
REQUIRE(model.extensions.size() == 2);
|
||||
REQUIRE(model.extensions.count("NV_MDL"));
|
||||
REQUIRE(model.extensions.count("KHR_lights_punctual"));
|
||||
}
|
||||
|
||||
// TODO(syoyo): create temp directory.
|
||||
{
|
||||
ret = ctx.WriteGltfSceneToFile(&model, "issue-261.gltf", true, true);
|
||||
REQUIRE(true == ret);
|
||||
|
||||
tinygltf::Model m;
|
||||
|
||||
// read back serialized glTF
|
||||
bool ret = ctx.LoadASCIIFromFile(&m, &err, &warn, "issue-261.gltf");
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
REQUIRE(true == ret);
|
||||
|
||||
REQUIRE(m.extensionsUsed.size() == 3);
|
||||
|
||||
REQUIRE(m.extensions.size() == 2);
|
||||
REQUIRE(m.extensions.count("NV_MDL"));
|
||||
REQUIRE(m.extensions.count("KHR_lights_punctual"));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("invalid-primitive-indices", "[bounds-checking]") {
|
||||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTF ctx;
|
||||
@@ -359,3 +412,19 @@ TEST_CASE("image-uri-spaces", "[issue-236]") {
|
||||
REQUIRE(true == ret);
|
||||
}
|
||||
|
||||
#ifndef TINYGLTF_NO_FS
|
||||
TEST_CASE("expandpath-utf-8", "[pr-226]") {
|
||||
|
||||
std::string s1 = "\xe5\xaf\xb9"; // utf-8 string
|
||||
|
||||
std::string ret = tinygltf::ExpandFilePath(s1, /* userdata */nullptr);
|
||||
|
||||
// expected: E5 AF B9
|
||||
REQUIRE(3 == ret.size());
|
||||
|
||||
REQUIRE(0xe5 == static_cast<uint8_t>(ret[0]));
|
||||
REQUIRE(0xaf == static_cast<uint8_t>(ret[1]));
|
||||
REQUIRE(0xb9 == static_cast<uint8_t>(ret[2]));
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
373
tiny_gltf.h
373
tiny_gltf.h
@@ -26,6 +26,8 @@
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Version:
|
||||
// - v2.4.3 Experimental sajson(lightweight JSON parser) backend support.
|
||||
// Introduce TINYGLTF_ENABLE_SERIALIZER.
|
||||
// - v2.4.2 Decode percent-encoded URI.
|
||||
// - v2.4.1 Fix some glTF object class does not have `extensions` and/or
|
||||
// `extras` property.
|
||||
@@ -43,6 +45,7 @@
|
||||
//
|
||||
// Tiny glTF loader is using following third party libraries:
|
||||
//
|
||||
// - sajso: Lightweight C++ JSON library.
|
||||
// - jsonhpp: C++ JSON library.
|
||||
// - base64: base64 decode/encode library.
|
||||
// - stb_image: Image loading library.
|
||||
@@ -52,6 +55,7 @@
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cmath> // std::fabs
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
@@ -322,7 +326,8 @@ class Value {
|
||||
}
|
||||
|
||||
// Use this function if you want to have number value as int.
|
||||
double GetNumberAsInt() const {
|
||||
// TODO(syoyo): Support int value larger than 32 bits
|
||||
int GetNumberAsInt() const {
|
||||
if (type_ == REAL_TYPE) {
|
||||
return int(real_value_);
|
||||
} else {
|
||||
@@ -1113,9 +1118,9 @@ struct SpotLight {
|
||||
struct Light {
|
||||
std::string name;
|
||||
std::vector<double> color;
|
||||
double intensity;
|
||||
double intensity{1.0};
|
||||
std::string type;
|
||||
double range;
|
||||
double range{0.0}; // 0.0 = inifinite
|
||||
SpotLight spot;
|
||||
|
||||
Light() : intensity(1.0), range(0.0) {}
|
||||
@@ -1247,7 +1252,13 @@ struct FsCallbacks {
|
||||
|
||||
bool FileExists(const std::string &abs_filename, void *);
|
||||
|
||||
std::string ExpandFilePath(const std::string &filepath, void *);
|
||||
///
|
||||
/// Expand file path(e.g. `~` to home directory on posix, `%APPDATA%` to `C:\Users\tinygltf\AppData`)
|
||||
///
|
||||
/// @param[in] filepath File path string. Assume UTF-8
|
||||
/// @param[in] userdata User data. Set to `nullptr` if you don't need it.
|
||||
///
|
||||
std::string ExpandFilePath(const std::string &filepath, void *userdata);
|
||||
|
||||
bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
|
||||
const std::string &filepath, void *);
|
||||
@@ -1315,6 +1326,8 @@ class TinyGLTF {
|
||||
const std::string &base_dir = "",
|
||||
unsigned int check_sections = REQUIRE_VERSION);
|
||||
|
||||
#if defined(TINYGLTF_ENABLE_SERIALIZER)
|
||||
|
||||
///
|
||||
/// Write glTF to stream, buffers and images will be embeded
|
||||
///
|
||||
@@ -1328,16 +1341,22 @@ class TinyGLTF {
|
||||
bool embedImages, bool embedBuffers,
|
||||
bool prettyPrint, bool writeBinary);
|
||||
|
||||
#endif
|
||||
|
||||
///
|
||||
/// Set callback to use for loading image data
|
||||
///
|
||||
void SetImageLoader(LoadImageDataFunction LoadImageData, void *user_data);
|
||||
|
||||
#if defined(TINYGLTF_ENABLE_SERIALIZER)
|
||||
|
||||
///
|
||||
/// Set callback to use for writing image data
|
||||
///
|
||||
void SetImageWriter(WriteImageDataFunction WriteImageData, void *user_data);
|
||||
|
||||
#endif
|
||||
|
||||
///
|
||||
/// Set callbacks to use for filesystem (fs) access and their user data
|
||||
///
|
||||
@@ -1499,14 +1518,38 @@ class TinyGLTF {
|
||||
#endif // __GNUC__
|
||||
|
||||
#ifndef TINYGLTF_NO_INCLUDE_JSON
|
||||
#ifndef TINYGLTF_USE_RAPIDJSON
|
||||
#include "json.hpp"
|
||||
#else
|
||||
#if defined(TINYGLTF_USE_RAPIDJSON)
|
||||
#include "document.h"
|
||||
#include "prettywriter.h"
|
||||
#include "rapidjson.h"
|
||||
#include "stringbuffer.h"
|
||||
#include "writer.h"
|
||||
#elif defined(TINYGLTF_USE_SAJSON)
|
||||
|
||||
#ifdef __clang__
|
||||
|
||||
#if __has_warning("-Wc99-extensions")
|
||||
#pragma clang diagnostic ignored "-Wc99-extensions"
|
||||
#endif
|
||||
|
||||
#if __has_warning("-Wshadow-field-in-constructor")
|
||||
#pragma clang diagnostic ignored "-Wshadow-field-in-constructor"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include "sajson.h"
|
||||
|
||||
// Serialization is not available for sajson backend.
|
||||
#ifdef TINYGLTF_ENABLE_SERIALIZER
|
||||
#undef TINYGLTF_ENABLE_SERIALIZER
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
// Default = nlohmann json
|
||||
#include "json.hpp"
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1642,7 +1685,62 @@ struct JsonDocument : public rapidjson::Document {
|
||||
|
||||
#endif // TINYGLTF_USE_RAPIDJSON_CRTALLOCATOR
|
||||
|
||||
#else
|
||||
#elif defined(TINYGLTF_USE_SAJSON)
|
||||
|
||||
using json = sajson::value;
|
||||
using JsonDocument = json;
|
||||
|
||||
// TODO(syoyo): Implement
|
||||
// muda
|
||||
|
||||
class sajson_const_iterator
|
||||
{
|
||||
public:
|
||||
sajson_const_iterator() = default;
|
||||
sajson_const_iterator(const sajson::value &v) : _v(v) {
|
||||
}
|
||||
|
||||
sajson_const_iterator(const sajson_const_iterator &rhs) = default;
|
||||
sajson_const_iterator &operator=(const sajson_const_iterator &rhs) = default;
|
||||
|
||||
std::string key() const {
|
||||
}
|
||||
|
||||
sajson::value &value() {
|
||||
return _v;
|
||||
}
|
||||
|
||||
sajson::value *begin() {
|
||||
return &_v;
|
||||
}
|
||||
|
||||
bool operator!=(sajson_const_iterator &rhs) {
|
||||
// TODO
|
||||
assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
sajson_const_iterator &operator++() {
|
||||
// TODO
|
||||
assert(0);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
sajson::value &operator*() {
|
||||
return _v;
|
||||
}
|
||||
|
||||
private:
|
||||
// `sajson::value` itself is a small struct, so having a copy of it
|
||||
// does not affect performance and memory consumption.
|
||||
sajson::value _v;
|
||||
|
||||
};
|
||||
|
||||
using json_const_iterator = sajson_const_iterator;
|
||||
using json_const_array_iterator = json_const_iterator;
|
||||
|
||||
#else // nlohmann JSON
|
||||
using nlohmann::json;
|
||||
using json_const_iterator = json::const_iterator;
|
||||
using json_const_array_iterator = json_const_iterator;
|
||||
@@ -1654,6 +1752,14 @@ void JsonParse(JsonDocument &doc, const char *str, size_t length,
|
||||
#ifdef TINYGLTF_USE_RAPIDJSON
|
||||
(void)throwExc;
|
||||
doc.Parse(str, length);
|
||||
#elif defined(TINYGLTF_USE_SAJSON)
|
||||
// This code path is not available.
|
||||
(void)doc;
|
||||
(void)str;
|
||||
(void)length;
|
||||
(void)throwExc;
|
||||
//doc = sajson::parse(sajson::dynamic_allocation(), sajson::mutable_string_view(length, const_cast<char *>(str)));
|
||||
//doc.parse(sajson::dynamic_allocation(), sajson::mutable_string_view(length, const_cast<char *>(str)));
|
||||
#else
|
||||
doc = json::parse(str, str + length, nullptr, throwExc);
|
||||
#endif
|
||||
@@ -2385,11 +2491,15 @@ bool LoadImageData(Image *image, const int image_idx, std::string *err,
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(TINYGLTF_ENABLE_SERIALIZER)
|
||||
|
||||
void TinyGLTF::SetImageWriter(WriteImageDataFunction func, void *user_data) {
|
||||
WriteImageData = func;
|
||||
write_image_user_data_ = user_data;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
|
||||
static void WriteToMemory_stbi(void *context, void *data, int size) {
|
||||
std::vector<unsigned char> *buffer =
|
||||
@@ -2481,6 +2591,15 @@ static inline std::wstring UTF8ToWchar(const std::string &str) {
|
||||
(int)wstr.size());
|
||||
return wstr;
|
||||
}
|
||||
|
||||
static inline std::string WcharToUTF8(const std::wstring &wstr) {
|
||||
int str_size = WideCharToMultiByte(CP_UTF8, 0, wstr.data(), (int)wstr.size(),
|
||||
nullptr, 0, NULL, NULL);
|
||||
std::string str(str_size, 0);
|
||||
WideCharToMultiByte(CP_UTF8, 0, wstr.data(), (int)wstr.size(), &str[0],
|
||||
(int)str.size(), NULL, NULL);
|
||||
return str;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef TINYGLTF_NO_FS
|
||||
@@ -2532,15 +2651,16 @@ bool FileExists(const std::string &abs_filename, void *) {
|
||||
|
||||
std::string ExpandFilePath(const std::string &filepath, void *) {
|
||||
#ifdef _WIN32
|
||||
DWORD len = ExpandEnvironmentStringsA(filepath.c_str(), NULL, 0);
|
||||
char *str = new char[len];
|
||||
ExpandEnvironmentStringsA(filepath.c_str(), str, len);
|
||||
// Assume input `filepath` is encoded in UTF-8
|
||||
std::wstring wfilepath = UTF8ToWchar(filepath);
|
||||
DWORD wlen = ExpandEnvironmentStringsW(wfilepath.c_str(), nullptr, 0);
|
||||
wchar_t *wstr = new wchar_t[wlen];
|
||||
ExpandEnvironmentStringsW(wfilepath.c_str(), wstr, wlen);
|
||||
|
||||
std::string s(str);
|
||||
std::wstring ws(wstr);
|
||||
delete[] wstr;
|
||||
return WcharToUTF8(ws);
|
||||
|
||||
delete[] str;
|
||||
|
||||
return s;
|
||||
#else
|
||||
|
||||
#if defined(TARGET_OS_IPHONE) || defined(TARGET_IPHONE_SIMULATOR) || \
|
||||
@@ -2592,11 +2712,12 @@ bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
|
||||
return false;
|
||||
}
|
||||
size_t size = AAsset_getLength(asset);
|
||||
if (size <= 0) {
|
||||
if (size == 0) {
|
||||
if (err) {
|
||||
(*err) += "Invalid file size : " + filepath +
|
||||
" (does the path point to a directory?)";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
out->resize(size);
|
||||
AAsset_read(asset, reinterpret_cast<char *>(&out->at(0)), size);
|
||||
@@ -2615,9 +2736,11 @@ bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
|
||||
_wopen(UTF8ToWchar(filepath).c_str(), _O_RDONLY | _O_BINARY);
|
||||
__gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor, std::ios_base::in);
|
||||
std::istream f(&wfile_buf);
|
||||
#elif defined(_MSC_VER)
|
||||
#elif defined(_MSC_VER) || defined(_LIBCPP_VERSION)
|
||||
// For libcxx, assume _LIBCPP_HAS_OPEN_WITH_WCHAR is defined to accept `wchar_t *`
|
||||
std::ifstream f(UTF8ToWchar(filepath).c_str(), std::ifstream::binary);
|
||||
#else // clang?
|
||||
#else
|
||||
// Unknown compiler/runtime
|
||||
std::ifstream f(filepath.c_str(), std::ifstream::binary);
|
||||
#endif
|
||||
#else
|
||||
@@ -2659,9 +2782,10 @@ bool WriteWholeFile(std::string *err, const std::string &filepath,
|
||||
const std::vector<unsigned char> &contents, void *) {
|
||||
#ifdef _WIN32
|
||||
#if defined(__GLIBCXX__) // mingw
|
||||
int file_descriptor =
|
||||
_wopen(UTF8ToWchar(filepath).c_str(), _O_WRONLY | _O_BINARY);
|
||||
__gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor, std::ios_base::in);
|
||||
int file_descriptor = _wopen(UTF8ToWchar(filepath).c_str(),
|
||||
_O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY);
|
||||
__gnu_cxx::stdio_filebuf<char> wfile_buf(
|
||||
file_descriptor, std::ios_base::out | std::ios_base::binary);
|
||||
std::ostream f(&wfile_buf);
|
||||
#elif defined(_MSC_VER)
|
||||
std::ofstream f(UTF8ToWchar(filepath).c_str(), std::ofstream::binary);
|
||||
@@ -2712,12 +2836,13 @@ static void UpdateImageObject(Image &image, std::string &baseDir, int index,
|
||||
void *user_data = nullptr) {
|
||||
std::string filename;
|
||||
std::string ext;
|
||||
|
||||
// If image have uri. Use it it as a filename
|
||||
// If image has uri, use it it as a filename
|
||||
if (image.uri.size()) {
|
||||
filename = GetBaseFilename(image.uri);
|
||||
ext = GetFilePathExtension(filename);
|
||||
|
||||
} else if (image.bufferView != -1) {
|
||||
// If there's no URI and the data exists in a buffer,
|
||||
// don't change properties or write images
|
||||
} else if (image.name.size()) {
|
||||
ext = MimeToExt(image.mimeType);
|
||||
// Otherwise use name as filename
|
||||
@@ -2729,7 +2854,7 @@ static void UpdateImageObject(Image &image, std::string &baseDir, int index,
|
||||
}
|
||||
|
||||
// If callback is set, modify image data object
|
||||
if (*WriteImageData != nullptr) {
|
||||
if (*WriteImageData != nullptr && !filename.empty()) {
|
||||
std::string uri;
|
||||
(*WriteImageData)(&baseDir, &filename, &image, embedImages, user_data);
|
||||
}
|
||||
@@ -2865,6 +2990,15 @@ bool GetInt(const json &o, int &val) {
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
#elif defined(TINYGLTF_USE_SAJSON)
|
||||
auto type = o.get_type();
|
||||
|
||||
if (type == sajson::TYPE_INTEGER) {
|
||||
val = static_cast<int>(o.get_number_value());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
#else
|
||||
auto type = o.type();
|
||||
@@ -2897,6 +3031,16 @@ bool GetNumber(const json &o, double &val) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
#elif defined(TINYGLTF_USE_SAJSON)
|
||||
auto type = o.get_type();
|
||||
|
||||
if ((type == sajson::TYPE_DOUBLE) ||
|
||||
(type == sajson::TYPE_INTEGER)) {
|
||||
val = static_cast<double>(o.get_number_value());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
#else
|
||||
if (o.is_number()) {
|
||||
@@ -2915,6 +3059,15 @@ bool GetString(const json &o, std::string &val) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
#elif defined(TINYGLTF_USE_SAJSON)
|
||||
auto type = o.get_type();
|
||||
|
||||
if (type == sajson::TYPE_STRING) {
|
||||
val = o.as_string();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
#else
|
||||
if (o.type() == json::value_t::string) {
|
||||
@@ -2929,6 +3082,8 @@ bool GetString(const json &o, std::string &val) {
|
||||
bool IsArray(const json &o) {
|
||||
#ifdef TINYGLTF_USE_RAPIDJSON
|
||||
return o.IsArray();
|
||||
#elif defined(TINYGLTF_USE_SAJSON)
|
||||
return o.get_type() == sajson::TYPE_ARRAY;
|
||||
#else
|
||||
return o.is_array();
|
||||
#endif
|
||||
@@ -2937,6 +3092,10 @@ bool IsArray(const json &o) {
|
||||
json_const_array_iterator ArrayBegin(const json &o) {
|
||||
#ifdef TINYGLTF_USE_RAPIDJSON
|
||||
return o.Begin();
|
||||
#elif TINYGLTF_USE_SAJSON
|
||||
// TODO(syoyo): Implement
|
||||
assert(0);
|
||||
return json_const_array_iterator(o);
|
||||
#else
|
||||
return o.begin();
|
||||
#endif
|
||||
@@ -2945,6 +3104,10 @@ json_const_array_iterator ArrayBegin(const json &o) {
|
||||
json_const_array_iterator ArrayEnd(const json &o) {
|
||||
#ifdef TINYGLTF_USE_RAPIDJSON
|
||||
return o.End();
|
||||
#elif TINYGLTF_USE_SAJSON
|
||||
// TODO(syoyo): Implement
|
||||
assert(0);
|
||||
return json_const_array_iterator(o);
|
||||
#else
|
||||
return o.end();
|
||||
#endif
|
||||
@@ -2953,6 +3116,8 @@ json_const_array_iterator ArrayEnd(const json &o) {
|
||||
bool IsObject(const json &o) {
|
||||
#ifdef TINYGLTF_USE_RAPIDJSON
|
||||
return o.IsObject();
|
||||
#elif defined(TINYGLTF_USE_SAJSON)
|
||||
return o.get_type() == sajson::TYPE_OBJECT;
|
||||
#else
|
||||
return o.is_object();
|
||||
#endif
|
||||
@@ -2961,6 +3126,11 @@ bool IsObject(const json &o) {
|
||||
json_const_iterator ObjectBegin(const json &o) {
|
||||
#ifdef TINYGLTF_USE_RAPIDJSON
|
||||
return o.MemberBegin();
|
||||
#elif defined(TINYGLTF_USE_SAJSON)
|
||||
assert(o.get_type() == sajson::TYPE_OBJECT);
|
||||
// TODO(syoyo): Implement
|
||||
assert(0);
|
||||
return json_const_iterator(o);
|
||||
#else
|
||||
return o.begin();
|
||||
#endif
|
||||
@@ -2969,6 +3139,11 @@ json_const_iterator ObjectBegin(const json &o) {
|
||||
json_const_iterator ObjectEnd(const json &o) {
|
||||
#ifdef TINYGLTF_USE_RAPIDJSON
|
||||
return o.MemberEnd();
|
||||
#elif defined(TINYGLTF_USE_SAJSON)
|
||||
assert(o.get_type() == sajson::TYPE_OBJECT);
|
||||
// TODO(syoyo): Implement
|
||||
assert(0);
|
||||
return json_const_iterator(o);
|
||||
#else
|
||||
return o.end();
|
||||
#endif
|
||||
@@ -2977,6 +3152,10 @@ json_const_iterator ObjectEnd(const json &o) {
|
||||
const char *GetKey(json_const_iterator &it) {
|
||||
#ifdef TINYGLTF_USE_RAPIDJSON
|
||||
return it->name.GetString();
|
||||
#elif defined(TINYGLTF_USE_SAJSON)
|
||||
// TODO(syoyo): Implement
|
||||
assert(0);
|
||||
return nullptr;
|
||||
#else
|
||||
return it.key().c_str();
|
||||
#endif
|
||||
@@ -2989,6 +3168,10 @@ bool FindMember(const json &o, const char *member, json_const_iterator &it) {
|
||||
}
|
||||
it = o.FindMember(member);
|
||||
return it != o.MemberEnd();
|
||||
#elif defined(TINYGLTF_USE_SAJSON)
|
||||
// TODO(syoyo): Implement
|
||||
assert(0);
|
||||
return false;
|
||||
#else
|
||||
it = o.find(member);
|
||||
return it != o.end();
|
||||
@@ -2998,6 +3181,10 @@ bool FindMember(const json &o, const char *member, json_const_iterator &it) {
|
||||
const json &GetValue(json_const_iterator &it) {
|
||||
#ifdef TINYGLTF_USE_RAPIDJSON
|
||||
return it->value;
|
||||
#elif defined(TINYGLTF_USE_SAJSON)
|
||||
// TODO(syoyo): Implement
|
||||
assert(0);
|
||||
return it.value();
|
||||
#else
|
||||
return it.value();
|
||||
#endif
|
||||
@@ -3016,6 +3203,11 @@ std::string JsonToString(const json &o, int spacing = -1) {
|
||||
o.Accept(writer);
|
||||
}
|
||||
return buffer.GetString();
|
||||
#elif defined(TINYGLTF_USE_SAJSON)
|
||||
// Serialize is not available for Sajson
|
||||
(void)o;
|
||||
(void)spacing;
|
||||
return std::string();
|
||||
#else
|
||||
return o.dump(spacing);
|
||||
#endif
|
||||
@@ -3071,7 +3263,10 @@ static bool ParseJsonAsValue(Value *ret, const json &o) {
|
||||
break;
|
||||
// all types are covered, so no `case default`
|
||||
}
|
||||
#else
|
||||
#elif defined(TINYGLTF_USE_SAJSON)
|
||||
// TODO
|
||||
assert(0);
|
||||
#else // json.hpp
|
||||
switch (o.type()) {
|
||||
case json::value_t::object: {
|
||||
Value::Object value_object;
|
||||
@@ -3154,6 +3349,11 @@ static bool ParseBooleanProperty(bool *ret, std::string *err, const json &o,
|
||||
if (isBoolean) {
|
||||
boolValue = value.GetBool();
|
||||
}
|
||||
#elif defined(TINYGLTF_USE_SAJSON)
|
||||
isBoolean = value.is_boolean();
|
||||
if (isBoolean) {
|
||||
boolValue = value.get_boolean_value();
|
||||
}
|
||||
#else
|
||||
isBoolean = value.is_boolean();
|
||||
if (isBoolean) {
|
||||
@@ -3243,6 +3443,11 @@ static bool ParseUnsignedProperty(size_t *ret, std::string *err, const json &o,
|
||||
uValue = value.GetUint64();
|
||||
isUValue = true;
|
||||
}
|
||||
#elif defined(TINYGLTF_USE_SAJSON)
|
||||
isUValue = value.get_type() == sajson::TYPE_INTEGER;
|
||||
if (isUValue) {
|
||||
uValue = value.get_integer_value();
|
||||
}
|
||||
#else
|
||||
isUValue = value.is_number_unsigned();
|
||||
if (isUValue) {
|
||||
@@ -4860,13 +5065,13 @@ static bool ParseAnimationChannel(
|
||||
}
|
||||
return false;
|
||||
}
|
||||
ParseExtensionsProperty(&channel->target_extensions, err, target_object);
|
||||
if (store_original_json_for_extras_and_extensions) {
|
||||
ParseExtensionsProperty(&channel->target_extensions, err, target_object);
|
||||
if (store_original_json_for_extras_and_extensions) {
|
||||
json_const_iterator it;
|
||||
if (FindMember(target_object, "extensions", it)) {
|
||||
channel->target_extensions_json_string = JsonToString(GetValue(it));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
channel->sampler = samplerIndex;
|
||||
@@ -5677,9 +5882,11 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
|
||||
.target = TINYGLTF_TARGET_ARRAY_BUFFER;
|
||||
}
|
||||
|
||||
for(auto &target : primitive.targets) {
|
||||
for(auto &attribute : target) {
|
||||
model->bufferViews[size_t(model->accessors[size_t(attribute.second)].bufferView)]
|
||||
for (auto &target : primitive.targets) {
|
||||
for (auto &attribute : target) {
|
||||
model
|
||||
->bufferViews[size_t(
|
||||
model->accessors[size_t(attribute.second)].bufferView)]
|
||||
.target = TINYGLTF_TARGET_ARRAY_BUFFER;
|
||||
}
|
||||
}
|
||||
@@ -6019,10 +6226,13 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
|
||||
// 19. Parse Extras
|
||||
ParseExtrasProperty(&model->extras, v);
|
||||
|
||||
#if !defined(TINYGLTF_USE_SAJSON)
|
||||
// TODO(syoyo): Support SAJSON backend
|
||||
if (store_original_json_for_extras_and_extensions_) {
|
||||
model->extras_json_string = JsonToString(v["extras"]);
|
||||
model->extensions_json_string = JsonToString(v["extensions"]);
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -6189,6 +6399,8 @@ bool TinyGLTF::LoadBinaryFromFile(Model *model, std::string *err,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(TINYGLTF_ENABLE_SERIALIZER)
|
||||
|
||||
///////////////////////
|
||||
// GLTF Serialization
|
||||
///////////////////////
|
||||
@@ -6265,6 +6477,13 @@ static void SerializeNumberProperty(const std::string &key, T number,
|
||||
JsonAddMember(obj, key.c_str(), json(number));
|
||||
}
|
||||
|
||||
#ifdef TINYGLTF_USE_RAPIDJSON
|
||||
template <>
|
||||
void SerializeNumberProperty(const std::string &key, size_t number, json &obj) {
|
||||
JsonAddMember(obj, key.c_str(), json(static_cast<uint64_t>(number)));
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
static void SerializeNumberArrayProperty(const std::string &key,
|
||||
const std::vector<T> &value,
|
||||
@@ -6415,9 +6634,10 @@ static bool SerializeGltfBufferData(const std::vector<unsigned char> &data,
|
||||
const std::string &binFilename) {
|
||||
#ifdef _WIN32
|
||||
#if defined(__GLIBCXX__) // mingw
|
||||
int file_descriptor =
|
||||
_wopen(UTF8ToWchar(binFilename).c_str(), _O_WRONLY | _O_BINARY);
|
||||
__gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor, std::ios_base::in);
|
||||
int file_descriptor = _wopen(UTF8ToWchar(binFilename).c_str(),
|
||||
_O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY);
|
||||
__gnu_cxx::stdio_filebuf<char> wfile_buf(
|
||||
file_descriptor, std::ios_base::out | std::ios_base::binary);
|
||||
std::ostream output(&wfile_buf);
|
||||
if (!wfile_buf.is_open()) return false;
|
||||
#elif defined(_MSC_VER)
|
||||
@@ -6500,9 +6720,10 @@ static void SerializeExtensionMap(const ExtensionMap &extensions, json &o) {
|
||||
}
|
||||
|
||||
static void SerializeGltfAccessor(Accessor &accessor, json &o) {
|
||||
SerializeNumberProperty<int>("bufferView", accessor.bufferView, o);
|
||||
if (accessor.bufferView >= 0)
|
||||
SerializeNumberProperty<int>("bufferView", accessor.bufferView, o);
|
||||
|
||||
if (accessor.byteOffset != 0.0)
|
||||
if (accessor.byteOffset != 0)
|
||||
SerializeNumberProperty<int>("byteOffset", int(accessor.byteOffset), o);
|
||||
|
||||
SerializeNumberProperty<int>("componentType", accessor.componentType, o);
|
||||
@@ -6551,7 +6772,7 @@ static void SerializeGltfAnimationChannel(AnimationChannel &channel, json &o) {
|
||||
SerializeNumberProperty("node", channel.target_node, target);
|
||||
SerializeStringProperty("path", channel.target_path, target);
|
||||
|
||||
SerializeExtensionMap(channel.target_extensions, target);
|
||||
SerializeExtensionMap(channel.target_extensions, target);
|
||||
|
||||
JsonAddMember(o, "target", std::move(target));
|
||||
}
|
||||
@@ -6958,7 +7179,9 @@ static void SerializeSpotLight(SpotLight &spot, json &o) {
|
||||
static void SerializeGltfLight(Light &light, json &o) {
|
||||
if (!light.name.empty()) SerializeStringProperty("name", light.name, o);
|
||||
SerializeNumberProperty("intensity", light.intensity, o);
|
||||
SerializeNumberProperty("range", light.range, o);
|
||||
if (light.range > 0.0) {
|
||||
SerializeNumberProperty("range", light.range, o);
|
||||
}
|
||||
SerializeNumberArrayProperty("color", light.color, o);
|
||||
SerializeStringProperty("type", light.type, o);
|
||||
if (light.type == "spot") {
|
||||
@@ -7072,6 +7295,11 @@ static void SerializeGltfCamera(const Camera &camera, json &o) {
|
||||
} else {
|
||||
// ???
|
||||
}
|
||||
|
||||
if (camera.extras.Type() != NULL_TYPE) {
|
||||
SerializeValue("extras", camera.extras, o);
|
||||
}
|
||||
SerializeExtensionMap(camera.extensions, o);
|
||||
}
|
||||
|
||||
static void SerializeGltfScene(Scene &scene, json &o) {
|
||||
@@ -7150,7 +7378,7 @@ static void SerializeGltfModel(Model *model, json &o) {
|
||||
JsonAddMember(o, "asset", std::move(asset));
|
||||
|
||||
// BUFFERVIEWS
|
||||
if(model->bufferViews.size()) {
|
||||
if (model->bufferViews.size()) {
|
||||
json bufferViews;
|
||||
JsonReserveArray(bufferViews, model->bufferViews.size());
|
||||
for (unsigned int i = 0; i < model->bufferViews.size(); ++i) {
|
||||
@@ -7161,11 +7389,6 @@ static void SerializeGltfModel(Model *model, json &o) {
|
||||
JsonAddMember(o, "bufferViews", std::move(bufferViews));
|
||||
}
|
||||
|
||||
// Extensions used
|
||||
if (model->extensionsUsed.size()) {
|
||||
SerializeStringArrayProperty("extensionsUsed", model->extensionsUsed, o);
|
||||
}
|
||||
|
||||
// Extensions required
|
||||
if (model->extensionsRequired.size()) {
|
||||
SerializeStringArrayProperty("extensionsRequired",
|
||||
@@ -7276,7 +7499,9 @@ static void SerializeGltfModel(Model *model, json &o) {
|
||||
// EXTENSIONS
|
||||
SerializeExtensionMap(model->extensions, o);
|
||||
|
||||
// LIGHTS as KHR_lights_cmn
|
||||
auto extensionsUsed = model->extensionsUsed;
|
||||
|
||||
// LIGHTS as KHR_lights_punctual
|
||||
if (model->lights.size()) {
|
||||
json lights;
|
||||
JsonReserveArray(lights, model->lights.size());
|
||||
@@ -7291,7 +7516,7 @@ static void SerializeGltfModel(Model *model, json &o) {
|
||||
|
||||
{
|
||||
json_const_iterator it;
|
||||
if (!FindMember(o, "extensions", it)) {
|
||||
if (FindMember(o, "extensions", it)) {
|
||||
JsonAssign(ext_j, GetValue(it));
|
||||
}
|
||||
}
|
||||
@@ -7299,6 +7524,23 @@ static void SerializeGltfModel(Model *model, json &o) {
|
||||
JsonAddMember(ext_j, "KHR_lights_punctual", std::move(khr_lights_cmn));
|
||||
|
||||
JsonAddMember(o, "extensions", std::move(ext_j));
|
||||
|
||||
// Also add "KHR_lights_punctual" to `extensionsUsed`
|
||||
{
|
||||
auto has_khr_lights_punctual = std::find_if(
|
||||
extensionsUsed.begin(), extensionsUsed.end(), [](const std::string &s) {
|
||||
return (s.compare("KHR_lights_punctual") == 0);
|
||||
});
|
||||
|
||||
if (has_khr_lights_punctual == extensionsUsed.end()) {
|
||||
extensionsUsed.push_back("KHR_lights_punctual");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extensions used
|
||||
if (model->extensionsUsed.size()) {
|
||||
SerializeStringArrayProperty("extensionsUsed", extensionsUsed, o);
|
||||
}
|
||||
|
||||
// EXTRAS
|
||||
@@ -7318,9 +7560,10 @@ static bool WriteGltfFile(const std::string &output,
|
||||
#if defined(_MSC_VER)
|
||||
std::ofstream gltfFile(UTF8ToWchar(output).c_str());
|
||||
#elif defined(__GLIBCXX__)
|
||||
int file_descriptor =
|
||||
_wopen(UTF8ToWchar(output).c_str(), _O_WRONLY | _O_BINARY);
|
||||
__gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor, std::ios_base::in);
|
||||
int file_descriptor = _wopen(UTF8ToWchar(output).c_str(),
|
||||
_O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY);
|
||||
__gnu_cxx::stdio_filebuf<char> wfile_buf(
|
||||
file_descriptor, std::ios_base::out | std::ios_base::binary);
|
||||
std::ostream gltfFile(&wfile_buf);
|
||||
if (!wfile_buf.is_open()) return false;
|
||||
#else
|
||||
@@ -7406,9 +7649,10 @@ static void WriteBinaryGltfFile(const std::string &output,
|
||||
#if defined(_MSC_VER)
|
||||
std::ofstream gltfFile(UTF8ToWchar(output).c_str(), std::ios::binary);
|
||||
#elif defined(__GLIBCXX__)
|
||||
int file_descriptor =
|
||||
_wopen(UTF8ToWchar(output).c_str(), _O_WRONLY | _O_BINARY);
|
||||
__gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor, std::ios_base::in);
|
||||
int file_descriptor = _wopen(UTF8ToWchar(output).c_str(),
|
||||
_O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY);
|
||||
__gnu_cxx::stdio_filebuf<char> wfile_buf(
|
||||
file_descriptor, std::ios_base::out | std::ios_base::binary);
|
||||
std::ostream gltfFile(&wfile_buf);
|
||||
#else
|
||||
std::ofstream gltfFile(output.c_str(), std::ios::binary);
|
||||
@@ -7429,13 +7673,13 @@ bool TinyGLTF::WriteGltfSceneToStream(Model *model, std::ostream &stream,
|
||||
|
||||
// BUFFERS
|
||||
std::vector<unsigned char> binBuffer;
|
||||
if(model->buffers.size()) {
|
||||
if (model->buffers.size()) {
|
||||
json buffers;
|
||||
JsonReserveArray(buffers, model->buffers.size());
|
||||
for (unsigned int i = 0; i < model->buffers.size(); ++i) {
|
||||
json buffer;
|
||||
if (writeBinary && i==0 && model->buffers[i].uri.empty()){
|
||||
SerializeGltfBufferBin(model->buffers[i], buffer,binBuffer);
|
||||
if (writeBinary && i == 0 && model->buffers[i].uri.empty()) {
|
||||
SerializeGltfBufferBin(model->buffers[i], buffer, binBuffer);
|
||||
} else {
|
||||
SerializeGltfBuffer(model->buffers[i], buffer);
|
||||
}
|
||||
@@ -7452,9 +7696,9 @@ bool TinyGLTF::WriteGltfSceneToStream(Model *model, std::ostream &stream,
|
||||
json image;
|
||||
|
||||
std::string dummystring = "";
|
||||
// UpdateImageObject need baseDir but only uses it if embededImages is
|
||||
// enable, since we won't write separte images when writing to a stream we
|
||||
// use a dummystring
|
||||
// UpdateImageObject need baseDir but only uses it if embeddedImages is
|
||||
// enabled, since we won't write separate images when writing to a stream
|
||||
// we
|
||||
UpdateImageObject(model->images[i], dummystring, int(i), false,
|
||||
&this->WriteImageData, this->write_image_user_data_);
|
||||
SerializeGltfImage(model->images[i], image);
|
||||
@@ -7501,14 +7745,15 @@ bool TinyGLTF::WriteGltfSceneToFile(Model *model, const std::string &filename,
|
||||
JsonReserveArray(buffers, model->buffers.size());
|
||||
for (unsigned int i = 0; i < model->buffers.size(); ++i) {
|
||||
json buffer;
|
||||
if (writeBinary && i==0 && model->buffers[i].uri.empty()){
|
||||
SerializeGltfBufferBin(model->buffers[i], buffer,binBuffer);
|
||||
if (writeBinary && i == 0 && model->buffers[i].uri.empty()) {
|
||||
SerializeGltfBufferBin(model->buffers[i], buffer, binBuffer);
|
||||
} else if (embedBuffers) {
|
||||
SerializeGltfBuffer(model->buffers[i], buffer);
|
||||
} else {
|
||||
std::string binSavePath;
|
||||
std::string binUri;
|
||||
if (!model->buffers[i].uri.empty() && !IsDataURI(model->buffers[i].uri)) {
|
||||
if (!model->buffers[i].uri.empty() &&
|
||||
!IsDataURI(model->buffers[i].uri)) {
|
||||
binUri = model->buffers[i].uri;
|
||||
} else {
|
||||
binUri = defaultBinFilename + defaultBinFileExt;
|
||||
@@ -7534,7 +7779,7 @@ bool TinyGLTF::WriteGltfSceneToFile(Model *model, const std::string &filename,
|
||||
}
|
||||
JsonPushBack(buffers, std::move(buffer));
|
||||
}
|
||||
JsonAddMember(output, "buffers", std::move(buffers));
|
||||
JsonAddMember(output, "buffers", std::move(buffers));
|
||||
}
|
||||
|
||||
// IMAGES
|
||||
@@ -7561,6 +7806,8 @@ bool TinyGLTF::WriteGltfSceneToFile(Model *model, const std::string &filename,
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // TINYGLTF_ENABLE_SERIALIZER
|
||||
|
||||
} // namespace tinygltf
|
||||
|
||||
#ifdef __clang__
|
||||
|
||||
Reference in New Issue
Block a user