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

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

Generated on Fri Nov 8 02:44:35 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002