/* model/asefile.cc This file is part of the Osirion project and is distributed under the terms of the GNU General Public License version 2 */ #include "sys/sys.h" #include "model/asefile.h" #include #include namespace model { // max geometry bounds const float MAX_BOUNDS = 16384.0f; 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; } } ASEFile::~ASEFile() { for (VertexList::iterator it = ase_tvertexlist.begin(); it != ase_tvertexlist.end(); it++) { delete(*it).second; } ase_tvertexlist.clear(); for (VertexList::iterator it = ase_vertexlist.begin(); it != ase_vertexlist.end(); it++) { delete(*it).second; } ase_vertexlist.clear(); for (FaceList::iterator it = ase_facelist.begin(); it != ase_facelist.end(); it++) { delete(*it).second; } ase_facelist.clear(); if (asefile_ifs.is_open()) asefile_ifs.close(); } bool ASEFile::read_header(std::istream &is) { if (!is.good()) { return false; } char data[1024]; memset(data, 0, sizeof(data)); if (!is.getline(data, sizeof(data) - 1)) { return false; } std::istringstream line(data); std::string word; line >> word; if (!word.compare("*3DSMAX_ASCIIEXPORT") == 0) { return false; } return true; } bool ASEFile::read_mesh_vertex_list(std::istream &is) { size_t count = 0; char data[1024]; memset(data, 0, sizeof(data)); while (is.getline(data, sizeof(data) - 1)) { std::istringstream line(data); std::string firstword; line >> firstword; if (firstword.compare("}") == 0) { //con_debug << " " << count << " mesh vertices" << std::endl; return true; } else if (firstword.compare("*MESH_VERTEX") == 0) { size_t index; float x, y, z; if (line >> index >> x >> y >> z) { math::Vector3f *v = new math::Vector3f(x, y, z); ase_vertexlist[index] = v; for (size_t i = 0; i < 3; i++) { if ((*v)[i] > ase_maxbbox[i]) { ase_maxbbox[i] = (*v)[i]; } if ((*v)[i] < ase_minbbox[i]) { ase_minbbox[i] = (*v)[i]; } } count++; } } } return false; } bool ASEFile::read_mesh_face_list(std::istream &is) { size_t count = 0; char data[1024]; memset(data, 0, sizeof(data)); while (is.getline(data, sizeof(data) - 1)) { std::istringstream line(data); std::string word; line >> word; if (word.compare("}") == 0) { //con_debug << " " << count << " mesh faces" << std::endl; return true; } else if (word.compare("*MESH_FACE") == 0) { std::string facestr; size_t a, b, c; if ((line >> facestr) && (line >> word) && (line >> a) && (line >> word) && (line >> b) && (line >> word) && (line >> c)) { if (facestr.size() && facestr[facestr.size()-1] == ':') { facestr.erase(facestr.size() - 1); } size_t index; std::istringstream faceindexstr(facestr); faceindexstr >> index; Triangle *triangle = new Triangle(*ase_vertexlist[a], *ase_vertexlist[b], *ase_vertexlist[c]); ase_facelist[index] = triangle; } count++; } } return false; } bool ASEFile::read_mesh_normals(std::istream &is) { char data[1024]; memset(data, 0, sizeof(data)); size_t count = 0; size_t index = 0; size_t vertindex = 0; float x, y, z; FaceList::iterator it; while (is.getline(data, sizeof(data) - 1)) { std::istringstream line(data); std::string firstword; line >> firstword; if (firstword.compare("}") == 0) { //con_debug << " " << count << " face normals" << std::endl; return true; } else if (firstword.compare("*MESH_FACENORMAL") == 0) { if (line >> index >> x >> y >> z) { it = ase_facelist.find(index); if (it != ase_facelist.end()) { (*it).second->normal().assign(x, y, z); count++; } else { con_warn << " could not find face " << index << std::endl; } vertindex = 0; } else { it = ase_facelist.end(); } } else if (firstword.compare("*MESH_VERTEXNORMAL") == 0) { if ((it != ase_facelist.end()) && (line >> index >> x >> y >> z)) { if (vertindex == 0) { (*it).second->n0().assign(x, y, z); } else if (vertindex == 1) { (*it).second->n1().assign(x, y, z); } else if (vertindex == 2) { (*it).second->n2().assign(x, y, z); } vertindex++; } } } return false; } bool ASEFile::read_mesh_tvertex_list(std::istream &is) { size_t count = 0; char data[1024]; memset(data, 0, sizeof(data)); while (is.getline(data, sizeof(data) - 1)) { std::istringstream line(data); std::string firstword; line >> firstword; if (firstword.compare("}") == 0) { //con_debug << " " << count << " texture vertices" << std::endl; return true; } else if (firstword.compare("*MESH_TVERT") == 0) { size_t index; float x, y, z; if (line >> index >> x >> y >> z) { math::Vector3f *v = new math::Vector3f(x, y, z); ase_tvertexlist[index] = v; count++; } } } return false; } bool ASEFile::read_mesh_tface_list(std::istream &is) { size_t count = 0; char data[1024]; memset(data, 0, sizeof(data)); while (is.getline(data, sizeof(data) - 1)) { std::istringstream line(data); std::string firstword; line >> firstword; if (firstword.compare("}") == 0) { //con_debug << " " << count << " face texture coordinates" << std::endl; return true; } else if (firstword.compare("*MESH_TFACE") == 0) { size_t index, a, b, c; if (line >> index >> a >> b >> c) { Triangle *triangle = ase_facelist[index]; math::Vector3f *t0 = ase_tvertexlist[a]; math::Vector3f *t1 = ase_tvertexlist[b]; math::Vector3f *t2 = ase_tvertexlist[c]; if (triangle) { if (t0) triangle->t0().assign(t0->x(), 1.0f - t0->y()); if (t1) triangle->t1().assign(t1->x(), 1.0f - t1->y()); if (t2) triangle->t2().assign(t2->x(), 1.0f - t2->y()); } count++; } } } return false; } bool ASEFile::read_mesh(std::istream &is) { char data[1024]; memset(data, 0, sizeof(data)); int level = 1; ase_vertexlist.clear(); while (is.getline(data, sizeof(data) - 1)) { std::istringstream line(data); std::string word; line >> word; if ((level == 1) && (word.compare("*MESH_VERTEX_LIST") == 0)) { if ((line >> word) && (word.compare("{") == 0)) { //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; 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; 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; 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; read_mesh_tface_list(is); } } 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_geom(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; line >> word; if ((level == 1) && (word.compare("*MESH") == 0)) { if ((line >> word) && (word.compare("{") == 0)) { //con_debug << " " << name() << " " << "*MESH" << std::endl; read_mesh(is); } } 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() { if (!read_header(asefile_ifs)) { con_warn << name() << ": not a valid ASE file!\n"; return 0; } char data[1024]; memset(data, 0, sizeof(data)); while (asefile_ifs.getline(data, sizeof(data) - 1)) { std::istringstream line(data); std::string word; line >> word; if (word.compare("*GEOMOBJECT") == 0) { if ((line >> word) && (word.compare("{") == 0)) { //con_debug << " " << name() << " " << "*GEOMOBJECT" << std::endl; read_geom(asefile_ifs); } } } return true; } Model * ASEFile::load(const std::string &name) { ASEFile asefile(name); if (!asefile.is_open()) { return 0; } if (!asefile.read()) { return 0; } if (!asefile.ase_facelist.size()) return 0; 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()); } // 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; return model; } } // namespace model