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