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

PSDisplayDevice.C

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

Generated on Tue Nov 18 02:47:56 2025 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002

AltStyle によって変換されたページ (->オリジナル) /