From a2dbf6d70f4868165bd412aa50eb8943f99b80ba Mon Sep 17 00:00:00 2001 From: Stijn Buys Date: Mon, 2 Nov 2009 17:15:51 +0000 Subject: ASE loader: support for multiple *GEOM objects and multiple materials --- src/model/asefile.cc | 256 ++++++++++++++++++++++++++++++++++++++------------- src/model/asefile.h | 47 ++++++++++ 2 files changed, 237 insertions(+), 66 deletions(-) (limited to 'src') diff --git a/src/model/asefile.cc b/src/model/asefile.cc index 3bf0d59..06e10dc 100644 --- a/src/model/asefile.cc +++ b/src/model/asefile.cc @@ -20,14 +20,20 @@ ASEFile::ASEFile(std::string const &name) { asefile_name.append(name); asefile_name.append(".ase"); - asefile_ifs.open(asefile_name); for (int i = 0; i < 3; i++) { - ase_minbbox[i] = MAX_BOUNDS; - ase_maxbbox[i] = -MAX_BOUNDS; + ase_minbbox[i] = 0; + ase_maxbbox[i] = 0; } + // a single fragmentgroup wil contain all the model triangles + ase_fragmentgroup = new FragmentGroup(); + ase_fragmentgroup->set_type(FragmentGroup::None); + + // reset counters + ase_vertexcount = 0; + ase_facecount = 0 ; } ASEFile::~ASEFile() @@ -47,6 +53,11 @@ ASEFile::~ASEFile() } ase_facelist.clear(); + for (MaterialList::iterator it = ase_materiallist.begin(); it != ase_materiallist.end(); it++) { + (*it).second = 0; + } + ase_materiallist.clear(); + if (asefile_ifs.is_open()) asefile_ifs.close(); } @@ -75,10 +86,91 @@ bool ASEFile::read_header(std::istream &is) return true; } -bool ASEFile::read_mesh_vertex_list(std::istream &is) +Material *ASEFile::read_material(std::istream &is) { - size_t count = 0; + Material *material = 0; + char data[1024]; + memset(data, 0, sizeof(data)); + int level = 1; + + while (is.getline(data, sizeof(data) - 1)) { + + std::istringstream line(data); + std::string word; + line >> word; + + if ((level == 1) && (word.compare("*MATERIAL_NAME") == 0)) { + // read material name + std::string n; + char c; + while ((line.get(c)) && (c != '"')); + while ((line.get(c)) && (c != '"')) + n += c; + + // find material + material = Material::find(n); + if (!material) { + material = new Material(n); + Material::add(material); + material->set_texture(material->name()); + } + + } else { + do { + if (word.compare("{") == 0) { + level++; + } else if (word.compare("}") == 0) { + level--; + } + } while (line >> word); + } + + if (level == 0) + return material; + } + + return material; +} +bool ASEFile::read_material_list(std::istream &is) +{ + char data[1024]; + memset(data, 0, sizeof(data)); + int level = 1; + + while (is.getline(data, sizeof(data) - 1)) { + + std::istringstream line(data); + std::string word; + size_t index; + line >> word; + + if ((level == 1) && (word.compare("*MATERIAL") == 0)) { + if ((line >> index) && (line >> word) && (word.compare("{") == 0)) { + // add material to the ase material list + ase_materiallist[index] = read_material(is); + con_debug << " " << name() << " " << "*MATERIAL " << index << " " << ase_materiallist[index]->name() << std::endl; + } + + } else { + do { + if (word.compare("{") == 0) { + level++; + } else if (word.compare("}") == 0) { + level--; + } + } while (line >> word); + } + + if (level == 0) + return true; + } + + return false; +} + +bool ASEFile::read_mesh_vertex_list(std::istream &is) +{ char data[1024]; memset(data, 0, sizeof(data)); @@ -89,8 +181,6 @@ bool ASEFile::read_mesh_vertex_list(std::istream &is) line >> firstword; if (firstword.compare("}") == 0) { - //con_debug << " " << count << " mesh vertices" << std::endl; - return true; } else if (firstword.compare("*MESH_VERTEX") == 0) { @@ -108,7 +198,7 @@ bool ASEFile::read_mesh_vertex_list(std::istream &is) ase_minbbox[i] = (*v)[i]; } } - count++; + ase_vertexcount++; } } } @@ -118,8 +208,6 @@ bool ASEFile::read_mesh_vertex_list(std::istream &is) bool ASEFile::read_mesh_face_list(std::istream &is) { - size_t count = 0; - char data[1024]; memset(data, 0, sizeof(data)); @@ -130,7 +218,6 @@ bool ASEFile::read_mesh_face_list(std::istream &is) line >> word; if (word.compare("}") == 0) { - //con_debug << " " << count << " mesh faces" << std::endl; return true; } else if (word.compare("*MESH_FACE") == 0) { @@ -152,7 +239,7 @@ bool ASEFile::read_mesh_face_list(std::istream &is) Triangle *triangle = new Triangle(*ase_vertexlist[a], *ase_vertexlist[b], *ase_vertexlist[c]); ase_facelist[index] = triangle; } - count++; + ase_facecount++; } } @@ -227,7 +314,7 @@ bool ASEFile::read_mesh_tvertex_list(std::istream &is) line >> firstword; if (firstword.compare("}") == 0) { - //con_debug << " " << count << " texture vertices" << std::endl; + con_debug << " " << count << " texture vertices" << std::endl; return true; } else if (firstword.compare("*MESH_TVERT") == 0) { @@ -258,10 +345,11 @@ bool ASEFile::read_mesh_tface_list(std::istream &is) line >> firstword; if (firstword.compare("}") == 0) { - //con_debug << " " << count << " face texture coordinates" << std::endl; + con_debug << " " << count << " face texture coordinates" << std::endl; return true; } else if (firstword.compare("*MESH_TFACE") == 0) { + // face texture coordinates size_t index, a, b, c; if (line >> index >> a >> b >> c) { Triangle *triangle = ase_facelist[index]; @@ -300,31 +388,31 @@ bool ASEFile::read_mesh(std::istream &is) if ((level == 1) && (word.compare("*MESH_VERTEX_LIST") == 0)) { if ((line >> word) && (word.compare("{") == 0)) { - //con_debug << " " << name() << " *MESH_VERTEX_LIST" << std::endl; + con_debug << " " << name() << " *MESH_VERTEX_LIST" << std::endl; read_mesh_vertex_list(is); } } else if ((level == 1) && (word.compare("*MESH_FACE_LIST") == 0)) { if ((line >> word) && (word.compare("{") == 0)) { - //con_debug << " " << name() << " *MESH_FACE_LIST" << std::endl; + con_debug << " " << name() << " *MESH_FACE_LIST" << std::endl; read_mesh_face_list(is); } } else if ((level == 1) && (word.compare("*MESH_NORMALS") == 0)) { if ((line >> word) && (word.compare("{") == 0)) { - //con_debug << " " << name() << " *MESH_NORMALS" << std::endl; + con_debug << " " << name() << " *MESH_NORMALS" << std::endl; read_mesh_normals(is); } } else if ((level == 1) && (word.compare("*MESH_TVERTLIST") == 0)) { if ((line >> word) && (word.compare("{") == 0)) { - //con_debug << " " << name() << " *MESH_TVERTLIST" << std::endl; + con_debug << " " << name() << " *MESH_TVERTLIST" << std::endl; read_mesh_tvertex_list(is); } } else if ((level == 1) && (word.compare("*MESH_TFACELIST") == 0)) { if ((line >> word) && (word.compare("{") == 0)) { - //con_debug << " " << name() << " *MESH_TFACELIST" << std::endl; + con_debug << " " << name() << " *MESH_TFACELIST" << std::endl; read_mesh_tface_list(is); } @@ -346,24 +434,59 @@ bool ASEFile::read_mesh(std::istream &is) return false; } +bool ASEFile::clear_geom() +{ + // delete texture vertices + for (VertexList::iterator it = ase_tvertexlist.begin(); it != ase_tvertexlist.end(); it++) { + delete(*it).second; + } + ase_tvertexlist.clear(); + + // delete geometry vertices + for (VertexList::iterator it = ase_vertexlist.begin(); it != ase_vertexlist.end(); it++) { + delete(*it).second; + } + ase_vertexlist.clear(); + + // delete faces + for (FaceList::iterator it = ase_facelist.begin(); it != ase_facelist.end(); it++) { + delete(*it).second; + } + ase_facelist.clear(); + + return true; +} + bool ASEFile::read_geom(std::istream &is) { char data[1024]; memset(data, 0, sizeof(data)); int level = 1; + Material *material = 0; while (is.getline(data, sizeof(data) - 1)) { std::istringstream line(data); std::string word; + size_t index; line >> word; if ((level == 1) && (word.compare("*MESH") == 0)) { if ((line >> word) && (word.compare("{") == 0)) { - //con_debug << " " << name() << " " << "*MESH" << std::endl; + con_debug << " " << name() << " " << "*MESH" << std::endl; read_mesh(is); } - + } else if ((level == 1) && (word.compare("*MATERIAL_REF") == 0)) { + // the material to use for this GEOMOBJECT + if (line >> index) { + con_debug << " " << name() << " " << "*MATERIAL_REF " << index << std::endl; + + // find the Material for index + MaterialList::iterator it = ase_materiallist.find(index); + if (it != ase_materiallist.end()) { + material = (*it).second; + } + } } else { do { if (word.compare("{") == 0) { @@ -374,10 +497,29 @@ bool ASEFile::read_geom(std::istream &is) } while (line >> word); } - if (level == 0) + if (level == 0) { + + // import only if the material is defined and there actually are triangles to import + if (material && ase_facelist.size()) { + // load GEOMOBJECT triangles in a model fragment + Fragment *fragment = new Fragment(Fragment::Triangles, material); + ase_fragmentgroup->add_fragment(fragment); + + for (FaceList::iterator it = ase_facelist.begin(); it != ase_facelist.end(); it++) { + Triangle *triangle = (*it).second; + fragment->add_vertex((triangle->v0() * SCALE) , triangle->n0(), triangle->t0(), false); + fragment->add_vertex((triangle->v1() * SCALE) , triangle->n1(), triangle->t1(), false); + fragment->add_vertex((triangle->v2() * SCALE) , triangle->n2(), triangle->t2(), false); + } + } + + // clear geometry data + clear_geom(); return true; + } } + clear_geom(); return false; } @@ -400,16 +542,22 @@ bool ASEFile::read() if (word.compare("*GEOMOBJECT") == 0) { if ((line >> word) && (word.compare("{") == 0)) { - //con_debug << " " << name() << " " << "*GEOMOBJECT" << std::endl; + con_debug << " " << name() << " " << "*GEOMOBJECT" << std::endl; read_geom(asefile_ifs); } + } else if (word.compare("*MATERIAL_LIST") == 0) { + + if ((line >> word) && (word.compare("{") == 0)) { + con_debug << " " << name() << " " << "*MATERIAL_LIST" << std::endl; + read_material_list(asefile_ifs); + } } } return true; } -Model * ASEFile::load(const std::string &name) +Model *ASEFile::load(const std::string &name) { ASEFile asefile(name); @@ -421,55 +569,31 @@ Model * ASEFile::load(const std::string &name) return 0; } + /* this is cleared by clear_geom() if (!asefile.ase_facelist.size()) return 0; - + */ + + // create a new model Model *model = new Model(name); - // default material - Material *material = Material::find(name); - if (!material) { - material = new Material(name); - Material::add(material); - //material->set_flags(Material::Texture); - material->set_texture(material->name()); + // set bounding box properties + math::Vector3f origin(0.0f, 0.0f, 0.0f); + model->set_origin(origin); + model->model_minbbox.assign (asefile.ase_minbbox * SCALE); + model->model_maxbbox.assign (asefile.ase_maxbbox * SCALE); + model->set_radius(math::max(model->model_minbbox.length(), model->model_maxbbox.length())); + + for (FragmentGroup::iterator fit = asefile.fragmentgroup()->begin(); fit != asefile.fragmentgroup()->end(); fit++) { + Fragment *fragment = (*fit); + model->model_tris_count += fragment->structural_size() + fragment->detail_size(); } + model->add_group(asefile.fragmentgroup()); - // a single fragment for all the model triangles - Fragment *fragment = new Fragment(Fragment::Triangles, material); - FragmentGroup *group = new FragmentGroup(); - group->set_type(FragmentGroup::None); - group->add_fragment(fragment); - - // calculate model center - math::Vector3f center((asefile.ase_minbbox + asefile.ase_maxbbox) * 0.5f); - - const float scale = SCALE; - //const float scale = 0.125f; - - // caculate bounding box - model->model_minbbox = (asefile.ase_minbbox - center) * scale; - model->model_maxbbox = (asefile.ase_maxbbox - center) * scale; - model->set_radius(model->model_maxbbox.length()); - model->set_origin(center * scale); - - // load the model faces into the fragment - for (FaceList::iterator it = asefile.ase_facelist.begin(); it != asefile.ase_facelist.end(); it++) { - Triangle *triangle = (*it).second; - - fragment->add_vertex((triangle->v0() - center) * scale , triangle->n0(), triangle->t0(), false); - fragment->add_vertex((triangle->v1() - center) * scale , triangle->n1(), triangle->t1(), false); - fragment->add_vertex((triangle->v2() - center) * scale , triangle->n2(), triangle->t2(), false); - - model->model_tris_count++; - } - - model->add_group(group); - - con_debug << " " << asefile.name() << " " << asefile.ase_vertexlist.size() << " vertices " << - model->model_tris_detail_count << "/" << model->model_tris_count << " detail/tris" << std::endl; - + con_debug << " " << asefile.name() << " " << asefile.vertexcount() << " vertices " << asefile.facecount() << " faces " << std::endl; + return model; } } // namespace model + diff --git a/src/model/asefile.h b/src/model/asefile.h index e129ec0..d8e3aea 100644 --- a/src/model/asefile.h +++ b/src/model/asefile.h @@ -10,11 +10,14 @@ #include "math/vector3f.h" #include "model/model.h" +#include "model/material.h" +#include "model/fragment.h" #include "model/triangle.h" #include "filesystem/filestream.h" #include #include +#include namespace model { @@ -31,14 +34,34 @@ public: static Model *load(std::string const &name); private: + /** + * @brief type definition for a list of materials in the ASE file + */ + typedef std::map MaterialList; + /** + * @brief type definition for a list of vertices in a GEOMOBJECT + */ typedef std::map VertexList; + /** + * @brief type definition for a list of faces in a GEOMOBJECT + */ typedef std::map FaceList; ASEFile(std::string const &name); ~ASEFile(); + /** + * @brief read *MATERIAL + */ + Material *read_material(std::istream &is); + + /** + * @brief read *MATERIAL_LIST + */ + bool read_material_list(std::istream &is); + /** * @brief read *MESH_NORMALS */ @@ -74,6 +97,11 @@ private: */ bool read_geom(std::istream &is); + /** + * @brief clear *GEOMOBJECT + */ + bool clear_geom(); + /** * @brief read the .ase header */ @@ -92,6 +120,18 @@ private: return asefile_ifs.is_open(); } + inline size_t vertexcount() const { + return ase_vertexcount; + } + + inline size_t facecount() const { + return ase_facecount; + } + + inline FragmentGroup *fragmentgroup() { + return ase_fragmentgroup; + } + std::string asefile_name; filesystem::IFileStream asefile_ifs; @@ -102,9 +142,16 @@ private: FaceList ase_facelist; + MaterialList ase_materiallist; + math::Vector3f ase_maxbbox; math::Vector3f ase_minbbox; + + FragmentGroup *ase_fragmentgroup; + + size_t ase_vertexcount; + size_t ase_facecount; }; } // namespace model -- cgit v1.2.3