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

TachyonDisplayDevice.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 /***************************************************************************
00010 * RCS INFORMATION:
00011 *
00012 *      $RCSfile: TachyonDisplayDevice.C,v $
00013 *      $Author: johns $        $Locker:  $               $State: Exp $
00014 *      $Revision: 1.135 $        $Date: 2022/03/21 01:54:41 $
00015 *
00016 ***************************************************************************/
00023 #include <string.h>
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026 #include <math.h>
00027 #include "TachyonDisplayDevice.h"
00028 #include "Matrix4.h"
00029 #include "DispCmds.h"
00030 #include "Inform.h"
00031 #include "utilities.h"
00032 #include "config.h"    // for VMDVERSION string
00033 #include "Hershey.h"   // needed for Hershey font rendering fctns
00034 
00035 #define DEFAULT_RADIUS 0.002f
00036 #define DASH_LENGTH 0.02f
00037 
00038 #if defined(_MSC_VER) || defined(WIN32)
00039 #define TACHYON_RUN_STRING " -aasamples 12 %s -format BMP -o %s.bmp"
00040 #else
00041 #define TACHYON_RUN_STRING " -aasamples 12 %s -format TARGA -o %s.tga"
00042 #endif
00043 
00044 static char tachyon_run_string[2048];
00045 
00046 static char * get_tachyon_run_string() {
00047   char *tbin;
00048   strcpy(tachyon_run_string, "tachyon");
00049   
00050   if ((tbin=getenv("TACHYON_BIN")) != NULL) {
00051     sprintf(tachyon_run_string, "\"%s\"", tbin);
00052   }
00053   strcat(tachyon_run_string, TACHYON_RUN_STRING);
00054  
00055   return tachyon_run_string;
00056 }
00057 
00058 void TachyonDisplayDevice::update_exec_cmd() {
00059   const char *tbin;
00060   if ((tbin = getenv("TACHYON_BIN")) == NULL)
00061     tbin = "tachyon";
00062 
00063   switch(curformat) {
00064     case 0:  // BMP
00065       sprintf(tachyon_run_string, 
00066         "\"%s\" -aasamples %d %%s -format %s -o %%s.%s", tbin, aasamples, "BMP", "bmp");
00067       break;
00068 
00069     case 1: // PPM
00070       sprintf(tachyon_run_string, 
00071         "\"%s\" -aasamples %d %%s -format %s -o %%s.%s", tbin, aasamples, "PPM", "ppm");
00072       break;
00073 
00074     case 2: // PPM48
00075       sprintf(tachyon_run_string, 
00076         "\"%s\" -aasamples %d %%s -format %s -o %%s.%s", tbin, aasamples, "PPM48", "ppm");
00077       break;
00078 
00079     case 3: // PSD
00080       sprintf(tachyon_run_string, 
00081         "\"%s\" -aasamples %d %%s -format %s -o %%s.%s", tbin, aasamples, "PSD48", "psd");
00082       break;
00083 
00084     case 4: // SGI RGB
00085       sprintf(tachyon_run_string, 
00086         "\"%s\" -aasamples %d %%s -format %s -o %%s.%s", tbin, aasamples, "RGB", "rgb");
00087       break;
00088 
00089     case 5: // TARGA
00090     default:
00091       sprintf(tachyon_run_string, 
00092         "\"%s\" -aasamples %d %%s -format %s -o %%s.%s", tbin, aasamples, "TARGA", "tga");
00093       break;
00094   }
00095   delete [] execCmd;
00096   execCmd = stringdup(tachyon_run_string);
00097 }
00098 
00100 
00101 // constructor ... initialize some variables
00102 
00103 TachyonDisplayDevice::TachyonDisplayDevice() : FileRenderer ("Tachyon", "Tachyon", "vmdscene.dat", get_tachyon_run_string()) { 
00104   // Add supported file formats
00105   formats.add_name("BMP", 0);
00106   formats.add_name("PPM", 0);
00107   formats.add_name("PPM48", 0);
00108   formats.add_name("PSD48", 0);
00109   formats.add_name("RGB", 0);
00110   formats.add_name("TGA", 0);
00111 
00112   // Set default aa level
00113   has_aa = TRUE;
00114   aasamples = 12;
00115   aosamples = 12;
00116 
00117   reset_vars();
00118 
00119   // Default image format depends on platform
00120 #if defined(_MSC_VER) || defined(WIN32)
00121   curformat = 0; // Windows BMP
00122 #else
00123   curformat = 5; // Targa
00124 #endif
00125 }
00126         
00127 // destructor
00128 TachyonDisplayDevice::~TachyonDisplayDevice(void) { }
00129 
00131 
00132 void TachyonDisplayDevice::reset_vars(void) {
00133   inclipgroup = 0; // not currently in a clipping group
00134   involtex = 0;    // volume texturing disabled
00135   voltexID = -1;   // invalid texture ID
00136   memset(xplaneeq, 0, sizeof(xplaneeq));
00137   memset(yplaneeq, 0, sizeof(xplaneeq));
00138   memset(zplaneeq, 0, sizeof(xplaneeq));
00139 }  
00140 
00141 
00142 // emit a comment line 
00143 void TachyonDisplayDevice::comment(const char *s) {
00144   fprintf(outfile, "# %s\n", s);
00145 }
00146 
00147 
00148 void TachyonDisplayDevice::text(float *pos, float size, float thickness, 
00149                                 const char *str) {
00150   float textpos[3];
00151   float textsize, textthickness;
00152   hersheyhandle hh;
00153 
00154   // transform the world coordinates
00155   (transMat.top()).multpoint3d(pos, textpos);
00156   textsize = size * 1.5f;
00157   textthickness = thickness*DEFAULT_RADIUS;
00158 
00159   while (*str != '\0') {
00160     float lm, rm, x, y, ox, oy;
00161     int draw, odraw;
00162     ox=oy=x=y=0.0f;
00163     draw=odraw=0;
00164 
00165     hersheyDrawInitLetter(&hh, *str, &lm, &rm);
00166     textpos[0] -= lm * textsize;
00167 
00168     while (!hersheyDrawNextLine(&hh, &draw, &x, &y)) {
00169       float oldpt[3], newpt[3];
00170       if (draw) {
00171         newpt[0] = textpos[0] + textsize * x;
00172         newpt[1] = textpos[1] + textsize * y;
00173         newpt[2] = textpos[2];
00174 
00175         if (odraw) {
00176           // if we have both previous and next points, connect them...
00177           oldpt[0] = textpos[0] + textsize * ox;
00178           oldpt[1] = textpos[1] + textsize * oy;
00179           oldpt[2] = textpos[2];
00180 
00181           fprintf(outfile, "FCylinder\n"); // flat-ended cylinder
00182           fprintf(outfile, "  Base %g %g %g\n", oldpt[0], oldpt[1], -oldpt[2]); 
00183           fprintf(outfile, "  Apex %g %g %g\n", newpt[0], newpt[1], -newpt[2]);
00184           fprintf(outfile, "  Rad %g \n", textthickness);
00185           write_cindexmaterial(colorIndex, materialIndex);
00186 
00187           fprintf(outfile, "Sphere \n");  // sphere
00188           fprintf(outfile, "  Center %g %g %g \n", newpt[0], newpt[1], -newpt[2]);
00189           fprintf(outfile, "  Rad %g \n", textthickness); 
00190           write_cindexmaterial(colorIndex, materialIndex);
00191         } else {
00192           // ...otherwise, just draw the next point
00193           fprintf(outfile, "Sphere \n");  // sphere
00194           fprintf(outfile, "  Center %g %g %g \n", newpt[0], newpt[1], -newpt[2]);
00195           fprintf(outfile, "  Rad %g \n", textthickness); 
00196           write_cindexmaterial(colorIndex, materialIndex);
00197         }
00198       }
00199 
00200       ox=x;
00201       oy=y;
00202       odraw=draw;
00203     }
00204     textpos[0] += rm * textsize;
00205 
00206     str++;
00207   }
00208 }
00209 
00210 
00211 // draw a point
00212 void TachyonDisplayDevice::point(float * spdata) {
00213   float vec[3];
00214   // transform the world coordinates
00215   (transMat.top()).multpoint3d(spdata, vec);
00216 
00217   // draw a sphere to represent the point, since we can't really draw points
00218   fprintf(outfile, "Sphere \n");  // sphere
00219   fprintf(outfile, "  Center %g %g %g \n ", vec[0], vec[1], -vec[2]);
00220   fprintf(outfile, "  Rad %g \n",     float(lineWidth)*DEFAULT_RADIUS); 
00221   write_cindexmaterial(colorIndex, materialIndex);
00222 }
00223 
00224 
00225 // draw a sphere
00226 void TachyonDisplayDevice::sphere(float * spdata) {
00227   float vec[3];
00228   float radius;
00229     
00230   // transform the world coordinates
00231   (transMat.top()).multpoint3d(spdata, vec);
00232   radius = scale_radius(spdata[3]);
00233    
00234   // draw the sphere
00235   fprintf(outfile, "Sphere \n");  // sphere
00236   fprintf(outfile, "  Center %g %g %g \n ", vec[0], vec[1], -vec[2]);
00237   fprintf(outfile, "  Rad %g \n", radius ); 
00238   write_cindexmaterial(colorIndex, materialIndex);
00239 }
00240 
00241 
00242 // draw a sphere array
00243 void TachyonDisplayDevice::sphere_array(int spnum, int spres, float *centers, float *radii, float *colors) {
00244   float vec[3];
00245   float radius;
00246   int i, ind;
00247 
00248   ind = 0;
00249   for (i=0; i<spnum; i++) {
00250     // transform the world coordinates
00251     (transMat.top()).multpoint3d(&centers[ind], vec);
00252     radius = scale_radius(radii[i]);
00253 
00254     // draw the sphere
00255     fprintf(outfile, "Sphere \n");  // sphere
00256     fprintf(outfile, "  Center %g %g %g \n ", vec[0], vec[1], -vec[2]);
00257     fprintf(outfile, "  Rad %g \n", radius );
00258     write_colormaterial(&colors[ind], materialIndex);
00259     ind += 3; // next sphere
00260   }
00261 
00262   // set final color state after array has been drawn
00263   ind=(spnum-1)*3;
00264   super_set_color(nearest_index(colors[ind], colors[ind+1], colors[ind+2]));
00265 }
00266 
00267 
00268 // draw a line (cylinder) from a to b
00269 void TachyonDisplayDevice::line(float *a, float*b) {
00270   int i, j, test;
00271   float dirvec[3], unitdirvec[3];
00272   float from[3], to[3], tmp1[3], tmp2[3];
00273     
00274   if (lineStyle == ::SOLIDLINE) {
00275     // transform the world coordinates
00276     (transMat.top()).multpoint3d(a, from);
00277     (transMat.top()).multpoint3d(b, to);
00278     
00279     // draw the cylinder
00280     fprintf(outfile, "FCylinder\n"); // flat-ended cylinder
00281     fprintf(outfile, "  Base %g %g %g\n", from[0], from[1], -from[2]); 
00282     fprintf(outfile, "  Apex %g %g %g\n", to[0], to[1], -to[2]);
00283     fprintf(outfile, "  Rad %g \n", float(lineWidth)*DEFAULT_RADIUS);
00284     write_cindexmaterial(colorIndex, materialIndex);
00285 
00286   } else if (lineStyle == ::DASHEDLINE) {
00287      // transform the world coordinates
00288     (transMat.top()).multpoint3d(a, tmp1);
00289     (transMat.top()).multpoint3d(b, tmp2);
00290 
00291     // how to create a dashed line
00292     vec_sub(dirvec, tmp2, tmp1);  // vector from a to b
00293     vec_copy(unitdirvec, dirvec);
00294     vec_normalize(unitdirvec);    // unit vector from a to b
00295     test = 1;
00296     i = 0;
00297     while (test == 1) {
00298       for (j=0; j<3; j++) {
00299         from[j] = (float) (tmp1[j] + (2*i    )*DASH_LENGTH*unitdirvec[j]);
00300           to[j] = (float) (tmp1[j] + (2*i + 1)*DASH_LENGTH*unitdirvec[j]);
00301       }
00302       if (fabsf(tmp1[0] - to[0]) >= fabsf(dirvec[0])) {
00303         vec_copy(to, tmp2);
00304         test = 0;
00305       }
00306     
00307       // draw the cylinder
00308       fprintf(outfile, "FCylinder\n"); // flat-ended cylinder
00309       fprintf(outfile, "  Base %g %g %g\n", from[0], from[1], -from[2]); 
00310       fprintf(outfile, "  Apex %g %g %g\n", to[0], to[1], -to[2]);
00311       fprintf(outfile, "  Rad %g \n", float(lineWidth)*DEFAULT_RADIUS);
00312       write_cindexmaterial(colorIndex, materialIndex);
00313       i++;
00314     }
00315   } else {
00316     msgErr << "TachyonDisplayDevice: Unknown line style " 
00317            << lineStyle << sendmsg;
00318   }
00319 }
00320 
00321 
00322 
00323 
00324 // draw a cylinder
00325 void TachyonDisplayDevice::cylinder(float *a, float *b, float r, int filled) {
00326   float from[3], to[3], norm[3];
00327   float radius;
00328 
00329   // transform the world coordinates
00330   (transMat.top()).multpoint3d(a, from);
00331   (transMat.top()).multpoint3d(b, to);
00332   radius = scale_radius(r);
00333  
00334   // draw the cylinder
00335   fprintf(outfile, "FCylinder\n"); // flat-ended cylinder
00336   fprintf(outfile, "  Base %g %g %g\n", from[0], from[1], -from[2]); 
00337   fprintf(outfile, "  Apex %g %g %g\n", to[0], to[1], -to[2]);
00338   fprintf(outfile, "  Rad %g\n", radius);
00339   write_cindexmaterial(colorIndex, materialIndex);
00340 
00341   // Cylinder caps?
00342   if (filled) {
00343     float div;
00344 
00345     norm[0] = to[0] - from[0];
00346     norm[1] = to[1] - from[1];
00347     norm[2] = to[2] - from[2];
00348 
00349     div = 1.0f / sqrtf(norm[0]*norm[0] + norm[1]*norm[1] + norm[2]*norm[2]);
00350     norm[0] *= div;
00351     norm[1] *= div;
00352     norm[2] *= div;
00353 
00354     if (filled & CYLINDER_TRAILINGCAP) {
00355       fprintf(outfile, "Ring\n");
00356       fprintf(outfile, "Center %g %g %g \n", from[0], from[1], -from[2]);
00357       fprintf(outfile, "Normal %g %g %g \n", norm[0], norm[1], -norm[2]); 
00358       fprintf(outfile, "Inner 0.0  Outer %g \n", radius);
00359       write_cindexmaterial(colorIndex, materialIndex);
00360     }
00361   
00362     if (filled & CYLINDER_LEADINGCAP) {
00363       fprintf(outfile, "Ring\n");
00364       fprintf(outfile, "Center %g %g %g \n", to[0], to[1], -to[2]);
00365       fprintf(outfile, "Normal %g %g %g \n", -norm[0], -norm[1], norm[2]); 
00366       fprintf(outfile, "Inner 0.0  Outer %g \n", radius);
00367       write_cindexmaterial(colorIndex, materialIndex);
00368     }
00369   }
00370 }
00371 
00372 
00373 // draw a triangle
00374 void TachyonDisplayDevice::triangle(const float *a, const float *b, const float *c, const float *n1, const float *n2, const float *n3) {
00375   float vec1[3], vec2[3], vec3[3];
00376   float norm1[3], norm2[3], norm3[3];
00377   
00378   
00379   // transform the world coordinates
00380   (transMat.top()).multpoint3d(a, vec1);
00381   (transMat.top()).multpoint3d(b, vec2);
00382   (transMat.top()).multpoint3d(c, vec3);
00383 
00384   // and the normals
00385   (transMat.top()).multnorm3d(n1, norm1);
00386   (transMat.top()).multnorm3d(n2, norm2);
00387   (transMat.top()).multnorm3d(n3, norm3);
00388 
00389   // draw the triangle
00390   fprintf(outfile, "STri\n"); // triangle
00391   fprintf(outfile, "  V0 %g %g %g\n", vec1[0], vec1[1], -vec1[2]);
00392   fprintf(outfile, "  V1 %g %g %g\n", vec2[0], vec2[1], -vec2[2]); 
00393   fprintf(outfile, "  V2 %g %g %g\n", vec3[0], vec3[1], -vec3[2]);
00394   fprintf(outfile, "  N0 %.3f %.3f %.3f\n", -norm1[0], -norm1[1], norm1[2]);
00395   fprintf(outfile, "  N1 %.3f %.3f %.3f\n", -norm2[0], -norm2[1], norm2[2]); 
00396   fprintf(outfile, "  N2 %.3f %.3f %.3f\n", -norm3[0], -norm3[1], norm3[2]);
00397   write_cindexmaterial(colorIndex, materialIndex);
00398 }
00399 
00400 // draw triangle with per-vertex colors
00401 void TachyonDisplayDevice::tricolor(const float * xyz1, const float * xyz2, const float * xyz3,
00402                                     const float * n1,   const float * n2,   const float * n3,
00403                                     const float *c1, const float *c2, const float *c3) {
00404   float vec1[3], vec2[3], vec3[3];
00405   float norm1[3], norm2[3], norm3[3];
00406 
00407   // transform the world coordinates
00408   (transMat.top()).multpoint3d(xyz1, vec1);
00409   (transMat.top()).multpoint3d(xyz2, vec2);
00410   (transMat.top()).multpoint3d(xyz3, vec3);
00411 
00412   // and the normals
00413   (transMat.top()).multnorm3d(n1, norm1);
00414   (transMat.top()).multnorm3d(n2, norm2);
00415   (transMat.top()).multnorm3d(n3, norm3);
00416 
00417   // draw the triangle
00418   if (!involtex) {
00419     fprintf(outfile, "VCSTri\n"); // triangle
00420   } else {
00421     fprintf(outfile, "STri\n"); // triangle
00422   }
00423   fprintf(outfile, "  V0 %g %g %g\n", vec1[0], vec1[1], -vec1[2]);
00424   fprintf(outfile, "  V1 %g %g %g\n", vec2[0], vec2[1], -vec2[2]);
00425   fprintf(outfile, "  V2 %g %g %g\n", vec3[0], vec3[1], -vec3[2]);
00426 
00427   fprintf(outfile, "  N0 %.3f %.3f %.3f\n", -norm1[0], -norm1[1], norm1[2]);
00428   fprintf(outfile, "  N1 %.3f %.3f %.3f\n", -norm2[0], -norm2[1], norm2[2]);
00429   fprintf(outfile, "  N2 %.3f %.3f %.3f\n", -norm3[0], -norm3[1], norm3[2]);
00430 
00431   if (!involtex) {
00432     fprintf(outfile, "  C0 %.3f %.3f %.3f\n", c1[0], c1[1], c1[2]);
00433     fprintf(outfile, "  C1 %.3f %.3f %.3f\n", c2[0], c2[1], c2[2]);
00434     fprintf(outfile, "  C2 %.3f %.3f %.3f\n", c3[0], c3[1], c3[2]);
00435   }
00436 
00437   if (materials_on) {
00438     fprintf(outfile, "  Ambient %g Diffuse %g Specular %g Opacity %g\n",
00439             mat_ambient, mat_diffuse, mat_mirror, mat_opacity);
00440   } else {
00441     fprintf(outfile, "  Ambient %g Diffuse %g Specular %g Opacity %g\n",
00442             1.0, 0.0, 0.0, mat_opacity);
00443   }
00444 
00445   if (mat_transmode != 0) {
00446     fprintf(outfile, "  TransMode R3D ");
00447   }
00448   if (mat_outline > 0.0) {
00449     fprintf(outfile, "  Outline %g Outline_Width %g ", 
00450             mat_outline, mat_outlinewidth);
00451   }
00452   fprintf(outfile, "  Phong Plastic %g Phong_size %g ", mat_specular,
00453           mat_shininess);
00454   fprintf(outfile, "VCST\n\n");
00455 }
00456 
00457 
00458 // use an efficient mesh primitve rather than individual triangles
00459 // when possible.
00460 void TachyonDisplayDevice::trimesh_c4n3v3(int numverts, float * cnv,
00461                                           int numfacets, int * facets) {
00462   int i;
00463   float vec1[3];
00464   float norm1[3];
00465 
00466   fprintf(outfile, "VertexArray");
00467   fprintf(outfile, "  Numverts %d\n", numverts);
00468 
00469   fprintf(outfile, "\nCoords\n");
00470   for (i=0; i<numverts; i++) {
00471     (transMat.top()).multpoint3d(cnv + i*10 + 7, vec1);
00472     fprintf(outfile, "%g %g %g\n", vec1[0], vec1[1], -vec1[2]);
00473   } 
00474 
00475   fprintf(outfile, "\nNormals\n");
00476   for (i=0; i<numverts; i++) {
00477     (transMat.top()).multnorm3d(cnv + i*10 + 4, norm1);
00478     fprintf(outfile, "%.3f %.3f %.3f\n", -norm1[0], -norm1[1], norm1[2]);
00479   } 
00480 
00481   // don't emit per-vertex colors when volumetric texturing is enabled
00482   if (!involtex) {
00483     fprintf(outfile, "\nColors\n");
00484     for (i=0; i<numverts; i++) {
00485       int idx = i * 10;
00486       fprintf(outfile, "%.3f %.3f %.3f\n", cnv[idx], cnv[idx+1], cnv[idx+2]);
00487     } 
00488   }
00489 
00490   // emit the texture to be used by the geometry that follows
00491   write_cindexmaterial(colorIndex, materialIndex);
00492 
00493   // loop over all of the facets in the mesh
00494   fprintf(outfile, "\nTriMesh %d\n", numfacets);
00495   for (i=0; i<numfacets*3; i+=3) {
00496     fprintf(outfile, "%d %d %d\n", facets[i], facets[i+1], facets[i+2]);
00497   }
00498  
00499   // terminate vertex array 
00500   fprintf(outfile, "\nEnd_VertexArray\n");
00501 }
00502 
00503 
00504 // use an efficient mesh primitve rather than individual triangles
00505 // when possible.
00506 void TachyonDisplayDevice::trimesh_c4u_n3b_v3f(unsigned char *c, 
00507                                                signed char *n, 
00508                                                float *v, int numfacets) {
00509   int i;
00510   float vec1[3];
00511   float norm1[3];
00512   int numverts = 3*numfacets;
00513 
00514   const float ci2f = 1.0f / 255.0f; // used for uchar2float and normal conv
00515   const float cn2f = 1.0f / 127.5f;
00516 
00517   fprintf(outfile, "VertexArray");
00518   fprintf(outfile, "  Numverts %d\n", numverts);
00519 
00520   fprintf(outfile, "\nCoords\n");
00521   for (i=0; i<numverts; i++) {
00522     int idx = i * 3;
00523     (transMat.top()).multpoint3d(v + idx, vec1);
00524     fprintf(outfile, "%g %g %g\n", vec1[0], vec1[1], -vec1[2]);
00525   } 
00526 
00527   fprintf(outfile, "\nNormals\n");
00528   for (i=0; i<numverts; i++) {
00529     float ntmp[3];
00530     int idx = i * 3;
00531 
00532     // conversion from GLbyte format, Table 2.6, p. 44 of OpenGL spec 1.2.1
00533     // float = (2c+1)/(2^8-1)
00534     ntmp[0] = n[idx  ] * cn2f + ci2f;
00535     ntmp[1] = n[idx+1] * cn2f + ci2f;
00536     ntmp[2] = n[idx+2] * cn2f + ci2f;
00537     (transMat.top()).multnorm3d(ntmp, norm1);
00538     fprintf(outfile, "%.3f %.3f %.3f\n", -norm1[0], -norm1[1], norm1[2]);
00539   } 
00540 
00541   // don't emit per-vertex colors when volumetric texturing is enabled
00542   if (!involtex) {
00543     fprintf(outfile, "\nColors\n");
00544     for (i=0; i<numverts; i++) {
00545       int idx = i * 4;
00546 
00547       // conversion from GLubyte format, Table 2.6, p. 44 of OpenGL spec 1.2.1
00548       // float = c/(2^8-1)
00549       fprintf(outfile, "%.3f %.3f %.3f\n", 
00550               c[idx  ] * ci2f,
00551               c[idx+1] * ci2f,
00552               c[idx+2] * ci2f);
00553     } 
00554   }
00555 
00556   // emit the texture to be used by the geometry that follows
00557   write_cindexmaterial(colorIndex, materialIndex);
00558 
00559   // loop over all of the facets in the mesh
00560   fprintf(outfile, "\nTriMesh %d\n", numfacets);
00561   for (i=0; i<numfacets*3; i+=3) {
00562     fprintf(outfile, "%d %d %d\n", i, i+1, i+2);
00563   }
00564  
00565   // terminate vertex array 
00566   fprintf(outfile, "\nEnd_VertexArray\n");
00567 }
00568 
00569 
00570 void TachyonDisplayDevice::tristrip(int numverts, const float * cnv,
00571                                    int numstrips, const int *vertsperstrip,
00572                                    const int *facets) {
00573   int i, strip, v=0;
00574   float vec1[3];
00575   float norm1[3];
00576 
00577   fprintf(outfile, "VertexArray");
00578   fprintf(outfile, "  Numverts %d\n", numverts);
00579 
00580   fprintf(outfile, "\nCoords\n");
00581   for (i=0; i<numverts; i++) {
00582     (transMat.top()).multpoint3d(cnv + i*10 + 7, vec1);
00583     fprintf(outfile, "%g %g %g\n", vec1[0], vec1[1], -vec1[2]);
00584   } 
00585 
00586   fprintf(outfile, "\nNormals\n");
00587   for (i=0; i<numverts; i++) {
00588     (transMat.top()).multnorm3d(cnv + i*10 + 4, norm1);
00589     fprintf(outfile, "%.3f %.3f %.3f\n", -norm1[0], -norm1[1], norm1[2]);
00590   } 
00591 
00592   // don't emit per-vertex colors when volumetric texturing is enabled
00593   if (!involtex) {
00594     fprintf(outfile, "\nColors\n");
00595     for (i=0; i<numverts; i++) {
00596       int idx = i * 10;
00597       fprintf(outfile, "%.3f %.3f %.3f\n", cnv[idx], cnv[idx+1], cnv[idx+2]);
00598     } 
00599   }
00600 
00601   // emit the texture to be used by the geometry that follows
00602   write_cindexmaterial(colorIndex, materialIndex);
00603 
00604   // loop over all of the triangle strips
00605   v=0;
00606   for (strip=0; strip < numstrips; strip++) {
00607     fprintf(outfile, "\nTriStrip %d\n", vertsperstrip[strip]);
00608 
00609     // loop over all triangles in this triangle strip
00610     for (i = 0; i < vertsperstrip[strip]; i++) {
00611       fprintf(outfile, "%d ", facets[v]);
00612       v++; // move on to the next triangle
00613     }
00614   }
00615  
00616   // terminate vertex array 
00617   fprintf(outfile, "\nEnd_VertexArray\n");
00618 }
00619 
00620 
00621 // define a volumetric texture map
00622 void TachyonDisplayDevice::define_volume_texture(int ID, 
00623                                                  int xs, int ys, int zs,
00624                                                  const float *xpq,
00625                                                  const float *ypq,
00626                                                  const float *zpq,
00627                                                  unsigned char *texmap) {
00628   voltexID = ID; // remember current texture ID
00629 
00630   memcpy(xplaneeq, xpq, sizeof(xplaneeq));
00631   memcpy(yplaneeq, ypq, sizeof(yplaneeq));
00632   memcpy(zplaneeq, zpq, sizeof(zplaneeq));
00633 
00634   fprintf(outfile, "# VMD volume texture definition: ID %d\n", ID);
00635   fprintf(outfile, "#  Res: %d %d %d\n", xs, ys, zs);
00636   fprintf(outfile, "#  xplaneeq: %g %g %g %g\n",
00637          xplaneeq[0], xplaneeq[1], xplaneeq[2], xplaneeq[3]);
00638   fprintf(outfile, "#  yplaneeq: %g %g %g %g\n",
00639          yplaneeq[0], yplaneeq[1], yplaneeq[2], yplaneeq[3]);
00640   fprintf(outfile, "#  zplaneeq: %g %g %g %g\n",
00641          zplaneeq[0], zplaneeq[1], zplaneeq[2], zplaneeq[3]);
00642 
00643   fprintf(outfile, "ImageDef ::VMDVolTex%d\n", ID);
00644   fprintf(outfile, "  Format RGB24\n");
00645   fprintf(outfile, "  Resolution %d %d %d\n", xs, ys, zs);
00646   fprintf(outfile, "  Encoding Hex\n");
00647  
00648   int x, y, z;
00649   for (z=0; z<zs; z++) {
00650     for (y=0; y<ys; y++) {
00651       int addr = (z * xs * ys) + (y * xs);
00652       for (x=0; x<xs; x++) {
00653         int addr2 = (addr + x) * 3;
00654         fprintf(outfile, "%02x%02x%02x ", 
00655                 texmap[addr2    ],
00656                 texmap[addr2 + 1],
00657                 texmap[addr2 + 2]);
00658       }
00659       fprintf(outfile, "\n");
00660     }
00661     fprintf(outfile, "\n");
00662   }  
00663   fprintf(outfile, "\n");
00664   fprintf(outfile, "# End of volume texture ::VMDVolTex%d\n", ID);
00665   fprintf(outfile, "\n");
00666   fprintf(outfile, "\n");
00667 }
00668 
00669 
00670 // enable volumetric texturing, either in "replace" or "modulate" mode
00671 void TachyonDisplayDevice::volume_texture_on(int texmode) {
00672   involtex = 1;
00673 }
00674 
00675 
00676 // disable volumetric texturing
00677 void TachyonDisplayDevice::volume_texture_off(void) {
00678   involtex = 0;
00679 }
00680 
00681 
00682 void TachyonDisplayDevice::start_clipgroup(void) {
00683   int i;
00684   int planesenabled = 0;
00685 
00686   for (i=0; i<VMD_MAX_CLIP_PLANE; i++) {
00687     if (clip_mode[i] > 0) {
00688       planesenabled++;  /* count number of active clipping planes */
00689       if (clip_mode[i] > 1)
00690         warningflags |= FILERENDERER_NOCLIP; /* emit warnings */
00691     }
00692   }
00693 
00694   if (planesenabled > 0) {
00695     fprintf(outfile, "Start_ClipGroup\n");
00696     fprintf(outfile, " NumPlanes %d\n", planesenabled);
00697     for (i=0; i<VMD_MAX_CLIP_PLANE; i++) { 
00698       if (clip_mode[i] > 0) {
00699         float tachyon_clip_center[3]; 
00700         float tachyon_clip_normal[3];
00701         float tachyon_clip_distance;
00702 
00703         inclipgroup = 1; // we're in a clipping group presently
00704 
00705         // Transform the plane center and the normal
00706         (transMat.top()).multpoint3d(clip_center[i], tachyon_clip_center);
00707         (transMat.top()).multnorm3d(clip_normal[i], tachyon_clip_normal);
00708         vec_negate(tachyon_clip_normal, tachyon_clip_normal);
00709 
00710         // Tachyon uses the distance from the origin to the plane for its
00711         // representation, instead of the plane center
00712         tachyon_clip_distance = dot_prod(tachyon_clip_normal, tachyon_clip_center);
00713 
00714         fprintf(outfile, "%g %g %g %g\n", tachyon_clip_normal[0], 
00715                 tachyon_clip_normal[1], -tachyon_clip_normal[2], 
00716                 tachyon_clip_distance);
00717       }    
00718     }
00719     fprintf(outfile, "\n");
00720   } else {
00721     inclipgroup = 0; // Not currently in a clipping group
00722   }
00723 }
00724 
00725 
00727 
00728 // initialize the file for output
00729 void TachyonDisplayDevice::write_header() {
00730   fprintf(outfile, "# \n"); 
00731   fprintf(outfile, "# Molecular graphics exported from VMD %s\n", VMDVERSION);
00732   fprintf(outfile, "# http://www.ks.uiuc.edu/Research/vmd/\n");
00733   fprintf(outfile, "# \n"); 
00734   fprintf(outfile, "# Requires Tachyon version 0.99.0 or newer\n");
00735   fprintf(outfile, "# \n"); 
00736   fprintf(outfile, "# Default tachyon rendering command for this scene:\n"); 
00737   fprintf(outfile, "#   tachyon %s\n", TACHYON_RUN_STRING); 
00738   fprintf(outfile, "# \n"); 
00739   // NOTE: the vmd variable "Aspect" has absolutely *nothing* to do
00740   //       with aspect ratio correction, it is only the ratio of the
00741   //       width of the graphics window to its height, and so it should
00742   //       be used only to cause the ray tracer to generate a similarly
00743   //       proportioned image.
00744 
00745   fprintf(outfile, "Begin_Scene\n");
00746   fprintf(outfile, "Resolution %d %d\n", (int) xSize, (int) ySize);
00747 
00748 
00749   // Emit shading mode information
00750   fprintf(outfile, "Shader_Mode ");
00751 
00752   // change shading mode depending on whether the user wants shadows
00753   // or ambient occlusion lighting.
00754   if (shadows_enabled() || ao_enabled()) {
00755     fprintf(outfile, "Full\n");
00756   } else {
00757     fprintf(outfile, "Medium\n");
00758   }
00759 
00760   // For VMD we always want to enable flags that preserve a more WYSIWYG  
00761   // type of output, although in some cases doing things in Tachyon's
00762   // preferred way might be nicer.  The user can override these with 
00763   // command line flags still if they want radial fog or other options.
00764   fprintf(outfile, "  Trans_VMD\n");
00765   fprintf(outfile, "  Fog_VMD\n");
00766 
00767   // render with ambient occlusion lighting if required
00768   if (ao_enabled()) {
00769     fprintf(outfile, "  Ambient_Occlusion\n");
00770 
00771 #if 1
00772     // Tachyon 0.99.2 or later adds AO max occlusion distance parameter
00773     if (getenv("VMDTACHYONAOMAXDIST")) {
00774       float tmp = float(atof(getenv("VMDTACHYONAOMAXDIST")));
00775       printf("LibTachyonDisplayDevice) setting AO maxdist: %f\n", tmp);
00776       fprintf(outfile, "    MaxDist %g\n", tmp);
00777     }
00778 #endif
00779 
00780     fprintf(outfile, "    Ambient_Color %g %g %g\n", 
00781             get_ao_ambient(), get_ao_ambient(), get_ao_ambient());
00782     fprintf(outfile, "    Rescale_Direct %g\n", get_ao_direct());
00783     fprintf(outfile, "    Samples %d\n", aosamples);
00784   }
00785   fprintf(outfile, "End_Shader_Mode\n");
00786 
00787   write_camera();    // has to be first thing in the file. 
00788   write_lights();    // could be anywhere.
00789   write_materials(); // has to be before objects that use them.
00790 }
00791 
00792 
00793 void TachyonDisplayDevice::end_clipgroup(void) {
00794   if (inclipgroup) {
00795     fprintf(outfile, "End_ClipGroup\n");
00796     inclipgroup = 0; // we're not in a clipping group anymore
00797   }
00798 }
00799 
00800 
00801 void TachyonDisplayDevice::write_trailer(void){
00802   fprintf(outfile, "End_Scene \n");
00803   if (inclipgroup) {
00804     msgErr << "TachyonDisplayDevice clipping group still active at end of scene\n" << sendmsg;
00805   }
00806   msgInfo << "Tachyon file generation finished" << sendmsg;
00807 
00808   reset_vars();
00809 }
00810 
00811 
00812 
00814 
00815 void TachyonDisplayDevice::write_camera(void) {
00816   int raydepth = 50;
00817  
00818   // Camera position
00819   // Tachyon uses a left-handed coordinate system
00820   // VMD uses right-handed, so z(Tachyon) = -z(VMD).
00821 
00822   switch (projection()) {
00823     // XXX code for new versions of Tachyon that support orthographic views
00824     case DisplayDevice::ORTHOGRAPHIC:
00825       fprintf(outfile, "Camera\n");
00826       fprintf(outfile, "  Projection Orthographic\n");
00827       fprintf(outfile, "  Zoom %g\n", 1.0 / (vSize / 2.0));
00828       fprintf(outfile, "  Aspectratio %g\n", 1.0f);
00829       fprintf(outfile, "  Antialiasing %d\n", aasamples);
00830       fprintf(outfile, "  Raydepth %d\n", raydepth);
00831       fprintf(outfile, "  Center  %g %g %g\n", eyePos[0], eyePos[1], -eyePos[2]);
00832       fprintf(outfile, "  Viewdir %g %g %g\n", eyeDir[0], eyeDir[1], -eyeDir[2]);
00833       fprintf(outfile, "  Updir   %g %g %g\n", upDir[0], upDir[1], -upDir[2]);
00834       fprintf(outfile, "End_Camera\n");
00835       break;
00836 
00837     case DisplayDevice::PERSPECTIVE:
00838     default:
00839       fprintf(outfile, "Camera\n");
00840 
00841       // render with depth of field, but only for perspective projection
00842       if (dof_enabled() && (projection() == DisplayDevice::PERSPECTIVE)) {
00843         msgInfo << "DoF focal blur enabled." << sendmsg;
00844         fprintf(outfile, "  Projection Perspective_DoF\n");
00845         fprintf(outfile, "  FocalDist %f\n", get_dof_focal_dist());
00846         fprintf(outfile, "  Aperture %f\n", get_dof_fnumber());
00847       }
00848 
00849       fprintf(outfile, "  Zoom %g\n", (eyePos[2] - zDist) / vSize);
00850       fprintf(outfile, "  Aspectratio %g\n", 1.0f);
00851       fprintf(outfile, "  Antialiasing %d\n", aasamples);
00852       fprintf(outfile, "  Raydepth %d\n", raydepth);
00853       fprintf(outfile, "  Center  %g %g %g\n", eyePos[0], eyePos[1], -eyePos[2]);
00854       fprintf(outfile, "  Viewdir %g %g %g\n", eyeDir[0], eyeDir[1], -eyeDir[2]);
00855       fprintf(outfile, "  Updir   %g %g %g\n", upDir[0], upDir[1], -upDir[2]);
00856       fprintf(outfile, "End_Camera\n");
00857       break;
00858 
00859   }
00860 }
00861 
00862   
00863 void TachyonDisplayDevice::write_lights(void) {  
00864   // Lights
00865   int i;  
00866   int lightcount = 0;
00867   for (i=0; i<DISP_LIGHTS; i++) {
00868     if (lightState[i].on) {
00869       /* give negated light position as the direction vector */
00870       fprintf(outfile, "Directional_Light Direction %g %g %g ", 
00871               -lightState[i].pos[0],
00872               -lightState[i].pos[1],
00873                lightState[i].pos[2]);
00874       fprintf(outfile, "Color %g %g %g\n", 
00875               lightState[i].color[0], lightState[i].color[1], lightState[i].color[2]);
00876       lightcount++;
00877     }
00878   }
00879 
00880   for (i=0; i<DISP_LIGHTS; i++) {
00881     if (advLightState[i].on) {
00882       float pos[3];
00883 
00884       // always use world coordinates for now
00885       vec_copy(pos, advLightState[i].pos);
00886 
00887       if (advLightState[i].spoton) {
00888         fprintf(outfile, "# SpotLight not implemented yet ...\n");
00889       } else {
00890         /* invert handedness of light position vector */
00891         fprintf(outfile, "Light Center %g %g %g Rad 0.0 ", 
00892                 pos[0], pos[1], -pos[2]);
00893 
00894         /* emit light attentuation parameters if needed */
00895         if (advLightState[i].constfactor != 1.0f ||
00896             advLightState[i].linearfactor != 0.0f ||
00897             advLightState[i].quadfactor != 0.0f) {
00898           fprintf(outfile, "Attenuation Constant %g Linear %g Quadratic %g\n", 
00899                   advLightState[i].constfactor, 
00900                   advLightState[i].linearfactor,
00901                   advLightState[i].quadfactor);
00902         }
00903  
00904         fprintf(outfile, "Color %g %g %g\n", 
00905                 lightState[i].color[0], lightState[i].color[1], lightState[i].color[2]);
00906       }
00907 
00908       lightcount++;
00909     }
00910   }
00911 
00912   if (lightcount < 1) {
00913     msgInfo << "Warning: no lights defined in exported scene!!" << sendmsg;
00914   }
00915 }
00916 
00917 void TachyonDisplayDevice::write_materials(void) {
00918   // background color
00919   fprintf(outfile, "\nBackground %g %g %g\n", 
00920           backColor[0], backColor[1], backColor[2]);
00921 
00922   // Specify Tachyon background sky sphere if background gradient
00923   // mode is enabled.
00924   if (backgroundmode == 1) {
00925     float bspheremag = 0.5f;
00926 
00927     // compute positive/negative magnitude of sphere gradient
00928     switch (projection()) {
00929       case DisplayDevice::ORTHOGRAPHIC:
00930         // For orthographic views, Tachyon uses the dot product between
00931         // the incident ray origin and the sky sphere gradient "up" vector,
00932         // since all camera rays have the same direction and differ only
00933         // in their origin.
00934         bspheremag = vSize / 4.0f;
00935         break;
00936 
00937       case DisplayDevice::PERSPECTIVE:
00938       default:
00939         // For perspective views, Tachyon uses the dot product between
00940         // the incident ray and the sky sphere gradient "up" vector,
00941         // so for larger values of vSize, we have to clamp the maximum
00942         // magnitude to 1.0.
00943         bspheremag = (vSize / 2.0f) / (eyePos[2] - zDist);
00944         if (bspheremag > 1.0f)
00945           bspheremag = 1.0f;
00946         break;
00947     }
00948 
00949    
00950     fprintf(outfile, "Background_Gradient "); 
00951     if (projection() == DisplayDevice::ORTHOGRAPHIC)
00952       fprintf(outfile, "Sky_Ortho_Plane\n");
00953     else
00954       fprintf(outfile, "Sky_Sphere\n");
00955     fprintf(outfile, "  UpDir %g %g %g\n", 0.0f, 1.0f, 0.0f);
00956     fprintf(outfile, "  TopVal %g\n",     bspheremag);
00957     fprintf(outfile, "  BottomVal %g\n", -bspheremag);
00958     fprintf(outfile, "  TopColor %g %g %g\n", backgradienttopcolor[0], 
00959             backgradienttopcolor[1], backgradienttopcolor[2]);
00960     fprintf(outfile, "  BottomColor %g %g %g\n", backgradientbotcolor[0],
00961             backgradientbotcolor[1], backgradientbotcolor[2]);
00962   }
00963 
00964   // set depth cueing parameters
00965   if (cueingEnabled) {
00966     switch (cueMode) {
00967       case CUE_LINEAR:
00968         fprintf(outfile, 
00969           "Fog Linear Start %g End %g Density %g Color %g %g %g\n", 
00970           get_cue_start(), get_cue_end(), 1.0f, 
00971           backColor[0], backColor[1], backColor[2]);
00972         break;
00973  
00974       case CUE_EXP:
00975         fprintf(outfile,
00976           "Fog Exp Start %g End %g Density %g Color %g %g %g\n", 
00977           0.0, get_cue_end(), get_cue_density(), 
00978           backColor[0], backColor[1], backColor[2]);
00979         break;
00980  
00981       case CUE_EXP2:
00982         fprintf(outfile, 
00983           "Fog Exp2 Start %g End %g Density %g Color %g %g %g\n", 
00984           0.0, get_cue_end(), get_cue_density(), 
00985           backColor[0], backColor[1], backColor[2]);
00986         break;
00987 
00988       case NUM_CUE_MODES:
00989         // this should never happen
00990         break;
00991     }
00992   } 
00993 }
00994 
00995 void TachyonDisplayDevice::write_cindexmaterial(int cindex, int material) {
00996   write_colormaterial((float *) &matData[cindex], material);
00997 }
00998 
00999 // XXX ignores material parameter, may need to improve this..
01000 void TachyonDisplayDevice::write_colormaterial(float *rgb, int /* material */) {
01001   fprintf(outfile, "Texture\n");
01002   if (materials_on) {
01003     fprintf(outfile, "  Ambient %g Diffuse %g Specular %g Opacity %g\n",
01004             mat_ambient, mat_diffuse, mat_mirror, mat_opacity);
01005   } else {
01006     fprintf(outfile, "  Ambient %g Diffuse %g Specular %g Opacity %g\n",
01007             1.0, 0.0, 0.0, mat_opacity);
01008   }
01009   
01010   if (mat_transmode != 0) {
01011     fprintf(outfile, "  TransMode R3D ");
01012   }
01013   if (mat_outline > 0.0) {
01014     fprintf(outfile, "  Outline %g Outline_Width %g ", 
01015             mat_outline, mat_outlinewidth);
01016   }
01017   fprintf(outfile, "  Phong Plastic %g Phong_size %g ", mat_specular, 
01018           mat_shininess);
01019   fprintf(outfile, "Color %g %g %g ", rgb[0], rgb[1], rgb[2]);
01020 
01022   if (!involtex) {
01024     fprintf(outfile, "TexFunc 0\n\n");
01025   } else {
01027     float voluaxs[3];           
01028     float volvaxs[3];           
01029     float volwaxs[3];
01030     float volcent[3];
01031 
01032     // transform the u/v/w texture coordinate axes from molecule
01033     // coordinates into world coordinates
01034     (transMat.top()).multplaneeq3d(xplaneeq, voluaxs);
01035     (transMat.top()).multplaneeq3d(yplaneeq, volvaxs);
01036     (transMat.top()).multplaneeq3d(zplaneeq, volwaxs);
01037 
01038     // undo the scaling operation applied by the transformation
01039     float invscale = 1.0f / scale_radius(1.0f); 
01040     int i;
01041     for (i=0; i<3; i++) {
01042       voluaxs[i] *= invscale;
01043       volvaxs[i] *= invscale;
01044       volwaxs[i] *= invscale;
01045     }
01046 
01047     // compute the volume origin in molecule coordinates by 
01048     // reverting the scaling factor that was previously applied
01049     // to the texture plane equation
01050     float volorgmol[3] = {0,0,0};
01051     volorgmol[0] = -xplaneeq[3] / norm(xplaneeq);
01052     volorgmol[1] = -yplaneeq[3] / norm(yplaneeq);
01053     volorgmol[2] = -zplaneeq[3] / norm(zplaneeq);
01054 
01055     // transform the volume origin into world coordinates
01056     (transMat.top()).multpoint3d(volorgmol, volcent);
01057 
01058     // emit the texture to the scene file
01059     fprintf(outfile, "\n  TexFunc  10  ::VMDVolTex%d\n", voltexID);
01060     fprintf(outfile, "  Center %g %g %g\n", volcent[0], volcent[1], -volcent[2]);
01061     fprintf(outfile, "  Rotate 0 0 0\n");
01062     fprintf(outfile, "  Scale  1 1 1\n");
01063     fprintf(outfile, "  Uaxis %g %g %g\n", voluaxs[0], voluaxs[1], -voluaxs[2]);
01064     fprintf(outfile, "  Vaxis %g %g %g\n", volvaxs[0], volvaxs[1], -volvaxs[2]);
01065     fprintf(outfile, "  Waxis %g %g %g\n", volwaxs[0], volwaxs[1], -volwaxs[2]);
01066     fprintf(outfile, "\n");
01067   }
01068 }
01069 
01070 
01071 
01072 

Generated on Thu Apr 18 02:45:38 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002