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

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

Generated on Tue Apr 16 02:45:10 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002