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