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 }
A basic node of the scene graph or data graph.
Definition: pandaNode.h:64
get_ref_count
Returns the current reference count.
Indicates a coordinate-system transform on vertices.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
static bool validate_effects()
Ensures that the cache is still stored in sorted order.
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
CPT(TransformState) RenderEffect
Preprocesses the accumulated transform that is about to be applied to (or through) this node due to a...
This collects together the pieces of data that are accumulated for each node while walking the scene ...
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
This is the base class for a number of special render effects that may be set on scene graph nodes to...
Definition: renderEffect.h:48
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void fillin(DatagramIterator &scan, BamReader *manager)
This internal function is intended to be called by each class's make_from_bam() method to read in all...
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
virtual void finalize(BamReader *manager)
Called by the BamReader to perform any final actions needed for setting up the object after all objec...
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...
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
void register_finalize(TypedWritable *whom)
Should be called by an object reading itself from the Bam file to indicate that this particular objec...
Definition: bamReader.cxx:808
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
virtual bool safe_to_transform() const
Returns true if it is generally safe to transform this particular kind of RenderEffect by calling the...
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 is our own Panda specialization on the default STL set.
Definition: pset.h:49
A class to retrieve the individual data elements previously stored in a Datagram.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
virtual ~RenderEffect()
The destructor is responsible for removing the RenderEffect from the global set if it is there.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
Definition: cullTraverser.h:45
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual bool unref() const
Explicitly decrements the reference count.
static void list_effects(std::ostream &out)
Lists all of the RenderEffects in the cache to the output stream, one per line.