diff --git a/examples/alembic_to_gltf/Makefile b/examples/alembic_to_gltf/Makefile deleted file mode 100644 index e7321b2..0000000 --- a/examples/alembic_to_gltf/Makefile +++ /dev/null @@ -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 diff --git a/examples/alembic_to_gltf/README.md b/examples/alembic_to_gltf/README.md deleted file mode 100644 index 4c08da5..0000000 --- a/examples/alembic_to_gltf/README.md +++ /dev/null @@ -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? diff --git a/examples/alembic_to_gltf/abc2gltf.cc b/examples/alembic_to_gltf/abc2gltf.cc deleted file mode 100644 index fc03bac..0000000 --- a/examples/alembic_to_gltf/abc2gltf.cc +++ /dev/null @@ -1,1510 +0,0 @@ -#include -#include -#include - -#include - -#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 - -#include -#include -#include - -#define PICOJSON_USE_INT64 -#include "../../picojson.h" - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -#include "../../tiny_gltf_loader.h" // To import some TINYGLTF_*** macros. - -template -class real3 { - public: - real3() {} - real3(T xx, T yy, T zz) { - v[0] = xx; - v[1] = yy; - v[2] = zz; - } - explicit real3(const T *p) { - v[0] = p[0]; - v[1] = p[1]; - v[2] = p[2]; - } - - inline T x() const { return v[0]; } - inline T y() const { return v[1]; } - inline T z() const { return v[2]; } - - real3 operator*(T f) const { return real3(x() * f, y() * f, z() * f); } - 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 real3 &f2) { - v[0] += f2.x(); - v[1] += f2.y(); - v[2] += f2.z(); - return (*this); - } - real3 operator/(const real3 &f2) const { - return real3(x() / f2.x(), y() / f2.y(), z() / f2.z()); - } - T operator[](int i) const { return v[i]; } - T &operator[](int i) { return v[i]; } - - T v[3]; - // T pad; // for alignment(when T = float) -}; - -template -inline real3 operator*(T f, const real3 &v) { - return real3(v.x() * f, v.y() * f, v.z() * f); -} - -template -inline real3 vneg(const real3 &rhs) { - return real3(-rhs.x(), -rhs.y(), -rhs.z()); -} - -template -inline T vlength(const real3 &rhs) { - return std::sqrt(rhs.x() * rhs.x() + rhs.y() * rhs.y() + rhs.z() * rhs.z()); -} - -template -inline real3 vnormalize(const real3 &rhs) { - real3 v = rhs; - T len = vlength(rhs); - if (std::fabs(len) > 1.0e-6f) { - float inv_len = 1.0f / len; - v.v[0] *= inv_len; - v.v[1] *= inv_len; - v.v[2] *= inv_len; - } - return v; -} - -template -inline real3 vcross(real3 a, real3 b) { - real3 c; - c[0] = a[1] * b[2] - a[2] * b[1]; - c[1] = a[2] * b[0] - a[0] * b[2]; - c[2] = a[0] * b[1] - a[1] * b[0]; - return c; -} - -template -inline T vdot(real3 a, real3 b) { - return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; -} - -typedef real3 float3; - -class Node { - public: - Node() {} - virtual ~Node(); - - Node(const Node &rhs) { - name = rhs.name; - children = rhs.children; - } - - Node &operator=(const Node &rhs) { - name = rhs.name; - children = rhs.children; - - return (*this); - } - - std::string name; - - std::vector children; -}; - -static void CalcNormal(float3 &N, float3 v0, float3 v1, float3 v2) { - float3 v10 = v1 - v0; - float3 v20 = v2 - v0; - - N = vcross(v20, v10); - N = vnormalize(N); -} - -static void ComputeGeometricNormals(std::vector *normals_out, - const unsigned char *data, - const size_t vertex_stride, - const unsigned int *indices, - const size_t num_indices) { - for (size_t i = 0; i < num_indices / 3; i++) { - const unsigned int i0 = indices[3 * i + 0]; - const unsigned int i1 = indices[3 * i + 1]; - const unsigned int i2 = indices[3 * i + 2]; - - const float *p0 = - reinterpret_cast(&data[vertex_stride * i0]); - const float *p1 = - reinterpret_cast(&data[vertex_stride * i1]); - const float *p2 = - reinterpret_cast(&data[vertex_stride * i2]); - - float3 v0(p0[0], p0[1], p0[2]); - float3 v1(p1[0], p1[1], p1[2]); - float3 v2(p2[0], p2[1], p2[2]); - - float3 n; - CalcNormal(n, v0, v1, v2); - // printf("n = %f, %f, %f\n", n[0], n[1], n[2]); - - (*normals_out)[3 * i0 + 0] += n[0]; - (*normals_out)[3 * i0 + 1] += n[1]; - (*normals_out)[3 * i0 + 2] += n[2]; - (*normals_out)[3 * i1 + 0] += n[0]; - (*normals_out)[3 * i1 + 1] += n[1]; - (*normals_out)[3 * i1 + 2] += n[2]; - (*normals_out)[3 * i2 + 0] += n[0]; - (*normals_out)[3 * i2 + 1] += n[1]; - (*normals_out)[3 * i2 + 2] += n[2]; - } - - // normalize - for (size_t i = 0; i < normals_out->size() / 3; i++) { - float3 n((*normals_out)[3 * i + 0], (*normals_out)[3 * i + 1], - (*normals_out)[3 * i + 2]); - n = vnormalize(n); - (*normals_out)[3 * i + 0] = n[0]; - (*normals_out)[3 * i + 1] = n[1]; - (*normals_out)[3 * i + 2] = n[2]; - } -} - -Node::~Node() {} - -class Xform : public Node { - public: - Xform() : Node() { - xform[0] = 1.0; - xform[1] = 0.0; - xform[2] = 0.0; - xform[3] = 0.0; - - xform[4] = 0.0; - xform[5] = 1.0; - xform[6] = 0.0; - xform[7] = 0.0; - - xform[8] = 0.0; - xform[9] = 0.0; - xform[10] = 1.0; - xform[11] = 0.0; - - xform[12] = 0.0; - xform[13] = 0.0; - xform[14] = 0.0; - xform[15] = 1.0; - } - - virtual ~Xform(); - - Xform &operator=(const Xform &rhs) { - if (this != &rhs) { - Node::operator=(rhs); - - for (size_t i = 0; i < 16; i++) { - xform[i] = rhs.xform[i]; - } - } - - return (*this); - } - - double xform[16]; -}; - -Xform::~Xform() {} - -class Mesh : public Node { - public: - Mesh() : Node() {} - virtual ~Mesh(); - - Mesh &operator=(const Mesh &rhs) { - if (this != &rhs) { - Node::operator=(rhs); - - vertices = rhs.vertices; - normals = rhs.normals; - facevarying_normals = rhs.facevarying_normals; - texcoords = rhs.texcoords; - facevarying_texcoords = rhs.facevarying_texcoords; - faces = rhs.faces; - } - - return (*this); - } - - std::vector vertices; - - // Either `normals` or `facevarying_normals` is filled. - std::vector normals; - std::vector facevarying_normals; - - // Either `texcoords` or `facevarying_texcoords` is filled. - std::vector texcoords; - std::vector facevarying_texcoords; - - std::vector faces; -}; - -Mesh::~Mesh() {} - -// Curves are represented as an array of curve. -// i'th curve has nverts[i] points. -// TODO(syoyo) knots, order to support NURBS curve. -class Curves : public Node { - public: - Curves() : Node() {} - virtual ~Curves(); - - Curves &operator=(const Curves &rhs) { - if (this != &rhs) { - Node::operator=(rhs); - - points = rhs.points; - nverts = rhs.nverts; - } - - return (*this); - } - - std::vector points; - std::vector nverts; // # of vertices per strand(curve). -}; - -Curves::~Curves() {} - -// Points represent particle data. -// TODO(syoyo) -class Points : public Node { - public: - Points() : Node() {} - ~Points(); - - Points &operator=(const Points &rhs) { - if (this != &rhs) { - Node::operator=(rhs); - - points = rhs.points; - radiuss = rhs.radiuss; - } - - return (*this); - } - - std::vector points; - std::vector radiuss; -}; - -Points::~Points() {} - -// TODO(Nurbs) - -class Scene { - public: - Scene() : root_node(NULL) {} - ~Scene() { Destroy(); } - - void Destroy() { - delete root_node; - root_node = NULL; - - { - std::map::const_iterator it( - xform_map.begin()); - for (; it != xform_map.end(); it++) { - delete it->second; - } - } - - { - std::map::const_iterator it(mesh_map.begin()); - for (; it != mesh_map.end(); it++) { - delete it->second; - } - } - - { - std::map::const_iterator it( - curves_map.begin()); - for (; it != curves_map.end(); it++) { - delete it->second; - } - } - } - - std::map xform_map; - std::map mesh_map; - std::map curves_map; - // std::map points_map; - - std::map id_map; - - const Node *root_node; - // std::map node_map; -}; - -// ---------------------------------------------------------------- -// 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( - ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4)); - char_array_4[2] = static_cast( - ((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( - ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4)); - char_array_4[2] = static_cast( - ((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 EncodeFloatArray(picojson::array* arr, const std::vector& -// values) { -// for (size_t i = 0; i < values.size(); i++) { -// arr->push_back(picojson::value(values[i])); -// } -// -// return true; -//} -// - -// --------------------------------------------------------------------------- - -static const char *g_sep = ":"; - -static void VisitProperties(std::stringstream &ss, - Alembic::AbcGeom::ICompoundProperty parent, - const std::string &indent); - -template -static void VisitSimpleProperty(std::stringstream &ss, PROP i_prop, - const std::string &indent) { - std::string ptype = "ScalarProperty "; - if (i_prop.isArray()) { - ptype = "ArrayProperty "; - } - - std::string mdstring = "interpretation="; - mdstring += i_prop.getMetaData().get("interpretation"); - - std::stringstream dtype; - dtype << "datatype="; - dtype << i_prop.getDataType(); - - mdstring += g_sep; - - mdstring += dtype.str(); - - ss << indent << " " << ptype << "name=" << i_prop.getName() << g_sep - << mdstring << g_sep << "numsamps=" << i_prop.getNumSamples() << std::endl; -} - -static void VisitCompoundProperty(std::stringstream &ss, - Alembic::Abc::ICompoundProperty i_prop, - const std::string &indent) { - std::string io_indent = indent + " "; - - std::string interp = "schema="; - interp += i_prop.getMetaData().get("schema"); - - ss << io_indent << "CompoundProperty " - << "name=" << i_prop.getName() << g_sep << interp << std::endl; - - VisitProperties(ss, i_prop, io_indent); -} - -void VisitProperties(std::stringstream &ss, - Alembic::AbcGeom::ICompoundProperty parent, - const std::string &indent) { - for (size_t i = 0; i < parent.getNumProperties(); i++) { - const Alembic::Abc::PropertyHeader &header = parent.getPropertyHeader(i); - - if (header.isCompound()) { - VisitCompoundProperty( - ss, Alembic::Abc::ICompoundProperty(parent, header.getName()), - indent); - } else if (header.isScalar()) { - VisitSimpleProperty( - ss, Alembic::Abc::IScalarProperty(parent, header.getName()), indent); - - } else { - assert(header.isArray()); - VisitSimpleProperty( - ss, Alembic::Abc::IArrayProperty(parent, header.getName()), indent); - } - } -} - -static bool BuildFaceSet(std::vector &faces, - Alembic::Abc::P3fArraySamplePtr iP, - Alembic::Abc::Int32ArraySamplePtr iIndices, - Alembic::Abc::Int32ArraySamplePtr iCounts) { - faces.clear(); - - // Get the number of each thing. - size_t numFaces = iCounts->size(); - size_t numIndices = iIndices->size(); - size_t numPoints = iP->size(); - if (numFaces < 1 || numIndices < 1 || numPoints < 1) { - // Invalid. - std::cerr << "Mesh update quitting because bad arrays" - << ", numFaces = " << numFaces << ", numIndices = " << numIndices - << ", numPoints = " << numPoints << std::endl; - return false; - } - - // Make triangles. - size_t faceIndexBegin = 0; - size_t faceIndexEnd = 0; - for (size_t face = 0; face < numFaces; ++face) { - faceIndexBegin = faceIndexEnd; - size_t count = static_cast((*iCounts)[face]); - faceIndexEnd = faceIndexBegin + count; - - // Check this face is valid - if (faceIndexEnd > numIndices || faceIndexEnd < faceIndexBegin) { - std::cerr << "Mesh update quitting on face: " << face - << " because of wonky numbers" - << ", faceIndexBegin = " << faceIndexBegin - << ", faceIndexEnd = " << faceIndexEnd - << ", numIndices = " << numIndices << ", count = " << count - << std::endl; - - // Just get out, make no more triangles. - break; - } - - // Checking indices are valid. - bool goodFace = true; - for (size_t fidx = faceIndexBegin; fidx < faceIndexEnd; ++fidx) { - if (static_cast(((*iIndices)[fidx])) >= numPoints) { - std::cout << "Mesh update quitting on face: " << face - << " because of bad indices" - << ", indexIndex = " << fidx - << ", vertexIndex = " << (*iIndices)[fidx] - << ", numPoints = " << numPoints << std::endl; - goodFace = false; - break; - } - } - - // Make triangles to fill this face. - if (goodFace && count > 2) { - faces.push_back( - static_cast((*iIndices)[faceIndexBegin + 0])); - faces.push_back( - static_cast((*iIndices)[faceIndexBegin + 1])); - faces.push_back( - static_cast((*iIndices)[faceIndexBegin + 2])); - - for (size_t c = 3; c < count; ++c) { - faces.push_back( - static_cast((*iIndices)[faceIndexBegin + 0])); - faces.push_back( - static_cast((*iIndices)[faceIndexBegin + c - 1])); - faces.push_back( - static_cast((*iIndices)[faceIndexBegin + c])); - } - } - } - - return true; -} - -static void readPolyNormals(std::vector *normals, - std::vector *facevarying_normals, - Alembic::AbcGeom::IN3fGeomParam normals_param) { - normals->clear(); - facevarying_normals->clear(); - - if (!normals_param) { - return; - } - - if ((normals_param.getScope() != Alembic::AbcGeom::kVertexScope) && - (normals_param.getScope() != Alembic::AbcGeom::kVaryingScope) && - (normals_param.getScope() != Alembic::AbcGeom::kFacevaryingScope)) { - std::cout << "Normal vector has an unsupported scope" << std::endl; - return; - } - - if (normals_param.getScope() == Alembic::AbcGeom::kVertexScope) { - std::cout << "Normal: VertexScope" << std::endl; - } else if (normals_param.getScope() == Alembic::AbcGeom::kVaryingScope) { - std::cout << "Normal: VaryingScope" << std::endl; - } else if (normals_param.getScope() == Alembic::AbcGeom::kFacevaryingScope) { - std::cout << "Normal: FacevaryingScope" << std::endl; - } - - // @todo { lerp normal among time sample.} - Alembic::AbcGeom::IN3fGeomParam::Sample samp; - Alembic::AbcGeom::ISampleSelector samplesel( - 0.0, Alembic::AbcGeom::ISampleSelector::kNearIndex); - normals_param.getExpanded(samp, samplesel); - - Alembic::Abc::N3fArraySamplePtr P = samp.getVals(); - size_t sample_size = P->size(); - - if (normals_param.getScope() == Alembic::AbcGeom::kFacevaryingScope) { - for (size_t i = 0; i < sample_size; i++) { - facevarying_normals->push_back((*P)[i].x); - facevarying_normals->push_back((*P)[i].y); - facevarying_normals->push_back((*P)[i].z); - } - } else { - for (size_t i = 0; i < sample_size; i++) { - normals->push_back((*P)[i].x); - normals->push_back((*P)[i].y); - normals->push_back((*P)[i].z); - } - } -} - -// @todo { Support multiple UVset. } -static void readPolyUVs(std::vector *uvs, - std::vector *facevarying_uvs, - Alembic::AbcGeom::IV2fGeomParam uvs_param) { - uvs->clear(); - facevarying_uvs->clear(); - - if (!uvs_param) { - return; - } - - if (uvs_param.getNumSamples() > 0) { - std::string uv_set_name = - Alembic::Abc::GetSourceName(uvs_param.getMetaData()); - std::cout << "UVset : " << uv_set_name << std::endl; - } - - if (uvs_param.isConstant()) { - std::cout << "UV is constant" << std::endl; - } - - if (uvs_param.getScope() == Alembic::AbcGeom::kVertexScope) { - std::cout << "UV: VertexScope" << std::endl; - } else if (uvs_param.getScope() == Alembic::AbcGeom::kVaryingScope) { - std::cout << "UV: VaryingScope" << std::endl; - } else if (uvs_param.getScope() == Alembic::AbcGeom::kFacevaryingScope) { - std::cout << "UV: FacevaryingScope" << std::endl; - } - - // @todo { lerp normal among time sample.} - Alembic::AbcGeom::IV2fGeomParam::Sample samp; - Alembic::AbcGeom::ISampleSelector samplesel( - 0.0, Alembic::AbcGeom::ISampleSelector::kNearIndex); - uvs_param.getIndexed(samp, samplesel); - - Alembic::Abc::V2fArraySamplePtr P = samp.getVals(); - size_t sample_size = P->size(); - - if (uvs_param.getScope() == Alembic::AbcGeom::kFacevaryingScope) { - for (size_t i = 0; i < sample_size; i++) { - facevarying_uvs->push_back((*P)[i].x); - facevarying_uvs->push_back((*P)[i].y); - } - } else { - for (size_t i = 0; i < sample_size; i++) { - uvs->push_back((*P)[i].x); - uvs->push_back((*P)[i].y); - } - } -} - -// Traverse Alembic object tree and extract data. -static void VisitObjectAndExtractNode(Node *node_out, std::stringstream &ss, - const Alembic::AbcGeom::IObject &obj, - const std::string &indent) { - std::string path = obj.getFullName(); - node_out->name = path; - - if (path.compare("/") != 0) { - ss << "Object: path = " << path << std::endl; - } - - Alembic::AbcGeom::ICompoundProperty props = obj.getProperties(); - VisitProperties(ss, props, indent); - - ss << "# of children = " << obj.getNumChildren() << std::endl; - - for (size_t i = 0; i < obj.getNumChildren(); i++) { - const Alembic::AbcGeom::ObjectHeader &header = obj.getChildHeader(i); - ss << " Child: header = " << header.getName() << std::endl; - - Alembic::AbcGeom::ICompoundProperty cprops = - obj.getChild(i).getProperties(); - VisitProperties(ss, props, indent); - - Node *node = NULL; - - if (Alembic::AbcGeom::IXform::matches(header)) { - ss << " IXform" << std::endl; - - Alembic::AbcGeom::IXform xform(obj, header.getName()); - - if (xform.getSchema().isConstant()) { - Alembic::AbcGeom::M44d static_matrix = - xform.getSchema().getValue().getMatrix(); - ss << "IXform static: " << header.getName() << ", " << static_matrix - << std::endl; - - Xform *xform_node = new Xform(); - xform_node->name = header.getName(); - xform_node->xform[0] = static_matrix[0][0]; - xform_node->xform[1] = static_matrix[0][1]; - xform_node->xform[2] = static_matrix[0][2]; - xform_node->xform[3] = static_matrix[0][3]; - xform_node->xform[4] = static_matrix[1][0]; - xform_node->xform[5] = static_matrix[1][1]; - xform_node->xform[6] = static_matrix[1][2]; - xform_node->xform[7] = static_matrix[1][3]; - xform_node->xform[8] = static_matrix[2][0]; - xform_node->xform[9] = static_matrix[2][1]; - xform_node->xform[10] = static_matrix[2][2]; - xform_node->xform[11] = static_matrix[2][3]; - xform_node->xform[12] = static_matrix[3][0]; - xform_node->xform[13] = static_matrix[3][1]; - xform_node->xform[14] = static_matrix[3][2]; - xform_node->xform[15] = static_matrix[3][3]; - - node = xform_node; - - } else { - Alembic::AbcGeom::ISampleSelector samplesel( - 0.0, Alembic::AbcGeom::ISampleSelector::kNearIndex); - Alembic::AbcGeom::IXformSchema &ps = xform.getSchema(); - Alembic::AbcGeom::M44d matrix = ps.getValue(samplesel).getMatrix(); - ss << matrix << std::endl; - } - - ss << " Child: xform" << std::endl; - } else if (Alembic::AbcGeom::IPolyMesh::matches(header)) { - ss << " IPolyMesh" << std::endl; - - // Polygon - Alembic::AbcGeom::IPolyMesh pmesh(obj, header.getName()); - - Alembic::AbcGeom::ISampleSelector samplesel( - 0.0, Alembic::AbcGeom::ISampleSelector::kNearIndex); - Alembic::AbcGeom::IPolyMeshSchema::Sample psample; - Alembic::AbcGeom::IPolyMeshSchema &ps = pmesh.getSchema(); - - std::cout << " # of samples = " << ps.getNumSamples() << std::endl; - - if (ps.getNumSamples() > 0) { - Mesh *mesh = new Mesh(); - ps.get(psample, samplesel); - Alembic::Abc::P3fArraySamplePtr P = psample.getPositions(); - std::cout << " # of positions = " << P->size() << std::endl; - std::cout << " # of face counts = " << psample.getFaceCounts()->size() - << std::endl; - - std::vector faces; // temp - bool ret = BuildFaceSet(faces, P, psample.getFaceIndices(), - psample.getFaceCounts()); - if (!ret) { - std::cout << " No faces in polymesh" << std::endl; - } - - mesh->vertices.resize(3 * P->size()); - memcpy(mesh->vertices.data(), P->get(), sizeof(float) * 3 * P->size()); - mesh->faces = faces; - - // normals - Alembic::AbcGeom::IN3fGeomParam normals_param = ps.getNormalsParam(); - std::vector normals; - std::vector facevarying_normals; - readPolyNormals(&normals, &facevarying_normals, normals_param); - std::cout << " # of normals = " << (normals.size() / 3) << std::endl; - std::cout << " # of facevarying normals = " - << (facevarying_normals.size() / 3) << std::endl; - - // TODO(syoyo): Do not generate normals when `facevarying_normals' - // exists. - if (normals.empty() && (!mesh->vertices.empty()) && - (!mesh->faces.empty())) { - // Compute geometric normal. - normals.resize(3 * P->size(), 0.0f); - std::cout << "Compute normals" << std::endl; - ComputeGeometricNormals( - &normals, reinterpret_cast(P->get()), - /* stride */ sizeof(float) * 3, &mesh->faces.at(0), - mesh->faces.size()); - } - - mesh->normals = normals; - - // UV - Alembic::AbcGeom::IV2fGeomParam uvs_param = ps.getUVsParam(); - std::vector uvs; - std::vector facevarying_uvs; - readPolyUVs(&uvs, &facevarying_uvs, uvs_param); - std::cout << " # of uvs = " << (uvs.size() / 2) << std::endl; - std::cout << " # of facevarying_uvs = " - << (facevarying_uvs.size() / 2) << std::endl; - mesh->texcoords = uvs; - mesh->facevarying_texcoords = facevarying_uvs; - - node = mesh; - - } else { - std::cout << "Warning: # of samples = 0" << std::endl; - } - } else if (Alembic::AbcGeom::ICurves::matches(header)) { - ss << " ICurves" << std::endl; - - // Curves - Alembic::AbcGeom::ICurves curve(obj, header.getName()); - - Alembic::AbcGeom::ISampleSelector samplesel( - 0.0, Alembic::AbcGeom::ISampleSelector::kNearIndex); - Alembic::AbcGeom::ICurvesSchema::Sample psample; - Alembic::AbcGeom::ICurvesSchema &ps = curve.getSchema(); - - std::cout << "Curve: # of samples = " << ps.getNumSamples() << std::endl; - - if (ps.getNumSamples() > 0) { - ps.get(psample, samplesel); - - const size_t num_curves = psample.getNumCurves(); - std::cout << " # of curves = " << num_curves << std::endl; - - if (num_curves > 0) { - Curves *curves = new Curves(); - - Alembic::Abc::P3fArraySamplePtr P = psample.getPositions(); - Alembic::Abc::FloatArraySamplePtr knots = psample.getKnots(); - Alembic::Abc::UcharArraySamplePtr orders = psample.getOrders(); - - Alembic::Abc::Int32ArraySamplePtr num_vertices = - psample.getCurvesNumVertices(); - - if (knots) std::cout << " # of knots= " << knots->size() << std::endl; - if (orders) - std::cout << " # of orders= " << orders->size() << std::endl; - std::cout << " # of nvs= " << num_vertices->size() << std::endl; - - curves->points.resize(3 * P->size()); - memcpy(curves->points.data(), P->get(), sizeof(float) * 3 * P->size()); - -#if 0 - for (size_t k = 0; k < P->size(); k++) { - std::cout << "P[" << k << "] " << (*P)[k].x << ", " << (*P)[k].y << ", " << (*P)[k].z << std::endl; - } - - if (knots) { - for (size_t k = 0; k < knots->size(); k++) { - std::cout << "knots[" << k << "] " << (*knots)[k] << std::endl; - } - } - - if (orders) { - for (size_t k = 0; k < orders->size(); k++) { - std::cout << "orders[" << k << "] " << (*orders)[k] << std::endl; - } - } - - for (size_t k = 0; k < num_vertices->size(); k++) { - std::cout << "nv[" << k << "] " << (*num_vertices)[k] << std::endl; - } -#endif - - if (num_vertices) { - curves->nverts.resize(num_vertices->size()); - memcpy(curves->nverts.data(), num_vertices->get(), - sizeof(int) * num_vertices->size()); - } - - node = curves; - } - - } else { - std::cout << "Warning: # of samples = 0" << std::endl; - } - - } else if (Alembic::AbcGeom::IFaceSet::matches(header)) { - ss << " IFaceSet" << std::endl; - } else { - ss << " TODO" << std::endl; - } - - if (node) { - // Visit child. - VisitObjectAndExtractNode( - node, ss, - Alembic::AbcGeom::IObject(obj, obj.getChildHeader(i).getName()), - indent); - } - - node_out->children.push_back(node); - } -} - -static bool ConvertNodeToGLTF(picojson::object *root_out, const Scene &scene, - const Node *node) { - assert(node); - assert(!node->name.empty()); - - // FIXME(syoyo): Add serialization method for each class. - if (dynamic_cast(node)) { - const Xform *xform = dynamic_cast(node); - - std::cout << "root xform" << node->name << std::endl; - - picojson::object json_node; - picojson::array json_xform; - picojson::array json_meshes; - for (size_t i = 0; i < 16; i++) { - json_xform.push_back(picojson::value(xform->xform[i])); - } - json_node["matrix"] = picojson::value(json_xform); - json_node["name"] = picojson::value(xform->name); - - if (xform->children.size() > 0) { - for (size_t i = 0; i < xform->children.size(); i++) { - if (dynamic_cast(xform->children[i])) { - std::map::const_iterator it = - scene.id_map.find(xform->children[i]->name); - assert(it != scene.id_map.end()); - std::stringstream ss; - ss << "_" << it->second; - const std::string prefix = ss.str(); - - json_meshes.push_back(picojson::value(std::string("mesh") + prefix)); - } else if (dynamic_cast(xform->children[i])) { - std::map::const_iterator it = - scene.id_map.find(xform->children[i]->name); - assert(it != scene.id_map.end()); - std::stringstream ss; - ss << "_" << it->second; - const std::string prefix = ss.str(); - - json_meshes.push_back(picojson::value(std::string("mesh") + prefix)); - } - } - if (json_meshes.size() > 0) { - json_node["meshes"] = picojson::value(json_meshes); - } - } - - picojson::array json_children; - if (xform->children.size() > 0) { - for (size_t i = 0; i < xform->children.size(); i++) { - if (xform->children[i]) { - picojson::object json_child_node; - bool ret = ConvertNodeToGLTF(root_out, scene, xform->children[i]); - if (ret) { - assert(!(xform->children[i]->name.empty())); - json_children.push_back(picojson::value(xform->children[i]->name)); - } - } - } - - if (!json_children.empty()) { - json_node["children"] = picojson::value(json_children); - } - } - - (*root_out)[node->name] = picojson::value(json_node); - } else { - return false; - } - - return true; -} - -static bool ConvertSceneToGLTF(picojson::object *out, const Scene &scene) { - assert(scene.root_node); - - // Nodes - picojson::object nodes; - picojson::array node_names; - { - // picojson::object node; - - ConvertNodeToGLTF(&nodes, scene, scene.root_node); - - // nodes[scene.root_node->name] = picojson::value(node); - node_names.push_back(picojson::value(scene.root_node->name)); - } - (*out)["nodes"] = picojson::value(nodes); - - picojson::object scenes; - picojson::object defaultScene; - defaultScene["nodes"] = picojson::value(node_names); - scenes["defaultScene"] = picojson::value(defaultScene); - - (*out)["scene"] = picojson::value("defaultScene"); - - (*out)["scenes"] = picojson::value(scenes); - - // @todo {} - picojson::object shaders; - picojson::object programs; - picojson::object techniques; - picojson::object materials; - picojson::object skins; - (*out)["shaders"] = picojson::value(shaders); - (*out)["programs"] = picojson::value(programs); - (*out)["techniques"] = picojson::value(techniques); - (*out)["materials"] = picojson::value(materials); - (*out)["skins"] = picojson::value(skins); - - return true; -} - -static bool ConvertMeshToGLTF(picojson::object *buffers_out, - picojson::object *buffer_views_out, - picojson::object *meshes_out, - picojson::object *accessors_out, const Mesh &mesh, - const int id) { - std::stringstream prefix_ss; - prefix_ss << "_" << id; - - const std::string prefix = prefix_ss.str(); - - { - // Position - { - std::string vertices_b64data = base64_encode( - reinterpret_cast(mesh.vertices.data()), - mesh.vertices.size() * sizeof(float)); - picojson::object buf; - - buf["type"] = picojson::value("arraybuffer"); - buf["uri"] = - picojson::value(std::string("data:application/octet-stream;base64,") + - vertices_b64data); - buf["byteLength"] = picojson::value( - static_cast(mesh.vertices.size() * sizeof(float))); - - (*buffers_out)["vertices" + prefix] = picojson::value(buf); - } - - // Normal - if (!mesh.normals.empty()) { - std::string normals_b64data = base64_encode( - reinterpret_cast(mesh.normals.data()), - mesh.normals.size() * sizeof(float)); - picojson::object buf; - - buf["type"] = picojson::value("arraybuffer"); - buf["uri"] = - picojson::value(std::string("data:application/octet-stream;base64,") + - normals_b64data); - buf["byteLength"] = picojson::value( - static_cast(mesh.normals.size() * sizeof(float))); - - (*buffers_out)["normals" + prefix] = picojson::value(buf); - } - - { - std::string faces_b64data = base64_encode( - reinterpret_cast(mesh.faces.data()), - mesh.faces.size() * sizeof(unsigned int)); - picojson::object buf; - - buf["type"] = picojson::value("arraybuffer"); - buf["uri"] = picojson::value( - std::string("data:application/octet-stream;base64,") + faces_b64data); - buf["byteLength"] = picojson::value( - static_cast(mesh.faces.size() * sizeof(unsigned int))); - - (*buffers_out)["indices" + prefix] = picojson::value(buf); - } - } - - { - { - picojson::object buffer_view_vertices; - buffer_view_vertices["buffer"] = - picojson::value(std::string("vertices") + prefix); - buffer_view_vertices["byteLength"] = picojson::value( - static_cast(mesh.vertices.size() * sizeof(float))); - buffer_view_vertices["byteOffset"] = - picojson::value(static_cast(0)); - buffer_view_vertices["target"] = - picojson::value(static_cast(TINYGLTF_TARGET_ARRAY_BUFFER)); - - (*buffer_views_out)["bufferView_vertices" + prefix] = - picojson::value(buffer_view_vertices); - } - - if (!mesh.normals.empty()) { - picojson::object buffer_view_normals; - buffer_view_normals["buffer"] = - picojson::value(std::string("normals") + prefix); - buffer_view_normals["byteLength"] = picojson::value( - static_cast(mesh.normals.size() * sizeof(float))); - buffer_view_normals["byteOffset"] = - picojson::value(static_cast(0)); - buffer_view_normals["target"] = - picojson::value(static_cast(TINYGLTF_TARGET_ARRAY_BUFFER)); - - (*buffer_views_out)["bufferView_normals" + prefix] = - picojson::value(buffer_view_normals); - } - - { - picojson::object buffer_view_indices; - buffer_view_indices["buffer"] = - picojson::value(std::string("indices") + prefix); - buffer_view_indices["byteLength"] = picojson::value( - static_cast(mesh.faces.size() * sizeof(unsigned int))); - buffer_view_indices["byteOffset"] = - picojson::value(static_cast(0)); - buffer_view_indices["target"] = picojson::value( - static_cast(TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER)); - - (*buffer_views_out)["bufferView_indices" + prefix] = - picojson::value(buffer_view_indices); - } - } - - { - picojson::object attributes; - - attributes["POSITION"] = - picojson::value(std::string("accessor_vertices") + prefix); - if (!mesh.normals.empty()) { - attributes["NORMAL"] = - picojson::value(std::string("accessor_normals") + prefix); - } - - picojson::object primitive; - primitive["attributes"] = picojson::value(attributes); - primitive["indices"] = picojson::value("accessor_indices" + prefix); - primitive["material"] = - picojson::value("material_1"); // FIXME(syoyo): Assign material. - primitive["mode"] = - picojson::value(static_cast(TINYGLTF_MODE_TRIANGLES)); - - picojson::array primitive_array; - primitive_array.push_back(picojson::value(primitive)); - - picojson::object m; - m["name"] = picojson::value(mesh.name); - m["primitives"] = picojson::value(primitive_array); - - picojson::object meshes; - (*meshes_out)["mesh" + prefix] = picojson::value(m); - } - - { - picojson::object accessors; - - { - picojson::object accessor_vertices; - accessor_vertices["bufferView"] = - picojson::value(std::string("bufferView_vertices" + prefix)); - accessor_vertices["byteOffset"] = - picojson::value(static_cast(0)); - accessor_vertices["byteStride"] = - picojson::value(static_cast(3 * sizeof(float))); - accessor_vertices["componentType"] = - picojson::value(static_cast(TINYGLTF_COMPONENT_TYPE_FLOAT)); - accessor_vertices["count"] = - picojson::value(static_cast(mesh.vertices.size())); - accessor_vertices["type"] = picojson::value(std::string("VEC3")); - (*accessors_out)["accessor_vertices" + prefix] = - picojson::value(accessor_vertices); - } - - if (!mesh.normals.empty()) { - picojson::object accessor_normals; - accessor_normals["bufferView"] = - picojson::value(std::string("bufferView_normals" + prefix)); - accessor_normals["byteOffset"] = picojson::value(static_cast(0)); - accessor_normals["byteStride"] = - picojson::value(static_cast(3 * sizeof(float))); - accessor_normals["componentType"] = - picojson::value(static_cast(TINYGLTF_COMPONENT_TYPE_FLOAT)); - accessor_normals["count"] = - picojson::value(static_cast(mesh.vertices.size())); - accessor_normals["type"] = picojson::value(std::string("VEC3")); - (*accessors_out)["accessor_normals" + prefix] = - picojson::value(accessor_normals); - } - - { - picojson::object accessor_indices; - accessor_indices["bufferView"] = - picojson::value(std::string("bufferView_indices" + prefix)); - accessor_indices["byteOffset"] = picojson::value(static_cast(0)); - accessor_indices["componentType"] = picojson::value( - static_cast(TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT)); - accessor_indices["count"] = - picojson::value(static_cast(mesh.faces.size())); - accessor_indices["type"] = picojson::value(std::string("SCALAR")); - (*accessors_out)["accessor_indices" + prefix] = - picojson::value(accessor_indices); - } - } - - return true; -} - -static bool ConvertCurvesToGLTF(picojson::object *buffers_out, - picojson::object *buffer_views_out, - picojson::object *meshes_out, - picojson::object *accessors_out, - const Curves &curves, const int id) { - std::stringstream prefix_ss; - prefix_ss << "_" << id; - - const std::string prefix = prefix_ss.str(); - - {{{std::string b64data = base64_encode( - reinterpret_cast(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(curves.points.size() * sizeof(float))); - - (*buffers_out)["points" + prefix] = picojson::value(buf); -} - -// Out extension -{ - std::string b64data = base64_encode( - reinterpret_cast(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(curves.nverts.size() * sizeof(int))); - - (*buffers_out)["nverts" + prefix] = picojson::value(buf); -} -} -} - -{{{picojson::object buffer_view_points; -buffer_view_points["buffer"] = picojson::value(std::string("points") + prefix); -buffer_view_points["byteLength"] = - picojson::value(static_cast(curves.points.size() * sizeof(float))); -buffer_view_points["byteOffset"] = picojson::value(static_cast(0)); -buffer_view_points["target"] = - picojson::value(static_cast(TINYGLTF_TARGET_ARRAY_BUFFER)); -(*buffer_views_out)["bufferView_points" + prefix] = - picojson::value(buffer_view_points); -} - -{ - picojson::object buffer_view_nverts; - buffer_view_nverts["buffer"] = - picojson::value(std::string("nverts") + prefix); - buffer_view_nverts["byteLength"] = - picojson::value(static_cast(curves.nverts.size() * sizeof(int))); - buffer_view_nverts["byteOffset"] = picojson::value(static_cast(0)); - buffer_view_nverts["target"] = - picojson::value(static_cast(TINYGLTF_TARGET_ARRAY_BUFFER)); - (*buffer_views_out)["bufferView_nverts" + prefix] = - picojson::value(buffer_view_nverts); -} -} -} - -{ - picojson::object attributes; - - attributes["POSITION"] = - picojson::value(std::string("accessor_points") + prefix); - attributes["NVERTS"] = - picojson::value(std::string("accessor_nverts") + prefix); - - // 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( - 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["name"] = picojson::value(curves.name); - m["primitives"] = picojson::value(primitive_array); - - picojson::object meshes; - (*meshes_out)["mesh" + prefix] = picojson::value(m); -} - -{ - { - picojson::object accessor_points; - accessor_points["bufferView"] = - picojson::value(std::string("bufferView_points") + prefix); - accessor_points["byteOffset"] = picojson::value(static_cast(0)); - accessor_points["byteStride"] = - picojson::value(static_cast(3 * sizeof(float))); - accessor_points["componentType"] = - picojson::value(static_cast(TINYGLTF_COMPONENT_TYPE_FLOAT)); - accessor_points["count"] = - picojson::value(static_cast(curves.points.size())); - accessor_points["type"] = picojson::value(std::string("VEC3")); - (*accessors_out)["accessor_points" + prefix] = - picojson::value(accessor_points); - } - - { - picojson::object accessor_nverts; - accessor_nverts["bufferView"] = - picojson::value(std::string("bufferView_nverts") + prefix); - accessor_nverts["byteOffset"] = picojson::value(static_cast(0)); - accessor_nverts["byteStride"] = - picojson::value(static_cast(sizeof(int))); - accessor_nverts["componentType"] = - picojson::value(static_cast(TINYGLTF_COMPONENT_TYPE_INT)); - accessor_nverts["count"] = - picojson::value(static_cast(curves.nverts.size())); - accessor_nverts["type"] = picojson::value(std::string("SCALAR")); - (*accessors_out)["accessor_nverts" + prefix] = - picojson::value(accessor_nverts); - } -} - -return true; -} - -static bool SaveSceneToGLTF(const std::string &output_filename, - const Scene &scene) { - picojson::object root; - - ConvertSceneToGLTF(&root, scene); - - // Write header. - { - picojson::object asset; - asset["generator"] = picojson::value("abc2gltf"); - asset["premultipliedAlpha"] = picojson::value(true); - asset["version"] = picojson::value(static_cast(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; - picojson::object buffer_views; - picojson::object meshes; - picojson::object accessors; - - // PolyMesh - std::map::const_iterator mesh_it( - scene.mesh_map.begin()); - for (; mesh_it != scene.mesh_map.end(); mesh_it++) { - const Mesh &mesh = *(mesh_it->second); - - assert(scene.id_map.find(mesh.name) != scene.id_map.end()); - - const int id = (scene.id_map.find(mesh.name))->second; - - bool ret = ConvertMeshToGLTF(&buffers, &buffer_views, &meshes, &accessors, - mesh, id); - assert(ret); - (void)ret; - } - - // Curves - std::map::const_iterator curves_it( - scene.curves_map.begin()); - for (; curves_it != scene.curves_map.end(); curves_it++) { - const Curves &curves = *(curves_it->second); - - assert(scene.id_map.find(curves_it->first) != scene.id_map.end()); - - const int id = (scene.id_map.find(curves.name))->second; - - std::cout << "Curves: " << curves.name << std::endl; - bool ret = ConvertCurvesToGLTF(&buffers, &buffer_views, &meshes, &accessors, - curves, id); - assert(ret); - (void)ret; - } - - root["buffers"] = picojson::value(buffers); - root["bufferViews"] = picojson::value(buffer_views); - root["meshes"] = picojson::value(meshes); - 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); - } - - 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(s.size())); - ifs.close(); - - return true; -} - -// Flatten node tree. -// Also assign ID for each graphics primitive. -static void ConvertNodeToScene(Scene *scene, int *id, const Node *node) { - if (!node) return; - - std::cout << "node " << node->name << std::endl; - - if (dynamic_cast(node)) { - // Allow only one root node in the scene. - if (scene->root_node == NULL) { - scene->root_node = node; - } else { - // Assume child xform node - assert(scene->xform_map.find(node->name) == scene->xform_map.end()); - scene->xform_map[node->name] = dynamic_cast(node); - // scene->id_map[node->name] = (*id)++; - } - - } else if (dynamic_cast(node)) { - assert(scene->mesh_map.find(node->name) == scene->mesh_map.end()); - scene->mesh_map[node->name] = dynamic_cast(node); - scene->id_map[node->name] = (*id)++; - } else if (dynamic_cast(node)) { - assert(scene->curves_map.find(node->name) == scene->curves_map.end()); - scene->curves_map[node->name] = dynamic_cast(node); - scene->id_map[node->name] = (*id)++; - } - - for (size_t i = 0; i < node->children.size(); i++) { - ConvertNodeToScene(scene, id, node->children[i]); - } -} - -int main(int argc, char **argv) { - std::string abc_filename; - std::string gltf_filename; - - if (argc < 3) { - std::cerr << "Usage: gltf2abc input.abc output.gltf" << std::endl; - return EXIT_FAILURE; - } - - abc_filename = std::string(argv[1]); - gltf_filename = std::string(argv[2]); - - Alembic::AbcCoreFactory::IFactory factory; - Alembic::AbcGeom::IArchive archive = factory.getArchive(abc_filename); - - Alembic::AbcGeom::IObject root = archive.getTop(); - - std::cout << "# of children " << root.getNumChildren() << std::endl; - - Scene scene; - std::stringstream ss; - Node *node = new Node(); - VisitObjectAndExtractNode(node, ss, root, /* indent */ " "); - - // std::cout << ss.str() << std::endl; - - int id = 1; // ID starts from 1. - ConvertNodeToScene(&scene, &id, node); - delete node; - - SaveSceneToGLTF(gltf_filename, scene); - - return EXIT_SUCCESS; -} diff --git a/examples/alembic_to_gltf/suzanne.abc b/examples/alembic_to_gltf/suzanne.abc deleted file mode 100644 index 1825f76..0000000 Binary files a/examples/alembic_to_gltf/suzanne.abc and /dev/null differ diff --git a/examples/cyhair_to_gltf/Makefile b/examples/cyhair_to_gltf/Makefile deleted file mode 100644 index 1ee69b2..0000000 --- a/examples/cyhair_to_gltf/Makefile +++ /dev/null @@ -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 - diff --git a/examples/cyhair_to_gltf/README.md b/examples/cyhair_to_gltf/README.md deleted file mode 100644 index 947e3ae..0000000 --- a/examples/cyhair_to_gltf/README.md +++ /dev/null @@ -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`). - diff --git a/examples/cyhair_to_gltf/cyhair2gltf.cc b/examples/cyhair_to_gltf/cyhair2gltf.cc deleted file mode 100644 index 668b1b0..0000000 --- a/examples/cyhair_to_gltf/cyhair2gltf.cc +++ /dev/null @@ -1,352 +0,0 @@ -#include -#include -#include - -#include - -#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 points; - std::vector 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( - ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4)); - char_array_4[2] = static_cast( - ((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( - ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4)); - char_array_4[2] = static_cast( - ((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(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(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(curves.points.size() * sizeof(float))); - - buffers["points"] = picojson::value(buf); - } - - // Out extension - { - std::string b64data = base64_encode(reinterpret_cast(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(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(curves.points.size() * sizeof(float))); - buffer_view_points["byteOffset"] = picojson::value(static_cast(0)); - buffer_view_points["target"] = picojson::value(static_cast(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(curves.nverts.size() * sizeof(int))); - buffer_view_nverts["byteOffset"] = picojson::value(static_cast(0)); - buffer_view_nverts["target"] = picojson::value(static_cast(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(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(0)); - accessor_points["byteStride"] = picojson::value(static_cast(3 * sizeof(float))); - accessor_points["componentType"] = picojson::value(static_cast(TINYGLTF_COMPONENT_TYPE_FLOAT)); - accessor_points["count"] = picojson::value(static_cast(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(0)); - accessor_nverts["byteStride"] = picojson::value(static_cast(sizeof(int))); - accessor_nverts["componentType"] = picojson::value(static_cast(TINYGLTF_COMPONENT_TYPE_INT)); - accessor_nverts["count"] = picojson::value(static_cast(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(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; -} diff --git a/examples/cyhair_to_gltf/cyhair_loader.cc b/examples/cyhair_to_gltf/cyhair_loader.cc deleted file mode 100644 index 4f930aa..0000000 --- a/examples/cyhair_to_gltf/cyhair_loader.cc +++ /dev/null @@ -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 -#include -#include -#include -#include - -#include - -#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(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(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(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(num_segments + 1); - } - - return true; -} - -bool CyHair::ToCubicBezierCurves(std::vector *vertices, - std::vector *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(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(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 segment_points; - for (size_t k = 0; k < static_cast(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 diff --git a/examples/cyhair_to_gltf/cyhair_loader.h b/examples/cyhair_to_gltf/cyhair_loader.h deleted file mode 100644 index 3852912..0000000 --- a/examples/cyhair_to_gltf/cyhair_loader.h +++ /dev/null @@ -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 -#include -#include -#include -#include - -#include - -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 *vertices, - std::vector *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 segments_; - std::vector points_; // xyz - std::vector thicknesses_; - std::vector transparencies_; - std::vector 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 strand_offsets_; -}; - -} // namespace example - -#endif // EXAMPLE_CYHAIR_LOADER_H_ diff --git a/examples/glview/README.md b/examples/glview/README.md index bb6194c..0ed9966 100644 --- a/examples/glview/README.md +++ b/examples/glview/README.md @@ -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 diff --git a/examples/glview/glview.cc b/examples/glview/glview.cc index e13ad38..aabf728 100644 --- a/examples/glview/glview.cc +++ b/examples/glview/glview.cc @@ -60,9 +60,9 @@ typedef struct { size_t count; // byte count } GLCurvesState; -std::map gBufferState; +std::map gBufferState; std::map gMeshState; -std::map gCurvesMesh; +std::map 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::const_iterator it( - scene.bufferViews.begin()); - std::map::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::const_iterator it( - scene.meshes.begin()); - std::map::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::const_iterator it( - primitive.attributes.begin()); - std::map::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::const_iterator it(primitive.attributes.begin()); + std::map::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::const_iterator it( + std::map::const_iterator it( primitive.attributes.begin()); - std::map::const_iterator itEnd( + std::map::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::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::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::const_iterator it(scene.meshes.begin()); std::map::const_iterator itEnd(scene.meshes.end()); @@ -699,19 +683,12 @@ static void DrawScene(tinygltf::Scene &scene) { DrawCurves(scene, it->second); } #else - std::map >::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::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::const_iterator it(scene.nodes.begin()); - std::map::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(); diff --git a/examples/writer/Makefile b/examples/writer/Makefile deleted file mode 100644 index 7f7a703..0000000 --- a/examples/writer/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -all: - $(CXX) -o gltf_writer -I../../ writer.cc diff --git a/examples/writer/README.md b/examples/writer/README.md deleted file mode 100644 index 32f2399..0000000 --- a/examples/writer/README.md +++ /dev/null @@ -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. - diff --git a/examples/writer/writer.cc b/examples/writer/writer.cc deleted file mode 100644 index 2b862e2..0000000 --- a/examples/writer/writer.cc +++ /dev/null @@ -1,431 +0,0 @@ -#include -#include -#include -#include - -#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& buffers) { - std::map::const_iterator it(buffers.begin()); - std::map::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(it->second.data.size())); - - (*o)[it->first] = picojson::value(buf); - } - - return true; -} - -bool EncodeBufferViews( - picojson::object* o, - const std::map& bufferViews) { - std::map::const_iterator it( - bufferViews.begin()); - std::map::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(it->second.byteLength)); - buf["byteOffset"] = - picojson::value(static_cast(it->second.byteOffset)); - buf["target"] = picojson::value(static_cast(it->second.target)); - - (*o)[it->first] = picojson::value(buf); - } - - return true; -} - -bool EncodeFloatArray(picojson::array* arr, const std::vector& 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& 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& nodes) { - std::map::const_iterator it(nodes.begin()); - std::map::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 >& scenes) { - std::map >::const_iterator it( - scenes.begin()); - std::map >::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& accessors) { - std::map::const_iterator it( - accessors.begin()); - std::map::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(it->second.byteOffset)); - buf["byteStride"] = - picojson::value(static_cast(it->second.byteStride)); - buf["componentType"] = - picojson::value(static_cast(it->second.componentType)); - buf["count"] = picojson::value(static_cast(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(primitive.mode)); - - std::map::const_iterator it( - primitive.attributes.begin()); - std::map::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& meshes) { - std::map::const_iterator it(meshes.begin()); - std::map::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(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; -} diff --git a/images/cyhair.png b/images/cyhair.png deleted file mode 100644 index ad130ca..0000000 Binary files a/images/cyhair.png and /dev/null differ diff --git a/images/glview_duck.png b/images/glview_duck.png deleted file mode 100644 index 55efc09..0000000 Binary files a/images/glview_duck.png and /dev/null differ diff --git a/loader_example.cc b/loader_example.cc index b26faa1..c57bb90 100644 --- a/loader_example.cc +++ b/loader_example.cc @@ -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(); + const tinygltf::Value::Object &o = value.Get(); 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::endl; + ss << Indent(indent) << name << " : " << value.Get() + << std::endl; } else if (value.IsBool()) { ss << Indent(indent) << name << " : " << value.Get() << 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 &m, - int indent) { +static void DumpStringIntMap(const std::map &m, int indent) { std::map::const_iterator it(m.begin()); std::map::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; } } diff --git a/models/Cube/Cube_BaseColor.png b/models/Cube/Cube_BaseColor.png index 2e29233..5e5cb20 100644 Binary files a/models/Cube/Cube_BaseColor.png and b/models/Cube/Cube_BaseColor.png differ diff --git a/models/Cube/Cube_MetallicRoughness.png b/models/Cube/Cube_MetallicRoughness.png index a944391..efd2026 100644 Binary files a/models/Cube/Cube_MetallicRoughness.png and b/models/Cube/Cube_MetallicRoughness.png differ diff --git a/tiny_gltf_loader.h b/tiny_gltf_loader.h index a371660..6f17932 100644 --- a/tiny_gltf_loader.h +++ b/tiny_gltf_loader.h @@ -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 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 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 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 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 minValues; // required std::vector 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 > targets; // array of morph targets, - //where each target is a dict with attribues in ["POSITION, "NORMAL", "TANGENT"] pointing - // to their corresponding accessors + std::vector > 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 primitives; - std::vector weights; // weights to be applied to the Morph Targets - std::vector >targets; + std::vector weights; // weights to be applied to the Morph Targets + std::vector > 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 scale; // length must be 0 or 3 std::vector translation; // length must be 0 or 3 std::vector matrix; // length must be 0 or 16 - std::vector weights; // The weights of the instantiated Morph Target + std::vector weights; // The weights of the instantiated Morph Target Value extras; }; @@ -508,12 +484,13 @@ class Node { typedef struct { std::string name; std::vector 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 *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 *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 *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(); - 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 *ret, std::string *err, - const picojson::object &o, - const std::string &property, - bool required) -{ +static bool ParseJSONProperty(std::map *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()) { + if (!it->second.is()) { if (required) { if (err) { (*err) += "'" + property + "' property is not a JSON object.\n"; @@ -1405,8 +1384,9 @@ static bool ParseJSONProperty(std::map *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()) - ret->insert(std::pair(it2->first, it2->second.get())); + if (it2->second.is()) + ret->insert(std::pair(it2->first, + it2->second.get())); } 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(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(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()) { + if ((targetsObject != o.end()) && + (targetsObject->second).is()) { const picojson::array &targetArray = (targetsObject->second).get(); 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(dictIt->second.get()); + targetAttribues[dictIt->first] = + static_cast(dictIt->second.get()); } 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(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(childrenArray[i].get()); + const int &childrenNode = + static_cast(childrenArray[i].get()); 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()) { const picojson::object &values_object = (it->second).get(); @@ -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()) { - const picojson::object &extension = (it->second).get(); + const picojson::object &extension = + (it->second).get(); - picojson::object::const_iterator extIt = extension.begin(); - if(!extIt->second.is()) - continue; + picojson::object::const_iterator extIt = extension.begin(); + if (!extIt->second.is()) continue; - const picojson::object &values_object = - (extIt->second).get(); + const picojson::object &values_object = + (extIt->second).get(); - 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(); - 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 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()) { + if (v.contains("scenes") && v.get("scenes").is()) { // OK } else if (check_sections & REQUIRE_SCENES) { if (err) { @@ -2191,8 +2170,7 @@ if (v.contains("scenes") && v.get("scenes").is()) { return false; } - if (v.contains("bufferViews") && - v.get("bufferViews").is()) { + if (v.contains("bufferViews") && v.get("bufferViews").is()) { // OK } else if (check_sections & REQUIRE_BUFFER_VIEWS) { if (err) { @@ -2217,10 +2195,11 @@ if (v.contains("scenes") && v.get("scenes").is()) { } // 0. Parse extensionUsed - if (v.contains("extensionsUsed") && v.get("extensionsUsed").is()) { - const picojson::array &root = v.get("extensionsUsed").get(); - for(unsigned int i=0; i< root.size(); ++i) - { + if (v.contains("extensionsUsed") && + v.get("extensionsUsed").is()) { + const picojson::array &root = + v.get("extensionsUsed").get(); + for (unsigned int i = 0; i < root.size(); ++i) { model->extensionsUsed.push_back(root[i].get()); } } @@ -2233,8 +2212,8 @@ if (v.contains("scenes") && v.get("scenes").is()) { picojson::array::const_iterator itEnd(root.end()); for (; it != itEnd; it++) { Buffer buffer; - if (!ParseBuffer(&buffer, err, it->get(), - base_dir, is_binary_, bin_data_, bin_size_)) { + if (!ParseBuffer(&buffer, err, it->get(), base_dir, + is_binary_, bin_data_, bin_size_)) { return false; } @@ -2243,16 +2222,14 @@ if (v.contains("scenes") && v.get("scenes").is()) { } // 2. Parse BufferView - if (v.contains("bufferViews") && - v.get("bufferViews").is()) { + if (v.contains("bufferViews") && v.get("bufferViews").is()) { const picojson::array &root = v.get("bufferViews").get(); 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())) { + if (!ParseBufferView(&bufferView, err, it->get())) { return false; } @@ -2268,8 +2245,7 @@ if (v.contains("scenes") && v.get("scenes").is()) { picojson::array::const_iterator itEnd(root.end()); for (; it != itEnd; it++) { Accessor accessor; - if (!ParseAccessor(&accessor, err, - it->get())) { + if (!ParseAccessor(&accessor, err, it->get())) { return false; } @@ -2371,8 +2347,8 @@ if (v.contains("scenes") && v.get("scenes").is()) { picojson::array::const_iterator itEnd(root.end()); for (; it != itEnd; it++) { Image image; - if (!ParseImage(&image, err, it->get(), - base_dir, is_binary_, bin_data_, bin_size_)) { + if (!ParseImage(&image, err, it->get(), base_dir, + is_binary_, bin_data_, bin_size_)) { return false; } @@ -2388,7 +2364,8 @@ if (v.contains("scenes") && v.get("scenes").is()) { 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::const_iterator itEnd(root.end()); for (; it != itEnd; it++) { Texture texture; - if (!ParseTexture(&texture, err, it->get(), - base_dir)) { + if (!ParseTexture(&texture, err, it->get(), base_dir)) { return false; } @@ -2428,8 +2404,7 @@ if (v.contains("scenes") && v.get("scenes").is()) { picojson::array::const_iterator itEnd(root.end()); for (; it != itEnd; ++it) { Animation animation; - if (!ParseAnimation(&animation, err, - it->get())) { + if (!ParseAnimation(&animation, err, it->get())) { return false; } @@ -2445,8 +2420,7 @@ if (v.contains("scenes") && v.get("scenes").is()) { picojson::array::const_iterator itEnd(root.end()); for (; it != itEnd; ++it) { Skin skin; - if (!ParseSkin(&skin, err, - it->get())) { + if (!ParseSkin(&skin, err, it->get())) { return false; }