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

PSDisplayDevice.C

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

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