Panda3D
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 ////////////////////////////////////////////////////////////////////
45 RenderEffects::
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::
138 safe_to_combine() const {
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::
465 get_num_states() {
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
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 is_empty() const
Returns true if the state 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
size_type_0 size() const
Returns the number of elements in the ordered vector.
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.
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.
bool debug_is_locked() const
Returns true if the current thread has locked the LightReMutex, false otherwise.
A lightweight reentrant mutex.
Definition: lightReMutex.h:34
This collects together the pieces of data that are accumulated for each node while walking the scene ...
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.
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...
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...
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:917
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.
void cull_callback(CullTraverser *trav, CullTraverserData &data, CPT(TransformState) &node_transform, CPT(RenderState) &node_state) const
Calls cull_callback() on all effects.
static Thread * get_main_thread()
Returns a pointer to the "main" Thread object–this is the Thread that started the whole process...
Definition: thread.I:107
virtual bool require_fully_complete() const
Some objects require all of their nested pointers to have been completed before the objects themselve...
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()...
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:451
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: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:886
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: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...
int get_ref_count() const
Returns the current reference count.
void add_uint16(PN_uint16 value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:181
virtual bool unref() const
Explicitly decrements the reference count.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:213
const RenderEffect * get_effect(int n) const
Returns the nth effect in the state.
void adjust_transform(CPT(TransformState) &net_transform, CPT(TransformState) &node_transform, PandaNode *node) const
Calls adjust_transform() on all effects.
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
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
virtual bool unref() const
Explicitly decrements the reference count.
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:658