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

POV3DisplayDevice.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: POV3DisplayDevice.C,v $
00012  *      $Author: johns $        $Locker:  $               $State: Exp $
00013  *      $Revision: 1.129 $        $Date: 2020/07/01 06:09:05 $
00014  *
00015  ***************************************************************************/
00021 #include <string.h>
00022 #include <stdio.h>
00023 #include <math.h>
00024 #include "POV3DisplayDevice.h"
00025 #include "Matrix4.h"
00026 #include "Inform.h"
00027 #include "utilities.h"
00028 #include "DispCmds.h"  // need for line styles
00029 #include "config.h"    // for VMDVERSION string
00030 #include "Hershey.h"   // needed for Hershey font rendering fctns
00031 
00032 #define DEFAULT_RADIUS  0.002f
00033 #define DASH_LENGTH     0.02f
00034 #define PHONG_DIVISOR  64.0f
00035 
00036 // Enable triangle coordinate scaling hacks to prevent POV-Ray 3.x
00037 // from emitting millions of "all determinants too small" warnings
00038 // when rendering finely tessellated geometry. #$@!#@$@ POV-Ray....
00039 // If/when POV-Ray gets fixed, this hack should gladly be removed.
00040 #define POVRAY_BRAIN_DAMAGE_WORKAROUND   1 
00041 #define POVRAY_SCALEHACK                 1000.0f
00042 
00044 
00045 // constructor ... initialize some variables
00046 
00047 POV3DisplayDevice::POV3DisplayDevice() : FileRenderer("POV3", "POV-Ray 3.6", "vmdscene.pov", "povray +W%w +H%h -I%s -O%s.tga +D +X +A +FT") {
00048   reset_vars(); // initialize state variables
00049 }
00050         
00051 // destructor
00052 POV3DisplayDevice::~POV3DisplayDevice(void) { }
00053 
00054 
00055 void POV3DisplayDevice::reset_vars(void) {
00056   degenerate_triangles = 0;
00057   degenerate_cylinders = 0;
00058   degenerate_cones = 0;
00059   memset(&clip_on, 0, sizeof(clip_on));
00060   old_materialIndex = -1;
00061 }
00062 
00063 
00065 
00066 void POV3DisplayDevice::text(float *pos, float size, float thickness,
00067                                    const char *str) {
00068   float textpos[3];
00069   float textsize, textthickness;
00070   hersheyhandle hh;
00071 
00072   // transform the world coordinates
00073   (transMat.top()).multpoint3d(pos, textpos);
00074   textsize = size * 1.5f;
00075   textthickness = thickness*DEFAULT_RADIUS;
00076 
00077   while (*str != '\0') {
00078     float lm, rm, x, y, ox, oy;
00079     int draw, odraw;
00080     ox=oy=x=y=0.0f;
00081     draw=odraw=0;
00082 
00083     hersheyDrawInitLetter(&hh, *str, &lm, &rm);
00084     textpos[0] -= lm * textsize;
00085 
00086     while (!hersheyDrawNextLine(&hh, &draw, &x, &y)) {
00087       float oldpt[3], newpt[3];
00088       if (draw) {
00089         newpt[0] = textpos[0] + textsize * x;
00090         newpt[1] = textpos[1] + textsize * y;
00091         newpt[2] = textpos[2];
00092 
00093         if (odraw) {
00094           // if we have both previous and next points, connect them...
00095           oldpt[0] = textpos[0] + textsize * ox;
00096           oldpt[1] = textpos[1] + textsize * oy;
00097           oldpt[2] = textpos[2];
00098 
00099           fprintf(outfile, "VMD_cylinder(<%.8f,%.8f,%.8f>,<%.8f,%.8f,%.8f>",
00100                   oldpt[0], oldpt[1], -oldpt[2], newpt[0], newpt[1], -newpt[2]);
00101           fprintf(outfile, "%.4f,rgbt<%.3f,%.3f,%.3f,%.3f>,%d)\n",
00102                   textthickness, matData[colorIndex][0], matData[colorIndex][1],
00103                   matData[colorIndex][2], 1 - mat_opacity, 1);
00104 
00105           fprintf(outfile, "VMD_sphere(<%.4f,%.4f,%.4f>,%.4f,",
00106                   newpt[0], newpt[1], -newpt[2], textthickness);
00107           fprintf(outfile, "rgbt<%.3f,%.3f,%.3f,%.3f>)\n",
00108                   matData[colorIndex][0], matData[colorIndex][1], 
00109                   matData[colorIndex][2], 1 - mat_opacity);
00110         } else {
00111           // ...otherwise, just draw the next point
00112           fprintf(outfile, "VMD_sphere(<%.4f,%.4f,%.4f>,%.4f,",
00113                   newpt[0], newpt[1], -newpt[2], textthickness);
00114           fprintf(outfile, "rgbt<%.3f,%.3f,%.3f,%.3f>)\n",
00115                   matData[colorIndex][0], matData[colorIndex][1], 
00116                   matData[colorIndex][2], 1 - mat_opacity);
00117         }
00118       }
00119 
00120       ox=x;
00121       oy=y;
00122       odraw=draw;
00123     }
00124     textpos[0] += rm * textsize;
00125 
00126     str++;
00127   }
00128 }
00129 
00130 
00131 // draw a point
00132 void POV3DisplayDevice::point(float * spdata) {
00133   float vec[3];
00134   // transform the world coordinates
00135   (transMat.top()).multpoint3d(spdata, vec);
00136 
00137 //  write_materials();
00138 
00139   // Draw the point
00140   fprintf(outfile, "VMD_point(<%.4f,%.4f,%.4f>,%.4f,rgbt<%.3f,%.3f,%.3f,%.3f>)\n",
00141           vec[0], vec[1], -vec[2], ((float)pointSize)*DEFAULT_RADIUS, 
00142           matData[colorIndex][0], matData[colorIndex][1], 
00143           matData[colorIndex][2], 1 - mat_opacity);
00144 }
00145 
00146 // draw a sphere
00147 void POV3DisplayDevice::sphere(float * spdata) {
00148   float vec[3];
00149   float radius;
00150     
00151   // transform the world coordinates
00152   (transMat.top()).multpoint3d(spdata, vec);
00153   radius = scale_radius(spdata[3]);
00154 
00155 //  write_materials();
00156 
00157   // Draw the sphere
00158   fprintf(outfile, "VMD_sphere(<%.4f,%.4f,%.4f>,%.4f,",
00159     vec[0], vec[1], -vec[2], radius);
00160   fprintf(outfile, "rgbt<%.3f,%.3f,%.3f,%.3f>)\n",
00161     matData[colorIndex][0], matData[colorIndex][1], matData[colorIndex][2],
00162     1 - mat_opacity);
00163 }
00164 
00165 // draw a line from a to b
00166 void POV3DisplayDevice::line(float *a, float*b) {
00167   int i, j, test;
00168   float dirvec[3], unitdirvec[3];
00169   float from[3], to[3], tmp1[3], tmp2[3];
00170 
00171   if (lineStyle == ::SOLIDLINE) {
00172     // transform the world coordinates
00173     (transMat.top()).multpoint3d(a, from);
00174     (transMat.top()).multpoint3d(b, to);
00175 
00176 //    write_materials();
00177 
00178     // Draw the line
00179     fprintf(outfile, "VMD_line(<%.4f,%.4f,%.4f>,<%.4f,%.4f,%.4f>,",
00180             from[0], from[1], -from[2], to[0], to[1], -to[2]);
00181     fprintf(outfile, "rgbt<%.3f,%.3f,%.3f,%.3f>)\n",
00182       matData[colorIndex][0], matData[colorIndex][1], matData[colorIndex][2],
00183       1 - mat_opacity);
00184 
00185   } 
00186   else if (lineStyle == ::DASHEDLINE) {
00187     // transform the world coordinates
00188     (transMat.top()).multpoint3d(a, tmp1);
00189     (transMat.top()).multpoint3d(b, tmp2);
00190 
00191     // how to create a dashed line
00192     vec_sub(dirvec, tmp2, tmp1);  // vector from a to b
00193     vec_copy(unitdirvec, dirvec);
00194     vec_normalize(unitdirvec);    // unit vector from a to b
00195     test = 1;
00196     i = 0;
00197     while (test == 1) {
00198       for (j=0; j<3; j++) {
00199         from[j] = (float) (tmp1[j] + (2*i)*DASH_LENGTH*unitdirvec[j]);
00200         to[j] =   (float) (tmp1[j] + (2*i + 1)*DASH_LENGTH*unitdirvec[j]);
00201       }
00202       if (fabsf(tmp1[0] - to[0]) >= fabsf(dirvec[0])) {
00203         vec_copy(to, tmp2);
00204         test = 0;
00205       }
00206 
00207 //      write_materials();
00208 
00209       // Draw the line
00210       fprintf(outfile, "VMD_line(<%.4f,%.4f,%.4f>,<%.4f,%.4f,%.4f>,",
00211               from[0], from[1], -from[2], to[0], to[1], -to[2]);
00212       fprintf(outfile, "rgbt<%.3f,%.3f,%.3f,%.3f>)\n",
00213         matData[colorIndex][0], matData[colorIndex][1], matData[colorIndex][2],
00214         1 - mat_opacity);
00215 
00216       i++;
00217     }
00218   } 
00219   else {
00220     msgErr << "POV3DisplayDevice: Unknown line style " << lineStyle << sendmsg;
00221   }
00222 }
00223 
00224 
00225 // draw a cylinder
00226 void POV3DisplayDevice::cylinder(float *a, float *b, float r, int filled) {
00227   float from[3], to[3];
00228   float radius;
00229 
00230   // transform the world coordinates
00231   (transMat.top()).multpoint3d(a, from);
00232   (transMat.top()).multpoint3d(b, to);
00233   radius = scale_radius(r);
00234 
00235   // check for degenerate cylinders
00236   if ( ((from[0]-to[0])*(from[0]-to[0]) +
00237         (from[1]-to[1])*(from[1]-to[1]) +
00238         (from[2]-to[2])*(from[2]-to[2])) < 1e-20 ) {
00239     degenerate_cylinders++;
00240     return;
00241   }
00242 
00243 //  write_materials();
00244    
00245   fprintf(outfile, "VMD_cylinder(<%g,%g,%g>,<%g,%g,%g>",
00246           from[0], from[1], -from[2], to[0], to[1], -to[2]);
00247   fprintf(outfile, "%.4f,rgbt<%.3f,%.3f,%.3f,%.3f>,%d)\n",
00248           radius, matData[colorIndex][0], matData[colorIndex][1],
00249           matData[colorIndex][2], 1 - mat_opacity, !filled);
00250 }
00251 
00252 // draw a cone
00253 void POV3DisplayDevice::cone(float *a, float *b, float r, int /* resolution */) {
00254   float from[3], to[3];
00255   float radius;
00256   
00257   // transform the world coordinates
00258   (transMat.top()).multpoint3d(a, from);
00259   (transMat.top()).multpoint3d(b, to);
00260   radius = scale_radius(r);
00261 
00262   // check for degenerate cylinders
00263   if ( ((from[0]-to[0])*(from[0]-to[0]) +
00264         (from[1]-to[1])*(from[1]-to[1]) +
00265         (from[2]-to[2])*(from[2]-to[2])) < 1e-20 ) {
00266     degenerate_cones++;
00267     return;
00268   }
00269 
00270 //  write_materials();
00271 
00272   // Draw the cone
00273   fprintf(outfile, "VMD_cone (<%g,%g,%g>,<%g,%g,%g>,%.4f,",
00274           from[0], from[1], -from[2], to[0], to[1], -to[2], radius);
00275   fprintf(outfile, "rgbt<%.3f,%.3f,%.3f,%.3f>)\n",
00276           matData[colorIndex][0], matData[colorIndex][1], matData[colorIndex][2],
00277           1 - mat_opacity);
00278 }
00279 
00280 // draw a triangle using the current color
00281 // XXX - POV-Ray doesn't support indexed color for triangles -- we need to
00282 // use an RGB triple. Here we just use the same RGB triple for each vertex
00283 // and call tricolor.
00284 void POV3DisplayDevice::triangle(const float *a, const float *b, const float *c, 
00285                                  const float *n1, const float *n2, const float *n3) {
00286   float c1[3], c2[3], c3[3];
00287 
00288   memcpy(c1, matData[colorIndex], 3 * sizeof(float));
00289   memcpy(c2, matData[colorIndex], 3 * sizeof(float));
00290   memcpy(c3, matData[colorIndex], 3 * sizeof(float));
00291 
00292   tricolor(a, b, c, n1, n2, n3, c1, c2, c3);
00293   return;
00294 }
00295 
00296 // draw triangle with per-vertex colors
00297 void POV3DisplayDevice::tricolor(const float * xyz1, const float * xyz2, const float * xyz3,
00298                                  const float * n1,   const float * n2,   const float * n3,
00299                                  const float *c1, const float *c2, const float *c3) {
00300   float vec1[3], vec2[3], vec3[3], norm1[3], norm2[3], norm3[3];
00301   float leg1[3], leg2[3], trinorm[3], ang1, ang2, ang3;
00302 
00303   // transform the world coordinates
00304   (transMat.top()).multpoint3d(xyz1, vec1);
00305   (transMat.top()).multpoint3d(xyz2, vec2);
00306   (transMat.top()).multpoint3d(xyz3, vec3);
00307 
00308   // and the normals
00309   (transMat.top()).multnorm3d(n1, norm1);
00310   (transMat.top()).multnorm3d(n2, norm2);
00311   (transMat.top()).multnorm3d(n3, norm3);
00312 
00313 //  write_materials();
00314 
00315   // Don't write degenerate triangles -- those with all normals more than 90
00316   // degrees from triangle normal or its inverse.
00317   vec_sub(leg1, vec2, vec1);
00318   vec_sub(leg2, vec3, vec1);
00319   cross_prod(trinorm, leg1, leg2);
00320   ang1 = dot_prod(trinorm, norm1);
00321   ang2 = dot_prod(trinorm, norm2);
00322   ang3 = dot_prod(trinorm, norm3);
00323   if ( ((ang1 >= 0.0) || (ang2 >= 0.0) || (ang3 >= 0.0)) &&
00324        ((ang1 <= 0.0) || (ang2 <= 0.0) || (ang3 <= 0.0)) ) {
00325     degenerate_triangles++;
00326     return;
00327   }
00328 
00329   // If all verticies have the same color, don't bother with per-vertex
00330   // coloring
00331   if ( (c1[0] == c2[0]) && (c1[0] == c3[0]) &&
00332        (c1[1] == c2[1]) && (c1[1] == c3[1]) &&
00333        (c1[2] == c2[2]) && (c1[2] == c3[2]) ) {
00334     fprintf(outfile, "VMD_triangle(");
00335     fprintf(outfile, "<%.8g,%.8g,%.8g>,<%.8g,%.8g,%.8g>,<%.8g,%.8g,%.8g>,",
00336         vec1[0], vec1[1], -vec1[2], vec2[0], vec2[1], -vec2[2], 
00337         vec3[0], vec3[1], -vec3[2]);
00338     fprintf(outfile, "<%.8g,%.8g,%.8g>,<%.8g,%.8g,%.8g>,<%.8g,%.8g,%.8g>,",
00339         norm1[0], norm1[1], -norm1[2], norm2[0], norm2[1], -norm2[2], 
00340         norm3[0], norm3[1], -norm3[2]);
00341     fprintf(outfile, "rgbt<%.3f,%.3f,%.3f,%.3f>)\n",
00342         c1[0], c1[1], c1[2], 1 - mat_opacity);
00343   }
00344   else {
00345     fprintf(outfile, "VMD_tricolor(");
00346     fprintf(outfile, "<%.8g,%.8g,%.8g>,<%.8g,%.8g,%.8g>,<%.8g,%.8g,%.8g>,",
00347         vec1[0], vec1[1], -vec1[2], vec2[0], vec2[1], -vec2[2], 
00348         vec3[0], vec3[1], -vec3[2]);
00349     fprintf(outfile, "<%.8g,%.8g,%.8g>,<%.8g,%.8g,%.8g>,<%.8g,%.8g,%.8g>,",
00350         norm1[0], norm1[1], -norm1[2], norm2[0], norm2[1], -norm2[2], 
00351         norm3[0], norm3[1], -norm3[2]);
00352     fprintf(outfile, "rgbt<%.3f,%.3f,%.3f,%.3f>,rgbt<%.3f,%.3f,%.3f,%.3f>,rgbt<%.3f,%.3f,%.3f,%.3f>)\n",
00353         c1[0], c1[1], c1[2], 1 - mat_opacity, c2[0], c2[1], c2[2], 
00354         1 - mat_opacity, c3[0], c3[1], c3[2], 1 - mat_opacity);
00355   }
00356 }
00357 
00358 #if 1
00359 // Draw a triangle mesh as a mesh2 POV-Ray object
00360 void POV3DisplayDevice::trimesh_c4n3v3(int numverts, float *cnv, 
00361                                        int numfacets, int *facets) {
00362   int i;
00363  
00364 //  write_materials();
00365 
00366   if (clip_on[2]) {
00367     fprintf(outfile, "intersection {\n");
00368   }
00369   fprintf(outfile, "mesh2 {\n");
00370 
00371   // Print the Vertex Vectors
00372   fprintf(outfile, "  vertex_vectors {\n");
00373   fprintf(outfile, "  %d,\n", numverts);
00374   for (i=0; i<numverts; i++) {
00375     int ind = i * 10;
00376     float vtmp[3];
00377     transMat.top().multpoint3d(cnv + ind + 7, vtmp);
00378 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND)
00379     vtmp[0] *= POVRAY_SCALEHACK;
00380     vtmp[1] *= POVRAY_SCALEHACK;
00381     vtmp[2] *= POVRAY_SCALEHACK;
00382 #endif
00383     fprintf(outfile, "  <%.4f,%.4f,%.4f>,\n", vtmp[0], vtmp[1], -vtmp[2]);
00384   }
00385   fprintf(outfile, "  }\n");
00386 
00387   // Print the Normal Vectors
00388   fprintf(outfile, "  normal_vectors {\n");
00389   fprintf(outfile, "  %d,\n", numverts);
00390   for (i=0; i<numverts; i++) {
00391     int ind = i * 10;
00392     float ntmp[3];
00393     transMat.top().multnorm3d(cnv + ind + 4, ntmp);
00394     fprintf(outfile, "  <%.4f,%.4f,%.4f>,\n", ntmp[0], ntmp[1], -ntmp[2]);
00395   }
00396   fprintf(outfile, "  }\n");
00397 
00398   // Print the Texture List
00399   fprintf(outfile, "  texture_list {\n");
00400   fprintf(outfile, "  %d,\n", numverts);
00401   for (i=0; i<numverts; i++) {
00402     int ind = i * 10;
00403     float *rgb = cnv + ind;
00404     fprintf(outfile, "  VMDC(<%.3f,%.3f,%.3f,%.3f>)\n", 
00405             rgb[0], rgb[1], rgb[2], 1 - mat_opacity);
00406   }
00407   fprintf(outfile, "  }\n");
00408 
00409   // Face Indices
00410   fprintf(outfile, "  face_indices {\n");
00411   fprintf(outfile, "  %d\n", numfacets);
00412   for (i = 0; i < numfacets; i++) {
00413     int ind = i * 3;
00414 
00415     fprintf(outfile, "  <%d,%d,%d>,%d,%d,%d\n",
00416             facets[ind], facets[ind + 1], facets[ind + 2], 
00417             facets[ind], facets[ind + 1], facets[ind + 2]);
00418   }
00419   fprintf(outfile, "  }\n");
00420 
00421   // Object Modifiers
00422   fprintf(outfile, "  inside_vector <0, 0, 1>\n");
00423   if (clip_on[1]) {
00424 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND)
00425     fprintf(outfile, "  clipped_by { VMD_scaledclip[1] }\n");
00426 #else
00427     fprintf(outfile, "  clipped_by { VMD_clip[1] }\n");
00428 #endif
00429   }
00430   if (!shadows_enabled())
00431     fprintf(outfile, "  no_shadow\n");
00432 
00433 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND)
00434   Matrix4 hackmatrix;
00435   hackmatrix.identity();
00436   hackmatrix.scale(1.0f / POVRAY_SCALEHACK);
00437   const float *trans = hackmatrix.mat;
00438   fprintf(outfile, "matrix < \n");
00439   fprintf(outfile, "  %f, %f, %f,\n", trans[ 0], trans[ 1], trans[ 2]);
00440   fprintf(outfile, "  %f, %f, %f,\n", trans[ 4], trans[ 5], trans[ 6]);
00441   fprintf(outfile, "  %f, %f, %f,\n", trans[ 8], trans[ 9], trans[10]);
00442   fprintf(outfile, "  %f, %f, %f \n", trans[12], trans[13], trans[14]);
00443   fprintf(outfile, "> ");
00444 #endif
00445 
00446   fprintf(outfile, "}\n");
00447 
00448   if (clip_on[2]) {
00449     fprintf(outfile, "  VMD_clip[2]\n");
00450     if (!shadows_enabled())
00451       fprintf(outfile, "  no_shadow\n");
00452     fprintf(outfile, "}\n");
00453   }
00454 }
00455 
00456 #else
00457 
00458 // Draw a triangle mesh as a mesh2 POV-Ray object
00459 void POV3DisplayDevice::trimesh_c4n3v3(int numverts, float *cnv, 
00460                                        int numfacets, int *facets) {
00461   float (*vert)[3], (*norm)[3], (*color)[3];
00462   int i, ind, v0, v1, v2, *c_index, curr_index;
00463  
00464 //  write_materials();
00465 
00466   if (clip_on[2]) {
00467     fprintf(outfile, "intersection {\n");
00468   }
00469   fprintf(outfile, "mesh2 {\n");
00470 
00471   // Read the mesh, storing vertex coordinates, normals, and (unique) colors
00472   // XXX - this can use a *lot* of memory, but not as much as POV will when
00473   // parsing the resulting scene file.
00474   vert = new float[numfacets * 3][3];
00475   norm = new float[numfacets * 3][3];
00476   color = new float[numfacets * 3][3];
00477   c_index = new int[numfacets * 3];
00478   curr_index = -1;
00479 
00480   float prev_color[3] = { -1, -1, -1 };
00481   for (i = 0; i < numfacets; i++) {
00482     ind = i * 3;
00483     v0 = facets[ind    ] * 10;
00484     v1 = facets[ind + 1] * 10;
00485     v2 = facets[ind + 2] * 10;
00486 
00487     // transform the verticies and store them in the array
00488     transMat.top().multpoint3d(cnv + v0 + 7, vert[ind    ]);
00489     transMat.top().multpoint3d(cnv + v1 + 7, vert[ind + 1]);
00490     transMat.top().multpoint3d(cnv + v2 + 7, vert[ind + 2]);
00491 
00492     // transform the normals and store them in the array
00493     transMat.top().multnorm3d(cnv + v0 + 4, norm[ind    ]);
00494     transMat.top().multnorm3d(cnv + v1 + 4, norm[ind + 1]);
00495     transMat.top().multnorm3d(cnv + v2 + 4, norm[ind + 2]);
00496 
00497 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND)
00498     vert[ind    ][0] *= POVRAY_SCALEHACK;
00499     vert[ind    ][1] *= POVRAY_SCALEHACK;
00500     vert[ind    ][2] *= POVRAY_SCALEHACK;
00501     vert[ind + 1][0] *= POVRAY_SCALEHACK;
00502     vert[ind + 1][1] *= POVRAY_SCALEHACK;
00503     vert[ind + 1][2] *= POVRAY_SCALEHACK;
00504     vert[ind + 2][0] *= POVRAY_SCALEHACK;
00505     vert[ind + 2][1] *= POVRAY_SCALEHACK;
00506     vert[ind + 2][2] *= POVRAY_SCALEHACK;
00507 #endif
00508 
00509     // Only store a color if it's different than the previous color,
00510     // this saves a lot of space for large triangle meshes.
00511     if (memcmp(prev_color, (cnv + v0), 3*sizeof(float)) != 0) {
00512       curr_index++;
00513       memcpy(color[curr_index], (cnv + v0), 3*sizeof(float));
00514       memcpy(prev_color, (cnv + v0), 3*sizeof(float));
00515     }
00516     c_index[ind] = curr_index;
00517 
00518     if (memcmp(prev_color, (cnv + v1), 3*sizeof(float)) != 0) {
00519       curr_index++;
00520       memcpy(color[curr_index], (cnv + v1), 3*sizeof(float));
00521       memcpy(prev_color, (cnv + v1), 3*sizeof(float));
00522     }
00523     c_index[ind+1] = curr_index;
00524 
00525     if (memcmp(prev_color, (cnv + v2), 3*sizeof(float)) != 0) {
00526       curr_index++;
00527       memcpy(color[curr_index], (cnv + v2), 3*sizeof(float));
00528       memcpy(prev_color, (cnv + v2), 3*sizeof(float));
00529     }
00530     c_index[ind+2] = curr_index;
00531   }
00532 
00533   // Print the Vertex Vectors
00534   fprintf(outfile, "  vertex_vectors {\n");
00535   fprintf(outfile, "  %d,\n", numfacets * 3);
00536   for (i = 0; i < (numfacets * 3); i++) {
00537     fprintf(outfile, "  <%.4f,%.4f,%.4f>,\n", 
00538             vert[i][0], vert[i][1], -vert[i][2]);
00539   }
00540   fprintf(outfile, "  }\n");
00541 
00542   // Print the Normal Vectors
00543   fprintf(outfile, "  normal_vectors {\n");
00544   fprintf(outfile, "  %d,\n", numfacets * 3);
00545   for (i = 0; i < (numfacets * 3); i++) {
00546     fprintf(outfile, "  <%.4f,%.4f,%.4f>,\n", 
00547             norm[i][0], norm[i][1], -norm[i][2]);
00548   }
00549   fprintf(outfile, "  }\n");
00550 
00551   // Print the Texture List
00552   fprintf(outfile, "  texture_list {\n");
00553   fprintf(outfile, "  %d,\n", curr_index+1);
00554   for (i = 0; i <= curr_index; i++) {
00555     fprintf(outfile, "  VMDC(<%.3f,%.3f,%.3f,%.3f>)\n", 
00556             color[i][0], color[i][1], color[i][2], 1 - mat_opacity);
00557   }
00558   fprintf(outfile, "  }\n");
00559 
00560   // Face Indices
00561   fprintf(outfile, "  face_indices {\n");
00562   fprintf(outfile, "  %d\n", numfacets);
00563   for (i = 0; i < numfacets; i++) {
00564     ind = i * 3;
00565 
00566     // Print three vertex/normal and color indicies.
00567     if ((c_index[ind] == c_index[ind+1]) && (c_index[ind] == c_index[ind+2])) {
00568       // Only one color index is required if the triangle doesn't use
00569       // per-vertex shading
00570       fprintf(outfile, "  <%d,%d,%d>,%d\n",
00571               ind, ind + 1, ind + 2, c_index[ind]);
00572     }
00573     else {
00574       fprintf(outfile, "  <%d,%d,%d>,%d,%d,%d\n",
00575               ind, ind + 1, ind + 2, 
00576               c_index[ind], c_index[ind+1], c_index[ind+2]);
00577     }
00578   }
00579   fprintf(outfile, "  }\n");
00580 
00581   // Object Modifiers
00582   fprintf(outfile, "  inside_vector <0, 0, 1>\n");
00583   if (clip_on[1]) {
00584 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND)
00585     fprintf(outfile, "  clipped_by { VMD_scaledclip[1] }\n");
00586 #else
00587     fprintf(outfile, "  clipped_by { VMD_clip[1] }\n");
00588 #endif
00589   }
00590   if (!shadows_enabled())
00591     fprintf(outfile, "  no_shadow\n");
00592 
00593 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND)
00594   Matrix4 hackmatrix;
00595   hackmatrix.identity();
00596   hackmatrix.scale(1.0f / POVRAY_SCALEHACK);
00597   const float *trans = hackmatrix.mat;
00598   fprintf(outfile, "matrix < \n");
00599   fprintf(outfile, "  %f, %f, %f,\n", trans[ 0], trans[ 1], trans[ 2]);
00600   fprintf(outfile, "  %f, %f, %f,\n", trans[ 4], trans[ 5], trans[ 6]);
00601   fprintf(outfile, "  %f, %f, %f,\n", trans[ 8], trans[ 9], trans[10]);
00602   fprintf(outfile, "  %f, %f, %f \n", trans[12], trans[13], trans[14]);
00603   fprintf(outfile, "> ");
00604 #endif
00605 
00606   fprintf(outfile, "}\n");
00607 
00608   if (clip_on[2]) {
00609     fprintf(outfile, "  VMD_clip[2]\n");
00610     if (!shadows_enabled())
00611       fprintf(outfile, "  no_shadow\n");
00612     fprintf(outfile, "}\n");
00613   }
00614 
00615   delete [] vert;
00616   delete [] norm;
00617   delete [] color;
00618   delete [] c_index;
00619 }
00620 #endif
00621 
00622 
00623 // Draw a triangle mesh as a mesh2 POV-Ray object
00624 void POV3DisplayDevice::trimesh_c4u_n3b_v3f(unsigned char *c, signed char *n,
00625                                             float *v, int numfacets) {
00626   int i;
00627   int numverts = 3*numfacets;
00628 
00629   const float ci2f = 1.0f / 255.0f; // used for uchar2float and normal conv
00630   const float cn2f = 1.0f / 127.5f;
00631  
00632 //  write_materials();
00633 
00634   if (clip_on[2]) {
00635     fprintf(outfile, "intersection {\n");
00636   }
00637   fprintf(outfile, "mesh2 {\n");
00638 
00639   // Read the mesh storing a list of unique colors
00640   float (*color)[3] = new float[numverts][3];
00641   int *c_index = new int[numverts];
00642   int curr_index = -1;
00643   float prev_color[3] = { -1, -1, -1 };
00644   for (i = 0; i < numverts; i++) {
00645     // Only store a color if it's different than the previous color,
00646     // this saves a lot of space for large triangle meshes.
00647     float ctmp[3];
00648     int ind = i * 4;
00649     ctmp[0] = c[ind  ] * ci2f; 
00650     ctmp[1] = c[ind+1] * ci2f; 
00651     ctmp[2] = c[ind+2] * ci2f; 
00652     if (memcmp(prev_color, ctmp, 3*sizeof(float)) != 0) {
00653       curr_index++;
00654       memcpy(color[curr_index], ctmp, 3*sizeof(float));
00655       memcpy(prev_color, ctmp, 3*sizeof(float));
00656     }
00657     c_index[i] = curr_index;
00658   }
00659 
00660   // Print the Vertex Vectors
00661   fprintf(outfile, "  vertex_vectors {\n");
00662   fprintf(outfile, "  %d,\n", numverts);
00663   for (i = 0; i < numverts; i++) {
00664     int ind = i * 3;
00665     float vtmp[3];
00666     transMat.top().multpoint3d(v+ind, vtmp);
00667 
00668 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND)
00669     vtmp[0] *= POVRAY_SCALEHACK;
00670     vtmp[1] *= POVRAY_SCALEHACK;
00671     vtmp[2] *= POVRAY_SCALEHACK;
00672 #endif
00673 
00674     fprintf(outfile, "  <%.4f,%.4f,%.4f>,\n", vtmp[0], vtmp[1], -vtmp[2]);
00675   }
00676   fprintf(outfile, "  }\n");
00677 
00678   // Print the Normal Vectors
00679   fprintf(outfile, "  normal_vectors {\n");
00680   fprintf(outfile, "  %d,\n", numverts);
00681   for (i = 0; i < numverts; i++) {
00682     int ind = i * 3;
00683     float ntmp[3], ntmp2[3];
00684 
00685     // conversion from GLbyte format, Table 2.6, p. 44 of OpenGL spec 1.2.1
00686     // float = (2c+1)/(2^8-1)
00687     ntmp[0] = n[ind  ] * cn2f + ci2f;
00688     ntmp[1] = n[ind+1] * cn2f + ci2f;
00689     ntmp[2] = n[ind+2] * cn2f + ci2f;
00690 
00691     // transform the normals and store them in the array
00692     transMat.top().multnorm3d(ntmp, ntmp2);
00693     fprintf(outfile, "  <%.3f,%.3f,%.3f>,\n", ntmp2[0], ntmp2[1], -ntmp[2]);
00694   }
00695   fprintf(outfile, "  }\n");
00696 
00697   // Print the Texture List
00698   fprintf(outfile, "  texture_list {\n");
00699   fprintf(outfile, "  %d,\n", curr_index+1);
00700   for (i = 0; i <= curr_index; i++) {
00701     fprintf(outfile, "  VMDC(<%.3f,%.3f,%.3f,%.3f>)\n", 
00702             color[i][0], color[i][1], color[i][2], 1 - mat_opacity);
00703   }
00704   fprintf(outfile, "  }\n");
00705 
00706   // Face Indices
00707   fprintf(outfile, "  face_indices {\n");
00708   fprintf(outfile, "  %d\n", numfacets);
00709   for (i = 0; i < numfacets; i++) {
00710     int ind = i * 3;
00711 
00712     // Print three vertex/normal and color indicies.
00713     if ((c_index[ind] == c_index[ind+1]) && (c_index[ind] == c_index[ind+2])) {
00714       // Only one color index is required if the triangle doesn't use
00715       // per-vertex shading
00716       fprintf(outfile, "  <%d,%d,%d>,%d\n",
00717               ind, ind + 1, ind + 2, c_index[ind]);
00718     }
00719     else {
00720       fprintf(outfile, "  <%d,%d,%d>,%d,%d,%d\n",
00721               ind, ind + 1, ind + 2, 
00722               c_index[ind], c_index[ind+1], c_index[ind+2]);
00723     }
00724   }
00725   fprintf(outfile, "  }\n");
00726 
00727   // Object Modifiers
00728   fprintf(outfile, "  inside_vector <0, 0, 1>\n");
00729   if (clip_on[1]) {
00730 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND)
00731     fprintf(outfile, "  clipped_by { VMD_scaledclip[1] }\n");
00732 #else
00733     fprintf(outfile, "  clipped_by { VMD_clip[1] }\n");
00734 #endif
00735   }
00736   if (!shadows_enabled())
00737     fprintf(outfile, "  no_shadow\n");
00738 
00739 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND)
00740   Matrix4 hackmatrix;
00741   hackmatrix.identity();
00742   hackmatrix.scale(1.0f / POVRAY_SCALEHACK);
00743   const float *trans = hackmatrix.mat;
00744   fprintf(outfile, "matrix < \n");
00745   fprintf(outfile, "  %f, %f, %f,\n", trans[ 0], trans[ 1], trans[ 2]);
00746   fprintf(outfile, "  %f, %f, %f,\n", trans[ 4], trans[ 5], trans[ 6]);
00747   fprintf(outfile, "  %f, %f, %f,\n", trans[ 8], trans[ 9], trans[10]);
00748   fprintf(outfile, "  %f, %f, %f \n", trans[12], trans[13], trans[14]);
00749   fprintf(outfile, "> ");
00750 #endif
00751 
00752   fprintf(outfile, "}\n");
00753 
00754   if (clip_on[2]) {
00755     fprintf(outfile, "  VMD_clip[2]\n");
00756     if (!shadows_enabled())
00757       fprintf(outfile, "  no_shadow\n");
00758     fprintf(outfile, "}\n");
00759   }
00760 
00761   delete [] color;
00762   delete [] c_index;
00763 }
00764 
00765 
00766 // Draw a collection of triangle strips as a mesh2 POV-Ray object
00767 void POV3DisplayDevice::tristrip(int numverts, const float *cnv, 
00768                         int numstrips, const int *vertsperstrip, 
00769                         const int *facets) {
00770   int strip, v, i, numfacets;
00771   float (*vert)[3], (*norm)[3], (*color)[3];
00772 
00773   // POV-Ray does use triangle winding-order to determine the orientation of
00774   // a triangle. Although the default triangle macro doesn't make use of
00775   // this, the interior_texture property can be specified to give
00776   // back-facing triangles a different texture.
00777   int stripaddr[2][3] = { {0, 1, 2}, {1, 0, 2} };
00778 
00779 //  write_materials();
00780 
00781   if (clip_on[2]) {
00782     fprintf(outfile, "intersection {\n");
00783   }
00784   fprintf(outfile, "mesh2 {\n");
00785 
00786   // Read the mesh, storing vertex coordinates, normals, and colors
00787   // XXX - this can use a *lot* of memory, but not as much as POV will when
00788   // parsing the resulting scene file.
00789   vert = new float[numverts][3];
00790   norm = new float[numverts][3];
00791   color = new float[numverts][3];
00792 
00793   for (i = 0; i < numverts; i++) {
00794     transMat.top().multpoint3d(cnv + i*10 + 7, vert[i]);
00795     transMat.top().multnorm3d(cnv + i*10 + 4, norm[i]);
00796 
00797 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND)
00798     vert[i][0] *= POVRAY_SCALEHACK;
00799     vert[i][1] *= POVRAY_SCALEHACK;
00800     vert[i][2] *= POVRAY_SCALEHACK;
00801 #endif
00802 
00803     memcpy(color[i], cnv + i*10, 3*sizeof(float));
00804   }
00805 
00806   // Print the Vertex Vectors
00807   fprintf(outfile, "  vertex_vectors {\n");
00808   fprintf(outfile, "  %d,\n", numverts);
00809   for (i = 0; i < numverts; i++) {
00810     fprintf(outfile, "  <%.4f,%.4f,%.4f>,\n", 
00811             vert[i][0], vert[i][1], -vert[i][2]);
00812   }
00813   fprintf(outfile, "  }\n");
00814 
00815   // Print the Normal Vectors
00816   fprintf(outfile, "  normal_vectors {\n");
00817   fprintf(outfile, "  %d,\n", numverts);
00818   for (i = 0; i < numverts; i++) {
00819     fprintf(outfile, "  <%.4f,%.4f,%.4f>,\n", 
00820             norm[i][0], norm[i][1], -norm[i][2]);
00821   }
00822   fprintf(outfile, "  }\n");
00823 
00824   // Print the Texture List
00825   fprintf(outfile, "  texture_list {\n");
00826   fprintf(outfile, "  %d,\n", numverts);
00827   for (i = 0; i < numverts; i++) {
00828     fprintf(outfile, "  VMDC(<%.3f,%.3f,%.3f,%.3f>)\n", 
00829             color[i][0], color[i][1], color[i][2], 1 - mat_opacity);
00830   }
00831   fprintf(outfile, "  }\n");
00832 
00833   // Find the number of facets
00834   numfacets = 0;
00835   for (strip = 0; strip < numstrips; strip++) {
00836     numfacets += (vertsperstrip[strip] - 2);
00837   }
00838 
00839   // Print the Face Indices
00840   v = 0;
00841   fprintf(outfile, "  face_indices {\n");
00842   fprintf(outfile, "  %d\n", numfacets);
00843   for (strip = 0; strip < numstrips; strip++) {
00844     for (i = 0; i < (vertsperstrip[strip] - 2); i++) {
00845       fprintf(outfile, "  <%d,%d,%d>,%d,%d,%d\n",
00846               facets[v + (stripaddr[i & 0x01][0])],
00847               facets[v + (stripaddr[i & 0x01][1])],
00848               facets[v + (stripaddr[i & 0x01][2])],
00849               facets[v + (stripaddr[i & 0x01][0])],
00850               facets[v + (stripaddr[i & 0x01][1])],
00851               facets[v + (stripaddr[i & 0x01][2])] );
00852       v++;
00853     }
00854     v += 2;
00855   }
00856   fprintf(outfile, "  }\n");
00857 
00858   // Object Modifiers
00859   fprintf(outfile, "  inside_vector <0, 0, 1>\n");
00860   if (clip_on[1]) {
00861 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND)
00862     fprintf(outfile, "  clipped_by { VMD_scaledclip[1] }\n");
00863 #else
00864     fprintf(outfile, "  clipped_by { VMD_clip[1] }\n");
00865 #endif
00866   }
00867 
00868 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND)
00869   Matrix4 hackmatrix;
00870   hackmatrix.identity();
00871   hackmatrix.scale(1.0f / POVRAY_SCALEHACK);
00872   const float *trans = hackmatrix.mat;
00873   fprintf(outfile, "matrix < \n");
00874   fprintf(outfile, "  %f, %f, %f,\n", trans[ 0], trans[ 1], trans[ 2]);
00875   fprintf(outfile, "  %f, %f, %f,\n", trans[ 4], trans[ 5], trans[ 6]);
00876   fprintf(outfile, "  %f, %f, %f,\n", trans[ 8], trans[ 9], trans[10]);
00877   fprintf(outfile, "  %f, %f, %f \n", trans[12], trans[13], trans[14]);
00878   fprintf(outfile, "> ");
00879 #endif
00880 
00881   if (!shadows_enabled())
00882     fprintf(outfile, "  no_shadow\n");
00883   fprintf(outfile, "}\n");
00884 
00885   if (clip_on[2]) {
00886     fprintf(outfile, "  VMD_clip[2]\n");
00887     if (!shadows_enabled())
00888       fprintf(outfile, "  no_shadow\n");
00889     fprintf(outfile, "}\n");
00890   }
00891 
00892   delete [] vert;
00893   delete [] norm;
00894   delete [] color;
00895 }
00896 
00897 // display a comment
00898 void POV3DisplayDevice::comment(const char *s) {
00899   fprintf (outfile, "// %s\n", s);
00900 }
00901 
00903 
00904 void POV3DisplayDevice::write_header() {
00905   long myXsize;
00906   float zDirection;
00907 
00908   // cross-eyes and side-by-side stereo split the screen; so we need
00909   // to cut xSize in half in this case
00910   myXsize = xSize;
00911   //if (inStereo == OPENGL_STEREO_SIDE)
00912   //   myXsize /= 2;
00913   // if (inStereo == OPENGL_STEREO_ABOVEBELOW) 
00914   //   myXsize *= 2;
00915   fprintf(outfile, "// \n");
00916   fprintf(outfile, "// Molecular graphics export from VMD %s\n", VMDVERSION);
00917   fprintf(outfile, "// http://www.ks.uiuc.edu/Research/vmd/\n");
00918   fprintf(outfile, "// Requires POV-Ray 3.5 or later\n");
00919   fprintf(outfile, "// \n");
00920 
00921   fprintf(outfile, "// POV 3.x input script : %s \n", my_filename);
00922   fprintf(outfile, "// try povray +W%ld +H%ld -I%s ", myXsize, ySize, my_filename);
00923   fprintf(outfile, "-O%s.tga +P +X +A +FT +C", my_filename);
00924 
00925   // need to disable the vista buffer when stereo rendering
00926   if (whichEye != DisplayDevice::NOSTEREO) fprintf(outfile, " -UV");
00927   fprintf(outfile, "\n");
00928 
00929 #if 0
00930   msgInfo << "Default povray command line should be:" << sendmsg;
00931 
00932   msgInfo << "  povray +W" << myXsize << " +H" << ySize << " -I" << my_filename
00933           << " -O" << my_filename << ".tga +P +X +A +FT +C";
00934   if (whichEye != DisplayDevice::NOSTEREO) msgInfo << " -UV";
00935   msgInfo << sendmsg;
00936 #endif
00937 
00938   // Warn the user if the plugin was compiled for a different version of POV
00939   // than they're using
00940   fprintf(outfile, "#if (version < 3.5) \n");
00941   fprintf(outfile, "#error \"VMD POV3DisplayDevice has been compiled for POV-Ray 3.5 or above.\\nPlease upgrade POV-Ray or recompile VMD.\"\n");
00942   fprintf(outfile, "#end \n");
00943 
00944   // Initialize POV-Ray state variables
00945   fprintf(outfile, "#declare VMD_clip_on=array[3] {0, 0, 0};\n");
00946   fprintf(outfile, "#declare VMD_clip=array[3];\n");
00947   fprintf(outfile, "#declare VMD_scaledclip=array[3];\n");
00948   fprintf(outfile, "#declare VMD_line_width=%.4f;\n", 
00949           ((float)lineWidth)*DEFAULT_RADIUS);
00950 
00951   //
00952   // Macros for VMD-like graphic primitives in POV.
00953   //
00954  
00955   // Color/Texture: save space when emitting texture lines for mesh2 primitives
00956   fprintf(outfile, "#macro VMDC ( C1 )\n");
00957   fprintf(outfile, "  texture { pigment { rgbt C1 }}\n");
00958   fprintf(outfile, "#end\n");
00959 
00960   // Point: can be quickly approximated as spheres with no shading.
00961   fprintf(outfile, "#macro VMD_point (P1, R1, C1)\n");
00962   fprintf(outfile, "  #local T = texture { finish { ambient 1.0 diffuse 0.0 phong 0.0 specular 0.0 } pigment { C1 } }\n");
00963   fprintf(outfile, "  #if(VMD_clip_on[2])\n");
00964   fprintf(outfile, "  intersection {\n");
00965   fprintf(outfile, "    sphere {P1, R1 texture {T} #if(VMD_clip_on[1]) clipped_by {VMD_clip[1]} #end %s}\n", (shadows_enabled()) ? "" : "no_shadow");
00966   fprintf(outfile, "    VMD_clip[2]\n");
00967   fprintf(outfile, "  }\n  #else\n");
00968   fprintf(outfile, "  sphere {P1, R1 texture {T} #if(VMD_clip_on[1]) clipped_by {VMD_clip[1]} #end %s}\n", (shadows_enabled()) ? "" : "no_shadow");
00969   fprintf(outfile, "  #end\n");
00970   fprintf(outfile, "#end\n");
00971 
00972   // Line: can be quickly approximated as cylinders with no shading
00973   fprintf(outfile, "#macro VMD_line (P1, P2, C1)\n");
00974   fprintf(outfile, "  #local T = texture { finish { ambient 1.0 diffuse 0.0 phong 0.0 specular 0.0 } pigment { C1 } }\n");
00975   fprintf(outfile, "  #if(VMD_clip_on[2])\n");
00976   fprintf(outfile, "  intersection {\n");
00977   fprintf(outfile, "    cylinder {P1, P2, VMD_line_width texture {T} #if(VMD_clip_on[1]) clipped_by {VMD_clip[1]} #end %s}\n", (shadows_enabled()) ? "" : "no_shadow");
00978   fprintf(outfile, "    VMD_clip[2]\n");
00979   fprintf(outfile, "  }\n  #else\n");
00980   fprintf(outfile, "  cylinder {P1, P2, VMD_line_width texture {T} #if(VMD_clip_on[1]) clipped_by {VMD_clip[1]} #end %s}\n", (shadows_enabled()) ? "" : "no_shadow");
00981   fprintf(outfile, "  #end\n");
00982   fprintf(outfile, "#end\n");
00983 
00984   // Sphere
00985   fprintf(outfile, "#macro VMD_sphere (P1, R1, C1)\n");
00986   fprintf(outfile, "  #local T = texture { pigment { C1 } }\n");
00987   fprintf(outfile, "  #if(VMD_clip_on[2])\n");
00988   fprintf(outfile, "  intersection {\n");
00989   fprintf(outfile, "    sphere {P1, R1 texture {T} #if(VMD_clip_on[1]) clipped_by {VMD_clip[1]} #end %s}\n", (shadows_enabled()) ? "" : "no_shadow");
00990   fprintf(outfile, "    VMD_clip[2]\n");
00991   fprintf(outfile, "  }\n  #else\n");
00992   fprintf(outfile, "  sphere {P1, R1 texture {T} #if(VMD_clip_on[1]) clipped_by {VMD_clip[1]} #end %s}\n", (shadows_enabled()) ? "" : "no_shadow");
00993   fprintf(outfile, "  #end\n");
00994   fprintf(outfile, "#end\n");
00995 
00996   // Cylinder: open iff O1 == 1
00997   fprintf(outfile, "#macro VMD_cylinder (P1, P2, R1, C1, O1)\n");
00998   fprintf(outfile, "  #local T = texture { pigment { C1 } }\n");
00999   fprintf(outfile, "  #if(VMD_clip_on[2])\n");
01000   fprintf(outfile, "  intersection {\n");
01001   fprintf(outfile, "    cylinder {P1, P2, R1 #if(O1) open #end texture {T} #if(VMD_clip_on[1]) clipped_by {VMD_clip[1]} #end %s}\n", (shadows_enabled()) ? "" : "no_shadow");
01002   fprintf(outfile, "    VMD_clip[2]\n");
01003   fprintf(outfile, "  }\n  #else\n");
01004   fprintf(outfile, "  cylinder {P1, P2, R1 #if(O1) open #end texture {T} #if(VMD_clip_on[1]) clipped_by {VMD_clip[1]} #end %s}\n", (shadows_enabled()) ? "" : "no_shadow");
01005   fprintf(outfile, "  #end\n");
01006   fprintf(outfile, "#end\n");
01007 
01008   // Cone: use the current lineWidth for the cap radius
01009   fprintf(outfile, "#macro VMD_cone (P1, P2, R1, C1)\n");
01010   fprintf(outfile, "  #local T = texture { pigment { C1 } }\n");
01011   fprintf(outfile, "  #if(VMD_clip_on[2])\n");
01012   fprintf(outfile, "  intersection {\n");
01013   fprintf(outfile, "    cone {P1, R1, P2, VMD_line_width texture {T} #if(VMD_clip_on[1]) clipped_by {VMD_clip[1]} #end %s}\n", (shadows_enabled()) ? "" : "no_shadow");
01014   fprintf(outfile, "    VMD_clip[2]\n");
01015   fprintf(outfile, "  }\n  #else\n");
01016   fprintf(outfile, "  cone {P1, R1, P2, VMD_line_width texture {T} #if(VMD_clip_on[1]) clipped_by {VMD_clip[1]} #end %s}\n", (shadows_enabled()) ? "" : "no_shadow");
01017   fprintf(outfile, "  #end\n");
01018   fprintf(outfile, "#end\n");
01019 
01020   // Triangle: single color, vertex normals
01021   // XXX - don't CSG clip triangles, behavior is undefined
01022   fprintf(outfile, "#macro VMD_triangle (P1, P2, P3, N1, N2, N3, C1)\n");
01023   fprintf(outfile, "  #local T = texture { pigment { C1 } }\n");
01024   fprintf(outfile, "  smooth_triangle {P1, N1, P2, N2, P3, N3 texture {T} #if(VMD_clip_on[1]) clipped_by {VMD_clip[1]} #end %s}\n", (shadows_enabled()) ? "" : "no_shadow");
01025   fprintf(outfile, "#end\n");
01026 
01027   // Tricolor: vertex colors and normals
01028   // XXX - don't CSG clip triangles, behavior is undefined
01029   fprintf(outfile, "#macro VMD_tricolor (P1, P2, P3, N1, N2, N3, C1, C2, C3)\n");
01030   fprintf(outfile, "  #local NX = P2-P1;\n");
01031   fprintf(outfile, "  #local NY = P3-P1;\n");
01032   fprintf(outfile, "  #local NZ = vcross(NX, NY);\n");
01033   fprintf(outfile, "  #local T = texture { pigment {\n");
01034 
01035   // Create a color cube with the vertex colors at three corners
01036   fprintf(outfile, "    average pigment_map {\n");
01037   fprintf(outfile, "      [1 gradient x color_map {[0 rgb 0] [1 C2*3]}]\n");
01038   fprintf(outfile, "      [1 gradient y color_map {[0 rgb 0] [1 C3*3]}]\n");
01039   fprintf(outfile, "      [1 gradient z color_map {[0 rgb 0] [1 C1*3]}]\n");
01040   fprintf(outfile, "    }\n");
01041 
01042   // Transform the cube so those corners match the triangle vertices
01043   fprintf(outfile, "    matrix <1.01,0,1,0,1.01,1,0,0,1,-.002,-.002,-1>\n");
01044   fprintf(outfile, "    matrix <NX.x,NX.y,NX.z,NY.x,NY.y,NY.z,NZ.x,NZ.y,NZ.z,P1.x,P1.y,P1.z>\n");
01045   fprintf(outfile, "  } }\n");
01046 
01047   fprintf(outfile, "  smooth_triangle {P1, N1, P2, N2, P3, N3 texture {T} #if(VMD_clip_on[1]) clipped_by {VMD_clip[1]} #end %s}\n", (shadows_enabled()) ? "" : "no_shadow");
01048   fprintf(outfile, "#end\n");
01049 
01050 
01051   // Camera position
01052   // POV uses a left-handed coordinate system 
01053   // VMD uses right-handed, so z(pov) = -z(vmd).
01054 
01055   switch (projection()) {
01056 
01057     case DisplayDevice::ORTHOGRAPHIC:
01058 
01059       fprintf(outfile, "camera {\n");
01060       fprintf(outfile, "  orthographic\n");
01061       fprintf(outfile, "  location <%.4f, %.4f, %.4f>\n",
01062               eyePos[0], eyePos[1], -eyePos[2]);
01063       fprintf(outfile, "  look_at <%.4f, %.4f, %.4f>\n",
01064               eyeDir[0], eyeDir[1], -eyeDir[2]);
01065       fprintf(outfile, "  up <0.0000, %.4f, 0.0000>\n", vSize / 2.0f);
01066       fprintf(outfile, "  right <%.4f, 0.0000, 0.0000>\n", Aspect * vSize / 2.0f);
01067       fprintf(outfile, "}\n");
01068 
01069       break;
01070 
01071     case DisplayDevice::PERSPECTIVE:
01072     default:
01073 
01074       if (whichEye != DisplayDevice::NOSTEREO) {
01075          if (whichEye == DisplayDevice::LEFTEYE)
01076             fprintf(outfile, "// Stereo rendering enabled. Now rendering left eye.\n");
01077          else
01078             fprintf(outfile, "// Stereo rendering enabled. Now rendering right eye.\n");
01079 
01080          fprintf(outfile, "// POV-Ray may give you a warning about non-perpendicular\n");
01081          fprintf(outfile, "// camera vectors; this is a result of the stereo rendering.\n");
01082          fprintf(outfile, "#warning \"You may ignore the following warning about "
01083                           "nonperpendicular camera vectors.\"\n");
01084       }
01085 
01086       fprintf(outfile, "camera {\n");
01087       fprintf(outfile, "  up <0, %.4f, 0>\n", vSize);
01088       fprintf(outfile, "  right <%.4f, 0, 0>\n", Aspect * vSize);
01089       fprintf(outfile, "  location <%.4f, %.4f, %.4f>\n",
01090               eyePos[0], eyePos[1], -eyePos[2]);
01091       fprintf(outfile, "  look_at <%.4f, %.4f, %.4f>\n",
01092               eyePos[0] + eyeDir[0],
01093               eyePos[1] + eyeDir[1],
01094               -(eyePos[2] + eyeDir[2]));
01095 
01096 
01097       // POV-Ray doesn't handle negative directions (i.e. when the image
01098       // plane is behind the viewpoint) well: the image should be mirrored
01099       // about both the x and y axes. We simulate this case by using a sky
01100       // vector.
01101       zDirection = eyePos[2] - zDist;
01102       if (zDirection < 0) {
01103         fprintf(outfile, "  direction <%.4f, %.4f, %.4f>\n",
01104                 -eyePos[0], -eyePos[1], -zDirection);
01105         fprintf(outfile, "  sky <0, -1, 0>\n");
01106       }
01107       else {
01108         fprintf(outfile, "  direction <%.4f, %.4f, %.4f>\n",
01109                 -eyePos[0], -eyePos[1], zDirection);
01110       }
01111 
01112 
01113       // render with depth of field, but only for perspective projection
01114       if (dof_enabled() && (projection() == DisplayDevice::PERSPECTIVE)) {
01115         msgInfo << "DoF focal blur enabled." << sendmsg;
01116         fprintf(outfile, "  focal_point <%g, %g, %g>\n",
01117                 eyePos[0] + eyeDir[0]*get_dof_focal_dist(),
01118                 eyePos[1] + eyeDir[1]*get_dof_focal_dist(),
01119                 -(eyePos[2] + eyeDir[2]*get_dof_focal_dist()));
01120         fprintf(outfile, "  aperture %f\n", 
01121                 vSize * 4.0f * get_dof_focal_dist() / get_dof_fnumber());
01122         fprintf(outfile, "  blur_samples 100\n");
01123         fprintf(outfile, "  confidence 0.9\n");
01124         fprintf(outfile, "  variance 1/128\n");
01125       }
01126 
01127       fprintf(outfile, "}\n");
01128 
01129       break;
01130 
01131   } // switch (projection())
01132         
01133   // Lights
01134   int i;
01135   for (i=0;i<DISP_LIGHTS;i++) {
01136     if (lightState[i].on) {
01137       // directional light source, as implemented in povray 3.5
01138       fprintf(outfile, "light_source { \n  <%.4f, %.4f, %.4f> \n",
01139               lightState[i].pos[0], lightState[i].pos[1],
01140               -lightState[i].pos[2]);
01141       fprintf(outfile, "  color rgb<%.3f, %.3f, %.3f> \n",
01142               lightState[i].color[0], lightState[i].color[1],
01143               lightState[i].color[2]);
01144       fprintf(outfile, "  parallel \n  point_at <0.0, 0.0, 0.0> \n}\n");
01145     }
01146   }
01147        
01148 
01149   // background color
01150   fprintf(outfile, "background {\n  color rgb<%.3f, %.3f, %.3f>\n}\n", 
01151           backColor[0], backColor[1], backColor[2]);
01152 
01153   // Specify background sky sphere if background gradient mode is enabled.
01154   if (backgroundmode == 1) {
01155     fprintf(outfile, "\n");
01156     fprintf(outfile, "sky_sphere {\n");
01157     fprintf(outfile, "  pigment {\n");
01158     fprintf(outfile, "    gradient y\n");
01159     fprintf(outfile, "    color_map {\n");
01160     fprintf(outfile, "      [ 0.0  color rgb<%.3f, %.3f, %.3f> ]\n",
01161             backgradientbotcolor[0], backgradientbotcolor[1], backgradientbotcolor[2]);
01162     fprintf(outfile, "      [ 1.0  color rgb<%.3f, %.3f, %.3f> ]\n",
01163             backgradienttopcolor[0], backgradienttopcolor[1], backgradienttopcolor[2]);
01164     fprintf(outfile, "    }\n");
01165     fprintf(outfile, "    scale 2\n");
01166     fprintf(outfile, "    translate -1\n");
01167     fprintf(outfile, "  }\n");
01168     fprintf(outfile, "}\n");
01169     fprintf(outfile, "\n");
01170   }
01171 
01172   // depth-cueing (fog)
01173   if (cueingEnabled && (get_cue_density() >= 1e-4)) {
01174     fprintf(outfile, "fog {\n");
01175 
01176     switch (cueMode) {
01177       case CUE_EXP2:
01178       case CUE_LINEAR:
01179       case CUE_EXP:
01180         // XXX We use povray's exponential fog for all cases 
01181         // since it doesn't currently support any other fog types yet.
01182         fprintf(outfile, "  distance %.4f \n", 
01183                 (get_cue_density() >= 1e4) ? 1e-4 : 1.0/get_cue_density() );
01184         fprintf(outfile, "  fog_type 1 \n");
01185       break;
01186 
01187       case NUM_CUE_MODES:
01188         // this should never happen
01189         break;
01190     }
01191 
01192     // for depth-cueing, the fog color is the background color
01193     fprintf(outfile, "  color rgb<%.3f, %.3f, %.3f> \n",
01194             backColor[0], backColor[1], backColor[2] );
01195     fprintf(outfile, "} \n");
01196   }
01197 }
01198 
01199 void POV3DisplayDevice::write_trailer(void){
01200   fprintf(outfile, "// End of POV-Ray 3.x generation \n");
01201 
01202   if (degenerate_cones != 0) {
01203     msgWarn << "Skipped " << degenerate_cones 
01204             << " degenerate cones" << sendmsg;
01205   }
01206   if (degenerate_cylinders != 0) {
01207     msgWarn << "Skipped " << degenerate_cylinders 
01208             << " degenerate cylinders" << sendmsg;
01209   }
01210   if (degenerate_triangles != 0) {
01211     msgWarn << "Skipped " << degenerate_triangles 
01212             << " degenerate triangles" << sendmsg;
01213   }
01214 
01215   reset_vars(); // Reset variables before the next rendering.
01216 }
01217     
01218 
01219 void POV3DisplayDevice::write_materials(void) {
01220   if (old_materialIndex != materialIndex) {
01221 
01222     old_materialIndex = materialIndex;
01223 
01224     fprintf(outfile, "#default { texture {\n");
01225     fprintf(outfile, " finish { ambient %.3f diffuse %.3f",
01226       mat_ambient, mat_diffuse);
01227     fprintf(outfile, " phong 0.1 phong_size %.3f specular %.3f }\n",
01228       mat_shininess, mat_specular);
01229     fprintf(outfile, "} }\n");
01230   }
01231 }
01232 
01233 
01234 void POV3DisplayDevice::start_clipgroup(void) {
01235   int i, num_clipplanes[3], mode;
01236   float pov_clip_center[3], pov_clip_distance[VMD_MAX_CLIP_PLANE];
01237   float pov_clip_normal[VMD_MAX_CLIP_PLANE][3];
01238 
01239   write_materials();
01240 
01241   memset(num_clipplanes, 0, 3*sizeof(int));
01242   for (i = 0; i < VMD_MAX_CLIP_PLANE; i++) {
01243     if (clip_mode[i] != 0) {
01244       // Count the number of clipping planes for each clip mode
01245       num_clipplanes[clip_mode[i]]++;
01246 
01247       // Translate the plane center
01248       (transMat.top()).multpoint3d(clip_center[i], pov_clip_center);
01249 
01250       // and the normal
01251       (transMat.top()).multnorm3d(clip_normal[i], pov_clip_normal[i]);
01252       vec_negate(pov_clip_normal[i], pov_clip_normal[i]);
01253 
01254       // POV-Ray uses the distance from the origin to the plane for its
01255       // representation, instead of the plane center
01256       pov_clip_distance[i] = dot_prod(pov_clip_normal[i], pov_clip_center);
01257     }
01258   }
01259 
01260   // Define the clip object for each clip mode
01261   for (mode = 1; mode < 3; mode++) {
01262     if (num_clipplanes[mode] > 0) {
01263       // This flag is used within VMD to determine if clipping information
01264       // should be written to the scene file
01265       clip_on[mode] = 1;
01266 
01267       // This flag is used within POV to determine if clipping should be done
01268       // within macros
01269       fprintf(outfile, "#declare VMD_clip_on[%d]=1;\n", mode);
01270 
01271       if (num_clipplanes[mode] == 1) {
01272         for (i = 0; i < VMD_MAX_CLIP_PLANE; i++) {
01273           if (clip_mode[i] == mode) {
01274             if (mode == 2) {
01275               // Textured plane for CSG clipping
01276               fprintf(outfile, "#declare VMD_clip[%d] = plane { <%.4f, %.4f, %.4f>, %.4f texture { pigment { rgbt<%.3f, %.3f, %.3f, %.3f> } } }\n",
01277                       mode, pov_clip_normal[i][0], pov_clip_normal[i][1], 
01278                       -pov_clip_normal[i][2], pov_clip_distance[i],
01279                       clip_color[i][0], clip_color[i][1], clip_color[i][2],
01280                       1 - mat_opacity);
01281             } else {
01282               // Non-textured plane for non-CSG clipping
01283               fprintf(outfile, "#declare VMD_clip[%d] = plane { <%.4f, %.4f, %.4f>, %.4f }\n",
01284                       mode, pov_clip_normal[i][0], pov_clip_normal[i][1], 
01285                       -pov_clip_normal[i][2], pov_clip_distance[i]);
01286 
01287 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND)
01288               // Non-textured plane for non-CSG clipping, but scaled for use
01289               // when emitting meshes with the scaling hack.
01290               fprintf(outfile, "#declare VMD_scaledclip[%d] = plane { <%.4f, %.4f, %.4f>, %.4f }\n",
01291                       mode, pov_clip_normal[i][0], pov_clip_normal[i][1], -pov_clip_normal[i][2], 
01292                       pov_clip_distance[i] * POVRAY_SCALEHACK);
01293 #endif
01294             }
01295           }
01296         }
01297       }
01298 
01299       // Declare the clipping object to be an intersection of planes
01300       else {
01301         fprintf(outfile, "#declare VMD_clip[%d] = intersection {\n", mode);
01302         for (i = 0; i < VMD_MAX_CLIP_PLANE; i++) {
01303           if (clip_mode[i] == mode) {
01304             if (mode == 2) {
01305               // Textured plane for CSG clipping
01306               fprintf(outfile, "  plane { <%.4f, %.4f, %.4f>, %.4f texture { pigment { rgbt<%.3f, %.3f, %.3f, %.3f> } } }\n",
01307                       pov_clip_normal[i][0], pov_clip_normal[i][1], 
01308                       -pov_clip_normal[i][2], pov_clip_distance[i],
01309                       clip_color[i][0], clip_color[i][1], clip_color[i][2],
01310                       1 - mat_opacity);
01311             } else {
01312               // Non-textured plane for non-CSG clipping
01313               fprintf(outfile, "  plane { <%.4f, %.4f, %.4f>, %.4f }\n",
01314                     pov_clip_normal[i][0], pov_clip_normal[i][1], 
01315                     -pov_clip_normal[i][2], pov_clip_distance[i]);
01316             }
01317           }
01318         }
01319         fprintf(outfile, "}\n");
01320 
01321 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND)
01322         fprintf(outfile, "#declare VMD_scaledclip[%d] = intersection {\n", mode);
01323         for (i = 0; i < VMD_MAX_CLIP_PLANE; i++) {
01324           if (clip_mode[i] == mode) {
01325             if (mode == 2) {
01326               // Textured plane for CSG clipping
01327               fprintf(outfile, "  plane { <%.4f, %.4f, %.4f>, %.4f texture { pigment { rgbt<%.3f, %.3f, %.3f, %.3f> } } }\n",
01328                       pov_clip_normal[i][0], pov_clip_normal[i][1], 
01329                       -pov_clip_normal[i][2], pov_clip_distance[i] * POVRAY_SCALEHACK,
01330                       clip_color[i][0], clip_color[i][1], clip_color[i][2],
01331                       1 - mat_opacity);
01332             } else {
01333               // Non-textured plane for non-CSG clipping
01334               fprintf(outfile, "  plane { <%.4f, %.4f, %.4f>, %.4f }\n",
01335                     pov_clip_normal[i][0], pov_clip_normal[i][1], 
01336                     -pov_clip_normal[i][2], pov_clip_distance[i] * POVRAY_SCALEHACK);
01337             }
01338           }
01339         }
01340         fprintf(outfile, "}\n");
01341 #endif
01342 
01343 
01344       }
01345 
01346     }
01347   }
01348 }
01349 
01350 void POV3DisplayDevice::end_clipgroup(void) {
01351   int i;
01352   for (i = 0; i < 3; i++) {
01353     if (clip_on[i]) {
01354       fprintf(outfile, "#declare VMD_clip_on[%d]=0;\n", i);
01355       clip_on[i] = 0;
01356     }
01357   }
01358 }
01359 
01360 void POV3DisplayDevice::set_line_width(int new_width) {
01361   // XXX - find out why lineWidth is getting set outside this function!
01362 //  if (lineWidth != new_width) {
01363   {
01364     lineWidth = new_width;
01365     fprintf(outfile, "#declare VMD_line_width=%.4f;\n", 
01366             ((float)new_width)*DEFAULT_RADIUS);
01367   }
01368 }
01369 

Generated on Wed Apr 24 02:43:12 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002