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(¢ers[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 }