Project::OSiRiON - Git repositories
Project::OSiRiON
News . About . Screenshots . Downloads . Forum . Wiki . Tracker . Git
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStijn Buys <ingar@osirion.org>2011-08-25 22:04:42 +0000
committerStijn Buys <ingar@osirion.org>2011-08-25 22:04:42 +0000
commit431421c7e626b50186fc54542db3967cde844a66 (patch)
tree31eddc445b1227e77e12f628305e9dacb3f81c39 /src/model/objfile.cc
parentbdd1e564921d7001c218d1e7bcde925057f9b3dc (diff)
OBJ model support, by Thorn
Diffstat (limited to 'src/model/objfile.cc')
-rw-r--r--src/model/objfile.cc353
1 files changed, 353 insertions, 0 deletions
diff --git a/src/model/objfile.cc b/src/model/objfile.cc
new file mode 100644
index 0000000..aa6b6cf
--- /dev/null
+++ b/src/model/objfile.cc
@@ -0,0 +1,353 @@
+/*
+ model/objfile.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/objfile.h"
+
+#include <sstream>
+#include <cstring>
+
+/* NOTE: Does NOT support reverse indexes. Cannot find an example
+ of this in use, or a program that will export using them.
+*/
+
+namespace model
+{
+
+// max geometry bounds
+const float MAX_BOUNDS = 16384.0f;
+
+OBJFile::OBJFile(std::string const &name)
+{
+ objfile_name.append(name);
+ objfile_name.append(".obj");
+ objfile_ifs.open(objfile_name);
+
+ obj_box.assign(MAX_BOUNDS, - MAX_BOUNDS);
+
+ // a single fragmentgroup will contain all the model polygons
+ obj_fragmentgroup = new FragmentGroup();
+ obj_fragmentgroup->set_type(FragmentGroup::None);
+
+ // reset counters
+ obj_normalcount = 0;
+}
+
+OBJFile::~OBJFile()
+{
+ for (VertexList::iterator it = obj_vertexlist.begin(); it != obj_vertexlist.end(); it++) {
+ delete(*it).second;
+ }
+ obj_vertexlist.clear();
+
+ for (NormalList::iterator it = obj_normallist.begin(); it != obj_normallist.end(); it++) {
+ delete(*it).second;
+ }
+ obj_normallist.clear();
+
+ for (UVList::iterator it = obj_uvlist.begin(); it != obj_uvlist.end(); it++) {
+ delete(*it).second;
+ }
+ obj_uvlist.clear();
+
+ for (TriList::iterator it = obj_trilist.begin(); it != obj_trilist.end(); it++) {
+ delete(*it).second;
+ }
+ obj_trilist.clear();
+
+ for (QuadList::iterator it = obj_quadlist.begin(); it != obj_quadlist.end(); it++) {
+ delete(*it).second;
+ }
+ obj_quadlist.clear();
+
+ if (objfile_ifs.is_open())
+ objfile_ifs.close();
+}
+
+bool OBJFile::read()
+{
+ char data[1024];
+ memset(data, 0, sizeof(data));
+
+ math::Vector3f zero;
+
+ size_t current_m = 0;
+
+ Fragment *fragment = 0;
+ Material *material = 0;
+
+ while (objfile_ifs.getline(data, sizeof(data) - 1)) {
+ std::istringstream line(data);
+
+ std::string word;
+ line >> word;
+
+ if( word.compare("usemtl") == 0) { /* material definition */
+
+ std::string materialname;
+ material = 0;
+
+ if(line >> materialname) {
+ for(MaterialList::iterator it = obj_materiallist.begin(); it != obj_materiallist.end(); ++it) {
+ if( (*it).second->name() == materialname) {
+ material = (*it).second;
+ current_m = (*it).first;
+ break;
+ }
+ }
+
+ if(!material) {
+ material = Material::find(materialname);
+
+ if(material)
+ obj_materiallist[obj_materiallist.size()] = material;
+ else {
+ material = new Material(materialname);
+ Material::add(material);
+ material->set_texture(materialname);
+
+ obj_materiallist[obj_materiallist.size()] = material;
+ }
+ current_m = obj_materiallist.size()-1;
+ }
+ }
+ else
+ con_warn << "Invalid material definition" << std::endl;
+
+
+ } else if( word.compare("v") == 0) { /* New wertex */
+ float x, y, z;
+ line >> x >> y >> z;
+
+ math::Vector3f *v = new math::Vector3f(x, y, z);
+ obj_vertexlist[obj_vertexlist.size()] = v;
+ obj_box.expand(*v * SCALE);
+
+ } else if( word.compare("vt") == 0) { /* wertex texture coordinate */
+ float u, v;
+ line >> u >> v;
+
+ math::Vector2f *uv = new math::Vector2f(u, v);
+ obj_uvlist[obj_uvlist.size()] = uv;
+
+ } else if( word.compare("vn") == 0) { /* wertex wormal */
+ float x, y, z;
+ line >> x >> y >> z;
+
+ math::Vector3f *nm = new math::Vector3f(x, y, z);
+ nm->normalize();
+ obj_normallist[obj_normalcount] = nm;
+ obj_normalcount++;
+
+ } else if( word.compare("f") == 0) { /* Face/Polygon */
+ size_t v[4];
+ size_t uv[4];
+ size_t vn[4];
+
+ bool have_vn[4], have_uv[4];
+ size_t nslash;
+
+ std::string strbuf(line.str());
+ strbuf.erase(0,2); //remove "f "
+
+ std::stringstream tmp(strbuf);
+
+ std::vector<std::string> points;
+ int i=0;
+ while(!tmp.eof()) {
+ nslash = 0;
+
+ have_vn[i] = 0;
+ have_uv[i] = 0;
+
+ std::string point;
+ tmp >> point;
+
+ if(point.compare(" ") == 0) //bordercase for space at end of face definition
+ continue;
+
+ for(size_t c=0; c<point.length(); c++) {
+ if(point[c] == '/') {
+ nslash++;
+ have_uv[i]=true;
+ point[c] = ' ';
+ }
+ if(point[c] == ' ' && point[c+1] == '/') {
+ have_uv[i]=false;
+ have_vn[i]=true;
+ nslash=2;
+ point.erase(c+1,1);
+ }
+ }
+
+ if(nslash==2 && have_vn[i] == false) {
+ have_vn[i] = true;
+ have_uv[i] = true;
+ }
+ points.push_back(point);
+
+ std::stringstream tmp2(point);
+ tmp2 >> v[i];
+ if(have_uv[i]) tmp2 >> uv[i];
+ if(have_vn[i]) tmp2 >> vn[i];
+ i++;
+ }
+
+ if(points.size() != 4 && points.size() != 3) {
+ con_warn << "Warning! " << objfile_name << ": Faces without 3 or 4 vertices will be ignored!" << std::endl;
+ points.clear();
+ continue;
+ }
+
+ math::Vector3f *v0 = obj_vertexlist.find(v[0]-1)->second;
+ math::Vector3f *v1 = obj_vertexlist.find(v[1]-1)->second;
+ math::Vector3f *v2 = obj_vertexlist.find(v[2]-1)->second;
+ math::Vector3f *v3 = obj_vertexlist.find(v[3]-1)->second;
+
+ math::Vector3f *n0 = obj_normallist[vn[0]-1];
+ math::Vector3f *n1 = obj_normallist[vn[1]-1];
+ math::Vector3f *n2 = obj_normallist[vn[2]-1];
+ math::Vector3f *n3 = obj_normallist[vn[3]-1];
+
+ math::Vector2f *t0 = obj_uvlist.find(uv[0]-1)->second;
+ math::Vector2f *t1 = obj_uvlist.find(uv[1]-1)->second;
+ math::Vector2f *t2 = obj_uvlist.find(uv[2]-1)->second;
+ math::Vector2f *t3 = obj_uvlist.find(uv[3]-1)->second;
+
+ if(points.size() == 3) {
+ if(!v0 || !v1 || !v2) {
+ con_warn << "Warning! " << objfile_name << ": Invalid vertex!" << std::endl;
+ continue;
+ }
+
+ Triangle *triangle = new Triangle(*v0, *v1, *v2);
+
+ if(!n0) n0 = new math::Vector3f(normal(triangle->v0(), triangle->v1(), triangle->v2()));
+ if(!n1) n1 = new math::Vector3f(normal(triangle->v1(), triangle->v2(), triangle->v0()));
+ if(!n2) n2 = new math::Vector3f(normal(triangle->v2(), triangle->v0(), triangle->v1()));
+
+ triangle->n0().assign(n0->x(), n0->y(), n0->z());
+ triangle->n1().assign(n1->x(), n1->y(), n1->z());
+ triangle->n2().assign(n2->x(), n2->y(), n2->z());
+
+ if(t0) triangle->t0().assign(t0->x(), 1.0 - t0->y());
+ if(t1) triangle->t1().assign(t1->x(), 1.0 - t1->y());
+ if(t2) triangle->t2().assign(t2->x(), 1.0 - t2->y());
+
+ std::pair<size_t, Triangle *> poly(current_m, triangle);
+ obj_trilist.push_back(poly);
+
+ } else if(points.size() == 4) {
+
+ if(!v0 || !v1 || !v2 || !v3) {
+ con_warn << "Warning! " << objfile_name << ": Invalid vertex!" << std::endl;
+ continue;
+ }
+
+ Quad *quad = new Quad(*v0, *v1, *v2, *v3, zero);
+
+ if(!n0) n0 = new math::Vector3f(normal(quad->v0(), quad->v1(), quad->v3()));
+ if(!n1) n1 = new math::Vector3f(normal(quad->v1(), quad->v2(), quad->v0()));
+ if(!n2) n2 = new math::Vector3f(normal(quad->v2(), quad->v3(), quad->v1()));
+ if(!n3) n3 = new math::Vector3f(normal(quad->v3(), quad->v0(), quad->v2()));
+
+ quad->n0().assign(n0->x(), n0->y(), n0->z());
+ quad->n1().assign(n1->x(), n1->y(), n1->z());
+ quad->n2().assign(n2->x(), n2->y(), n2->z());
+ quad->n3().assign(n3->x(), n3->y(), n3->z());
+
+ if(t0) quad->t0().assign(t0->x(), 1.0 - t0->y());
+ if(t1) quad->t1().assign(t1->x(), 1.0 - t1->y());
+ if(t2) quad->t2().assign(t2->x(), 1.0 - t2->y());
+ if(t3) quad->t3().assign(t3->x(), 1.0 - t3->y());
+
+ std::pair<size_t, Quad *> poly(current_m, quad);
+ obj_quadlist.push_back(poly);
+ }
+ }
+ }
+
+ //Go through tri and quad lists and create fragments for each material
+ size_t total_m = obj_materiallist.size();
+ for(size_t i = 0; i <= total_m; i++) {
+ material = obj_materiallist[i];
+ fragment = new Fragment(Fragment::Triangles, material);
+
+ for(TriList::iterator it = obj_trilist.begin(); it != obj_trilist.end(); ++it) {
+ if((*it).first == i) {
+ fragment->add_vertex(((*it).second->v0() * SCALE) , (*it).second->n0(), (*it).second->t0(), false);
+ fragment->add_vertex(((*it).second->v1() * SCALE) , (*it).second->n1(), (*it).second->t1(), false);
+ fragment->add_vertex(((*it).second->v2() * SCALE) , (*it).second->n2(), (*it).second->t2(), false);
+ }
+ }
+
+ if( fragment->structural_size() + fragment->detail_size() > 0 )
+ obj_fragmentgroup->add_fragment(fragment);
+
+ fragment = new Fragment(Fragment::Quads, material);
+
+ for(QuadList::iterator it = obj_quadlist.begin(); it != obj_quadlist.end(); ++it) {
+ if((*it).first == i) {
+ fragment->add_vertex(((*it).second->v0() * SCALE) , (*it).second->n0(), (*it).second->t0(), false);
+ fragment->add_vertex(((*it).second->v1() * SCALE) , (*it).second->n1(), (*it).second->t1(), false);
+ fragment->add_vertex(((*it).second->v2() * SCALE) , (*it).second->n2(), (*it).second->t2(), false);
+ fragment->add_vertex(((*it).second->v3() * SCALE) , (*it).second->n3(), (*it).second->t3(), false);
+ }
+ }
+
+ if( fragment->structural_size() + fragment->detail_size() > 0 )
+ obj_fragmentgroup->add_fragment(fragment);
+ }
+
+ return true;
+}
+
+Model *OBJFile::load(const std::string &name)
+{
+ OBJFile objfile(name);
+
+ if (!objfile.is_open()) {
+ return 0;
+ }
+
+ if (!objfile.read()) {
+ return 0;
+ }
+
+ if (!objfile.fragmentgroup()->size())
+ return 0;
+
+ // create a new model
+ Model *model = new Model(name);
+
+ // center model around (0,0,0) and set the bounding box
+ math::Vector3f obj_center((objfile.box().min() + objfile.box().max()) * 0.5f);
+ model->model_box.assign(
+ objfile.box().min() - obj_center,
+ objfile.box().max() - obj_center
+ );
+ model->set_radius(model->box().max().length());
+ model->set_origin(obj_center * -1.0f);
+
+ objfile.fragmentgroup()->set_location(obj_center * -1.0f);
+
+ for (FragmentGroup::Fragments::const_iterator fit = objfile.fragmentgroup()->fragments().begin(); fit != objfile.fragmentgroup()->fragments().end(); fit++) {
+ const Fragment *fragment = (*fit);
+
+ if(fragment->type() == Fragment::Triangles)
+ model->model_tris_count += (fragment->structural_size() + fragment->detail_size()) / 3;
+ else
+ model->model_quad_count += (fragment->structural_size() + fragment->detail_size()) / 4;
+ }
+
+ model->add_group(objfile.fragmentgroup());
+
+ con_debug << " " << objfile.name() << " " << objfile.vertexcount() << " vertices " << model->model_tris_count << " triangles " << model->model_quad_count << " quads" << std::endl;
+
+ return model;
+}
+
+} // namespace model