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

WavefrontDisplayDevice.C

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

Generated on Thu Mar 28 02:44:28 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002