Panda3D

clipPlaneAttrib.cxx

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