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

DisplayDevice.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr                                                                       
00003  *cr            (C) Copyright 1995-2011 The Board of Trustees of the           
00004  *cr                        University of Illinois                       
00005  *cr                         All Rights Reserved                        
00006  *cr                                                                   
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  * RCS INFORMATION:
00011  *
00012  *      $RCSfile: DisplayDevice.C,v $
00013  *      $Author: johns $        $Locker:  $             $State: Exp $
00014  *      $Revision: 1.137 $      $Date: 2011/10/17 18:36:33 $
00015  *
00016  ***************************************************************************
00017  * DESCRIPTION:
00018  *
00019  * DisplayDevice - abstract base class for all particular objects which
00020  *      can process a list of drawing commands and render the drawing
00021  *      to some device (screen, file, preprocessing script, etc.)
00022  *
00023  ***************************************************************************/
00024 
00025 #include <math.h>
00026 #include "DisplayDevice.h"
00027 #include "Inform.h"
00028 #include "DispCmds.h"
00029 #include "utilities.h"
00030 #include "Mouse.h"     // for WAIT_CURSOR
00031 #include "VMDDisplayList.h"
00032 #include "Scene.h"
00033 
00034 // static data for this object (yuck)
00035 static const char *cacheNameStr[1]  = { "Off" };
00036 static const char *renderNameStr[1] = { "Normal" };
00037 static const char *stereoNameStr[1] = { "Stereo Off" };
00038 
00039 const char *DisplayDevice::projNames[NUM_PROJECTIONS] = {
00040   "Perspective", "Orthographic"
00041 };
00042 
00043 const char *DisplayDevice::cueModeNames[NUM_CUE_MODES] = {
00044   "Linear", "Exp", "Exp2"
00045 };
00046 
00048 DisplayDevice::DisplayDevice (const char *nm) : transMat(16) {
00049   name = stringdup(nm);       // save the string name of this display device
00050   num_display_processes  = 1; // set number of rendering processes etc
00051   renderer_process = 1;       // we're a rendering process until told otherwise
00052   _needRedraw = 0;            // Start life not needing to be redrawn. 
00053   backgroundmode = 0;         // set default background mode to solid color
00054 
00055   // set drawing characteristics default values
00056   lineStyle = ::SOLIDLINE;
00057   lineWidth = 1;
00058   sphereRes = 3;
00059   cylinderRes = 6;
00060   sphereMode = ::SOLIDSPHERE;
00061 
00062   // set scalar values
00063   aaAvailable = cueingAvailable = TRUE;
00064   aaPrevious = aaEnabled = cueingEnabled = cullingEnabled = FALSE;
00065   xOrig = yOrig = xSize = ySize = 0;
00066   screenX = screenY = 0;
00067 
00068   // set viewing geometry ... looking from z-axis in negative direction,
00069   // with 90-degree field of view and assuming the origin is in the
00070   // center of the viewer's 'screen'
00071   nearClip = 0.5f;
00072   farClip = 10.0f;
00073   eyePos[0] = eyePos[1] = 0.0f;  eyePos[2] = 2.0f;
00074   set_screen_pos(2.0f * eyePos[2], 0.0f, 4.0f/3.0f);
00075 
00076   // set initial depth cueing parameters 
00077   // (defaults are compatible with old revs of VMD)
00078   cueMode = CUE_EXP2;
00079   cueDensity = 0.32f;
00080   cueStart = 0.5f;
00081   cueEnd = 10.0f;
00082 
00083   // set initial shadow mode
00084   shadowEnabled = 0;
00085 
00086   // set initial ambient occlusion settings
00087   aoEnabled = 0;
00088   aoAmbient = 0.8f;
00089   aoDirect = 0.3f;
00090 
00091   // XXX stereo modes and rendering modes should be enumerated 
00092   // dynamically not hard-coded, to allow much greater flexibility
00093 
00094   // Setup stereo options ... while there is no stereo mode by default,
00095   // set up normal values for stereo data
00096   inStereo = 0;
00097   stereoSwap = 0;
00098   stereoModes = 1;
00099   stereoNames = stereoNameStr;
00100 
00101   // Setup caching mode options
00102   cacheMode = 0;
00103   cacheModes = 1;
00104   cacheNames = cacheNameStr;
00105 
00106   // Setup rendering mode options
00107   renderMode = 0;
00108   renderModes = 1;
00109   renderNames = renderNameStr;
00110 
00111   // default view/projection settings
00112   eyeSep = 0.065f;               // default eye seperation
00113   eyeDist = eyePos[2];           // assumes viewer on pos z-axis
00114 
00115   float lookatorigin[3];
00116   vec_scale(&lookatorigin[0], -1, &eyePos[0]); // calc dir to origin
00117   set_eye_dir(&lookatorigin[0]);               // point camera at origin
00118   upDir[0] = upDir[2] = 0.0;  upDir[1] = 1.0;
00119   calc_eyedir();                 // determines eye separation direction
00120   my_projection = PERSPECTIVE;
00121 
00122   // load identity matrix onto top of transformation matrix stack
00123   Matrix4 temp_ident;
00124   transMat.push(temp_ident);
00125 
00126   mouseX = mouseY = 0;
00127 }
00128 
00129 // destructor
00130 DisplayDevice::~DisplayDevice(void) {
00131   set_stereo_mode(0);           // return to non-stereo, if necessary
00132   delete [] name;
00133 }
00134 
00135 int DisplayDevice::set_eye_defaults() {
00136   float defaultDir[3];
00137   float defaultPos[3] = {0, 0, 2};           // camera 2 units back from origin
00138   float defaultUp[3] = {0, 1, 0};            // Y is up
00139 
00140   vec_scale(&defaultDir[0], -1, &eyePos[0]); // calc dir to origin
00141   set_eye_dir(&defaultDir[0]);               // point camera at origin
00142 
00143   set_eye_pos(&defaultPos[0]);
00144   set_eye_dir(&defaultDir[0]);
00145   set_eye_up(&defaultUp[0]);
00146 
00147   return TRUE;
00148 }
00149 
00151 // calculate the position of the near frustum plane, based on current values
00152 // of Aspect, vSize, zDist, nearClip and eyePosition
00153 // Assumes the viewer is looking toward the xy-plane
00154 void DisplayDevice::calc_frustum(void) {
00155   float d; 
00156   float halfvsize = 0.5f * vSize;       
00157   float halfhsize = Aspect * halfvsize; // width = aspect * height
00158 
00159   // if the frustum parameters don't cause division by zero,
00160   // calculate the new view frustum
00161   if(eyePos[2] - zDist != 0.0f) {
00162     // scaling ratio for the view frustum, essentially the amount of 
00163     // perspective to apply.  Since we define the nearClip plane in
00164     // the user interface, we can control how strong the perspective
00165     // is by varying (eyePos[2] - zDist) or by scaling d by some other
00166     // user controllable factor.  In order to make this more transparent
00167     // to the user however, we'd need to automatically apply a scaling 
00168     // operation on the molecular geometry so that it looks about the same
00169     // despite the perspective change.  We should also be able to calculate
00170     // the field of view angles (vertical, horizontal, and diagonal) based
00171     // on all of these variables.
00172     d = nearClip / (eyePos[2] - zDist);
00173 
00174     cpRight = d * halfhsize;     // right side is at half width
00175      cpLeft = -cpRight;          // left side is at negative half width
00176        cpUp = d * halfvsize;     // top side is at half height              
00177      cpDown = -cpUp;             // bottom is at negative half height
00178   }
00179 }
00180 
00181 
00182 // calculate eyeSepDir, based on up vector and look vector
00183 // eyeSepDir = 1/2 * eyeSep * (lookdir x updir) / mag(lookdir x updir)
00184 void DisplayDevice::calc_eyedir(void) {
00185   float *L = eyeDir;
00186   float *U = upDir;
00187   float m, A = 0.5f * eyeSep;
00188   eyeSepDir[0] = L[1] * U[2] - L[2] * U[1];
00189   eyeSepDir[1] = L[2] * U[0] - L[0] * U[2];
00190   eyeSepDir[2] = L[0] * U[1] - L[1] * U[0];
00191   m = sqrtf(eyeSepDir[0] * eyeSepDir[0] + eyeSepDir[1] * eyeSepDir[1] +
00192             eyeSepDir[2] * eyeSepDir[2]);
00193   if(m > 0.0)
00194     A /= m;
00195   else
00196     A = 0.0;
00197   eyeSepDir[0] *= A;
00198   eyeSepDir[1] *= A;
00199   eyeSepDir[2] *= A;
00200 }
00201 
00203 
00204 // Copy all relevant properties from one DisplayDevice to another
00205 DisplayDevice& DisplayDevice::operator=( DisplayDevice &display) {
00206   int i;
00207   
00208   xOrig = display.xOrig;
00209   yOrig = display.yOrig;
00210   xSize = display.xSize;
00211   ySize = display.ySize;
00212   
00213   // Do something about the stack.  For the moment, only copy the top
00214   // item on the stack.
00215   if (transMat.num() > 0) {
00216     transMat.pop();
00217   }
00218   transMat.push( (display.transMat).top() );
00219   
00220   for (i=0; i<3; i++) {
00221     eyePos[i] = display.eyePos[i];
00222     eyeDir[i] = display.eyeDir[i];
00223     upDir[i] = display.upDir[i];
00224     eyeSepDir[i] = display.eyeSepDir[i];
00225   }
00226   
00227   whichEye = display.whichEye;
00228   nearClip = display.nearClip;
00229   farClip = display.farClip;
00230   vSize = display.vSize;
00231   zDist = display.zDist;
00232   Aspect = display.Aspect;
00233   cpUp = display.cpUp;
00234   cpDown = display.cpDown;
00235   cpLeft = display.cpLeft;
00236   cpRight = display.cpRight;
00237   inStereo = display.inStereo;
00238   eyeSep = display.eyeSep;
00239   eyeDist = display.eyeDist;
00240   lineStyle = display.lineStyle;
00241   lineWidth = display.lineWidth;
00242   my_projection = display.my_projection;
00243   backgroundmode = display.backgroundmode;
00244   cueingEnabled = display.cueingEnabled;
00245   cueMode = display.cueMode;
00246   cueDensity = display.cueDensity;
00247   cueStart = display.cueStart;
00248   cueEnd = display.cueEnd;
00249   shadowEnabled = display.shadowEnabled;
00250   aoEnabled = display.aoEnabled;
00251   aoAmbient = display.aoAmbient;
00252   aoDirect = display.aoDirect; 
00253   return *this;
00254 }
00255 
00257 
00258 void DisplayDevice::do_resize_window(int w, int h) {
00259   xSize = w;
00260   ySize = h;
00261   set_screen_pos((float)xSize / (float)ySize);
00262 }
00263 
00264 //
00265 // event handling routines
00266 //
00267 
00268 // queue the standard events (need only be called once ... but this is
00269 // not done automatically by the window because it may not be necessary or
00270 // even wanted)
00271 void DisplayDevice::queue_events(void) { return; }
00272 
00273 // read the next event ... returns an event type (one of the above ones),
00274 // and a value.  Returns success, and sets arguments.
00275 int DisplayDevice::read_event(long &, long &) { return FALSE; }
00276 
00277 //
00278 // get the current state of the device's pointer (i.e. cursor if it has one)
00279 //
00280 
00281 // abs pos of cursor from lower-left corner
00282 int DisplayDevice::x(void) { return mouseX; }
00283 
00284 // same, for y direction
00285 int DisplayDevice::y(void) { return mouseY; }
00286 
00287 // the shift state (shift key, control key, and/or alt key)
00288 int DisplayDevice::shift_state(void) {
00289   return 0; // by default, nothing is down
00290 }
00291 
00292 // set the Nth cursor shape as the current one.  If no arg given, the
00293 // default shape (n=0) is used.
00294 void DisplayDevice::set_cursor(int) { }
00295 
00296 // virtual functions to turn on/off depth cuing and antialiasing
00297 void DisplayDevice::aa_on(void) { }
00298 void DisplayDevice::aa_off(void) { }
00299 void DisplayDevice::cueing_on(void) { 
00300   if (cueingAvailable)
00301     cueingEnabled = TRUE;
00302 }
00303 void DisplayDevice::cueing_off(void) { }
00304 void DisplayDevice::culling_on(void) { }
00305 void DisplayDevice::culling_off(void) { }
00306 
00307 // return absolute 2D screen coordinates, given 2D or 3D world coordinates.
00308 void DisplayDevice::abs_screen_loc_3D(float *wloc, float *sloc) {
00309   // just return world coords
00310   for(int i=0; i < 3; i++)
00311     sloc[i] = wloc[i];
00312 }
00313 
00314 void DisplayDevice::abs_screen_loc_2D(float *wloc, float *sloc) {
00315   // just return world coords
00316   for(int i=0; i < 2; i++)
00317     sloc[i] = wloc[i];
00318 }
00319 
00320 // change to a different stereo mode (0 means 'off')
00321 void DisplayDevice::set_stereo_mode(int sm) {
00322   if(sm != 0) {
00323     msgErr << "DisplayDevice: Illegal stereo mode " << sm << " specified."
00324            << sendmsg;
00325   } else {
00326     inStereo = sm;
00327   }
00328 }
00329 
00330 // change to a different rendering mode (0 means 'normal')
00331 void DisplayDevice::set_cache_mode(int sm) {
00332   if(sm != 0) {
00333     msgErr << "DisplayDevice: Illegal caching mode " << sm << " specified."
00334            << sendmsg;
00335   } else {
00336     cacheMode = sm;
00337   }
00338 }
00339 
00340 // change to a different rendering mode (0 means 'normal')
00341 void DisplayDevice::set_render_mode(int sm) {
00342   if(sm != 0) {
00343     msgErr << "DisplayDevice: Illegal rendering mode " << sm << " specified."
00344            << sendmsg;
00345   } else {
00346     renderMode = sm;
00347   }
00348 }
00349 
00350 // replace the current trans matrix with the given one
00351 void DisplayDevice::loadmatrix(const Matrix4 &m) {
00352   (transMat.top()).loadmatrix(m);
00353 }
00354 
00355 // multiply the current trans matrix with the given one
00356 void DisplayDevice::multmatrix(const Matrix4 &m) {
00357   (transMat.top()).multmatrix(m);
00358 }
00359 
00360 //
00361 // virtual routines for preparing to draw, drawing, and finishing drawing
00362 //
00363   
00364 int DisplayDevice::prepare3D(int) { return 1;}  // ready to draw 3D
00365 void DisplayDevice::clear(void) { }             // erase the device
00366 void DisplayDevice::left(void) {                // ready to draw left eye
00367   whichEye = LEFTEYE; 
00368 }
00369 void DisplayDevice::right(void) {               // ready to draw right eye
00370   whichEye = RIGHTEYE;
00371 }
00372 void DisplayDevice::normal(void) {              // ready to draw non-stereo
00373   whichEye = NOSTEREO;
00374 }
00375 void DisplayDevice::update(int) { }             // finish up after drawing
00376 void DisplayDevice::reshape(void) { }           // refresh device after change
00377 
00378 // Grab the screen
00379 unsigned char * DisplayDevice::readpixels(int &x, int &y) { 
00380   x = 0;
00381   y = 0;
00382 
00383   return NULL;
00384 }
00385 
00386 void DisplayDevice::find_pbc_images(const VMDDisplayList *cmdList, 
00387                                     ResizeArray<Matrix4> &pbcImages) {
00388   if (cmdList->pbc == PBC_NONE) {
00389     pbcImages.append(Matrix4());
00390     return;
00391   }
00392   ResizeArray<int> pbcCells;
00393   find_pbc_cells(cmdList, pbcCells);
00394   for (int i=0; i<pbcCells.num(); i += 3) {
00395     int nx=pbcCells[i  ];
00396     int ny=pbcCells[i+1];
00397     int nz=pbcCells[i+2];
00398     Matrix4 mat;
00399     for (int i1=1; i1<=nx; i1++) mat.multmatrix(cmdList->transX);
00400     for (int i2=-1; i2>=nx; i2--) mat.multmatrix(cmdList->transXinv);
00401     for (int i3=1; i3<=ny; i3++) mat.multmatrix(cmdList->transY);
00402     for (int i4=-1; i4>=ny; i4--) mat.multmatrix(cmdList->transYinv);
00403     for (int i5=1; i5<=nz; i5++) mat.multmatrix(cmdList->transZ);
00404     for (int i6=-1; i6>=nz; i6--) mat.multmatrix(cmdList->transZinv);
00405     pbcImages.append(mat);
00406   }
00407 }
00408 
00409 void DisplayDevice::find_pbc_cells(const VMDDisplayList *cmdList, 
00410                                     ResizeArray<int> &pbcCells) {
00411   int pbc = cmdList->pbc;
00412   if (pbc == PBC_NONE) {
00413     pbcCells.append(0);
00414     pbcCells.append(0);
00415     pbcCells.append(0);
00416   } else {
00417     int npbc = cmdList->npbc;
00418     int nx = pbc & PBC_X ? npbc : 0;
00419     int ny = pbc & PBC_Y ? npbc : 0;
00420     int nz = pbc & PBC_Z ? npbc : 0;
00421     int nox = pbc & PBC_OPX ? -npbc : 0;
00422     int noy = pbc & PBC_OPY ? -npbc : 0;
00423     int noz = pbc & PBC_OPZ ? -npbc : 0;
00424     int i, j, k;
00425     for (i=nox; i<=nx; i++) {
00426       for (j=noy; j<=ny; j++) {
00427         for (k=noz; k<=nz; k++) {
00428           if (! (pbc & PBC_NOSELF && !i && !j && !k)) {
00429             pbcCells.append(i);
00430             pbcCells.append(j);
00431             pbcCells.append(k);
00432           }
00433         }
00434       }
00435     }
00436   }
00437 }
00438 
00439 //
00440 //*******************  the picking routine  *********************
00441 //
00442 // This scans the given command list until the end, finding which item is
00443 // closest to the given pointer position.
00444 //
00445 // arguments are dimension of picking (2 or 3), position of pointer,
00446 // draw command list, and returned distance from object to eye position.
00447 // Returns ID code ('tag') for item closest to pointer, or (-1) if no pick.
00448 // If an object is picked, the eye distance argument is set to the distance
00449 // from the display's eye position to the object (after its position has been
00450 // found from the transformation matrix).  If the value of the argument when
00451 // 'pick' is called is <= 0, a pick will be generated if any item is near the
00452 // pointer.  If the value of the argument is > 0, a pick will be generated
00453 // only if an item is closer to the eye position than the value of the
00454 // argument.
00455 // For 2D picking, coordinates are relative position in window from
00456 //      lower-left corner (both in range 0 ... 1)
00457 // For 3D picking, coordinates are the world coords of the pointer.  They
00458 //      are the coords of the pointer after its transformation matrix has been
00459 //      applied, and these coordinates are compared to the coords of the objects
00460 //      when their transformation matrices are applied.
00461 
00462 // but first, a macro for returning the distance^2 from the eyepos to the
00463 // given position
00464 #define DTOEYE(x,y,z) ( (x-eyePos[0])*(x-eyePos[0]) + \
00465                         (y-eyePos[1])*(y-eyePos[1]) + \
00466                         (z-eyePos[2])*(z-eyePos[2]) )
00467 #define DTOPOINT(x,y,z) ( (x-pos[0])*(x-pos[0]) + \
00468                         (y-pos[1])*(y-pos[1]) + \
00469                         (z-pos[2])*(z-pos[2]) )
00470 
00471 int DisplayDevice::pick(int dim, const float *pos, const VMDDisplayList *cmdList,
00472                         float &eyedist, int *unitcell, float window_size) {
00473   char *cmdptr = NULL;
00474   int tok;
00475   float newEyeDist, currEyeDist = eyedist;
00476   int tag = (-1), inRegion, currTag;
00477   float minX=0.0f, minY=0.0f, maxX=0.0f, maxY=0.0f;
00478   float fminX=0.0f, fminY=0.0f, fminZ=0.0f, fmaxX=0.0f, fmaxY=0.0f, fmaxZ=0.0f;
00479   float wpntpos[3], pntpos[3], cpos[3];
00480 
00481   if(!cmdList)
00482     return (-1);
00483 
00484   // initialize picking: find screen region to look for object
00485   if (dim == 2) {
00486     fminX = pos[0] - window_size;
00487     fmaxX = pos[0] + window_size;
00488     fminY = pos[1] - window_size;
00489     fmaxY = pos[1] + window_size;
00490     abs_screen_pos(fminX, fminY);
00491     abs_screen_pos(fmaxX, fmaxY);
00492 #if defined(_MSC_VER)
00493     // Win32 lacks the C99 round() routine
00494     // Add +/- 0.5 then then round towards zero.
00495 #if 1
00496     minX = (int) ((float) (fminX + (fminX >= 0.0f ?  0.5f : -0.5f)));
00497     maxX = (int) ((float) (fmaxX + (fmaxX >= 0.0f ?  0.5f : -0.5f)));
00498     minY = (int) ((float) (fminY + (fminY >= 0.0f ?  0.5f : -0.5f)));
00499     maxY = (int) ((float) (fmaxY + (fmaxY >= 0.0f ?  0.5f : -0.5f)));
00500 #else
00501     minX = truncf(fminX + (fminX >= 0.0f ?  0.5f : -0.5f));
00502     maxX = truncf(fmaxX + (fmaxX >= 0.0f ?  0.5f : -0.5f));
00503     minY = truncf(fminY + (fminY >= 0.0f ?  0.5f : -0.5f));
00504     maxY = truncf(fmaxY + (fmaxY >= 0.0f ?  0.5f : -0.5f));
00505 //    minX = floor(fminX + 0.5);
00506 //    maxX = floor(fmaxX + 0.5);
00507 //    minY = floor(fminY + 0.5);
00508 //    maxY = floor(fmaxY + 0.5);
00509 #endif
00510 #else
00511     minX = round(fminX);
00512     maxX = round(fmaxX);
00513     minY = round(fminY);
00514     maxY = round(fmaxY);
00515 #endif
00516 
00517   } else {
00518     fminX = pos[0] - window_size;
00519     fmaxX = pos[0] + window_size;
00520     fminY = pos[1] - window_size;
00521     fmaxY = pos[1] + window_size;
00522     fminZ = pos[2] - window_size;
00523     fmaxZ = pos[2] + window_size;
00524   }
00525 
00526   // make sure we do not disturb the regular transformation matrix
00527   transMat.dup();
00528   (transMat.top()).multmatrix(cmdList->mat);
00529 
00530   // Transform the current pick point for each periodic image 
00531   ResizeArray<Matrix4> pbcImages;
00532   ResizeArray<int> pbcCells;
00533   find_pbc_images(cmdList, pbcImages);
00534   find_pbc_cells(cmdList, pbcCells);
00535   int pbcimg;
00536   for (pbcimg=0; pbcimg<pbcImages.num(); pbcimg++) {
00537     transMat.dup();
00538     (transMat.top()).multmatrix(pbcImages[pbcimg]);
00539 
00540     // scan through the list, getting each command and executing it, until
00541     // the end of commands token is found
00542     VMDDisplayList::VMDLinkIter cmditer;
00543     cmdList->first(&cmditer);
00544     while((tok = cmdList->next(&cmditer, cmdptr)) != DLASTCOMMAND) {
00545       switch (tok) {
00546         case DPICKPOINT:
00547           // calculate the transformed position of the point
00548           {
00549             DispCmdPickPoint *cmd = (DispCmdPickPoint *)cmdptr;
00550             vec_copy(wpntpos, cmd->postag);
00551             currTag = cmd->tag;
00552           }
00553           (transMat.top()).multpoint3d(wpntpos, pntpos);
00554 
00555           // check if in picking region ... different for 2D and 3D
00556           if (dim == 2) {
00557             // convert the 3D world coordinate to 2D (XY) absolute screen 
00558             // coordinate, and a normalized Z coordinate.
00559             abs_screen_loc_3D(pntpos, cpos);
00560       
00561             // check to see if the projected picking position falls within the 
00562             // view frustum, with the XY coords falling within the displayed 
00563             // window, and the Z coordinate falling within the view volume
00564             // between the front and rear clipping planes.
00565             inRegion = (cpos[0] >= minX && cpos[0] <= maxX &&
00566                         cpos[1] >= minY && cpos[1] <= maxY &&
00567                         cpos[2] >= 0.0  && cpos[2] <= 1.0);
00568           } else {
00569             // just check to see if the position is in a box centered on our
00570             // pointer.  The pointer position should already be transformed.
00571             inRegion = (pntpos[0] >= fminX && pntpos[0] <= fmaxX &&     
00572                         pntpos[1] >= fminY && pntpos[1] <= fmaxY &&
00573                         pntpos[2] >= fminZ && pntpos[2] <= fmaxZ);
00574           }
00575 
00576           // Clip still-viable pick points against all active clipping planes
00577           if (inRegion) {
00578             // We must perform a check against all of the active
00579             // user-defined clipping planes to ensure that only pick points
00580             // associated with visible geometry can be selected.
00581             int cp;
00582             for (cp=0; cp < VMD_MAX_CLIP_PLANE; cp++) {
00583               // The final result is the intersection of all of the
00584               // individual clipping plane tests...
00585               if (cmdList->clipplanes[cp].mode) {
00586                 float cpdist[3];
00587                 vec_sub(cpdist, wpntpos, cmdList->clipplanes[cp].center);
00588                 inRegion &= (dot_prod(cpdist, 
00589                                       cmdList->clipplanes[cp].normal) > 0.0f);
00590               }
00591             }
00592           }
00593       
00594           // has a hit occurred?
00595           if (inRegion) {
00596             // yes, see if it is closer to the eye position than earlier objects
00597             if(dim==2) 
00598               newEyeDist = DTOEYE(pntpos[0], pntpos[1], pntpos[2]);
00599             else 
00600               newEyeDist = DTOPOINT(pntpos[0],pntpos[1],pntpos[2]);
00601 
00602             if(currEyeDist < 0.0 || newEyeDist < currEyeDist) {
00603               currEyeDist = newEyeDist;
00604               tag = currTag;
00605               if (unitcell) {
00606                 unitcell[0] = pbcCells[3*pbcimg  ];
00607                 unitcell[1] = pbcCells[3*pbcimg+1];
00608                 unitcell[2] = pbcCells[3*pbcimg+2];
00609               }
00610             }
00611           }
00612           break;
00613 
00614         case DPICKPOINT_ARRAY:
00615           // loop over all of the pick points in the pick point index array
00616           DispCmdPickPointArray *cmd = (DispCmdPickPointArray *)cmdptr;
00617           float *pickpos=NULL;
00618           float *crds=NULL;
00619           int *indices=NULL;
00620           cmd->getpointers(crds, indices); 
00621 
00622           int i;
00623           for (i=0; i<cmd->numpicks; i++) {
00624             pickpos = crds + i*3;
00625             if (cmd->allselected) {
00626               currTag = i + cmd->firstindex;
00627             } else {
00628               currTag = indices[i];
00629             }
00630             vec_copy(wpntpos, pickpos);
00631 
00632             (transMat.top()).multpoint3d(pickpos, pntpos);
00633 
00634             // check if in picking region ... different for 2D and 3D
00635             if (dim == 2) {
00636               // convert the 3D world coordinate to 2D absolute screen coord
00637               abs_screen_loc_3D(pntpos, cpos);
00638 
00639               // check to see if the position falls in our picking region
00640               // including the clipping region (cpos[2])
00641               inRegion = (cpos[0] >= minX && cpos[0] <= maxX &&
00642                           cpos[1] >= minY && cpos[1] <= maxY &&
00643                           cpos[2] >= 0.0  && cpos[2] <= 1.0);
00644             } else {
00645               // just check to see if the position is in a box centered on our
00646               // pointer.  The pointer position should already be transformed.
00647               inRegion = (pntpos[0] >= fminX && pntpos[0] <= fmaxX &&
00648                           pntpos[1] >= fminY && pntpos[1] <= fmaxY &&
00649                           pntpos[2] >= fminZ && pntpos[2] <= fmaxZ);
00650             }
00651 
00652             // Clip still-viable pick points against all active clipping planes
00653             if (inRegion) {
00654               // We must perform a check against all of the active
00655               // user-defined clipping planes to ensure that only pick points
00656               // associated with visible geometry can be selected.
00657               int cp;
00658               for (cp=0; cp < VMD_MAX_CLIP_PLANE; cp++) {
00659                 // The final result is the intersection of all of the
00660                 // individual clipping plane tests...
00661                 if (cmdList->clipplanes[cp].mode) {
00662                   float cpdist[3];
00663                   vec_sub(cpdist, wpntpos, cmdList->clipplanes[cp].center);
00664                   inRegion &= (dot_prod(cpdist, 
00665                                         cmdList->clipplanes[cp].normal) > 0.0f);
00666                 }
00667               }
00668             }
00669 
00670             // has a hit occurred?
00671             if (inRegion) {
00672               // yes, see if it is closer to the eye than earlier hits
00673               if (dim==2)
00674                 newEyeDist = DTOEYE(pntpos[0], pntpos[1], pntpos[2]);
00675               else
00676                 newEyeDist = DTOPOINT(pntpos[0],pntpos[1],pntpos[2]);
00677 
00678               if (currEyeDist < 0.0 || newEyeDist < currEyeDist) {
00679                 currEyeDist = newEyeDist;
00680                 tag = currTag;
00681                 if (unitcell) {
00682                   unitcell[0] = pbcCells[3*pbcimg  ];
00683                   unitcell[1] = pbcCells[3*pbcimg+1];
00684                   unitcell[2] = pbcCells[3*pbcimg+2];
00685                 }
00686               }
00687             }
00688           }
00689           break;
00690       }
00691     }
00692 
00693     // Pop the PBC image transform
00694     transMat.pop();
00695   } // end of loop over PBC images
00696 
00697   // make sure we do not disturb the regular transformation matrix
00698   transMat.pop();
00699 
00700   // return result; if tag >= 0, we found something
00701   eyedist = currEyeDist;
00702   return tag;
00703 }
00704 
00705 
00706 

Generated on Wed May 16 01:49:11 2012 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002