Panda3D
Loading...
Searching...
No Matches
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
32LightReMutex *RenderEffects::_states_lock = nullptr;
33RenderEffects::States *RenderEffects::_states = nullptr;
34CPT(RenderEffects) RenderEffects::_empty_state;
35TypeHandle 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 */
42RenderEffects::
43RenderEffects() : _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 */
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 */
69safe_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 */
86CPT(TransformState) RenderEffects::
87prepare_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 */
103bool RenderEffects::
104safe_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 */
119CPT(RenderEffects) RenderEffects::
120xform(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 */
149bool RenderEffects::
150operator < (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(),
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 */
163int RenderEffects::
164find_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 */
175CPT(RenderEffects) RenderEffects::
176make_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 */
190CPT(RenderEffects) RenderEffects::
191make(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 */
201CPT(RenderEffects) RenderEffects::
202make(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 */
215CPT(RenderEffects) RenderEffects::
216make(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 */
231CPT(RenderEffects) RenderEffects::
232make(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 */
251CPT(RenderEffects) RenderEffects::
252add_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 */
288CPT(RenderEffects) RenderEffects::
289remove_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 */
312get_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 */
334unref() 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 */
353void RenderEffects::
354output(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 */
374void RenderEffects::
375write(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 */
388int RenderEffects::
389get_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 */
403list_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 */
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 */
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 */
477adjust_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 */
494init_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");
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 */
515CPT(RenderEffects) RenderEffects::
516return_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 */
560void RenderEffects::
561release_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 */
574void RenderEffects::
575determine_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 */
592void RenderEffects::
593determine_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 */
614void RenderEffects::
615determine_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 */
636void RenderEffects::
637determine_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 */
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 */
668write_datagram(BamWriter *manager, Datagram &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 */
688complete_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 */
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 */
744change_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 */
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 */
786TypedWritable *RenderEffects::
787make_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 */
803void RenderEffects::
804fillin(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}
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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 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...
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
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.
An STL function object class, this is intended to be used on any ordered collection of classes that c...
Definition compareTo.h:25
This collects together the pieces of data that are accumulated for each node while walking the scene ...
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
A class to retrieve the individual data elements previously stored in a Datagram.
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition datagram.h:38
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
Similar to MutexHolder, but for a light mutex.
bool debug_is_locked() const
Returns true if the current thread has locked the LightReMutex, false otherwise.
Similar to MutexHolder, but for a light reentrant mutex.
A lightweight reentrant mutex.
A basic node of the scene graph or data graph.
Definition pandaNode.h:65
get_ref_count
Returns the current reference count.
virtual bool unref() const
Explicitly decrements the reference count.
This is the base class for a number of special render effects that may be set on scene graph nodes to...
This represents a unique collection of RenderEffect objects that correspond to a particular renderabl...
virtual void finalize(BamReader *manager)
Called by the BamReader to perform any final actions needed for setting up the object after all objec...
static void list_states(std::ostream &out)
Lists all of the RenderEffects in the cache to the output stream, one per line.
void adjust_transform(CPT(TransformState) &net_transform, CPT(TransformState) &node_transform, const PandaNode *node) const
Calls adjust_transform() on all effects.
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
virtual ~RenderEffects()
The destructor is responsible for removing the RenderEffects from the global set if it is there.
bool is_empty() const
Returns true if the state is empty, false otherwise.
static bool validate_states()
Ensures that the cache is still stored in sorted order.
virtual bool unref() const
Explicitly decrements the reference count.
const RenderEffect * get_effect(size_t n) const
Returns the nth effect in the state.
bool safe_to_transform() const
Returns true if all of the effects in this set can safely be transformed, and therefore the complete ...
virtual bool require_fully_complete() const
Some objects require all of their nested pointers to have been completed before the objects themselve...
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 TypedWritable * change_this(TypedWritable *old_ptr, BamReader *manager)
Called immediately after complete_pointers(), this gives the object a chance to adjust its own pointe...
void cull_callback(CullTraverser *trav, CullTraverserData &data, CPT(TransformState) &node_transform, CPT(RenderState) &node_state) const
Calls cull_callback() on all effects.
static void init_states()
Make sure the global _states map is allocated.
static void register_with_read_factory()
Tells the BamReader how to create objects of type RenderEffects.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition renderState.h:47
Applied to a GeomNode to cause a visible bounding volume to be drawn for this node.
bool get_tight() const
Returns true if the "tight" flag was set, meaning the effect should compute and draw the tight boundi...
get_main_thread
Returns a pointer to the "main" Thread object–this is the Thread that started the whole process.
Definition thread.h:107
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition thread.h:109
Indicates a coordinate-system transform on vertices.
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
Base class for objects that can be written to and read from Bam files.
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...
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
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().
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.
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().
This is our own Panda specialization on the default STL set.
Definition pset.h:49
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.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition indent.cxx:20
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.