Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

obj2sm.C

Go to the documentation of this file.
00001 /********************************************************************************
00002  * obj2sm:
00003  *
00004  *   Convert .obj file to .sm file. 
00005  *
00006  *   Reads obj file from stdin, writes .sm file to stdout.
00007  *
00008  *   Usage: % obj2sm < model.obj > model.sm
00009  *
00010  *   Preliminary version 1/2005:
00011  *      Reads vertices, texture coordinates, and triangles.
00012  *      Ignores everything else.
00013  *
00014  *   TODO: read material info and create patches with 
00015  *         textures and colors.
00016  *
00017  ********************************************************************************/
00018 
00019 /********************************************************************************
00020  * The descriptions of .obj and .mtl formats provided below are from:
00021  *
00022  *    http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/\
00023  *    directx9_c_Summer_04/directx/graphics/tutorialsandsamples/samples/\
00024  *    meshfromobj.asp
00025  *
00026  * See also: 
00027  *
00028  *    http://www.nada.kth.se/~asa/Ray/matlabobj.html#4    
00029  *    http://netghost.narod.ru/gff/graphics/summary/waveobj.htm
00030  *    http://astronomy.swin.edu.au/~pbourke/geomformats/obj/
00031  *
00032  ********************************************************************************/
00033 
00034 /********************************************************************************
00035  * .obj file:
00036  *
00037  * TOKEN                        MEANING
00038  *
00039  * v float float float          Vertex position v (x) (y) (z)
00040  * 
00041  * vn float float float         Vertex normal vn (normal x) (normal y) (normal z)
00042  * 
00043  * vt float float               Texture coordinate vt (tu) (tv)
00044  * 
00045  * f int int int f (v) (v) (v)  Faces are stored as a series of three vertices
00046  *                              in clockwise order. Vertices are described by
00047  *                              their position, optional texture coordinate, and
00048  *                              optional normal, encoded as indices into the
00049  *                              respective component lists.
00050  * 
00051  * f int/int int/int int/int    f (v)/(vt) (v)/(vt) (v)/(vt)
00052  * 
00053  * f int/int/int int/int/int int/int/int        
00054  *                              f (v)/(vt)/(vn) (v)/(vt)/(vn) (v)/(vt)/(vn)
00055  * 
00056  * mtllib string                Material file (MTL) mtllib (filename.mtl)
00057  *                              References the MTL file for this mesh. MTL files
00058  *                              contain illumination variables and texture
00059  *                              filenames.
00060  * 
00061  * usemtl string                Material selection usemtl (material name) Faces
00062  *                              which are listed after this point in the file
00063  *                              will use the selected material
00064  ********************************************************************************/
00065 
00066 /********************************************************************************
00067  * .mtl file:
00068  *
00069  * TOKEN                        MEANING
00070  * 
00071  * newmtl string                Material newmtl (material name). Begins a new
00072  *                              material description.
00073  * 
00074  * Ka float float float         Ambient color Ka (red) (green) (blue)
00075  * 
00076  * Kd float float float         Diffuse color Kd (red) (green) (blue)
00077  * 
00078  * Ks float float float         Specular color Ks (red) (green) (blue)
00079  * 
00080  * d float Tr float             Transparency Tr (alpha)
00081  * 
00082  * Ns int                       Shininess Ns (specular power)
00083  * 
00084  * illum int                    Illumination model illum (1 / 2); 1 if specular
00085  *                              disabled, 2 if specular enabled.
00086  * 
00087  * map_Kd string                Texture map_Kd (filename)
00088  ********************************************************************************/
00089 #include <string>
00090 #include <sstream>
00091 #include <limits>
00092 #include "mesh/lmesh.H"
00093 #include "std/config.H"
00094 
00095 static bool debug = Config::get_var_bool("DEBUG_OBJ2SM",false,true);
00096 
00097 inline void
00098 skip_line(istream& in)
00099 {
00100    in.ignore(numeric_limits<std::streamsize>::max(), '\n');
00101 }
00102 
00103 inline void
00104 read_vert(LMESH* mesh, istream& in)
00105 {
00106    double x, y, z;
00107    in >> x >> y >> z;
00108    skip_line(in);
00109    assert(mesh);
00110    mesh->add_vertex(Wpt(x,y,z));
00111 }
00112 
00113 inline void
00114 read_texcoord(UVpt_list& uvs, istream& in)
00115 {
00116    double u, v;
00117    in >> u >> v;
00118    skip_line(in);
00119    uvs += UVpt(u,v);
00120 }
00121 
00122 class vtn {
00123  public:
00124    int _v, _t, _n; // vertex, texture coordinate, and normal indices
00125 
00126    vtn(int v = -1, int t = -1, int n = -1) : _v(v), _t(t), _n(n) {}
00127 
00128    bool operator==(const vtn& v) const {
00129       return v._v == _v && v._t == _t && v._n == _n;
00130    }
00131 
00132    bool is_valid() const { return _v >= 0; }
00133 };
00134 
00135 inline istream&
00136 operator>>(istream& in, vtn& v)
00137 {
00138    // read a vertex index, texcoord index, and normal index.
00139    // the last two are optional.
00140 
00141    in >> v._v;
00142    v._v -= 1;   // do correction to start counting from 0, not 1
00143    if (in.peek() == '/') {
00144       char slash; 
00145       in >> slash >> v._t;
00146       v._t -= 1;
00147       if (in.peek() == '/') {
00148          in >> slash >> v._n;
00149          v._n -= 1;
00150       }
00151    }
00152    return in;
00153 }
00154 
00155 template <class T>
00156 inline bool
00157 all_valid_indices(const T& l, int i, int j, int k)
00158 {
00159    return l.valid_index(i) && l.valid_index(j) && l.valid_index(k);
00160 }
00161 
00162 template <class T>
00163 inline bool
00164 any_valid_indices(const T& l, int i, int j, int k)
00165 {
00166    return l.valid_index(i) || l.valid_index(j) || l.valid_index(k);
00167 }
00168 
00169 inline void
00170 add_tri(LMESH* mesh, CUVpt_list& uvs, const vtn& v1, const vtn& v2, const vtn& v3)
00171 {
00172    assert(mesh);
00173    assert(all_valid_indices(mesh->verts(), v1._v, v2._v, v3._v));
00174 
00175    if (all_valid_indices(uvs, v1._t, v2._t, v3._t)) {
00176       mesh->add_face(v1._v, v2._v, v3._v, uvs[v1._t], uvs[v2._t], uvs[v3._t]);
00177    } else {
00178       mesh->add_face(v1._v, v2._v, v3._v);
00179    }
00180 }
00181 
00182 inline void
00183 add_poly(LMESH* mesh, CUVpt_list& uvs, const ARRAY<vtn>& vtns)
00184 {
00185    assert(vtns.num() > 2);
00186 
00187    for (int k=2; k < vtns.num(); k++) {
00188       add_tri(mesh, uvs, vtns[0], vtns[k-1], vtns[k]);
00189    }
00190    // if it is a quad, mark the quad diagonal as "weak"
00191    if (vtns.num() == 4) {
00192       Bedge* e = lookup_edge(mesh->bv(vtns[0]._v), mesh->bv(vtns[2]._v));
00193       assert(e);
00194       e->set_bit(Bedge::WEAK_BIT);
00195    }
00196 }
00197 
00198 inline void
00199 read_face(LMESH* mesh, CUVpt_list& uvs, istream& in)
00200 {
00201    // The docs say each face has 3 vertices, but out there in the
00202    // world we're finding some with 4 or more.  So here we read
00203    // an arbitrary number of vertices following the "f" token,
00204    // then create a triangle fan for cases where there are > 3
00205    // vertices. If there are exactly 4 we make a quad.
00206 
00207    // use an istringstream to read vertices until the end of the line:
00208    ARRAY<vtn> vtns;
00209    const int BUF_SIZE = (1 << 12);
00210    char buf[BUF_SIZE] = {};
00211    in.getline(buf, BUF_SIZE);
00212    if (in.fail())
00213       return;
00214    istringstream is(buf);
00215    while (!(is.eof() || is.fail())) {
00216       vtn v;
00217       is >> v;
00218       if (v.is_valid())
00219          vtns += v;
00220       else break;
00221    }
00222 
00223    // create a polygon (triangle fan) from the vertices:
00224    if (vtns.num() < 3) {
00225       cerr << "read_face: error: read " << vtns.num() << " vertices for face" << endl;
00226       return;
00227    }
00228    add_poly(mesh, uvs, vtns);
00229 }
00230 
00231 static LMESHptr
00232 read_obj(istream& in)
00233 {
00234    UVpt_list    uvs;
00235 
00236    LMESHptr mesh = new LMESH;
00237 
00238    string token;
00239    while (!(in.eof() || in.fail())) {
00240       in >> token;
00241       if (token == "v") {
00242          read_vert(mesh, in);
00243       } else if (token == "vt") {
00244          read_texcoord(uvs, in);
00245       } else if (token == "f") {
00246          read_face(mesh, uvs, in);
00247       } else {
00248          // can add more cases...
00249          skip_line(in);
00250       }
00251    }
00252 
00253    return mesh;
00254 }
00255 
00256 int
00257 main(int argc, char *argv[])
00258 {
00259    if (argc != 1) {
00260       err_msg("usage: %s < mesh.obj > mesh.sm", argv[0]);
00261       return 1;
00262    }
00263 
00264    LMESHptr mesh = read_obj(cin);
00265    if (!mesh)
00266       return 1;
00267 
00268    if (Config::get_var_bool("JOT_RECENTER"))
00269       mesh->recenter();
00270 
00271    mesh->write_stream(cout);
00272 
00273    return 0;
00274 }
00275 
00276 // end of file obj2sm.C

Generated on Mon Sep 18 11:39:32 2006 for jot by  doxygen 1.4.4