diff --git a/examples/mesh-modify/mesh-modify.cc b/examples/mesh-modify/mesh-modify.cc index 867e833..8d75f7a 100644 --- a/examples/mesh-modify/mesh-modify.cc +++ b/examples/mesh-modify/mesh-modify.cc @@ -6,6 +6,11 @@ #include #include #include +#include + +#if !defined(__ANDROID__) && !defined(_WIN32) +#include +#endif #ifdef __clang__ #pragma clang diagnostic push @@ -20,10 +25,6 @@ using json = nlohmann::json; #pragma clang diagnostic pop #endif -#define TINYGLTF_IMPLEMENTATION -#define STB_IMAGE_IMPLEMENTATION -#define STB_IMAGE_WRITE_IMPLEMENTATION - #ifdef _WIN32 #include "../../tiny_gltf.h" #else @@ -32,6 +33,10 @@ using json = nlohmann::json; #include "mesh-util.hh" +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wunused-function" +#endif + namespace { static std::string PrintMode(int mode) { @@ -143,11 +148,13 @@ struct MeshPrim { }; #endif +#if 0 static std::string GetFilePathExtension(const std::string &FileName) { if (FileName.find_last_of(".") != std::string::npos) return FileName.substr(FileName.find_last_of(".") + 1); return ""; } +#endif static size_t ComponentTypeByteSize(int type) { switch (type) { @@ -289,11 +296,13 @@ static std::string FindFile(const std::vector &paths, return std::string(); } +#if 0 static std::string GetBaseDir(const std::string &filepath) { if (filepath.find_last_of("/\\") != std::string::npos) return filepath.substr(0, filepath.find_last_of("/\\")); return ""; } +#endif static int GetSlotId(const std::string &name) { if (name.rfind("TEXCOORD_", 0) == 0) { @@ -566,6 +575,7 @@ static bool DumpMesh(const tinygltf::Model &model, const tinygltf::Mesh &mesh, return true; } +#if 0 static bool ExtractMesh(const std::string &asset_path, tinygltf::Model &model, std::vector *outs) { // Get .bin data @@ -613,6 +623,7 @@ static bool ExtractMesh(const std::string &asset_path, tinygltf::Model &model, return true; } +#endif } // namespace @@ -713,6 +724,8 @@ int main(int argc, char **argv) { } n++; } + + return ret ? EXIT_SUCCESS : EXIT_FAILURE; #else { @@ -728,9 +741,11 @@ int main(int argc, char **argv) { if (!ok) { return EXIT_FAILURE; } + + PrintMeshPrim(mesh); } + return EXIT_SUCCESS; #endif - return ret ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/examples/mesh-modify/mesh-util.cc b/examples/mesh-modify/mesh-util.cc index 63dbd86..6675c76 100644 --- a/examples/mesh-modify/mesh-util.cc +++ b/examples/mesh-modify/mesh-util.cc @@ -9,8 +9,99 @@ #define TINYOBJLOADER_IMPLEMENTATION #include "tiny_obj_loader.h" +// Include defines +#include "tiny_gltf.h" + namespace example { +template +std::ostream &operator<<(std::ostream &os, const std::vector &v) { + os << "("; + for (size_t i = 0; i < v.size(); i++) { + os << v[i]; + if (i != (v.size() - 1)) { + os << ", "; + } + } + os << ")"; + + return os; +} + +#if 0 +static std::string PrintMode(int mode) { + if (mode == TINYGLTF_MODE_POINTS) { + return "POINTS"; + } else if (mode == TINYGLTF_MODE_LINE) { + return "LINE"; + } else if (mode == TINYGLTF_MODE_LINE_LOOP) { + return "LINE_LOOP"; + } else if (mode == TINYGLTF_MODE_TRIANGLES) { + return "TRIANGLES"; + } else if (mode == TINYGLTF_MODE_TRIANGLE_FAN) { + return "TRIANGLE_FAN"; + } else if (mode == TINYGLTF_MODE_TRIANGLE_STRIP) { + return "TRIANGLE_STRIP"; + } + return "**UNKNOWN**"; +} + +static std::string PrintTarget(int target) { + if (target == 34962) { + return "GL_ARRAY_BUFFER"; + } else if (target == 34963) { + return "GL_ELEMENT_ARRAY_BUFFER"; + } else { + return "**UNKNOWN**"; + } +} +#endif + +static std::string PrintType(int ty) { + if (ty == TINYGLTF_TYPE_SCALAR) { + return "SCALAR"; + } else if (ty == TINYGLTF_TYPE_VECTOR) { + return "VECTOR"; + } else if (ty == TINYGLTF_TYPE_VEC2) { + return "VEC2"; + } else if (ty == TINYGLTF_TYPE_VEC3) { + return "VEC3"; + } else if (ty == TINYGLTF_TYPE_VEC4) { + return "VEC4"; + } else if (ty == TINYGLTF_TYPE_MATRIX) { + return "MATRIX"; + } else if (ty == TINYGLTF_TYPE_MAT2) { + return "MAT2"; + } else if (ty == TINYGLTF_TYPE_MAT3) { + return "MAT3"; + } else if (ty == TINYGLTF_TYPE_MAT4) { + return "MAT4"; + } + return "**UNKNOWN**"; +} + +static std::string PrintComponentType(int ty) { + if (ty == TINYGLTF_COMPONENT_TYPE_BYTE) { + return "BYTE"; + } else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) { + return "UNSIGNED_BYTE"; + } else if (ty == TINYGLTF_COMPONENT_TYPE_SHORT) { + return "SHORT"; + } else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) { + return "UNSIGNED_SHORT"; + } else if (ty == TINYGLTF_COMPONENT_TYPE_INT) { + return "INT"; + } else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) { + return "UNSIGNED_INT"; + } else if (ty == TINYGLTF_COMPONENT_TYPE_FLOAT) { + return "FLOAT"; + } else if (ty == TINYGLTF_COMPONENT_TYPE_DOUBLE) { + return "DOUBLE"; + } + + return "**UNKNOWN**"; +} + // TODO(syoyo): Specify CCW(Counter-ClockWise) or CW(ClockWise) static void CalcNormal(float N[3], float v0[3], float v1[3], float v2[3]) { float v10[3]; @@ -111,17 +202,29 @@ bool SaveAsObjMesh(const std::string &filename, const MeshPrim &mesh, return true; } +bool SaveAsGLTFMesh(const std::string &filename, const MeshPrim &mesh) { + + tinygltf::TinyGLTF ctx; + tinygltf::Model model; + + return true; +} + bool RequireFacevaringLayout(const tinyobj::attrib_t &attrib, const std::vector &shapes) { // Check if all normals and texcoords has same index with vertex - if ((attrib.texcoords.size() / 3) != attrib.vertices.size() / 3) { + if ((attrib.texcoords.size() / 2) != attrib.vertices.size() / 3) { std::cerr << "Texcoords and Vertices length mismatch. Mesh data cannot be " - "represented as non-facevarying\n"; + "represented as non-facevarying. texcoords.size = " + << (attrib.texcoords.size() / 2) + << ", vertices.size = " << (attrib.vertices.size() / 3) << "\n"; return true; } - if ((attrib.normals.size() / 2) != attrib.vertices.size() / 3) { + if ((attrib.normals.size() / 3) != attrib.vertices.size() / 3) { std::cerr << "Normals and Vertices length mismatch. Mesh data cannot be " - "represented as non-facevarying\n"; + "represented as non-facevarying. normals.size = " + << (attrib.normals.size() / 3) + << ", vertices.szie = " << (attrib.vertices.size() / 3) << "\n"; return true; } @@ -155,6 +258,27 @@ bool RequireFacevaringLayout(const tinyobj::attrib_t &attrib, return false; } +static void ConstructVertexSkinWeight( + const std::vector &vertices, + const std::vector &skin_weights, + std::vector *vertex_skin_weights) +{ + size_t num_vertices = vertices.size() / 3; + + vertex_skin_weights->resize(num_vertices); + + for (size_t i = 0; i < skin_weights.size(); i++) { + const tinyobj::skin_weight_t &skin = skin_weights[i]; + + assert(skin.vertex_id >= 0); + assert(skin.vertex_id < num_vertices); + + (*vertex_skin_weights)[skin.vertex_id] = skin; + } + + // now you can lookup i'th vertex skin weight by `vertex_skin_weights[i]` +} + bool LoadObjMesh(const std::string &filename, bool facevarying, MeshPrim *mesh) { tinyobj::attrib_t attrib; @@ -196,6 +320,7 @@ bool LoadObjMesh(const std::string &filename, bool facevarying, if (facevarying) { mesh->position.data.clear(); mesh->normal.data.clear(); + mesh->tangent.data.clear(); mesh->texcoords[0] = VertexAttrib(); // Concat shapes @@ -333,6 +458,64 @@ bool LoadObjMesh(const std::string &filename, bool facevarying, } } + // weights/joints + if (attrib.skin_weights.size() > 0) { + + // Reorder vertex skin weights + std::vector vertex_skin_weights; + ConstructVertexSkinWeight( + attrib.vertices, + attrib.skin_weights, + &vertex_skin_weights); + + // Find max # of slots. + size_t maxn = 0; + for (size_t i = 0; i < vertex_skin_weights.size(); i++) { + maxn = std::max(vertex_skin_weights[i].weightValues.size(), maxn); + } + + int num_slots = 0; + if (maxn > 0) { + num_slots = (((maxn - 1) / 4) + 1) * 4; + } + std::cout << "# of slots = " << num_slots << "\n"; + + for (size_t t = 0; t < size_t(num_slots); t++) { + + VertexAttrib weights, joints; + + size_t num_faceverts = mesh->indices.size(); + + // facevarying weights/joints Fill with zeros + weights.data.resize(4 * num_faceverts, 0.0f); + joints.data.resize(4 * num_faceverts, 0.0f); + + for (size_t s = 0; s < shapes.size(); s++) { + const tinyobj::shape_t &shape = shapes[s]; + + for (size_t f = 0; f < shape.mesh.indices.size(); f++) { + tinyobj::index_t idx = shape.mesh.indices[f]; + + size_t vid = idx.vertex_index; + + assert(vid < vertex_skin_weights.size()); + const tinyobj::skin_weight_t &sw = vertex_skin_weights[vid]; + + for (size_t j0 = 0; j0 < 4; j0++) { + size_t j = t * 4 + j0; + if (j < sw.weightValues.size()) { + joints.data[4 * vid + j0] = float(sw.weightValues[j].joint_id); + weights.data[4 * vid + j0] = float(sw.weightValues[j].weight); + } + } + } + } + + mesh->weights[t] = weights; + mesh->joints[t] = joints; + } + } + } else { // position/texcoord/normal can be represented in shared vertex manner @@ -351,6 +534,7 @@ bool LoadObjMesh(const std::string &filename, bool facevarying, mesh->texcoords[0].data.push_back(attrib.texcoords[v]); } + mesh->indices_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT; mesh->indices.clear(); size_t face_index_offset = 0; @@ -358,15 +542,362 @@ bool LoadObjMesh(const std::string &filename, bool facevarying, const tinyobj::shape_t &shape = shapes[s]; for (size_t f = 0; f < shape.mesh.indices.size(); f++) { - mesh->indices.push_back(uint32_t(face_index_offset) + uint32_t(shape.mesh.indices[f].vertex_index)); + mesh->indices.push_back(uint32_t(face_index_offset) + + uint32_t(shape.mesh.indices[f].vertex_index)); } face_index_offset = mesh->indices.size(); } + // weights/joints + if (attrib.skin_weights.size() > 0) { + + // Find max # of slots. + size_t maxn = 0; + for (size_t i = 0; i < attrib.skin_weights.size(); i++) { + maxn = std::max(attrib.skin_weights[i].weightValues.size(), maxn); + } + + int num_slots = 0; + if (maxn > 0) { + num_slots = (((maxn - 1) / 4) + 1) * 4; + } + std::cout << "# of slots = " << num_slots << "\n"; + + for (size_t s = 0; s < size_t(num_slots); s++) { + + VertexAttrib weights, joints; + + // Fill with zeros + weights.data.resize(4 * (mesh->position.data.size() / 3), 0.0f); + joints.data.resize(4 * (mesh->position.data.size() / 3), 0.0f); + + for (size_t v = 0; v < attrib.skin_weights.size(); v++) { + const tinyobj::skin_weight_t &sw = attrib.skin_weights[v]; + + assert(sw.vertex_id < (mesh->position.data.size() / 3)); + + size_t dst_vid = sw.vertex_id; + + for (size_t j0 = 0; j0 < 4; j0++) { + size_t j = s * 4 + j0; + if (j < sw.weightValues.size()) { + joints.data[4 * dst_vid + j0] = float(sw.weightValues[j].joint_id); + weights.data[4 * dst_vid + j0] = float(sw.weightValues[j].weight); + } + } + } + + weights.data_type = TINYGLTF_TYPE_VEC4; + weights.component_type = TINYGLTF_COMPONENT_TYPE_FLOAT; // storage format + mesh->weights[s] = weights; + + joints.data_type = TINYGLTF_TYPE_VEC4; + joints.component_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT; // storage format + + mesh->joints[s] = joints; + } + } + } + + // postprocessing. e.g. find min/max + { + { + uint32_t minv = 0.0; + uint32_t maxv = 0.0; + for (size_t i = 0; i < mesh->indices.size(); i++) { + minv = std::min(minv, uint32_t(mesh->indices[i])); + maxv = std::max(maxv, uint32_t(mesh->indices[i])); + } + + mesh->indices_min = int(minv); + mesh->indices_max = int(maxv); + + mesh->indices_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT; + } + + { + float bmin[3]; + float bmax[3]; + bmin[0] = bmin[1] = bmin[2] = std::numeric_limits::max(); + bmax[0] = bmax[1] = bmax[2] = -std::numeric_limits::max(); + + for (size_t i = 0; i < mesh->position.data.size() / 3; i++) { + for (size_t k = 0; k < 3; k++) { + bmin[k] = std::min(bmin[k], mesh->position.data[3 * i + k]); + bmax[k] = std::max(bmax[k], mesh->position.data[3 * i + k]); + } + } + + mesh->position.minValues.resize(3); + mesh->position.minValues[0] = bmin[0]; + mesh->position.minValues[1] = bmin[1]; + mesh->position.minValues[2] = bmin[2]; + + mesh->position.maxValues.resize(3); + mesh->position.maxValues[0] = bmax[0]; + mesh->position.maxValues[1] = bmax[1]; + mesh->position.maxValues[2] = bmax[2]; + + mesh->position.data_type = TINYGLTF_TYPE_VEC3; + mesh->position.component_type = TINYGLTF_COMPONENT_TYPE_FLOAT; + } + + { + float bmin[3]; + float bmax[3]; + bmin[0] = bmin[1] = bmin[2] = std::numeric_limits::max(); + bmax[0] = bmax[1] = bmax[2] = -std::numeric_limits::max(); + + for (size_t i = 0; i < mesh->normal.data.size() / 3; i++) { + for (size_t k = 0; k < 3; k++) { + bmin[k] = std::min(bmin[k], mesh->normal.data[3 * i + k]); + bmax[k] = std::max(bmax[k], mesh->normal.data[3 * i + k]); + } + } + + mesh->normal.minValues.resize(3); + mesh->normal.minValues[0] = bmin[0]; + mesh->normal.minValues[1] = bmin[1]; + mesh->normal.minValues[2] = bmin[2]; + + mesh->normal.maxValues.resize(3); + mesh->normal.maxValues[0] = bmax[0]; + mesh->normal.maxValues[1] = bmax[1]; + mesh->normal.maxValues[2] = bmax[2]; + + mesh->normal.data_type = TINYGLTF_TYPE_VEC3; + mesh->normal.component_type = TINYGLTF_COMPONENT_TYPE_FLOAT; + } + + { + float bmin[4]; + float bmax[4]; + bmin[0] = bmin[1] = bmin[2] = bmin[3] = std::numeric_limits::max(); + bmax[0] = bmax[1] = bmax[2] = bmin[3] = + -std::numeric_limits::max(); + + size_t n = 3; + + for (size_t i = 0; i < mesh->tangent.data.size() / n; i++) { + for (size_t k = 0; k < n; k++) { + bmin[k] = std::min(bmin[k], mesh->tangent.data[n * i + k]); + bmax[k] = std::max(bmax[k], mesh->tangent.data[n * i + k]); + } + } + + mesh->tangent.minValues.resize(n); + mesh->tangent.maxValues.resize(n); + for (size_t k = 0; k < n; k++) { + mesh->tangent.minValues[k] = bmin[k]; + mesh->tangent.maxValues[k] = bmax[k]; + } + + mesh->tangent.data_type = + (n == 3) ? TINYGLTF_TYPE_VEC3 : TINYGLTF_TYPE_VEC4; + mesh->tangent.component_type = TINYGLTF_COMPONENT_TYPE_FLOAT; + } + + // texcoord + for (auto &item : mesh->texcoords) { + float bmin[2]; + float bmax[2]; + bmin[0] = bmin[1] = std::numeric_limits::max(); + bmax[0] = bmax[1] = -std::numeric_limits::max(); + + for (size_t i = 0; i < item.second.data.size() / 2; i++) { + for (size_t k = 0; k < 2; k++) { + bmin[k] = std::min(bmin[k], item.second.data[2 * i + k]); + bmax[k] = std::max(bmax[k], item.second.data[2 * i + k]); + } + } + + item.second.minValues.resize(2); + item.second.maxValues.resize(2); + for (size_t k = 0; k < 2; k++) { + item.second.minValues[k] = bmin[k]; + item.second.maxValues[k] = bmax[k]; + } + + item.second.data_type = TINYGLTF_TYPE_VEC2; + item.second.component_type = TINYGLTF_COMPONENT_TYPE_FLOAT; + } + + // joints + for (auto &item : mesh->joints) { + float bmin; + float bmax; + bmin = std::numeric_limits::max(); + bmax = -std::numeric_limits::max(); + + for (size_t i = 0; i < item.second.data.size(); i++) { + bmin = std::min(bmin, item.second.data[i]); + bmax = std::max(bmax, item.second.data[i]); + } + + item.second.minValues.resize(1); + item.second.maxValues.resize(1); + + item.second.minValues[0] = bmin; + item.second.maxValues[0] = bmax; + + item.second.data_type = TINYGLTF_TYPE_VEC4; + item.second.component_type = + TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT; // storage format + } + + // weights + for (auto &item : mesh->weights) { + float bmin; + float bmax; + bmin = std::numeric_limits::max(); + bmax = -std::numeric_limits::max(); + + for (size_t i = 0; i < item.second.data.size(); i++) { + bmin = std::min(bmin, item.second.data[i]); + bmax = std::max(bmax, item.second.data[i]); + } + + item.second.minValues.resize(1); + item.second.maxValues.resize(1); + + item.second.minValues[0] = bmin; + item.second.maxValues[0] = bmax; + + item.second.data_type = TINYGLTF_TYPE_VEC4; + item.second.component_type = + TINYGLTF_COMPONENT_TYPE_FLOAT; // storage format + } } return true; } +void PrintMeshPrim(const MeshPrim &mesh) { + std::cout << "indices.component_type : " + << PrintComponentType(mesh.indices_type) << "\n"; + std::cout << "# of indices : " << mesh.indices.size() << "\n"; + std::cout << " indices.min = " << mesh.indices_min + << ", max = " << mesh.indices_max << "\n"; + for (size_t i = 0; i < mesh.indices.size(); i++) { + std::cout << " index[" << i << "] = " << mesh.indices[i] << "\n"; + } + + std::cout << "position.type : " << PrintType(mesh.position.data_type) << "\n"; + std::cout << "position.component_type : " + << PrintComponentType(mesh.position.component_type) << "\n"; + std::cout << "# of positions : " << mesh.position.data.size() / 3 << "\n"; + if ((mesh.position.minValues.size() == 3) && + (mesh.position.maxValues.size() == 3)) { + std::cout << " position.min = " << mesh.position.minValues + << ", max = " << mesh.position.maxValues << "\n"; + } + for (size_t i = 0; i < mesh.position.data.size() / 3; i++) { + std::cout << " position[" << i << "] = " << mesh.position.data[3 * i + 0] + << ", " << mesh.position.data[3 * i + 1] << ", " + << mesh.position.data[3 * i + 2] << std::endl; + } + + std::cout << "normal.type : " << PrintType(mesh.normal.data_type) << "\n"; + std::cout << "normal.component_type : " + << PrintComponentType(mesh.normal.component_type) << "\n"; + std::cout << "# of normals : " << mesh.normal.data.size() / 3 << "\n"; + if ((mesh.normal.minValues.size() == 3) && + (mesh.normal.maxValues.size() == 3)) { + std::cout << " normal.min = " << mesh.normal.minValues + << ", max = " << mesh.normal.maxValues << "\n"; + } + for (size_t i = 0; i < mesh.normal.data.size() / 3; i++) { + std::cout << " normal[" << i << "] = " << mesh.normal.data[3 * i + 0] + << ", " << mesh.normal.data[3 * i + 1] << ", " + << mesh.normal.data[3 * i + 2] << std::endl; + } + + if (mesh.tangent.data.size() > 0) { + assert((mesh.tangent.data_type == TINYGLTF_TYPE_VEC3) || + (mesh.tangent.data_type == TINYGLTF_TYPE_VEC4)); + + size_t n = mesh.tangent.data_type == TINYGLTF_TYPE_VEC3 ? 3 : 4; + + std::cout << "tangent.type : " << PrintType(mesh.tangent.data_type) << "\n"; + std::cout << "tangent.component_type : " + << PrintComponentType(mesh.tangent.component_type) << "\n"; + std::cout << "# of tangents : " << mesh.tangent.data.size() / n << "\n"; + if ((mesh.tangent.minValues.size() == 3) && + (mesh.tangent.maxValues.size() == 3)) { + std::cout << " tangent.min = " << mesh.tangent.minValues + << ", max = " << mesh.tangent.maxValues << "\n"; + } + for (size_t i = 0; i < mesh.tangent.data.size() / n; i++) { + std::cout << " tangent[" << i << "] = " << mesh.tangent.data[n * i + 0] + << ", " << mesh.tangent.data[n * i + 1] << ", " + << mesh.tangent.data[n * i + 2]; + + if (n == 4) { + std::cout << ", " << mesh.tangent.data[n * i + 3]; + } + std::cout << std::endl; + } + } + + std::cout << "# of texcoord slots : " << mesh.texcoords.size() << "\n"; + for (const auto &item : mesh.texcoords) { + std::cout << "TEXCOORD_" << item.first << "\n"; + + assert(item.second.data_type == TINYGLTF_TYPE_VEC2); + std::cout << "texcoord.type : " << PrintType(item.second.data_type) << "\n"; + std::cout << "texcoord.component_type : " + << PrintComponentType(item.second.component_type) << "\n"; + std::cout << "# of texcoords : " << item.second.data.size() / 2 << "\n"; + if ((item.second.minValues.size() == 2) && + (item.second.maxValues.size() == 2)) { + std::cout << " texcood.min = " << item.second.minValues + << ", max = " << item.second.maxValues << "\n"; + } + for (size_t i = 0; i < item.second.data.size() / 2; i++) { + std::cout << " texcoord[" << i << "] = " << item.second.data[2 * i + 0] + << ", " << item.second.data[2 * i + 1]; + std::cout << std::endl; + } + } + + assert(mesh.joints.size() == mesh.weights.size()); + std::cout << "# of joints/weights slots : " << mesh.joints.size() << "\n"; + for (const auto &item : mesh.joints) { + assert(mesh.weights.count(item.first)); + + assert(item.second.data_type == TINYGLTF_TYPE_VEC4); + + // joint must be uint8 or uint16 + assert( + (item.second.component_type == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) || + (item.second.component_type == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT)); + + std::cout << "joint.type : " << PrintType(item.second.data_type) << "\n"; + std::cout << "joint.component_type : " + << PrintComponentType(item.second.component_type) << "\n"; + + std::cout << "JOINTS_" << item.first << "\n"; + for (size_t i = 0; i < item.second.data.size(); i++) { + std::cout << " joints[" << i << "] = " << int(item.second.data[i]) + << "\n"; + } + + const VertexAttrib &attrib = mesh.weights.at(item.first); + + // weight must be uint8 or uint16(normalized), or float + assert((attrib.component_type == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) || + (attrib.component_type == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) || + (attrib.component_type == TINYGLTF_COMPONENT_TYPE_FLOAT)); + + std::cout << "weight.type : " << PrintType(attrib.data_type) << "\n"; + std::cout << "weight.component_type : " + << PrintComponentType(attrib.component_type) << "\n"; + std::cout << "WEIGHTS_" << item.first << "\n"; + for (size_t i = 0; i < attrib.data.size(); i++) { + std::cout << " weights[" << i << "] = " << attrib.data[i] << "\n"; + } + } +} + } // namespace example diff --git a/examples/mesh-modify/mesh-util.hh b/examples/mesh-modify/mesh-util.hh index e8d28d1..79f9e9e 100644 --- a/examples/mesh-modify/mesh-util.hh +++ b/examples/mesh-modify/mesh-util.hh @@ -19,6 +19,11 @@ struct VertexAttrib { // TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT uint64_t buffer_offset{0}; size_t buffer_length{0}; + + // Optional. + std::vector minValues; + std::vector maxValues; + }; struct MeshPrim { @@ -36,6 +41,10 @@ struct MeshPrim { std::map joints; // store data as float type + + // min/max of index value. -1 = undef + int indices_min{-1}; + int indices_max{-1}; int indices_type{-1}; // storage type(componentType) of `indices`. std::vector indices; // vertex indices }; @@ -45,6 +54,11 @@ struct MeshPrim { /// bool SaveAsObjMesh(const std::string &filename, const MeshPrim &mesh); +/// +/// Save MeshPrim as glTF mesh +/// +bool SaveAsGLTFMesh(const std::string &filename, const MeshPrim &mesh); + /// /// Loads .obj and convert to MeshPrim /// @@ -52,4 +66,9 @@ bool SaveAsObjMesh(const std::string &filename, const MeshPrim &mesh); /// bool LoadObjMesh(const std::string &filename, bool facevarying, MeshPrim *mesh); +/// +/// Print MeshPrim datra +/// +void PrintMeshPrim(const MeshPrim &mesh); + } // namespace example diff --git a/examples/mesh-modify/meson.build b/examples/mesh-modify/meson.build index 1f9c4b7..92e669c 100644 --- a/examples/mesh-modify/meson.build +++ b/examples/mesh-modify/meson.build @@ -4,4 +4,4 @@ thread_dep = dependency('threads') incdir = include_directories(['../../', '../common']) -executable('mesh-modify', ['mesh-modify.cc', 'mesh-util.cc'], include_directories : incdir, dependencies : thread_dep) +executable('mesh-modify', ['mesh-modify.cc', 'mesh-util.cc', 'tinygltf_impl.cc'], include_directories : incdir, dependencies : thread_dep)