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

Displayable.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: Displayable.C,v $
00013  *      $Author: johns $        $Locker:  $             $State: Exp $
00014  *      $Revision: 1.113 $      $Date: 2010/12/16 04:08:11 $
00015  *
00016  ***************************************************************************
00017  * DESCRIPTION:
00018  *
00019  * Base class for all objects which are drawn in the DisplayDevice.
00020  *
00021  ***************************************************************************/
00022 
00023 #include <string.h>
00024 #include "Displayable.h"
00025 #include "DispCmds.h"
00026 #include "PickList.h"
00027 #include "utilities.h"
00028 #include "VMDApp.h"
00029 #include "DisplayDevice.h"
00030 
00031 /*
00032  Notes about how displayables work
00033  ---------------------------------
00034  1. Each Displayable contains an array of drawing/display commands.
00035     This array actually has some character-sized flags at the beginning, and
00036     then a sequential list of commands.  The format for the cmdList is:
00037         Integer: On (T) or Off (F)
00038         Integer: Fixed (T) or Free (F)
00039         Push Matrix command
00040         Multiply Matrix (with this objs trans matrix) command
00041         ... all commands for this object
00042         Pop Matrix command
00043 
00044   2. Each command has the form (as set up in DispCmds.h):
00045         command code (integer)
00046         data for command (0 or more bytes)
00047 
00048   3. A Displayable 'registers' with one or more Scene objects; this
00049      means it gives the display command list pointer to the Scene, which then
00050      uses that to draw the object.  Before drawing, however, the Scene calls
00051      the 'prepare' routine for each Displayable.  When deleted, the Displayable
00052      'unregisters' with all Scene objs it has previously registered with.
00053      If a Scene is deleted, it unregisters the Displayables in it's possession.
00054 
00055   4. A Displayable is either a 'parent' one or a 'child' one.  The
00056      difference is that parent Displayables register with the scene, and have
00057      only one transformation; children do NOT register with the scene, and have
00058      not only their main transformation (which is the same as the parent) but
00059      also a second one which multiplies the first.  Note that children can have
00060      children of their own, but are not 'parents', i.e. child Displayables do 
00061      not register with a scene even if they have children of their own.
00062   5. Children do register their DISPLAY LISTS, just not themselves
00063      (thus, they are not prepared, etc.; just rendered.)
00064   6. Children are created as normal, but with the parent Displayable
00065      specified instead of the Scene.  As part of the creation, the child will 
00066      be added to the parent's list via the 'add child' routine.
00067 */
00068 
00069 
00070 void *Displayable::operator new(size_t n) {
00071   return vmd_alloc(n);
00072 }
00073 
00074 void Displayable::operator delete(void *p, size_t) {
00075   vmd_dealloc(p);
00076 }
00077 
00078 Displayable::Displayable(Scene *s) : scene(s) {
00079   // Initialize scaling and other transformations, since we're a parent 
00080   parent = NULL;
00081   scale = 1;
00082   globt[0] = globt[1] = globt[2] = 0;
00083   centt[0] = centt[1] = centt[2] = 0;
00084   
00085   // get values for this items as default values
00086   isOn = TRUE;
00087   doCent = doRot = doGlob = doScale = TRUE;
00088   do_create();
00089 }
00090 
00091 Displayable::Displayable(Displayable *pops)  : scene(pops->scene) {
00092 
00093   _needUpdate = 1; // default to needing an update
00094   parent = pops;
00095 
00096   // get copies of all of parents tranformation matrices from parent
00097   vec_copy(centt, parent->centt);
00098   rotm = parent->rotm;
00099   vec_copy(globt, parent->globt);
00100   scale = parent->scale;
00101   tm = parent->tm;
00102 
00103   isOn = parent->displayed();
00104   doCent = parent->doCent;
00105   doRot = parent->doRot;
00106   doGlob = parent->doGlob;
00107   doScale = parent->doScale;
00108 
00109   // do common creation action
00110   do_create();
00111   
00112   // take initial material settings from parent
00113   cmdList->ambient = parent->cmdList->ambient;
00114   cmdList->specular = parent->cmdList->specular;
00115   cmdList->diffuse = parent->cmdList->diffuse;
00116   cmdList->shininess = parent->cmdList->shininess;
00117   cmdList->opacity = parent->cmdList->opacity;
00118   cmdList->outline = parent->cmdList->outline;
00119   cmdList->outlinewidth = parent->cmdList->outlinewidth;
00120   cmdList->transmode = parent->cmdList->transmode;
00121   cmdList->materialtag = parent->cmdList->materialtag;
00122 
00123   // inherit cacheability from parent
00124   cmdList->cacheskip = parent->cmdList->cacheskip;
00125 
00126   // finally, add this Displayable as a child to the parent
00127   parent->add_child(this);
00128 }
00129 
00130 
00131 // does all the creation work after variables have been initialized
00132 void Displayable::do_create() {
00133 
00134   children = (Displayable **)vmd_alloc(16*sizeof(Displayable*));
00135   num_children = 0;
00136   max_children = 16;
00137 
00138   // initialize the display command list 
00139   cmdList = new VMDDisplayList;
00140 
00141   // initialize flags and scalar settings
00142   needMatrixRecalc = TRUE;
00143   isFixed = FALSE;
00144 
00145   // initialize display list
00146   cmdList->mat = tm;
00147 
00148 }
00149 
00150 // reset the display command list; remove all current commands
00151 void Displayable::reset_disp_list(void) {
00152   _needUpdate = 1;
00153 
00154   // Must use a unique rep serial number, so that display list caching
00155   // works correctly in the rendering code
00156   cmdList->reset_and_free(VMDApp::get_repserialnum()); 
00157 }
00158 
00159 // destructor; free up allocated space
00160 Displayable::~Displayable(void) {
00161   // delete all children still around; also unregistered them
00162   while(num_children > 0)
00163     // delete first child object, the child destructor then removes the
00164     // child from this parent's list, until there are no more
00165     delete child(0);
00166 
00167   cmdList->reset_and_free(0); // free space allocated for disp storage
00168   delete cmdList;             // free the cmdList itself back to scene memory
00169 
00170   // if this is a child, remove it from it's parent's list of children
00171   if (parent)
00172     parent->remove_child(this);
00173 
00174   vmd_dealloc(children);
00175 }
00176 
00177 
00179 
00180 // recalculate the transformation matrix, and replace matrix in cmdList
00181 // This is composed of these operations (applied as R to L):
00182 //      TM =  GlobalTrans * Scale * Rotation * CenterTrans
00183 void Displayable::recalc_mat(void) {
00184   if (needMatrixRecalc) {
00185     _needUpdate = 1;
00186     tm.identity();
00187     tm.translate(globt);
00188     tm.multmatrix(rotm);
00189     tm.scale(scale);
00190     tm.translate(centt);
00191     // reload this matrix in the display command list
00192     cmdList->mat = tm;
00193 
00194     needMatrixRecalc = FALSE;
00195   }
00196 
00197   // recalc matrix for all children
00198   for (int i=0; i < num_children; i++)
00199     child(i)->recalc_mat();
00200 }
00201 
00203 
00204 // turn this object on or off
00205 void Displayable::off(void) { 
00206   isOn = FALSE;
00207   _needUpdate = 1;
00208 }
00209 
00210 void Displayable::on(void) { 
00211   isOn = TRUE;
00212   _needUpdate = 1;
00213 }
00214   
00215 // add the given Displayable as a child (assuming it is one)
00216 void Displayable::add_child(Displayable *d) {
00217     
00218   // append child to list of children
00219   children[num_children++] = d;
00220   if (num_children == max_children) {
00221     void *tmp = vmd_alloc(max_children*2*sizeof(Displayable*));
00222     memcpy(tmp,children,max_children*sizeof(Displayable*));
00223     vmd_dealloc(children);
00224     children = (Displayable **)tmp;
00225     max_children *= 2;
00226   } 
00227 }
00228 
00229 
00230 // remove the given Displayable as a child. return success.
00231 int Displayable::remove_child(Displayable *d) {
00232   // remove first child that matches the pointer, if available.
00233   int n = child_index(d);
00234   if (n >= 0) {
00235     // copy the entries from children+n+1  
00236     for (int i=n; i<num_children-1; i++) {
00237       children[i] = children[i+1];
00238     }
00239     num_children--;
00240     _needUpdate = 1;
00241     return TRUE;
00242   }
00243   return FALSE;
00244 }
00245 
00246 //
00247 // prepare/update routines
00248 //
00249 
00250 // prepare for drawing, called by draw_prepare, supplied by derived class.
00251 void Displayable::prepare() { }
00252   
00253 // prepare to draw; possibly recalc the trans matrix, and do particular preps
00254 int Displayable::draw_prepare() {
00255   int needupdate;
00256 
00257   if (parent == NULL)
00258     recalc_mat();    // update matrix if this is a parent Displayable
00259     
00260   prepare();         // do derived class preparations for this object
00261 
00262   needupdate = _needUpdate; // cache update state before we clear it
00263 
00264   // prepare child displayables; done after the parent has been prepared.
00265   for (int i=0; i < num_children; i++)
00266     needupdate |= child(i)->draw_prepare();
00267 
00268   // set the _needUpdate flag to zero _after_ all children have been updated
00269   // so that they can check (through needUpdate() if their parent has been
00270   // updated.  DrawForce currently uses this to determine whether to redraw. 
00271   _needUpdate = 0;          // once we've been prepared, we're ready to draw
00272   return needupdate; // return whether this or child displayables need updating
00273 }
00274 
00275 // do the actual drawing
00276 void Displayable::draw(DisplayDevice *d) const {
00277   // only render myself and my children if parent is turned on
00278   if (isOn) {
00279     d->render(cmdList);
00280     for (int i=0; i<num_children; i++)
00281       child(i)->draw(d);
00282   }
00283 }
00284 
00285 
00286 //
00287 // commands to change transformation
00288 //
00289 
00290 // reset the transformation to the identity matrix
00291 void Displayable::reset_transformation(void) {
00292   // only reset if we're not fixed and given operations are allowed
00293   if (scaling())           scale=1;
00294   if (rotating())          { rotm.identity(); }
00295   if (glob_translating())  globt[0] = globt[1] = globt[2] = 0;
00296   if (cent_translating())  centt[0] = centt[1] = centt[2] = 0;  
00297   need_matrix_recalc();
00298 
00299   // do reset for all children as well
00300   for (int i=0; i < num_children; i++)
00301     child(i)->reset_transformation();
00302 }
00303 
00304 void Displayable::set_scale(float s) {
00305   if (fixed())  return;         // only transform unfixed objects
00306 
00307   // do trans for all children as well
00308   for (int i=0; i < num_children; i++)
00309     child(i)->set_scale(s);
00310 
00311   if (!scaling())  return;
00312   scale = s;
00313   need_matrix_recalc();
00314 }
00315 
00316 void Displayable::mult_scale(float s) {
00317   if (fixed())  return;         // only transform unfixed objects
00318 
00319   // do trans for all children as well
00320   for (int i=0; i < num_children; i++)
00321     child(i)->mult_scale(s);
00322 
00323   if (!scaling())  return;
00324   scale *= s;
00325   need_matrix_recalc();
00326 }
00327 
00328 void Displayable::add_rot(float x, char axis) {
00329   if (fixed())  return;         // only transform unfixed objects
00330 
00331   // do trans for all children as well
00332   for (int i=0; i < num_children; i++)
00333     child(i)->add_rot(x, axis);
00334 
00335   if (!rotating())  return;
00336 
00337   // Need to apply the new rotation first
00338   Matrix4 mat;
00339   mat.rot(x, axis);
00340   mat.multmatrix(rotm);
00341   rotm = mat;
00342   need_matrix_recalc();
00343 }
00344 
00345 void Displayable::set_rot(float x, char axis) {
00346   if (fixed())  return;         // only transform unfixed objects
00347 
00348   // do trans for all children as well
00349   for (int i=0; i < num_children; i++)
00350     child(i)->set_rot(x, axis);
00351 
00352   if (!rotating())  return;
00353   // apply rotation to identity, and then multiply this by old rot matrix
00354   rotm.identity();
00355   rotm.rot(x,axis);
00356   need_matrix_recalc();
00357 }
00358 
00359 void Displayable::add_rot(const Matrix4 &m) {
00360   if (fixed())  return;         // only transform unfixed objects
00361 
00362   // do trans for all children as well
00363   for (int i=0; i < num_children; i++)
00364     child(i)->add_rot(m);
00365 
00366   if (!rotating())  return;
00367   Matrix4 mat(m);
00368   mat.multmatrix(rotm);
00369   rotm = mat;
00370   need_matrix_recalc();
00371 }
00372 
00373 void Displayable::set_rot(const Matrix4 &m) {
00374   if (fixed())  return;         // only transform unfixed objects
00375 
00376   // do trans for all children as well
00377   for (int i=0; i < num_children; i++)
00378     child(i)->set_rot(m);
00379 
00380   if (!rotating())  return;
00381   rotm = m;
00382   need_matrix_recalc();
00383 }
00384 
00385 void Displayable::set_glob_trans(float x, float y, float z) {
00386   if (fixed())  return;         // only transform unfixed objects
00387 
00388   // do trans for all children as well
00389   for (int i=0; i < num_children; i++)
00390     child(i)->set_glob_trans(x, y, z);
00391 
00392   if (!glob_translating())  return;
00393   globt[0] = x;
00394   globt[1] = y;
00395   globt[2] = z;
00396   need_matrix_recalc();
00397 }
00398 
00399 void Displayable::add_glob_trans(float x, float y, float z) {
00400   if (fixed())  return;         // only transform unfixed objects
00401 
00402   // do trans for all children as well
00403   for (int i=0; i < num_children; i++)
00404     child(i)->add_glob_trans(x, y, z);
00405 
00406   if (!glob_translating())  return;
00407   globt[0] += x;
00408   globt[1] += y;
00409   globt[2] += z;
00410   need_matrix_recalc();
00411 }
00412 
00413 void Displayable::set_cent_trans(float x, float y, float z) {
00414   // do trans for all children as well
00415   for (int i=0; i < num_children; i++)
00416     child(i)->set_cent_trans(x, y, z);
00417 
00418   if (!cent_translating())  return;
00419   centt[0] = x;
00420   centt[1] = y;
00421   centt[2] = z;
00422   need_matrix_recalc();
00423 }
00424 
00425 void Displayable::add_cent_trans(float x, float y, float z) {
00426   // do trans for all children as well
00427   for (int i=0; i < num_children; i++)
00428     child(i)->add_cent_trans(x, y, z);
00429 
00430   if (!cent_translating())  return;
00431   centt[0] += x;
00432   centt[1] += y;
00433   centt[2] += z;
00434   recalc_mat();
00435 }
00436 
00437 void Displayable::change_center(float x, float y, float z)
00438 {
00439     // Here's the math:
00440     //  T = global translation (offset) matrix
00441     //  M = scaling*rotation matrix
00442     //  C = centering (offset) matrix
00443     //  p = picked point
00444     //  x = any point
00445     // and let G = T*M*C, the global transformation
00446 
00447     // the current transformation is: T*M*C * p
00448     // I want a new T', C' such that
00449     //   C' * p = {0 0 0 1}
00450     // and
00451     //   T'*M*C' * x = T M C x
00452 
00453     // JRG: Here's my new math:
00454     // C' * p = {0 0 0 1} so T' M C' p = G p = T' M {0 0 0 1}
00455     // Hence T' = translate( G*p - M*{0 0 0 1} )
00456     // and we don't need any inverses
00457 
00458   float p[4], g[4], ident[4], m[4];
00459   ident[0]=0.0; ident[1] = 0.0; ident[2]=0.0; ident[3]=1.0;
00460   p[0]=x; p[1]=y; p[2]=z; p[3]=1.0;
00461 
00462   // Set g = G * p
00463   tm.multpoint4d(p,g);
00464 
00465   // Set m = M * {0 0 0 1}
00466   Matrix4 M(rotm);
00467   M.scale(scale);
00468   M.multpoint4d(ident, m);
00469 
00470     // and apply the result
00471   set_cent_trans(-x, -y, -z);
00472 
00473   // Set Tprime = translate(g - m)
00474   set_glob_trans(g[0]-m[0], g[1]-m[1], g[2]-m[2]);
00475 }
00476 
00477 void Displayable::change_material(const Material *mat) {
00478   _needUpdate = 1;
00479   cmdList->ambient = mat->ambient;
00480   cmdList->specular = mat->specular;
00481   cmdList->diffuse = mat->diffuse;
00482   cmdList->shininess = mat->shininess;
00483   cmdList->opacity = mat->opacity;
00484   cmdList->outline = mat->outline;
00485   cmdList->outlinewidth = mat->outlinewidth;
00486   cmdList->transmode = mat->transmode;
00487   cmdList->materialtag = mat->ind;
00488 }
00489 
00490 void Displayable::cacheskip(int onoff) {
00491   cmdList->cacheskip = onoff;
00492 }
00493 
00494 int Displayable::curr_material() const {
00495   return cmdList->materialtag;
00496 }
00497 
00498 void Displayable::update_material(const Material *mat) {
00499   if (mat->ind == curr_material()) change_material(mat);
00500   for (int i=0; i<num_children; i++) children[i]->update_material(mat);
00501 }
00502 
00503 void Displayable::delete_material(int n, const MaterialList *mlist) {
00504   if (n == curr_material()) {
00505     change_material(mlist->material(0)); // 0th material can't be deleted 
00506   }
00507   for (int i=0; i<num_children; i++) children[i]->delete_material(n, mlist);
00508 }
00509 
00510 //
00511 // routines for working as a Pickable
00512 //
00513   
00514 // return our list of draw commands with picking draw commands in them
00515 VMDDisplayList *Displayable::pick_cmd_list(void) {
00516   return cmdList;
00517 }
00518 
00519 // return whether the pickable object is being displayed
00520 int Displayable::pickable_on(void) {
00521   return displayed();
00522 }
00523 
00524 void Displayable::color_changed(int cat) {
00525   do_color_changed(cat);
00526   for (int i=0; i<num_children; i++) child(i)->color_changed(cat);
00527 }
00528 
00529 void Displayable::color_rgb_changed(int color) {
00530   do_color_rgb_changed(color);
00531   for (int i=0; i<num_children; i++) child(i)->color_rgb_changed(color);
00532 }
00533 
00534 void Displayable::color_scale_changed() {
00535   do_color_scale_changed();
00536   for (int i=0; i<num_children; i++) child(i)->color_scale_changed();
00537 }
00538 

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