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