Panda3D

renderEffects.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 renderEffects.cxx
10 * @author drose
11 * @date 2002-03-14
12 */
13
14 #include "renderEffects.h"
15 #include "billboardEffect.h"
16 #include "decalEffect.h"
17 #include "compassEffect.h"
18 #include "polylightEffect.h"
19 #include "showBoundsEffect.h"
20 #include "config_pgraph.h"
21 #include "bamReader.h"
22 #include "bamWriter.h"
23 #include "datagramIterator.h"
24 #include "indent.h"
25 #include "compareTo.h"
26 #include "lightReMutexHolder.h"
27 #include "lightMutexHolder.h"
28 #include "thread.h"
29
30 #include <iterator>
31
32 LightReMutex *RenderEffects::_states_lock = nullptr;
33 RenderEffects::States *RenderEffects::_states = nullptr;
34 CPT(RenderEffects) RenderEffects::_empty_state;
35 TypeHandle RenderEffects::_type_handle;
36
37 /**
38 * Actually, this could be a private constructor, since no one inherits from
39 * RenderEffects, but gcc gives us a spurious warning if all constructors are
40 * private.
41 */
42 RenderEffects::
43 RenderEffects() : _lock("RenderEffects") {
44 if (_states == nullptr) {
45 init_states();
46 }
47 _saved_entry = _states->end();
48 _flags = 0;
49 }
50
51 /**
52 * The destructor is responsible for removing the RenderEffects from the
53 * global set if it is there.
54 */
55 RenderEffects::
56 ~RenderEffects() {
57 // Remove the deleted RenderEffects object from the global pool.
58 LightReMutexHolder holder(*_states_lock);
59
60 // unref() should have cleared this.
61 nassertv(_saved_entry == _states->end());
62 }
63
64 /**
65 * Returns true if all of the effects in this set can safely be transformed,
66 * and therefore the complete set can be transformed, by calling xform().
67 */
68 bool RenderEffects::
69 safe_to_transform() const {
70 Effects::const_iterator ai;
71 for (ai = _effects.begin(); ai != _effects.end(); ++ai) {
72 const Effect &effect = (*ai);
73 if (!effect._effect->safe_to_transform()) {
74 return false;
75 }
76 }
77
78 return true;
79 }
80
81 /**
82 * Preprocesses the accumulated transform that is about to be applied to (or
83 * through) this node due to a flatten operation. The returned value will be
84 * used instead.
85 */
86 CPT(TransformState) RenderEffects::
87 prepare_flatten_transform(const TransformState *net_transform) const {
88 CPT(TransformState) result = net_transform;
89 Effects::const_iterator ai;
90 for (ai = _effects.begin(); ai != _effects.end(); ++ai) {
91 const Effect &effect = (*ai);
92 result = effect._effect->prepare_flatten_transform(result);
93 }
94
95 return result;
96 }
97
98 /**
99 * Returns true if all of the effects in this set can safely be shared with a
100 * sibling node that has the exact same set of effects, or false if this would
101 * be bad for any of the effects.
102 */
103 bool RenderEffects::
104 safe_to_combine() const {
105 Effects::const_iterator ai;
106 for (ai = _effects.begin(); ai != _effects.end(); ++ai) {
107 const Effect &effect = (*ai);
108 if (!effect._effect->safe_to_combine()) {
109 return false;
110 }
111 }
112
113 return true;
114 }
115
116 /**
117 * Returns a new RenderEffects transformed by the indicated matrix.
118 */
119 CPT(RenderEffects) RenderEffects::
120 xform(const LMatrix4 &mat) const {
121 if (is_empty()) {
122 return this;
123 }
124
125 RenderEffects *new_state = new RenderEffects;
126 std::back_insert_iterator<Effects> result =
127 std::back_inserter(new_state->_effects);
128
129 Effects::const_iterator ai;
130 for (ai = _effects.begin(); ai != _effects.end(); ++ai) {
131 const Effect &effect = (*ai);
132 Effect new_effect(effect);
133 new_effect._effect = effect._effect->xform(mat);
134 *result = new_effect;
135 ++result;
136 }
137
138 return return_new(new_state);
139 }
140
141 /**
142 * Provides an arbitrary ordering among all unique RenderEffects, so we can
143 * store the essentially different ones in a big set and throw away the rest.
144 *
145 * This method is not needed outside of the RenderEffects class because all
146 * equivalent RenderEffects objects are guaranteed to share the same pointer;
147 * thus, a pointer comparison is always sufficient.
148 */
149 bool RenderEffects::
150 operator < (const RenderEffects &other) const {
151 // We must compare all the properties of the effects, not just the type;
152 // thus, we compare them one at a time using compare_to().
153 return lexicographical_compare(_effects.begin(), _effects.end(),
154 other._effects.begin(), other._effects.end(),
155 CompareTo<Effect>());
156 }
157
158
159 /**
160 * Searches for an effect with the indicated type in the state, and returns
161 * its index if it is found, or -1 if it is not.
162 */
163 int RenderEffects::
164 find_effect(TypeHandle type) const {
165 Effects::const_iterator ai = _effects.find(Effect(type));
166 if (ai == _effects.end()) {
167 return -1;
168 }
169 return ai - _effects.begin();
170 }
171
172 /**
173 * Returns a RenderEffects with no effects set.
174 */
175 CPT(RenderEffects) RenderEffects::
176 make_empty() {
177 // The empty state is asked for so often, we make it a special case and
178 // store a pointer forever once we find it the first time.
179 if (_empty_state == nullptr) {
180 RenderEffects *state = new RenderEffects;
181 _empty_state = return_new(state);
182 }
183
184 return _empty_state;
185 }
186
187 /**
188 * Returns a RenderEffects with one effect set.
189 */
190 CPT(RenderEffects) RenderEffects::
191 make(const RenderEffect *effect) {
192 RenderEffects *state = new RenderEffects;
193 state->_effects.reserve(1);
194 state->_effects.insert(Effect(effect));
195 return return_new(state);
196 }
197
198 /**
199 * Returns a RenderEffects with two effects set.
200 */
201 CPT(RenderEffects) RenderEffects::
202 make(const RenderEffect *effect1,
203 const RenderEffect *effect2) {
204 RenderEffects *state = new RenderEffects;
205 state->_effects.reserve(2);
206 state->_effects.push_back(Effect(effect1));
207 state->_effects.push_back(Effect(effect2));
208 state->_effects.sort();
209 return return_new(state);
210 }
211
212 /**
213 * Returns a RenderEffects with three effects set.
214 */
215 CPT(RenderEffects) RenderEffects::
216 make(const RenderEffect *effect1,
217 const RenderEffect *effect2,
218 const RenderEffect *effect3) {
219 RenderEffects *state = new RenderEffects;
220 state->_effects.reserve(2);
221 state->_effects.push_back(Effect(effect1));
222 state->_effects.push_back(Effect(effect2));
223 state->_effects.push_back(Effect(effect3));
224 state->_effects.sort();
225 return return_new(state);
226 }
227
228 /**
229 * Returns a RenderEffects with four effects set.
230 */
231 CPT(RenderEffects) RenderEffects::
232 make(const RenderEffect *effect1,
233 const RenderEffect *effect2,
234 const RenderEffect *effect3,
235 const RenderEffect *effect4) {
236 RenderEffects *state = new RenderEffects;
237 state->_effects.reserve(2);
238 state->_effects.push_back(Effect(effect1));
239 state->_effects.push_back(Effect(effect2));
240 state->_effects.push_back(Effect(effect3));
241 state->_effects.push_back(Effect(effect4));
242 state->_effects.sort();
243 return return_new(state);
244 }
245
246 /**
247 * Returns a new RenderEffects object that represents the same as the source
248 * state, with the new RenderEffect added. If there is already a RenderEffect
249 * with the same type, it is replaced.
250 */
251 CPT(RenderEffects) RenderEffects::
252 add_effect(const RenderEffect *effect) const {
253 RenderEffects *new_state = new RenderEffects;
254 std::back_insert_iterator<Effects> result =
255 std::back_inserter(new_state->_effects);
256
257 Effect new_effect(effect);
258 Effects::const_iterator ai = _effects.begin();
259
260 while (ai != _effects.end() && (*ai) < new_effect) {
261 *result = *ai;
262 ++ai;
263 ++result;
264 }
265 *result = new_effect;
266 ++result;
267
268 if (ai != _effects.end() && !(new_effect < (*ai))) {
269 // At this point we know: !((*ai) < new_effect) && !(new_effect < (*ai))
270 // which means (*ai) == new_effect--so we should leave it out, to avoid
271 // duplicating effects in the set.
272 ++ai;
273 }
274
275 while (ai != _effects.end()) {
276 *result = *ai;
277 ++ai;
278 ++result;
279 }
280
281 return return_new(new_state);
282 }
283
284 /**
285 * Returns a new RenderEffects object that represents the same as the source
286 * state, with the indicated RenderEffect removed.
287 */
288 CPT(RenderEffects) RenderEffects::
289 remove_effect(TypeHandle type) const {
290 RenderEffects *new_state = new RenderEffects;
291 std::back_insert_iterator<Effects> result =
292 std::back_inserter(new_state->_effects);
293
294 Effects::const_iterator ai = _effects.begin();
295
296 while (ai != _effects.end()) {
297 if ((*ai)._type != type) {
298 *result = *ai;
299 ++result;
300 }
301 ++ai;
302 }
303
304 return return_new(new_state);
305 }
306
307 /**
308 * Looks for a RenderEffect of the indicated type in the state, and returns it
309 * if it is found, or NULL if it is not.
310 */
311 const RenderEffect *RenderEffects::
312 get_effect(TypeHandle type) const {
313 Effects::const_iterator ai;
314 ai = _effects.find(Effect(type));
315 if (ai != _effects.end()) {
316 return (*ai)._effect;
317 }
318 return nullptr;
319 }
320
321 /**
322 * This method overrides ReferenceCount::unref() to check whether the
323 * remaining reference count is entirely in the cache, and if so, it checks
324 * for and breaks a cycle in the cache involving this object. This is
325 * designed to prevent leaks from cyclical references within the cache.
326 *
327 * Note that this is not a virtual method, and cannot be because
328 * ReferenceCount itself declares no virtual methods (it avoids the overhead
329 * of a virtual function pointer). But this doesn't matter, because
330 * PT(TransformState) is a template class, and will call the appropriate
331 * method even though it is non-virtual.
332 */
333 bool RenderEffects::
334 unref() const {
335 LightReMutexHolder holder(*_states_lock);
336
337 if (ReferenceCount::unref()) {
338 // The reference count is still nonzero.
339 return true;
340 }
341
342 // The reference count has just reached zero. Make sure the object is
343 // removed from the global object pool, before anyone else finds it and
344 // tries to ref it.
345 ((RenderEffects *)this)->release_new();
346
347 return false;
348 }
349
350 /**
351 *
352 */
353 void RenderEffects::
354 output(std::ostream &out) const {
355 out << "E:";
356 if (_effects.empty()) {
357 out << "(empty)";
358
359 } else {
360 Effects::const_iterator ai = _effects.begin();
361 out << "(" << (*ai)._type;
362 ++ai;
363 while (ai != _effects.end()) {
364 out << " " << (*ai)._type;
365 ++ai;
366 }
367 out << ")";
368 }
369 }
370
371 /**
372 *
373 */
374 void RenderEffects::
375 write(std::ostream &out, int indent_level) const {
376 indent(out, indent_level) << _effects.size() << " effects:\n";
377 Effects::const_iterator ai;
378 for (ai = _effects.begin(); ai != _effects.end(); ++ai) {
379 const Effect &effect = (*ai);
380 effect._effect->write(out, indent_level + 2);
381 }
382 }
383
384 /**
385 * Returns the total number of unique RenderEffects objects allocated in the
386 * world. This will go up and down during normal operations.
387 */
388 int RenderEffects::
389 get_num_states() {
390 if (_states == nullptr) {
391 return 0;
392 }
393 LightReMutexHolder holder(*_states_lock);
394 return _states->size();
395 }
396
397 /**
398 * Lists all of the RenderEffects in the cache to the output stream, one per
399 * line. This can be quite a lot of output if the cache is large, so be
400 * prepared.
401 */
402 void RenderEffects::
403 list_states(std::ostream &out) {
404 out << _states->size() << " states:\n";
405 States::const_iterator si;
406 for (si = _states->begin(); si != _states->end(); ++si) {
407 const RenderEffects *state = (*si);
408 state->write(out, 2);
409 }
410 }
411
412 /**
413 * Ensures that the cache is still stored in sorted order. Returns true if
414 * so, false if there is a problem (which implies someone has modified one of
415 * the supposedly-const RenderEffects objects).
416 */
417 bool RenderEffects::
418 validate_states() {
419 if (_states->empty()) {
420 return true;
421 }
422 LightReMutexHolder holder(*_states_lock);
423
424 States::const_iterator si = _states->begin();
425 States::const_iterator snext = si;
426 ++snext;
427 while (snext != _states->end()) {
428 if (!(*(*si) < *(*snext))) {
429 pgraph_cat.error()
430 << "RenderEffects out of order!\n";
431 (*si)->write(pgraph_cat.error(false), 2);
432 (*snext)->write(pgraph_cat.error(false), 2);
433 return false;
434 }
435 if ((*(*snext) < *(*si))) {
436 pgraph_cat.error()
437 << "RenderEffects::operator < not defined properly!\n";
438 pgraph_cat.error(false)
439 << "a < b: " << (*(*si) < *(*snext)) << "\n";
440 pgraph_cat.error(false)
441 << "b < a: " << (*(*snext) < *(*si)) << "\n";
442 (*si)->write(pgraph_cat.error(false), 2);
443 (*snext)->write(pgraph_cat.error(false), 2);
444 return false;
445 }
446 si = snext;
447 ++snext;
448 }
449
450 return true;
451 }
452
453 /**
454 * Calls cull_callback() on all effects. You may check has_cull_callback()
455 * first to see if any effects define this method to do anything useful.
456 */
457 void RenderEffects::
458 cull_callback(CullTraverser *trav, CullTraverserData &data,
459 CPT(TransformState) &node_transform,
460 CPT(RenderState) &node_state) const {
461 Effects::const_iterator ei;
462 for (ei = _effects.begin(); ei != _effects.end(); ++ei) {
463 (*ei)._effect->cull_callback(trav, data, node_transform, node_state);
464 }
465 }
466
467 /**
468 * Calls adjust_transform() on all effects. You may check
469 * has_adjust_transform() first to see if any effects define this method to do
470 * anything useful.
471 *
472 * The order in which the individual effects are applied is not defined, so if
473 * more than one effect applies a change to the transform on any particular
474 * node, you might get indeterminate results.
475 */
476 void RenderEffects::
477 adjust_transform(CPT(TransformState) &net_transform,
478 CPT(TransformState) &node_transform,
479 const PandaNode *node) const {
480 Effects::const_iterator ei;
481 for (ei = _effects.begin(); ei != _effects.end(); ++ei) {
482 (*ei)._effect->adjust_transform(net_transform, node_transform, node);
483 }
484 }
485
486 /**
487 * Make sure the global _states map is allocated. This only has to be done
488 * once. We could make this map static, but then we run into problems if
489 * anyone creates a RenderEffects object at static init time; it also seems to
490 * cause problems when the Panda shared library is unloaded at application
491 * exit time.
492 */
493 void RenderEffects::
494 init_states() {
495 _states = new States;
496
497 // TODO: we should have a global Panda mutex to allow us to safely create
498 // _states_lock without a startup race condition. For the meantime, this is
499 // OK because we guarantee that this method is called at static init time,
500 // presumably when there is still only one thread in the world.
501 _states_lock = new LightReMutex("RenderEffects::_states_lock");
502 nassertv(Thread::get_current_thread() == Thread::get_main_thread());
503 }
504
505
506 /**
507 * This function is used to share a common RenderEffects pointer for all
508 * equivalent RenderEffects objects.
509 *
510 * See the similar logic in RenderEffect. The idea is to create a new
511 * RenderEffects object and pass it through this function, which will share
512 * the pointer with a previously-created RenderEffects object if it is
513 * equivalent.
514 */
515 CPT(RenderEffects) RenderEffects::
516 return_new(RenderEffects *state) {
517 nassertr(state != nullptr, state);
518
519 #ifndef NDEBUG
520 if (!state_cache) {
521 return state;
522 }
523 #endif
524
525 #ifndef NDEBUG
526 if (paranoid_const) {
527 nassertr(validate_states(), state);
528 }
529 #endif
530
531 LightReMutexHolder holder(*_states_lock);
532
533 // This should be a newly allocated pointer, not one that was used for
534 // anything else.
535 nassertr(state->_saved_entry == _states->end(), state);
536
537 // Save the state in a local PointerTo so that it will be freed at the end
538 // of this function if no one else uses it.
539 CPT(RenderEffects) pt_state = state;
540
541 std::pair<States::iterator, bool> result = _states->insert(state);
542 if (result.second) {
543 // The state was inserted; save the iterator and return the input state.
544 state->_saved_entry = result.first;
545 nassertr(_states->find(state) == state->_saved_entry, pt_state);
546 return pt_state;
547 }
548
549 // The state was not inserted; there must be an equivalent one already in
550 // the set. Return that one.
551 return *(result.first);
552 }
553
554 /**
555 * This inverse of return_new, this releases this object from the global
556 * RenderEffects table.
557 *
558 * You must already be holding _states_lock before you call this method.
559 */
560 void RenderEffects::
561 release_new() {
562 nassertv(_states_lock->debug_is_locked());
563
564 if (_saved_entry != _states->end()) {
565 nassertv(_states->find(this) == _saved_entry);
566 _states->erase(_saved_entry);
567 _saved_entry = _states->end();
568 }
569 }
570
571 /**
572 * This is the private implementation of has_decal().
573 */
574 void RenderEffects::
575 determine_decal() {
576 LightMutexHolder holder(_lock);
577 if ((_flags & F_checked_decal) != 0) {
578 // Someone else checked it first.
579 return;
580 }
581
582 const RenderEffect *effect = get_effect(DecalEffect::get_class_type());
583 if (effect != nullptr) {
584 _flags |= F_has_decal;
585 }
586 _flags |= F_checked_decal;
587 }
588
589 /**
590 * This is the private implementation of has_show_bounds().
591 */
592 void RenderEffects::
593 determine_show_bounds() {
594 LightMutexHolder holder(_lock);
595 if ((_flags & F_checked_show_bounds) != 0) {
596 // Someone else checked it first.
597 return;
598 }
599
600 const RenderEffect *effect = get_effect(ShowBoundsEffect::get_class_type());
601 if (effect != nullptr) {
602 _flags |= F_has_show_bounds;
603 const ShowBoundsEffect *sba = DCAST(ShowBoundsEffect, effect);
604 if (sba->get_tight()) {
605 _flags |= F_has_show_tight_bounds;
606 }
607 }
608 _flags |= F_checked_show_bounds;
609 }
610
611 /**
612 * This is the private implementation of has_cull_callback().
613 */
614 void RenderEffects::
615 determine_cull_callback() {
616 LightMutexHolder holder(_lock);
617 if ((_flags & F_checked_cull_callback) != 0) {
618 // Someone else checked it first.
619 return;
620 }
621
622 _flags |= F_checked_cull_callback;
623
624 Effects::const_iterator ei;
625 for (ei = _effects.begin(); ei != _effects.end(); ++ei) {
626 if ((*ei)._effect->has_cull_callback()) {
627 _flags |= F_has_cull_callback;
628 return;
629 }
630 }
631 }
632
633 /**
634 * This is the private implementation of has_adjust_transform().
635 */
636 void RenderEffects::
637 determine_adjust_transform() {
638 LightMutexHolder holder(_lock);
639 if ((_flags & F_checked_adjust_transform) != 0) {
640 // Someone else checked it first.
641 return;
642 }
643
644 _flags |= F_checked_adjust_transform;
645
646 Effects::const_iterator ei;
647 for (ei = _effects.begin(); ei != _effects.end(); ++ei) {
648 if ((*ei)._effect->has_adjust_transform()) {
649 _flags |= F_has_adjust_transform;
650 return;
651 }
652 }
653 }
654
655 /**
656 * Tells the BamReader how to create objects of type RenderEffects.
657 */
658 void RenderEffects::
659 register_with_read_factory() {
660 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
661 }
662
663 /**
664 * Writes the contents of this object to the datagram for shipping out to a
665 * Bam file.
666 */
667 void RenderEffects::
668 write_datagram(BamWriter *manager, Datagram &dg) {
669 TypedWritable::write_datagram(manager, dg);
670
671 int num_effects = _effects.size();
672 nassertv(num_effects == (int)(uint16_t)num_effects);
673 dg.add_uint16(num_effects);
674
675 Effects::const_iterator ai;
676 for (ai = _effects.begin(); ai != _effects.end(); ++ai) {
677 const Effect &effect = (*ai);
678
679 manager->write_pointer(dg, effect._effect);
680 }
681 }
682
683 /**
684 * Receives an array of pointers, one for each time manager->read_pointer()
685 * was called in fillin(). Returns the number of pointers processed.
686 */
687 int RenderEffects::
688 complete_pointers(TypedWritable **p_list, BamReader *manager) {
689 int pi = TypedWritable::complete_pointers(p_list, manager);
690
691 // Get the effect pointers.
692 size_t i = 0;
693 while (i < _effects.size()) {
694 Effect &effect = _effects[i];
695
696 effect._effect = DCAST(RenderEffect, p_list[pi++]);
697 if (effect._effect == nullptr) {
698 // Remove this bogus RenderEffect pointer (it must have been from an
699 // unwritable class).
700 _effects.erase(_effects.begin() + i);
701
702 } else {
703 // Keep this good pointer, and increment.
704 effect._type = effect._effect->get_type();
705 ++i;
706 }
707 }
708
709 // Now make sure the array is properly sorted. (It won't necessarily
710 // preserve its correct sort after being read from bam, because the sort is
711 // based on TypeHandle indices, which can change from session to session.)
712 _effects.sort();
713
714 nassertr(_saved_entry == _states->end(), pi);
715 return pi;
716 }
717
718 /**
719 * Some objects require all of their nested pointers to have been completed
720 * before the objects themselves can be completed. If this is the case,
721 * override this method to return true, and be careful with circular
722 * references (which would make the object unreadable from a bam file).
723 */
724 bool RenderEffects::
725 require_fully_complete() const {
726 // Since we sort _states based on each RenderEffects' operator < method,
727 // which in turn compares based on each nested RenderEffect object's
728 // compare_to() method, some of which depend on the RenderEffect's pointers
729 // having already been completed (e.g. CharacterJointEffect), we therefore
730 // require each of out our nested RenderEffect objects to have been
731 // completed before we can be completed.
732 return true;
733 }
734
735 /**
736 * Called immediately after complete_pointers(), this gives the object a
737 * chance to adjust its own pointer if desired. Most objects don't change
738 * pointers after completion, but some need to.
739 *
740 * Once this function has been called, the old pointer will no longer be
741 * accessed.
742 */
743 TypedWritable *RenderEffects::
744 change_this(TypedWritable *old_ptr, BamReader *manager) {
745 // First, uniquify the pointer.
746 RenderEffects *state = DCAST(RenderEffects, old_ptr);
747 CPT(RenderEffects) pointer = return_new(state);
748
749 // But now we have a problem, since we have to hold the reference count and
750 // there's no way to return a TypedWritable while still holding the
751 // reference count! We work around this by explicitly upping the count, and
752 // also setting a finalize() callback to down it later.
753 if (pointer == state) {
754 pointer->ref();
755 manager->register_finalize(state);
756 }
757
758 // We have to cast the pointer back to non-const, because the bam reader
759 // expects that.
760 return (RenderEffects *)pointer.p();
761 }
762
763 /**
764 * Called by the BamReader to perform any final actions needed for setting up
765 * the object after all objects have been read and all pointers have been
766 * completed.
767 */
768 void RenderEffects::
769 finalize(BamReader *) {
770 // Unref the pointer that we explicitly reffed in change_this().
771 unref();
772
773 // We should never get back to zero after unreffing our own count, because
774 // we expect to have been stored in a pointer somewhere. If we do get to
775 // zero, it's a memory leak; the way to avoid this is to call unref_delete()
776 // above instead of unref(), but this is dangerous to do from within a
777 // virtual function.
778 nassertv(get_ref_count() != 0);
779 }
780
781 /**
782 * This function is called by the BamReader's factory when a new object of
783 * type RenderEffects is encountered in the Bam file. It should create the
784 * RenderEffects and extract its information from the file.
785 */
786 TypedWritable *RenderEffects::
787 make_from_bam(const FactoryParams &params) {
788 RenderEffects *state = new RenderEffects;
789 DatagramIterator scan;
790 BamReader *manager;
791
792 parse_params(params, scan, manager);
793 state->fillin(scan, manager);
794 manager->register_change_this(change_this, state);
795
796 return state;
797 }
798
799 /**
800 * This internal function is called by make_from_bam to read in all of the
801 * relevant data from the BamFile for the new RenderEffects.
802 */
803 void RenderEffects::
804 fillin(DatagramIterator &scan, BamReader *manager) {
805 TypedWritable::fillin(scan, manager);
806
807 int num_effects = scan.get_uint16();
808
809 // Push back a NULL pointer for each effect for now, until we get the actual
810 // list of pointers later in complete_pointers().
811 _effects.reserve(num_effects);
812 for (int i = 0; i < num_effects; i++) {
813 manager->read_pointer(scan);
814 _effects.push_back(Effect());
815 }
816
817 nassertv(_saved_entry == _states->end());
818 }
bamReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
bamWriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
billboardEffect.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
BamReader
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
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
BamReader::register_change_this
void register_change_this(ChangeThisFunc func, TypedWritable *whom)
Called by an object reading itself from the bam file to indicate that the object pointer that will be...
Definition: bamReader.cxx:835
BamReader::read_pointer
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:610
BamReader::get_factory
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
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
CompareTo
An STL function object class, this is intended to be used on any ordered collection of classes that c...
Definition: compareTo.h:25
CullTraverserData
This collects together the pieces of data that are accumulated for each node while walking the scene ...
Definition: cullTraverserData.h:40
CullTraverser
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
Definition: cullTraverser.h:45
DatagramIterator
A class to retrieve the individual data elements previously stored in a Datagram.
Definition: datagramIterator.h:27
DatagramIterator::get_uint16
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
Definition: datagramIterator.I:145
Datagram
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
Datagram::add_uint16
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:85
FactoryParams
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
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
LightMutexHolder
Similar to MutexHolder, but for a light mutex.
Definition: lightMutexHolder.h:25
LightReMutexDirect::debug_is_locked
bool debug_is_locked() const
Returns true if the current thread has locked the LightReMutex, false otherwise.
Definition: lightReMutexDirect.I:123
LightReMutexHolder
Similar to MutexHolder, but for a light reentrant mutex.
Definition: lightReMutexHolder.h:25
LightReMutex
A lightweight reentrant mutex.
Definition: lightReMutex.h:32
PandaNode
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
ReferenceCount::get_ref_count
get_ref_count
Returns the current reference count.
Definition: referenceCount.h:53
ReferenceCount::unref
virtual bool unref() const
Explicitly decrements the reference count.
Definition: referenceCount.I:179
RenderEffect
This is the base class for a number of special render effects that may be set on scene graph nodes to...
Definition: renderEffect.h:48
RenderEffects
This represents a unique collection of RenderEffect objects that correspond to a particular renderabl...
Definition: renderEffects.h:41
RenderEffects::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: renderEffects.cxx:769
RenderEffects::list_states
static void list_states(std::ostream &out)
Lists all of the RenderEffects in the cache to the output stream, one per line.
Definition: renderEffects.cxx:403
RenderEffects::adjust_transform
void adjust_transform(CPT(TransformState) &net_transform, CPT(TransformState) &node_transform, const PandaNode *node) const
Calls adjust_transform() on all effects.
Definition: renderEffects.cxx:477
RenderEffects::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: renderEffects.cxx:688
RenderEffects::~RenderEffects
virtual ~RenderEffects()
The destructor is responsible for removing the RenderEffects from the global set if it is there.
Definition: renderEffects.cxx:56
RenderEffects::is_empty
bool is_empty() const
Returns true if the state is empty, false otherwise.
Definition: renderEffects.I:94
RenderEffects::validate_states
static bool validate_states()
Ensures that the cache is still stored in sorted order.
Definition: renderEffects.cxx:418
RenderEffects::unref
virtual bool unref() const
Explicitly decrements the reference count.
RenderEffects::get_effect
const RenderEffect * get_effect(size_t n) const
Returns the nth effect in the state.
Definition: renderEffects.I:111
RenderEffects::safe_to_transform
bool safe_to_transform() const
Returns true if all of the effects in this set can safely be transformed, and therefore the complete ...
Definition: renderEffects.cxx:69
RenderEffects::require_fully_complete
virtual bool require_fully_complete() const
Some objects require all of their nested pointers to have been completed before the objects themselve...
Definition: renderEffects.cxx:725
RenderEffects::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: renderEffects.cxx:668
RenderEffects::change_this
static TypedWritable * change_this(TypedWritable *old_ptr, BamReader *manager)
Called immediately after complete_pointers(), this gives the object a chance to adjust its own pointe...
Definition: renderEffects.cxx:744
RenderEffects::cull_callback
void cull_callback(CullTraverser *trav, CullTraverserData &data, CPT(TransformState) &node_transform, CPT(RenderState) &node_state) const
Calls cull_callback() on all effects.
Definition: renderEffects.cxx:458
RenderEffects::init_states
static void init_states()
Make sure the global _states map is allocated.
Definition: renderEffects.cxx:494
RenderEffects::register_with_read_factory
static void register_with_read_factory()
Tells the BamReader how to create objects of type RenderEffects.
Definition: renderEffects.cxx:659
RenderState
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
ShowBoundsEffect
Applied to a GeomNode to cause a visible bounding volume to be drawn for this node.
Definition: showBoundsEffect.h:28
ShowBoundsEffect::get_tight
bool get_tight() const
Returns true if the "tight" flag was set, meaning the effect should compute and draw the tight boundi...
Definition: showBoundsEffect.I:28
Thread::get_main_thread
get_main_thread
Returns a pointer to the "main" Thread object–this is the Thread that started the whole process.
Definition: thread.h:107
Thread::get_current_thread
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition: thread.h:109
TransformState
Indicates a coordinate-system transform on vertices.
Definition: transformState.h:54
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
TypedWritable
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
TypedWritable::fillin
virtual void fillin(DatagramIterator &scan, BamReader *manager)
This internal function is intended to be called by each class's make_from_bam() method to read in all...
Definition: typedWritable.cxx:103
TypedWritable::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: typedWritable.cxx:54
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
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
ordered_vector::begin
iterator_0 begin()
Returns the iterator that marks the first element in the ordered vector.
Definition: ordered_vector.I:41
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
ordered_vector::size
size_type_0 size() const
Returns the number of elements in the ordered vector.
Definition: ordered_vector.I:221
ordered_vector::empty
bool empty() const
Returns true if the ordered vector is empty, false otherwise.
Definition: ordered_vector.I:240
ordered_vector::end
iterator_0 end()
Returns the iterator that marks the end of the ordered vector.
Definition: ordered_vector.I:50
ov_set::sort
void sort()
Maps to sort_unique().
Definition: ordered_vector.I:731
pset
This is our own Panda specialization on the default STL set.
Definition: pset.h:49
compareTo.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
compassEffect.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
config_pgraph.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
datagramIterator.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
decalEffect.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
indent
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
indent.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
lightMutexHolder.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
lightReMutexHolder.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
polylightEffect.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CPT
CPT(TransformState) RenderEffects
Preprocesses the accumulated transform that is about to be applied to (or through) this node due to a...
Definition: renderEffects.cxx:86
renderEffects.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
showBoundsEffect.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
thread.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.