Panda3D
|
00001 // Filename: clipPlaneAttrib.cxx 00002 // Created by: drose (11Jul02) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "clipPlaneAttrib.h" 00016 #include "pandaNode.h" 00017 #include "graphicsStateGuardianBase.h" 00018 #include "bamReader.h" 00019 #include "bamWriter.h" 00020 #include "datagram.h" 00021 #include "datagramIterator.h" 00022 #include "config_pgraph.h" 00023 #include "attribNodeRegistry.h" 00024 00025 CPT(RenderAttrib) ClipPlaneAttrib::_empty_attrib; 00026 CPT(RenderAttrib) ClipPlaneAttrib::_all_off_attrib; 00027 TypeHandle ClipPlaneAttrib::_type_handle; 00028 int ClipPlaneAttrib::_attrib_slot; 00029 00030 // This STL Function object is used in filter_to_max(), below, to sort 00031 // a list of PlaneNodes in reverse order by priority. 00032 class ComparePlaneNodePriorities { 00033 public: 00034 bool operator ()(const NodePath &a, const NodePath &b) const { 00035 nassertr(!a.is_empty() && !b.is_empty(), a < b); 00036 PlaneNode *pa = DCAST(PlaneNode, a.node()); 00037 PlaneNode *pb = DCAST(PlaneNode, b.node()); 00038 nassertr(pa != (PlaneNode *)NULL && pb != (PlaneNode *)NULL, a < b); 00039 00040 return pa->get_priority() > pb->get_priority(); 00041 } 00042 }; 00043 00044 //////////////////////////////////////////////////////////////////// 00045 // Function: ClipPlaneAttrib::make 00046 // Access: Published, Static 00047 // Description: Constructs a new ClipPlaneAttrib object that enables (or 00048 // disables, according to op) the indicated plane(s). 00049 // 00050 // This method is now deprecated. Use add_on_plane() or 00051 // add_off_plane() instead. 00052 //////////////////////////////////////////////////////////////////// 00053 CPT(RenderAttrib) ClipPlaneAttrib:: 00054 make(ClipPlaneAttrib::Operation op, PlaneNode *plane) { 00055 pgraph_cat.warning() 00056 << "Using deprecated ClipPlaneAttrib interface.\n"; 00057 00058 CPT(RenderAttrib) attrib; 00059 00060 switch (op) { 00061 case O_set: 00062 attrib = make_all_off(); 00063 attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane)); 00064 return attrib; 00065 00066 case O_add: 00067 attrib = make(); 00068 attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane)); 00069 return attrib; 00070 00071 case O_remove: 00072 attrib = make(); 00073 attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane)); 00074 return attrib; 00075 } 00076 00077 nassertr(false, make()); 00078 return make(); 00079 } 00080 00081 //////////////////////////////////////////////////////////////////// 00082 // Function: ClipPlaneAttrib::make 00083 // Access: Published, Static 00084 // Description: Constructs a new ClipPlaneAttrib object that turns on (or 00085 // off, according to op) the indicate plane(s). 00086 // 00087 // This method is now deprecated. Use add_on_plane() or 00088 // add_off_plane() instead. 00089 //////////////////////////////////////////////////////////////////// 00090 CPT(RenderAttrib) ClipPlaneAttrib:: 00091 make(ClipPlaneAttrib::Operation op, PlaneNode *plane1, PlaneNode *plane2) { 00092 pgraph_cat.warning() 00093 << "Using deprecated ClipPlaneAttrib interface.\n"; 00094 00095 CPT(RenderAttrib) attrib; 00096 00097 switch (op) { 00098 case O_set: 00099 attrib = make_all_off(); 00100 attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane1)); 00101 attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane2)); 00102 return attrib; 00103 00104 case O_add: 00105 attrib = make(); 00106 attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane1)); 00107 attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane2)); 00108 return attrib; 00109 00110 case O_remove: 00111 attrib = make(); 00112 attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane1)); 00113 attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane2)); 00114 return attrib; 00115 } 00116 00117 nassertr(false, make()); 00118 return make(); 00119 } 00120 00121 //////////////////////////////////////////////////////////////////// 00122 // Function: ClipPlaneAttrib::make 00123 // Access: Published, Static 00124 // Description: Constructs a new ClipPlaneAttrib object that turns on (or 00125 // off, according to op) the indicate plane(s). 00126 // 00127 // This method is now deprecated. Use add_on_plane() or 00128 // add_off_plane() instead. 00129 //////////////////////////////////////////////////////////////////// 00130 CPT(RenderAttrib) ClipPlaneAttrib:: 00131 make(ClipPlaneAttrib::Operation op, PlaneNode *plane1, PlaneNode *plane2, 00132 PlaneNode *plane3) { 00133 pgraph_cat.warning() 00134 << "Using deprecated ClipPlaneAttrib interface.\n"; 00135 00136 CPT(RenderAttrib) attrib; 00137 00138 switch (op) { 00139 case O_set: 00140 attrib = make_all_off(); 00141 attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane1)); 00142 attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane2)); 00143 attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane3)); 00144 return attrib; 00145 00146 case O_add: 00147 attrib = make(); 00148 attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane1)); 00149 attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane2)); 00150 attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane3)); 00151 return attrib; 00152 00153 case O_remove: 00154 attrib = make(); 00155 attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane1)); 00156 attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane2)); 00157 attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane3)); 00158 return attrib; 00159 } 00160 00161 nassertr(false, make()); 00162 return make(); 00163 } 00164 00165 //////////////////////////////////////////////////////////////////// 00166 // Function: ClipPlaneAttrib::make 00167 // Access: Published, Static 00168 // Description: Constructs a new ClipPlaneAttrib object that turns on (or 00169 // off, according to op) the indicate plane(s). 00170 // 00171 // This method is now deprecated. Use add_on_plane() or 00172 // add_off_plane() instead. 00173 //////////////////////////////////////////////////////////////////// 00174 CPT(RenderAttrib) ClipPlaneAttrib:: 00175 make(ClipPlaneAttrib::Operation op, PlaneNode *plane1, PlaneNode *plane2, 00176 PlaneNode *plane3, PlaneNode *plane4) { 00177 pgraph_cat.warning() 00178 << "Using deprecated ClipPlaneAttrib interface.\n"; 00179 00180 CPT(RenderAttrib) attrib; 00181 00182 switch (op) { 00183 case O_set: 00184 attrib = make_all_off(); 00185 attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane1)); 00186 attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane2)); 00187 attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane3)); 00188 attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane4)); 00189 return attrib; 00190 00191 case O_add: 00192 attrib = make(); 00193 attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane1)); 00194 attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane2)); 00195 attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane3)); 00196 attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane4)); 00197 return attrib; 00198 00199 case O_remove: 00200 attrib = make(); 00201 attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane1)); 00202 attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane2)); 00203 attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane3)); 00204 attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane4)); 00205 return attrib; 00206 } 00207 00208 nassertr(false, make()); 00209 return make(); 00210 } 00211 00212 //////////////////////////////////////////////////////////////////// 00213 // Function: ClipPlaneAttrib::make_default 00214 // Access: Published, Static 00215 // Description: Returns a RenderAttrib that corresponds to whatever 00216 // the standard default properties for render attributes 00217 // of this type ought to be. 00218 //////////////////////////////////////////////////////////////////// 00219 CPT(RenderAttrib) ClipPlaneAttrib:: 00220 make_default() { 00221 return return_new(new ClipPlaneAttrib); 00222 } 00223 00224 //////////////////////////////////////////////////////////////////// 00225 // Function: ClipPlaneAttrib::get_operation 00226 // Access: Published 00227 // Description: Returns the basic operation type of the ClipPlaneAttrib. 00228 // If this is O_set, the planes listed here completely 00229 // replace any planes that were already on. If this is 00230 // O_add, the planes here are added to the set of of 00231 // planes that were already on, and if O_remove, the 00232 // planes here are removed from the set of planes that 00233 // were on. 00234 // 00235 // This method is now deprecated. ClipPlaneAttribs 00236 // nowadays have a separate list of on_planes and 00237 // off_planes, so this method doesn't make sense. Query 00238 // the lists independently. 00239 //////////////////////////////////////////////////////////////////// 00240 ClipPlaneAttrib::Operation ClipPlaneAttrib:: 00241 get_operation() const { 00242 pgraph_cat.warning() 00243 << "Using deprecated ClipPlaneAttrib interface.\n"; 00244 00245 if (has_all_off()) { 00246 return O_set; 00247 00248 } else if (get_num_off_planes() == 0) { 00249 return O_add; 00250 00251 } else { 00252 return O_remove; 00253 } 00254 } 00255 00256 //////////////////////////////////////////////////////////////////// 00257 // Function: ClipPlaneAttrib::get_num_planes 00258 // Access: Published 00259 // Description: Returns the number of planes listed in the attribute. 00260 // 00261 // This method is now deprecated. ClipPlaneAttribs 00262 // nowadays have a separate list of on_planes and 00263 // off_planes, so this method doesn't make sense. Query 00264 // the lists independently. 00265 //////////////////////////////////////////////////////////////////// 00266 int ClipPlaneAttrib:: 00267 get_num_planes() const { 00268 pgraph_cat.warning() 00269 << "Using deprecated ClipPlaneAttrib interface.\n"; 00270 00271 if (get_num_off_planes() == 0) { 00272 return get_num_on_planes(); 00273 } else { 00274 return get_num_off_planes(); 00275 } 00276 } 00277 00278 //////////////////////////////////////////////////////////////////// 00279 // Function: ClipPlaneAttrib::get_plane 00280 // Access: Published 00281 // Description: Returns the nth plane listed in the attribute. 00282 // 00283 // This method is now deprecated. ClipPlaneAttribs 00284 // nowadays have a separate list of on_planes and 00285 // off_planes, so this method doesn't make sense. Query 00286 // the lists independently. 00287 //////////////////////////////////////////////////////////////////// 00288 PlaneNode *ClipPlaneAttrib:: 00289 get_plane(int n) const { 00290 pgraph_cat.warning() 00291 << "Using deprecated ClipPlaneAttrib interface.\n"; 00292 00293 if (get_num_off_planes() == 0) { 00294 return DCAST(PlaneNode, get_on_plane(n).node()); 00295 } else { 00296 return DCAST(PlaneNode, get_off_plane(n).node()); 00297 } 00298 } 00299 00300 //////////////////////////////////////////////////////////////////// 00301 // Function: ClipPlaneAttrib::has_plane 00302 // Access: Published 00303 // Description: Returns true if the indicated plane is listed in the 00304 // attrib, false otherwise. 00305 // 00306 // This method is now deprecated. ClipPlaneAttribs 00307 // nowadays have a separate list of on_planes and 00308 // off_planes, so this method doesn't make sense. Query 00309 // the lists independently. 00310 //////////////////////////////////////////////////////////////////// 00311 bool ClipPlaneAttrib:: 00312 has_plane(PlaneNode *plane) const { 00313 pgraph_cat.warning() 00314 << "Using deprecated ClipPlaneAttrib interface.\n"; 00315 00316 if (get_num_off_planes() == 0) { 00317 return has_on_plane(NodePath(plane)); 00318 } else { 00319 return has_off_plane(NodePath(plane)); 00320 } 00321 } 00322 00323 //////////////////////////////////////////////////////////////////// 00324 // Function: ClipPlaneAttrib::add_plane 00325 // Access: Published 00326 // Description: Returns a new ClipPlaneAttrib, just like this one, but 00327 // with the indicated plane added to the list of planes. 00328 // 00329 // This method is now deprecated. Use add_on_plane() or 00330 // add_off_plane() instead. 00331 //////////////////////////////////////////////////////////////////// 00332 CPT(RenderAttrib) ClipPlaneAttrib:: 00333 add_plane(PlaneNode *plane) const { 00334 pgraph_cat.warning() 00335 << "Using deprecated ClipPlaneAttrib interface.\n"; 00336 00337 if (get_num_off_planes() == 0) { 00338 return add_on_plane(NodePath(plane)); 00339 } else { 00340 return add_off_plane(NodePath(plane)); 00341 } 00342 } 00343 00344 //////////////////////////////////////////////////////////////////// 00345 // Function: ClipPlaneAttrib::remove_plane 00346 // Access: Published 00347 // Description: Returns a new ClipPlaneAttrib, just like this one, but 00348 // with the indicated plane removed from the list of 00349 // planes. 00350 // 00351 // This method is now deprecated. Use remove_on_plane() 00352 // or remove_off_plane() instead. 00353 //////////////////////////////////////////////////////////////////// 00354 CPT(RenderAttrib) ClipPlaneAttrib:: 00355 remove_plane(PlaneNode *plane) const { 00356 pgraph_cat.warning() 00357 << "Using deprecated ClipPlaneAttrib interface.\n"; 00358 00359 if (get_num_off_planes() == 0) { 00360 return remove_on_plane(NodePath(plane)); 00361 } else { 00362 return remove_off_plane(NodePath(plane)); 00363 } 00364 } 00365 00366 //////////////////////////////////////////////////////////////////// 00367 // Function: ClipPlaneAttrib::make 00368 // Access: Published, Static 00369 // Description: Constructs a new ClipPlaneAttrib object that does 00370 // nothing. 00371 //////////////////////////////////////////////////////////////////// 00372 CPT(RenderAttrib) ClipPlaneAttrib:: 00373 make() { 00374 // We make it a special case and store a pointer to the empty attrib 00375 // forever once we find it the first time, as an optimization. 00376 if (_empty_attrib == (RenderAttrib *)NULL) { 00377 _empty_attrib = return_new(new ClipPlaneAttrib); 00378 } 00379 00380 return _empty_attrib; 00381 } 00382 00383 //////////////////////////////////////////////////////////////////// 00384 // Function: ClipPlaneAttrib::make_all_off 00385 // Access: Published, Static 00386 // Description: Constructs a new ClipPlaneAttrib object that disables 00387 // all planes (and hence disables clipping). 00388 //////////////////////////////////////////////////////////////////// 00389 CPT(RenderAttrib) ClipPlaneAttrib:: 00390 make_all_off() { 00391 // We make it a special case and store a pointer to the off attrib 00392 // forever once we find it the first time, as an optimization. 00393 if (_all_off_attrib == (RenderAttrib *)NULL) { 00394 ClipPlaneAttrib *attrib = new ClipPlaneAttrib; 00395 attrib->_off_all_planes = true; 00396 _all_off_attrib = return_new(attrib); 00397 } 00398 00399 return _all_off_attrib; 00400 } 00401 00402 //////////////////////////////////////////////////////////////////// 00403 // Function: ClipPlaneAttrib::add_on_plane 00404 // Access: Published 00405 // Description: Returns a new ClipPlaneAttrib, just like this one, but 00406 // with the indicated plane added to the list of planes 00407 // enabled by this attrib. 00408 //////////////////////////////////////////////////////////////////// 00409 CPT(RenderAttrib) ClipPlaneAttrib:: 00410 add_on_plane(const NodePath &plane) const { 00411 nassertr(!plane.is_empty() && plane.node()->is_of_type(PlaneNode::get_class_type()), this); 00412 ClipPlaneAttrib *attrib = new ClipPlaneAttrib(*this); 00413 attrib->_on_planes.insert(plane); 00414 attrib->_off_planes.erase(plane); 00415 00416 pair<Planes::iterator, bool> insert_result = 00417 attrib->_on_planes.insert(Planes::value_type(plane)); 00418 if (insert_result.second) { 00419 // Also ensure it is removed from the off_planes list. 00420 attrib->_off_planes.erase(plane); 00421 } 00422 00423 return return_new(attrib); 00424 } 00425 00426 //////////////////////////////////////////////////////////////////// 00427 // Function: ClipPlaneAttrib::remove_on_plane 00428 // Access: Published 00429 // Description: Returns a new ClipPlaneAttrib, just like this one, but 00430 // with the indicated plane removed from the list of 00431 // planes enabled by this attrib. 00432 //////////////////////////////////////////////////////////////////// 00433 CPT(RenderAttrib) ClipPlaneAttrib:: 00434 remove_on_plane(const NodePath &plane) const { 00435 nassertr(!plane.is_empty() && plane.node()->is_of_type(PlaneNode::get_class_type()), this); 00436 ClipPlaneAttrib *attrib = new ClipPlaneAttrib(*this); 00437 attrib->_on_planes.erase(plane); 00438 return return_new(attrib); 00439 } 00440 00441 //////////////////////////////////////////////////////////////////// 00442 // Function: ClipPlaneAttrib::add_off_plane 00443 // Access: Published 00444 // Description: Returns a new ClipPlaneAttrib, just like this one, but 00445 // with the indicated plane added to the list of planes 00446 // disabled by this attrib. 00447 //////////////////////////////////////////////////////////////////// 00448 CPT(RenderAttrib) ClipPlaneAttrib:: 00449 add_off_plane(const NodePath &plane) const { 00450 nassertr(!plane.is_empty() && plane.node()->is_of_type(PlaneNode::get_class_type()), this); 00451 ClipPlaneAttrib *attrib = new ClipPlaneAttrib(*this); 00452 if (!_off_all_planes) { 00453 attrib->_off_planes.insert(plane); 00454 } 00455 attrib->_on_planes.erase(plane); 00456 return return_new(attrib); 00457 } 00458 00459 //////////////////////////////////////////////////////////////////// 00460 // Function: ClipPlaneAttrib::remove_off_plane 00461 // Access: Published 00462 // Description: Returns a new ClipPlaneAttrib, just like this one, but 00463 // with the indicated plane removed from the list of 00464 // planes disabled by this attrib. 00465 //////////////////////////////////////////////////////////////////// 00466 CPT(RenderAttrib) ClipPlaneAttrib:: 00467 remove_off_plane(const NodePath &plane) const { 00468 nassertr(!plane.is_empty() && plane.node()->is_of_type(PlaneNode::get_class_type()), this); 00469 ClipPlaneAttrib *attrib = new ClipPlaneAttrib(*this); 00470 attrib->_off_planes.erase(plane); 00471 return return_new(attrib); 00472 } 00473 00474 //////////////////////////////////////////////////////////////////// 00475 // Function: ClipPlaneAttrib::filter_to_max 00476 // Access: Public 00477 // Description: Returns a new ClipPlaneAttrib, very much like this one, 00478 // but with the number of on_planes reduced to be no 00479 // more than max_clip_planes. The number of off_planes in 00480 // the new ClipPlaneAttrib is undefined. 00481 //////////////////////////////////////////////////////////////////// 00482 CPT(ClipPlaneAttrib) ClipPlaneAttrib:: 00483 filter_to_max(int max_clip_planes) const { 00484 if (max_clip_planes < 0 || (int)_on_planes.size() <= max_clip_planes) { 00485 // Trivial case: this ClipPlaneAttrib qualifies. 00486 return this; 00487 } 00488 00489 // Since check_filtered() will clear the _filtered list if we are out 00490 // of date, we should call it first. 00491 check_filtered(); 00492 00493 Filtered::const_iterator fi; 00494 fi = _filtered.find(max_clip_planes); 00495 if (fi != _filtered.end()) { 00496 // Easy case: we have already computed this for this particular 00497 // ClipPlaneAttrib. 00498 return (*fi).second; 00499 } 00500 00501 // Harder case: we have to compute it now. We must choose the n 00502 // planeNodes with the highest priority in our list of planeNodes. 00503 Planes priority_planes = _on_planes; 00504 00505 // This sort function uses the STL function object defined above. 00506 sort(priority_planes.begin(), priority_planes.end(), 00507 ComparePlaneNodePriorities()); 00508 00509 // Now lop off all of the planeNodes after the first max_clip_planes. 00510 priority_planes.erase(priority_planes.begin() + max_clip_planes, 00511 priority_planes.end()); 00512 00513 // And re-sort the ov_set into its proper order. 00514 priority_planes.sort(); 00515 00516 // Now create a new attrib reflecting these planeNodes. 00517 PT(ClipPlaneAttrib) attrib = new ClipPlaneAttrib; 00518 attrib->_on_planes.swap(priority_planes); 00519 00520 CPT(RenderAttrib) new_attrib = return_new(attrib); 00521 00522 // Finally, record this newly-created attrib in the map for next 00523 // time. 00524 CPT(ClipPlaneAttrib) planeNode_attrib = (const ClipPlaneAttrib *)new_attrib.p(); 00525 ((ClipPlaneAttrib *)this)->_filtered[max_clip_planes] = planeNode_attrib; 00526 return planeNode_attrib; 00527 } 00528 00529 //////////////////////////////////////////////////////////////////// 00530 // Function: ClipPlaneAttrib::compose_off 00531 // Access: Public 00532 // Description: This is a special method which composes two 00533 // ClipPlaneAttribs with regard only to their set of 00534 // "off" clip planes, for the purposes of deriving 00535 // PandaNode::get_off_clip_planes(). 00536 // 00537 // The result will be a ClipPlaneAttrib that represents 00538 // the union of all of the clip planes turned off in 00539 // either attrib. The set of on planes in the result is 00540 // undefined and should be ignored. 00541 //////////////////////////////////////////////////////////////////// 00542 CPT(RenderAttrib) ClipPlaneAttrib:: 00543 compose_off(const RenderAttrib *other) const { 00544 const ClipPlaneAttrib *ta; 00545 DCAST_INTO_R(ta, other, 0); 00546 00547 if (_off_all_planes || (!ta->_off_all_planes && ta->_off_planes.empty())) { 00548 // If we turn off all planes, or the other turns none off, the 00549 // result is the same as this one. 00550 return this; 00551 } 00552 00553 if (ta->_off_all_planes || _off_planes.empty()) { 00554 // And contrariwise. 00555 return ta; 00556 } 00557 00558 Planes::const_iterator ai = _off_planes.begin(); 00559 Planes::const_iterator bi = ta->_off_planes.begin(); 00560 00561 // Create a new ClipPlaneAttrib that will hold the result. 00562 ClipPlaneAttrib *new_attrib = new ClipPlaneAttrib; 00563 back_insert_iterator<Planes> result = 00564 back_inserter(new_attrib->_on_planes); 00565 00566 while (ai != _off_planes.end() && 00567 bi != ta->_off_planes.end()) { 00568 if ((*ai) < (*bi)) { 00569 // Here is a plane that we have in the original, which is not 00570 // present in the secondary. 00571 *result = *ai; 00572 ++ai; 00573 ++result; 00574 00575 } else if ((*bi) < (*ai)) { 00576 // Here is a new plane we have in the secondary, that was not 00577 // present in the original. 00578 *result = *bi; 00579 ++bi; 00580 ++result; 00581 00582 } else { // (*bi) == (*ai) 00583 // Here is a plane we have in both. 00584 *result = *bi; 00585 ++ai; 00586 ++bi; 00587 ++result; 00588 } 00589 } 00590 00591 while (ai != _off_planes.end()) { 00592 *result = *ai; 00593 ++ai; 00594 ++result; 00595 } 00596 00597 while (bi != ta->_off_planes.end()) { 00598 *result = *bi; 00599 ++bi; 00600 ++result; 00601 } 00602 00603 return return_new(new_attrib); 00604 } 00605 00606 //////////////////////////////////////////////////////////////////// 00607 // Function: ClipPlaneAttrib::output 00608 // Access: Public, Virtual 00609 // Description: 00610 //////////////////////////////////////////////////////////////////// 00611 void ClipPlaneAttrib:: 00612 output(ostream &out) const { 00613 out << get_type() << ":"; 00614 if (_off_planes.empty()) { 00615 if (_on_planes.empty()) { 00616 if (_off_all_planes) { 00617 out << "all off"; 00618 } else { 00619 out << "identity"; 00620 } 00621 } else { 00622 if (_off_all_planes) { 00623 out << "set"; 00624 } else { 00625 out << "on"; 00626 } 00627 } 00628 00629 } else { 00630 out << "off"; 00631 Planes::const_iterator fi; 00632 for (fi = _off_planes.begin(); fi != _off_planes.end(); ++fi) { 00633 NodePath plane = (*fi); 00634 out << " " << plane; 00635 } 00636 00637 if (!_on_planes.empty()) { 00638 out << " on"; 00639 } 00640 } 00641 00642 Planes::const_iterator li; 00643 for (li = _on_planes.begin(); li != _on_planes.end(); ++li) { 00644 NodePath plane = (*li); 00645 out << " " << plane; 00646 } 00647 } 00648 00649 //////////////////////////////////////////////////////////////////// 00650 // Function: ClipPlaneAttrib::compare_to_impl 00651 // Access: Protected, Virtual 00652 // Description: Intended to be overridden by derived ClipPlaneAttrib 00653 // types to return a unique number indicating whether 00654 // this ClipPlaneAttrib is equivalent to the other one. 00655 // 00656 // This should return 0 if the two ClipPlaneAttrib 00657 // objects are equivalent, a number less than zero if 00658 // this one should be sorted before the other one, and a 00659 // number greater than zero otherwise. 00660 // 00661 // This will only be called with two ClipPlaneAttrib 00662 // objects whose get_type() functions return the same. 00663 //////////////////////////////////////////////////////////////////// 00664 int ClipPlaneAttrib:: 00665 compare_to_impl(const RenderAttrib *other) const { 00666 const ClipPlaneAttrib *ta; 00667 DCAST_INTO_R(ta, other, 0); 00668 00669 if (_off_all_planes != ta->_off_all_planes) { 00670 return (int)_off_all_planes - (int)ta->_off_all_planes; 00671 } 00672 00673 Planes::const_iterator li = _on_planes.begin(); 00674 Planes::const_iterator oli = ta->_on_planes.begin(); 00675 00676 while (li != _on_planes.end() && oli != ta->_on_planes.end()) { 00677 NodePath plane = (*li); 00678 NodePath other_plane = (*oli); 00679 00680 int compare = plane.compare_to(other_plane); 00681 if (compare != 0) { 00682 return compare; 00683 } 00684 00685 ++li; 00686 ++oli; 00687 } 00688 00689 if (li != _on_planes.end()) { 00690 return 1; 00691 } 00692 if (oli != ta->_on_planes.end()) { 00693 return -1; 00694 } 00695 00696 Planes::const_iterator fi = _off_planes.begin(); 00697 Planes::const_iterator ofi = ta->_off_planes.begin(); 00698 00699 while (fi != _off_planes.end() && ofi != ta->_off_planes.end()) { 00700 NodePath plane = (*fi); 00701 NodePath other_plane = (*ofi); 00702 00703 int compare = plane.compare_to(other_plane); 00704 if (compare != 0) { 00705 return compare; 00706 } 00707 00708 ++fi; 00709 ++ofi; 00710 } 00711 00712 if (fi != _off_planes.end()) { 00713 return 1; 00714 } 00715 if (ofi != ta->_off_planes.end()) { 00716 return -1; 00717 } 00718 00719 return 0; 00720 } 00721 00722 //////////////////////////////////////////////////////////////////// 00723 // Function: ClipPlaneAttrib::compose_impl 00724 // Access: Protected, Virtual 00725 // Description: Intended to be overridden by derived RenderAttrib 00726 // types to specify how two consecutive RenderAttrib 00727 // objects of the same type interact. 00728 // 00729 // This should return the result of applying the other 00730 // RenderAttrib to a node in the scene graph below this 00731 // RenderAttrib, which was already applied. In most 00732 // cases, the result is the same as the other 00733 // RenderAttrib (that is, a subsequent RenderAttrib 00734 // completely replaces the preceding one). On the other 00735 // hand, some kinds of RenderAttrib (for instance, 00736 // ColorTransformAttrib) might combine in meaningful 00737 // ways. 00738 //////////////////////////////////////////////////////////////////// 00739 CPT(RenderAttrib) ClipPlaneAttrib:: 00740 compose_impl(const RenderAttrib *other) const { 00741 const ClipPlaneAttrib *ta; 00742 DCAST_INTO_R(ta, other, 0); 00743 00744 if (ta->_off_all_planes) { 00745 // If the other type turns off all planes, it doesn't matter what 00746 // we are. 00747 return ta; 00748 } 00749 00750 // This is a three-way merge between ai, bi, and ci, except that bi 00751 // and ci should have no intersection and therefore needn't be 00752 // compared to each other. 00753 Planes::const_iterator ai = _on_planes.begin(); 00754 Planes::const_iterator bi = ta->_on_planes.begin(); 00755 Planes::const_iterator ci = ta->_off_planes.begin(); 00756 00757 // Create a new ClipPlaneAttrib that will hold the result. 00758 ClipPlaneAttrib *new_attrib = new ClipPlaneAttrib; 00759 back_insert_iterator<Planes> result = 00760 back_inserter(new_attrib->_on_planes); 00761 00762 while (ai != _on_planes.end() && 00763 bi != ta->_on_planes.end() && 00764 ci != ta->_off_planes.end()) { 00765 if ((*ai) < (*bi)) { 00766 if ((*ai) < (*ci)) { 00767 // Here is a plane that we have in the original, which is not 00768 // present in the secondary. 00769 *result = *ai; 00770 ++ai; 00771 ++result; 00772 00773 } else if ((*ci) < (*ai)) { 00774 // Here is a plane that is disabled in the secondary, but 00775 // was not present in the original. 00776 ++ci; 00777 00778 } else { // (*ci) == (*ai) 00779 // Here is a plane that is disabled in the secondary, and 00780 // was present in the original. 00781 ++ai; 00782 ++ci; 00783 } 00784 00785 } else if ((*bi) < (*ai)) { 00786 // Here is a new plane we have in the secondary, that was not 00787 // present in the original. 00788 *result = *bi; 00789 ++bi; 00790 ++result; 00791 00792 } else { // (*bi) == (*ai) 00793 // Here is a plane we have in both. 00794 *result = *bi; 00795 ++ai; 00796 ++bi; 00797 ++result; 00798 } 00799 } 00800 00801 while (ai != _on_planes.end() && bi != ta->_on_planes.end()) { 00802 if ((*ai) < (*bi)) { 00803 // Here is a plane that we have in the original, which is not 00804 // present in the secondary. 00805 *result = *ai; 00806 ++ai; 00807 ++result; 00808 00809 } else if ((*bi) < (*ai)) { 00810 // Here is a new plane we have in the secondary, that was not 00811 // present in the original. 00812 *result = *bi; 00813 ++bi; 00814 ++result; 00815 00816 } else { 00817 // Here is a plane we have in both. 00818 *result = *bi; 00819 ++ai; 00820 ++bi; 00821 ++result; 00822 } 00823 } 00824 00825 while (ai != _on_planes.end() && ci != ta->_off_planes.end()) { 00826 if ((*ai) < (*ci)) { 00827 // Here is a plane that we have in the original, which is not 00828 // present in the secondary. 00829 *result = *ai; 00830 ++ai; 00831 ++result; 00832 00833 } else if ((*ci) < (*ai)) { 00834 // Here is a plane that is disabled in the secondary, but 00835 // was not present in the original. 00836 ++ci; 00837 00838 } else { // (*ci) == (*ai) 00839 // Here is a plane that is disabled in the secondary, and 00840 // was present in the original. 00841 ++ai; 00842 ++ci; 00843 } 00844 } 00845 00846 while (ai != _on_planes.end()) { 00847 *result = *ai; 00848 ++ai; 00849 ++result; 00850 } 00851 00852 while (bi != ta->_on_planes.end()) { 00853 *result = *bi; 00854 ++bi; 00855 ++result; 00856 } 00857 00858 return return_new(new_attrib); 00859 } 00860 00861 //////////////////////////////////////////////////////////////////// 00862 // Function: ClipPlaneAttrib::invert_compose_impl 00863 // Access: Protected, Virtual 00864 // Description: Intended to be overridden by derived RenderAttrib 00865 // types to specify how two consecutive RenderAttrib 00866 // objects of the same type interact. 00867 // 00868 // See invert_compose() and compose_impl(). 00869 //////////////////////////////////////////////////////////////////// 00870 CPT(RenderAttrib) ClipPlaneAttrib:: 00871 invert_compose_impl(const RenderAttrib *other) const { 00872 // I think in this case the other attrib always wins. Maybe this 00873 // needs a bit more thought. It's hard to imagine that it's even 00874 // important to compute this properly. 00875 return other; 00876 } 00877 00878 //////////////////////////////////////////////////////////////////// 00879 // Function: ClipPlaneAttrib::sort_on_planes 00880 // Access: Private 00881 // Description: This is patterned after 00882 // TextureAttrib::sort_on_stages(), but since planeNodes 00883 // don't actually require sorting, this only empties the 00884 // _filtered map. 00885 //////////////////////////////////////////////////////////////////// 00886 void ClipPlaneAttrib:: 00887 sort_on_planes() { 00888 _sort_seq = PlaneNode::get_sort_seq(); 00889 _filtered.clear(); 00890 } 00891 00892 //////////////////////////////////////////////////////////////////// 00893 // Function: ClipPlaneAttrib::register_with_read_factory 00894 // Access: Public, Static 00895 // Description: Tells the BamReader how to create objects of type 00896 // ClipPlaneAttrib. 00897 //////////////////////////////////////////////////////////////////// 00898 void ClipPlaneAttrib:: 00899 register_with_read_factory() { 00900 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); 00901 } 00902 00903 //////////////////////////////////////////////////////////////////// 00904 // Function: ClipPlaneAttrib::write_datagram 00905 // Access: Public, Virtual 00906 // Description: Writes the contents of this object to the datagram 00907 // for shipping out to a Bam file. 00908 //////////////////////////////////////////////////////////////////// 00909 void ClipPlaneAttrib:: 00910 write_datagram(BamWriter *manager, Datagram &dg) { 00911 RenderAttrib::write_datagram(manager, dg); 00912 00913 dg.add_bool(_off_all_planes); 00914 00915 // write the number of off_planes 00916 dg.add_uint16(get_num_off_planes()); 00917 // write the off planes pointers if any 00918 Planes::const_iterator fi; 00919 for (fi = _off_planes.begin(); fi != _off_planes.end(); ++fi) { 00920 NodePath plane = (*fi); 00921 00922 // Since we can't write out a NodePath, we write out just the 00923 // plain PandaNode. The user can use the AttribNodeRegistry on 00924 // re-read if there is any ambiguity that needs to be resolved. 00925 manager->write_pointer(dg, plane.node()); 00926 } 00927 00928 // write the number of on planes 00929 dg.add_uint16(get_num_on_planes()); 00930 // write the on planes pointers if any 00931 Planes::const_iterator nti; 00932 for (nti = _on_planes.begin(); nti != _on_planes.end(); ++nti) { 00933 NodePath plane = (*nti); 00934 manager->write_pointer(dg, plane.node()); 00935 } 00936 } 00937 00938 //////////////////////////////////////////////////////////////////// 00939 // Function: ClipPlaneAttrib::complete_pointers 00940 // Access: Public, Virtual 00941 // Description: Receives an array of pointers, one for each time 00942 // manager->read_pointer() was called in fillin(). 00943 // Returns the number of pointers processed. 00944 //////////////////////////////////////////////////////////////////// 00945 int ClipPlaneAttrib:: 00946 complete_pointers(TypedWritable **p_list, BamReader *manager) { 00947 int pi = RenderAttrib::complete_pointers(p_list, manager); 00948 AttribNodeRegistry *areg = AttribNodeRegistry::get_global_ptr(); 00949 00950 Planes::iterator ci = _off_planes.begin(); 00951 while (ci != _off_planes.end()) { 00952 PandaNode *node; 00953 DCAST_INTO_R(node, p_list[pi++], pi); 00954 00955 // We go through some effort to look up the node in the registry 00956 // without creating a NodePath around it first (which would up, 00957 // and then down, the reference count, possibly deleting the 00958 // node). 00959 int ni = areg->find_node(node->get_type(), node->get_name()); 00960 if (ni != -1) { 00961 (*ci) = areg->get_node(ni); 00962 } else { 00963 (*ci) = NodePath(node); 00964 } 00965 ++ci; 00966 } 00967 _off_planes.sort(); 00968 00969 ci = _on_planes.begin(); 00970 while (ci != _on_planes.end()) { 00971 PandaNode *node; 00972 DCAST_INTO_R(node, p_list[pi++], pi); 00973 00974 int ni = areg->find_node(node->get_type(), node->get_name()); 00975 if (ni != -1) { 00976 (*ci) = areg->get_node(ni); 00977 } else { 00978 (*ci) = NodePath(node); 00979 } 00980 ++ci; 00981 } 00982 _on_planes.sort(); 00983 00984 return pi; 00985 } 00986 00987 //////////////////////////////////////////////////////////////////// 00988 // Function: ClipPlaneAttrib::require_fully_complete 00989 // Access: Public, Virtual 00990 // Description: Some objects require all of their nested pointers to 00991 // have been completed before the objects themselves can 00992 // be completed. If this is the case, override this 00993 // method to return true, and be careful with circular 00994 // references (which would make the object unreadable 00995 // from a bam file). 00996 //////////////////////////////////////////////////////////////////// 00997 bool ClipPlaneAttrib:: 00998 require_fully_complete() const { 00999 return true; 01000 } 01001 01002 //////////////////////////////////////////////////////////////////// 01003 // Function: ClipPlaneAttrib::make_from_bam 01004 // Access: Protected, Static 01005 // Description: This function is called by the BamReader's factory 01006 // when a new object of type ClipPlaneAttrib is encountered 01007 // in the Bam file. It should create the ClipPlaneAttrib 01008 // and extract its information from the file. 01009 //////////////////////////////////////////////////////////////////// 01010 TypedWritable *ClipPlaneAttrib:: 01011 make_from_bam(const FactoryParams ¶ms) { 01012 ClipPlaneAttrib *attrib = new ClipPlaneAttrib; 01013 DatagramIterator scan; 01014 BamReader *manager; 01015 01016 parse_params(params, scan, manager); 01017 attrib->fillin(scan, manager); 01018 01019 return attrib; 01020 } 01021 01022 //////////////////////////////////////////////////////////////////// 01023 // Function: ClipPlaneAttrib::fillin 01024 // Access: Protected 01025 // Description: This internal function is called by make_from_bam to 01026 // read in all of the relevant data from the BamFile for 01027 // the new ClipPlaneAttrib. 01028 //////////////////////////////////////////////////////////////////// 01029 void ClipPlaneAttrib:: 01030 fillin(DatagramIterator &scan, BamReader *manager) { 01031 RenderAttrib::fillin(scan, manager); 01032 01033 // We cheat a little bit here. In the middle of bam version 4.10, 01034 // we completely redefined the bam storage definition for 01035 // ClipPlaneAttribs, without bothering to up the bam version or even to 01036 // attempt to read the old definition. We get away with this, 01037 // knowing that the egg loader doesn't create ClipPlaneAttribs, and 01038 // hence no old bam files have the old definition for ClipPlaneAttrib 01039 // within them. 01040 01041 _off_all_planes = scan.get_bool(); 01042 01043 int num_off_planes = scan.get_uint16(); 01044 01045 // Push back an empty NodePath for each off Plane for now, until we 01046 // get the actual list of pointers later in complete_pointers(). 01047 _off_planes.reserve(num_off_planes); 01048 int i; 01049 for (i = 0; i < num_off_planes; i++) { 01050 manager->read_pointer(scan); 01051 _off_planes.push_back(NodePath()); 01052 } 01053 01054 int num_on_planes = scan.get_uint16(); 01055 _on_planes.reserve(num_on_planes); 01056 for (i = 0; i < num_on_planes; i++) { 01057 manager->read_pointer(scan); 01058 _on_planes.push_back(NodePath()); 01059 } 01060 }