Remove unused examples.

Refactor source code.
This commit is contained in:
Syoyo Fujita 2017-06-04 17:42:41 +09:00
parent 40c4a0a60a
commit 5b40745f7a
20 changed files with 249 additions and 3122 deletions

View File

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

View File

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

View File

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

View File

@ -1,18 +0,0 @@
# Simple CyHair to glTF converter
![](../../images/cyhair.png)
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`).

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,2 +0,0 @@
all:
$(CXX) -o gltf_writer -I../../ writer.cc

View File

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

View File

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

View File

@ -210,18 +210,20 @@ static std::string PrintParameterValue(const tinygltf::Parameter &param) {
}
}
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

View File

@ -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(&param->json_double_value, err, o, prop, false)) {
} else if (ParseJSONProperty(&param->json_double_value, err, o, prop,
false)) {
return true;
} else if(ParseBooleanProperty(&param->bool_value, err, o, prop, false)) {
} else if (ParseBooleanProperty(&param->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(&param, err, values_object, itVal->first,
false)) {
material->extPBRValues[itVal->first] = param;
for (; itVal != itValEnd; itVal++) {
Parameter param;
if (ParseParameterProperty(&param, err, values_object, itVal->first,
false)) {
material->extPBRValues[itVal->first] = param;
}
}
}
}
else
{
Parameter param;
if (ParseParameterProperty(&param, err, o, it->first,
false)) {
material->additionalValues[it->first] = param;
}
} else {
Parameter param;
if (ParseParameterProperty(&param, 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;
}