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