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

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