Panda3D
 All Classes Functions Variables Enumerations
clipPlaneAttrib.cxx
1 // Filename: clipPlaneAttrib.cxx
2 // Created by: drose (11Jul02)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "clipPlaneAttrib.h"
16 #include "pandaNode.h"
17 #include "graphicsStateGuardianBase.h"
18 #include "bamReader.h"
19 #include "bamWriter.h"
20 #include "datagram.h"
21 #include "datagramIterator.h"
22 #include "config_pgraph.h"
23 #include "attribNodeRegistry.h"
24 #include <iterator>
25 
26 CPT(RenderAttrib) ClipPlaneAttrib::_empty_attrib;
27 CPT(RenderAttrib) ClipPlaneAttrib::_all_off_attrib;
28 TypeHandle ClipPlaneAttrib::_type_handle;
29 int ClipPlaneAttrib::_attrib_slot;
30 
31 // This STL Function object is used in filter_to_max(), below, to sort
32 // a list of PlaneNodes in reverse order by priority.
34 public:
35  bool operator ()(const NodePath &a, const NodePath &b) const {
36  nassertr(!a.is_empty() && !b.is_empty(), a < b);
37  PlaneNode *pa = DCAST(PlaneNode, a.node());
38  PlaneNode *pb = DCAST(PlaneNode, b.node());
39  nassertr(pa != (PlaneNode *)NULL && pb != (PlaneNode *)NULL, a < b);
40 
41  return pa->get_priority() > pb->get_priority();
42  }
43 };
44 
45 ////////////////////////////////////////////////////////////////////
46 // Function: ClipPlaneAttrib::make
47 // Access: Published, Static
48 // Description: Constructs a new ClipPlaneAttrib object that enables (or
49 // disables, according to op) the indicated plane(s).
50 //
51 // This method is now deprecated. Use add_on_plane() or
52 // add_off_plane() instead.
53 ////////////////////////////////////////////////////////////////////
55 make(ClipPlaneAttrib::Operation op, PlaneNode *plane) {
56  pgraph_cat.warning()
57  << "Using deprecated ClipPlaneAttrib interface.\n";
58 
59  CPT(RenderAttrib) attrib;
60 
61  switch (op) {
62  case O_set:
63  attrib = make_all_off();
64  attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane));
65  return attrib;
66 
67  case O_add:
68  attrib = make();
69  attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane));
70  return attrib;
71 
72  case O_remove:
73  attrib = make();
74  attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane));
75  return attrib;
76  }
77 
78  nassertr(false, make());
79  return make();
80 }
81 
82 ////////////////////////////////////////////////////////////////////
83 // Function: ClipPlaneAttrib::make
84 // Access: Published, Static
85 // Description: Constructs a new ClipPlaneAttrib object that turns on (or
86 // off, according to op) the indicate plane(s).
87 //
88 // This method is now deprecated. Use add_on_plane() or
89 // add_off_plane() instead.
90 ////////////////////////////////////////////////////////////////////
92 make(ClipPlaneAttrib::Operation op, PlaneNode *plane1, PlaneNode *plane2) {
93  pgraph_cat.warning()
94  << "Using deprecated ClipPlaneAttrib interface.\n";
95 
96  CPT(RenderAttrib) attrib;
97 
98  switch (op) {
99  case O_set:
100  attrib = make_all_off();
101  attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane1));
102  attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane2));
103  return attrib;
104 
105  case O_add:
106  attrib = make();
107  attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane1));
108  attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane2));
109  return attrib;
110 
111  case O_remove:
112  attrib = make();
113  attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane1));
114  attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane2));
115  return attrib;
116  }
117 
118  nassertr(false, make());
119  return make();
120 }
121 
122 ////////////////////////////////////////////////////////////////////
123 // Function: ClipPlaneAttrib::make
124 // Access: Published, Static
125 // Description: Constructs a new ClipPlaneAttrib object that turns on (or
126 // off, according to op) the indicate plane(s).
127 //
128 // This method is now deprecated. Use add_on_plane() or
129 // add_off_plane() instead.
130 ////////////////////////////////////////////////////////////////////
132 make(ClipPlaneAttrib::Operation op, PlaneNode *plane1, PlaneNode *plane2,
133  PlaneNode *plane3) {
134  pgraph_cat.warning()
135  << "Using deprecated ClipPlaneAttrib interface.\n";
136 
137  CPT(RenderAttrib) attrib;
138 
139  switch (op) {
140  case O_set:
141  attrib = make_all_off();
142  attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane1));
143  attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane2));
144  attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane3));
145  return attrib;
146 
147  case O_add:
148  attrib = make();
149  attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane1));
150  attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane2));
151  attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane3));
152  return attrib;
153 
154  case O_remove:
155  attrib = make();
156  attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane1));
157  attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane2));
158  attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane3));
159  return attrib;
160  }
161 
162  nassertr(false, make());
163  return make();
164 }
165 
166 ////////////////////////////////////////////////////////////////////
167 // Function: ClipPlaneAttrib::make
168 // Access: Published, Static
169 // Description: Constructs a new ClipPlaneAttrib object that turns on (or
170 // off, according to op) the indicate plane(s).
171 //
172 // This method is now deprecated. Use add_on_plane() or
173 // add_off_plane() instead.
174 ////////////////////////////////////////////////////////////////////
176 make(ClipPlaneAttrib::Operation op, PlaneNode *plane1, PlaneNode *plane2,
177  PlaneNode *plane3, PlaneNode *plane4) {
178  pgraph_cat.warning()
179  << "Using deprecated ClipPlaneAttrib interface.\n";
180 
181  CPT(RenderAttrib) attrib;
182 
183  switch (op) {
184  case O_set:
185  attrib = make_all_off();
186  attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane1));
187  attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane2));
188  attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane3));
189  attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane4));
190  return attrib;
191 
192  case O_add:
193  attrib = make();
194  attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane1));
195  attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane2));
196  attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane3));
197  attrib = DCAST(ClipPlaneAttrib, attrib)->add_on_plane(NodePath(plane4));
198  return attrib;
199 
200  case O_remove:
201  attrib = make();
202  attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane1));
203  attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane2));
204  attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane3));
205  attrib = DCAST(ClipPlaneAttrib, attrib)->add_off_plane(NodePath(plane4));
206  return attrib;
207  }
208 
209  nassertr(false, make());
210  return make();
211 }
212 
213 ////////////////////////////////////////////////////////////////////
214 // Function: ClipPlaneAttrib::make_default
215 // Access: Published, Static
216 // Description: Returns a RenderAttrib that corresponds to whatever
217 // the standard default properties for render attributes
218 // of this type ought to be.
219 ////////////////////////////////////////////////////////////////////
221 make_default() {
222  return return_new(new ClipPlaneAttrib);
223 }
224 
225 ////////////////////////////////////////////////////////////////////
226 // Function: ClipPlaneAttrib::get_operation
227 // Access: Published
228 // Description: Returns the basic operation type of the ClipPlaneAttrib.
229 // If this is O_set, the planes listed here completely
230 // replace any planes that were already on. If this is
231 // O_add, the planes here are added to the set of of
232 // planes that were already on, and if O_remove, the
233 // planes here are removed from the set of planes that
234 // were on.
235 //
236 // This method is now deprecated. ClipPlaneAttribs
237 // nowadays have a separate list of on_planes and
238 // off_planes, so this method doesn't make sense. Query
239 // the lists independently.
240 ////////////////////////////////////////////////////////////////////
241 ClipPlaneAttrib::Operation ClipPlaneAttrib::
242 get_operation() const {
243  pgraph_cat.warning()
244  << "Using deprecated ClipPlaneAttrib interface.\n";
245 
246  if (has_all_off()) {
247  return O_set;
248 
249  } else if (get_num_off_planes() == 0) {
250  return O_add;
251 
252  } else {
253  return O_remove;
254  }
255 }
256 
257 ////////////////////////////////////////////////////////////////////
258 // Function: ClipPlaneAttrib::get_num_planes
259 // Access: Published
260 // Description: Returns the number of planes listed in the attribute.
261 //
262 // This method is now deprecated. ClipPlaneAttribs
263 // nowadays have a separate list of on_planes and
264 // off_planes, so this method doesn't make sense. Query
265 // the lists independently.
266 ////////////////////////////////////////////////////////////////////
268 get_num_planes() const {
269  pgraph_cat.warning()
270  << "Using deprecated ClipPlaneAttrib interface.\n";
271 
272  if (get_num_off_planes() == 0) {
273  return get_num_on_planes();
274  } else {
275  return get_num_off_planes();
276  }
277 }
278 
279 ////////////////////////////////////////////////////////////////////
280 // Function: ClipPlaneAttrib::get_plane
281 // Access: Published
282 // Description: Returns the nth plane listed in the attribute.
283 //
284 // This method is now deprecated. ClipPlaneAttribs
285 // nowadays have a separate list of on_planes and
286 // off_planes, so this method doesn't make sense. Query
287 // the lists independently.
288 ////////////////////////////////////////////////////////////////////
290 get_plane(int n) const {
291  pgraph_cat.warning()
292  << "Using deprecated ClipPlaneAttrib interface.\n";
293 
294  if (get_num_off_planes() == 0) {
295  return DCAST(PlaneNode, get_on_plane(n).node());
296  } else {
297  return DCAST(PlaneNode, get_off_plane(n).node());
298  }
299 }
300 
301 ////////////////////////////////////////////////////////////////////
302 // Function: ClipPlaneAttrib::has_plane
303 // Access: Published
304 // Description: Returns true if the indicated plane is listed in the
305 // attrib, false otherwise.
306 //
307 // This method is now deprecated. ClipPlaneAttribs
308 // nowadays have a separate list of on_planes and
309 // off_planes, so this method doesn't make sense. Query
310 // the lists independently.
311 ////////////////////////////////////////////////////////////////////
313 has_plane(PlaneNode *plane) const {
314  pgraph_cat.warning()
315  << "Using deprecated ClipPlaneAttrib interface.\n";
316 
317  if (get_num_off_planes() == 0) {
318  return has_on_plane(NodePath(plane));
319  } else {
320  return has_off_plane(NodePath(plane));
321  }
322 }
323 
324 ////////////////////////////////////////////////////////////////////
325 // Function: ClipPlaneAttrib::add_plane
326 // Access: Published
327 // Description: Returns a new ClipPlaneAttrib, just like this one, but
328 // with the indicated plane added to the list of planes.
329 //
330 // This method is now deprecated. Use add_on_plane() or
331 // add_off_plane() instead.
332 ////////////////////////////////////////////////////////////////////
334 add_plane(PlaneNode *plane) const {
335  pgraph_cat.warning()
336  << "Using deprecated ClipPlaneAttrib interface.\n";
337 
338  if (get_num_off_planes() == 0) {
339  return add_on_plane(NodePath(plane));
340  } else {
341  return add_off_plane(NodePath(plane));
342  }
343 }
344 
345 ////////////////////////////////////////////////////////////////////
346 // Function: ClipPlaneAttrib::remove_plane
347 // Access: Published
348 // Description: Returns a new ClipPlaneAttrib, just like this one, but
349 // with the indicated plane removed from the list of
350 // planes.
351 //
352 // This method is now deprecated. Use remove_on_plane()
353 // or remove_off_plane() instead.
354 ////////////////////////////////////////////////////////////////////
356 remove_plane(PlaneNode *plane) const {
357  pgraph_cat.warning()
358  << "Using deprecated ClipPlaneAttrib interface.\n";
359 
360  if (get_num_off_planes() == 0) {
361  return remove_on_plane(NodePath(plane));
362  } else {
363  return remove_off_plane(NodePath(plane));
364  }
365 }
366 
367 ////////////////////////////////////////////////////////////////////
368 // Function: ClipPlaneAttrib::make
369 // Access: Published, Static
370 // Description: Constructs a new ClipPlaneAttrib object that does
371 // nothing.
372 ////////////////////////////////////////////////////////////////////
374 make() {
375  // We make it a special case and store a pointer to the empty attrib
376  // forever once we find it the first time, as an optimization.
377  if (_empty_attrib == (RenderAttrib *)NULL) {
378  _empty_attrib = return_new(new ClipPlaneAttrib);
379  }
380 
381  return _empty_attrib;
382 }
383 
384 ////////////////////////////////////////////////////////////////////
385 // Function: ClipPlaneAttrib::make_all_off
386 // Access: Published, Static
387 // Description: Constructs a new ClipPlaneAttrib object that disables
388 // all planes (and hence disables clipping).
389 ////////////////////////////////////////////////////////////////////
391 make_all_off() {
392  // We make it a special case and store a pointer to the off attrib
393  // forever once we find it the first time, as an optimization.
394  if (_all_off_attrib == (RenderAttrib *)NULL) {
395  ClipPlaneAttrib *attrib = new ClipPlaneAttrib;
396  attrib->_off_all_planes = true;
397  _all_off_attrib = return_new(attrib);
398  }
399 
400  return _all_off_attrib;
401 }
402 
403 ////////////////////////////////////////////////////////////////////
404 // Function: ClipPlaneAttrib::add_on_plane
405 // Access: Published
406 // Description: Returns a new ClipPlaneAttrib, just like this one, but
407 // with the indicated plane added to the list of planes
408 // enabled by this attrib.
409 ////////////////////////////////////////////////////////////////////
411 add_on_plane(const NodePath &plane) const {
412  nassertr(!plane.is_empty() && plane.node()->is_of_type(PlaneNode::get_class_type()), this);
413  ClipPlaneAttrib *attrib = new ClipPlaneAttrib(*this);
414  attrib->_on_planes.insert(plane);
415  attrib->_off_planes.erase(plane);
416 
417  pair<Planes::iterator, bool> insert_result =
418  attrib->_on_planes.insert(Planes::value_type(plane));
419  if (insert_result.second) {
420  // Also ensure it is removed from the off_planes list.
421  attrib->_off_planes.erase(plane);
422  }
423 
424  return return_new(attrib);
425 }
426 
427 ////////////////////////////////////////////////////////////////////
428 // Function: ClipPlaneAttrib::remove_on_plane
429 // Access: Published
430 // Description: Returns a new ClipPlaneAttrib, just like this one, but
431 // with the indicated plane removed from the list of
432 // planes enabled by this attrib.
433 ////////////////////////////////////////////////////////////////////
435 remove_on_plane(const NodePath &plane) const {
436  nassertr(!plane.is_empty() && plane.node()->is_of_type(PlaneNode::get_class_type()), this);
437  ClipPlaneAttrib *attrib = new ClipPlaneAttrib(*this);
438  attrib->_on_planes.erase(plane);
439  return return_new(attrib);
440 }
441 
442 ////////////////////////////////////////////////////////////////////
443 // Function: ClipPlaneAttrib::add_off_plane
444 // Access: Published
445 // Description: Returns a new ClipPlaneAttrib, just like this one, but
446 // with the indicated plane added to the list of planes
447 // disabled by this attrib.
448 ////////////////////////////////////////////////////////////////////
450 add_off_plane(const NodePath &plane) const {
451  nassertr(!plane.is_empty() && plane.node()->is_of_type(PlaneNode::get_class_type()), this);
452  ClipPlaneAttrib *attrib = new ClipPlaneAttrib(*this);
453  if (!_off_all_planes) {
454  attrib->_off_planes.insert(plane);
455  }
456  attrib->_on_planes.erase(plane);
457  return return_new(attrib);
458 }
459 
460 ////////////////////////////////////////////////////////////////////
461 // Function: ClipPlaneAttrib::remove_off_plane
462 // Access: Published
463 // Description: Returns a new ClipPlaneAttrib, just like this one, but
464 // with the indicated plane removed from the list of
465 // planes disabled by this attrib.
466 ////////////////////////////////////////////////////////////////////
468 remove_off_plane(const NodePath &plane) const {
469  nassertr(!plane.is_empty() && plane.node()->is_of_type(PlaneNode::get_class_type()), this);
470  ClipPlaneAttrib *attrib = new ClipPlaneAttrib(*this);
471  attrib->_off_planes.erase(plane);
472  return return_new(attrib);
473 }
474 
475 ////////////////////////////////////////////////////////////////////
476 // Function: ClipPlaneAttrib::filter_to_max
477 // Access: Public
478 // Description: Returns a new ClipPlaneAttrib, very much like this one,
479 // but with the number of on_planes reduced to be no
480 // more than max_clip_planes. The number of off_planes in
481 // the new ClipPlaneAttrib is undefined.
482 ////////////////////////////////////////////////////////////////////
484 filter_to_max(int max_clip_planes) const {
485  if (max_clip_planes < 0 || (int)_on_planes.size() <= max_clip_planes) {
486  // Trivial case: this ClipPlaneAttrib qualifies.
487  return this;
488  }
489 
490  // Since check_filtered() will clear the _filtered list if we are out
491  // of date, we should call it first.
492  check_filtered();
493 
494  Filtered::const_iterator fi;
495  fi = _filtered.find(max_clip_planes);
496  if (fi != _filtered.end()) {
497  // Easy case: we have already computed this for this particular
498  // ClipPlaneAttrib.
499  return (*fi).second;
500  }
501 
502  // Harder case: we have to compute it now. We must choose the n
503  // planeNodes with the highest priority in our list of planeNodes.
504  Planes priority_planes = _on_planes;
505 
506  // This sort function uses the STL function object defined above.
507  sort(priority_planes.begin(), priority_planes.end(),
509 
510  // Now lop off all of the planeNodes after the first max_clip_planes.
511  priority_planes.erase(priority_planes.begin() + max_clip_planes,
512  priority_planes.end());
513 
514  // And re-sort the ov_set into its proper order.
515  priority_planes.sort();
516 
517  // Now create a new attrib reflecting these planeNodes.
518  PT(ClipPlaneAttrib) attrib = new ClipPlaneAttrib;
519  attrib->_on_planes.swap(priority_planes);
520 
521  CPT(RenderAttrib) new_attrib = return_new(attrib);
522 
523  // Finally, record this newly-created attrib in the map for next
524  // time.
525  CPT(ClipPlaneAttrib) planeNode_attrib = (const ClipPlaneAttrib *)new_attrib.p();
526  ((ClipPlaneAttrib *)this)->_filtered[max_clip_planes] = planeNode_attrib;
527  return planeNode_attrib;
528 }
529 
530 ////////////////////////////////////////////////////////////////////
531 // Function: ClipPlaneAttrib::compose_off
532 // Access: Public
533 // Description: This is a special method which composes two
534 // ClipPlaneAttribs with regard only to their set of
535 // "off" clip planes, for the purposes of deriving
536 // PandaNode::get_off_clip_planes().
537 //
538 // The result will be a ClipPlaneAttrib that represents
539 // the union of all of the clip planes turned off in
540 // either attrib. The set of on planes in the result is
541 // undefined and should be ignored.
542 ////////////////////////////////////////////////////////////////////
543 CPT(RenderAttrib) ClipPlaneAttrib::
544 compose_off(const RenderAttrib *other) const {
545  const ClipPlaneAttrib *ta;
546  DCAST_INTO_R(ta, other, 0);
547 
548  if (_off_all_planes || (!ta->_off_all_planes && ta->_off_planes.empty())) {
549  // If we turn off all planes, or the other turns none off, the
550  // result is the same as this one.
551  return this;
552  }
553 
554  if (ta->_off_all_planes || _off_planes.empty()) {
555  // And contrariwise.
556  return ta;
557  }
558 
559  Planes::const_iterator ai = _off_planes.begin();
560  Planes::const_iterator bi = ta->_off_planes.begin();
561 
562  // Create a new ClipPlaneAttrib that will hold the result.
563  ClipPlaneAttrib *new_attrib = new ClipPlaneAttrib;
564  back_insert_iterator<Planes> result =
565  back_inserter(new_attrib->_on_planes);
566 
567  while (ai != _off_planes.end() &&
568  bi != ta->_off_planes.end()) {
569  if ((*ai) < (*bi)) {
570  // Here is a plane that we have in the original, which is not
571  // present in the secondary.
572  *result = *ai;
573  ++ai;
574  ++result;
575 
576  } else if ((*bi) < (*ai)) {
577  // Here is a new plane we have in the secondary, that was not
578  // present in the original.
579  *result = *bi;
580  ++bi;
581  ++result;
582 
583  } else { // (*bi) == (*ai)
584  // Here is a plane we have in both.
585  *result = *bi;
586  ++ai;
587  ++bi;
588  ++result;
589  }
590  }
591 
592  while (ai != _off_planes.end()) {
593  *result = *ai;
594  ++ai;
595  ++result;
596  }
597 
598  while (bi != ta->_off_planes.end()) {
599  *result = *bi;
600  ++bi;
601  ++result;
602  }
603 
604  return return_new(new_attrib);
605 }
606 
607 ////////////////////////////////////////////////////////////////////
608 // Function: ClipPlaneAttrib::output
609 // Access: Public, Virtual
610 // Description:
611 ////////////////////////////////////////////////////////////////////
612 void ClipPlaneAttrib::
613 output(ostream &out) const {
614  out << get_type() << ":";
615  if (_off_planes.empty()) {
616  if (_on_planes.empty()) {
617  if (_off_all_planes) {
618  out << "all off";
619  } else {
620  out << "identity";
621  }
622  } else {
623  if (_off_all_planes) {
624  out << "set";
625  } else {
626  out << "on";
627  }
628  }
629 
630  } else {
631  out << "off";
632  Planes::const_iterator fi;
633  for (fi = _off_planes.begin(); fi != _off_planes.end(); ++fi) {
634  NodePath plane = (*fi);
635  out << " " << plane;
636  }
637 
638  if (!_on_planes.empty()) {
639  out << " on";
640  }
641  }
642 
643  Planes::const_iterator li;
644  for (li = _on_planes.begin(); li != _on_planes.end(); ++li) {
645  NodePath plane = (*li);
646  out << " " << plane;
647  }
648 }
649 
650 ////////////////////////////////////////////////////////////////////
651 // Function: ClipPlaneAttrib::compare_to_impl
652 // Access: Protected, Virtual
653 // Description: Intended to be overridden by derived ClipPlaneAttrib
654 // types to return a unique number indicating whether
655 // this ClipPlaneAttrib is equivalent to the other one.
656 //
657 // This should return 0 if the two ClipPlaneAttrib
658 // objects are equivalent, a number less than zero if
659 // this one should be sorted before the other one, and a
660 // number greater than zero otherwise.
661 //
662 // This will only be called with two ClipPlaneAttrib
663 // objects whose get_type() functions return the same.
664 ////////////////////////////////////////////////////////////////////
665 int ClipPlaneAttrib::
666 compare_to_impl(const RenderAttrib *other) const {
667  const ClipPlaneAttrib *ta;
668  DCAST_INTO_R(ta, other, 0);
669 
670  if (_off_all_planes != ta->_off_all_planes) {
671  return (int)_off_all_planes - (int)ta->_off_all_planes;
672  }
673 
674  Planes::const_iterator li = _on_planes.begin();
675  Planes::const_iterator oli = ta->_on_planes.begin();
676 
677  while (li != _on_planes.end() && oli != ta->_on_planes.end()) {
678  NodePath plane = (*li);
679  NodePath other_plane = (*oli);
680 
681  int compare = plane.compare_to(other_plane);
682  if (compare != 0) {
683  return compare;
684  }
685 
686  ++li;
687  ++oli;
688  }
689 
690  if (li != _on_planes.end()) {
691  return 1;
692  }
693  if (oli != ta->_on_planes.end()) {
694  return -1;
695  }
696 
697  Planes::const_iterator fi = _off_planes.begin();
698  Planes::const_iterator ofi = ta->_off_planes.begin();
699 
700  while (fi != _off_planes.end() && ofi != ta->_off_planes.end()) {
701  NodePath plane = (*fi);
702  NodePath other_plane = (*ofi);
703 
704  int compare = plane.compare_to(other_plane);
705  if (compare != 0) {
706  return compare;
707  }
708 
709  ++fi;
710  ++ofi;
711  }
712 
713  if (fi != _off_planes.end()) {
714  return 1;
715  }
716  if (ofi != ta->_off_planes.end()) {
717  return -1;
718  }
719 
720  return 0;
721 }
722 
723 ////////////////////////////////////////////////////////////////////
724 // Function: ClipPlaneAttrib::get_hash_impl
725 // Access: Protected, Virtual
726 // Description: Intended to be overridden by derived RenderAttrib
727 // types to return a unique hash for these particular
728 // properties. RenderAttribs that compare the same with
729 // compare_to_impl(), above, should return the same
730 // hash; RenderAttribs that compare differently should
731 // return a different hash.
732 ////////////////////////////////////////////////////////////////////
733 size_t ClipPlaneAttrib::
734 get_hash_impl() const {
735  size_t hash = 0;
736 
737  Planes::const_iterator li;
738  for (li = _on_planes.begin(); li != _on_planes.end(); ++li) {
739  NodePath plane = (*li);
740  hash = plane.add_hash(hash);
741  }
742 
743  // This bool value goes here, between the two lists, to
744  // differentiate between the two.
745  hash = int_hash::add_hash(hash, (int)_off_all_planes);
746 
747  for (li = _off_planes.begin(); li != _off_planes.end(); ++li) {
748  NodePath plane = (*li);
749  hash = plane.add_hash(hash);
750  }
751 
752  return hash;
753 }
754 
755 ////////////////////////////////////////////////////////////////////
756 // Function: ClipPlaneAttrib::compose_impl
757 // Access: Protected, Virtual
758 // Description: Intended to be overridden by derived RenderAttrib
759 // types to specify how two consecutive RenderAttrib
760 // objects of the same type interact.
761 //
762 // This should return the result of applying the other
763 // RenderAttrib to a node in the scene graph below this
764 // RenderAttrib, which was already applied. In most
765 // cases, the result is the same as the other
766 // RenderAttrib (that is, a subsequent RenderAttrib
767 // completely replaces the preceding one). On the other
768 // hand, some kinds of RenderAttrib (for instance,
769 // ColorTransformAttrib) might combine in meaningful
770 // ways.
771 ////////////////////////////////////////////////////////////////////
772 CPT(RenderAttrib) ClipPlaneAttrib::
773 compose_impl(const RenderAttrib *other) const {
774  const ClipPlaneAttrib *ta;
775  DCAST_INTO_R(ta, other, 0);
776 
777  if (ta->_off_all_planes) {
778  // If the other type turns off all planes, it doesn't matter what
779  // we are.
780  return ta;
781  }
782 
783  // This is a three-way merge between ai, bi, and ci, except that bi
784  // and ci should have no intersection and therefore needn't be
785  // compared to each other.
786  Planes::const_iterator ai = _on_planes.begin();
787  Planes::const_iterator bi = ta->_on_planes.begin();
788  Planes::const_iterator ci = ta->_off_planes.begin();
789 
790  // Create a new ClipPlaneAttrib that will hold the result.
791  ClipPlaneAttrib *new_attrib = new ClipPlaneAttrib;
792  back_insert_iterator<Planes> result =
793  back_inserter(new_attrib->_on_planes);
794 
795  while (ai != _on_planes.end() &&
796  bi != ta->_on_planes.end() &&
797  ci != ta->_off_planes.end()) {
798  if ((*ai) < (*bi)) {
799  if ((*ai) < (*ci)) {
800  // Here is a plane that we have in the original, which is not
801  // present in the secondary.
802  *result = *ai;
803  ++ai;
804  ++result;
805 
806  } else if ((*ci) < (*ai)) {
807  // Here is a plane that is disabled in the secondary, but
808  // was not present in the original.
809  ++ci;
810 
811  } else { // (*ci) == (*ai)
812  // Here is a plane that is disabled in the secondary, and
813  // was present in the original.
814  ++ai;
815  ++ci;
816  }
817 
818  } else if ((*bi) < (*ai)) {
819  // Here is a new plane we have in the secondary, that was not
820  // present in the original.
821  *result = *bi;
822  ++bi;
823  ++result;
824 
825  } else { // (*bi) == (*ai)
826  // Here is a plane we have in both.
827  *result = *bi;
828  ++ai;
829  ++bi;
830  ++result;
831  }
832  }
833 
834  while (ai != _on_planes.end() && bi != ta->_on_planes.end()) {
835  if ((*ai) < (*bi)) {
836  // Here is a plane that we have in the original, which is not
837  // present in the secondary.
838  *result = *ai;
839  ++ai;
840  ++result;
841 
842  } else if ((*bi) < (*ai)) {
843  // Here is a new plane we have in the secondary, that was not
844  // present in the original.
845  *result = *bi;
846  ++bi;
847  ++result;
848 
849  } else {
850  // Here is a plane we have in both.
851  *result = *bi;
852  ++ai;
853  ++bi;
854  ++result;
855  }
856  }
857 
858  while (ai != _on_planes.end() && ci != ta->_off_planes.end()) {
859  if ((*ai) < (*ci)) {
860  // Here is a plane that we have in the original, which is not
861  // present in the secondary.
862  *result = *ai;
863  ++ai;
864  ++result;
865 
866  } else if ((*ci) < (*ai)) {
867  // Here is a plane that is disabled in the secondary, but
868  // was not present in the original.
869  ++ci;
870 
871  } else { // (*ci) == (*ai)
872  // Here is a plane that is disabled in the secondary, and
873  // was present in the original.
874  ++ai;
875  ++ci;
876  }
877  }
878 
879  while (ai != _on_planes.end()) {
880  *result = *ai;
881  ++ai;
882  ++result;
883  }
884 
885  while (bi != ta->_on_planes.end()) {
886  *result = *bi;
887  ++bi;
888  ++result;
889  }
890 
891  return return_new(new_attrib);
892 }
893 
894 ////////////////////////////////////////////////////////////////////
895 // Function: ClipPlaneAttrib::invert_compose_impl
896 // Access: Protected, Virtual
897 // Description: Intended to be overridden by derived RenderAttrib
898 // types to specify how two consecutive RenderAttrib
899 // objects of the same type interact.
900 //
901 // See invert_compose() and compose_impl().
902 ////////////////////////////////////////////////////////////////////
903 CPT(RenderAttrib) ClipPlaneAttrib::
904 invert_compose_impl(const RenderAttrib *other) const {
905  // I think in this case the other attrib always wins. Maybe this
906  // needs a bit more thought. It's hard to imagine that it's even
907  // important to compute this properly.
908  return other;
909 }
910 
911 ////////////////////////////////////////////////////////////////////
912 // Function: ClipPlaneAttrib::get_auto_shader_attrib_impl
913 // Access: Protected, Virtual
914 // Description:
915 ////////////////////////////////////////////////////////////////////
916 CPT(RenderAttrib) ClipPlaneAttrib::
917 get_auto_shader_attrib_impl(const RenderState *state) const {
918  return this;
919 }
920 
921 ////////////////////////////////////////////////////////////////////
922 // Function: ClipPlaneAttrib::sort_on_planes
923 // Access: Private
924 // Description: This is patterned after
925 // TextureAttrib::sort_on_stages(), but since planeNodes
926 // don't actually require sorting, this only empties the
927 // _filtered map.
928 ////////////////////////////////////////////////////////////////////
929 void ClipPlaneAttrib::
930 sort_on_planes() {
931  _sort_seq = PlaneNode::get_sort_seq();
932  _filtered.clear();
933 }
934 
935 ////////////////////////////////////////////////////////////////////
936 // Function: ClipPlaneAttrib::register_with_read_factory
937 // Access: Public, Static
938 // Description: Tells the BamReader how to create objects of type
939 // ClipPlaneAttrib.
940 ////////////////////////////////////////////////////////////////////
943  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
944 }
945 
946 ////////////////////////////////////////////////////////////////////
947 // Function: ClipPlaneAttrib::write_datagram
948 // Access: Public, Virtual
949 // Description: Writes the contents of this object to the datagram
950 // for shipping out to a Bam file.
951 ////////////////////////////////////////////////////////////////////
954  RenderAttrib::write_datagram(manager, dg);
955 
956  dg.add_bool(_off_all_planes);
957 
958  // write the number of off_planes
960  // write the off planes pointers if any
961  Planes::const_iterator fi;
962  for (fi = _off_planes.begin(); fi != _off_planes.end(); ++fi) {
963  NodePath plane = (*fi);
964 
965  // Since we can't write out a NodePath, we write out just the
966  // plain PandaNode. The user can use the AttribNodeRegistry on
967  // re-read if there is any ambiguity that needs to be resolved.
968  manager->write_pointer(dg, plane.node());
969  }
970 
971  // write the number of on planes
973  // write the on planes pointers if any
974  Planes::const_iterator nti;
975  for (nti = _on_planes.begin(); nti != _on_planes.end(); ++nti) {
976  NodePath plane = (*nti);
977  manager->write_pointer(dg, plane.node());
978  }
979 }
980 
981 ////////////////////////////////////////////////////////////////////
982 // Function: ClipPlaneAttrib::complete_pointers
983 // Access: Public, Virtual
984 // Description: Receives an array of pointers, one for each time
985 // manager->read_pointer() was called in fillin().
986 // Returns the number of pointers processed.
987 ////////////////////////////////////////////////////////////////////
990  int pi = RenderAttrib::complete_pointers(p_list, manager);
991  AttribNodeRegistry *areg = AttribNodeRegistry::get_global_ptr();
992 
993  Planes::iterator ci = _off_planes.begin();
994  while (ci != _off_planes.end()) {
995  PandaNode *node;
996  DCAST_INTO_R(node, p_list[pi++], pi);
997 
998  // We go through some effort to look up the node in the registry
999  // without creating a NodePath around it first (which would up,
1000  // and then down, the reference count, possibly deleting the
1001  // node).
1002  int ni = areg->find_node(node->get_type(), node->get_name());
1003  if (ni != -1) {
1004  (*ci) = areg->get_node(ni);
1005  } else {
1006  (*ci) = NodePath(node);
1007  }
1008  ++ci;
1009  }
1010  _off_planes.sort();
1011 
1012  ci = _on_planes.begin();
1013  while (ci != _on_planes.end()) {
1014  PandaNode *node;
1015  DCAST_INTO_R(node, p_list[pi++], pi);
1016 
1017  int ni = areg->find_node(node->get_type(), node->get_name());
1018  if (ni != -1) {
1019  (*ci) = areg->get_node(ni);
1020  } else {
1021  (*ci) = NodePath(node);
1022  }
1023  ++ci;
1024  }
1025  _on_planes.sort();
1026 
1027  return pi;
1028 }
1029 
1030 ////////////////////////////////////////////////////////////////////
1031 // Function: ClipPlaneAttrib::require_fully_complete
1032 // Access: Public, Virtual
1033 // Description: Some objects require all of their nested pointers to
1034 // have been completed before the objects themselves can
1035 // be completed. If this is the case, override this
1036 // method to return true, and be careful with circular
1037 // references (which would make the object unreadable
1038 // from a bam file).
1039 ////////////////////////////////////////////////////////////////////
1040 bool ClipPlaneAttrib::
1042  return true;
1043 }
1044 
1045 ////////////////////////////////////////////////////////////////////
1046 // Function: ClipPlaneAttrib::make_from_bam
1047 // Access: Protected, Static
1048 // Description: This function is called by the BamReader's factory
1049 // when a new object of type ClipPlaneAttrib is encountered
1050 // in the Bam file. It should create the ClipPlaneAttrib
1051 // and extract its information from the file.
1052 ////////////////////////////////////////////////////////////////////
1053 TypedWritable *ClipPlaneAttrib::
1054 make_from_bam(const FactoryParams &params) {
1055  ClipPlaneAttrib *attrib = new ClipPlaneAttrib;
1056  DatagramIterator scan;
1057  BamReader *manager;
1058 
1059  parse_params(params, scan, manager);
1060  attrib->fillin(scan, manager);
1061 
1062  return attrib;
1063 }
1064 
1065 ////////////////////////////////////////////////////////////////////
1066 // Function: ClipPlaneAttrib::fillin
1067 // Access: Protected
1068 // Description: This internal function is called by make_from_bam to
1069 // read in all of the relevant data from the BamFile for
1070 // the new ClipPlaneAttrib.
1071 ////////////////////////////////////////////////////////////////////
1072 void ClipPlaneAttrib::
1073 fillin(DatagramIterator &scan, BamReader *manager) {
1074  RenderAttrib::fillin(scan, manager);
1075 
1076  // We cheat a little bit here. In the middle of bam version 4.10,
1077  // we completely redefined the bam storage definition for
1078  // ClipPlaneAttribs, without bothering to up the bam version or even to
1079  // attempt to read the old definition. We get away with this,
1080  // knowing that the egg loader doesn't create ClipPlaneAttribs, and
1081  // hence no old bam files have the old definition for ClipPlaneAttrib
1082  // within them.
1083 
1084  _off_all_planes = scan.get_bool();
1085 
1086  int num_off_planes = scan.get_uint16();
1087 
1088  // Push back an empty NodePath for each off Plane for now, until we
1089  // get the actual list of pointers later in complete_pointers().
1090  _off_planes.reserve(num_off_planes);
1091  int i;
1092  for (i = 0; i < num_off_planes; i++) {
1093  manager->read_pointer(scan);
1094  _off_planes.push_back(NodePath());
1095  }
1096 
1097  int num_on_planes = scan.get_uint16();
1098  _on_planes.reserve(num_on_planes);
1099  for (i = 0; i < num_on_planes; i++) {
1100  manager->read_pointer(scan);
1101  _on_planes.push_back(NodePath());
1102  }
1103 }
NodePath get_node(int n) const
Returns the nth NodePath recorded in the registry.
A basic node of the scene graph or data graph.
Definition: pandaNode.h:72
bool get_bool()
Extracts a boolean value.
virtual bool require_fully_complete() const
Some objects require all of their nested pointers to have been completed before the objects themselve...
This is the base class for a number of render attributes (other than transform) that may be set on sc...
Definition: renderAttrib.h:60
int compare_to(const NodePath &other) const
Returns a number less than zero if this NodePath sorts before the other one, greater than zero if it ...
Definition: nodePath.I:2412
bool empty() const
Returns true if the ordered vector is empty, false otherwise.
bool has_all_off() const
Returns true if this attrib disables all planes (although it may also enable some).
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:122
This global object records NodePaths that are referenced by scene graph attribs, such as ClipPlaneAtt...
Operation get_operation() const
Returns the basic operation type of the ClipPlaneAttrib.
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:37
iterator_0 begin()
Returns the iterator that marks the first element in the ordered vector.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:284
This functions similarly to a LightAttrib.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:73
iterator_0 end()
Returns the iterator that marks the end of the ordered vector.
void reserve(size_type_0 n)
Informs the vector of a planned change in size; ensures that the capacity of the vector is greater th...
PN_uint16 get_uint16()
Extracts an unsigned 16-bit integer.
bool has_on_plane(const NodePath &plane) const
Returns true if the indicated plane is enabled by the attrib, false otherwise.
static size_t add_hash(size_t start, const Key &key)
Adds the indicated key into a running hash.
Definition: stl_compares.I:122
bool has_off_plane(const NodePath &plane) const
Returns true if the indicated plane is disabled by the attrib, false otherwise.
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition: datagram.I:118
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
static UpdateSeq get_sort_seq()
Returns a global sequence number that is incremented any time any PlaneNode in the world changes sort...
Definition: planeNode.I:171
int get_num_off_planes() const
Returns the number of planes that are disabled by the attribute.
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager-&gt;read_pointer() was called in fillin()...
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Receives an array of pointers, one for each time manager-&gt;read_pointer() was called in fillin()...
NodePath get_off_plane(int n) const
Returns the nth plane disabled by the attribute, sorted in arbitrary (pointer) order.
void sort()
Maps to sort_unique().
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:40
NodePath get_on_plane(int n) const
Returns the nth plane enabled by the attribute, sorted in render order.
bool has_plane(PlaneNode *plane) const
Returns true if the indicated plane is listed in the attrib, false otherwise.
int get_num_on_planes() const
Returns the number of planes that are enabled by the attribute.
void push_back(const value_type_0 &key)
Adds the new element to the end of the vector without regard for proper sorting.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:53
void register_factory(TypeHandle handle, CreateFunc *func)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:90
void add_uint16(PN_uint16 value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:181
PlaneNode * get_plane(int n) const
Returns the nth plane listed in the attribute.
int find_node(const NodePath &attrib_node) const
Returns the index number of the indicated NodePath in the registry (assuming its name hasn&#39;t changed ...
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:213
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition: nodePath.I:236
static void register_with_read_factory()
Tells the BamReader how to create objects of type ClipPlaneAttrib.
size_t add_hash(size_t hash) const
Adds the NodePath into the running hash.
Definition: nodePath.I:330
A class to retrieve the individual data elements previously stored in a Datagram. ...
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:43
int get_num_planes() const
Returns the number of planes listed in the attribute.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:165
A node that contains a plane.
Definition: planeNode.h:39
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
Definition: bamWriter.cxx:279
void read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:652