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 
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 &params) {
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 }
 All Classes Functions Variables Enumerations