Panda3D
renderEffect.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 renderEffect.cxx
10  * @author drose
11  * @date 2002-03-14
12  */
13 
14 #include "renderEffect.h"
15 #include "bamReader.h"
16 #include "indent.h"
17 #include "config_pgraph.h"
18 
19 RenderEffect::Effects *RenderEffect::_effects = nullptr;
20 TypeHandle RenderEffect::_type_handle;
21 
22 /**
23  *
24  */
25 RenderEffect::
26 RenderEffect() {
27  if (_effects == nullptr) {
28  // Make sure the global _effects map is allocated. This only has to be
29  // done once. We could make this map static, but then we run into
30  // problems if anyone creates a RenderState object at static init time; it
31  // also seems to cause problems when the Panda shared library is unloaded
32  // at application exit time.
33  _effects = new Effects;
34  }
35  _saved_entry = _effects->end();
36 }
37 
38 /**
39  * The destructor is responsible for removing the RenderEffect from the global
40  * set if it is there.
41  */
44  if (_saved_entry != _effects->end()) {
45  // We cannot make this assertion, because the RenderEffect has already
46  // partially destructed--this means we cannot look up the object in the
47  // map. In fact, the map is temporarily invalid until we finish
48  // destructing, since we screwed up the ordering when we changed the
49  // return value of get_type(). nassertv(_effects->find(this) ==
50  // _saved_entry);
51 
52  // Note: this isn't thread-safe, because once the derived class destructor
53  // exits and before this destructor completes, the map is invalid, and
54  // other threads may inadvertently attempt to read the invalid map. To
55  // make it thread-safe, we need to move this functionality to a separate
56  // method, that is to be called from *each* derived class's destructor
57  // (and then we can put the above assert back in).
58  _effects->erase(_saved_entry);
59  _saved_entry = _effects->end();
60  }
61 }
62 
63 /**
64  * Returns true if it is generally safe to transform this particular kind of
65  * RenderEffect by calling the xform() method, false otherwise.
66  */
67 bool RenderEffect::
69  return true;
70 }
71 
72 /**
73  * Preprocesses the accumulated transform that is about to be applied to (or
74  * through) this node due to a flatten operation. The returned value will be
75  * used instead.
76  */
77 CPT(TransformState) RenderEffect::
78 prepare_flatten_transform(const TransformState *net_transform) const {
79  return net_transform;
80 }
81 
82 /**
83  * Returns true if this kind of effect can safely be combined with sibling
84  * nodes that share the exact same effect, or false if this is not a good
85  * idea.
86  */
87 bool RenderEffect::
88 safe_to_combine() const {
89  return true;
90 }
91 
92 /**
93  * Returns a new RenderEffect transformed by the indicated matrix.
94  */
95 CPT(RenderEffect) RenderEffect::
96 xform(const LMatrix4 &) const {
97  return this;
98 }
99 
100 /**
101  * Should be overridden by derived classes to return true if cull_callback()
102  * has been defined. Otherwise, returns false to indicate cull_callback()
103  * does not need to be called for this effect during the cull traversal.
104  */
105 bool RenderEffect::
106 has_cull_callback() const {
107  return false;
108 }
109 
110 /**
111  * If has_cull_callback() returns true, this function will be called during
112  * the cull traversal to perform any additional operations that should be
113  * performed at cull time. This may include additional manipulation of render
114  * state or additional visible/invisible decisions, or any other arbitrary
115  * operation.
116  *
117  * At the time this function is called, the current node's transform and state
118  * have not yet been applied to the net_transform and net_state. This
119  * callback may modify the node_transform and node_state to apply an effective
120  * change to the render state at this level.
121  */
122 void RenderEffect::
123 cull_callback(CullTraverser *, CullTraverserData &,
124  CPT(TransformState) &, CPT(RenderState) &) const {
125 }
126 
127 /**
128  * Should be overridden by derived classes to return true if
129  * adjust_transform() has been defined, and therefore the RenderEffect has
130  * some effect on the node's apparent local and net transforms.
131  */
132 bool RenderEffect::
133 has_adjust_transform() const {
134  return false;
135 }
136 
137 /**
138  * Performs some operation on the node's apparent net and/or local transforms.
139  * This will only be called if has_adjust_transform() is redefined to return
140  * true.
141  *
142  * Both parameters are in/out. The original transforms will be passed in, and
143  * they may (or may not) be modified in-place by the RenderEffect.
144  */
145 void RenderEffect::
146 adjust_transform(CPT(TransformState) &, CPT(TransformState) &,
147  const PandaNode *) const {
148 }
149 
150 /**
151  *
152  */
153 void RenderEffect::
154 output(std::ostream &out) const {
155  out << get_type();
156 }
157 
158 /**
159  *
160  */
161 void RenderEffect::
162 write(std::ostream &out, int indent_level) const {
163  indent(out, indent_level) << *this << "\n";
164 }
165 
166 /**
167  * Returns the total number of unique RenderEffect objects allocated in the
168  * world. This will go up and down during normal operations.
169  */
170 int RenderEffect::
171 get_num_effects() {
172  if (_effects == nullptr) {
173  return 0;
174  }
175  return _effects->size();
176 }
177 
178 /**
179  * Lists all of the RenderEffects in the cache to the output stream, one per
180  * line. This can be quite a lot of output if the cache is large, so be
181  * prepared.
182  */
183 void RenderEffect::
184 list_effects(std::ostream &out) {
185  out << _effects->size() << " effects:\n";
186  Effects::const_iterator si;
187  for (si = _effects->begin(); si != _effects->end(); ++si) {
188  const RenderEffect *effect = (*si);
189  effect->write(out, 2);
190  }
191 }
192 
193 /**
194  * Ensures that the cache is still stored in sorted order. Returns true if
195  * so, false if there is a problem (which implies someone has modified one of
196  * the supposedly-const RenderEffect objects).
197  */
198 bool RenderEffect::
200  if (_effects->empty()) {
201  return true;
202  }
203 
204  Effects::const_iterator si = _effects->begin();
205  Effects::const_iterator snext = si;
206  ++snext;
207  while (snext != _effects->end()) {
208  if ((*si)->compare_to(*(*snext)) >= 0) {
209  pgraph_cat.error()
210  << "RenderEffects out of order!\n";
211  (*si)->write(pgraph_cat.error(false), 2);
212  (*snext)->write(pgraph_cat.error(false), 2);
213  return false;
214  }
215  si = snext;
216  ++snext;
217  }
218 
219  return true;
220 }
221 
222 /**
223  * This function is used by derived RenderEffect types to share a common
224  * RenderEffect pointer for all equivalent RenderEffect objects.
225  *
226  * The make() function of the derived type should create a new RenderEffect
227  * and pass it through return_new(), which will either save the pointer and
228  * return it unchanged (if this is the first similar such object) or delete it
229  * and return an equivalent pointer (if there was already a similar object
230  * saved).
231  */
232 CPT(RenderEffect) RenderEffect::
233 return_new(RenderEffect *effect) {
234  nassertr(effect != nullptr, effect);
235 
236  // This should be a newly allocated pointer, not one that was used for
237  // anything else.
238  nassertr(effect->_saved_entry == _effects->end(), effect);
239 
240 #ifndef NDEBUG
241  if (paranoid_const) {
242  nassertr(validate_effects(), effect);
243  }
244 #endif
245 
246  // Save the effect in a local PointerTo so that it will be freed at the end
247  // of this function if no one else uses it.
248  CPT(RenderEffect) pt_effect = effect;
249 
250  std::pair<Effects::iterator, bool> result = _effects->insert(effect);
251  if (result.second) {
252  // The effect was inserted; save the iterator and return the input effect.
253  effect->_saved_entry = result.first;
254  return pt_effect;
255  }
256 
257  // The effect was not inserted; there must be an equivalent one already in
258  // the set. Return that one.
259  return *(result.first);
260 }
261 
262 /**
263  * Intended to be overridden by derived RenderEffect types to return a unique
264  * number indicating whether this RenderEffect is equivalent to the other one.
265  *
266  * This should return 0 if the two RenderEffect objects are equivalent, a
267  * number less than zero if this one should be sorted before the other one,
268  * and a number greater than zero otherwise.
269  *
270  * This will only be called with two RenderEffect objects whose get_type()
271  * functions return the same.
272  */
273 int RenderEffect::
274 compare_to_impl(const RenderEffect *other) const {
275  return 0;
276 }
277 
278 /**
279  * Writes the contents of this object to the datagram for shipping out to a
280  * Bam file.
281  */
282 void RenderEffect::
284  TypedWritable::write_datagram(manager, dg);
285 }
286 
287 /**
288  * Called immediately after complete_pointers(), this gives the object a
289  * chance to adjust its own pointer if desired. Most objects don't change
290  * pointers after completion, but some need to.
291  *
292  * Once this function has been called, the old pointer will no longer be
293  * accessed.
294  */
296 change_this(TypedWritable *old_ptr, BamReader *manager) {
297  // First, uniquify the pointer.
298  RenderEffect *effect = DCAST(RenderEffect, old_ptr);
299  CPT(RenderEffect) pointer = return_new(effect);
300 
301  // But now we have a problem, since we have to hold the reference count and
302  // there's no way to return a TypedWritable while still holding the
303  // reference count! We work around this by explicitly upping the count, and
304  // also setting a finalize() callback to down it later.
305  if (pointer == effect) {
306  pointer->ref();
307  manager->register_finalize(effect);
308  }
309 
310  // We have to cast the pointer back to non-const, because the bam reader
311  // expects that.
312  return (RenderEffect *)pointer.p();
313 }
314 
315 /**
316  * Called by the BamReader to perform any final actions needed for setting up
317  * the object after all objects have been read and all pointers have been
318  * completed.
319  */
320 void RenderEffect::
322  // Unref the pointer that we explicitly reffed in change_this().
323  unref();
324 
325  // We should never get back to zero after unreffing our own count, because
326  // we expect to have been stored in a pointer somewhere. If we do get to
327  // zero, it's a memory leak; the way to avoid this is to call unref_delete()
328  // above instead of unref(), but this is dangerous to do from within a
329  // virtual function.
330  nassertv(get_ref_count() != 0);
331 }
332 
333 /**
334  * This internal function is called by make_from_bam to read in all of the
335  * relevant data from the BamFile for the new RenderEffect.
336  */
337 void RenderEffect::
338 fillin(DatagramIterator &scan, BamReader *manager) {
339  TypedWritable::fillin(scan, manager);
340 }
indent
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
RenderEffect::validate_effects
static bool validate_effects()
Ensures that the cache is still stored in sorted order.
Definition: renderEffect.cxx:199
RenderEffect
This is the base class for a number of special render effects that may be set on scene graph nodes to...
Definition: renderEffect.h:48
DatagramIterator
A class to retrieve the individual data elements previously stored in a Datagram.
Definition: datagramIterator.h:27
BamReader
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
BamWriter
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
CullTraverser
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
Definition: cullTraverser.h:45
RenderEffect::safe_to_transform
virtual bool safe_to_transform() const
Returns true if it is generally safe to transform this particular kind of RenderEffect by calling the...
Definition: renderEffect.cxx:68
bamReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypedWritable
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
Datagram
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
RenderState
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
BamReader::register_finalize
void register_finalize(TypedWritable *whom)
Should be called by an object reading itself from the Bam file to indicate that this particular objec...
Definition: bamReader.cxx:808
CPT
CPT(TransformState) RenderEffect
Preprocesses the accumulated transform that is about to be applied to (or through) this node due to a...
Definition: renderEffect.cxx:77
RenderEffect::change_this
static TypedWritable * change_this(TypedWritable *old_ptr, BamReader *manager)
Called immediately after complete_pointers(), this gives the object a chance to adjust its own pointe...
Definition: renderEffect.cxx:296
RenderEffect::list_effects
static void list_effects(std::ostream &out)
Lists all of the RenderEffects in the cache to the output stream, one per line.
Definition: renderEffect.cxx:184
TypedWritable::write_datagram
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: typedWritable.cxx:54
TransformState
Indicates a coordinate-system transform on vertices.
Definition: transformState.h:54
RenderEffect::finalize
virtual void finalize(BamReader *manager)
Called by the BamReader to perform any final actions needed for setting up the object after all objec...
Definition: renderEffect.cxx:321
CullTraverserData
This collects together the pieces of data that are accumulated for each node while walking the scene ...
Definition: cullTraverserData.h:40
RenderEffect::write_datagram
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: renderEffect.cxx:283
ReferenceCount::unref
virtual bool unref() const
Explicitly decrements the reference count.
Definition: referenceCount.I:179
renderEffect.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
indent.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypedWritable::fillin
virtual void fillin(DatagramIterator &scan, BamReader *manager)
This internal function is intended to be called by each class's make_from_bam() method to read in all...
Definition: typedWritable.cxx:103
PandaNode
A basic node of the scene graph or data graph.
Definition: pandaNode.h:64
config_pgraph.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ReferenceCount::get_ref_count
get_ref_count
Returns the current reference count.
Definition: referenceCount.h:53
pset
This is our own Panda specialization on the default STL set.
Definition: pset.h:49
RenderEffect::~RenderEffect
virtual ~RenderEffect()
The destructor is responsible for removing the RenderEffect from the global set if it is there.
Definition: renderEffect.cxx:43