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

FileRenderer.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr                                                                       
00003  *cr            (C) Copyright 1995-2008 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: FileRenderer.C,v $
00013  *      $Author: johns $        $Locker:  $             $State: Exp $
00014  *      $Revision: 1.120 $      $Date: 2008/04/24 02:55:35 $
00015  *
00016  ***************************************************************************
00017  * DESCRIPTION:
00018  * 
00019  * The FileRenderer class implements the data and functions needed to 
00020  * render a scene to a file in some format (postscript, raster3d, etc.)
00021  *
00022  ***************************************************************************/
00023 
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026 #include "utilities.h"
00027 #include "DispCmds.h"
00028 #include "FileRenderer.h"
00029 #include "VMDDisplayList.h"
00030 #include "Inform.h"
00031 #include "Scene.h"
00032 #include "Hershey.h"
00033 
00034 // constructor
00035 FileRenderer::FileRenderer(const char *public_name, 
00036                            const char *default_file_name,
00037                            const char *default_command_line) : 
00038   DisplayDevice(public_name), transMat(10)
00039 {
00040   // save the various names
00041   publicName = stringdup(public_name);
00042   defaultFilename = stringdup(default_file_name);
00043   defaultCommandLine = stringdup(default_command_line);
00044   execCmd = stringdup(defaultCommandLine);
00045   has_aa = 0;
00046   aalevel = -1;
00047   has_imgsize = 0;
00048   imgwidth = imgheight = 0;
00049   aspectratio = 0.0f;
00050   curformat = -1;
00051   warningflags = FILERENDERER_NOWARNINGS;
00052 
00053   // init some state variables
00054   outfile = NULL;
00055   isOpened = FALSE;
00056   my_filename = NULL;
00057 
00058   // initialize sphere tesselation variables
00059   sph_nverts = 0;
00060   sph_verts = NULL;
00061 }
00062 
00063 // close (to be on the safe side) and delete
00064 FileRenderer::~FileRenderer(void) {
00065   // free sphere tessellation data
00066   if (sph_verts && sph_nverts) 
00067     free(sph_verts);
00068 
00069   close_file();
00070   delete [] my_filename;
00071   delete [] publicName;
00072   delete [] defaultFilename;
00073   delete [] defaultCommandLine;
00074   delete [] execCmd;
00075 }
00076 
00077 int FileRenderer::do_define_light(int n, float *color, float *position) {
00078   for (int i=0; i<3; i++) {
00079     lightState[n].color[i] = color[i];
00080     lightState[n].pos[i] = position[i];
00081   }
00082   return TRUE;
00083 }
00084 
00085 int FileRenderer::do_activate_light(int n, int turnon) {
00086   lightState[n].on = turnon;
00087   return TRUE;
00088 }
00089 
00090 void FileRenderer::do_use_colors() {
00091   for (int i=0; i<MAXCOLORS; i++) {
00092     matData[i][0] = colorData[3*i  ];
00093     matData[i][1] = colorData[3*i+1];
00094     matData[i][2] = colorData[3*i+2];
00095   }
00096 }
00097 
00098 int FileRenderer::set_imagesize(int *w, int *h) {
00099   if (*w < 0 || *h < 0) return FALSE;
00100   if (*w == imgwidth && *h == imgheight) return TRUE;
00101   if (!aspectratio) {
00102     if (*w) imgwidth = *w; 
00103     if (*h) imgheight = *h;
00104   } else {
00105     if (*w) {
00106       imgwidth = *w;
00107       imgheight = (int)(*w / aspectratio);
00108     } else if (*h) {
00109       imgwidth = (int)(*h * aspectratio);
00110       imgheight = *h;
00111     } else {
00112       if (imgwidth || imgheight) {
00113         int wtmp = imgwidth, htmp = imgheight;
00114         set_imagesize(&wtmp, &htmp);
00115       }
00116     }
00117   }
00118   update_exec_cmd();
00119   *w = imgwidth;
00120   *h = imgheight;
00121   return TRUE;
00122 }
00123 
00124 float FileRenderer::set_aspectratio(float aspect) {
00125   if (aspect >= 0) aspectratio = aspect;
00126   int w=0, h=0;
00127   set_imagesize(&w, &h);  // update_exec_cmd() called from set_imagesize() 
00128   return aspectratio;
00129 }
00130 
00131 int FileRenderer::nearest_index(float r, float g, float b) const {
00132    const float *rcol = matData[BEGREGCLRS];  // get the solid colors
00133    float lsq = r - rcol[0]; lsq *= lsq;
00134    float tmp = g - rcol[1]; lsq += tmp * tmp;
00135          tmp = b - rcol[2]; lsq += tmp * tmp;
00136    float best = lsq;
00137    int bestidx = BEGREGCLRS;
00138    for (int n= BEGREGCLRS+1; n < (BEGREGCLRS + REGCLRS); n++) {
00139      rcol = matData[n];
00140      lsq = r - rcol[0]; lsq *= lsq;
00141      tmp = g - rcol[1]; lsq += tmp * tmp;
00142      tmp = b - rcol[2]; lsq += tmp * tmp;
00143      if (lsq < best) {
00144        best = lsq;
00145        bestidx = n;
00146      }
00147    }
00148    return bestidx;
00149 }
00150 
00151 void FileRenderer::set_background(const float * bg) {
00152   backColor[0] = bg[0];
00153   backColor[1] = bg[1];
00154   backColor[2] = bg[2];
00155 }
00156 
00157 
00158 // open file, closing the previous file if it was still open
00159 int FileRenderer::open_file(const char *filename) {
00160   if (isOpened) {
00161     close_file();
00162   }
00163   if ( (outfile = fopen(filename, "wa")) == NULL) {
00164     msgErr << "Could not open file " << filename
00165            << " in current directory for writing!" << sendmsg;
00166     return FALSE;
00167   }
00168   my_filename = stringdup(filename);
00169   isOpened = TRUE;
00170   reset_state();
00171   return TRUE;
00172 }
00173 
00174 void FileRenderer::reset_state(void) {
00175   // empty out the viewing stack
00176   while (transMat.num()) {
00177     transMat.pop();
00178   }
00179   // reset everything else
00180   colorIndex = -1;
00181   materialIndex = -1;
00182   dataBlock = NULL;
00183   lineWidth = 1;
00184   lineStyle = 1;
00185   pointSize = 1;
00186   sphereResolution = 4;
00187   sphereStyle = 1;
00188   materials_on = TRUE;
00189 }
00190 
00191 // close the file.  This could be called by open_file if the previous
00192 // file wasn't closed, so don't put too much here
00193 void FileRenderer::close_file(void) {
00194   if (outfile) {
00195     fclose(outfile);
00196     outfile = NULL;
00197   }
00198   delete [] my_filename;
00199   my_filename = NULL;
00200   isOpened = FALSE;
00201 }
00202 
00203 
00204 int FileRenderer::prepare3D(int) {
00205   // set the eye position, based on the value of whichEye, which was
00206   // obtained when we copied the current visible display device to the
00207   // file renderer.  
00208   int i;
00209   float lookat[3];
00210   for (i=0; i<3; i++) 
00211     lookat[i] = eyePos[i] + eyeDir[i];
00212 
00213   switch (whichEye) {
00214     case LEFTEYE:
00215       for (i=0; i<3; i++) 
00216         eyePos[i] -= eyeSepDir[i];
00217   
00218       for (i=0; i<3; i++) 
00219         eyeDir[i] = lookat[i] - eyePos[i];
00220       break; 
00221 
00222     case RIGHTEYE:
00223       for (i=0; i<3; i++) 
00224         eyePos[i] += eyeSepDir[i]; 
00225 
00226       for (i=0; i<3; i++) 
00227         eyeDir[i] = lookat[i] - eyePos[i];
00228       break;
00229 
00230     case NOSTEREO: 
00231       break;
00232   }
00233 
00234   if (isOpened) {
00235     write_header();
00236   }
00237 
00238   return TRUE;
00239 }
00240 
00242 
00243 void FileRenderer::render(const VMDDisplayList *cmdList) {
00244   if (!cmdList) return;
00245   int tok, i;
00246   char *cmdptr; 
00247 
00248   // scan through the list and do the action based on the token type
00249   // if the command relates to the viewing state, keep track of it
00250   // for those renderers that don't store state
00251   while (transMat.num()) {    // clear the stack
00252     transMat.pop();
00253   }
00254   Matrix4 m;
00255   transMat.push(m);           // push on the identity matrix
00256   super_multmatrix(cmdList->mat.mat);
00257 
00258   colorIndex = 0;
00259   materialIndex = 0;
00260   lineWidth = 1;
00261   lineStyle = 1;
00262   pointSize = 1;
00263   sphereResolution = 4;
00264   sphereStyle = 1;
00265  
00266   // set the material properties
00267   super_set_material(cmdList->materialtag);
00268   mat_ambient   = cmdList->ambient;
00269   mat_specular  = cmdList->specular;
00270   mat_diffuse   = cmdList->diffuse;
00271   mat_shininess = cmdList->shininess;
00272   mat_opacity   = cmdList->opacity;
00273 
00274   for (i=0; i<VMD_MAX_CLIP_PLANE; i++) {
00275     clip_mode[i] = cmdList->clipplanes[i].mode;
00276     memcpy(&clip_center[i][0], &cmdList->clipplanes[i].center, 3*sizeof(float));
00277     memcpy(&clip_normal[i][0], &cmdList->clipplanes[i].normal, 3*sizeof(float));
00278     memcpy(&clip_color[i][0],  &cmdList->clipplanes[i].color,  3*sizeof(float));
00279   }
00280   start_clipgroup();
00281 
00282   // Compute periodic images
00283   ResizeArray<Matrix4> pbcImages;
00284   find_pbc_images(cmdList, pbcImages);
00285   int nimages = pbcImages.num();
00286 
00287 for (int pbcimage = 0; pbcimage < nimages; pbcimage++) {
00288  transMat.dup();
00289  super_multmatrix(pbcImages[pbcimage].mat);
00290 
00291   VMDDisplayList::VMDLinkIter cmditer;
00292   cmdList->first(&cmditer);
00293   while ((tok = cmdList->next(&cmditer, cmdptr))  != DLASTCOMMAND) {
00294     switch (tok) {   // plot a point
00295     case DDATABLOCK:
00296 #ifdef VMDCAVE
00297       dataBlock = (float *)cmdptr;
00298 #else
00299       dataBlock = ((DispCmdDataBlock *)cmdptr)->data;
00300 #endif
00301       break;                                                                  
00302 
00303     case DPOINT:
00304       point(((DispCmdPoint *)cmdptr)->pos);  
00305       break;
00306 
00307     case DPOINTARRAY:
00308       {
00309       int i, ind;
00310       DispCmdPointArray *pa = (DispCmdPointArray *)cmdptr;
00311       float *centers;
00312       float *colors;
00313       pa->getpointers(centers, colors);
00314 
00315       pointSize = (int) pa->size;     // set the point size
00316       ind = 0;
00317       for (i=0; i<pa->numpoints; i++) {
00318         super_set_color(nearest_index(colors[ind], colors[ind+1], colors[ind+2])); 
00319         point(&centers[ind]);  
00320         ind += 3;
00321       }
00322       pointSize = 1;            // reset the point size
00323       }
00324       break;
00325 
00326     case DLITPOINTARRAY:
00327       {
00328       int i, ind;
00329       DispCmdLitPointArray *pa = (DispCmdLitPointArray *)cmdptr;
00330       float *centers;
00331       float *normals;
00332       float *colors;
00333       pa->getpointers(centers, normals, colors);
00334       pointSize = (int) pa->size;     // set the point size
00335       ind = 0;
00336       for (i=0; i<pa->numpoints; i++) {
00337         super_set_color(nearest_index(colors[ind], colors[ind+1], colors[ind+2])); 
00338         point(&centers[ind]);  
00339         ind += 3;
00340       }
00341       pointSize = 1;            // reset the point size
00342       }
00343       break;
00344 
00345     case DSPHERE:    // draw a sphere
00346       sphere((float *)cmdptr);  
00347       break;
00348 
00349     case DSPHERE_I: {// plot a sphere using indices into dataBlock
00350       DispCmdSphereIndex *cmd = (DispCmdSphereIndex *)cmdptr;
00351       int n1 = cmd->pos; 
00352       float spheredata[4];
00353       spheredata[0] = dataBlock[n1++];
00354       spheredata[1] = dataBlock[n1++];
00355       spheredata[2] = dataBlock[n1];
00356       spheredata[3] = cmd->rad; 
00357       sphere(spheredata);
00358       break;
00359     }
00360 
00361     case DSPHEREARRAY:     
00362       {
00363       DispCmdSphereArray *sa = (DispCmdSphereArray *)cmdptr;
00364       int i, ind;
00365       float * centers;
00366       float * radii;
00367       float * colors;
00368       sa->getpointers(centers, radii, colors);
00369 
00370       set_sphere_res(sa->sphereres); // set the current sphere resolution
00371 
00372       ind = 0;
00373       for (i=0; i<sa->numspheres; i++) {
00374         float xyzr[4];
00375         xyzr[0]=centers[ind    ];
00376         xyzr[1]=centers[ind + 1];
00377         xyzr[2]=centers[ind + 2];
00378         xyzr[3]=radii[i];
00379 
00380         super_set_color(nearest_index(colors[ind], colors[ind+1], colors[ind+2])); 
00381         sphere(xyzr);
00382         ind += 3; // next sphere
00383       }
00384       }
00385       break;
00386 
00387     case DLINE:    // plot a line
00388       // don't draw degenerate lines of zero length
00389       if (memcmp(cmdptr, cmdptr+3*sizeof(float), 3*sizeof(float))) {
00390         line((float *)cmdptr, ((float *)cmdptr) + 3);
00391       }
00392       break;
00393    
00394     case DLINEARRAY: // array of lines
00395       {
00396       float *v = (float *) cmdptr;
00397       int nlines = (int)v[0];
00398       v++;
00399       for (int i=0; i<nlines; i++) {
00400         // don't draw degenerate lines of zero length
00401         if (memcmp(v,v+3,3*sizeof(float))) {
00402           line(v,v+3);
00403         }
00404         v += 6;
00405       }
00406       }
00407       break; 
00408 
00409     case DPOLYLINEARRAY: // array of lines
00410       {
00411       float *v = (float *) cmdptr;
00412       int nlines = (int)v[0];
00413       v++;
00414       for (int i=0; i<nlines-1; i++) {
00415         // don't draw degenerate lines of zero length
00416         if (memcmp(v,v+3,3*sizeof(float))) {
00417           line(v,v+3);
00418         }
00419         v += 3;
00420       }
00421       }
00422       break; 
00423 
00424     case DCYLINDER: // plot a cylinder
00425       if (memcmp(cmdptr, cmdptr+3*sizeof(float), 3*sizeof(float))) {
00426         cylinder((float *)cmdptr, ((float *)cmdptr) + 3, ((float *)cmdptr)[6],
00427                  ((int) ((float *) cmdptr)[8]));
00428       }
00429       break;
00430 
00431     case DCONE:      // plot a cone  
00432       {
00433       DispCmdCone *cmd = (DispCmdCone *)cmdptr;
00434       if (memcmp(cmd->pos1, cmd->pos2, 3*sizeof(float))) 
00435         cone(cmd->pos1, cmd->pos2, cmd->radius, cmd->radius2, cmd->res);
00436       }
00437       break;
00438    
00439     case DTRIANGLE:    // plot a triangle
00440       {
00441       DispCmdTriangle *cmd = (DispCmdTriangle *)cmdptr;
00442       triangle(cmd->pos1,cmd->pos2,cmd->pos3,
00443                cmd->norm1, cmd->norm2, cmd->norm3);
00444       }
00445       break;
00446 
00447     case DTRIMESH:     // draw a triangle mesh
00448       {
00449       DispCmdTriMesh *cmd = (DispCmdTriMesh *) cmdptr;
00450       float *cnv;
00451       int *f;
00452       cmd->getpointers(cnv, f);
00453       trimesh(cmd->numverts, cnv, cmd->numfacets, f); 
00454       }
00455       break;
00456 
00457     case DTRISTRIP:     // draw a triangle strip
00458       {
00459       DispCmdTriStrips *cmd = (DispCmdTriStrips *) cmdptr;
00460       float *cnv;
00461       int *f;
00462       int *vertsperstrip;
00463       cmd->getpointers(cnv, f, vertsperstrip);
00464       tristrip(cmd->numverts, cnv, cmd->numstrips, vertsperstrip, f); 
00465       }
00466       break;
00467 
00468     case DWIREMESH:     // draw a triangle mesh in wireframe
00469       {
00470       DispCmdWireMesh *cmd = (DispCmdWireMesh *) cmdptr;
00471       float *cnv;
00472       int *l;
00473       cmd->getpointers(cnv, l);
00474       wiremesh(cmd->numverts, cnv, cmd->numlines, l); 
00475       }
00476       break;
00477 
00478     case DSQUARE:      // plot a square (norm, 4 verticies
00479       {
00480       DispCmdSquare *cmd = (DispCmdSquare *)cmdptr;
00481       square(cmd->norml, cmd->pos1, cmd->pos2, cmd->pos3, cmd->pos4);
00482       }
00483       break;
00484 
00485 
00487     case DLINEWIDTH:   //  set the line width (and in superclass)
00488       lineWidth = ((DispCmdLineWidth *)cmdptr)->width;
00489       set_line_width(lineWidth);
00490       break;
00491 
00492     case DLINESTYLE:   // set the line style (and in superclass)
00493       lineStyle = ((DispCmdLineType *)cmdptr)->type;
00494       set_line_style(lineStyle);
00495       break;
00496 
00497     case DSPHERERES:   // sphere resolution (and in superclass)
00498       sphereResolution = ((DispCmdSphereRes *)cmdptr)->res;
00499       set_sphere_res(sphereResolution);
00500       break;
00501 
00502     case DSPHERETYPE:   // sphere resolution (and in superclass)
00503       sphereStyle = ((DispCmdSphereType *)cmdptr)->type;
00504       set_sphere_style(sphereStyle);
00505       break;
00506 
00507     case DMATERIALON:
00508       super_materials(1); 
00509       break;
00510 
00511     case DMATERIALOFF:
00512       super_materials(0); 
00513       break;
00514 
00515     case DCOLORINDEX:  // change the color
00516       super_set_color(((DispCmdColorIndex *)cmdptr)->color);
00517       break; 
00518 
00519     case DTEXTSIZE:
00520       // not implemented yet
00521       warningflags |= FILERENDERER_NOTEXT;
00522       break;
00523 
00524     case DTEXT: 
00525       {
00526       float *pos = (float *)cmdptr;
00527       super_text_position(pos[0], pos[1], pos[2]);
00528       text((char *) (pos+3));
00529       }
00530       break;
00531 
00532     case DCOMMENT:
00533       comment((char *)cmdptr);
00534       break;
00535 
00536     // pick selections (only one implemented)
00537     case DPICKPOINT:
00538       pick_point(((DispCmdPickPoint *)cmdptr)->postag,
00539                  ((DispCmdPickPoint *)cmdptr)->tag); 
00540       break;
00541 
00542     case DPICKPOINT_I:
00543       pick_point(dataBlock + ((DispCmdPickPointIndex *)cmdptr)->pos,
00544                  ((DispCmdPickPointIndex *)cmdptr)->tag); 
00545       break;
00546 
00547     case DPICKPOINT_IARRAY:
00548       { 
00549         int i;
00550         DispCmdPickPointIndexArray *cmd =  ((DispCmdPickPointIndexArray *)cmdptr);
00551         if (cmd->allselected) {
00552           for (i=0; i<cmd->numpicks; i++) {
00553             pick_point(dataBlock + i*3, i);
00554           }
00555         } else {
00556           int *indices;
00557           cmd->getpointers(indices);
00558           for (i=0; i<cmd->numpicks; i++) {
00559             pick_point(dataBlock + indices[i]*3, indices[i]); 
00560           }
00561         }
00562       }
00563       break;
00564 
00565     // generate warnings if any geometry token is unimplemented the renderer
00566 #if 0
00567     case DSTRIPETEXON:
00568     case DSTRIPETEXOFF:
00569 #endif
00570     case DVOLUMETEXTURE:
00571       {
00572       DispCmdVolumeTexture *cmd = (DispCmdVolumeTexture *)cmdptr;
00573       float xplaneeq[4];
00574       float yplaneeq[4];
00575       float zplaneeq[4];
00576       int i;
00577 
00578       // automatically generate texture coordinates by translating from
00579       // model coordinate space to volume coordinates.
00580       for (i=0; i<3; i++) {
00581         xplaneeq[i] = cmd->v1[i];
00582         yplaneeq[i] = cmd->v2[i];
00583         zplaneeq[i] = cmd->v3[i];
00584       }
00585       xplaneeq[3] = cmd->v0[0];
00586       yplaneeq[3] = cmd->v0[1];
00587       zplaneeq[3] = cmd->v0[2];
00588 
00589       // define a volumetric texture map
00590       define_volume_texture(cmd->ID, cmd->xsize, cmd->ysize, cmd->zsize,
00591                             xplaneeq, yplaneeq, zplaneeq,
00592                             cmd->texmap);
00593       }
00594       break;
00595 
00596     case DVOLSLICE:
00597       {
00598       DispCmdVolSlice *cmd = (DispCmdVolSlice *)cmdptr;
00599       volume_texture_on(1);
00600       square(cmd->normal, cmd->v, cmd->v + 3, cmd->v + 6, cmd->v + 9); 
00601       volume_texture_off();
00602       }
00603       break;
00604 
00605     case DVOLTEXON:
00606       volume_texture_on(0);
00607       break;
00608 
00609     case DVOLTEXOFF:
00610       volume_texture_off();
00611       break;
00612 
00613 #if 0
00614     // generate warnings if any geometry token is unimplemented the renderer
00615     default:
00616       warningflags |= FILERENDERER_NOMISCFEATURE;
00617       break;
00618 #endif
00619     } // end of switch statement
00620   } // while (tok != DLASTCOMMAND)
00621  transMat.pop();
00622 } // end of loop over periodic images
00623   end_clipgroup();
00624 }
00625 
00627 
00628 
00629 // change the active color
00630 void FileRenderer::super_set_color(int color_index) {
00631   if (colorIndex != color_index) {
00632     colorIndex = color_index;
00633     set_color(color_index);
00634   }
00635   super_materials(1);
00636 }
00637 
00638 // change the active material
00639 void FileRenderer::super_set_material(int material_index) {
00640   if (materialIndex != material_index) {
00641     materialIndex = material_index;
00642     set_material(material_index);
00643   }
00644   super_materials(1);
00645 }
00646 
00647 // turn materials on or off
00648 void FileRenderer::super_materials(int on_or_off) {
00649   if (on_or_off) {
00650     materials_on = 1;
00651     activate_materials();
00652   } else {
00653     materials_on = 0;
00654     deactivate_materials();
00655   }
00656 }
00657 
00658 
00660 
00661 void FileRenderer::super_load(float *cmdptr) {
00662   Matrix4 tmp(cmdptr);
00663   (transMat.top()).loadmatrix(tmp);
00664   load(tmp);
00665 }
00666 void FileRenderer::super_multmatrix(const float *cmdptr) {
00667   Matrix4 tmp(cmdptr);
00668   (transMat.top()).multmatrix(tmp);
00669   multmatrix(tmp);
00670 }
00671 
00672 void FileRenderer::super_translate(float *cmdptr) {
00673   (transMat.top()).translate( cmdptr[0], cmdptr[1], cmdptr[2]);
00674   translate( cmdptr[0], cmdptr[1], cmdptr[2]);
00675 }
00676 
00677 void FileRenderer::super_rot(float * cmdptr) {
00678   (transMat.top()).rot( cmdptr[0], 'x' + (int) (cmdptr[1]) );
00679   rot( cmdptr[0], 'x' + (int) (cmdptr[1]) );
00680 }
00681 
00682 void FileRenderer::super_scale(float *cmdptr) {
00683   (transMat.top()).scale( cmdptr[0], cmdptr[1], cmdptr[2] );
00684   scale( cmdptr[0], cmdptr[1], cmdptr[2] );
00685 }
00686 
00687 void FileRenderer::super_scale(float s) {
00688   transMat.top().scale(s,s,s);
00689   scale(s,s,s);
00690 }
00691 
00692 // scale the radius a by the global scaling factor, return as b.
00693 float FileRenderer::scale_radius(float r) {
00694   // of course, VMD does not have a direction-independent scaling
00695   // factor, so I'll fake it using an average of the scaling
00696   // factors in each direction.
00697   
00698   float scaleFactor;
00699   
00700   scaleFactor = (sqrtf( 
00701   (((transMat.top()).mat)[0])*(((transMat.top()).mat)[0]) +
00702   (((transMat.top()).mat)[4])*(((transMat.top()).mat)[4]) +
00703   (((transMat.top()).mat)[8])*(((transMat.top()).mat)[8]) ) +
00704   sqrtf( (((transMat.top()).mat)[1])*(((transMat.top()).mat)[1]) +
00705   (((transMat.top()).mat)[5])*(((transMat.top()).mat)[5]) +
00706   (((transMat.top()).mat)[9])*(((transMat.top()).mat)[9]) ) +
00707   sqrtf( (((transMat.top()).mat)[2])*(((transMat.top()).mat)[2]) +
00708   (((transMat.top()).mat)[6])*(((transMat.top()).mat)[6]) +
00709   (((transMat.top()).mat)[10])*(((transMat.top()).mat)[10]) ) ) / 3.0f;
00710   
00711   if(r < 0.0) {
00712     msgErr << "FileRenderer: Error, Negative radius" << sendmsg;
00713     r = -r;
00714   } 
00715   
00716   r = r * scaleFactor;
00717   
00718   return r;
00719 }
00720 
00721 
00723 void FileRenderer::super_text_position(float x, float y, float z) {
00724   textpos[0] = x;
00725   textpos[1] = y;
00726   textpos[2] = z;
00727   text_position(x, y, z);
00728 }
00729 
00731 void FileRenderer::set_exec_string(const char *extstr) {
00732   delete [] execCmd;
00733   execCmd = stringdup(extstr);
00734 }
00735 
00736 
00737 // default triangulated implementation of two-radius cones
00738 void FileRenderer::cone(float *base, float *apex, float radius, float radius2, int numsides) {
00739   int h;
00740   float theta, incTheta, cosTheta, sinTheta;
00741   float axis[3], temp[3], perp[3], perp2[3];
00742   float vert0[3], vert1[3], vert2[3], edge0[3], edge1[3], face0[3], face1[3], norm0[3], norm1[3];
00743 
00744   axis[0] = base[0] - apex[0];
00745   axis[1] = base[1] - apex[1];
00746   axis[2] = base[2] - apex[2];
00747   vec_normalize(axis);
00748 
00749   // Find an arbitrary vector that is not the axis and has non-zero length
00750   temp[0] = axis[0] - 1.0f;
00751   temp[1] = 1.0f;
00752   temp[2] = 1.0f;
00753 
00754   // use the cross product to find orthoganal vectors
00755   cross_prod(perp, axis, temp);
00756   vec_normalize(perp);
00757   cross_prod(perp2, axis, perp); // shouldn't need normalization
00758 
00759   // Draw the triangles
00760   incTheta = (float) VMD_TWOPI / numsides;
00761   theta = 0.0;
00762 
00763   if (radius2>0) {
00764     float negaxis[3], offsetL[3], offsetT[3], vert3[3];
00765     int filled=1;
00766     vec_negate(negaxis, axis);
00767     memset(vert0, 0, sizeof(vert0));
00768     memset(vert1, 0, sizeof(vert1));
00769     memset(norm0, 0, sizeof(norm0));
00770 
00771     for (h=0; h <= numsides+3; h++) {
00772       cosTheta = (float) cos(theta);
00773       sinTheta = (float) sin(theta);
00774       offsetL[0] = radius2 * (cosTheta*perp[0] + sinTheta*perp2[0]);
00775       offsetL[1] = radius2 * (cosTheta*perp[1] + sinTheta*perp2[1]);
00776       offsetL[2] = radius2 * (cosTheta*perp[2] + sinTheta*perp2[2]);
00777       offsetT[0] = radius  * (cosTheta*perp[0] + sinTheta*perp2[0]);
00778       offsetT[1] = radius  * (cosTheta*perp[1] + sinTheta*perp2[1]);
00779       offsetT[2] = radius  * (cosTheta*perp[2] + sinTheta*perp2[2]);
00780 
00781       // copy old vertices
00782       vec_copy(vert2, vert0); 
00783       vec_copy(vert3, vert1); 
00784       vec_copy(norm1, norm0); 
00785 
00786       // calculate new vertices
00787       vec_add(vert0, base, offsetT);
00788       vec_add(vert1, apex, offsetL);
00789 
00790       // Use the new vertex to find new edges
00791       edge0[0] = vert0[0] - vert1[0];
00792       edge0[1] = vert0[1] - vert1[1];
00793       edge0[2] = vert0[2] - vert1[2];
00794       edge1[0] = vert0[0] - vert2[0];
00795       edge1[1] = vert0[1] - vert2[1];
00796       edge1[2] = vert0[2] - vert2[2];
00797 
00798       // Use the new edge to find a new facet normal
00799       cross_prod(norm0, edge1, edge0);
00800       vec_normalize(norm0);
00801 
00802       if (h > 2) {
00803         // Use the new normal to draw the previous side
00804         triangle(vert0, vert1, vert3, norm0, norm0, norm1);
00805         triangle(vert3, vert2, vert0, norm1, norm1, norm0);
00806 
00807         // Draw cylinder caps
00808         if (filled & CYLINDER_LEADINGCAP) {
00809           triangle(vert1, vert3, apex, axis, axis, axis);
00810         }
00811         if (filled & CYLINDER_TRAILINGCAP) {
00812           triangle(vert0, vert2, base, negaxis, negaxis, negaxis);
00813         }
00814       }
00815 
00816       theta += incTheta;
00817     }
00818   } else {
00819     for (h=0; h < numsides+3; h++) {
00820       cosTheta = (float) cos(theta);
00821       sinTheta = (float) sin(theta);
00822 
00823       // Find a new vertex
00824       vert0[0] = base[0] + radius * ( cosTheta*perp[0] + sinTheta*perp2[0] );
00825       vert0[1] = base[1] + radius * ( cosTheta*perp[1] + sinTheta*perp2[1] );
00826       vert0[2] = base[2] + radius * ( cosTheta*perp[2] + sinTheta*perp2[2] );
00827 
00828       // Use the new vertex to find a new edge
00829       edge0[0] = vert0[0] - apex[0];
00830       edge0[1] = vert0[1] - apex[1];
00831       edge0[2] = vert0[2] - apex[2];
00832 
00833       if (h > 0) {
00834         // Use the new edge to find a new face
00835         cross_prod(face0, edge1, edge0);
00836         vec_normalize(face0);
00837 
00838         if (h > 1) {
00839           // Use the new face to find the normal of the previous triangle
00840           norm0[0] = (face1[0] + face0[0]) / 2.0f;
00841           norm0[1] = (face1[1] + face0[1]) / 2.0f;
00842           norm0[2] = (face1[2] + face0[2]) / 2.0f;
00843           vec_normalize(norm0);
00844 
00845           if (h > 2) {
00846             // Use the new normal to draw the previous side and base of the cone
00847             triangle(vert2, vert1, apex, norm1, norm0, face1);
00848             triangle(vert2, vert1, base, axis, axis, axis);
00849           }
00850 
00851         }
00852         // Copy the old values
00853         memcpy(norm1, norm0, 3*sizeof(float));
00854         memcpy(vert2, vert1, 3*sizeof(float));
00855         memcpy(face1, face0, 3*sizeof(float));
00856       }
00857       memcpy(vert1, vert0, 3*sizeof(float));
00858       memcpy(edge1, edge0, 3*sizeof(float));
00859   
00860       theta += incTheta;
00861     }
00862   }
00863 }
00864 
00865 
00866 // default trianglulated cylinder implementation, with optional end caps
00867 void FileRenderer::cylinder(float *base, float *apex, float radius, int filled) {
00868   const int numsides = 20;
00869   int h;
00870   float theta, incTheta, cosTheta, sinTheta;
00871   float axis[3], negaxis[3], temp[3], perp[3], perp2[3];
00872   float vert0[3], vert1[3], vert2[3], vert3[3];
00873   float offset[3], norm0[3], norm1[3];
00874 
00875   axis[0] = base[0] - apex[0];
00876   axis[1] = base[1] - apex[1];
00877   axis[2] = base[2] - apex[2];
00878   vec_normalize(axis);
00879   vec_negate(negaxis, axis);
00880 
00881   // Find an arbitrary vector that is not the axis and has non-zero length
00882   temp[0] = axis[0] - 1.0f;
00883   temp[1] = 1.0f;
00884   temp[2] = 1.0f;
00885 
00886   // use the cross product to find orthoganal vectors
00887   cross_prod(perp, axis, temp);
00888   vec_normalize(perp);
00889   cross_prod(perp2, axis, perp); // shouldn't need normalization
00890 
00891   // Draw the triangles
00892   incTheta = (float) VMD_TWOPI / numsides;
00893   theta = 0.0;
00894 
00895   memset(vert0, 0, sizeof(vert0));
00896   memset(vert1, 0, sizeof(vert1));
00897   memset(norm0, 0, sizeof(norm0));
00898 
00899   for (h=0; h <= numsides; h++) {
00900     cosTheta = (float) cos(theta);
00901     sinTheta = (float) sin(theta);
00902     offset[0] = radius * (cosTheta*perp[0] + sinTheta*perp2[0]);
00903     offset[1] = radius * (cosTheta*perp[1] + sinTheta*perp2[1]);
00904     offset[2] = radius * (cosTheta*perp[2] + sinTheta*perp2[2]);
00905 
00906     // copy old vertices
00907     vec_copy(vert2, vert0); 
00908     vec_copy(vert3, vert1); 
00909     vec_copy(norm1, norm0); 
00910 
00911     // calculate new vertices
00912     vec_add(vert0, base, offset);
00913     vec_add(vert1, apex, offset);
00914 
00915     // new normal
00916     vec_copy(norm0, offset);
00917     vec_normalize(norm0);
00918 
00919     if (h > 0) {
00920       // Use the new normal to draw the previous side
00921       triangle(vert0, vert1, vert3, norm0, norm0, norm1);
00922       triangle(vert3, vert2, vert0, norm1, norm1, norm0);
00923 
00924       // Draw cylinder caps
00925       if (filled & CYLINDER_LEADINGCAP) {
00926         triangle(vert1, vert3, apex, axis, axis, axis);
00927       }
00928       if (filled & CYLINDER_TRAILINGCAP) {
00929         triangle(vert0, vert2, base, negaxis, negaxis, negaxis);
00930       }
00931     }
00932 
00933     theta += incTheta;
00934   }
00935 }
00936 
00937 
00938 // default cylinder-based implementation of lines used
00939 // for ray tracing packages that can't draw real lines
00940 void FileRenderer::line(float * a, float * b) {
00941   // draw a line (cylinder) from a to b
00942   int i, j, test;
00943   float dirvec[3], unitdirvec[3];
00944   float from[3], to[3]; 
00945 
00946   if (lineStyle == ::SOLIDLINE) {
00947     cylinder(a, b, lineWidth * 0.002f, 0);
00948   } else if (lineStyle == ::DASHEDLINE) {
00949     vec_sub(dirvec, b, a);        // vector from a to b
00950     vec_copy(unitdirvec, dirvec);
00951     vec_normalize(unitdirvec);    // unit vector from a to b
00952     test = 1;
00953     i = 0;
00954     while (test == 1) {
00955       for (j=0; j<3; j++) {
00956         from[j] = (float) (a[j] + (2*i    )* 0.05 * unitdirvec[j]);
00957           to[j] = (float) (a[j] + (2*i + 1)* 0.05 * unitdirvec[j]);
00958       }
00959       if (fabsf(a[0] - to[0]) >= fabsf(dirvec[0])) {
00960         vec_copy(to, b);
00961         test = 0;
00962       }
00963       cylinder(from, to, lineWidth * 0.002f, 0);
00964       i++;
00965     }
00966   } 
00967 }
00968 
00969 
00970 // default triangulated sphere implementation
00971 void FileRenderer::sphere(float * xyzr) {
00972   float c[3], r;
00973   int pi, ni;
00974   int i;
00975   int sph_iter = -1;
00976   int sph_desired_iter = 0;
00977 
00978   // copy params
00979   vec_copy(c, xyzr);
00980   r = xyzr[3];
00981 
00982   // the sphere resolution has changed. if sphereRes is less than 32, we
00983   // will use a lookup table to achieve equal or better resolution than
00984   // OpenGL. otherwise we use the following equation:
00985   //    iterations = .9 *
00986   //    (sphereRes)^(1/2)
00987   // This is used as a lookup table to determine the proper
00988   // number of iterations used in the sphere approximation
00989   // algorithm.
00990   const int sph_iter_table[] = {
00991       0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3,
00992       3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4 };
00993 
00994   if (sphereResolution < 0) 
00995     return;
00996   else if (sphereResolution < 32) 
00997     sph_desired_iter = sph_iter_table[sphereResolution];
00998   else 
00999     sph_desired_iter = (int) (0.8f * sqrtf((float) sphereResolution));
01000  
01001   // first we need to determine if a recalculation of the cached
01002   // unit sphere is necessary. this is necessary if the number
01003   // of desired iterations has changed.
01004   if (!sph_verts || !sph_nverts || sph_iter != sph_desired_iter) {
01005     float a[3], b[3], c[3];
01006     float *newverts;
01007     float *oldverts;
01008     int nverts, ntris;
01009     int level;
01010 
01011     // remove old cached copy
01012     if (sph_verts && sph_nverts) free(sph_verts);
01013 
01014     newverts = (float *) malloc(sizeof(float) * 36);
01015     nverts = 12;
01016     ntris = 4;
01017 
01018     // start with half of a unit octahedron (front, convex half)
01019 
01020     // top left triangle
01021     newverts[0] = -1;    newverts[1] = 0;     newverts[2] = 0;
01022     newverts[3] = 0;     newverts[4] = 1;     newverts[5] = 0;
01023     newverts[6] = 0;     newverts[7] = 0;     newverts[8] = 1;
01024 
01025     // top right triangle
01026     newverts[9] = 0;     newverts[10] = 0;    newverts[11] = 1;
01027     newverts[12] = 0;    newverts[13] = 1;    newverts[14] = 0;
01028     newverts[15] = 1;    newverts[16] = 0;    newverts[17] = 0;
01029 
01030     // bottom right triangle
01031     newverts[18] = 0;    newverts[19] = 0;    newverts[20] = 1;
01032     newverts[21] = 1;    newverts[22] = 0;    newverts[23] = 0;
01033     newverts[24] = 0;    newverts[25] = -1;   newverts[26] = 0;
01034 
01035     // bottom left triangle
01036     newverts[27] = 0;    newverts[28] = 0;    newverts[29] = 1;
01037     newverts[30] = 0;    newverts[31] = -1;   newverts[32] = 0;
01038     newverts[33] = -1;   newverts[34] = 0;    newverts[35] = 0;
01039 
01040     for (level = 1; level < sph_desired_iter; level++) {
01041       oldverts = newverts;
01042 
01043       // allocate memory for the next iteration: we will need
01044       // four times the current number of vertices
01045       newverts = (float *) malloc(sizeof(float) * 12 * nverts);
01046       if (!newverts) {
01047         // memory error
01048         sph_iter = -1;
01049         sph_nverts = 0;
01050         sph_verts = NULL;
01051         free(oldverts);
01052         msgErr << "FileRenderer::sphere(): Out of memory. Some "
01053                << "objects were not drawn." << sendmsg;
01054         return;
01055       }
01056 
01057       pi = 0;
01058       ni = 0;
01059       for (i = 0; i < ntris; i++) {
01060         // compute intermediate vertices
01061         a[0] = (oldverts[pi    ] + oldverts[pi + 6]) / 2;
01062         a[1] = (oldverts[pi + 1] + oldverts[pi + 7]) / 2;
01063         a[2] = (oldverts[pi + 2] + oldverts[pi + 8]) / 2;
01064         vec_normalize(a);
01065         b[0] = (oldverts[pi    ] + oldverts[pi + 3]) / 2;
01066         b[1] = (oldverts[pi + 1] + oldverts[pi + 4]) / 2;
01067         b[2] = (oldverts[pi + 2] + oldverts[pi + 5]) / 2;
01068         vec_normalize(b);
01069         c[0] = (oldverts[pi + 3] + oldverts[pi + 6]) / 2;
01070         c[1] = (oldverts[pi + 4] + oldverts[pi + 7]) / 2;
01071         c[2] = (oldverts[pi + 5] + oldverts[pi + 8]) / 2;
01072         vec_normalize(c);
01073 
01074         // build triangles
01075         memcpy(&newverts[ni     ], &oldverts[pi], sizeof(float) * 3);
01076         memcpy(&newverts[ni + 3 ], b, sizeof(float) * 3);
01077         memcpy(&newverts[ni + 6 ], a, sizeof(float) * 3);
01078 
01079         memcpy(&newverts[ni + 9 ], b, sizeof(float) * 3);
01080         memcpy(&newverts[ni + 12], &oldverts[pi + 3], sizeof(float) * 3);
01081         memcpy(&newverts[ni + 15], c, sizeof(float) * 3);
01082 
01083         memcpy(&newverts[ni + 18], a, sizeof(float) * 3);
01084         memcpy(&newverts[ni + 21], b, sizeof(float) * 3);
01085         memcpy(&newverts[ni + 24], c, sizeof(float) * 3);
01086 
01087         memcpy(&newverts[ni + 27], a, sizeof(float) * 3);
01088         memcpy(&newverts[ni + 30], c, sizeof(float) * 3);
01089         memcpy(&newverts[ni + 33], &oldverts[pi + 6], sizeof(float) * 3);
01090 
01091         pi += 9;
01092         ni += 36;
01093       }
01094 
01095       free(oldverts);
01096       nverts *= 4;
01097       ntris *= 4;
01098     }
01099 
01100     sph_iter = sph_desired_iter;
01101     sph_nverts = nverts;
01102     sph_verts = newverts;
01103   }
01104 
01105   // now we're guaranteed to have a valid cached unit sphere, so
01106   // all we need to do is translate each coordinate based on the
01107   // desired position and radius, and add the triangles
01108   pi = 0;
01109   for (i = 0; i < sph_nverts / 3; i++) {
01110     float v0[3], v1[3], v2[3];
01111     float n0[3], n1[3], n2[3];
01112 
01113     // calculate upper hemisphere translation and scaling
01114     v0[0] = r * sph_verts[pi    ] + c[0];
01115     v0[1] = r * sph_verts[pi + 1] + c[1];
01116     v0[2] = r * sph_verts[pi + 2] + c[2];
01117     v1[0] = r * sph_verts[pi + 3] + c[0];
01118     v1[1] = r * sph_verts[pi + 4] + c[1];
01119     v1[2] = r * sph_verts[pi + 5] + c[2];
01120     v2[0] = r * sph_verts[pi + 6] + c[0];
01121     v2[1] = r * sph_verts[pi + 7] + c[1];
01122     v2[2] = r * sph_verts[pi + 8] + c[2];
01123 
01124     // calculate upper hemisphere normals
01125     vec_copy(n0, &sph_verts[pi    ]);
01126     vec_copy(n1, &sph_verts[pi + 3]);
01127     vec_copy(n2, &sph_verts[pi + 6]);
01128 
01129     // draw upper hemisphere
01130     triangle(v0, v1, v2, n0, n1, n2);
01131 
01132     // calculate lower hemisphere translation and scaling
01133     v0[2] = (-r * sph_verts[pi + 2]) + c[2];
01134     v1[2] = (-r * sph_verts[pi + 5]) + c[2];
01135     v2[2] = (-r * sph_verts[pi + 8]) + c[2];
01136 
01137     // calculate lower hemisphere normals
01138     n0[2] = -n0[2];
01139     n1[2] = -n1[2];
01140     n2[2] = -n2[2];
01141 
01142     // draw lower hemisphere
01143     triangle(v0, v2, v1, n0, n2, n1);
01144 
01145     pi += 9;
01146   }
01147 }
01148 
01149 
01150 // start rendering geometry for which user-defined
01151 // clipping planes have been applied.
01152 void FileRenderer::start_clipgroup() {
01153   int i;
01154 
01155   for (i=0; i<VMD_MAX_CLIP_PLANE; i++) {
01156     if (clip_mode[i]) {
01157       warningflags |= FILERENDERER_NOCLIP;
01158       break;
01159     }
01160   }
01161 }
01162 
01163 
01164 void FileRenderer::text(const char *str) {
01165 #if 0
01166   hersheyhandle hh;
01167   float lm, rm, x, y, ox, oy;
01168   int draw, odraw;
01169 
01170   Matrix4 m;
01171   transMat.push(m);           // push on the identity matrix
01172 
01173   while (*str != '\0') {
01174     hersheyDrawInitLetter(&hh, *str, &lm, &rm);
01175     (transMat.top()).translate(-lm, 0, 0);
01176     ox=0;
01177     oy=0;
01178     odraw=0;
01179     while (!hersheyDrawNextLine(&hh, &draw, &x, &y)) {
01180       if (draw && odraw) {
01181         float a[3], b[3];
01182         a[0] = ox; 
01183         a[1] = oy;
01184         a[2] = 0;
01185         b[0] = x;
01186         b[1] = y;
01187         b[2] = 0;
01188 
01189   //      printf("line: %g %g -> %g %g\n", ox, oy, x, y);
01190         line(a, b);        
01191       }
01192 
01193       ox=x;
01194       oy=y;
01195       odraw=draw;
01196     }
01197     (transMat.top()).translate(rm, 0, 0);
01198 
01199     str++;
01200   }
01201 
01202   transMat.pop();
01203 #endif
01204 }
01205 
01206 

Generated on Sat Sep 6 01:26:49 2008 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002