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  */
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::
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(),
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  */
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::
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::
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::
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::
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::
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::
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::
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::
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  */
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::
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 }
static void list_states(std::ostream &out)
Lists all of the RenderEffects in the cache to the output stream, one per line.
A basic node of the scene graph or data graph.
Definition: pandaNode.h:64
An STL function object class, this is intended to be used on any ordered collection of classes that c...
Definition: compareTo.h:25
get_ref_count
Returns the current reference count.
Indicates a coordinate-system transform on vertices.
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...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CPT(TransformState) RenderEffects
Preprocesses the accumulated transform that is about to be applied to (or through) this node due to a...
bool is_empty() const
Returns true if the state is empty, false otherwise.
Definition: renderEffects.I:94
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
size_type_0 size() const
Returns the number of elements in the ordered vector.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool safe_to_transform() const
Returns true if all of the effects in this set can safely be transformed, and therefore the complete ...
static void init_states()
Make sure the global _states map is allocated.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
iterator_0 begin()
Returns the iterator that marks the first element in the ordered vector.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool debug_is_locked() const
Returns true if the current thread has locked the LightReMutex, false otherwise.
A lightweight reentrant mutex.
Definition: lightReMutex.h:30
This collects together the pieces of data that are accumulated for each node while walking the scene ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Applied to a GeomNode to cause a visible bounding volume to be drawn for this node.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
iterator_0 end()
Returns the iterator that marks the end of the ordered vector.
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...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool empty() const
Returns true if the ordered vector is empty, false otherwise.
bool get_tight() const
Returns true if the "tight" flag was set, meaning the effect should compute and draw the tight boundi...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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...
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
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static bool validate_states()
Ensures that the cache is still stored in sorted order.
void cull_callback(CullTraverser *trav, CullTraverserData &data, CPT(TransformState) &node_transform, CPT(RenderState) &node_state) const
Calls cull_callback() on all effects.
void adjust_transform(CPT(TransformState) &net_transform, CPT(TransformState) &node_transform, const PandaNode *node) const
Calls adjust_transform() on all effects.
virtual bool require_fully_complete() const
Some objects require all of their nested pointers to have been completed before the objects themselve...
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
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:85
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 int complete_pointers(TypedWritable **p_list, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
Similar to MutexHolder, but for a light mutex.
void sort()
Maps to sort_unique().
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:73
const RenderEffect * get_effect(size_t n) const
Returns the nth effect in the state.
static void register_with_read_factory()
Tells the BamReader how to create objects of type RenderEffects.
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Similar to MutexHolder, but for a light reentrant mutex.
void push_back(const value_type_0 &key)
Adds the new element to the end of the vector without regard for proper sorting.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void finalize(BamReader *manager)
Called by the BamReader to perform any final actions needed for setting up the object after all objec...
virtual bool unref() const
Explicitly decrements the reference count.
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:610
This is our own Panda specialization on the default STL set.
Definition: pset.h:49
A class to retrieve the individual data elements previously stored in a Datagram.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
virtual ~RenderEffects()
The destructor is responsible for removing the RenderEffects from the global set if it is there.
This represents a unique collection of RenderEffect objects that correspond to a particular renderabl...
Definition: renderEffects.h:41
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
Definition: cullTraverser.h:45
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual bool unref() const
Explicitly decrements the reference count.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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