Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

WavefrontDisplayDevice.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr
00003  *cr            (C) Copyright 1995-2011 The Board of Trustees of the
00004  *cr                        University of Illinois
00005  *cr                         All Rights Reserved
00006  *cr
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  * RCS INFORMATION:
00011  *
00012  *      $RCSfile: WavefrontDisplayDevice.C,v $
00013  *      $Author: johns $        $Locker:  $             $State: Exp $
00014  *      $Revision: 1.24 $       $Date: 2011/11/10 17:05:35 $
00015  *
00016  ***************************************************************************
00017  * DESCRIPTION:
00018  *
00019  *   Render to a Wavefront Object or "OBJ" file.
00020  *   This file format is one of the most universally supported 3-D model
00021  *   file formats, particular for animation software such as Maya, 
00022  *   3-D Studio, etc.  The file format is simple, but good enough for getting
00023  *   a lot of things done.  The Wavefront format only supports per-facet 
00024  *   colors and materials.  This code currently generates a fixed size set of 
00025  *   color/material entries and indexes into this set based on the active VMD
00026  *   color index.
00027  *
00028  ***************************************************************************/
00029 
00030 #include <stdio.h>
00031 #include <string.h>
00032 #include <math.h>
00033 #include <time.h>
00034 #include "WavefrontDisplayDevice.h"
00035 #include "Matrix4.h"
00036 #include "DispCmds.h"
00037 #include "Inform.h"
00038 #include "utilities.h"
00039 #include "config.h"    // for VMDVERSION string
00040 
00041 #define DASH_LENGTH 0.02f
00042 
00043 #define VMDGENMTLFILE 1
00044 
00045 static int replacefileextension(char * s, 
00046                                 const char * oldextension, 
00047                                 const char * newextension) {
00048   int sz, extsz;
00049   sz = strlen(s);
00050   extsz = strlen(oldextension);
00051 
00052   if (strlen(newextension) != strlen(oldextension))
00053    return -1;
00054 
00055   if (extsz > sz)
00056     return -1;
00057 
00058   if (strupncmp(s + (sz - extsz), oldextension, extsz)) {
00059     return -1;
00060   }
00061 
00062   strcpy(s + (sz - extsz), newextension);
00063 
00064   return 0;
00065 }
00066 
00067 static char * stripleadingfilepath(const char *fullpath) {
00068   int i, j;
00069   char *s = NULL;
00070   int len=strlen(fullpath);
00071   s = (char *) calloc(1, len+1);
00072 
00073   // find last '/' or '\' path separator character 
00074   // and copy remaining string
00075   for (i=0,j=0; i<len; i++) {
00076     if (fullpath[i] == '/' || fullpath[i] == '\\')
00077       j=i;
00078   }
00079 
00080   // char after the last path separator begins shortened path
00081   strcpy(s, fullpath+j+1);
00082 
00083   return s;
00084 }
00085 
00086 
00087 // constructor ... call the parent with the right values
00088 WavefrontDisplayDevice::WavefrontDisplayDevice(void) 
00089 : FileRenderer("Wavefront", "Wavefront (OBJ and MTL)", "vmdscene.obj", "true") { }
00090 
00091 // destructor
00092 WavefrontDisplayDevice::~WavefrontDisplayDevice(void) { }
00093 
00094 // emit a representation geometry group line
00095 void WavefrontDisplayDevice::beginrepgeomgroup(const char *s) {
00096   fprintf(outfile, "g %s\n", s);
00097 }
00098 
00099 // emit a comment line
00100 void WavefrontDisplayDevice::comment(const char *s) {
00101   fprintf(outfile, "# %s\n", s);
00102 }
00103 
00104 // draw a point
00105 void WavefrontDisplayDevice::point(float * spdata) {
00106   float vec[3];
00107   // transform the world coordinates
00108   (transMat.top()).multpoint3d(spdata, vec);
00109 
00110   // draw the sphere
00111   fprintf(outfile, "v %5f %5f %5f\n", vec[0], vec[1], -vec[2]);
00112   fprintf(outfile, "p -1\n");
00113 }
00114 
00115 // draw a line from a to b
00116 void WavefrontDisplayDevice::line(float *a, float*b) {
00117   int i, j, test;
00118   float dirvec[3], unitdirvec[3];
00119   float from[3], to[3], tmp1[3], tmp2[3];
00120   float len;
00121    
00122   if (lineStyle == ::SOLIDLINE) {
00123     // transform the world coordinates
00124     (transMat.top()).multpoint3d(a, from);
00125     (transMat.top()).multpoint3d(b, to);
00126 
00127     // draw the solid line
00128     fprintf(outfile, "v %5f %5f %5f\n", from[0], from[1], -from[2]);
00129     fprintf(outfile, "v %5f %5f %5f\n", to[0], to[1], -to[2]);
00130     fprintf(outfile, "l -1 -2\n");
00131   } else if (lineStyle == ::DASHEDLINE) {
00132      // transform the world coordinates
00133     (transMat.top()).multpoint3d(a, tmp1);
00134     (transMat.top()).multpoint3d(b, tmp2);
00135 
00136     // how to create a dashed line
00137     for(i=0; i<3; i++) {
00138       dirvec[i] = tmp2[i] - tmp1[i];  // vector from a to b
00139     }
00140     len = sqrtf(dirvec[0]*dirvec[0] + dirvec[1]*dirvec[1] + dirvec[2]*dirvec[2])
00141 ;
00142     for(i=0;i<3;i++) {
00143       unitdirvec[i] = dirvec[i] / sqrtf(len); // unit vector from a to b
00144     }
00145           
00146     test = 1;
00147     i = 0;
00148     while(test == 1) {
00149       for(j=0;j<3;j++) {
00150         from[j] = (float) (tmp1[j] + (2*i    )*DASH_LENGTH*unitdirvec[j]);
00151           to[j] = (float) (tmp1[j] + (2*i + 1)*DASH_LENGTH*unitdirvec[j]);
00152       }
00153 
00154       if (fabsf(tmp1[0] - to[0]) >= fabsf(dirvec[0])) {
00155         for(j=0;j<3;j++)
00156           to[j] = tmp2[j];
00157         test = 0;
00158       }
00159 
00160       // draw the solid line dash
00161       fprintf(outfile, "v %5f %5f %5f\n", from[0], from[1], -from[2]);
00162       fprintf(outfile, "v %5f %5f %5f\n", to[0], to[1], -to[2]);
00163       fprintf(outfile, "l -1 -2\n");
00164       i++;
00165     }
00166   } else {
00167     msgErr << "WavefrontDisplayDevice: Unknown line style "
00168            << lineStyle << sendmsg;
00169   }
00170 }
00171 
00172 
00173 
00174 
00175 void WavefrontDisplayDevice::triangle(const float *v1, const float *v2, const float *v3, 
00176                                       const float *n1, const float *n2, const float *n3) {
00177   float a[3], b[3], c[3];
00178   float norm1[3], norm2[3], norm3[3];
00179 
00180   // transform the world coordinates
00181   (transMat.top()).multpoint3d(v1, a);
00182   (transMat.top()).multpoint3d(v2, b);
00183   (transMat.top()).multpoint3d(v3, c);
00184 
00185   // and the normals
00186   (transMat.top()).multnorm3d(n1, norm1);
00187   (transMat.top()).multnorm3d(n2, norm2);
00188   (transMat.top()).multnorm3d(n3, norm3);
00189 
00190 #ifdef VMDGENMTLFILE
00191   // set colors
00192   write_cindexmaterial(colorIndex, materialIndex);
00193 #endif
00194                                                        
00195   // draw the triangle 
00196   fprintf(outfile,"v %f %f %f\n", a[0], a[1], a[2]);
00197   fprintf(outfile,"v %f %f %f\n", b[0], b[1], b[2]);
00198   fprintf(outfile,"v %f %f %f\n", c[0], c[1], c[2]);
00199   fprintf(outfile,"vn %f %f %f\n", norm1[0], norm1[1], norm1[2]);
00200   fprintf(outfile,"vn %f %f %f\n", norm2[0], norm2[1], norm2[2]);
00201   fprintf(outfile,"vn %f %f %f\n", norm3[0], norm3[1], norm3[2]);
00202   fprintf(outfile,"f -3//-3 -2//-2 -1//-1\n");
00203 }
00204 
00205 
00206 // use an efficient mesh primitve rather than individual triangles
00207 // when possible.
00208 void WavefrontDisplayDevice::trimesh_c4n3v3(int numverts, float * cnv,
00209                                             int numfacets, int * facets) {
00210   int i;
00211   float vec1[3];
00212   float norm1[3];
00213   const float onethird = (1.0f / 3.0f);
00214 
00215   // write out list of vertices and normals
00216   for (i=0; i<numverts; i++) {
00217     int idx = i*10;
00218 
00219     (transMat.top()).multpoint3d(cnv + idx + 7, vec1);
00220     fprintf(outfile, "v %f %f %f\n", vec1[0], vec1[1], vec1[2]);
00221 
00222     (transMat.top()).multnorm3d(cnv + idx + 4, norm1);
00223     fprintf(outfile, "vn %f %f %f\n", norm1[0], norm1[1], norm1[2]);
00224   }
00225 
00226   // loop over all of the facets in the mesh
00227   for (i=0; i<numfacets*3; i+=3) {
00228     int v0 = facets[i    ];
00229     int v1 = facets[i + 1];
00230     int v2 = facets[i + 2];
00231 
00232 #ifdef VMDGENMTLFILE
00233     // The Wavefront format does not allow per-vertex colors/materials,
00234     // so we use per-facet coloring, averaging the three vertex colors and
00235     // selecting the closest color from the VMD color table.
00236     const float *c1 = cnv + v0 * 10;
00237     const float *c2 = cnv + v1 * 10;
00238     const float *c3 = cnv + v2 * 10;
00239     float r, g, b;
00240     r = (c1[0] + c2[0] + c3[0]) * onethird; // average three vertex colors
00241     g = (c1[1] + c2[1] + c3[1]) * onethird;
00242     b = (c1[2] + c2[2] + c3[2]) * onethird;
00243 
00244     int cindex = nearest_index(r, g, b);
00245     write_cindexmaterial(cindex, materialIndex);
00246 #endif
00247 
00248     // use negative relative indices required for wavefront obj format
00249     v0 -= numverts;
00250     v1 -= numverts;
00251     v2 -= numverts;
00252     fprintf(outfile, "f %d//%d %d//%d %d//%d\n", v0, v0, v1, v1, v2, v2);
00253   }
00254 }
00255 
00256 
00257 void WavefrontDisplayDevice::tristrip(int numverts, const float * cnv,
00258                                       int numstrips, const int *vertsperstrip,
00259                                       const int *facets) {
00260   int i, strip, t, v = 0;
00261   int stripaddr[2][3] = { {0, 1, 2}, {1, 0, 2} };
00262   float vec1[3];
00263   float norm1[3];
00264   const float onethird = (1.0f / 3.0f);
00265 
00266   // write out list of vertices and normals
00267   for (i=0; i<numverts; i++) {
00268     int idx = i*10;
00269 
00270     (transMat.top()).multpoint3d(cnv + idx + 7, vec1);
00271     fprintf(outfile, "v %f %f %f\n", vec1[0], vec1[1], vec1[2]);
00272 
00273     (transMat.top()).multnorm3d(cnv + idx + 4, norm1);
00274     fprintf(outfile, "vn %f %f %f\n", norm1[0], norm1[1], norm1[2]);
00275   }
00276 
00277   // render triangle strips one triangle at a time
00278   // triangle winding order is:
00279   //   v0, v1, v2, then v2, v1, v3, then v2, v3, v4, etc.
00280   // loop over all of the triangle strips
00281   for (strip=0; strip < numstrips; strip++) {
00282     // loop over all triangles in this triangle strip
00283     for (t = 0; t < (vertsperstrip[strip] - 2); t++) {
00284       // render one triangle, using lookup table to fix winding order
00285       int v0 = facets[v + (stripaddr[t & 0x01][0])];
00286       int v1 = facets[v + (stripaddr[t & 0x01][1])];
00287       int v2 = facets[v + (stripaddr[t & 0x01][2])];
00288 
00289 #ifdef VMDGENMTLFILE
00290       // The Wavefront format does not allow per-vertex colors/materials,
00291       // so we use per-facet coloring, averaging the three vertex colors and
00292       // selecting the closest color from the VMD color table.
00293       const float *c1 = cnv + v0 * 10;
00294       const float *c2 = cnv + v1 * 10;
00295       const float *c3 = cnv + v2 * 10;
00296       float r, g, b;
00297       r = (c1[0] + c2[0] + c3[0]) * onethird; // average three vertex colors
00298       g = (c1[1] + c2[1] + c3[1]) * onethird;
00299       b = (c1[2] + c2[2] + c3[2]) * onethird;
00300 
00301       int cindex = nearest_index(r, g, b);
00302       write_cindexmaterial(cindex, materialIndex);
00303 #endif
00304 
00305       // use negative relative indices required for wavefront obj format
00306       v0 -= numverts;
00307       v1 -= numverts;
00308       v2 -= numverts;
00309       fprintf(outfile, "f %d//%d %d//%d %d//%d\n", v0, v0, v1, v1, v2, v2); 
00310       v++; // move on to next vertex
00311     }
00312     v+=2; // last two vertices are already used by last triangle
00313   }
00314 }
00315 
00316 
00317 int WavefrontDisplayDevice::open_file(const char *filename) {
00318   if (isOpened) {
00319     close_file();
00320   }
00321   if ((outfile = fopen(filename, "w")) == NULL) {
00322     msgErr << "Could not open file " << filename
00323            << " in current directory for writing!" << sendmsg;
00324     return FALSE;
00325   }
00326   my_filename = stringdup(filename);
00327 
00328 #ifdef VMDGENMTLFILE
00329   mtlfilename = stringdup(filename);
00330   if (replacefileextension(mtlfilename, ".obj", ".mtl")) {
00331     msgErr << "Could not generate material filename" << sendmsg;
00332     return FALSE;
00333   }
00334   if ((mtlfile = fopen(mtlfilename, "w")) == NULL) {
00335     msgErr << "Could not open file " << mtlfilename
00336            << " in current directory for writing!" << sendmsg;
00337     return FALSE;
00338   }
00339 #endif
00340 
00341   isOpened = TRUE;
00342   reset_state();
00343   oldColorIndex = -1; 
00344   oldMaterialIndex = -1; 
00345   oldMaterialState = -1; 
00346   return TRUE;
00347 }
00348 
00349 void WavefrontDisplayDevice::close_file(void) {
00350   if (outfile) {
00351     fclose(outfile);
00352     outfile = NULL;
00353   }
00354   delete [] my_filename;
00355   my_filename = NULL;
00356 
00357 #ifdef VMDGENMTLFILE
00358   if (mtlfile) {
00359     fclose(mtlfile);
00360     mtlfile = NULL;
00361   }
00362   delete [] mtlfilename;
00363   mtlfilename = NULL;
00364 #endif
00365 
00366   isOpened = FALSE;
00367 }
00368 
00369 void WavefrontDisplayDevice::write_header(void) {
00370   fprintf(outfile, "# Wavefront OBJ file export by VMD\n");
00371   fprintf(outfile, "# \n");
00372   fprintf(outfile, "# Molecular graphics exported from VMD %s\n", VMDVERSION);
00373   fprintf(outfile, "# http://www.ks.uiuc.edu/Research/vmd/\n");
00374   fprintf(outfile, "# \n");
00375 
00376 #ifdef VMDGENMTLFILE
00377   fprintf(mtlfile, "# Wavefront OBJ MTL file export by VMD\n");
00378   fprintf(mtlfile, "# \n");
00379   fprintf(mtlfile, "# Molecular graphics exported from VMD %s\n", VMDVERSION);
00380   fprintf(mtlfile, "# http://www.ks.uiuc.edu/Research/vmd/\n");
00381   fprintf(mtlfile, "# \n");
00382 
00383   if (mtlfilename) {
00384     char *shortmtlfilename = NULL;
00385     shortmtlfilename = stripleadingfilepath(mtlfilename);
00386     fprintf(outfile, "# Load Material Library paired with this scene:\n");
00387     fprintf(outfile, "mtllib %s\n", shortmtlfilename);
00388     free(shortmtlfilename);
00389   }
00390 
00391   write_material_block();
00392 #endif
00393 }
00394 
00395 void WavefrontDisplayDevice::write_material_block(void) {
00396 #ifdef VMDGENMTLFILE
00397    int n;
00398 
00399    // materials for normal lighting modes
00400    for (n=BEGREGCLRS; n < (BEGREGCLRS + REGCLRS + MAPCLRS); n++) {
00401      float rgb[3];
00402      fprintf(mtlfile, "newmtl vmd_mat_cindex_%d\n", n); 
00403      vec_scale(rgb, 0.0f, matData[n]);
00404      fprintf(mtlfile, "Ka %.2f %.2f %.2f\n", rgb[0], rgb[1], rgb[2]); 
00405      vec_scale(rgb, 0.65f, matData[n]);
00406      fprintf(mtlfile, "Kd %.2f %.2f %.2f\n", rgb[0], rgb[1], rgb[2]); 
00407      vec_scale(rgb, 0.50f, matData[n]);
00408      fprintf(mtlfile, "Ks %.2f %.2f %.2f\n", rgb[0], rgb[1], rgb[2]); 
00409      vec_scale(rgb, 0.0f, matData[n]);
00410      fprintf(mtlfile, "Tf %.2f %.2f %.2f\n", rgb[0], rgb[1], rgb[2]); 
00411      fprintf(mtlfile, "d 1.0\n");
00412      fprintf(mtlfile, "Ns 40.0\n");
00413      fprintf(mtlfile, "illum_4\n");
00414      fprintf(mtlfile, "\n");
00415    }
00416 
00417    // materials for non-lighted modes
00418    for (n=BEGREGCLRS; n < (BEGREGCLRS + REGCLRS + MAPCLRS); n++) {
00419      float rgb[3];
00420      fprintf(mtlfile, "newmtl vmd_nomat_cindex_%d\n", n); 
00421      vec_scale(rgb, 0.0f, matData[n]);
00422      fprintf(mtlfile, "Ka %.2f %.2f %.2f\n", rgb[0], rgb[1], rgb[2]); 
00423      vec_scale(rgb, 0.65f, matData[n]);
00424      fprintf(mtlfile, "Kd %.2f %.2f %.2f\n", rgb[0], rgb[1], rgb[2]); 
00425      fprintf(mtlfile, "illum_0\n");
00426      fprintf(mtlfile, "\n");
00427    }
00428 #endif
00429 }
00430 
00431 void WavefrontDisplayDevice::write_cindexmaterial(int cindex, int material) {
00432 #ifdef VMDGENMTLFILE
00433   if ((oldColorIndex != cindex) ||
00434       (oldMaterialIndex != material) ||
00435       (oldMaterialState != materials_on)) {
00436     if (materials_on) {
00437       fprintf(outfile, "usemtl vmd_mat_cindex_%d\n", cindex);
00438     } else {
00439       fprintf(outfile, "usemtl vmd_nomat_cindex_%d\n", cindex);
00440     }
00441   }
00442 #endif
00443   oldMaterialIndex = material;
00444   oldColorIndex = cindex;
00445   oldMaterialState = materials_on;
00446 }
00447 
00448 void WavefrontDisplayDevice::write_colormaterial(float *rgb, int material) {
00449 #ifdef VMDGENMTLFILE
00450   int cindex = nearest_index(rgb[0], rgb[1], rgb[2]);
00451   write_cindexmaterial(cindex, material);
00452 #endif
00453 }
00454 
00455 void WavefrontDisplayDevice::write_trailer (void) {
00456   msgWarn << "Materials are not exported to Wavefront files.\n";
00457 }
00458 

Generated on Wed May 23 01:50:36 2012 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002