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

PSDisplayDevice.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  * RCS INFORMATION:
00010  *
00011  *      $RCSfile: PSDisplayDevice.C,v $
00012  *      $Author: johns $        $Locker:  $             $State: Exp $
00013  *      $Revision: 1.118 $       $Date: 2020/02/26 07:21:45 $
00014  *
00015  ***************************************************************************/
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include "DepthSortObj.h"
00024 #include "Matrix4.h"
00025 #include "PSDisplayDevice.h"
00026 #include "VMDDisplayList.h"
00027 #include "Inform.h"
00028 
00029 
00030 PSDisplayDevice::PSDisplayDevice(void)
00031 : FileRenderer ("PostScript", "PostScript (vector graphics)", "vmdscene.ps","ghostview %s &") {
00032    memerror = 0;
00033    x_offset = 306;
00034    y_offset = 396;
00035 
00036    // initialize some variables used to cache a triangle mesh
00037    // approximation of a unit sphere
00038    sph_iter = -1;
00039    sph_desired_iter = 0;
00040    sph_nverts = 0;
00041    sph_verts = NULL;
00042 
00043    memusage = 0;
00044    points = 0;
00045    objects = 0;
00046 }
00047 
00048 
00049 PSDisplayDevice::~PSDisplayDevice(void) {
00050    // if necessary, free any memory used in caching the
00051    // unit sphere (see sphere_approx())
00052    if (sph_nverts && sph_verts) free(sph_verts);
00053 }
00054 
00055 
00056 void PSDisplayDevice::render(const VMDDisplayList *cmdList) {
00057    if (!cmdList) return;
00058    DepthSortObject depth_obj;
00059    char *cmd_ptr;
00060    int draw;
00061    int tok;
00062    int nc;
00063    float a[3], b[3], c[3], d[3];
00064    float cent[3];
00065    float r;
00066    Matrix4 ident;
00067 
00068    // first we want to clear the transformation matrix stack
00069    while (transMat.num())
00070       transMat.pop();
00071 
00072    // push on the identity matrix
00073    transMat.push(ident);
00074 
00075    // load the display list's transformation matrix
00076    super_multmatrix(cmdList->mat.mat);
00077 
00078    // Now we need to calculate the normalized position of the light
00079    // so we can compute angles of surfaces to that light for shading
00080    norm_light[0] = lightState[0].pos[0];
00081    norm_light[1] = lightState[0].pos[1];
00082    norm_light[2] = lightState[0].pos[2];
00083    if (norm_light[0] || norm_light[1] || norm_light[2])
00084       vec_normalize(norm_light);
00085 
00086    // Compute periodic image transformation matrices
00087    ResizeArray<Matrix4> pbcImages;
00088    find_pbc_images(cmdList, pbcImages);
00089    int npbcimages = pbcImages.num();
00090 
00091    // Retreive instance image transformation matrices
00092    ResizeArray<Matrix4> instanceImages;
00093    find_instance_images(cmdList, instanceImages);
00094    int ninstances = instanceImages.num();
00095 
00096    for (int pbcimage = 0; pbcimage < npbcimages; pbcimage++) {
00097      transMat.dup();
00098      super_multmatrix(pbcImages[pbcimage].mat);
00099 
00100    for (int instanceimage = 0; instanceimage < ninstances; instanceimage++) {
00101      transMat.dup();
00102      super_multmatrix(instanceImages[instanceimage].mat);
00103 
00104    // Loop through the display list and add each object to our
00105    // depth-sort list for final rendering.
00106    VMDDisplayList::VMDLinkIter cmditer;
00107    cmdList->first(&cmditer);
00108    while ((tok = cmdList->next(&cmditer, cmd_ptr)) != DLASTCOMMAND) {
00109       draw = 0;
00110       nc = -1;
00111 
00112       switch (tok) {
00113          case DPOINT:
00114             // allocate memory
00115             depth_obj.points = (float *) malloc(sizeof(float) * 2);
00116             if (!depth_obj.points) {
00117                // memory error
00118                if (!memerror) {
00119                   memerror = 1;
00120                   msgErr << "PSDisplayDevice: Out of memory. Some " <<
00121                      "objects were not drawn." << sendmsg;
00122                }
00123                break;
00124             }
00125 
00126             // copy data
00127             depth_obj.npoints = 1;
00128             depth_obj.color = colorIndex;
00129             (transMat.top()).multpoint3d(((DispCmdPoint *) cmd_ptr)->pos, a);
00130             memcpy(depth_obj.points, a, sizeof(float) * 2);
00131 
00132             // compute the distance to the eye
00133             depth_obj.dist = compute_dist(a);
00134 
00135             // valid object to depth sort
00136             draw = 1;
00137             break;
00138 
00139          case DSPHERE:
00140          {
00141             (transMat.top()).multpoint3d(((DispCmdSphere *) cmd_ptr)->pos_r, c);
00142             r = scale_radius(((DispCmdSphere *) cmd_ptr)->pos_r[3]);
00143 
00144             sphere_approx(c, r);
00145             break;
00146          }
00147 
00148          case DSPHEREARRAY:
00149          {
00150             DispCmdSphereArray *sa = (DispCmdSphereArray *) cmd_ptr;
00151             int cIndex, rIndex; // cIndex: index of colors & centers
00152                                 // rIndex: index of radii.
00153             float * centers;
00154             float * radii;
00155             float * colors;
00156             sa->getpointers(centers, radii, colors);
00157 
00158             set_sphere_res(sa->sphereres);
00159 
00160             for (cIndex = 0, rIndex=0; rIndex < sa->numspheres; 
00161                  cIndex+=3, rIndex++)
00162             {
00163                 colorIndex = nearest_index(colors[cIndex],
00164                                            colors[cIndex+1],
00165                                            colors[cIndex+2]);
00166                 (transMat.top()).multpoint3d(&centers[cIndex] , c);
00167                 r = scale_radius(radii[rIndex]);
00168 
00169                 sphere_approx(c, r);
00170             }
00171 
00172             break;
00173          }   
00174 
00175          case DLINE:
00176             // check for zero-length line (degenerate)
00177             if (!memcmp(((DispCmdLine *) cmd_ptr)->pos1,
00178                         ((DispCmdLine *) cmd_ptr)->pos2,
00179                         sizeof(float) * 3)) {
00180                // degenerate line
00181                break;
00182             }
00183 
00184             // allocate memory
00185             depth_obj.points = (float *) malloc(sizeof(float) * 4);
00186             if (!depth_obj.points) {
00187                // memory error
00188                if (!memerror) {
00189                   memerror = 1;
00190                   msgErr << "PSDisplayDevice: Out of memory. Some " <<
00191                      "objects were not drawn." << sendmsg;
00192                }
00193                break;
00194             }
00195 
00196             // copy data
00197             depth_obj.npoints = 2;
00198             depth_obj.color = colorIndex;
00199             (transMat.top()).multpoint3d(((DispCmdLine *) cmd_ptr)->pos1, a);
00200             (transMat.top()).multpoint3d(((DispCmdLine *) cmd_ptr)->pos2, b);
00201             memcpy(depth_obj.points, a, sizeof(float) * 2);
00202             memcpy(&depth_obj.points[2], b, sizeof(float) * 2);
00203 
00204             // compute the centerpoint of the object
00205             cent[0] = (a[0] + b[0]) / 2;
00206             cent[1] = (a[1] + b[1]) / 2;
00207             cent[2] = (a[2] + b[2]) / 2;
00208 
00209             // compute the distance to the eye
00210             depth_obj.dist = compute_dist(cent);
00211 
00212             // valid object to depth sort
00213             draw = 1;
00214             break;
00215 
00216          case DLINEARRAY:
00217            {
00218             // XXX much replicated code from DLINE
00219             float *v = (float *)cmd_ptr;
00220             int nlines = (int)v[0];
00221             v++;
00222             for (int i=0; i<nlines; i++) {
00223               // check for degenerate line
00224               if (!memcmp(v,v+3,3*sizeof(float)))
00225                 break;
00226 
00227               // allocate memory
00228               depth_obj.points = (float *) malloc(sizeof(float) * 4);
00229               if (!depth_obj.points) {
00230                  // memory error
00231                  if (!memerror) {
00232                     memerror = 1;
00233                     msgErr << "PSDisplayDevice: Out of memory. Some " <<
00234                        "objects were not drawn." << sendmsg;
00235                  }
00236                  break;
00237               }
00238 
00239               // copy data
00240               depth_obj.npoints = 2;
00241               depth_obj.color = colorIndex;
00242               (transMat.top()).multpoint3d(v, a);
00243               (transMat.top()).multpoint3d(v+3, b);
00244               memcpy(depth_obj.points, a, sizeof(float) * 2);
00245               memcpy(&depth_obj.points[2], b, sizeof(float) * 2);
00246   
00247               // compute the centerpoint of the object
00248               cent[0] = (a[0] + b[0]) / 2;
00249               cent[1] = (a[1] + b[1]) / 2;
00250               cent[2] = (a[2] + b[2]) / 2;
00251   
00252               // compute the distance to the eye
00253               depth_obj.dist = compute_dist(cent);
00254  
00255               // we'll add the object here, since we have multiple objects 
00256               draw = 0;
00257               memusage += sizeof(float) * 2 * depth_obj.npoints;
00258               points += depth_obj.npoints;
00259               objects++;
00260               depth_list.append(depth_obj);
00261 
00262               v += 6;
00263             } 
00264            }
00265            break;           
00266 
00267          case DPOLYLINEARRAY:
00268            {
00269             // XXX much replicated code from DLINE / DLINEARRAY
00270             float *v = (float *)cmd_ptr;
00271             int nverts = (int)v[0];
00272             v++;
00273             for (int i=0; i<nverts-1; i++) {
00274               // check for degenerate line
00275               if (!memcmp(v,v+3,3*sizeof(float)))
00276                 break;
00277 
00278               // allocate memory
00279               depth_obj.points = (float *) malloc(sizeof(float) * 4);
00280               if (!depth_obj.points) {
00281                  // memory error
00282                  if (!memerror) {
00283                     memerror = 1;
00284                     msgErr << "PSDisplayDevice: Out of memory. Some " <<
00285                        "objects were not drawn." << sendmsg;
00286                  }
00287                  break;
00288               }
00289 
00290               // copy data
00291               depth_obj.npoints = 2;
00292               depth_obj.color = colorIndex;
00293               (transMat.top()).multpoint3d(v, a);
00294               (transMat.top()).multpoint3d(v+3, b);
00295               memcpy(depth_obj.points, a, sizeof(float) * 2);
00296               memcpy(&depth_obj.points[2], b, sizeof(float) * 2);
00297   
00298               // compute the centerpoint of the object
00299               cent[0] = (a[0] + b[0]) / 2;
00300               cent[1] = (a[1] + b[1]) / 2;
00301               cent[2] = (a[2] + b[2]) / 2;
00302   
00303               // compute the distance to the eye
00304               depth_obj.dist = compute_dist(cent);
00305  
00306               // we'll add the object here, since we have multiple objects 
00307               draw = 0;
00308               memusage += sizeof(float) * 2 * depth_obj.npoints;
00309               points += depth_obj.npoints;
00310               objects++;
00311               depth_list.append(depth_obj);
00312 
00313               v += 3;
00314             } 
00315            }
00316            break;           
00317  
00318          case DCYLINDER:
00319          {
00320             int res;
00321 
00322             (transMat.top()).multpoint3d((float *) cmd_ptr, a);
00323             (transMat.top()).multpoint3d(&((float *) cmd_ptr)[3], b);
00324             r = scale_radius(((float *) cmd_ptr)[6]);
00325             res = (int) ((float *) cmd_ptr)[7];
00326 
00327             cylinder_approx(a, b, r, res, (int) ((float *) cmd_ptr)[8]);
00328             break;
00329          }
00330 
00331          case DCONE:
00332          {
00333             (transMat.top()).multpoint3d(((DispCmdCone *) cmd_ptr)->pos1, a);
00334             (transMat.top()).multpoint3d(((DispCmdCone *) cmd_ptr)->pos2, b);
00335             float r1 = scale_radius(((DispCmdCone *) cmd_ptr)->radius);
00336             float r2 = scale_radius(((DispCmdCone *) cmd_ptr)->radius2);
00337 
00338             // XXX current implementation can't draw truncated cones.
00339             if (r2 > 0.0f) {
00340               msgWarn << "PSDisplayDevice) can't draw truncated cones" 
00341                       << sendmsg;
00342             }
00343             cone_approx(a, b, r1);
00344             break;
00345          }
00346 
00347         case DTEXT:
00348         {
00349             float* pos = (float *)cmd_ptr;
00350             float textsize = pos[4];
00351 #if 0
00352             // thickness not implemented yet
00353             float thickness = pos[3];    // thickness is stored in 4th slot
00354 #endif
00355             char* txt = (char *)(pos+7);
00356             int   txtlen = strlen(txt);
00357             // allocate memory
00358             depth_obj.points = (float *) malloc(sizeof(float) * 2);
00359             depth_obj.text   = (char  *) malloc(sizeof(char) * (txtlen+1));
00360             if ( !(depth_obj.points || depth_obj.text) ) {
00361               // memory error
00362               if (!memerror) {
00363                  memerror = 1;
00364                  msgErr << "PSDisplayDevice: Out of memory. Some " <<
00365                     "objects were not drawn." << sendmsg;
00366               }
00367               break;
00368            }
00369 
00370             // copy data
00371             depth_obj.npoints = 1;
00372             depth_obj.color = colorIndex;
00373             (transMat.top()).multpoint3d(((DispCmdPoint *) cmd_ptr)->pos, a);
00374             memcpy(depth_obj.points, a, sizeof(float) * 2);
00375             strcpy(depth_obj.text , txt);
00376 
00377             // note scale factor, stored into "light_scale", so we didn't
00378             // have to add a new structure member just for this.
00379             depth_obj.light_scale = textsize * 15;
00380 
00381             // compute the distance to the eye
00382             depth_obj.dist = compute_dist(a);
00383 
00384             // valid object to depth sort
00385             draw = 1;
00386             break;
00387          }
00388 
00389          case DTRIANGLE:
00390             // check for degenerate triangle
00391             if (!memcmp(((DispCmdTriangle *) cmd_ptr)->pos1,
00392                         ((DispCmdTriangle *) cmd_ptr)->pos2,
00393                         sizeof(float) * 3) ||
00394                 !memcmp(((DispCmdTriangle *) cmd_ptr)->pos2,
00395                         ((DispCmdTriangle *) cmd_ptr)->pos3,
00396                         sizeof(float) * 3) ||
00397                 !memcmp(((DispCmdTriangle *) cmd_ptr)->pos2,
00398                         ((DispCmdTriangle *) cmd_ptr)->pos3,
00399                         sizeof(float) * 3)) {
00400                // degenerate triangle
00401                break;
00402             }
00403 
00404             // allocate memory
00405             depth_obj.points = (float *) malloc(sizeof(float) * 6);
00406             if (!depth_obj.points) {
00407                // memory error
00408                if (!memerror) {
00409                   memerror = 1;
00410                   msgErr << "PSDisplayDevice: Out of memory. Some " <<
00411                      "objects were not drawn." << sendmsg;
00412                }
00413                break;
00414             }
00415 
00416             // copy data
00417             depth_obj.npoints = 3;
00418             depth_obj.color = (nc >= 0) ? nc : colorIndex;
00419             (transMat.top()).multpoint3d(((DispCmdTriangle *) cmd_ptr)->pos1, a);
00420             (transMat.top()).multpoint3d(((DispCmdTriangle *) cmd_ptr)->pos2, b);
00421             (transMat.top()).multpoint3d(((DispCmdTriangle *) cmd_ptr)->pos3, c);
00422             memcpy(depth_obj.points, a, sizeof(float) * 2);
00423             memcpy(&depth_obj.points[2], b, sizeof(float) * 2);
00424             memcpy(&depth_obj.points[4], c, sizeof(float) * 2);
00425 
00426             // compute the centerpoint of the object
00427             cent[0] = (a[0] + b[0] + c[0]) / 3;
00428             cent[1] = (a[1] + b[1] + c[1]) / 3;
00429             cent[2] = (a[2] + b[2] + c[2]) / 3;
00430 
00431             // compute the distance to the eye for depth sorting
00432             depth_obj.dist = compute_dist(cent);
00433 
00434             // compute a light shading factor
00435             depth_obj.light_scale = compute_light(a, b, c);
00436 
00437             // valid object to depth sort
00438             draw = 1;
00439             break;
00440 
00441          case DTRIMESH_C4F_N3F_V3F:
00442             // call a separate routine to break up the mesh into
00443             // its component triangles
00444             decompose_mesh((DispCmdTriMesh *) cmd_ptr);
00445             break;
00446 
00447          case DTRISTRIP:
00448             // call a separate routine to break up the strip into
00449             // its component triangles
00450             decompose_tristrip((DispCmdTriStrips *) cmd_ptr);
00451             break;
00452 
00453          case DSQUARE:
00454             // check for degenerate quadrilateral
00455             if (!memcmp(((DispCmdSquare *) cmd_ptr)->pos1,
00456                         ((DispCmdSquare *) cmd_ptr)->pos2,
00457                         sizeof(float) * 3) ||
00458                 !memcmp(((DispCmdSquare *) cmd_ptr)->pos1,
00459                         ((DispCmdSquare *) cmd_ptr)->pos3,
00460                         sizeof(float) * 3) ||
00461                 !memcmp(((DispCmdSquare *) cmd_ptr)->pos1,
00462                         ((DispCmdSquare *) cmd_ptr)->pos4,
00463                         sizeof(float) * 3) ||
00464                 !memcmp(((DispCmdSquare *) cmd_ptr)->pos2,
00465                         ((DispCmdSquare *) cmd_ptr)->pos3,
00466                         sizeof(float) * 3) ||
00467                 !memcmp(((DispCmdSquare *) cmd_ptr)->pos2,
00468                         ((DispCmdSquare *) cmd_ptr)->pos4,
00469                         sizeof(float) * 3) ||
00470                 !memcmp(((DispCmdSquare *) cmd_ptr)->pos3,
00471                         ((DispCmdSquare *) cmd_ptr)->pos4,
00472                         sizeof(float) * 3)) {
00473                // degenerate quadrilateral
00474                break;
00475             }
00476 
00477             // allocate memory
00478             depth_obj.points = (float *) malloc(sizeof(float) * 8);
00479             if (!depth_obj.points) {
00480                // memory error
00481                if (!memerror) {
00482                   memerror = 1;
00483                   msgErr << "PSDisplayDevice: Out of memory. Some " <<
00484                      "objects were not drawn." << sendmsg;
00485                }
00486                break;
00487             }
00488 
00489             // copy data
00490             depth_obj.npoints = 4;
00491             depth_obj.color = colorIndex;
00492             (transMat.top()).multpoint3d(((DispCmdSquare *) cmd_ptr)->pos1, a);
00493             (transMat.top()).multpoint3d(((DispCmdSquare *) cmd_ptr)->pos2, b);
00494             (transMat.top()).multpoint3d(((DispCmdSquare *) cmd_ptr)->pos3, c);
00495             (transMat.top()).multpoint3d(((DispCmdSquare *) cmd_ptr)->pos4, d);
00496             memcpy(depth_obj.points, a, sizeof(float) * 2);
00497             memcpy(&depth_obj.points[2], b, sizeof(float) * 2);
00498             memcpy(&depth_obj.points[4], c, sizeof(float) * 2);
00499             memcpy(&depth_obj.points[6], d, sizeof(float) * 2);
00500 
00501             // compute the centerpoint of the object
00502             cent[0] = (a[0] + b[0] + c[0] + d[0]) / 4;
00503             cent[1] = (a[1] + b[1] + c[1] + d[1]) / 4;
00504             cent[2] = (a[2] + b[2] + c[2] + d[2]) / 4;
00505 
00506             // compute the distance to the eye for depth sorting
00507             depth_obj.dist = compute_dist(cent);
00508 
00509             // compute a light shading factor
00510             depth_obj.light_scale = compute_light(a, b, c);
00511 
00512             // valid object to depth sort
00513             draw = 1;
00514             break;
00515 
00516          case DCOLORINDEX:
00517             colorIndex = ((DispCmdColorIndex *) cmd_ptr)->color;
00518             break;
00519 
00520          case DSPHERERES:
00521             set_sphere_res(((int *) cmd_ptr)[0]);
00522             break;
00523 
00524          default:
00525             // unknown object, so just skip it
00526             break;
00527       }
00528 
00529       // if we have a valid object to add to the depth sort list
00530       if (draw && depth_obj.npoints) {
00531          memusage += sizeof(float) * 2 * depth_obj.npoints;
00532          if ( depth_obj.text )
00533            memusage += sizeof(char) * (1+strlen(depth_obj.text));
00534          points += depth_obj.npoints;
00535          objects++;
00536          depth_list.append(depth_obj);
00537       }
00538 
00539       depth_obj.npoints = 0;
00540       depth_obj.points = NULL;
00541 
00542    } // while (tok != DLASTCOMMAND)
00543 
00544      transMat.pop();
00545    } // end for() [instance images]
00546 
00547      transMat.pop();
00548    } // end for() [periodic images]
00549 }
00550 
00551 
00552 // This is called after all molecules to be displayed have been rendered.
00553 // We need to depth sort our list and then render each one at a time,
00554 // we also need to first define all the PostScript functions to handle
00555 // triangles and quadrilaterals
00556 void PSDisplayDevice::render_done() {
00557    x_scale = 1.33f * 792 / Aspect / vSize;
00558    y_scale = x_scale;
00559 
00560    msgInfo << "PSDisplayDevice: peak memory totals: " << sendmsg;
00561    msgInfo << "    total dynamic memory used: " <<
00562       (long) (memusage + sizeof(DepthSortObject) * objects) << sendmsg;
00563    msgInfo << "    total dynamic points: " << points << sendmsg;
00564    msgInfo << "    total depthsorted object: " << objects << sendmsg;
00565 
00566    if (depth_list.num()) {
00567       depth_list.qsort(0, depth_list.num() - 1);
00568       process_depth_list();
00569    }
00570 }
00571 
00572 
00573 void PSDisplayDevice::process_depth_list(void) {
00574    DepthSortObject obj;
00575    int i, nobjs;
00576 
00577    nobjs = depth_list.num();
00578    float textsize = -20;
00579    for (i = 0; i < nobjs; i++) {
00580       obj = depth_list.item(i);
00581 
00582       if (obj.text) {
00583         // check to see if we have to output a new scaling factor
00584         // in the generated postscript file, only output if it has
00585         // changed.
00586         if (obj.light_scale != textsize) {
00587           textsize = obj.light_scale;
00588           fprintf(outfile, "%f ts\n", textsize);
00589         }
00590         fprintf(outfile, "%d 1 c (%s) %d %d text\n",
00591                 obj.color,
00592                 obj.text,
00593                 (int) (obj.points[0] * x_scale + x_offset),
00594                 (int) (obj.points[1] * y_scale + y_offset));
00595       } else {
00596         switch (obj.npoints) {
00597           case 1: // point
00598             fprintf(outfile, "%d 1 c %d %d p\n",
00599                     obj.color,
00600                     (int) (obj.points[0] * x_scale + x_offset),
00601                     (int) (obj.points[1] * y_scale + y_offset));
00602             break;
00603             
00604           case 2: // line
00605             fprintf(outfile, "%d 1 c %d %d %d %d l\n",
00606                     obj.color,
00607                     (int) (obj.points[0] * x_scale + x_offset),
00608                     (int) (obj.points[1] * y_scale + y_offset),
00609                     (int) (obj.points[2] * x_scale + x_offset),
00610                     (int) (obj.points[3] * y_scale + y_offset));
00611             break;
00612             
00613           case 3: // triangle
00614             fprintf(outfile, "%d %.2f c %d %d %d %d %d %d t\n",
00615                     obj.color, obj.light_scale,
00616                     (int) (obj.points[0] * x_scale + x_offset),
00617                     (int) (obj.points[1] * y_scale + y_offset),
00618                     (int) (obj.points[2] * x_scale + x_offset),
00619                     (int) (obj.points[3] * y_scale + y_offset),
00620                     (int) (obj.points[4] * x_scale + x_offset),
00621                     (int) (obj.points[5] * y_scale + y_offset));
00622             break;
00623             
00624          case 4: // quadrilateral
00625            fprintf(outfile, "%d %.2f c %d %d %d %d %d %d %d %d s\n",
00626                    obj.color, obj.light_scale,
00627                    (int) (obj.points[0] * x_scale + x_offset),
00628                    (int) (obj.points[1] * y_scale + y_offset),
00629                    (int) (obj.points[2] * x_scale + x_offset),
00630                    (int) (obj.points[3] * y_scale + y_offset),
00631                    (int) (obj.points[4] * x_scale + x_offset),
00632                    (int) (obj.points[5] * y_scale + y_offset),
00633                    (int) (obj.points[6] * x_scale + x_offset),
00634                    (int) (obj.points[7] * y_scale + y_offset));
00635            break;
00636         }
00637       }
00638 
00639       // free up the memory we've used
00640       memusage -= sizeof(float) * 2 * obj.npoints;
00641       if (obj.npoints) free(obj.points);
00642       if (obj.text) {
00643         memusage -= sizeof(char) * (1+strlen(obj.text));
00644         free(obj.text);
00645       }
00646    }
00647 
00648    // put the finishing touches on the Postscript output...
00649    fprintf(outfile, "showpage\n");
00650    close_file();
00651 
00652    // finally, clear the depth sorted list
00653    depth_list.remove(-1, -1);
00654 
00655    msgInfo << "PSDisplayDevice: end memory summary:" << sendmsg;
00656    msgInfo << "    total dynamic memory used: " << memusage << sendmsg;
00657    msgInfo << "    total dynamic points: " << points << sendmsg;
00658    msgInfo << "    total depthsorted object: " << objects << sendmsg;
00659 
00660    // reset the memory totals
00661    memusage = 0;
00662    objects = 0;
00663    points = 0;
00664 
00665    // and hooray, we're done!
00666 }
00667 
00668 
00669 void PSDisplayDevice::set_sphere_res(int res)
00670 {
00671     // the sphere resolution has changed. if sphereRes is less than 32, we
00672     // will use a lookup table to achieve equal or better resolution than
00673     // OpenGL. otherwise we use the following equation:
00674     //    iterations = .9 *
00675     //    (sphereRes)^(1/2)
00676 
00677     // this is used as a lookup table to determine the proper
00678     // number of iterations used in the sphere approximation
00679     // algorithm.
00680     const int sph_iter_table[] = {
00681         0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3,
00682         3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4 };
00683 
00684     if (res < 0) return;
00685     else if (res < 32) sph_desired_iter = sph_iter_table[res];
00686     else sph_desired_iter = (int) (0.8f * sqrtf((float) res));
00687 }
00688 
00689 
00690 void PSDisplayDevice::sphere_approx(float *c, float r) {
00691    DepthSortObject depth_obj;
00692    float x[3], y[3], z[3];
00693    float cent[3];
00694    int pi, ni;
00695    int i;
00696 
00697    // first we need to determine if a recalculation of the cached
00698    // unit sphere is necessary. this is necessary if the number
00699    // of desired iterations has changed.
00700    if (!sph_verts || !sph_nverts || sph_iter != sph_desired_iter) {
00701       float a[3], b[3], c[3];
00702       float *newverts;
00703       float *oldverts;
00704       int nverts, ntris;
00705       int level;
00706 
00707       // remove old cached copy
00708       if (sph_verts && sph_nverts) free(sph_verts);
00709 
00710       // XXX TODO it should be possible here to use the old
00711       // sphere as an aid in calculating the new sphere. in
00712       // this manner we can save calculations during resolution
00713       // changes.
00714 
00715       newverts = (float *) malloc(sizeof(float) * 36);
00716       nverts = 12;
00717       ntris = 4;
00718 
00719       // start with half of a unit octahedron (front, convex half)
00720 
00721       // top left triangle
00722       newverts[0] = -1;    newverts[1] = 0;     newverts[2] = 0;
00723       newverts[3] = 0;     newverts[4] = 1;     newverts[5] = 0;
00724       newverts[6] = 0;     newverts[7] = 0;     newverts[8] = 1;
00725 
00726       // top right triangle
00727       newverts[9] = 0;     newverts[10] = 0;    newverts[11] = 1;
00728       newverts[12] = 0;    newverts[13] = 1;    newverts[14] = 0;
00729       newverts[15] = 1;    newverts[16] = 0;    newverts[17] = 0;
00730 
00731       // bottom right triangle
00732       newverts[18] = 0;    newverts[19] = 0;    newverts[20] = 1;
00733       newverts[21] = 1;    newverts[22] = 0;    newverts[23] = 0;
00734       newverts[24] = 0;    newverts[25] = -1;   newverts[26] = 0;
00735 
00736       // bottom left triangle
00737       newverts[27] = 0;    newverts[28] = 0;    newverts[29] = 1;
00738       newverts[30] = 0;    newverts[31] = -1;   newverts[32] = 0;
00739       newverts[33] = -1;   newverts[34] = 0;    newverts[35] = 0;
00740 
00741       for (level = 1; level < sph_desired_iter; level++) {
00742          oldverts = newverts;
00743 
00744          // allocate memory for the next iteration: we will need
00745          // four times the current number of vertices
00746          newverts = (float *) malloc(sizeof(float) * 12 * nverts);
00747          if (!newverts) {
00748             // memory error
00749             sph_iter = -1;
00750             sph_nverts = 0;
00751             sph_verts = NULL;
00752             free(oldverts);
00753 
00754             if (!memerror) {
00755                memerror = 1;
00756                msgErr << "PSDisplayDevice: Out of memory. Some " 
00757                       << "objects were not drawn." << sendmsg;
00758             }
00759 
00760             return;
00761          }
00762 
00763          pi = 0;
00764          ni = 0;
00765          for (i = 0; i < ntris; i++) {
00766             // compute intermediate vertices
00767             a[0] = (oldverts[pi    ] + oldverts[pi + 6]) / 2;
00768             a[1] = (oldverts[pi + 1] + oldverts[pi + 7]) / 2;
00769             a[2] = (oldverts[pi + 2] + oldverts[pi + 8]) / 2;
00770             vec_normalize(a);
00771             b[0] = (oldverts[pi    ] + oldverts[pi + 3]) / 2;
00772             b[1] = (oldverts[pi + 1] + oldverts[pi + 4]) / 2;
00773             b[2] = (oldverts[pi + 2] + oldverts[pi + 5]) / 2;
00774             vec_normalize(b);
00775             c[0] = (oldverts[pi + 3] + oldverts[pi + 6]) / 2;
00776             c[1] = (oldverts[pi + 4] + oldverts[pi + 7]) / 2;
00777             c[2] = (oldverts[pi + 5] + oldverts[pi + 8]) / 2;
00778             vec_normalize(c);
00779 
00780             // build triangles
00781             memcpy(&newverts[ni     ], &oldverts[pi], sizeof(float) * 3);
00782             memcpy(&newverts[ni + 3 ], b, sizeof(float) * 3);
00783             memcpy(&newverts[ni + 6 ], a, sizeof(float) * 3);
00784 
00785             memcpy(&newverts[ni + 9 ], b, sizeof(float) * 3);
00786             memcpy(&newverts[ni + 12], &oldverts[pi + 3], sizeof(float) * 3);
00787             memcpy(&newverts[ni + 15], c, sizeof(float) * 3);
00788 
00789             memcpy(&newverts[ni + 18], a, sizeof(float) * 3);
00790             memcpy(&newverts[ni + 21], b, sizeof(float) * 3);
00791             memcpy(&newverts[ni + 24], c, sizeof(float) * 3);
00792 
00793             memcpy(&newverts[ni + 27], a, sizeof(float) * 3);
00794             memcpy(&newverts[ni + 30], c, sizeof(float) * 3);
00795             memcpy(&newverts[ni + 33], &oldverts[pi + 6], sizeof(float) * 3);
00796 
00797             pi += 9;
00798             ni += 36;
00799          }
00800 
00801          free(oldverts);
00802 
00803          nverts *= 4;
00804          ntris *= 4;
00805       }
00806 
00807       sph_iter = sph_desired_iter;
00808       sph_nverts = nverts;
00809       sph_verts = newverts;
00810    }
00811 
00812    // now we're guaranteed to have a valid cached unit sphere, so
00813    // all we need to do is translate each coordinate based on the
00814    // desired position and radius, and add the triangles to the
00815    // depth sort list.
00816 #if 0
00817    if (!points) {
00818       // memory error
00819       if (!memerror) {
00820          memerror = 1;
00821          msgErr << "PSDisplayDevice: Out of memory. Some " <<
00822             "objects were not drawn." << sendmsg;
00823       }
00824       return;
00825    }
00826 #endif
00827 
00828    // perform the desired translations and scalings on each
00829    // vertex, then add each triangle to the depth sort list
00830    depth_obj.npoints = 3;
00831    depth_obj.color = colorIndex;
00832 
00833    pi = 0;
00834    for (i = 0; i < sph_nverts / 3; i++) {
00835       // allocate memory for the triangle
00836       depth_obj.points = (float *) malloc(sizeof(float) * 6);
00837       if (!depth_obj.points) {
00838          // memory error
00839          if (!memerror) {
00840             memerror = 1;
00841             msgErr << "PSDisplayDevice: Out of memory. Some " 
00842                    << "objects were not drawn." << sendmsg;
00843          }
00844          return;
00845       }
00846 
00847       // translations and scalings
00848       x[0] = r * sph_verts[pi] + c[0];
00849       x[1] = r * sph_verts[pi + 1] + c[1];
00850       x[2] = r * sph_verts[pi + 2] + c[2];
00851       y[0] = r * sph_verts[pi + 3] + c[0];
00852       y[1] = r * sph_verts[pi + 4] + c[1];
00853       y[2] = r * sph_verts[pi + 5] + c[2];
00854       z[0] = r * sph_verts[pi + 6] + c[0];
00855       z[1] = r * sph_verts[pi + 7] + c[1];
00856       z[2] = r * sph_verts[pi + 8] + c[2];
00857 
00858       memcpy(depth_obj.points, x, sizeof(float) * 2);
00859       memcpy(&depth_obj.points[2], y, sizeof(float) * 2);
00860       memcpy(&depth_obj.points[4], z, sizeof(float) * 2);
00861 
00862       // now need to compute centerpoint and distance to eye
00863       cent[0] = (x[0] + y[0] + z[0]) / 3;
00864       cent[1] = (x[1] + y[1] + z[1]) / 3;
00865       cent[2] = (x[2] + y[2] + z[2]) / 3;
00866       depth_obj.dist = compute_dist(cent);
00867       depth_obj.light_scale = compute_light(x, y, z);
00868 
00869       // and add to the depth sort list
00870       memusage += sizeof(float) * 2 * depth_obj.npoints;
00871       points += depth_obj.npoints;
00872       objects++;
00873       depth_list.append(depth_obj);
00874 
00875       pi += 9;
00876    }
00877 }
00878 
00879 
00880 void PSDisplayDevice::cylinder_approx(float *a, float *b, float r, int res, 
00881                                       int filled) {
00882 
00883    float axis[3];
00884    float perp1[3], perp2[3];
00885    float pt1[3], pt2[3];
00886    float cent[3];
00887    float theta, theta_inc;
00888    float my_sin, my_cos;
00889    float w[3], x[3], y[3], z[3];
00890    int n;
00891 
00892    DepthSortObject cyl_body, cyl_trailcap, cyl_leadcap;
00893 
00894    // check against degenerate cylinder
00895    if (a[0] == b[0] && a[1] == b[1] && a[2] == b[2]) return;
00896    if (r <= 0) return;
00897 
00898    // first we compute the axis of the cylinder
00899    axis[0] = b[0] - a[0];
00900    axis[1] = b[1] - a[1];
00901    axis[2] = b[2] - a[2];
00902    vec_normalize(axis);
00903 
00904    // now we compute some arbitrary perpendicular to that axis
00905    if ((ABS(axis[0]) < ABS(axis[1])) &&
00906        (ABS(axis[0]) < ABS(axis[2]))) {
00907       perp1[0] = 0;
00908       perp1[1] = axis[2];
00909       perp1[2] = -axis[1];
00910    }
00911    else if ((ABS(axis[1]) < ABS(axis[2]))) {
00912       perp1[0] = -axis[2];
00913       perp1[1] = 0;
00914       perp1[2] = axis[0];
00915    }
00916    else {
00917       perp1[0] = axis[1];
00918       perp1[1] = -axis[0];
00919       perp1[2] = 0;
00920    }
00921    vec_normalize(perp1);
00922 
00923    // now we compute another vector perpendicular both to the
00924    // cylinder's axis and to the perpendicular we just found.
00925    cross_prod(perp2, axis, perp1);
00926 
00927    // initialize some stuff in the depth sort objects
00928    cyl_body.npoints = 4;
00929    cyl_body.color = colorIndex;
00930 
00931    if (filled & CYLINDER_TRAILINGCAP) {
00932       cyl_trailcap.npoints = 3;
00933       cyl_trailcap.color = colorIndex;
00934    }
00935 
00936    if (filled & CYLINDER_LEADINGCAP) {
00937       cyl_leadcap.npoints = 3;
00938       cyl_leadcap.color = colorIndex;
00939    }
00940 
00941    // we will start out with the point defined by perp2
00942    pt1[0] = r * perp2[0];
00943    pt1[1] = r * perp2[1];
00944    pt1[2] = r * perp2[2];
00945    theta = 0;
00946    theta_inc = (float) (VMD_TWOPI / res);
00947    for (n = 1; n <= res; n++) {
00948       // save the last point
00949       memcpy(pt2, pt1, sizeof(float) * 3);
00950 
00951       // increment the angle and compute new points
00952       theta += theta_inc;
00953       sincosf(theta, &my_sin, &my_cos);
00954 
00955       // compute the new points
00956       pt1[0] = r * (perp2[0] * my_cos + perp1[0] * my_sin);
00957       pt1[1] = r * (perp2[1] * my_cos + perp1[1] * my_sin);
00958       pt1[2] = r * (perp2[2] * my_cos + perp1[2] * my_sin);
00959 
00960       cyl_body.points = (float *) malloc(sizeof(float) * 8);
00961       cyl_trailcap.points = (float *) malloc(sizeof(float) * 6);
00962       cyl_leadcap.points = (float *) malloc(sizeof(float) * 6);
00963       if (!(cyl_body.points && cyl_trailcap.points && cyl_leadcap.points)) {
00964          // memory error
00965          if (!memerror) {
00966             memerror = 1;
00967             msgErr << "PSDisplayDevice: Out of memory. Some " <<
00968                "objects were not drawn." << sendmsg;
00969          }
00970          continue;
00971       }
00972 
00973       // we have to translate them back to their original point...
00974       w[0] = pt1[0] + a[0];
00975       w[1] = pt1[1] + a[1];
00976       w[2] = pt1[2] + a[2];
00977       x[0] = pt2[0] + a[0];
00978       x[1] = pt2[1] + a[1];
00979       x[2] = pt2[2] + a[2];
00980       y[0] = pt2[0] + b[0];
00981       y[1] = pt2[1] + b[1];
00982       y[2] = pt2[2] + b[2];
00983       z[0] = pt1[0] + b[0];
00984       z[1] = pt1[1] + b[1];
00985       z[2] = pt1[2] + b[2];
00986 
00987       memcpy(cyl_body.points, w, sizeof(float) * 2);
00988       memcpy(&cyl_body.points[2], x, sizeof(float) * 2);
00989       memcpy(&cyl_body.points[4], y, sizeof(float) * 2);
00990       memcpy(&cyl_body.points[6], z, sizeof(float) * 2);
00991 
00992       // finally, we have to compute the centerpoint of this cylinder...
00993       // we can make a slight optimization here since we know the
00994       // cylinder will be a parellelogram. we only need to average
00995       // 2 corner points to find the center.
00996       cent[0] = (w[0] + y[0]) / 2;
00997       cent[1] = (w[1] + y[1]) / 2;
00998       cent[2] = (w[2] + y[2]) / 2;
00999       cyl_body.dist = compute_dist(cent);
01000 
01001       // and finally the light scale
01002       cyl_body.light_scale = compute_light(w, x, y);
01003 
01004       // go ahead and add this to our depth-sort list
01005       memusage += sizeof(float) * 2 * cyl_body.npoints;
01006       points += cyl_body.npoints;
01007       objects++;
01008       depth_list.append(cyl_body);
01009 
01010       // Now do the same thing for the trailing end cap...
01011       if (filled & CYLINDER_TRAILINGCAP) {
01012         memcpy(&cyl_trailcap.points[0], x, sizeof(float) * 2);
01013         memcpy(&cyl_trailcap.points[2], w, sizeof(float) * 2);
01014         memcpy(&cyl_trailcap.points[4], a, sizeof(float) * 2);
01015       
01016         // finally, we have to compute the centerpoint of the triangle
01017         cent[0] = (x[0] + w[0] + a[0]) / 3;
01018         cent[1] = (x[1] + w[1] + a[1]) / 3;
01019         cent[2] = (x[2] + w[2] + a[2]) / 3;
01020         cyl_trailcap.dist = compute_dist(cent);
01021 
01022         // and finally the light scale
01023         cyl_trailcap.light_scale = compute_light(x, w, a);
01024 
01025         memusage += sizeof(float) * 2 * cyl_trailcap.npoints;
01026         points += cyl_trailcap.npoints;
01027         objects++;
01028         depth_list.append(cyl_trailcap);
01029       }
01030 
01031       // ...and the leading end cap.
01032       if (filled & CYLINDER_LEADINGCAP) {
01033         memcpy(cyl_leadcap.points, z, sizeof(float) * 2);
01034         memcpy(&cyl_leadcap.points[2], y, sizeof(float) * 2);
01035         memcpy(&cyl_leadcap.points[4], b, sizeof(float) * 2);
01036 
01037         // finally, we have to compute the centerpoint of the triangle
01038         cent[0] = (z[0] + y[0] + b[0]) / 3;
01039         cent[1] = (z[1] + y[1] + b[1]) / 3;
01040         cent[2] = (z[2] + y[2] + b[2]) / 3;
01041         cyl_leadcap.dist = compute_dist(cent);
01042 
01043         // and finally the light scale
01044         cyl_leadcap.light_scale = compute_light(z, y, b);
01045 
01046         memusage += sizeof(float) * 2 * cyl_leadcap.npoints;
01047         points += cyl_leadcap.npoints;
01048         objects++;
01049         depth_list.append(cyl_leadcap);
01050       }
01051    }
01052 }
01053 
01054 
01055 void PSDisplayDevice::cone_approx(float *a, float *b, float r) {
01056    // XXX add ability to change number of triangles
01057    const int tris = 20;
01058 
01059    float axis[3];
01060    float perp1[3], perp2[3];
01061    float pt1[3], pt2[3];
01062    float cent[3];
01063    float x[3], y[3], z[3];
01064    float theta, theta_inc;
01065    float my_sin, my_cos;
01066    int n;
01067 
01068    DepthSortObject depth_obj;
01069 
01070    // check against degenerate cone
01071    if (a[0] == b[0] && a[1] == b[1] && a[2] == b[2]) return;
01072    if (r <= 0) return;
01073 
01074    // first we compute the axis of the cone
01075    axis[0] = b[0] - a[0];
01076    axis[1] = b[1] - a[1];
01077    axis[2] = b[2] - a[2];
01078    vec_normalize(axis);
01079 
01080    // now we compute some arbitrary perpendicular to that axis
01081    if ((ABS(axis[0]) < ABS(axis[1])) &&
01082        (ABS(axis[0]) < ABS(axis[2]))) {
01083       perp1[0] = 0;
01084       perp1[1] = axis[2];
01085       perp1[2] = -axis[1];
01086    }
01087    else if ((ABS(axis[1]) < ABS(axis[2]))) {
01088       perp1[0] = -axis[2];
01089       perp1[1] = 0;
01090       perp1[2] = axis[0];
01091    }
01092    else {
01093       perp1[0] = axis[1];
01094       perp1[1] = -axis[0];
01095       perp1[2] = 0;
01096    }
01097    vec_normalize(perp1);
01098 
01099    // now we compute another vector perpendicular both to the
01100    // cone's axis and to the perpendicular we just found.
01101    cross_prod(perp2, axis, perp1);
01102 
01103    // initialize some stuff in the depth sort object
01104    depth_obj.npoints = 3;
01105    depth_obj.color = colorIndex;
01106 
01107    // we will start out with the point defined by perp2
01108    pt1[0] = r * perp2[0];
01109    pt1[1] = r * perp2[1];
01110    pt1[2] = r * perp2[2];
01111    theta = 0;
01112    theta_inc = (float) (VMD_TWOPI / tris);
01113    for (n = 1; n <= tris; n++) {
01114       // save the last point
01115       memcpy(pt2, pt1, sizeof(float) * 3);
01116 
01117       // increment the angle and compute new points
01118       theta += theta_inc;
01119       sincosf(theta, &my_sin, &my_cos);
01120 
01121       // compute the new points
01122       pt1[0] = r * (perp2[0] * my_cos + perp1[0] * my_sin);
01123       pt1[1] = r * (perp2[1] * my_cos + perp1[1] * my_sin);
01124       pt1[2] = r * (perp2[2] * my_cos + perp1[2] * my_sin);
01125 
01126       depth_obj.points = (float *) malloc(sizeof(float) * 6);
01127       if (!depth_obj.points) {
01128          // memory error
01129          if (!memerror) {
01130             memerror = 1;
01131             msgErr << "PSDisplayDevice: Out of memory. Some " <<
01132                "objects were not drawn." << sendmsg;
01133          }
01134          continue;
01135       }
01136 
01137       // we have to translate them back to their original point...
01138       x[0] = pt1[0] + a[0];
01139       x[1] = pt1[1] + a[1];
01140       x[2] = pt1[2] + a[2];
01141       y[0] = pt2[0] + a[0];
01142       y[1] = pt2[1] + a[1];
01143       y[2] = pt2[2] + a[2];
01144 
01145       // now we use the apex of the cone as the third point
01146       z[0] = b[0];
01147       z[1] = b[1];
01148       z[2] = b[2];
01149 
01150       memcpy(depth_obj.points, x, sizeof(float) * 2);
01151       memcpy(&depth_obj.points[2], y, sizeof(float) * 2);
01152       memcpy(&depth_obj.points[4], z, sizeof(float) * 2);
01153 
01154       // finally, we have to compute the centerpoint of this
01155       // triangle...
01156       cent[0] = (x[0] + y[0] + z[0]) / 3;
01157       cent[1] = (x[1] + y[1] + z[1]) / 3;
01158       cent[2] = (x[2] + y[2] + z[2]) / 3;
01159       depth_obj.dist = compute_dist(cent);
01160 
01161       // and the light shading factor
01162       depth_obj.light_scale = compute_light(x, y, z);
01163 
01164       // go ahead and add this to our depth-sort list
01165       memusage += sizeof(float) * 2 * depth_obj.npoints;
01166       points += depth_obj.npoints;
01167       objects++;
01168       depth_list.append(depth_obj);
01169    }
01170 }
01171 
01172 
01173 void PSDisplayDevice::decompose_mesh(DispCmdTriMesh *mesh) {
01174    int i;
01175    int fi;
01176    int f1, f2, f3;
01177    float r, g, b;
01178    float x[3], y[3], z[3], cent[3];
01179    float *cnv;
01180    int *f;
01181    mesh->getpointers(cnv, f);
01182    DepthSortObject depth_obj;
01183 
01184    depth_obj.npoints = 3;
01185 
01186    fi = -3;
01187    for (i = 0; i < mesh->numfacets; i++) {
01188       fi += 3;
01189       f1 = f[fi    ] * 10;
01190       f2 = f[fi + 1] * 10;
01191       f3 = f[fi + 2] * 10;
01192 
01193       // allocate memory for the points
01194       depth_obj.points = (float *) malloc(6 * sizeof(float));
01195       if (!depth_obj.points) {
01196          if (!memerror) {
01197             memerror = 1;
01198             msgErr << "PSDisplayDevice: Out of memory. Some " <<
01199                "objects were not drawn." << sendmsg;
01200          }
01201          continue;
01202       }
01203 
01204       // average the three colors and use that average as the color for
01205       // this triangle
01206       r = (cnv[f1] + cnv[f2] + cnv[f3]) / 3;
01207       g = (cnv[f1 + 1] + cnv[f2 + 1] + cnv[f3 + 1]) / 3;
01208       b = (cnv[f1 + 2] + cnv[f2 + 2] + cnv[f3 + 2]) / 3;
01209       depth_obj.color = nearest_index(r, g, b);
01210 
01211       // transform from world coordinates to screen coordinates and copy
01212       // each point to the depth sort structure in one fell swoop
01213       (transMat.top()).multpoint3d(&cnv[f1 + 7], x);
01214       (transMat.top()).multpoint3d(&cnv[f2 + 7], y);
01215       (transMat.top()).multpoint3d(&cnv[f3 + 7], z);
01216       memcpy(depth_obj.points, x, sizeof(float) * 2);
01217       memcpy(&depth_obj.points[2], y, sizeof(float) * 2);
01218       memcpy(&depth_obj.points[4], z, sizeof(float) * 2);
01219 
01220       // compute the centerpoint of the object
01221       cent[0] = (x[0] + y[0] + z[0]) / 3;
01222       cent[1] = (x[1] + y[1] + z[1]) / 3;
01223       cent[2] = (x[2] + y[2] + z[2]) / 3;
01224 
01225       // now compute distance to eye
01226       depth_obj.dist = compute_dist(cent);
01227 
01228       // light shading factor
01229       depth_obj.light_scale = compute_light(x, y, z);
01230 
01231       // done ... add the object to the list
01232       memusage += sizeof(float) * 2 * depth_obj.npoints;
01233       points += depth_obj.npoints;
01234       objects++;
01235       depth_list.append(depth_obj);
01236    }
01237 
01238 }
01239 
01240 
01241 void PSDisplayDevice::decompose_tristrip(DispCmdTriStrips *strip)
01242 {
01243     int s, t, v = 0;
01244     int v0, v1, v2;
01245     float r, g, b;
01246     float x[3], y[3], z[3], cent[3];
01247     DepthSortObject depth_obj;
01248 
01249     depth_obj.npoints = 3;
01250 
01251     // lookup table for winding order
01252     const int stripaddr[2][3] = { {0, 1, 2}, {1, 0, 2} };
01253 
01254     float *cnv;
01255     int *f;
01256     int *vertsperstrip;
01257     strip->getpointers(cnv, f, vertsperstrip);
01258 
01259     // loop over all of the triangle strips
01260     for (s = 0; s < strip->numstrips; s++)
01261     {
01262         // loop over all triangles in this triangle strip
01263         for (t = 0; t < vertsperstrip[s] - 2; t++)
01264         {
01265             v0 = f[v + (stripaddr[t & 0x01][0])] * 10;
01266             v1 = f[v + (stripaddr[t & 0x01][1])] * 10;
01267             v2 = f[v + (stripaddr[t & 0x01][2])] * 10;
01268 
01269             // allocate memory for the points
01270             depth_obj.points = (float *) malloc(6 * sizeof(float));
01271             if (!depth_obj.points) {
01272                 if (!memerror) {
01273                     memerror = 1;
01274                     msgErr << "PSDisplayDevice: Out of memory. Some "
01275                            << "objects were not drawn." << sendmsg;
01276                 }
01277                 continue;
01278             }
01279 
01280             // average the three colors and use that average as the color for
01281             // this triangle
01282             r = (cnv[v0+0] + cnv[v1+0] + cnv[v2+0]) / 3; 
01283             g = (cnv[v0+1] + cnv[v1+1] + cnv[v2+1]) / 3; 
01284             b = (cnv[v0+2] + cnv[v1+2] + cnv[v2+2]) / 3; 
01285             depth_obj.color = nearest_index(r, g, b);
01286 
01287             // transform from world coordinates to screen coordinates and copy
01288             // each point to the depth sort structure in one fell swoop
01289             (transMat.top()).multpoint3d(&cnv[v0 + 7], x);
01290             (transMat.top()).multpoint3d(&cnv[v1 + 7], y);
01291             (transMat.top()).multpoint3d(&cnv[v2 + 7], z);
01292             memcpy(depth_obj.points, x, sizeof(float) * 2);
01293             memcpy(&depth_obj.points[2], y, sizeof(float) * 2);
01294             memcpy(&depth_obj.points[4], z, sizeof(float) * 2);
01295 
01296             // compute the centerpoint of the object
01297             cent[0] = (x[0] + y[0] + z[0]) / 3;
01298             cent[1] = (x[1] + y[1] + z[1]) / 3;
01299             cent[2] = (x[2] + y[2] + z[2]) / 3;
01300 
01301             // now compute distance to eye
01302             depth_obj.dist = compute_dist(cent);
01303 
01304             // light shading factor
01305             depth_obj.light_scale = compute_light(x, y, z);
01306 
01307             // done ... add the object to the list
01308             memusage += sizeof(float) * 2 * depth_obj.npoints;
01309             points += depth_obj.npoints;
01310             objects++;
01311             depth_list.append(depth_obj);
01312 
01313             v++; // move on to next vertex
01314         } // triangles
01315     v+=2; // last two vertices are already used by last triangle
01316     } // strips  
01317 }
01318 
01319 
01320 void PSDisplayDevice::write_header(void) {
01321    int i;
01322 
01323    fprintf(outfile, "%%!PS-Adobe-1.0\n");
01324    fprintf(outfile, "%%%%DocumentFonts:Helvetica\n");
01325    fprintf(outfile, "%%%%Title:vmd.ps\n");
01326    fprintf(outfile, "%%%%Creator:VMD -- Visual Molecular Dynamics\n");
01327    fprintf(outfile, "%%%%CreationDate:\n");
01328    fprintf(outfile, "%%%%Pages:1\n");
01329    fprintf(outfile, "%%%%BoundingBox:0 0 612 792\n");
01330    fprintf(outfile, "%%%%EndComments\n");
01331    fprintf(outfile, "%%%%Page:1 1\n");
01332 
01333    fprintf(outfile, "%3.2f %3.2f %3.2f setrgbcolor    %% background color\n",
01334       backColor[0], backColor[1], backColor[2]);
01335    fprintf(outfile, "newpath\n");
01336    fprintf(outfile, "0 0 moveto\n");
01337    fprintf(outfile, "0 792 lineto\n");
01338    fprintf(outfile, "792 792 lineto\n");
01339    fprintf(outfile, "792 0 lineto\n");
01340    fprintf(outfile, "closepath\nfill\nstroke\n");
01341 
01342    // quadrilateral ( /s )
01343    // Format: x1 y1 x2 y2 x3 y3 x4 y4 s
01344    fprintf(outfile, "/s\n");
01345    fprintf(outfile, "{ newpath moveto lineto lineto lineto closepath fill stroke } def\n");
01346 
01347    // quadrilateral-w ( /sw )
01348    fprintf(outfile, "/sw\n");
01349    fprintf(outfile, "{ newpath moveto lineto lineto lineto closepath stroke } def\n");
01350 
01351    // triangle ( /t )
01352    fprintf(outfile, "/t\n");
01353    fprintf(outfile, "{ newpath moveto lineto lineto closepath fill stroke } def\n");
01354 
01355    // triangle-w ( /tw )
01356    fprintf(outfile, "/tw\n");
01357    fprintf(outfile, "{ newpath moveto lineto lineto closepath stroke } def\n");
01358 
01359    // point ( /p )
01360    // A point is drawn by making a 'cross' around the point, meaning two
01361    // lines from (x-1,y) to (x+1,y) and (x,y-1) to (x,y+1). The PostScript
01362    // here is from the old PSDisplayDevice, and it can probably be cleaned
01363    // up, but is not urgent.
01364    fprintf(outfile, "/p\n");
01365    fprintf(outfile, "{ dup dup dup 5 -1 roll dup dup dup 8 -1 roll exch 8 -1\n");
01366    fprintf(outfile, "  roll 4 1 roll 8 -1 roll 6 1 roll newpath -1 add moveto\n");
01367    fprintf(outfile, "  1 add lineto exch -1 add exch moveto exch 1 add exch\n");
01368    fprintf(outfile, "  lineto closepath stroke } def\n");
01369 
01370    // line ( /l )
01371    fprintf(outfile, "/l\n");
01372    fprintf(outfile, "{ newpath moveto lineto closepath stroke } def\n");
01373 
01374    // scalecolor ( /mc )
01375    // This takes an rgb triplet and scales it according to a floating point
01376    // value. This is useful for polygon shading and is used with the color table.
01377    fprintf(outfile, "/mc\n");
01378    fprintf(outfile, "{ dup 4 1 roll dup 3 1 roll mul 5 1 roll mul 4 1 roll\n");
01379    fprintf(outfile, "  mul 3 1 roll } def\n");
01380 
01381    // getcolor ( /gc )
01382    // This function retrieves a color from the color table.
01383    fprintf(outfile, "/gc\n");
01384    fprintf(outfile, "{ 2 1 roll dup 3 -1 roll get dup dup 0 get 3 1 roll\n");
01385    fprintf(outfile, "  1 get 3 1 roll 2 get 3 -1 roll exch } def\n");
01386 
01387    // /text :  draw text at given position
01388    fprintf(outfile, "/text\n");
01389    fprintf(outfile,"{ moveto show } def\n");
01390 
01391    // textsize ( /ts )
01392    fprintf(outfile, "/ts\n");
01393    fprintf(outfile, "{ /Helvetica findfont exch scalefont setfont } def\n");
01394 
01395    // load font and set defaults
01396    //fprintf(outfile,"15 ts\n");
01397 
01398    // setcolor ( /c )
01399    // This function retrieves a color table entry and scales it.
01400    fprintf(outfile, "/c\n");
01401    fprintf(outfile, "{ 3 1 roll gc 5 -1 roll mc setrgbcolor } def\n");
01402 
01403    // Now we need to write out the entire color table to the Postscript
01404    // file. The table is implemented as a double array. Each element in the
01405    // array contains another array of 3 elements -- the RGB triple. The
01406    // getcolor function retrieves a triplet from this array.
01407    fprintf(outfile, "\n");
01408    for (i = 0; i < MAXCOLORS; i++) {
01409       fprintf(outfile, "[ %.2f %.2f %.2f ]\n",
01410          matData[i][0],
01411          matData[i][1],
01412          matData[i][2]);
01413    }
01414    fprintf(outfile, "%d array astore\n", MAXCOLORS);
01415 }
01416 
01417 
01418 void PSDisplayDevice::write_trailer(void) {
01419 }
01420 
01421 
01422 void PSDisplayDevice::comment(const char *s) {
01423    fprintf(outfile, "%%%% %s\n", s);
01424 }
01425 
01426 
01427 inline float PSDisplayDevice::compute_dist(float *s) {
01428    return
01429       (s[0] - eyePos[0]) * (s[0] - eyePos[0]) +
01430       (s[1] - eyePos[1]) * (s[1] - eyePos[1]) +
01431       (s[2] - eyePos[2]) * (s[2] - eyePos[2]);
01432 }
01433 
01434 
01435 float PSDisplayDevice::compute_light(float *a, float *b, float *c) {
01436    float norm[3];
01437    float light_scale;
01438 
01439    // compute a normal vector to the surface of the polygon
01440    norm[0] =
01441       a[1] * (b[2] - c[2]) +
01442       b[1] * (c[2] - a[2]) +
01443       c[1] * (a[2] - b[2]);
01444    norm[1] =
01445       a[2] * (b[0] - c[0]) +
01446       b[2] * (c[0] - a[0]) +
01447       c[2] * (a[0] - b[0]);
01448    norm[2] =
01449       a[0] * (b[1] - c[1]) +
01450       b[0] * (c[1] - a[1]) +
01451       c[0] * (a[1] - b[1]);
01452 
01453    // if the normal vector is zero, something is wrong with the
01454    // object so we'll just display it with a light_scale of zero
01455    if (!norm[0] && !norm[1] && !norm[2]) {
01456       light_scale = 0;
01457    } else {
01458       // otherwise we use the dot product of the surface normal
01459       // and the light normal to determine a light_scale
01460       vec_normalize(norm);
01461       light_scale = dot_prod(norm, norm_light);
01462       if (light_scale < 0) light_scale = -light_scale;
01463    }
01464 
01465    return light_scale;
01466 }

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