mirror of
https://git.mirrors.martin98.com/https://github.com/syoyo/tinygltf.git
synced 2025-04-22 14:09:55 +08:00
Remove unused examples.
Refactor source code.
This commit is contained in:
parent
40c4a0a60a
commit
5b40745f7a
@ -1,13 +0,0 @@
|
||||
ABC_INC := -I/usr/local/include
|
||||
ABC_LDFLAGS := -L/usr/local/lib -lAlembic
|
||||
|
||||
ILMBASE_INC := -I/usr/local/include/OpenEXR
|
||||
|
||||
# Suppress some C++ warnings(in clang).
|
||||
EXTRA_CXXFLAGS := -Wno-deprecated-register -Weverything
|
||||
|
||||
all:
|
||||
clang++ -std=c++11 -g -o abc2gltf $(ABC_INC) $(ILMBASE_INC) $(EXTRA_CXXFLAGS) abc2gltf.cc $(ABC_LDFLAGS)
|
||||
|
||||
run:
|
||||
./abc2gltf suzanne.abc suzanne.gltf
|
@ -1,62 +0,0 @@
|
||||
# Simple Alembic to glTF converter example
|
||||
|
||||
## Features
|
||||
|
||||
* Node hierarchy(Xform).
|
||||
* Polygon mesh.
|
||||
* Curves(as an extension)
|
||||
|
||||
## Limitations
|
||||
|
||||
* Alembic data with Ogawa backend only
|
||||
* Simple poly mesh only
|
||||
* Simple curve only
|
||||
* Static mesh only(Use first time sample. no animation)
|
||||
|
||||
## Compile
|
||||
|
||||
OpenEXR(ilmbase), and Alembic 1.6 or later are equired to compile the converter.
|
||||
|
||||
Edit include and lib paths for Alembic OpenEXR(ilmbase) in `Makefile`, then simply:
|
||||
|
||||
$ make
|
||||
|
||||
## Alembic data
|
||||
|
||||
I am testing with Alembic data using Blender's Alembic exporter(feature available from Blender 2.78)
|
||||
|
||||
## Extensions
|
||||
|
||||
### Curves
|
||||
|
||||
Curves are reprenseted as point primitive(mode = 0) in glTF level for the backward compatibility of existing glTF specification.
|
||||
The number of vertices per curve information is aded to `NVERRTS` attribute.
|
||||
"ext_mode" extra property is added and set it to "curves" string to specify the object as curves primitive.
|
||||
|
||||
Here is an example JSON description of curves primitive.
|
||||
|
||||
|
||||
"meshes": {
|
||||
"curves_1": {
|
||||
"primitives": [
|
||||
{
|
||||
"attributes": {
|
||||
"POSITION": "accessor_vertices",
|
||||
"NVERTS": "accessor_nverts",
|
||||
},
|
||||
"material": "material_1",
|
||||
"mode": 0,
|
||||
"extras" {
|
||||
"ext_mode" : "curves"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
## TODO
|
||||
|
||||
* [ ] Support facevarying normals and texcoords/facevarying texcoords.
|
||||
* [ ] Support animation(time samples)
|
||||
* [ ] Support Point and SubD?
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -1,6 +0,0 @@
|
||||
# Suppress some C++ warnings(in clang).
|
||||
EXTRA_CXXFLAGS := -Weverything -Werror
|
||||
|
||||
all:
|
||||
clang++ -g -o cyhair2gltf $(EXTRA_CXXFLAGS) cyhair2gltf.cc cyhair_loader.cc
|
||||
|
@ -1,18 +0,0 @@
|
||||
# Simple CyHair to glTF converter
|
||||
|
||||

|
||||
|
||||
Convert CyHair to curve points using glTF + extension(curve data format is described in `../alembic_to_gltf/README.md`).
|
||||
|
||||
For CyHair format, please refer: http://www.cemyuksel.com/cyCodeBase/code.html .
|
||||
|
||||
For hair model with CyHair format, please refer for example: http://www.cemyuksel.com/research/hairmodels/
|
||||
|
||||
## Convert
|
||||
|
||||
$ ./cyhair2gltf input.hair output.gltf
|
||||
|
||||
## View
|
||||
|
||||
You can view converted .gltf with glviwew exmaple(`example/glview`).
|
||||
|
@ -1,352 +0,0 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wc++11-long-long"
|
||||
#pragma clang diagnostic ignored "-Wold-style-cast"
|
||||
#pragma clang diagnostic ignored "-Wpadded"
|
||||
#pragma clang diagnostic ignored "-Wsign-conversion"
|
||||
#pragma clang diagnostic ignored "-Wc++11-extensions"
|
||||
#pragma clang diagnostic ignored "-Wconversion"
|
||||
#pragma clang diagnostic ignored "-Wreserved-id-macro"
|
||||
#pragma clang diagnostic ignored "-Wfloat-equal"
|
||||
#pragma clang diagnostic ignored "-Wdeprecated"
|
||||
#pragma clang diagnostic ignored "-Wweak-vtables"
|
||||
#pragma clang diagnostic ignored "-Wextra-semi"
|
||||
#pragma clang diagnostic ignored "-Wswitch-enum"
|
||||
#pragma clang diagnostic ignored "-Wglobal-constructors"
|
||||
#pragma clang diagnostic ignored "-Wunused-parameter"
|
||||
#pragma clang diagnostic ignored "-Wexit-time-destructors"
|
||||
#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
|
||||
#pragma clang diagnostic ignored "-Wdocumentation-unknown-command"
|
||||
#pragma clang diagnostic ignored "-Wdouble-promotion"
|
||||
#pragma clang diagnostic ignored "-Wcovered-switch-default"
|
||||
#endif
|
||||
|
||||
#define PICOJSON_USE_INT64
|
||||
#include "../../picojson.h"
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#include "../../tiny_gltf_loader.h" // To import some TINYGLTF_*** macros.
|
||||
|
||||
#include "cyhair_loader.h"
|
||||
|
||||
// Curves are represented as an array of curve.
|
||||
// i'th curve has nverts[i] points.
|
||||
// TODO(syoyo) knots, order to support NURBS curve.
|
||||
typedef struct
|
||||
{
|
||||
std::vector<float> points;
|
||||
std::vector<int> nverts; // # of vertices per strand(curve).
|
||||
} Curves;
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// writer module
|
||||
// @todo { move writer code to tiny_gltf_writer.h }
|
||||
|
||||
// http://www.adp-gmbh.ch/cpp/common/base64.html
|
||||
static const char *base64_chars =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
|
||||
static std::string base64_encode(unsigned char const* bytes_to_encode,
|
||||
size_t in_len) {
|
||||
std::string ret;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
unsigned char char_array_3[3];
|
||||
unsigned char char_array_4[4];
|
||||
|
||||
while (in_len--) {
|
||||
char_array_3[i++] = *(bytes_to_encode++);
|
||||
if (i == 3) {
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] = static_cast<unsigned char>(
|
||||
((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4));
|
||||
char_array_4[2] = static_cast<unsigned char>(
|
||||
((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6));
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
|
||||
for (i = 0; (i < 4); i++) ret += base64_chars[char_array_4[i]];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i) {
|
||||
for (j = i; j < 3; j++) char_array_3[j] = '\0';
|
||||
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] = static_cast<unsigned char>(
|
||||
((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4));
|
||||
char_array_4[2] = static_cast<unsigned char>(
|
||||
((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6));
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
|
||||
for (j = 0; (j < i + 1); j++) ret += base64_chars[char_array_4[j]];
|
||||
|
||||
while ((i++ < 3)) ret += '=';
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool SaveCurvesToGLTF(const std::string& output_filename,
|
||||
const Curves& curves) {
|
||||
picojson::object root;
|
||||
|
||||
{
|
||||
picojson::object asset;
|
||||
asset["generator"] = picojson::value("abc2gltf");
|
||||
asset["premultipliedAlpha"] = picojson::value(true);
|
||||
asset["version"] = picojson::value(static_cast<double>(1));
|
||||
picojson::object profile;
|
||||
profile["api"] = picojson::value("WebGL");
|
||||
profile["version"] = picojson::value("1.0.2");
|
||||
asset["profile"] = picojson::value(profile);
|
||||
root["assets"] = picojson::value(asset);
|
||||
}
|
||||
|
||||
{
|
||||
picojson::object buffers;
|
||||
{
|
||||
{
|
||||
std::string b64data = base64_encode(reinterpret_cast<unsigned char const*>(curves.points.data()), curves.points.size() * sizeof(float));
|
||||
picojson::object buf;
|
||||
|
||||
buf["type"] = picojson::value("arraybuffer");
|
||||
buf["uri"] = picojson::value(
|
||||
std::string("data:application/octet-stream;base64,") + b64data);
|
||||
buf["byteLength"] =
|
||||
picojson::value(static_cast<double>(curves.points.size() * sizeof(float)));
|
||||
|
||||
buffers["points"] = picojson::value(buf);
|
||||
}
|
||||
|
||||
// Out extension
|
||||
{
|
||||
std::string b64data = base64_encode(reinterpret_cast<unsigned char const*>(curves.nverts.data()), curves.nverts.size() * sizeof(int));
|
||||
picojson::object buf;
|
||||
|
||||
buf["type"] = picojson::value("arraybuffer");
|
||||
buf["uri"] = picojson::value(
|
||||
std::string("data:application/octet-stream;base64,") + b64data);
|
||||
buf["byteLength"] =
|
||||
picojson::value(static_cast<double>(curves.nverts.size() * sizeof(int)));
|
||||
|
||||
buffers["nverts"] = picojson::value(buf);
|
||||
}
|
||||
|
||||
}
|
||||
root["buffers"] = picojson::value(buffers);
|
||||
}
|
||||
|
||||
{
|
||||
picojson::object buffer_views;
|
||||
{
|
||||
{
|
||||
picojson::object buffer_view_points;
|
||||
buffer_view_points["buffer"] = picojson::value(std::string("points"));
|
||||
buffer_view_points["byteLength"] = picojson::value(static_cast<double>(curves.points.size() * sizeof(float)));
|
||||
buffer_view_points["byteOffset"] = picojson::value(static_cast<double>(0));
|
||||
buffer_view_points["target"] = picojson::value(static_cast<int64_t>(TINYGLTF_TARGET_ARRAY_BUFFER));
|
||||
buffer_views["bufferView_points"] = picojson::value(buffer_view_points);
|
||||
}
|
||||
|
||||
{
|
||||
picojson::object buffer_view_nverts;
|
||||
buffer_view_nverts["buffer"] = picojson::value(std::string("nverts"));
|
||||
buffer_view_nverts["byteLength"] = picojson::value(static_cast<double>(curves.nverts.size() * sizeof(int)));
|
||||
buffer_view_nverts["byteOffset"] = picojson::value(static_cast<double>(0));
|
||||
buffer_view_nverts["target"] = picojson::value(static_cast<int64_t>(TINYGLTF_TARGET_ARRAY_BUFFER));
|
||||
buffer_views["bufferView_nverts"] = picojson::value(buffer_view_nverts);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
root["bufferViews"] = picojson::value(buffer_views);
|
||||
}
|
||||
|
||||
{
|
||||
picojson::object attributes;
|
||||
|
||||
attributes["POSITION"] = picojson::value(std::string("accessor_points"));
|
||||
attributes["NVERTS"] = picojson::value(std::string("accessor_nverts"));
|
||||
|
||||
// Extra information for curves primtive.
|
||||
picojson::object extra;
|
||||
extra["ext_mode"] = picojson::value("curves");
|
||||
|
||||
picojson::object primitive;
|
||||
primitive["attributes"] = picojson::value(attributes);
|
||||
//primitive["indices"] = picojson::value("accessor_indices");
|
||||
primitive["material"] = picojson::value("material_1");
|
||||
primitive["mode"] = picojson::value(static_cast<int64_t>(TINYGLTF_MODE_POINTS)); // Use GL_POINTS for backward compatibility
|
||||
primitive["extras"] = picojson::value(extra);
|
||||
|
||||
|
||||
picojson::array primitive_array;
|
||||
primitive_array.push_back(picojson::value(primitive));
|
||||
|
||||
picojson::object m;
|
||||
m["primitives"] = picojson::value(primitive_array);
|
||||
|
||||
picojson::object meshes;
|
||||
meshes["mesh_1"] = picojson::value(m);
|
||||
|
||||
|
||||
root["meshes"] = picojson::value(meshes);
|
||||
}
|
||||
|
||||
{
|
||||
picojson::object accessors;
|
||||
|
||||
{
|
||||
picojson::object accessor_points;
|
||||
accessor_points["bufferView"] = picojson::value(std::string("bufferView_points"));
|
||||
accessor_points["byteOffset"] = picojson::value(static_cast<int64_t>(0));
|
||||
accessor_points["byteStride"] = picojson::value(static_cast<double>(3 * sizeof(float)));
|
||||
accessor_points["componentType"] = picojson::value(static_cast<int64_t>(TINYGLTF_COMPONENT_TYPE_FLOAT));
|
||||
accessor_points["count"] = picojson::value(static_cast<int64_t>(curves.points.size()));
|
||||
accessor_points["type"] = picojson::value(std::string("VEC3"));
|
||||
accessors["accessor_points"] = picojson::value(accessor_points);
|
||||
}
|
||||
|
||||
{
|
||||
picojson::object accessor_nverts;
|
||||
accessor_nverts["bufferView"] = picojson::value(std::string("bufferView_nverts"));
|
||||
accessor_nverts["byteOffset"] = picojson::value(static_cast<int64_t>(0));
|
||||
accessor_nverts["byteStride"] = picojson::value(static_cast<double>(sizeof(int)));
|
||||
accessor_nverts["componentType"] = picojson::value(static_cast<int64_t>(TINYGLTF_COMPONENT_TYPE_INT));
|
||||
accessor_nverts["count"] = picojson::value(static_cast<int64_t>(curves.nverts.size()));
|
||||
accessor_nverts["type"] = picojson::value(std::string("SCALAR"));
|
||||
accessors["accessor_nverts"] = picojson::value(accessor_nverts);
|
||||
}
|
||||
|
||||
picojson::object accessor_indices;
|
||||
|
||||
root["accessors"] = picojson::value(accessors);
|
||||
}
|
||||
|
||||
{
|
||||
// Use Default Material(Do not supply `material.technique`)
|
||||
picojson::object default_material;
|
||||
picojson::object materials;
|
||||
|
||||
materials["material_1"] = picojson::value(default_material);
|
||||
|
||||
root["materials"] = picojson::value(materials);
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
picojson::object nodes;
|
||||
picojson::object node;
|
||||
picojson::array meshes;
|
||||
|
||||
meshes.push_back(picojson::value(std::string("mesh_1")));
|
||||
|
||||
node["meshes"] = picojson::value(meshes);
|
||||
|
||||
nodes["node_1"] = picojson::value(node);
|
||||
root["nodes"] = picojson::value(nodes);
|
||||
}
|
||||
|
||||
{
|
||||
picojson::object defaultScene;
|
||||
picojson::array nodes;
|
||||
|
||||
nodes.push_back(picojson::value(std::string("node_1")));
|
||||
|
||||
defaultScene["nodes"] = picojson::value(nodes);
|
||||
|
||||
root["scene"] = picojson::value("defaultScene");
|
||||
picojson::object scenes;
|
||||
scenes["defaultScene"] = picojson::value(defaultScene);
|
||||
root["scenes"] = picojson::value(scenes);
|
||||
}
|
||||
|
||||
|
||||
// @todo {}
|
||||
picojson::object shaders;
|
||||
picojson::object programs;
|
||||
picojson::object techniques;
|
||||
picojson::object materials;
|
||||
picojson::object skins;
|
||||
root["shaders"] = picojson::value(shaders);
|
||||
root["programs"] = picojson::value(programs);
|
||||
root["techniques"] = picojson::value(techniques);
|
||||
root["materials"] = picojson::value(materials);
|
||||
root["skins"] = picojson::value(skins);
|
||||
|
||||
std::ofstream ifs(output_filename.c_str());
|
||||
if (ifs.bad()) {
|
||||
std::cerr << "Failed to open " << output_filename << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
picojson::value v = picojson::value(root);
|
||||
|
||||
std::string s = v.serialize(/* pretty */true);
|
||||
ifs.write(s.data(), static_cast<ssize_t>(s.size()));
|
||||
ifs.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
std::string cyhair_filename;
|
||||
std::string gltf_filename;
|
||||
|
||||
if (argc < 3) {
|
||||
std::cerr << "Usage: cyhair2abc input.hair output.gltf" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
cyhair_filename = std::string(argv[1]);
|
||||
gltf_filename = std::string(argv[2]);
|
||||
|
||||
example::CyHair cyhair;
|
||||
{
|
||||
bool ret = cyhair.Load(cyhair_filename.c_str());
|
||||
if (!ret) {
|
||||
std::cerr << "Failed to load " << cyhair_filename << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert to curves.
|
||||
Curves curves;
|
||||
{
|
||||
// TODO(syoyo): thickness, colors, etc.
|
||||
curves.points = cyhair.points_;
|
||||
|
||||
// NVETS = numSegments + 1
|
||||
if (cyhair.segments_.empty()) {
|
||||
for (size_t i = 0; i < cyhair.num_strands_; i++) {
|
||||
curves.nverts.push_back(cyhair.default_segments_ + 1);
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < cyhair.segments_.size(); i++) {
|
||||
curves.nverts.push_back(cyhair.segments_[i] + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ret = SaveCurvesToGLTF(gltf_filename, curves);
|
||||
if (ret) {
|
||||
std::cout << "Wrote " << gltf_filename << std::endl;
|
||||
} else {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -1,305 +0,0 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Light Transport Entertainment, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Simple Cyhair loader.
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "cyhair_loader.h"
|
||||
|
||||
namespace example {
|
||||
|
||||
class real3 {
|
||||
public:
|
||||
real3() : x(0.0f), y(0.0f), z(0.0f) {}
|
||||
real3(float v) : x(v), y(v), z(v) {}
|
||||
real3(float xx, float yy, float zz) : x(xx), y(yy), z(zz) {}
|
||||
//~real3() {}
|
||||
|
||||
real3 operator+(const real3 &f2) const {
|
||||
return real3(x + f2.x, y + f2.y, z + f2.z);
|
||||
}
|
||||
real3 operator*(const real3 &f2) const {
|
||||
return real3(x * f2.x, y * f2.y, z * f2.z);
|
||||
}
|
||||
real3 operator/(const real3 &f2) const {
|
||||
return real3(x / f2.x, y / f2.y, z / f2.z);
|
||||
}
|
||||
real3 operator/(const float f) const { return real3(x / f, y / f, z / f); }
|
||||
|
||||
float x, y, z;
|
||||
};
|
||||
|
||||
inline real3 operator*(float f, const real3 &v) {
|
||||
return real3(v.x * f, v.y * f, v.z * f);
|
||||
}
|
||||
|
||||
static const float toC2B[4][4] = {
|
||||
{0.0f, 6.0f / 6.0f, 0.0f, 0.0f},
|
||||
{-1.0f / 6.0f, 6.0f / 6.0f, 1.0f / 6.0f, 0.0f},
|
||||
{0.0f, 1.0f / 6.0f, 6.0f / 6.0f, -1.0f / 6.0f},
|
||||
{0.0f, 0.0, 6.0f / 6.0f, 0.0f}};
|
||||
|
||||
static const float toC2B0[4][4] = {
|
||||
{0.0f, 6.0f / 6.0f, 0.0f, 0.0f},
|
||||
{0.0f, 3.0f / 6.0f, 4.0f / 6.0f, -1.0f / 6.0f},
|
||||
{0.0f, 1.0f / 6.0f, 6.0f / 6.0f, -1.0f / 6.0f},
|
||||
{0.0f, 0.0f, 6.0f / 6.0f, 0.0f}};
|
||||
|
||||
static const float toC2B1[4][4] = {
|
||||
{0.0f, 6.0f / 6.0f, 0.0f, 0.0f},
|
||||
{-1.0f / 6.0f, 6.0f / 6.0f, 1.0f / 6.0f, 0.0f},
|
||||
{-1.0f / 6.0f, 4.0f / 6.0f, 3.0f / 6.0f, 0.0f},
|
||||
{0.0f, 0.0f, 6.0f / 6.0f, 0.0f}};
|
||||
|
||||
static void mul_matrix(real3 out[4], const float mat[4][4], const real3 pt[4]) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
out[i] = mat[i][0] * pt[0] + mat[i][1] * pt[1] + mat[i][2] * pt[2] +
|
||||
mat[i][3] * pt[3];
|
||||
}
|
||||
}
|
||||
|
||||
static void CamullRomToCubicBezier(real3 Q[4], const real3 *cps, int cps_size,
|
||||
int seg_idx) {
|
||||
size_t sz = static_cast<size_t>(cps_size);
|
||||
if (sz == 2) {
|
||||
Q[0] = cps[seg_idx];
|
||||
Q[1] = cps[seg_idx] * 2.0f / 3.0f + cps[seg_idx + 1] * 1.0f / 3.0f;
|
||||
Q[2] = cps[seg_idx] * 1.0f / 3.0f + cps[seg_idx + 1] * 2.0f / 3.0f;
|
||||
Q[3] = cps[seg_idx + 1];
|
||||
} else {
|
||||
real3 P[4];
|
||||
if (seg_idx == 0) {
|
||||
P[0] = real3(0.0f);
|
||||
P[1] = cps[seg_idx + 0];
|
||||
P[2] = cps[seg_idx + 1];
|
||||
P[3] = cps[seg_idx + 2];
|
||||
mul_matrix(Q, toC2B0, P);
|
||||
} else if (seg_idx == static_cast<int>(sz - 2)) {
|
||||
P[0] = cps[seg_idx - 1];
|
||||
P[1] = cps[seg_idx + 0];
|
||||
P[2] = cps[seg_idx + 1];
|
||||
P[3] = real3(0.0f);
|
||||
mul_matrix(Q, toC2B1, P);
|
||||
} else {
|
||||
P[0] = cps[seg_idx - 1];
|
||||
P[1] = cps[seg_idx + 0];
|
||||
P[2] = cps[seg_idx + 1];
|
||||
P[3] = cps[seg_idx + 2];
|
||||
mul_matrix(Q, toC2B, P);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CyHair::Load(const char *filename) {
|
||||
FILE *fp = fopen(filename, "rb");
|
||||
if (!fp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(sizeof(CyHairHeader) == 128);
|
||||
CyHairHeader header;
|
||||
|
||||
if (1 != fread(&header, 128, 1, fp)) {
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
if (memcmp(header.magic, "HAIR", 4) != 0) {
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
flags_ = header.flags;
|
||||
default_thickness_ = header.default_thickness;
|
||||
default_transparency_ = header.default_transparency;
|
||||
default_segments_ = static_cast<int>(header.default_segments);
|
||||
default_color_[0] = header.default_color[0];
|
||||
default_color_[1] = header.default_color[1];
|
||||
default_color_[2] = header.default_color[2];
|
||||
|
||||
const bool has_segments = flags_ & 0x1;
|
||||
const bool has_points = flags_ & 0x2;
|
||||
const bool has_thickness = flags_ & 0x4;
|
||||
const bool has_transparency = flags_ & 0x8;
|
||||
const bool has_color = flags_ & 0x10;
|
||||
|
||||
num_strands_ = header.num_strands;
|
||||
total_points_ = header.total_points;
|
||||
|
||||
if (!has_points) {
|
||||
std::cout << "No point data in CyHair." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((default_segments_ < 1) && (!has_segments)) {
|
||||
std::cout << "No valid segment information in CyHair." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// First read all strand data from a file.
|
||||
if (has_segments) {
|
||||
segments_.resize(num_strands_);
|
||||
if (1 !=
|
||||
fread(&segments_[0], sizeof(unsigned short) * num_strands_, 1, fp)) {
|
||||
std::cout << "Failed to read CyHair segments data." << std::endl;
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_points) {
|
||||
points_.resize(3 * total_points_);
|
||||
size_t n = fread(&points_[0], total_points_ * sizeof(float) * 3, 1, fp);
|
||||
if (1 != n) {
|
||||
std::cout << "Failed to read CyHair points data." << std::endl;
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (has_thickness) {
|
||||
thicknesses_.resize(total_points_);
|
||||
if (1 != fread(&thicknesses_[0], total_points_ * sizeof(float), 1, fp)) {
|
||||
std::cout << "Failed to read CyHair thickness data." << std::endl;
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_transparency) {
|
||||
transparencies_.resize(total_points_);
|
||||
if (1 != fread(&transparencies_[0], total_points_ * sizeof(float), 1, fp)) {
|
||||
std::cout << "Failed to read CyHair transparencies data." << std::endl;
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_color) {
|
||||
colors_.resize(3 * total_points_);
|
||||
if (1 != fread(&colors_[0], total_points_ * sizeof(float) * 3, 1, fp)) {
|
||||
std::cout << "Failed to read CyHair colors data." << std::endl;
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Build strand offset table.
|
||||
strand_offsets_.resize(num_strands_);
|
||||
strand_offsets_[0] = 0;
|
||||
for (size_t i = 1; i < num_strands_; i++) {
|
||||
int num_segments = segments_.empty() ? default_segments_ : segments_[i - 1];
|
||||
strand_offsets_[i] =
|
||||
strand_offsets_[i - 1] + static_cast<unsigned int>(num_segments + 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CyHair::ToCubicBezierCurves(std::vector<float> *vertices,
|
||||
std::vector<float> *radiuss,
|
||||
const float vertex_scale[3],
|
||||
const float vertex_translate[3],
|
||||
const int max_strands, const float user_thickness) {
|
||||
if (points_.empty() || strand_offsets_.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
vertices->clear();
|
||||
radiuss->clear();
|
||||
|
||||
int num_strands = static_cast<int>(num_strands_);
|
||||
|
||||
if ((max_strands > 0) && (max_strands < num_strands)) {
|
||||
num_strands = max_strands;
|
||||
}
|
||||
|
||||
std::cout << "[Hair] Convert first " << num_strands << " strands from "
|
||||
<< max_strands << " strands in the original hair data."
|
||||
<< std::endl;
|
||||
|
||||
// Assume input points are CatmullRom spline.
|
||||
for (size_t i = 0; i < static_cast<size_t>(num_strands); i++) {
|
||||
if ((i % 1000) == 0) {
|
||||
std::cout << i << " / " << num_strands_ << std::endl;
|
||||
}
|
||||
|
||||
int num_segments = segments_.empty() ? default_segments_ : segments_[i];
|
||||
if (num_segments < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<real3> segment_points;
|
||||
for (size_t k = 0; k < static_cast<size_t>(num_segments); k++) {
|
||||
// Zup -> Yup
|
||||
real3 p(points_[3 * (strand_offsets_[i] + k) + 0],
|
||||
points_[3 * (strand_offsets_[i] + k) + 2],
|
||||
points_[3 * (strand_offsets_[i] + k) + 1]);
|
||||
segment_points.push_back(p);
|
||||
}
|
||||
|
||||
// Skip both endpoints
|
||||
for (int s = 1; s < num_segments - 1; s++) {
|
||||
int seg_idx = s - 1;
|
||||
real3 q[4];
|
||||
CamullRomToCubicBezier(q, segment_points.data(), num_segments, seg_idx);
|
||||
|
||||
vertices->push_back(vertex_scale[0] * q[0].x + vertex_translate[0]);
|
||||
vertices->push_back(vertex_scale[1] * q[0].y + vertex_translate[1]);
|
||||
vertices->push_back(vertex_scale[2] * q[0].z + vertex_translate[2]);
|
||||
vertices->push_back(vertex_scale[0] * q[1].x + vertex_translate[0]);
|
||||
vertices->push_back(vertex_scale[1] * q[1].y + vertex_translate[1]);
|
||||
vertices->push_back(vertex_scale[2] * q[1].z + vertex_translate[2]);
|
||||
vertices->push_back(vertex_scale[0] * q[2].x + vertex_translate[0]);
|
||||
vertices->push_back(vertex_scale[1] * q[2].y + vertex_translate[1]);
|
||||
vertices->push_back(vertex_scale[2] * q[2].z + vertex_translate[2]);
|
||||
vertices->push_back(vertex_scale[0] * q[3].x + vertex_translate[0]);
|
||||
vertices->push_back(vertex_scale[1] * q[3].y + vertex_translate[1]);
|
||||
vertices->push_back(vertex_scale[2] * q[3].z + vertex_translate[2]);
|
||||
|
||||
if (user_thickness > 0) {
|
||||
// Use user supplied thickness.
|
||||
radiuss->push_back(user_thickness);
|
||||
radiuss->push_back(user_thickness);
|
||||
radiuss->push_back(user_thickness);
|
||||
radiuss->push_back(user_thickness);
|
||||
} else {
|
||||
// TODO(syoyo) Support per point/segment thickness
|
||||
radiuss->push_back(default_thickness_);
|
||||
radiuss->push_back(default_thickness_);
|
||||
radiuss->push_back(default_thickness_);
|
||||
radiuss->push_back(default_thickness_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace example
|
@ -1,109 +0,0 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Light Transport Entertainment, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Simple Cyhair loader.
|
||||
|
||||
#ifndef EXAMPLE_CYHAIR_LOADER_H_
|
||||
#define EXAMPLE_CYHAIR_LOADER_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace example {
|
||||
|
||||
struct CyHairHeader {
|
||||
char magic[4];
|
||||
unsigned int num_strands;
|
||||
unsigned int total_points;
|
||||
unsigned int flags;
|
||||
unsigned int default_segments;
|
||||
float default_thickness;
|
||||
float default_transparency;
|
||||
float default_color[3];
|
||||
char infomation[88];
|
||||
};
|
||||
|
||||
class CyHair {
|
||||
public:
|
||||
CyHair()
|
||||
: flags_(0),
|
||||
num_strands_(0),
|
||||
total_points_(0),
|
||||
default_segments_(-1),
|
||||
default_thickness_(0.01f),
|
||||
default_transparency_(1.0f) {
|
||||
default_color_[0] = 0.5f;
|
||||
default_color_[1] = 0.5f;
|
||||
default_color_[2] = 0.5f;
|
||||
}
|
||||
|
||||
~CyHair() {}
|
||||
|
||||
/// Load CyHair data from a file.
|
||||
bool Load(const char *filename);
|
||||
|
||||
/// Convert to cubic bezier curves.
|
||||
/// 4(cubic) * 3(xyz) * num_curves = vertices.size()
|
||||
/// 4(cubic) * num_curves = radiuss.size()
|
||||
/// `max_strands` limits the number of strands to convert. -1 = convert all
|
||||
/// strands.
|
||||
/// `thickness` overwrites strand thickness if it have positive value.
|
||||
/// Apply `vertex_translate` after `vertex_scale`.
|
||||
/// TODO(syoyo) return strand/segment information
|
||||
bool ToCubicBezierCurves(std::vector<float> *vertices,
|
||||
std::vector<float> *radiuss,
|
||||
const float vertex_scale[3],
|
||||
const float vertex_translate[3],
|
||||
const int max_strands = -1,
|
||||
const float thickness = -1.0f);
|
||||
|
||||
CyHairHeader header_;
|
||||
|
||||
// Raw CyHair values
|
||||
std::vector<unsigned short> segments_;
|
||||
std::vector<float> points_; // xyz
|
||||
std::vector<float> thicknesses_;
|
||||
std::vector<float> transparencies_;
|
||||
std::vector<float> colors_; // rgb
|
||||
unsigned int flags_;
|
||||
unsigned int num_strands_;
|
||||
unsigned int total_points_;
|
||||
int default_segments_;
|
||||
float default_thickness_;
|
||||
float default_transparency_;
|
||||
float default_color_[3];
|
||||
int pad0;
|
||||
|
||||
// Processed CyHair values
|
||||
std::vector<unsigned int> strand_offsets_;
|
||||
};
|
||||
|
||||
} // namespace example
|
||||
|
||||
#endif // EXAMPLE_CYHAIR_LOADER_H_
|
@ -27,7 +27,6 @@ When running .exe, glew and glfw dll must exist in the working directory.
|
||||
|
||||
## TODO
|
||||
|
||||
* [x] Texture
|
||||
* [ ] Various texture format.
|
||||
* [ ] Shader
|
||||
* [ ] PBR Material
|
||||
* [ ] PBR Texture.
|
||||
* [ ] Animation
|
||||
|
@ -60,9 +60,9 @@ typedef struct {
|
||||
size_t count; // byte count
|
||||
} GLCurvesState;
|
||||
|
||||
std::map<std::string, GLBufferState> gBufferState;
|
||||
std::map<int, GLBufferState> gBufferState;
|
||||
std::map<std::string, GLMeshState> gMeshState;
|
||||
std::map<std::string, GLCurvesState> gCurvesMesh;
|
||||
std::map<int, GLCurvesState> gCurvesMesh;
|
||||
GLProgramState gGLProgramState;
|
||||
|
||||
void CheckErrors(std::string desc) {
|
||||
@ -243,22 +243,17 @@ void motionFunc(GLFWwindow *window, double mouse_x, double mouse_y) {
|
||||
prevMouseY = mouse_y;
|
||||
}
|
||||
|
||||
static void SetupMeshState(tinygltf::Scene &scene, GLuint progId) {
|
||||
static void SetupMeshState(tinygltf::Model &model, GLuint progId) {
|
||||
// Buffer
|
||||
{
|
||||
std::map<std::string, tinygltf::BufferView>::const_iterator it(
|
||||
scene.bufferViews.begin());
|
||||
std::map<std::string, tinygltf::BufferView>::const_iterator itEnd(
|
||||
scene.bufferViews.end());
|
||||
|
||||
for (; it != itEnd; it++) {
|
||||
const tinygltf::BufferView &bufferView = it->second;
|
||||
for (size_t i = 0; i < model.bufferViews.size(); i++) {
|
||||
const tinygltf::BufferView &bufferView = model.bufferViews[i];
|
||||
if (bufferView.target == 0) {
|
||||
std::cout << "WARN: bufferView.target is zero" << std::endl;
|
||||
continue; // Unsupported bufferView.
|
||||
}
|
||||
|
||||
const tinygltf::Buffer &buffer = scene.buffers[bufferView.buffer];
|
||||
const tinygltf::Buffer &buffer = model.buffers[bufferView.buffer];
|
||||
GLBufferState state;
|
||||
glGenBuffers(1, &state.vb);
|
||||
glBindBuffer(bufferView.target, state.vb);
|
||||
@ -268,19 +263,15 @@ static void SetupMeshState(tinygltf::Scene &scene, GLuint progId) {
|
||||
&buffer.data.at(0) + bufferView.byteOffset, GL_STATIC_DRAW);
|
||||
glBindBuffer(bufferView.target, 0);
|
||||
|
||||
gBufferState[it->first] = state;
|
||||
gBufferState[i] = state;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 // TODO(syoyo): Implement
|
||||
// Texture
|
||||
{
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator it(
|
||||
scene.meshes.begin());
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(
|
||||
scene.meshes.end());
|
||||
|
||||
for (; it != itEnd; it++) {
|
||||
const tinygltf::Mesh &mesh = it->second;
|
||||
for (size_t i = 0; i < model.meshes.size(); i++) {
|
||||
const tinygltf::Mesh &mesh = model.meshes[i];
|
||||
|
||||
gMeshState[mesh.name].diffuseTex.resize(mesh.primitives.size());
|
||||
for (size_t primId = 0; primId < mesh.primitives.size(); primId++) {
|
||||
@ -288,17 +279,17 @@ static void SetupMeshState(tinygltf::Scene &scene, GLuint progId) {
|
||||
|
||||
gMeshState[mesh.name].diffuseTex[primId] = 0;
|
||||
|
||||
if (primitive.material.empty()) {
|
||||
if (primitive.material < 0) {
|
||||
continue;
|
||||
}
|
||||
tinygltf::Material &mat = scene.materials[primitive.material];
|
||||
tinygltf::Material &mat = model.materials[primitive.material];
|
||||
// printf("material.name = %s\n", mat.name.c_str());
|
||||
if (mat.values.find("diffuse") != mat.values.end()) {
|
||||
std::string diffuseTexName = mat.values["diffuse"].string_value;
|
||||
if (scene.textures.find(diffuseTexName) != scene.textures.end()) {
|
||||
tinygltf::Texture &tex = scene.textures[diffuseTexName];
|
||||
if (scene.images.find(tex.source) != scene.images.end()) {
|
||||
tinygltf::Image &image = scene.images[tex.source];
|
||||
if (model.textures.find(diffuseTexName) != model.textures.end()) {
|
||||
tinygltf::Texture &tex = model.textures[diffuseTexName];
|
||||
if (scene.images.find(tex.source) != model.images.end()) {
|
||||
tinygltf::Image &image = model.images[tex.source];
|
||||
GLuint texId;
|
||||
glGenTextures(1, &texId);
|
||||
glBindTexture(tex.target, texId);
|
||||
@ -326,22 +317,24 @@ static void SetupMeshState(tinygltf::Scene &scene, GLuint progId) {
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
glUseProgram(progId);
|
||||
GLint vtloc = glGetAttribLocation(progId, "in_vertex");
|
||||
GLint nrmloc = glGetAttribLocation(progId, "in_normal");
|
||||
GLint uvloc = glGetAttribLocation(progId, "in_texcoord");
|
||||
|
||||
GLint diffuseTexLoc = glGetUniformLocation(progId, "diffuseTex");
|
||||
// GLint diffuseTexLoc = glGetUniformLocation(progId, "diffuseTex");
|
||||
GLint isCurvesLoc = glGetUniformLocation(progId, "uIsCurves");
|
||||
|
||||
gGLProgramState.attribs["POSITION"] = vtloc;
|
||||
gGLProgramState.attribs["NORMAL"] = nrmloc;
|
||||
gGLProgramState.attribs["TEXCOORD_0"] = uvloc;
|
||||
gGLProgramState.uniforms["diffuseTex"] = diffuseTexLoc;
|
||||
// gGLProgramState.uniforms["diffuseTex"] = diffuseTexLoc;
|
||||
gGLProgramState.uniforms["isCurvesLoc"] = isCurvesLoc;
|
||||
};
|
||||
|
||||
#if 0 // TODO(syoyo): Implement
|
||||
// Setup curves geometry extension
|
||||
static void SetupCurvesState(tinygltf::Scene &scene, GLuint progId) {
|
||||
// Find curves primitive.
|
||||
@ -503,16 +496,17 @@ static void SetupCurvesState(tinygltf::Scene &scene, GLuint progId) {
|
||||
gGLProgramState.uniforms["diffuseTex"] = diffuseTexLoc;
|
||||
gGLProgramState.uniforms["uIsCurves"] = isCurvesLoc;
|
||||
};
|
||||
#endif
|
||||
|
||||
static void DrawMesh(tinygltf::Scene &scene, const tinygltf::Mesh &mesh) {
|
||||
// Skip curves primitive.
|
||||
if (gCurvesMesh.find(mesh.name) != gCurvesMesh.end()) {
|
||||
return;
|
||||
}
|
||||
static void DrawMesh(tinygltf::Model &model, const tinygltf::Mesh &mesh) {
|
||||
//// Skip curves primitive.
|
||||
// if (gCurvesMesh.find(mesh.name) != gCurvesMesh.end()) {
|
||||
// return;
|
||||
//}
|
||||
|
||||
if (gGLProgramState.uniforms["diffuseTex"] >= 0) {
|
||||
glUniform1i(gGLProgramState.uniforms["diffuseTex"], 0); // TEXTURE0
|
||||
}
|
||||
// if (gGLProgramState.uniforms["diffuseTex"] >= 0) {
|
||||
// glUniform1i(gGLProgramState.uniforms["diffuseTex"], 0); // TEXTURE0
|
||||
//}
|
||||
|
||||
if (gGLProgramState.uniforms["isCurvesLoc"] >= 0) {
|
||||
glUniform1i(gGLProgramState.uniforms["isCurvesLoc"], 0);
|
||||
@ -521,19 +515,18 @@ static void DrawMesh(tinygltf::Scene &scene, const tinygltf::Mesh &mesh) {
|
||||
for (size_t i = 0; i < mesh.primitives.size(); i++) {
|
||||
const tinygltf::Primitive &primitive = mesh.primitives[i];
|
||||
|
||||
if (primitive.indices.empty()) return;
|
||||
|
||||
std::map<std::string, std::string>::const_iterator it(
|
||||
primitive.attributes.begin());
|
||||
std::map<std::string, std::string>::const_iterator itEnd(
|
||||
primitive.attributes.end());
|
||||
if (primitive.indices < 0) return;
|
||||
|
||||
// Assume TEXTURE_2D target for the texture object.
|
||||
glBindTexture(GL_TEXTURE_2D, gMeshState[mesh.name].diffuseTex[i]);
|
||||
// glBindTexture(GL_TEXTURE_2D, gMeshState[mesh.name].diffuseTex[i]);
|
||||
|
||||
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++) {
|
||||
assert(scene.accessors.find(it->second) != scene.accessors.end());
|
||||
const tinygltf::Accessor &accessor = scene.accessors[it->second];
|
||||
assert(it->second >= 0);
|
||||
const tinygltf::Accessor &accessor = model.accessors[it->second];
|
||||
glBindBuffer(GL_ARRAY_BUFFER, gBufferState[accessor.bufferView].vb);
|
||||
CheckErrors("bind buffer");
|
||||
int count = 1;
|
||||
@ -565,7 +558,7 @@ static void DrawMesh(tinygltf::Scene &scene, const tinygltf::Mesh &mesh) {
|
||||
}
|
||||
|
||||
const tinygltf::Accessor &indexAccessor =
|
||||
scene.accessors[primitive.indices];
|
||||
model.accessors[primitive.indices];
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
|
||||
gBufferState[indexAccessor.bufferView].vb);
|
||||
CheckErrors("bind buffer");
|
||||
@ -590,9 +583,9 @@ static void DrawMesh(tinygltf::Scene &scene, const tinygltf::Mesh &mesh) {
|
||||
CheckErrors("draw elements");
|
||||
|
||||
{
|
||||
std::map<std::string, std::string>::const_iterator it(
|
||||
std::map<std::string, int>::const_iterator it(
|
||||
primitive.attributes.begin());
|
||||
std::map<std::string, std::string>::const_iterator itEnd(
|
||||
std::map<std::string, int>::const_iterator itEnd(
|
||||
primitive.attributes.end());
|
||||
|
||||
for (; it != itEnd; it++) {
|
||||
@ -608,6 +601,7 @@ static void DrawMesh(tinygltf::Scene &scene, const tinygltf::Mesh &mesh) {
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 // TODO(syoyo): Implement
|
||||
static void DrawCurves(tinygltf::Scene &scene, const tinygltf::Mesh &mesh) {
|
||||
(void)scene;
|
||||
|
||||
@ -636,9 +630,10 @@ static void DrawCurves(tinygltf::Scene &scene, const tinygltf::Mesh &mesh) {
|
||||
glDisableVertexAttribArray(gGLProgramState.attribs["POSITION"]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Hierarchically draw nodes
|
||||
static void DrawNode(tinygltf::Scene &scene, const tinygltf::Node &node) {
|
||||
static void DrawNode(tinygltf::Model &model, const tinygltf::Node &node) {
|
||||
// Apply xform
|
||||
|
||||
glPushMatrix();
|
||||
@ -662,34 +657,23 @@ static void DrawNode(tinygltf::Scene &scene, const tinygltf::Node &node) {
|
||||
}
|
||||
}
|
||||
|
||||
//std::cout << "node " << node.name << ", Meshes " << node.meshes.size() << std::endl;
|
||||
// std::cout << "node " << node.name << ", Meshes " << node.meshes.size() <<
|
||||
// std::endl;
|
||||
|
||||
for (size_t i = 0; i < node.meshes.size(); i++) {
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator it =
|
||||
scene.meshes.find(node.meshes[i]);
|
||||
|
||||
if (it != scene.meshes.end()) {
|
||||
//std::cout << it->first << std::endl;
|
||||
// FIXME(syoyo): Refactor.
|
||||
DrawCurves(scene, it->second);
|
||||
DrawMesh(scene, it->second);
|
||||
}
|
||||
}
|
||||
// std::cout << it->first << std::endl;
|
||||
// FIXME(syoyo): Refactor.
|
||||
// DrawCurves(scene, it->second);
|
||||
DrawMesh(model, model.meshes[node.mesh]);
|
||||
|
||||
// Draw child nodes.
|
||||
for (size_t i = 0; i < node.children.size(); i++) {
|
||||
std::map<std::string, tinygltf::Node>::const_iterator it =
|
||||
scene.nodes.find(node.children[i]);
|
||||
|
||||
if (it != scene.nodes.end()) {
|
||||
DrawNode(scene, it->second);
|
||||
}
|
||||
DrawNode(model, model.nodes[node.children[i]]);
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
static void DrawScene(tinygltf::Scene &scene) {
|
||||
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,19 +683,12 @@ static void DrawScene(tinygltf::Scene &scene) {
|
||||
DrawCurves(scene, it->second);
|
||||
}
|
||||
#else
|
||||
std::map<std::string, std::vector<std::string> >::const_iterator it =
|
||||
scene.scenes.find(scene.defaultScene);
|
||||
if (it == scene.scenes.end()) return;
|
||||
|
||||
for (size_t i = 0; i < it->second.size(); i++) {
|
||||
std::map<std::string, tinygltf::Node>::const_iterator node_it =
|
||||
scene.nodes.find((it->second)[i]);
|
||||
|
||||
if (node_it == scene.nodes.end()) continue;
|
||||
|
||||
//std::cout << "root: " << node_it->first << std::endl;
|
||||
|
||||
DrawNode(scene, node_it->second);
|
||||
// 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]]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -733,12 +710,8 @@ static void Init() {
|
||||
}
|
||||
|
||||
static void PrintNodes(const tinygltf::Scene &scene) {
|
||||
std::map<std::string, tinygltf::Node>::const_iterator it(scene.nodes.begin());
|
||||
std::map<std::string, tinygltf::Node>::const_iterator itEnd(
|
||||
scene.nodes.end());
|
||||
|
||||
for (; it != itEnd; it++) {
|
||||
std::cout << "node.name : " << it->second.name << std::endl;
|
||||
for (size_t i = 0; i < scene.nodes.size(); i++) {
|
||||
std::cout << "node.name : " << scene.nodes[i] << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@ -753,7 +726,7 @@ int main(int argc, char **argv) {
|
||||
scale = atof(argv[2]);
|
||||
}
|
||||
|
||||
tinygltf::Scene scene;
|
||||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTFLoader loader;
|
||||
std::string err;
|
||||
std::string input_filename(argv[1]);
|
||||
@ -762,10 +735,10 @@ int main(int argc, char **argv) {
|
||||
bool ret = false;
|
||||
if (ext.compare("glb") == 0) {
|
||||
// assume binary glTF.
|
||||
ret = loader.LoadBinaryFromFile(&scene, &err, input_filename.c_str());
|
||||
ret = loader.LoadBinaryFromFile(&model, &err, input_filename.c_str());
|
||||
} else {
|
||||
// assume ascii glTF.
|
||||
ret = loader.LoadASCIIFromFile(&scene, &err, input_filename.c_str());
|
||||
ret = loader.LoadASCIIFromFile(&model, &err, input_filename.c_str());
|
||||
}
|
||||
|
||||
if (!err.empty()) {
|
||||
@ -779,7 +752,7 @@ int main(int argc, char **argv) {
|
||||
Init();
|
||||
|
||||
// DBG
|
||||
PrintNodes(scene);
|
||||
PrintNodes(model.scenes[model.defaultScene]);
|
||||
|
||||
if (!glfwInit()) {
|
||||
std::cerr << "Failed to initialize GLFW." << std::endl;
|
||||
@ -843,11 +816,11 @@ int main(int argc, char **argv) {
|
||||
glUseProgram(progId);
|
||||
CheckErrors("useProgram");
|
||||
|
||||
SetupMeshState(scene, progId);
|
||||
SetupCurvesState(scene, progId);
|
||||
SetupMeshState(model, progId);
|
||||
// SetupCurvesState(model, progId);
|
||||
CheckErrors("SetupGLState");
|
||||
|
||||
std::cout << "# of meshes = " << scene.meshes.size() << std::endl;
|
||||
std::cout << "# of meshes = " << model.meshes.size() << std::endl;
|
||||
|
||||
while (glfwWindowShouldClose(window) == GL_FALSE) {
|
||||
glfwPollEvents();
|
||||
@ -871,7 +844,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
glScalef(scale, scale, scale);
|
||||
|
||||
DrawScene(scene);
|
||||
DrawModel(model);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
|
@ -1,2 +0,0 @@
|
||||
all:
|
||||
$(CXX) -o gltf_writer -I../../ writer.cc
|
@ -1,11 +0,0 @@
|
||||
# Simple glTF writer in C++.
|
||||
|
||||
Read glTF with tinygltfloader, and write it to glTF JSON.
|
||||
|
||||
## TODO
|
||||
|
||||
* [ ] Asset export option(embed, external file)
|
||||
* [ ] Textures
|
||||
* [ ] Materials
|
||||
* [ ] etc.
|
||||
|
@ -1,431 +0,0 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#define TINYGLTF_LOADER_IMPLEMENTATION
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "../../tiny_gltf_loader.h"
|
||||
|
||||
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 "";
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// writer module
|
||||
// @todo { move writer code to tiny_gltf_writer.h }
|
||||
|
||||
static std::string EncodeType(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**";
|
||||
}
|
||||
|
||||
// http://www.adp-gmbh.ch/cpp/common/base64.html
|
||||
static const std::string base64_chars =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
|
||||
std::string base64_encode(unsigned char const* bytes_to_encode,
|
||||
unsigned int in_len) {
|
||||
std::string ret;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
unsigned char char_array_3[3];
|
||||
unsigned char char_array_4[4];
|
||||
|
||||
while (in_len--) {
|
||||
char_array_3[i++] = *(bytes_to_encode++);
|
||||
if (i == 3) {
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] =
|
||||
((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||
char_array_4[2] =
|
||||
((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
|
||||
for (i = 0; (i < 4); i++) ret += base64_chars[char_array_4[i]];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i) {
|
||||
for (j = i; j < 3; j++) char_array_3[j] = '\0';
|
||||
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] =
|
||||
((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||
char_array_4[2] =
|
||||
((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
|
||||
for (j = 0; (j < i + 1); j++) ret += base64_chars[char_array_4[j]];
|
||||
|
||||
while ((i++ < 3)) ret += '=';
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool EncodeBuffers(picojson::object* o,
|
||||
const std::map<std::string, tinygltf::Buffer>& buffers) {
|
||||
std::map<std::string, tinygltf::Buffer>::const_iterator it(buffers.begin());
|
||||
std::map<std::string, tinygltf::Buffer>::const_iterator itEnd(buffers.end());
|
||||
for (; it != itEnd; it++) {
|
||||
// @todo { Support external file resource. }
|
||||
picojson::object buf;
|
||||
std::string b64_data =
|
||||
base64_encode(it->second.data.data(), it->second.data.size());
|
||||
buf["type"] = picojson::value("arraybuffer");
|
||||
buf["uri"] = picojson::value(
|
||||
std::string("data:application/octet-stream;base64,") + b64_data);
|
||||
buf["byteLength"] =
|
||||
picojson::value(static_cast<double>(it->second.data.size()));
|
||||
|
||||
(*o)[it->first] = picojson::value(buf);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EncodeBufferViews(
|
||||
picojson::object* o,
|
||||
const std::map<std::string, tinygltf::BufferView>& bufferViews) {
|
||||
std::map<std::string, tinygltf::BufferView>::const_iterator it(
|
||||
bufferViews.begin());
|
||||
std::map<std::string, tinygltf::BufferView>::const_iterator itEnd(
|
||||
bufferViews.end());
|
||||
|
||||
for (; it != itEnd; it++) {
|
||||
picojson::object buf;
|
||||
buf["buffer"] = picojson::value(it->second.buffer);
|
||||
buf["byteLength"] =
|
||||
picojson::value(static_cast<double>(it->second.byteLength));
|
||||
buf["byteOffset"] =
|
||||
picojson::value(static_cast<double>(it->second.byteOffset));
|
||||
buf["target"] = picojson::value(static_cast<double>(it->second.target));
|
||||
|
||||
(*o)[it->first] = picojson::value(buf);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EncodeFloatArray(picojson::array* arr, const std::vector<double>& values) {
|
||||
for (size_t i = 0; i < values.size(); i++) {
|
||||
arr->push_back(picojson::value(values[i]));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EncodeStringArray(picojson::array* arr,
|
||||
const std::vector<std::string>& values) {
|
||||
for (size_t i = 0; i < values.size(); i++) {
|
||||
arr->push_back(picojson::value(values[i]));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EncodeNode(picojson::object* o, const tinygltf::Node& node) {
|
||||
(*o)["name"] = picojson::value(node.name);
|
||||
(*o)["camera"] = picojson::value(node.camera);
|
||||
|
||||
if (!node.rotation.empty()) {
|
||||
picojson::array arr;
|
||||
EncodeFloatArray(&arr, node.rotation);
|
||||
(*o)["rotation"] = picojson::value(arr);
|
||||
}
|
||||
if (!node.scale.empty()) {
|
||||
picojson::array arr;
|
||||
EncodeFloatArray(&arr, node.scale);
|
||||
(*o)["scale"] = picojson::value(arr);
|
||||
}
|
||||
if (!node.translation.empty()) {
|
||||
picojson::array arr;
|
||||
EncodeFloatArray(&arr, node.translation);
|
||||
(*o)["translation"] = picojson::value(arr);
|
||||
}
|
||||
|
||||
if (!node.matrix.empty()) {
|
||||
picojson::array arr;
|
||||
EncodeFloatArray(&arr, node.matrix);
|
||||
(*o)["matrix"] = picojson::value(arr);
|
||||
}
|
||||
|
||||
if (!node.meshes.empty()) {
|
||||
picojson::array arr;
|
||||
EncodeStringArray(&arr, node.meshes);
|
||||
(*o)["meshes"] = picojson::value(arr);
|
||||
}
|
||||
|
||||
if (!node.children.empty()) {
|
||||
picojson::array arr;
|
||||
EncodeStringArray(&arr, node.children);
|
||||
(*o)["children"] = picojson::value(arr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EncodeNodes(picojson::object* o,
|
||||
const std::map<std::string, tinygltf::Node>& nodes) {
|
||||
std::map<std::string, tinygltf::Node>::const_iterator it(nodes.begin());
|
||||
std::map<std::string, tinygltf::Node>::const_iterator itEnd(nodes.end());
|
||||
|
||||
for (; it != itEnd; it++) {
|
||||
picojson::object node;
|
||||
EncodeNode(&node, it->second);
|
||||
|
||||
(*o)[it->first] = picojson::value(node);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EncodeScenes(
|
||||
picojson::object* o,
|
||||
const std::map<std::string, std::vector<std::string> >& scenes) {
|
||||
std::map<std::string, std::vector<std::string> >::const_iterator it(
|
||||
scenes.begin());
|
||||
std::map<std::string, std::vector<std::string> >::const_iterator itEnd(
|
||||
scenes.end());
|
||||
|
||||
for (; it != itEnd; it++) {
|
||||
picojson::object buf;
|
||||
picojson::array arr;
|
||||
for (size_t i = 0; i < it->second.size(); i++) {
|
||||
arr.push_back(picojson::value(it->second[i]));
|
||||
}
|
||||
|
||||
buf["nodes"] = picojson::value(arr);
|
||||
|
||||
(*o)[it->first] = picojson::value(buf);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EncodeAccessors(
|
||||
picojson::object* o,
|
||||
const std::map<std::string, tinygltf::Accessor>& accessors) {
|
||||
std::map<std::string, tinygltf::Accessor>::const_iterator it(
|
||||
accessors.begin());
|
||||
std::map<std::string, tinygltf::Accessor>::const_iterator itEnd(
|
||||
accessors.end());
|
||||
for (; it != itEnd; it++) {
|
||||
picojson::object buf;
|
||||
buf["bufferView"] = picojson::value(it->second.bufferView);
|
||||
buf["byteOffset"] =
|
||||
picojson::value(static_cast<double>(it->second.byteOffset));
|
||||
buf["byteStride"] =
|
||||
picojson::value(static_cast<double>(it->second.byteStride));
|
||||
buf["componentType"] =
|
||||
picojson::value(static_cast<double>(it->second.componentType));
|
||||
buf["count"] = picojson::value(static_cast<double>(it->second.count));
|
||||
buf["type"] = picojson::value(EncodeType(it->second.type));
|
||||
|
||||
if (!it->second.minValues.empty()) {
|
||||
picojson::array arr;
|
||||
EncodeFloatArray(&arr, it->second.minValues);
|
||||
buf["min"] = picojson::value(arr);
|
||||
}
|
||||
if (!it->second.maxValues.empty()) {
|
||||
picojson::array arr;
|
||||
EncodeFloatArray(&arr, it->second.maxValues);
|
||||
buf["max"] = picojson::value(arr);
|
||||
}
|
||||
|
||||
(*o)[it->first] = picojson::value(buf);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EncodePrimitive(picojson::object* o,
|
||||
const tinygltf::Primitive& primitive) {
|
||||
(*o)["material"] = picojson::value(primitive.material);
|
||||
(*o)["indices"] = picojson::value(primitive.indices);
|
||||
(*o)["mode"] = picojson::value(static_cast<double>(primitive.mode));
|
||||
|
||||
std::map<std::string, std::string>::const_iterator it(
|
||||
primitive.attributes.begin());
|
||||
std::map<std::string, std::string>::const_iterator itEnd(
|
||||
primitive.attributes.end());
|
||||
|
||||
picojson::object attributes;
|
||||
for (; it != itEnd; it++) {
|
||||
picojson::object buf;
|
||||
attributes[it->first] = picojson::value(it->second);
|
||||
}
|
||||
|
||||
(*o)["attributes"] = picojson::value(attributes);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EncodeMeshes(picojson::object* o,
|
||||
const std::map<std::string, tinygltf::Mesh>& meshes) {
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator it(meshes.begin());
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(meshes.end());
|
||||
for (; it != itEnd; it++) {
|
||||
picojson::object buf;
|
||||
|
||||
buf["name"] = picojson::value(it->second.name);
|
||||
|
||||
picojson::array arr;
|
||||
for (size_t i = 0; i < it->second.primitives.size(); i++) {
|
||||
picojson::object primitive;
|
||||
EncodePrimitive(&primitive, it->second.primitives[i]);
|
||||
arr.push_back(picojson::value(primitive));
|
||||
}
|
||||
buf["primitives"] = picojson::value(arr);
|
||||
|
||||
(*o)[it->first] = picojson::value(buf);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveGLTF(const std::string& output_filename,
|
||||
const tinygltf::Scene& scene) {
|
||||
picojson::object root;
|
||||
|
||||
{
|
||||
picojson::object asset;
|
||||
asset["generator"] = picojson::value("tinygltf_writer");
|
||||
asset["premultipliedAlpha"] = picojson::value(true);
|
||||
asset["version"] = picojson::value(static_cast<double>(1));
|
||||
picojson::object profile;
|
||||
profile["api"] = picojson::value("WebGL");
|
||||
profile["version"] = picojson::value("1.0.2");
|
||||
asset["profile"] = picojson::value(profile);
|
||||
root["assets"] = picojson::value(asset);
|
||||
}
|
||||
|
||||
{
|
||||
picojson::object buffers;
|
||||
bool ret = EncodeBuffers(&buffers, scene.buffers);
|
||||
assert(ret);
|
||||
root["buffers"] = picojson::value(buffers);
|
||||
}
|
||||
|
||||
{
|
||||
picojson::object bufferViews;
|
||||
bool ret = EncodeBufferViews(&bufferViews, scene.bufferViews);
|
||||
assert(ret);
|
||||
root["bufferViews"] = picojson::value(bufferViews);
|
||||
}
|
||||
|
||||
{
|
||||
picojson::object accessors;
|
||||
bool ret = EncodeAccessors(&accessors, scene.accessors);
|
||||
assert(ret);
|
||||
root["accessors"] = picojson::value(accessors);
|
||||
}
|
||||
|
||||
{
|
||||
picojson::object meshes;
|
||||
bool ret = EncodeMeshes(&meshes, scene.meshes);
|
||||
assert(ret);
|
||||
root["meshes"] = picojson::value(meshes);
|
||||
}
|
||||
|
||||
{
|
||||
picojson::object nodes;
|
||||
bool ret = EncodeNodes(&nodes, scene.nodes);
|
||||
assert(ret);
|
||||
root["nodes"] = picojson::value(nodes);
|
||||
}
|
||||
|
||||
root["scene"] = picojson::value(scene.defaultScene);
|
||||
{
|
||||
picojson::object scenes;
|
||||
bool ret = EncodeScenes(&scenes, scene.scenes);
|
||||
assert(ret);
|
||||
root["scenes"] = picojson::value(scenes);
|
||||
}
|
||||
|
||||
// @todo {}
|
||||
picojson::object shaders;
|
||||
picojson::object programs;
|
||||
picojson::object techniques;
|
||||
picojson::object materials;
|
||||
picojson::object skins;
|
||||
root["shaders"] = picojson::value(shaders);
|
||||
root["programs"] = picojson::value(programs);
|
||||
root["techniques"] = picojson::value(techniques);
|
||||
root["materials"] = picojson::value(materials);
|
||||
root["skins"] = picojson::value(skins);
|
||||
|
||||
picojson::value v = picojson::value(root);
|
||||
|
||||
std::ofstream ifs(output_filename.c_str());
|
||||
if (ifs.bad()) {
|
||||
std::cerr << "Failed to open " << output_filename << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string s = v.serialize(/* pretty */true);
|
||||
ifs.write(s.data(), s.size());
|
||||
ifs.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc < 3) {
|
||||
printf("Needs input.gltf output.gltf\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
tinygltf::Scene scene;
|
||||
tinygltf::TinyGLTFLoader loader;
|
||||
std::string err;
|
||||
std::string input_filename(argv[1]);
|
||||
std::string ext = GetFilePathExtension(input_filename);
|
||||
|
||||
bool ret = false;
|
||||
if (ext.compare("glb") == 0) {
|
||||
// assume binary glTF.
|
||||
ret = loader.LoadBinaryFromFile(&scene, &err, input_filename.c_str());
|
||||
} else {
|
||||
// assume ascii glTF.
|
||||
ret = loader.LoadASCIIFromFile(&scene, &err, input_filename.c_str());
|
||||
}
|
||||
|
||||
if (!err.empty()) {
|
||||
printf("Err: %s\n", err.c_str());
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
printf("Failed to parse glTF\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = SaveGLTF(argv[2], scene);
|
||||
|
||||
return ret ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 160 KiB |
Binary file not shown.
Before Width: | Height: | Size: 46 KiB |
@ -210,18 +210,20 @@ static std::string PrintParameterValue(const tinygltf::Parameter ¶m) {
|
||||
}
|
||||
}
|
||||
|
||||
static std::string PrintValue(const std::string& name, const tinygltf::Value &value, const int indent) {
|
||||
static std::string PrintValue(const std::string &name,
|
||||
const tinygltf::Value &value, const int indent) {
|
||||
std::stringstream ss;
|
||||
|
||||
if (value.IsObject()) {
|
||||
const tinygltf::Value::Object& o = value.Get<tinygltf::Value::Object>();
|
||||
const tinygltf::Value::Object &o = value.Get<tinygltf::Value::Object>();
|
||||
tinygltf::Value::Object::const_iterator it(o.begin());
|
||||
tinygltf::Value::Object::const_iterator itEnd(o.end());
|
||||
for (; it != itEnd; it++) {
|
||||
ss << PrintValue(name, it->second, indent + 1);
|
||||
}
|
||||
} else if (value.IsString()) {
|
||||
ss << Indent(indent) << name << " : " << value.Get<std::string>() << std::endl;
|
||||
ss << Indent(indent) << name << " : " << value.Get<std::string>()
|
||||
<< std::endl;
|
||||
} else if (value.IsBool()) {
|
||||
ss << Indent(indent) << name << " : " << value.Get<bool>() << std::endl;
|
||||
} else if (value.IsNumber()) {
|
||||
@ -262,8 +264,7 @@ static void DumpNode(const tinygltf::Node &node, int indent) {
|
||||
<< "children : " << PrintIntArray(node.children) << std::endl;
|
||||
}
|
||||
|
||||
static void DumpStringIntMap(const std::map<std::string, int> &m,
|
||||
int indent) {
|
||||
static void DumpStringIntMap(const std::map<std::string, int> &m, int indent) {
|
||||
std::map<std::string, int>::const_iterator it(m.begin());
|
||||
std::map<std::string, int>::const_iterator itEnd(m.end());
|
||||
for (; it != itEnd; it++) {
|
||||
@ -282,9 +283,8 @@ static void DumpPrimitive(const tinygltf::Primitive &primitive, int indent) {
|
||||
<< std::endl;
|
||||
DumpStringIntMap(primitive.attributes, indent + 1);
|
||||
|
||||
std::cout << Indent(indent)
|
||||
<< "extras :" << std::endl
|
||||
<< PrintValue("extras", primitive.extras, indent+1) << std::endl;
|
||||
std::cout << Indent(indent) << "extras :" << std::endl
|
||||
<< PrintValue("extras", primitive.extras, indent + 1) << std::endl;
|
||||
}
|
||||
|
||||
static void Dump(const tinygltf::Model &model) {
|
||||
@ -305,14 +305,16 @@ static void Dump(const tinygltf::Model &model) {
|
||||
{
|
||||
std::cout << "scenes(items=" << model.scenes.size() << ")" << std::endl;
|
||||
for (size_t i = 0; i < model.scenes.size(); i++) {
|
||||
std::cout << Indent(1) << "scene[" << i << "] name : " << model.scenes[i].name << std::endl;
|
||||
std::cout << Indent(1) << "scene[" << i
|
||||
<< "] name : " << model.scenes[i].name << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::cout << "meshes(item=" << model.meshes.size() << ")" << std::endl;
|
||||
for (size_t i = 0; i < model.meshes.size(); i++) {
|
||||
std::cout << Indent(1) << "name : " << model.meshes[i].name << std::endl;
|
||||
std::cout << Indent(1) << "name : " << model.meshes[i].name
|
||||
<< std::endl;
|
||||
std::cout << Indent(1)
|
||||
<< "primitives(items=" << model.meshes[i].primitives.size()
|
||||
<< "): " << std::endl;
|
||||
@ -364,7 +366,8 @@ static void Dump(const tinygltf::Model &model) {
|
||||
<< std::endl;
|
||||
for (size_t i = 0; i < model.animations.size(); i++) {
|
||||
const tinygltf::Animation &animation = model.animations[i];
|
||||
std::cout << Indent(1) << "name : " << animation.name << std::endl;
|
||||
std::cout << Indent(1) << "name : " << animation.name
|
||||
<< std::endl;
|
||||
|
||||
std::cout << Indent(1) << "channels : [ " << std::endl;
|
||||
for (size_t j = 0; i < animation.channels.size(); i++) {
|
||||
@ -387,13 +390,11 @@ static void Dump(const tinygltf::Model &model) {
|
||||
const tinygltf::AnimationSampler &sampler = animation.samplers[j];
|
||||
std::cout << Indent(2) << "input : " << sampler.input
|
||||
<< std::endl;
|
||||
std::cout << Indent(2)
|
||||
<< "interpolation : " << sampler.interpolation
|
||||
std::cout << Indent(2) << "interpolation : " << sampler.interpolation
|
||||
<< std::endl;
|
||||
std::cout << Indent(2) << "output : " << sampler.output
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -402,7 +403,8 @@ static void Dump(const tinygltf::Model &model) {
|
||||
<< std::endl;
|
||||
for (size_t i = 0; i < model.bufferViews.size(); i++) {
|
||||
const tinygltf::BufferView &bufferView = model.bufferViews[i];
|
||||
std::cout << Indent(1) << "name : " << bufferView.name << std::endl;
|
||||
std::cout << Indent(1) << "name : " << bufferView.name
|
||||
<< std::endl;
|
||||
std::cout << Indent(2) << "buffer : " << bufferView.buffer
|
||||
<< std::endl;
|
||||
std::cout << Indent(2) << "byteLength : " << bufferView.byteLength
|
||||
@ -431,8 +433,8 @@ static void Dump(const tinygltf::Model &model) {
|
||||
for (size_t i = 0; i < model.materials.size(); i++) {
|
||||
const tinygltf::Material &material = model.materials[i];
|
||||
std::cout << Indent(1) << "name : " << material.name << std::endl;
|
||||
std::cout << Indent(1) << "values(items=" << material.values.size()
|
||||
<< ")" << std::endl;
|
||||
std::cout << Indent(1) << "values(items=" << material.values.size() << ")"
|
||||
<< std::endl;
|
||||
|
||||
tinygltf::ParameterMap::const_iterator p(material.values.begin());
|
||||
tinygltf::ParameterMap::const_iterator pEnd(material.values.end());
|
||||
@ -460,10 +462,8 @@ static void Dump(const tinygltf::Model &model) {
|
||||
std::cout << Indent(1) << "name : " << image.name << std::endl;
|
||||
|
||||
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;
|
||||
std::cout << Indent(2) << "height : " << image.height << std::endl;
|
||||
std::cout << Indent(2) << "component : " << image.component << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 871 KiB |
Binary file not shown.
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 319 B |
@ -4,7 +4,8 @@
|
||||
//
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2015 - 2017 Syoyo Fujita, Aurélien Chatelain and many contributors.
|
||||
// Copyright (c) 2015 - 2017 Syoyo Fujita, Aurélien Chatelain and many
|
||||
// contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
@ -286,29 +287,22 @@ typedef struct {
|
||||
typedef std::map<std::string, Parameter> ParameterMap;
|
||||
|
||||
struct AnimationChannel {
|
||||
int sampler; // required
|
||||
int target_node; // required (index of the node to target)
|
||||
std::string target_path; // required in ["translation", "rotation", "scale", "weights"]
|
||||
int sampler; // required
|
||||
int target_node; // required (index of the node to target)
|
||||
std::string target_path; // required in ["translation", "rotation", "scale",
|
||||
// "weights"]
|
||||
Value extras;
|
||||
|
||||
AnimationChannel()
|
||||
: sampler(-1)
|
||||
, target_node(-1)
|
||||
{
|
||||
}
|
||||
AnimationChannel() : sampler(-1), target_node(-1) {}
|
||||
};
|
||||
|
||||
struct AnimationSampler {
|
||||
int input; // required
|
||||
int output; // required
|
||||
std::string interpolation; // in ["LINEAR", "STEP", "CATMULLROMSPLINE", "CUBICSPLINE"], default "LINEAR"
|
||||
int input; // required
|
||||
int output; // required
|
||||
std::string interpolation; // in ["LINEAR", "STEP", "CATMULLROMSPLINE",
|
||||
// "CUBICSPLINE"], default "LINEAR"
|
||||
|
||||
AnimationSampler()
|
||||
: input(-1)
|
||||
, output(-1)
|
||||
, interpolation("LINEAR")
|
||||
{
|
||||
}
|
||||
AnimationSampler() : input(-1), output(-1), interpolation("LINEAR") {}
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@ -320,61 +314,53 @@ typedef struct {
|
||||
|
||||
struct Skin {
|
||||
std::string name;
|
||||
int inverseBindMatrices; // required here but not in the spec
|
||||
int skeleton; // The index of the node used as a skeleton root
|
||||
std::vector<int> joints; // Indices of skeleton nodes
|
||||
int inverseBindMatrices; // required here but not in the spec
|
||||
int skeleton; // The index of the node used as a skeleton root
|
||||
std::vector<int> joints; // Indices of skeleton nodes
|
||||
|
||||
Skin()
|
||||
{
|
||||
inverseBindMatrices = -1;
|
||||
}
|
||||
Skin() { inverseBindMatrices = -1; }
|
||||
};
|
||||
|
||||
struct Sampler {
|
||||
std::string name;
|
||||
int minFilter; // ["NEAREST", "LINEAR", "NEAREST_MIPMAP_LINEAR", "LINEAR_MIPMAP_NEAREST", "NEAREST_MIPMAP_LINEAR", "LINEAR_MIPMAP_LINEAR"]
|
||||
int magFilter; // ["NEAREST", "LINEAR"]
|
||||
int wrapS; // ["CLAMP_TO_EDGE", "MIRRORED_REPEAT", "REPEAT"], default "REPEAT"
|
||||
int wrapT; // ["CLAMP_TO_EDGE", "MIRRORED_REPEAT", "REPEAT"], default "REPEAT"
|
||||
int wrapR; // TinyGLTF extension
|
||||
int minFilter; // ["NEAREST", "LINEAR", "NEAREST_MIPMAP_LINEAR",
|
||||
// "LINEAR_MIPMAP_NEAREST", "NEAREST_MIPMAP_LINEAR",
|
||||
// "LINEAR_MIPMAP_LINEAR"]
|
||||
int magFilter; // ["NEAREST", "LINEAR"]
|
||||
int wrapS; // ["CLAMP_TO_EDGE", "MIRRORED_REPEAT", "REPEAT"], default
|
||||
// "REPEAT"
|
||||
int wrapT; // ["CLAMP_TO_EDGE", "MIRRORED_REPEAT", "REPEAT"], default
|
||||
// "REPEAT"
|
||||
int wrapR; // TinyGLTF extension
|
||||
int pad0;
|
||||
Value extras;
|
||||
|
||||
Sampler()
|
||||
: wrapS(TINYGLTF_TEXTURE_WRAP_RPEAT)
|
||||
, wrapT(TINYGLTF_TEXTURE_WRAP_RPEAT)
|
||||
{
|
||||
}
|
||||
: wrapS(TINYGLTF_TEXTURE_WRAP_RPEAT),
|
||||
wrapT(TINYGLTF_TEXTURE_WRAP_RPEAT) {}
|
||||
};
|
||||
|
||||
struct Image{
|
||||
struct Image {
|
||||
std::string name;
|
||||
int width;
|
||||
int height;
|
||||
int component;
|
||||
int pad0;
|
||||
std::vector<unsigned char> image;
|
||||
int bufferView; // (required if no uri)
|
||||
std::string mimeType; // (required if no uri) ["image/jpeg", "image/png"]
|
||||
std::string uri; // (reqiored if no mimeType)
|
||||
int bufferView; // (required if no uri)
|
||||
std::string mimeType; // (required if no uri) ["image/jpeg", "image/png"]
|
||||
std::string uri; // (reqiored if no mimeType)
|
||||
Value extras;
|
||||
|
||||
Image()
|
||||
{
|
||||
bufferView = -1;
|
||||
}
|
||||
Image() { bufferView = -1; }
|
||||
};
|
||||
|
||||
struct Texture {
|
||||
int sampler;
|
||||
int source; // Required (not specified in the spec ?)
|
||||
int source; // Required (not specified in the spec ?)
|
||||
Value extras;
|
||||
|
||||
Texture()
|
||||
: sampler(-1)
|
||||
, source(-1)
|
||||
{
|
||||
}
|
||||
Texture() : sampler(-1), source(-1) {}
|
||||
};
|
||||
|
||||
// Each extension should be stored in a ParameterMap.
|
||||
@ -383,47 +369,41 @@ struct Texture {
|
||||
struct Material {
|
||||
std::string name;
|
||||
|
||||
ParameterMap values; // PBR metal/roughness workflow
|
||||
ParameterMap additionalValues; // normal/occlusion/emissive values
|
||||
ParameterMap extCommonValues; // KHR_common_material extension
|
||||
ParameterMap values; // PBR metal/roughness workflow
|
||||
ParameterMap additionalValues; // normal/occlusion/emissive values
|
||||
ParameterMap extCommonValues; // KHR_common_material extension
|
||||
ParameterMap extPBRValues;
|
||||
Value extras;
|
||||
};
|
||||
|
||||
struct BufferView{
|
||||
struct BufferView {
|
||||
std::string name;
|
||||
int buffer; // Required
|
||||
size_t byteOffset; // minimum 0, default 0
|
||||
size_t byteLength; // required, minimum 1
|
||||
int buffer; // Required
|
||||
size_t byteOffset; // minimum 0, default 0
|
||||
size_t byteLength; // required, minimum 1
|
||||
size_t byteStride; // minimum 4, maximum 252 (multiple of 4)
|
||||
int target; // ["ARRAY_BUFFER", "ELEMENT_ARRAY_BUFFER"]
|
||||
int target; // ["ARRAY_BUFFER", "ELEMENT_ARRAY_BUFFER"]
|
||||
int pad0;
|
||||
Value extras;
|
||||
|
||||
BufferView()
|
||||
: byteOffset(0)
|
||||
, byteStride(4)
|
||||
{}
|
||||
|
||||
BufferView() : byteOffset(0), byteStride(4) {}
|
||||
};
|
||||
|
||||
struct Accessor {
|
||||
int bufferView; // optional in spec but required here since sparse accessor are not supported
|
||||
int bufferView; // optional in spec but required here since sparse accessor
|
||||
// are not supported
|
||||
std::string name;
|
||||
size_t byteOffset;
|
||||
size_t byteStride;
|
||||
int componentType; // (required) One of TINYGLTF_COMPONENT_TYPE_***
|
||||
size_t count; // required
|
||||
int type; // (required) One of TINYGLTF_TYPE_*** ..
|
||||
size_t count; // required
|
||||
int type; // (required) One of TINYGLTF_TYPE_*** ..
|
||||
Value extras;
|
||||
|
||||
std::vector<double> minValues; // required
|
||||
std::vector<double> maxValues; // required
|
||||
|
||||
Accessor()
|
||||
{
|
||||
bufferView = -1;
|
||||
}
|
||||
Accessor() { bufferView = -1; }
|
||||
};
|
||||
|
||||
class Camera {
|
||||
@ -435,16 +415,16 @@ class Camera {
|
||||
bool isOrthographic; // false = perspective.
|
||||
|
||||
// Orthographic properties
|
||||
float xMag; // required
|
||||
float yMag; // required
|
||||
float zFar; // required
|
||||
float zNear; //required
|
||||
float xMag; // required
|
||||
float yMag; // required
|
||||
float zFar; // required
|
||||
float zNear; // required
|
||||
|
||||
// Perspective properties
|
||||
float aspectRatio;
|
||||
float yfov; // required
|
||||
float yfov; // required
|
||||
float zfar;
|
||||
float znear; // required
|
||||
float znear; // required
|
||||
|
||||
ParameterMap extensions;
|
||||
Value extras;
|
||||
@ -456,16 +436,16 @@ struct Primitive {
|
||||
// is the index of the accessor
|
||||
// containing an attribute.
|
||||
int material; // The index of the material to apply to this primitive
|
||||
// when rendering.
|
||||
// when rendering.
|
||||
int indices; // The index of the accessor that contains the indices.
|
||||
int mode; // one of TINYGLTF_MODE_***
|
||||
std::vector<std::map<std::string, int> > targets; // array of morph targets,
|
||||
//where each target is a dict with attribues in ["POSITION, "NORMAL", "TANGENT"] pointing
|
||||
// to their corresponding accessors
|
||||
std::vector<std::map<std::string, int> > targets; // array of morph targets,
|
||||
// where each target is a dict with attribues in ["POSITION, "NORMAL",
|
||||
// "TANGENT"] pointing
|
||||
// to their corresponding accessors
|
||||
Value extras;
|
||||
|
||||
Primitive()
|
||||
{
|
||||
Primitive() {
|
||||
material = -1;
|
||||
indices = -1;
|
||||
}
|
||||
@ -474,19 +454,15 @@ struct Primitive {
|
||||
typedef struct {
|
||||
std::string name;
|
||||
std::vector<Primitive> primitives;
|
||||
std::vector<double> weights; // weights to be applied to the Morph Targets
|
||||
std::vector<std::map<std::string, int> >targets;
|
||||
std::vector<double> weights; // weights to be applied to the Morph Targets
|
||||
std::vector<std::map<std::string, int> > targets;
|
||||
ParameterMap extensions;
|
||||
Value extras;
|
||||
} Mesh;
|
||||
|
||||
class Node {
|
||||
public:
|
||||
Node()
|
||||
: skin(-1)
|
||||
, mesh(-1)
|
||||
{
|
||||
}
|
||||
Node() : skin(-1), mesh(-1) {}
|
||||
|
||||
~Node() {}
|
||||
|
||||
@ -500,7 +476,7 @@ class Node {
|
||||
std::vector<double> scale; // length must be 0 or 3
|
||||
std::vector<double> translation; // length must be 0 or 3
|
||||
std::vector<double> matrix; // length must be 0 or 16
|
||||
std::vector<double> weights; // The weights of the instantiated Morph Target
|
||||
std::vector<double> weights; // The weights of the instantiated Morph Target
|
||||
|
||||
Value extras;
|
||||
};
|
||||
@ -508,12 +484,13 @@ class Node {
|
||||
typedef struct {
|
||||
std::string name;
|
||||
std::vector<unsigned char> data;
|
||||
std::string uri; // considered as required here but not in the spec (need to clarify)
|
||||
std::string
|
||||
uri; // considered as required here but not in the spec (need to clarify)
|
||||
Value extras;
|
||||
} Buffer;
|
||||
|
||||
typedef struct {
|
||||
std::string version; // required
|
||||
std::string version; // required
|
||||
std::string generator;
|
||||
std::string minVersion;
|
||||
std::string copyright;
|
||||
@ -950,11 +927,15 @@ static bool LoadExternalFile(std::vector<unsigned char> *out, std::string *err,
|
||||
static bool LoadImageData(Image *image, std::string *err, int req_width,
|
||||
int req_height, const unsigned char *bytes,
|
||||
int size) {
|
||||
std::cout << "size " << size << std::endl;
|
||||
|
||||
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)
|
||||
// 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, 0);
|
||||
if (!data) {
|
||||
if (err) {
|
||||
@ -966,7 +947,7 @@ static bool LoadImageData(Image *image, std::string *err, int req_width,
|
||||
if (w < 1 || h < 1) {
|
||||
free(data);
|
||||
if (err) {
|
||||
(*err) += "Unknown image format.\n";
|
||||
(*err) += "Invalid image data.\n";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1147,7 +1128,9 @@ static bool ParseBooleanProperty(bool *ret, std::string *err,
|
||||
|
||||
static bool ParseNumberProperty(double *ret, std::string *err,
|
||||
const picojson::object &o,
|
||||
const std::string &property, const bool required, const std::string &parent_node = "") {
|
||||
const std::string &property,
|
||||
const bool required,
|
||||
const std::string &parent_node = "") {
|
||||
picojson::object::const_iterator it = o.find(property);
|
||||
if (it == o.end()) {
|
||||
if (required) {
|
||||
@ -1180,8 +1163,7 @@ static bool ParseNumberProperty(double *ret, std::string *err,
|
||||
|
||||
static bool ParseNumberArrayProperty(std::vector<double> *ret, std::string *err,
|
||||
const picojson::object &o,
|
||||
const std::string &property,
|
||||
bool required,
|
||||
const std::string &property, bool required,
|
||||
const std::string &parent_node = "") {
|
||||
picojson::object::const_iterator it = o.find(property);
|
||||
if (it == o.end()) {
|
||||
@ -1312,9 +1294,8 @@ static bool ParseStringIntProperty(std::map<std::string, int> *ret,
|
||||
}
|
||||
|
||||
static bool ParseKHRBinaryExtension(const picojson::object &o, std::string *err,
|
||||
double *buffer_view,
|
||||
std::string *mime_type, int *image_width,
|
||||
int *image_height) {
|
||||
double *buffer_view, std::string *mime_type,
|
||||
int *image_width, int *image_height) {
|
||||
picojson::object j = o;
|
||||
|
||||
if (j.find("extensions") == j.end()) {
|
||||
@ -1350,7 +1331,8 @@ static bool ParseKHRBinaryExtension(const picojson::object &o, std::string *err,
|
||||
|
||||
picojson::object k = ext["KHR_binary_glTF"].get<picojson::object>();
|
||||
|
||||
if (!ParseNumberProperty(buffer_view, err, k, "bufferView", true)) {
|
||||
if (!ParseNumberProperty(buffer_view, err, k, "bufferView", true,
|
||||
"KHR_binary_glTF")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1375,23 +1357,20 @@ static bool ParseKHRBinaryExtension(const picojson::object &o, std::string *err,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ParseJSONProperty(std::map<std::string, double> *ret, std::string *err,
|
||||
const picojson::object &o,
|
||||
const std::string &property,
|
||||
bool required)
|
||||
{
|
||||
static bool ParseJSONProperty(std::map<std::string, double> *ret,
|
||||
std::string *err, const picojson::object &o,
|
||||
const std::string &property, bool required) {
|
||||
picojson::object::const_iterator it = o.find(property);
|
||||
if(it == o.end())
|
||||
{
|
||||
if (it == o.end()) {
|
||||
if (required) {
|
||||
if(err) {
|
||||
if (err) {
|
||||
(*err) += "'" + property + "' property is missing. \n'";
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!it->second.is<picojson::object>()) {
|
||||
if (!it->second.is<picojson::object>()) {
|
||||
if (required) {
|
||||
if (err) {
|
||||
(*err) += "'" + property + "' property is not a JSON object.\n";
|
||||
@ -1405,8 +1384,9 @@ static bool ParseJSONProperty(std::map<std::string, double> *ret, std::string *e
|
||||
picojson::object::const_iterator it2(obj.begin());
|
||||
picojson::object::const_iterator itEnd(obj.end());
|
||||
for (; it2 != itEnd; it2++) {
|
||||
if(it2->second.is<double>())
|
||||
ret->insert(std::pair<std::string, double>(it2->first, it2->second.get<double>()));
|
||||
if (it2->second.is<double>())
|
||||
ret->insert(std::pair<std::string, double>(it2->first,
|
||||
it2->second.get<double>()));
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -1430,13 +1410,14 @@ static bool ParseImage(Image *image, std::string *err,
|
||||
size_t bin_size) {
|
||||
// A glTF image must either reference a bufferView or an image uri
|
||||
double bufferView = -1;
|
||||
bool isEmbedded = ParseNumberProperty(&bufferView, err, o, "bufferView", true);
|
||||
isEmbedded = isEmbedded && static_cast<int>(bufferView) != -1;
|
||||
bool isEmbedded =
|
||||
ParseNumberProperty(&bufferView, err, o, "bufferView", false);
|
||||
|
||||
std::string uri;
|
||||
if (!ParseStringProperty(&uri, err, o, "uri", true, "Image") && !isEmbedded) {
|
||||
std::string tmp_err;
|
||||
if (!ParseStringProperty(&uri, &tmp_err, o, "uri", false) && !isEmbedded) {
|
||||
if (err) {
|
||||
(*err) += "Invalid image data (required data is missing).\n";
|
||||
(*err) += "`bufferView` or `uri` required for Image.\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -1649,7 +1630,8 @@ static bool ParseBufferView(BufferView *bufferView, std::string *err,
|
||||
ParseNumberProperty(&byteOffset, err, o, "byteOffset", false);
|
||||
|
||||
double byteLength = 1.0;
|
||||
if(!ParseNumberProperty(&byteLength, err, o, "byteLength", true, "BufferView")) {
|
||||
if (!ParseNumberProperty(&byteLength, err, o, "byteLength", true,
|
||||
"BufferView")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1680,7 +1662,8 @@ static bool ParseBufferView(BufferView *bufferView, std::string *err,
|
||||
static bool ParseAccessor(Accessor *accessor, std::string *err,
|
||||
const picojson::object &o) {
|
||||
double bufferView = -1.0;
|
||||
if (!ParseNumberProperty(&bufferView, err, o, "bufferView", true, "Accessor")) {
|
||||
if (!ParseNumberProperty(&bufferView, err, o, "bufferView", true,
|
||||
"Accessor")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1688,7 +1671,8 @@ static bool ParseAccessor(Accessor *accessor, std::string *err,
|
||||
ParseNumberProperty(&byteOffset, err, o, "byteOffset", false, "Accessor");
|
||||
|
||||
double componentType = 0.0;
|
||||
if (!ParseNumberProperty(&componentType, err, o, "componentType", true, "Accessor")) {
|
||||
if (!ParseNumberProperty(&componentType, err, o, "componentType", true,
|
||||
"Accessor")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1732,11 +1716,13 @@ static bool ParseAccessor(Accessor *accessor, std::string *err,
|
||||
|
||||
accessor->minValues.clear();
|
||||
accessor->maxValues.clear();
|
||||
if(!ParseNumberArrayProperty(&accessor->minValues, err, o, "min", true, "Accessor")) {
|
||||
if (!ParseNumberArrayProperty(&accessor->minValues, err, o, "min", true,
|
||||
"Accessor")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!ParseNumberArrayProperty(&accessor->maxValues, err, o, "max", true, "Accessor")) {
|
||||
if (!ParseNumberArrayProperty(&accessor->maxValues, err, o, "max", true,
|
||||
"Accessor")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1776,7 +1762,7 @@ static bool ParsePrimitive(Primitive *primitive, std::string *err,
|
||||
ParseNumberProperty(&mode, err, o, "mode", false);
|
||||
|
||||
int primMode = static_cast<int>(mode);
|
||||
primitive->mode = primMode; // Why only triangled were supported ?
|
||||
primitive->mode = primMode; // Why only triangled were supported ?
|
||||
|
||||
double indices = -1.0;
|
||||
ParseNumberProperty(&indices, err, o, "indices", false);
|
||||
@ -1811,7 +1797,8 @@ static bool ParseMesh(Mesh *mesh, std::string *err, const picojson::object &o) {
|
||||
|
||||
// Look for morph targets
|
||||
picojson::object::const_iterator targetsObject = o.find("targets");
|
||||
if ((targetsObject != o.end()) && (targetsObject->second).is<picojson::array>()) {
|
||||
if ((targetsObject != o.end()) &&
|
||||
(targetsObject->second).is<picojson::array>()) {
|
||||
const picojson::array &targetArray =
|
||||
(targetsObject->second).get<picojson::array>();
|
||||
for (size_t i = 0; i < targetArray.size(); i++) {
|
||||
@ -1822,7 +1809,8 @@ static bool ParseMesh(Mesh *mesh, std::string *err, const picojson::object &o) {
|
||||
picojson::object::const_iterator dictItEnd(dict.end());
|
||||
|
||||
for (; dictIt != dictItEnd; ++dictIt) {
|
||||
targetAttribues[dictIt->first] = static_cast<int>(dictIt->second.get<double>());
|
||||
targetAttribues[dictIt->first] =
|
||||
static_cast<int>(dictIt->second.get<double>());
|
||||
}
|
||||
mesh->targets.push_back(targetAttribues);
|
||||
}
|
||||
@ -1844,8 +1832,7 @@ static bool ParseNode(Node *node, std::string *err, const picojson::object &o) {
|
||||
node->skin = static_cast<int>(skin);
|
||||
|
||||
// Matrix and T/R/S are exclusive
|
||||
if(!ParseNumberArrayProperty(&node->matrix, err, o, "matrix", false)) {
|
||||
|
||||
if (!ParseNumberArrayProperty(&node->matrix, err, o, "matrix", false)) {
|
||||
ParseNumberArrayProperty(&node->rotation, err, o, "rotation", false);
|
||||
ParseNumberArrayProperty(&node->scale, err, o, "scale", false);
|
||||
ParseNumberArrayProperty(&node->translation, err, o, "translation", false);
|
||||
@ -1872,7 +1859,8 @@ static bool ParseNode(Node *node, std::string *err, const picojson::object &o) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const int &childrenNode = static_cast<int>(childrenArray[i].get<double>());
|
||||
const int &childrenNode =
|
||||
static_cast<int>(childrenArray[i].get<double>());
|
||||
node->children.push_back(childrenNode);
|
||||
}
|
||||
}
|
||||
@ -1902,9 +1890,10 @@ static bool ParseParameterProperty(Parameter *param, std::string *err,
|
||||
} else if (ParseNumberProperty(&num_val, err, o, prop, false)) {
|
||||
param->number_array.push_back(num_val);
|
||||
return true;
|
||||
} else if(ParseJSONProperty(¶m->json_double_value, err, o, prop, false)) {
|
||||
} else if (ParseJSONProperty(¶m->json_double_value, err, o, prop,
|
||||
false)) {
|
||||
return true;
|
||||
} else if(ParseBooleanProperty(¶m->bool_value, err, o, prop, false)) {
|
||||
} else if (ParseBooleanProperty(¶m->bool_value, err, o, prop, false)) {
|
||||
return true;
|
||||
} else {
|
||||
if (required) {
|
||||
@ -1917,8 +1906,7 @@ static bool ParseParameterProperty(Parameter *param, std::string *err,
|
||||
}
|
||||
|
||||
static bool ParseMaterial(Material *material, std::string *err,
|
||||
const picojson::object &o) {
|
||||
|
||||
const picojson::object &o) {
|
||||
material->values.clear();
|
||||
material->extPBRValues.clear();
|
||||
material->additionalValues.clear();
|
||||
@ -1927,8 +1915,7 @@ static bool ParseMaterial(Material *material, std::string *err,
|
||||
picojson::object::const_iterator itEnd(o.end());
|
||||
|
||||
for (; it != itEnd; it++) {
|
||||
if(it->first == "pbrMetallicRoughness")
|
||||
{
|
||||
if (it->first == "pbrMetallicRoughness") {
|
||||
if ((it->second).is<picojson::object>()) {
|
||||
const picojson::object &values_object =
|
||||
(it->second).get<picojson::object>();
|
||||
@ -1944,40 +1931,35 @@ static bool ParseMaterial(Material *material, std::string *err,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(it->first == "extensions")
|
||||
{
|
||||
} else if (it->first == "extensions") {
|
||||
if ((it->second).is<picojson::object>()) {
|
||||
const picojson::object &extension = (it->second).get<picojson::object>();
|
||||
const picojson::object &extension =
|
||||
(it->second).get<picojson::object>();
|
||||
|
||||
picojson::object::const_iterator extIt = extension.begin();
|
||||
if(!extIt->second.is<picojson::object>())
|
||||
continue;
|
||||
picojson::object::const_iterator extIt = extension.begin();
|
||||
if (!extIt->second.is<picojson::object>()) continue;
|
||||
|
||||
const picojson::object &values_object =
|
||||
(extIt->second).get<picojson::object>();
|
||||
const picojson::object &values_object =
|
||||
(extIt->second).get<picojson::object>();
|
||||
|
||||
picojson::object::const_iterator itVal(values_object.begin());
|
||||
picojson::object::const_iterator itValEnd(values_object.end());
|
||||
picojson::object::const_iterator itVal(values_object.begin());
|
||||
picojson::object::const_iterator itValEnd(values_object.end());
|
||||
|
||||
for (; itVal != itValEnd; itVal++) {
|
||||
Parameter param;
|
||||
if (ParseParameterProperty(¶m, err, values_object, itVal->first,
|
||||
false)) {
|
||||
material->extPBRValues[itVal->first] = param;
|
||||
for (; itVal != itValEnd; itVal++) {
|
||||
Parameter param;
|
||||
if (ParseParameterProperty(¶m, err, values_object, itVal->first,
|
||||
false)) {
|
||||
material->extPBRValues[itVal->first] = param;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Parameter param;
|
||||
if (ParseParameterProperty(¶m, err, o, it->first,
|
||||
false)) {
|
||||
material->additionalValues[it->first] = param;
|
||||
}
|
||||
} else {
|
||||
Parameter param;
|
||||
if (ParseParameterProperty(¶m, err, o, it->first, false)) {
|
||||
material->additionalValues[it->first] = param;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ParseExtrasProperty(&(material->extras), o);
|
||||
|
||||
@ -2000,8 +1982,7 @@ static bool ParseAnimationChannel(AnimationChannel *channel, std::string *err,
|
||||
const picojson::object &target_object =
|
||||
(targetIt->second).get<picojson::object>();
|
||||
|
||||
if (!ParseNumberProperty(&targetIndex, err, target_object, "node",
|
||||
true)) {
|
||||
if (!ParseNumberProperty(&targetIndex, err, target_object, "node", true)) {
|
||||
if (err) {
|
||||
(*err) += "`id` field is missing in animation.channels.target\n";
|
||||
}
|
||||
@ -2115,9 +2096,7 @@ static bool ParseSampler(Sampler *sampler, std::string *err,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ParseSkin(Skin *skin, std::string *err,
|
||||
const picojson::object &o) {
|
||||
|
||||
static bool ParseSkin(Skin *skin, std::string *err, const picojson::object &o) {
|
||||
ParseStringProperty(&skin->name, err, o, "name", false, "Skin");
|
||||
|
||||
std::vector<double> joints;
|
||||
@ -2153,9 +2132,9 @@ bool TinyGLTFLoader::LoadFromString(Model *model, std::string *err,
|
||||
}
|
||||
|
||||
// scene is not mandatory.
|
||||
//FIXME Maybe a better way to handle it than removing the code
|
||||
// FIXME Maybe a better way to handle it than removing the code
|
||||
|
||||
if (v.contains("scenes") && v.get("scenes").is<picojson::array>()) {
|
||||
if (v.contains("scenes") && v.get("scenes").is<picojson::array>()) {
|
||||
// OK
|
||||
} else if (check_sections & REQUIRE_SCENES) {
|
||||
if (err) {
|
||||
@ -2191,8 +2170,7 @@ if (v.contains("scenes") && v.get("scenes").is<picojson::array>()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (v.contains("bufferViews") &&
|
||||
v.get("bufferViews").is<picojson::array>()) {
|
||||
if (v.contains("bufferViews") && v.get("bufferViews").is<picojson::array>()) {
|
||||
// OK
|
||||
} else if (check_sections & REQUIRE_BUFFER_VIEWS) {
|
||||
if (err) {
|
||||
@ -2217,10 +2195,11 @@ if (v.contains("scenes") && v.get("scenes").is<picojson::array>()) {
|
||||
}
|
||||
|
||||
// 0. Parse extensionUsed
|
||||
if (v.contains("extensionsUsed") && v.get("extensionsUsed").is<picojson::array>()) {
|
||||
const picojson::array &root = v.get("extensionsUsed").get<picojson::array>();
|
||||
for(unsigned int i=0; i< root.size(); ++i)
|
||||
{
|
||||
if (v.contains("extensionsUsed") &&
|
||||
v.get("extensionsUsed").is<picojson::array>()) {
|
||||
const picojson::array &root =
|
||||
v.get("extensionsUsed").get<picojson::array>();
|
||||
for (unsigned int i = 0; i < root.size(); ++i) {
|
||||
model->extensionsUsed.push_back(root[i].get<std::string>());
|
||||
}
|
||||
}
|
||||
@ -2233,8 +2212,8 @@ if (v.contains("scenes") && v.get("scenes").is<picojson::array>()) {
|
||||
picojson::array::const_iterator itEnd(root.end());
|
||||
for (; it != itEnd; it++) {
|
||||
Buffer buffer;
|
||||
if (!ParseBuffer(&buffer, err, it->get<picojson::object>(),
|
||||
base_dir, is_binary_, bin_data_, bin_size_)) {
|
||||
if (!ParseBuffer(&buffer, err, it->get<picojson::object>(), base_dir,
|
||||
is_binary_, bin_data_, bin_size_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2243,16 +2222,14 @@ if (v.contains("scenes") && v.get("scenes").is<picojson::array>()) {
|
||||
}
|
||||
|
||||
// 2. Parse BufferView
|
||||
if (v.contains("bufferViews") &&
|
||||
v.get("bufferViews").is<picojson::array>()) {
|
||||
if (v.contains("bufferViews") && v.get("bufferViews").is<picojson::array>()) {
|
||||
const picojson::array &root = v.get("bufferViews").get<picojson::array>();
|
||||
|
||||
picojson::array::const_iterator it(root.begin());
|
||||
picojson::array::const_iterator itEnd(root.end());
|
||||
for (; it != itEnd; it++) {
|
||||
BufferView bufferView;
|
||||
if (!ParseBufferView(&bufferView, err,
|
||||
it->get<picojson::object>())) {
|
||||
if (!ParseBufferView(&bufferView, err, it->get<picojson::object>())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2268,8 +2245,7 @@ if (v.contains("scenes") && v.get("scenes").is<picojson::array>()) {
|
||||
picojson::array::const_iterator itEnd(root.end());
|
||||
for (; it != itEnd; it++) {
|
||||
Accessor accessor;
|
||||
if (!ParseAccessor(&accessor, err,
|
||||
it->get<picojson::object>())) {
|
||||
if (!ParseAccessor(&accessor, err, it->get<picojson::object>())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2371,8 +2347,8 @@ if (v.contains("scenes") && v.get("scenes").is<picojson::array>()) {
|
||||
picojson::array::const_iterator itEnd(root.end());
|
||||
for (; it != itEnd; it++) {
|
||||
Image image;
|
||||
if (!ParseImage(&image, err, it->get<picojson::object>(),
|
||||
base_dir, is_binary_, bin_data_, bin_size_)) {
|
||||
if (!ParseImage(&image, err, it->get<picojson::object>(), base_dir,
|
||||
is_binary_, bin_data_, bin_size_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2388,7 +2364,8 @@ if (v.contains("scenes") && v.get("scenes").is<picojson::array>()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const BufferView &bufferView = model->bufferViews[size_t(image.bufferView)];
|
||||
const BufferView &bufferView =
|
||||
model->bufferViews[size_t(image.bufferView)];
|
||||
const Buffer &buffer = model->buffers[size_t(bufferView.buffer)];
|
||||
|
||||
bool ret = LoadImageData(&image, err, image.width, image.height,
|
||||
@ -2411,8 +2388,7 @@ if (v.contains("scenes") && v.get("scenes").is<picojson::array>()) {
|
||||
picojson::array::const_iterator itEnd(root.end());
|
||||
for (; it != itEnd; it++) {
|
||||
Texture texture;
|
||||
if (!ParseTexture(&texture, err, it->get<picojson::object>(),
|
||||
base_dir)) {
|
||||
if (!ParseTexture(&texture, err, it->get<picojson::object>(), base_dir)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2428,8 +2404,7 @@ if (v.contains("scenes") && v.get("scenes").is<picojson::array>()) {
|
||||
picojson::array::const_iterator itEnd(root.end());
|
||||
for (; it != itEnd; ++it) {
|
||||
Animation animation;
|
||||
if (!ParseAnimation(&animation, err,
|
||||
it->get<picojson::object>())) {
|
||||
if (!ParseAnimation(&animation, err, it->get<picojson::object>())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2445,8 +2420,7 @@ if (v.contains("scenes") && v.get("scenes").is<picojson::array>()) {
|
||||
picojson::array::const_iterator itEnd(root.end());
|
||||
for (; it != itEnd; ++it) {
|
||||
Skin skin;
|
||||
if (!ParseSkin(&skin, err,
|
||||
it->get<picojson::object>())) {
|
||||
if (!ParseSkin(&skin, err, it->get<picojson::object>())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user