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 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This global object records NodePaths that are referenced by scene graph attribs, such as ClipPlaneAtt...
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 ...
get_node
Returns the nth NodePath recorded in the registry.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
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
void read_pointers(DatagramIterator &scan, int count)
A convenience function to read a contiguous list of pointers.
Definition: bamReader.cxx:653
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
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:83
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
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
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
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being written.
Definition: bamWriter.I:59
This functions similarly to a LightAttrib.
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 void register_with_read_factory()
Tells the BamReader how to create objects of type ClipPlaneAttrib.
get_num_off_planes
Returns the number of planes that are disabled by the attribute.
bool has_all_off() const
Returns true if this attrib disables all planes (although it may also enable some).
int get_num_planes() const
Returns the number of planes listed in the attribute.
bool has_on_plane(const NodePath &plane) const
Returns true if the indicated plane is enabled by the attrib, false otherwise.
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
bool has_off_plane(const NodePath &plane) const
Returns true if the indicated plane is disabled by the attrib, false otherwise.
bool has_plane(PlaneNode *plane) const
Returns true if the indicated plane is listed in the attrib, false otherwise.
PlaneNode * get_plane(int n) const
Returns the nth plane listed in the attribute.
get_on_plane
Returns the nth plane enabled by the attribute, sorted in render order.
virtual void finalize(BamReader *manager)
Called by the BamReader to perform any final actions needed for setting up the object after all objec...
get_num_on_planes
Returns the number of planes that are enabled by the attribute.
Operation get_operation() const
Returns the basic operation type of the ClipPlaneAttrib.
get_off_plane
Returns the nth plane disabled by the attribute, sorted in arbitrary (pointer) order.
A class to retrieve the individual data elements previously stored in a Datagram.
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
bool get_bool()
Extracts a boolean value.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition: datagram.I:34
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:85
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
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 is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
size_t add_hash(size_t hash) const
Adds the NodePath into the running hash.
Definition: nodePath.I:264
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition: nodePath.I:188
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:227
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:1965
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
A node that contains a plane.
Definition: planeNode.h:36
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
int get_priority() const
Returns the priority associated with this clip plane.
Definition: planeNode.I:107
This is the base class for a number of render attributes (other than transform) that may be set on sc...
Definition: renderAttrib.h:51
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
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().
static size_t add_hash(size_t start, const Key &key)
Adds the indicated key into a running hash.
Definition: stl_compares.I:101
reference back()
Returns a reference to the first element.
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...
iterator_0 begin()
Returns the iterator that marks the first element in the ordered vector.
void push_back(const value_type_0 &key)
Adds the new element to the end of the vector without regard for proper sorting.
void swap(ordered_vector< Key, Compare, Vector > &other)
Exchanges the contents of this vector and the other vector, in constant time (e.g....
size_type_0 size() const
Returns the number of elements in the ordered vector.
bool empty() const
Returns true if the ordered vector is empty, false otherwise.
iterator_0 end()
Returns the iterator that marks the end of the ordered vector.
void sort()
Maps to sort_unique().
CPT(RenderAttrib) ClipPlaneAttrib
Constructs a new ClipPlaneAttrib object that enables (or disables, according to op) the indicated pla...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.