From 33cd9a4768b7e643dcb5564ac40a9c4a46aadd48 Mon Sep 17 00:00:00 2001 From: Mykhailo Parfeniuk Date: Sun, 7 Sep 2014 14:19:22 +0300 Subject: [PATCH] Added multiple materials per shape/object --- tiny_obj_loader.cc | 101 ++++++++++++++++++++++++--------------------- tiny_obj_loader.h | 14 +++++-- 2 files changed, 63 insertions(+), 52 deletions(-) diff --git a/tiny_obj_loader.cc b/tiny_obj_loader.cc index 5417487..5c28379 100755 --- a/tiny_obj_loader.cc +++ b/tiny_obj_loader.cc @@ -224,24 +224,22 @@ void InitMaterial(material_t& material) { static bool exportFaceGroupToShape( shape_t& shape, + std::map vertexCache, const std::vector &in_positions, const std::vector &in_normals, const std::vector &in_texcoords, const std::vector >& faceGroup, - const material_t &material, + const int material, const std::string &name, - const bool is_material_seted) + bool clearCache) { if (faceGroup.empty()) { return false; } - // Flattened version of vertex data - std::vector positions; - std::vector normals; - std::vector texcoords; - std::map vertexCache; - std::vector indices; + size_t offset; + + offset = shape.mesh.indices.size(); // Flatten vertices and indices for (size_t i = 0; i < faceGroup.size(); i++) { @@ -258,13 +256,13 @@ exportFaceGroupToShape( i1 = i2; i2 = face[k]; - unsigned int v0 = updateVertex(vertexCache, positions, normals, texcoords, in_positions, in_normals, in_texcoords, i0); - unsigned int v1 = updateVertex(vertexCache, positions, normals, texcoords, in_positions, in_normals, in_texcoords, i1); - unsigned int v2 = updateVertex(vertexCache, positions, normals, texcoords, in_positions, in_normals, in_texcoords, i2); + unsigned int v0 = updateVertex(vertexCache, shape.mesh.positions, shape.mesh.normals, shape.mesh.texcoords, in_positions, in_normals, in_texcoords, i0); + unsigned int v1 = updateVertex(vertexCache, shape.mesh.positions, shape.mesh.normals, shape.mesh.texcoords, in_positions, in_normals, in_texcoords, i1); + unsigned int v2 = updateVertex(vertexCache, shape.mesh.positions, shape.mesh.normals, shape.mesh.texcoords, in_positions, in_normals, in_texcoords, i2); - indices.push_back(v0); - indices.push_back(v1); - indices.push_back(v2); + shape.mesh.indices.push_back(v0); + shape.mesh.indices.push_back(v1); + shape.mesh.indices.push_back(v2); } } @@ -272,27 +270,22 @@ exportFaceGroupToShape( // // Construct shape. // - shape.name = name; - shape.mesh.positions.swap(positions); - shape.mesh.normals.swap(normals); - shape.mesh.texcoords.swap(texcoords); - shape.mesh.indices.swap(indices); + shape.submeshes.push_back(std::pair(offset, shape.mesh.indices.size()-offset)); - if(is_material_seted) { - shape.material = material; - } else { - InitMaterial(shape.material); - shape.material.diffuse[0] = 1.f; - shape.material.diffuse[1] = 1.f; - shape.material.diffuse[2] = 1.f; - } + shape.name = name; + + shape.materials.push_back(material); + + if (clearCache) + vertexCache.clear(); return true; } std::string LoadMtl ( - std::map& material_map, + std::map& material_map, + std::vector& materials, std::istream& inStream) { material_map.clear(); @@ -332,7 +325,11 @@ std::string LoadMtl ( // new mtl if ((0 == strncmp(token, "newmtl", 6)) && isSpace((token[6]))) { // flush previous material. - material_map.insert(std::pair(material.name, material)); + if (!material.name.empty()) + { + material_map.insert(std::pair(material.name, materials.size())); + materials.push_back(material); + } // initial temporary material InitMaterial(material); @@ -474,14 +471,16 @@ std::string LoadMtl ( } } // flush last material. - material_map.insert(std::pair(material.name, material)); + material_map.insert(std::pair(material.name, materials.size())); + materials.push_back(material); return err.str(); } std::string MaterialFileReader::operator() ( const std::string& matId, - std::map& matMap) + std::vector& materials, + std::map& matMap) { std::string filepath; @@ -492,12 +491,13 @@ std::string MaterialFileReader::operator() ( } std::ifstream matIStream(filepath.c_str()); - return LoadMtl(matMap, matIStream); + return LoadMtl(matMap, materials, matIStream); } std::string LoadObj( std::vector& shapes, + std::vector& materials, // [output] const char* filename, const char* mtl_basepath) { @@ -518,11 +518,12 @@ LoadObj( } MaterialFileReader matFileReader( basePath ); - return LoadObj(shapes, ifs, matFileReader); + return LoadObj(shapes, materials, ifs, matFileReader); } std::string LoadObj( std::vector& shapes, + std::vector& materials, // [output] std::istream& inStream, MaterialReader& readMatFn) { @@ -535,9 +536,11 @@ std::string LoadObj( std::string name; // material - std::map material_map; - material_t material; - bool is_material_seted = false; + std::map material_map; + std::map vertexCache; + int material = -1; + + shape_t shape; int maxchars = 8192; // Alloc enough size. std::vector buf(maxchars); // Alloc enough size. @@ -625,13 +628,16 @@ std::string LoadObj( token += 7; sscanf(token, "%s", namebuf); + bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt, faceGroup, material, name, false); + faceGroup.clear(); + if (material_map.find(namebuf) != material_map.end()) { material = material_map[namebuf]; - is_material_seted = true; } else { // { error!! material not found } - InitMaterial(material); + material = -1; } + continue; } @@ -642,7 +648,7 @@ std::string LoadObj( token += 7; sscanf(token, "%s", namebuf); - std::string err_mtl = readMatFn(namebuf, material_map); + std::string err_mtl = readMatFn(namebuf, materials, material_map); if (!err_mtl.empty()) { faceGroup.clear(); // for safety return err_mtl; @@ -655,13 +661,14 @@ std::string LoadObj( if (token[0] == 'g' && isSpace((token[1]))) { // flush previous face group. - shape_t shape; - bool ret = exportFaceGroupToShape(shape, v, vn, vt, faceGroup, material, name, is_material_seted); + bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt, faceGroup, material, name, true); if (ret) { shapes.push_back(shape); } - is_material_seted = false; + shape = shape_t(); + + material = -1; faceGroup.clear(); std::vector names; @@ -687,14 +694,14 @@ std::string LoadObj( if (token[0] == 'o' && isSpace((token[1]))) { // flush previous face group. - shape_t shape; - bool ret = exportFaceGroupToShape(shape, v, vn, vt, faceGroup, material, name, is_material_seted); + bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt, faceGroup, material, name, true); if (ret) { shapes.push_back(shape); } - is_material_seted = false; + material = -1; faceGroup.clear(); + shape = shape_t(); // @todo { multiple object name? } char namebuf[4096]; @@ -709,12 +716,10 @@ std::string LoadObj( // Ignore unknown command. } - shape_t shape; - bool ret = exportFaceGroupToShape(shape, v, vn, vt, faceGroup, material, name, is_material_seted); + bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt, faceGroup, material, name, true); if (ret) { shapes.push_back(shape); } - is_material_seted = false; // for safety faceGroup.clear(); // for safety return err.str(); diff --git a/tiny_obj_loader.h b/tiny_obj_loader.h index b4c9337..a832aa5 100644 --- a/tiny_obj_loader.h +++ b/tiny_obj_loader.h @@ -45,8 +45,9 @@ typedef struct typedef struct { std::string name; - material_t material; mesh_t mesh; + std::vector< std::pair > submeshes; + std::vector< int > materials; } shape_t; class MaterialReader @@ -57,7 +58,8 @@ public: virtual std::string operator() ( const std::string& matId, - std::map& matMap) = 0; + std::vector& materials, + std::map& matMap) = 0; }; class MaterialFileReader: @@ -68,7 +70,8 @@ class MaterialFileReader: virtual ~MaterialFileReader() {} virtual std::string operator() ( const std::string& matId, - std::map& matMap); + std::vector& materials, + std::map& matMap); private: std::string m_mtlBasePath; @@ -81,6 +84,7 @@ class MaterialFileReader: /// 'mtl_basepath' is optional, and used for base path for .mtl file. std::string LoadObj( std::vector& shapes, // [output] + std::vector& materials, // [output] const char* filename, const char* mtl_basepath = NULL); @@ -89,13 +93,15 @@ std::string LoadObj( /// Returns empty string when loading .obj success. std::string LoadObj( std::vector& shapes, // [output] + std::vector& materials, // [output] std::istream& inStream, MaterialReader& readMatFn); /// Loads materials into std::map /// Returns an empty string if successful std::string LoadMtl ( - std::map& material_map, + std::map& material_map, + std::vector& materials, std::istream& inStream); }