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

Generated on Sat May 26 01:47:58 2012 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002