Panda3D
Loading...
Searching...
No Matches
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
25CPT(RenderAttrib) ClipPlaneAttrib::_empty_attrib;
26CPT(RenderAttrib) ClipPlaneAttrib::_all_off_attrib;
27TypeHandle ClipPlaneAttrib::_type_handle;
28int 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.
32class ComparePlaneNodePriorities {
33public:
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 */
50CPT(RenderAttrib) ClipPlaneAttrib::
51make(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 */
84CPT(RenderAttrib) ClipPlaneAttrib::
85make(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 */
121CPT(RenderAttrib) ClipPlaneAttrib::
122make(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 */
162CPT(RenderAttrib) ClipPlaneAttrib::
163make(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 */
204CPT(RenderAttrib) ClipPlaneAttrib::
205make_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 */
220ClipPlaneAttrib::Operation ClipPlaneAttrib::
221get_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 */
244get_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 */
263get_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 */
283has_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 */
300CPT(RenderAttrib) ClipPlaneAttrib::
301add_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 */
318CPT(RenderAttrib) ClipPlaneAttrib::
319remove_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 */
333CPT(RenderAttrib) ClipPlaneAttrib::
334make() {
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 */
348CPT(RenderAttrib) ClipPlaneAttrib::
349make_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 */
365CPT(RenderAttrib) ClipPlaneAttrib::
366add_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 */
386CPT(RenderAttrib) ClipPlaneAttrib::
387remove_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 */
398CPT(RenderAttrib) ClipPlaneAttrib::
399add_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 */
413CPT(RenderAttrib) ClipPlaneAttrib::
414remove_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 */
426CPT(ClipPlaneAttrib) ClipPlaneAttrib::
427filter_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 */
481CPT(RenderAttrib) ClipPlaneAttrib::
482compose_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 */
548void ClipPlaneAttrib::
549output(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 */
598int ClipPlaneAttrib::
599compare_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 */
662size_t ClipPlaneAttrib::
663get_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 */
695CPT(RenderAttrib) ClipPlaneAttrib::
696compose_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 */
822CPT(RenderAttrib) ClipPlaneAttrib::
823invert_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 */
835void ClipPlaneAttrib::
836sort_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 */
854write_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 */
895complete_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 */
936finalize(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 */
1006TypedWritable *ClipPlaneAttrib::
1007make_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 */
1024void ClipPlaneAttrib::
1025fillin(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...
void read_pointers(DatagramIterator &scan, int count)
A convenience function to read a contiguous list of pointers.
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.
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(),...
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.
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...
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
get_priority
Returns the priority associated with this clip plane.
Definition planeNode.h:70
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
This is the base class for a number of render attributes (other than transform) that may be set on sc...
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.
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.
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().
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.