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

LibTachyonDisplayDevice.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: LibTachyonDisplayDevice.C,v $
00013 *      $Author: johns $        $Locker:  $               $State: Exp $
00014 *      $Revision: 1.99 $        $Date: 2021/03/06 20:51:52 $
00015 *
00016 ***************************************************************************/
00022 #include <string.h>
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include <math.h>
00026 #include "LibTachyonDisplayDevice.h"
00027 #include "Matrix4.h"
00028 #include "DispCmds.h"
00029 #include "Inform.h"
00030 #include "utilities.h"
00031 #include "config.h"    // needed for default image viewer
00032 #include "Hershey.h"   // needed for Hershey font rendering fctns
00033 
00034 #if !(((TACHYON_MAJOR_VERSION >= 0) && (TACHYON_MINOR_VERSION >= 99)) || ((TACHYON_MAJOR_VERSION == 0) && (TACHYON_MINOR_VERSION == 99) && (TACHYON_PATCH_VERSION >= 0)))
00035 #error "LibTachyonDisplayDevice requires Tachyon version 0.99.0 or higher."
00036 #endif
00037 
00038 #define DEFAULT_RADIUS 0.002f
00039 #define DASH_LENGTH 0.02f
00040 
00041 extern "C" {
00042 
00043 void vmd_rt_ui_message(int a, char * msg) {
00044   printf("Tachyon) %s\n", msg);
00045 }
00046 
00047 void vmd_rt_ui_progress(int percent) {
00048   printf("\rTachyon) Rendering progress: %3d%% complete          \r", percent);
00049   fflush(stdout);
00050 }
00051 
00052 }
00053 
00055 LibTachyonDisplayDevice::LibTachyonDisplayDevice(VMDApp *app) : FileRenderer ("TachyonInternal", "Tachyon (internal, in-memory rendering)", "vmdscene.tga", DEF_VMDIMAGEVIEWER) { 
00056   vmdapp = app; // save VMDApp handle for GPU memory management routines
00057 
00058   reset_vars();  // initialize internal state
00059   trt_timer = wkf_timer_create();
00060 
00061 #if 0 && defined(VMDMPI)
00062   // init scene-independent parts of Tachyon library
00063   parallel_group = 0;
00064   if (getenv("VMDNOMPI") != NULL || getenv("VMDTACHYONNOMPI") != NULL) {
00065     rt_initialize_nompi();
00066   } else {
00067     // set Tachyon to use MPI_COMM_WORLD initially.
00068     rt_initialize_mpi_comm_world();
00069 
00070 #if 1
00071     // Unless overridden, every VMD node runs Tachyon independently of one another,
00072     // with each node in its own communicator...
00073     if (getenv("VMDTACHYONWORKGROUP") == NULL) {
00074       parallel_group = -1;
00075       rt_set_mpi_comm_world_split_all();
00076     } else {
00077       parallel_group = atoi(getenv("VMDTACHYONWORKGROUP"));
00078       rt_set_mpi_comm_world_split(parallel_group, 0);
00079     }
00080 #endif
00081   }
00082 #else
00083   rt_initialize(0, NULL); // init scene-independent parts of Tachyon library
00084 #endif
00085 
00086 #if defined(VMDMPI)
00087   // When VMD is running with MPI enabled, we disable console output
00088   // for Tachyon rendering status and progress messages.  If VMD
00089   // was compiled with MPI support, we only turn on console output
00090   // when we detect that MPI has been disabled.
00091   if (getenv("VMDNOMPI") != NULL) {
00092     // rt_set_ui_message(vmd_rt_ui_message);
00093     rt_set_ui_progress(vmd_rt_ui_progress);
00094   }
00095 #else
00096   // rt_set_ui_message(vmd_rt_ui_message);
00097   rt_set_ui_progress(vmd_rt_ui_progress);
00098 #endif
00099 
00100   // Add supported file formats
00101   formats.add_name("Auto", 0);
00102   formats.add_name("BMP", 0);
00103   formats.add_name("PPM", 0);
00104   formats.add_name("PPM48", 0);
00105   formats.add_name("PSD48", 0);
00106   formats.add_name("RGB", 0);
00107   formats.add_name("TGA", 0);
00108 
00109   // Default image format depends on platform
00110   curformat = 0;
00111 
00112   // Set default aa level
00113   has_aa = TRUE;
00114   aasamples = 12;
00115   aosamples = 12;
00116 }
00117         
00118 LibTachyonDisplayDevice::~LibTachyonDisplayDevice(void) { 
00119   rt_finalize(); // shut down Tachyon library
00120   wkf_timer_destroy(trt_timer);
00121 }
00122 
00123 
00125 
00126 // reset internal state between renders
00127 void LibTachyonDisplayDevice::reset_vars(void) {
00128   inclipgroup = 0; // not currently in a clipping group
00129   involtex = 0;    // volume texturing disabled
00130   voltexID = -1;   // invalid texture ID
00131   memset(xplaneeq, 0, sizeof(xplaneeq));
00132   memset(yplaneeq, 0, sizeof(xplaneeq));
00133   memset(zplaneeq, 0, sizeof(xplaneeq));
00134 }
00135 
00136 
00138 
00139 void LibTachyonDisplayDevice::text(float *pos, float size, float thickness, 
00140                                    const char *str) {
00141   float textpos[3];
00142   float textsize, textthickness;
00143   hersheyhandle hh;
00144 
00145   // transform the world coordinates
00146   (transMat.top()).multpoint3d(pos, textpos);
00147   textsize = size * 1.5f;
00148   textthickness = thickness*DEFAULT_RADIUS;
00149 
00150   // create texture to use for text rendering
00151   void *tex=tex_cindexmaterial(colorIndex, materialIndex);
00152 
00153   while (*str != '\0') {
00154     float lm, rm, x, y, ox, oy;
00155     int draw, odraw;
00156     ox=oy=x=y=0.0f;
00157     draw=odraw=0;
00158 
00159     hersheyDrawInitLetter(&hh, *str, &lm, &rm);
00160     textpos[0] -= lm * textsize;
00161 
00162     while (!hersheyDrawNextLine(&hh, &draw, &x, &y)) {
00163       float oldpt[3], newpt[3];
00164       if (draw) {
00165         newpt[0] = textpos[0] + textsize * x;
00166         newpt[1] = textpos[1] + textsize * y;
00167         newpt[2] = textpos[2];
00168 
00169         if (odraw) {
00170           // if we have both previous and next points, connect them...
00171           oldpt[0] = textpos[0] + textsize * ox;
00172           oldpt[1] = textpos[1] + textsize * oy;
00173           oldpt[2] = textpos[2];
00174 
00175           rt_fcylinder(rtscene, tex, rt_vector(oldpt[0], oldpt[1], -oldpt[2]),
00176                        rt_vector(newpt[0]-oldpt[0], newpt[1]-oldpt[1], -newpt[2]+oldpt[2]),
00177                        textthickness);
00178           rt_sphere(rtscene, tex, 
00179                     rt_vector(newpt[0], newpt[1], -newpt[2]), textthickness);
00180         } else {
00181           // ...otherwise, just draw the next point
00182           rt_sphere(rtscene, tex, 
00183                     rt_vector(newpt[0], newpt[1], -newpt[2]), textthickness);
00184         }
00185       }
00186 
00187       ox=x;
00188       oy=y;
00189       odraw=draw;
00190     }
00191     textpos[0] += rm * textsize;
00192 
00193     str++;
00194   }
00195 }
00196 
00197 
00198 // draw a point
00199 void LibTachyonDisplayDevice::point(float * spdata) {
00200   float vec[3];
00201   void *tex;
00202   // transform the world coordinates
00203   (transMat.top()).multpoint3d(spdata, vec);
00204 
00205   // draw the sphere
00206   tex=tex_cindexmaterial(colorIndex, materialIndex);
00207   rt_sphere(rtscene, tex, 
00208             rt_vector(vec[0], vec[1], -vec[2]),
00209             float(lineWidth)*DEFAULT_RADIUS);
00210 }
00211 
00212 
00213 // draw a sphere
00214 void LibTachyonDisplayDevice::sphere(float * spdata) {
00215   float vec[3];
00216   float radius;
00217   void *tex;
00218     
00219   // transform the world coordinates
00220   (transMat.top()).multpoint3d(spdata, vec);
00221   radius = scale_radius(spdata[3]);
00222    
00223   // draw the sphere
00224   tex=tex_cindexmaterial(colorIndex, materialIndex);
00225   rt_sphere(rtscene, tex, rt_vector(vec[0], vec[1], -vec[2]), radius);
00226 }
00227 
00228 
00229 // draw a sphere array
00230 void LibTachyonDisplayDevice::sphere_array(int spnum, int spres, float *centers, float *radii, float *colors) {
00231   float vec[3];
00232   float radius;
00233   int i, ind;
00234   void *tex;
00235 
00236   ind = 0;
00237   for (i=0; i<spnum; i++) {
00238     // transform the world coordinates
00239     (transMat.top()).multpoint3d(&centers[ind], vec);
00240     radius = scale_radius(radii[i]);
00241 
00242     // draw the sphere
00243     tex=tex_colormaterial(&colors[ind], materialIndex);
00244     rt_sphere(rtscene, tex, rt_vector(vec[0], vec[1], -vec[2]), radius);
00245     ind += 3; // next sphere
00246   }
00247 
00248   // set final color state after array has been drawn
00249   ind=(spnum-1)*3;
00250   super_set_color(nearest_index(colors[ind], colors[ind+1], colors[ind+2]));
00251 }
00252 
00253 
00254 // draw a line (cylinder) from a to b
00255 void LibTachyonDisplayDevice::line(float *a, float*b) {
00256   int i, j, test;
00257   float dirvec[3], unitdirvec[3];
00258   float from[3], to[3], tmp1[3], tmp2[3];
00259   void *tex;
00260   
00261   if (lineStyle == ::SOLIDLINE) {
00262     // transform the world coordinates
00263     (transMat.top()).multpoint3d(a, from);
00264     (transMat.top()).multpoint3d(b, to);
00265     
00266     // draw the cylinder
00267     tex=tex_cindexmaterial(colorIndex, materialIndex);
00268     rt_fcylinder(rtscene, tex, 
00269                  rt_vector(from[0], from[1], -from[2]),
00270                  rt_vector(to[0]-from[0], to[1]-from[1], -to[2]+from[2]),
00271                  float(lineWidth)*DEFAULT_RADIUS);
00272 
00273   } else if (lineStyle == ::DASHEDLINE) {
00274      // transform the world coordinates
00275     (transMat.top()).multpoint3d(a, tmp1);
00276     (transMat.top()).multpoint3d(b, tmp2);
00277 
00278     // how to create a dashed line
00279     vec_sub(dirvec, tmp2, tmp1);  // vector from a to b
00280     vec_copy(unitdirvec, dirvec);
00281     vec_normalize(unitdirvec);    // unit vector from a to b
00282     test = 1;
00283     i = 0;
00284     while (test == 1) {
00285       for (j=0; j<3; j++) {
00286         from[j] = (float) (tmp1[j] + (2*i    )*DASH_LENGTH*unitdirvec[j]);
00287           to[j] = (float) (tmp1[j] + (2*i + 1)*DASH_LENGTH*unitdirvec[j]);
00288       }
00289       if (fabsf(tmp1[0] - to[0]) >= fabsf(dirvec[0])) {
00290         vec_copy(to, tmp2);
00291         test = 0;
00292       }
00293     
00294       // draw the cylinder
00295       tex=tex_cindexmaterial(colorIndex, materialIndex);
00296       rt_fcylinder(rtscene, tex, 
00297                    rt_vector(from[0], from[1], -from[2]),
00298                    rt_vector(to[0]-from[0], to[1]-from[1], -to[2]+from[2]),
00299                    float(lineWidth)*DEFAULT_RADIUS);
00300       i++;
00301     }
00302   } else {
00303     msgErr << "LibTachyonDisplayDevice: Unknown line style " 
00304            << lineStyle << sendmsg;
00305   }
00306 }
00307 
00308 
00309 // draw a cylinder
00310 void LibTachyonDisplayDevice::cylinder(float *a, float *b, float r, int filled) {
00311   float from[3], to[3], norm[3];
00312   float radius;
00313   void * tex;
00314 
00315   // transform the world coordinates
00316   (transMat.top()).multpoint3d(a, from);
00317   (transMat.top()).multpoint3d(b, to);
00318   radius = scale_radius(r);
00319    
00320   // draw the cylinder
00321   tex=tex_cindexmaterial(colorIndex, materialIndex);
00322   rt_fcylinder(rtscene, tex, 
00323                rt_vector(from[0], from[1], -from[2]),
00324                rt_vector(to[0]-from[0], to[1]-from[1], -to[2]+from[2]),
00325                radius);
00326 
00327   // Cylinder caps?
00328   if (filled) {
00329     float div;
00330 
00331     norm[0] = to[0] - from[0];
00332     norm[1] = to[1] - from[1];
00333     norm[2] = to[2] - from[2];
00334 
00335     div = 1.0f / sqrtf(norm[0]*norm[0] + norm[1]*norm[1] + norm[2]*norm[2]);
00336     norm[0] *= div;
00337     norm[1] *= div;
00338     norm[2] *= div;
00339 
00340     if (filled & CYLINDER_TRAILINGCAP) {
00341       rt_ring(rtscene, tex,
00342               rt_vector(from[0], from[1], -from[2]),
00343               rt_vector(norm[0], norm[1], -norm[2]),
00344               0.0, radius);
00345     }
00346   
00347     if (filled & CYLINDER_LEADINGCAP) {
00348       rt_ring(rtscene, tex,
00349               rt_vector(to[0], to[1], -to[2]),
00350               rt_vector(-norm[0], -norm[1],  norm[2]),
00351               0.0, radius);
00352     }
00353   }
00354 }
00355 
00356 // draw a triangle
00357 void LibTachyonDisplayDevice::triangle(const float *a, const float *b, const float *c, const float *n1, const float *n2, const float *n3) {
00358   float vec1[3], vec2[3], vec3[3];
00359   float norm1[3], norm2[3], norm3[3];
00360   void *tex;
00361   
00362   // transform the world coordinates
00363   (transMat.top()).multpoint3d(a, vec1);
00364   (transMat.top()).multpoint3d(b, vec2);
00365   (transMat.top()).multpoint3d(c, vec3);
00366 
00367   // and the normals
00368   (transMat.top()).multnorm3d(n1, norm1);
00369   (transMat.top()).multnorm3d(n2, norm2);
00370   (transMat.top()).multnorm3d(n3, norm3);
00371 
00372   // draw the triangle
00373   tex=tex_cindexmaterial(colorIndex, materialIndex);
00374   rt_stri(rtscene, tex, 
00375           rt_vector(vec1[0], vec1[1], -vec1[2]),
00376           rt_vector(vec2[0], vec2[1], -vec2[2]),
00377           rt_vector(vec3[0], vec3[1], -vec3[2]),
00378           rt_vector(-norm1[0], -norm1[1], norm1[2]),
00379           rt_vector(-norm2[0], -norm2[1], norm2[2]),
00380           rt_vector(-norm3[0], -norm3[1], norm3[2]));
00381 }
00382 
00383 
00384 // draw triangle with per-vertex colors
00385 void LibTachyonDisplayDevice::tricolor(const float * xyz1, const float * xyz2, const float * xyz3,
00386                                        const float * n1,   const float * n2,   const float * n3,
00387                                        const float *c1, const float *c2, const float *c3) {
00388   float vec1[3], vec2[3], vec3[3];
00389   float norm1[3], norm2[3], norm3[3];
00390   float rgb[3];
00391   void *tex;
00392 
00393   // transform the world coordinates
00394   (transMat.top()).multpoint3d(xyz1, vec1);
00395   (transMat.top()).multpoint3d(xyz2, vec2);
00396   (transMat.top()).multpoint3d(xyz3, vec3);
00397 
00398   // and the normals
00399   (transMat.top()).multnorm3d(n1, norm1);
00400   (transMat.top()).multnorm3d(n2, norm2);
00401   (transMat.top()).multnorm3d(n3, norm3);
00402 
00403   rgb[0] = 0.0;
00404   rgb[1] = 0.0;
00405   rgb[2] = 0.0;
00406 
00407   // draw the triangle
00408   tex=tex_colormaterial(rgb, materialIndex);
00409 
00410   if (!involtex) {
00411     rt_vcstri(rtscene, tex,
00412               rt_vector(vec1[0], vec1[1], -vec1[2]),
00413               rt_vector(vec2[0], vec2[1], -vec2[2]),
00414               rt_vector(vec3[0], vec3[1], -vec3[2]),
00415               rt_vector(-norm1[0], -norm1[1], norm1[2]),
00416               rt_vector(-norm2[0], -norm2[1], norm2[2]),
00417               rt_vector(-norm3[0], -norm3[1], norm3[2]),
00418               rt_color(c1[0], c1[1], c1[2]),
00419               rt_color(c2[0], c2[1], c2[2]),
00420               rt_color(c3[0], c3[1], c3[2]));
00421   } else {
00422     rt_stri(rtscene, tex,
00423             rt_vector(vec1[0], vec1[1], -vec1[2]),
00424             rt_vector(vec2[0], vec2[1], -vec2[2]),
00425             rt_vector(vec3[0], vec3[1], -vec3[2]),
00426             rt_vector(-norm1[0], -norm1[1], norm1[2]),
00427             rt_vector(-norm2[0], -norm2[1], norm2[2]),
00428             rt_vector(-norm3[0], -norm3[1], norm3[2]));
00429   }
00430 }
00431 
00432 
00433 // draw triangle strips with per-vertex colors
00434 void LibTachyonDisplayDevice::tristrip(int numverts, const float *cnv, 
00435                               int numstrips, const int *vertsperstrip, 
00436                               const int *facets) {
00437   int i;
00438   float rgb[3];
00439   void *tex;
00440 
00441   Matrix4 topMatrix = transMat.top();
00442 
00443   /* transform all vertices and normals, copy colors as-is */
00444   float *tcnv = new float[numverts * 10];
00445 
00446   for (i=0; i<numverts; i++) {
00447     int addr = i * 10;
00448     int j;
00449 
00450     for (j=0; j<3; j++)
00451       tcnv[addr + j] = cnv[addr + j];
00452 
00453     topMatrix.multnorm3d(&cnv[addr + 4], &tcnv[addr + 4]);
00454     tcnv[addr + 4] = -tcnv[addr + 4];
00455     tcnv[addr + 5] = -tcnv[addr + 5];
00456     topMatrix.multpoint3d(&cnv[addr + 7], &tcnv[addr + 7]);
00457     tcnv[addr + 9] = -tcnv[addr + 9];
00458   }
00459 
00460   rgb[0] = 0.0;
00461   rgb[1] = 0.0;
00462   rgb[2] = 0.0;
00463 
00464   // draw the triangle strips
00465   tex=tex_colormaterial(rgb, materialIndex);
00466   rt_tristripscnv3fv(rtscene, tex, numverts, tcnv, 
00467                      numstrips, vertsperstrip, facets);
00468 
00469   delete [] tcnv;
00470 }
00471 
00472 
00473 
00475 
00476 int LibTachyonDisplayDevice::open_file(const char *filename) {
00477   my_filename = stringdup(filename);
00478   isOpened = TRUE;
00479   reset_state();
00480   return TRUE;
00481 }
00482 
00483 void LibTachyonDisplayDevice::close_file(void) {
00484   outfile = NULL;
00485   delete [] my_filename;
00486   my_filename = NULL;
00487   isOpened = FALSE;
00488 }
00489 
00490 static int checkfileextension(const char * s, const char * extension) {
00491   int sz, extsz;
00492   sz = strlen(s);
00493   extsz = strlen(extension);
00494 
00495   if (extsz > sz)
00496     return 0;
00497 
00498   if (!strupncmp(s + (sz - extsz), extension, extsz)) {
00499     return 1;
00500   }
00501 
00502   return 0;
00503 }
00504 
00505 // initialize the file for output
00506 void LibTachyonDisplayDevice::write_header() {
00507   wkf_timer_start(trt_timer);
00508 
00509   // NOTE: the vmd variable "Aspect" has absolutely *nothing* to do
00510   //       with aspect ratio correction, it is only the ratio of the
00511   //       width of the graphics window to its height, and so it should
00512   //       be used only to cause the ray tracer to generate a similarly
00513   //       proportioned image.
00514 
00515   buildtime = rt_timer_create();
00516   rendertime = rt_timer_create();
00517 
00518   rt_timer_start(buildtime);
00519 
00520 #if 0 && defined(VMDMPI)
00521   if (getenv("VMDNOMPI") == NULL || getenv("VMDTACHYONNOMPI") == NULL) {
00522     // Unless overridden, every VMD node runs Tachyon independently of one another,
00523     // with each node in its own communicator...
00524     if (getenv("VMDTACHYONWORKGROUP") == NULL) {
00525       parallel_group = -1;
00526       rt_set_mpi_comm_world_split_all();
00527     } else {
00528       parallel_group = atoi(getenv("VMDTACHYONWORKGROUP"));
00529       rt_set_mpi_comm_world_split(parallel_group, 0);
00530     }
00531   }
00532 #endif
00533 
00534   rtscene = rt_newscene();
00535   rt_outputfile(rtscene, my_filename);      // get filename from base class
00536 
00537   switch (curformat) {
00538     case 0: // autodetermine...
00539       // set appropriate image file format
00540       if (checkfileextension(my_filename, ".bmp")) {
00541         rt_outputformat(rtscene, RT_FORMAT_WINBMP);
00542       } else if (checkfileextension(my_filename, ".ppm")) {
00543         rt_outputformat(rtscene, RT_FORMAT_PPM);
00544       } else if (checkfileextension(my_filename, ".psd")) {
00545         rt_outputformat(rtscene, RT_FORMAT_PSD48);
00546       } else if (checkfileextension(my_filename, ".rgb")) {
00547         rt_outputformat(rtscene, RT_FORMAT_SGIRGB);
00548       } else if (checkfileextension(my_filename, ".tga")) {
00549         rt_outputformat(rtscene, RT_FORMAT_TARGA);
00550       } else {
00551 #if defined(_MSC_VER) || defined(WIN32)
00552         msgErr << "Unrecognized image file extension, writing Windows Bitmap file."
00553                << sendmsg;
00554         rt_outputformat(rtscene, RT_FORMAT_WINBMP);
00555 #else
00556         msgErr << "Unrecognized image file extension, writing Targa file."
00557                << sendmsg;
00558         rt_outputformat(rtscene, RT_FORMAT_TARGA);
00559 #endif
00560       }
00561       break;
00562 
00563     case 1:
00564       rt_outputformat(rtscene, RT_FORMAT_WINBMP);
00565       break;
00566 
00567     case 2:    
00568       rt_outputformat(rtscene, RT_FORMAT_PPM);
00569       break;
00570 
00571     case 3:
00572       rt_outputformat(rtscene, RT_FORMAT_PPM48);
00573 
00574     case 4:
00575       rt_outputformat(rtscene, RT_FORMAT_PSD48);
00576 
00577     case 5:
00578       rt_outputformat(rtscene, RT_FORMAT_SGIRGB);
00579 
00580     case 6:
00581     default:
00582       rt_outputformat(rtscene, RT_FORMAT_TARGA);
00583   }
00584 
00585 
00586   rt_resolution(rtscene,  (int) xSize, (int) ySize);
00587 
00588   // use opacity post-multiply transparency mode for output that closely 
00589   // matches what user's see in the OpenGL window in VMD.
00590   rt_trans_mode(rtscene, RT_TRANS_VMD);     
00591 
00592   // use planar fog mode (rather than the more physically correct radial fog)
00593   // for output that closely matches what user's see in the VMD OpenGL window.
00594   rt_fog_rendering_mode(rtscene, RT_FOG_VMD);
00595 
00596   write_camera();    // has to be first thing in the file. 
00597   write_lights();    // could be anywhere.
00598   write_materials(); // has to be before objects that use them.
00599 
00600   // render with/without shadows
00601   if (shadows_enabled() || ao_enabled()) {
00602     if (shadows_enabled() && !ao_enabled())
00603       msgInfo << "Shadow rendering enabled." << sendmsg;
00604  
00605     rt_shadermode(rtscene, RT_SHADER_FULL);   // full shading mode required
00606   } else {
00607     rt_shadermode(rtscene, RT_SHADER_MEDIUM); // disable shadows by default
00608   }
00609 
00610   // render with ambient occlusion, but only if shadows are also enabled
00611   if (ao_enabled()) {
00612     apicolor skycol;
00613     skycol.r = get_ao_ambient();
00614     skycol.g = get_ao_ambient();
00615     skycol.b = get_ao_ambient();
00616 
00617     msgInfo << "Ambient occlusion rendering enabled." << sendmsg;
00618     rt_rescale_lights(rtscene, get_ao_direct());
00619 
00620 #if ((TACHYON_MAJOR_VERSION == 0) && (TACHYON_MINOR_VERSION == 99) && (TACHYON_PATCH_VERSION <= 1))
00621     rt_ambient_occlusion(rtscene, aosamples, skycol);
00622 #else
00623     float ao_maxdist = RT_AO_MAXDIST_UNLIMITED;
00624  
00625     if (getenv("VMDTACHYONAOMAXDIST")) {
00626       float tmp = atof(getenv("VMDTACHYONAOMAXDIST"));
00627       printf("LibTachyonDisplayDevice) setting AO maxdist: %f\n", tmp);
00628       ao_maxdist = tmp;
00629     }
00630 
00631     rt_ambient_occlusion(rtscene, aosamples, ao_maxdist, skycol);
00632 #endif
00633   } 
00634 
00635   // render with depth of field, but only for perspective projection
00636   if (dof_enabled() && (projection() == DisplayDevice::PERSPECTIVE)) {
00637     msgInfo << "DoF focal blur enabled." << sendmsg;
00638     rt_camera_projection(rtscene, RT_PROJECTION_PERSPECTIVE_DOF);
00639     rt_camera_dof(rtscene, get_dof_focal_dist(), get_dof_fnumber());
00640   }
00641 }
00642 
00643 
00644 void LibTachyonDisplayDevice::write_trailer(void){
00645   rt_timer_stop(buildtime);
00646   rt_timer_start(rendertime);
00647   rt_renderscene(rtscene);
00648   rt_timer_stop(rendertime);
00649   rt_deletescene(rtscene);
00650    
00651   msgInfo << "Tachyon: preprocessing time " 
00652           << rt_timer_time(buildtime)  << " sec, render time "
00653           << rt_timer_time(rendertime) << " sec." << sendmsg;
00654   rt_timer_destroy(buildtime);
00655   rt_timer_destroy(rendertime);
00656 
00657   if (inclipgroup) {
00658     msgErr << "LibTachyonDisplayDevice clip group still active at end of scene" << sendmsg;
00659   }
00660 
00661   wkf_timer_stop(trt_timer);
00662   printf("Total Tachyon rendering time: %.1f sec\n", wkf_timer_time(trt_timer));
00663 
00664   reset_vars(); // reset internal state between renders
00665 }
00666 
00667 
00668 // define a volumetric texture map
00669 void LibTachyonDisplayDevice::define_volume_texture(int ID,
00670                                                  int xs, int ys, int zs,
00671                                                  const float *xpq,
00672                                                  const float *ypq,
00673                                                  const float *zpq,
00674                                                  unsigned char *texmap) {
00675   char texname[1024];
00676   unsigned char *rgb=NULL;
00677 
00678   voltexID = ID; // remember current texture ID
00679 
00680   // remember texture plane equations
00681   memcpy(xplaneeq, xpq, sizeof(xplaneeq));
00682   memcpy(yplaneeq, ypq, sizeof(yplaneeq));
00683   memcpy(zplaneeq, zpq, sizeof(zplaneeq));
00684   
00685   sprintf(texname, "::VMDVolTex%d", voltexID);
00686 
00687   // copy incoming texture map to a new buffer
00688   // XXX ideally we'd have Tachyon use the existing image
00689   //     buffer rather than copy it
00690   long txsz = long(xs) * long(ys) * long(zs) * 3L;
00691   rgb = (unsigned char *) malloc(txsz);
00692   memcpy(rgb, texmap, txsz);
00693 
00694   // define the texture map image within Tachyon
00695   rt_define_teximage_rgb24(texname, xs, ys, zs, rgb);
00696 }
00697 
00698 
00699 // enable volumetric texturing, either in "replace" or "modulate" mode
00700 void LibTachyonDisplayDevice::volume_texture_on(int texmode) {
00701   involtex = 1;
00702 }
00703 
00704 
00705 // disable volumetric texturing
00706 void LibTachyonDisplayDevice::volume_texture_off(void) {
00707   involtex = 0;
00708 }
00709 
00710 
00711 void LibTachyonDisplayDevice::start_clipgroup(void) {
00712   int i;
00713   int planesenabled = 0;
00714 
00715   for (i=0; i<VMD_MAX_CLIP_PLANE; i++) {
00716     if (clip_mode[i] > 0) {
00717       planesenabled++;  /* count number of active clipping planes */
00718       if (clip_mode[i] > 1)
00719         warningflags |= FILERENDERER_NOCLIP; /* emit warnings */
00720     }
00721   }
00722 
00723   if (planesenabled > 0) {
00724     float *planes = (float *) malloc(planesenabled * 4 * sizeof(float));
00725 
00726     int j=0;
00727     for (i=0; i<VMD_MAX_CLIP_PLANE; i++) {
00728       if (clip_mode[i] > 0) {
00729         float tachyon_clip_center[3];
00730         float tachyon_clip_normal[3];
00731         float tachyon_clip_distance;
00732 
00733         inclipgroup = 1; // we're in a clipping group presently
00734 
00735         // Transform the plane center and the normal
00736         (transMat.top()).multpoint3d(clip_center[i], tachyon_clip_center);
00737         (transMat.top()).multnorm3d(clip_normal[i], tachyon_clip_normal);
00738         vec_negate(tachyon_clip_normal, tachyon_clip_normal);
00739 
00740         // Tachyon uses the distance from the origin to the plane for its
00741         // representation, instead of the plane center
00742         tachyon_clip_distance = dot_prod(tachyon_clip_normal, tachyon_clip_center);
00743 
00744         planes[j * 4    ] =  tachyon_clip_normal[0];
00745         planes[j * 4 + 1] =  tachyon_clip_normal[1];
00746         planes[j * 4 + 2] = -tachyon_clip_normal[2];
00747         planes[j * 4 + 3] =  tachyon_clip_distance;
00748 
00749         rt_clip_fv(rtscene, planesenabled, planes); // add the clipping planes
00750         j++;
00751       }
00752     }
00753 
00754     free(planes);
00755   } else {
00756     inclipgroup = 0; // Not currently in a clipping group
00757   }
00758 }
00759 
00760 
00761 void LibTachyonDisplayDevice::end_clipgroup(void) {
00762   if (inclipgroup) {
00763     rt_clip_off(rtscene); // disable clipping planes
00764     inclipgroup = 0;      // we're not in a clipping group anymore 
00765   }
00766 }
00767 
00768 
00770 
00771 void LibTachyonDisplayDevice::write_camera(void) {
00772   int raydepth = 50;
00773 
00774   // Camera position
00775   // Tachyon uses a left-handed coordinate system
00776   // VMD uses right-handed, so z(Tachyon) = -z(VMD).
00777   switch (projection()) {
00778     case DisplayDevice::ORTHOGRAPHIC:
00779       rt_camera_projection(rtscene, RT_PROJECTION_ORTHOGRAPHIC);
00780       rt_camera_setup(rtscene,
00781                      1.0 / (vSize / 2.0),           // zoom
00782                      1.0f,                          // aspect ratio
00783                      aasamples,                     // antialiasing
00784                      raydepth,                      // ray depth
00785                      rt_vector(eyePos[0], eyePos[1], -eyePos[2]), // camcent
00786                      rt_vector(eyeDir[0], eyeDir[1], -eyeDir[2]), // camview
00787                      rt_vector(upDir[0],   upDir[1],  -upDir[2]));   // camup
00788       break;
00789 
00790     case DisplayDevice::PERSPECTIVE:
00791     default:
00792       rt_camera_projection(rtscene, RT_PROJECTION_PERSPECTIVE);
00793       rt_camera_setup(rtscene,
00794                      ((eyePos[2] - zDist) / vSize), // zoom
00795                      1.0f,                          // aspect ratio
00796                      aasamples,                     // antialiasing
00797                      raydepth,                      // ray depth
00798                      rt_vector(eyePos[0], eyePos[1], -eyePos[2]), // camcent
00799                      rt_vector(eyeDir[0], eyeDir[1], -eyeDir[2]), // camview
00800                      rt_vector(upDir[0],   upDir[1], -upDir[2])); // camup
00801       break;
00802   }
00803 }
00804 
00805   
00806 void LibTachyonDisplayDevice::write_lights(void) {  
00807   int i;  
00808   int lightcount = 0;
00809 
00810   /* directional lights */
00811   for (i=0; i<DISP_LIGHTS; i++) {
00812     if (lightState[i].on) {
00813       apitexture tex;
00814       memset(&tex, 0, sizeof(apitexture));
00815 
00816       tex.col.r=lightState[i].color[0];
00817       tex.col.g=lightState[i].color[1];
00818       tex.col.b=lightState[i].color[2];
00819      
00820       rt_directional_light(rtscene, 
00821                rt_texture(rtscene, &tex), 
00822                /* give negated light position for direction vector... */ 
00823                rt_vector(-lightState[i].pos[0], 
00824                          -lightState[i].pos[1], 
00825                           lightState[i].pos[2]));
00826  
00827       lightcount++;
00828     }
00829   }
00830 
00831   /* advanced positional lights */
00832   for (i=0; i<DISP_LIGHTS; i++) {
00833     if (advLightState[i].on) {
00834       float pos[3];
00835 
00836       // always use world coordinates for now
00837       vec_copy(pos, advLightState[i].pos);
00838 
00839       if (advLightState[i].spoton) {
00840         printf("TachyonInternal) SpotLight not implemented yet ...\n");
00841       } else {
00842         apitexture tex;
00843         memset(&tex, 0, sizeof(apitexture));
00844 
00845         tex.col.r=advLightState[i].color[0];
00846         tex.col.g=advLightState[i].color[1];
00847         tex.col.b=advLightState[i].color[2];
00848      
00849         void *l = rt_light(rtscene, 
00850                            rt_texture(rtscene, &tex),
00851                            /* negate position to correct handedness... */ 
00852                            rt_vector(pos[0], pos[1], -pos[2]), 0.0f);
00853 
00854         /* emit light attentuation parameters if needed */
00855         if (advLightState[i].constfactor != 1.0f ||
00856             advLightState[i].linearfactor != 0.0f ||
00857             advLightState[i].quadfactor != 0.0f) {
00858           rt_light_attenuation(l,
00859                                advLightState[i].constfactor,
00860                                advLightState[i].linearfactor,
00861                                advLightState[i].quadfactor);
00862         }
00863       }
00864 
00865       lightcount++;
00866     }
00867   }
00868 
00869   if (lightcount < 1) {
00870     msgInfo << "Warning: no lights defined in exported scene!!" << sendmsg;
00871   }
00872 }
00873 
00874 void LibTachyonDisplayDevice::write_materials(void) {
00875   // background color
00876   apicolor col;
00877   col.r = backColor[0];
00878   col.g = backColor[1];
00879   col.b = backColor[2];
00880   rt_background(rtscene, col);
00881 
00882   // Specify Tachyon background sky sphere if background gradient
00883   // mode is enabled.
00884   if (backgroundmode == 1) {
00885     float bspheremag = 0.5f;
00886 
00887     // compute positive/negative magnitude of sphere gradient
00888     switch (projection()) {
00889       case DisplayDevice::ORTHOGRAPHIC:
00890         // For orthographic views, Tachyon uses the dot product between
00891         // the incident ray origin and the sky sphere gradient "up" vector,
00892         // since all camera rays have the same direction and differ only
00893         // in their origin.
00894         bspheremag = vSize / 4.0f;
00895         break;
00896 
00897       case DisplayDevice::PERSPECTIVE:
00898       default:
00899         // For perspective views, Tachyon uses the dot product between
00900         // the incident ray and the sky sphere gradient "up" vector,
00901         // so for larger values of vSize, we have to clamp the maximum
00902         // magnitude to 1.0. 
00903         bspheremag = (vSize / 2.0f) / (eyePos[2] - zDist);
00904         if (bspheremag > 1.0f)
00905           bspheremag = 1.0f;
00906         break;
00907     }
00908 
00909     if (projection() == DisplayDevice::ORTHOGRAPHIC)
00910       rt_background_mode(rtscene, RT_BACKGROUND_TEXTURE_SKY_ORTHO_PLANE);
00911     else
00912       rt_background_mode(rtscene, RT_BACKGROUND_TEXTURE_SKY_SPHERE);
00913     rt_background_gradient(rtscene, 
00914                              rt_vector(0, 1, 0),
00915                              bspheremag, -bspheremag, 
00916                              rt_color(backgradienttopcolor[0],
00917                                       backgradienttopcolor[1],
00918                                       backgradienttopcolor[2]),
00919                              rt_color(backgradientbotcolor[0],
00920                                       backgradientbotcolor[1],
00921                                       backgradientbotcolor[2]));
00922   } 
00923 
00924   // set depth cueing parameters
00925   if (cueingEnabled) {
00926     switch (cueMode) {
00927       case CUE_LINEAR:
00928         rt_fog_mode(rtscene, RT_FOG_LINEAR);
00929         rt_fog_parms(rtscene, col, get_cue_start(), get_cue_end(), 1.0f);
00930         break;
00931  
00932       case CUE_EXP:
00933         rt_fog_mode(rtscene, RT_FOG_EXP);
00934         rt_fog_parms(rtscene, col, 0.0, get_cue_end(), get_cue_density());
00935         break;
00936  
00937       case CUE_EXP2:
00938         rt_fog_mode(rtscene, RT_FOG_EXP2);
00939         rt_fog_parms(rtscene, col, 0.0, get_cue_end(), get_cue_density());
00940         break;
00941 
00942       case NUM_CUE_MODES:
00943         // this should never happen
00944         break;
00945     } 
00946   } else {
00947     rt_fog_mode(rtscene, RT_FOG_NONE);
00948   }
00949 }
00950 
00951 
00952 void * LibTachyonDisplayDevice::tex_cindexmaterial(int cindex, int material) {
00953   float *rgb = (float *) &matData[cindex];
00954   void *voidtex;
00955 
00956   voidtex = tex_colormaterial(rgb, material);
00957  
00958   return voidtex;
00959 }
00960 
00961 
00962 void * LibTachyonDisplayDevice::tex_colormaterial(float *rgb, int material) {
00963   apitexture tex;
00964   void *voidtex;
00965 
00966   memset(&tex, 0, sizeof(apitexture));
00967 
00968   if (materials_on) {
00969     tex.ambient  = mat_ambient;
00970     tex.diffuse  = mat_diffuse;
00971     tex.specular = mat_mirror;
00972   } else {
00973     tex.ambient  = 1.0;
00974     tex.diffuse  = 0.0;
00975     tex.specular = 0.0;
00976   }
00977 
00978   tex.opacity  = mat_opacity;
00979   tex.col.r =  rgb[0];
00980   tex.col.g =  rgb[1];
00981   tex.col.b =  rgb[2];
00982 
00984   if (!involtex) {
00986     tex.texturefunc = RT_TEXTURE_CONSTANT;
00987   } else {
00991     float voluaxs[3];           
00992     float volvaxs[3];           
00993     float volwaxs[3];
00994     float volcent[3];
00995 
00996     // transform the y/v/w texture coordinate axes from molecule
00997     // coordinates into world coordinates
00998     (transMat.top()).multplaneeq3d(xplaneeq, voluaxs);
00999     (transMat.top()).multplaneeq3d(yplaneeq, volvaxs);
01000     (transMat.top()).multplaneeq3d(zplaneeq, volwaxs);
01001 
01002     // undo the scaling operation applied by the transformation
01003     float invscale = 1.0f / scale_radius(1.0f);
01004     int i;
01005     for (i=0; i<3; i++) {
01006       voluaxs[i] *= invscale;
01007       volvaxs[i] *= invscale;
01008       volwaxs[i] *= invscale;
01009     }
01010 
01011     // compute the volume origin in molecule coordinates by
01012     // reverting the scaling factor that was previously applied
01013     // to the texture plane equation
01014     float volorgmol[3] = {0,0,0};
01015     volorgmol[0] = -xplaneeq[3] / norm(xplaneeq);
01016     volorgmol[1] = -yplaneeq[3] / norm(yplaneeq);
01017     volorgmol[2] = -zplaneeq[3] / norm(zplaneeq);
01018 
01019     // transform the volume origin into world coordinates
01020     (transMat.top()).multpoint3d(volorgmol, volcent);
01021 
01022     tex.texturefunc = RT_TEXTURE_VOLUME_IMAGE;
01023 
01024     sprintf(tex.imap, "::VMDVolTex%d", voltexID);
01025     tex.ctr.x =  volcent[0];
01026     tex.ctr.y =  volcent[1];
01027     tex.ctr.z = -volcent[2];
01028     tex.rot.x = 0;
01029     tex.rot.y = 0;
01030     tex.rot.z = 0;
01031     tex.scale.x = 1;
01032     tex.scale.y = 1;
01033     tex.scale.z = 1;
01034     tex.uaxs.x =  voluaxs[0];
01035     tex.uaxs.y =  voluaxs[1];
01036     tex.uaxs.z = -voluaxs[2];
01037     tex.vaxs.x =  volvaxs[0];
01038     tex.vaxs.y =  volvaxs[1];
01039     tex.vaxs.z = -volvaxs[2];
01040     tex.waxs.x =  volwaxs[0];
01041     tex.waxs.y =  volwaxs[1];
01042     tex.waxs.z = -volwaxs[2];
01043   }
01044 
01046   voidtex=rt_texture(rtscene, &tex);
01047 
01049   rt_tex_phong(voidtex, mat_specular, mat_shininess, RT_PHONG_PLASTIC);
01050 
01052   if (mat_transmode)
01053     rt_tex_transmode(voidtex, RT_TRANS_RASTER3D);
01054 
01056   rt_tex_outline(voidtex, mat_outline, mat_outlinewidth);
01057  
01058   return voidtex;
01059 }
01060 
01061 

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