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
19RenderEffect::Effects *RenderEffect::_effects = nullptr;
20TypeHandle RenderEffect::_type_handle;
21
22/**
23 *
24 */
25RenderEffect::
26RenderEffect() {
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 */
68safe_to_transform() const {
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 */
77CPT(TransformState) RenderEffect::
78prepare_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 */
87bool RenderEffect::
88safe_to_combine() const {
89 return true;
90}
91
92/**
93 * Returns a new RenderEffect transformed by the indicated matrix.
94 */
95CPT(RenderEffect) RenderEffect::
96xform(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 */
105bool RenderEffect::
106has_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 */
122void RenderEffect::
123cull_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 */
132bool RenderEffect::
133has_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 */
145void RenderEffect::
146adjust_transform(CPT(TransformState) &, CPT(TransformState) &,
147 const PandaNode *) const {
148}
149
150/**
151 *
152 */
153void RenderEffect::
154output(std::ostream &out) const {
155 out << get_type();
156}
157
158/**
159 *
160 */
161void RenderEffect::
162write(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 */
170int RenderEffect::
171get_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 */
184list_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 */
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 */
232CPT(RenderEffect) RenderEffect::
233return_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 */
273int RenderEffect::
274compare_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 */
283write_datagram(BamWriter *manager, Datagram &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 */
296change_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 */
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 */
337void RenderEffect::
338fillin(DatagramIterator &scan, BamReader *manager) {
339 TypedWritable::fillin(scan, manager);
340}
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
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
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
This collects together the pieces of data that are accumulated for each node while walking the scene ...
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
Definition: cullTraverser.h:45
A class to retrieve the individual data elements previously stored in a Datagram.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
get_ref_count
Returns the current reference count.
virtual bool unref() const
Explicitly decrements the reference count.
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
static void list_effects(std::ostream &out)
Lists all of the RenderEffects in the cache to the output stream, one per line.
virtual ~RenderEffect()
The destructor is responsible for removing the RenderEffect from the global set if it is there.
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 finalize(BamReader *manager)
Called by the BamReader to perform any final actions needed for setting up the object after all objec...
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 TypedWritable * change_this(TypedWritable *old_ptr, BamReader *manager)
Called immediately after complete_pointers(), this gives the object a chance to adjust its own pointe...
static bool validate_effects()
Ensures that the cache is still stored in sorted order.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
Indicates a coordinate-system transform on vertices.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
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.
This is our own Panda specialization on the default STL set.
Definition: pset.h:49
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: dcindent.cxx:22
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CPT(TransformState) RenderEffect
Preprocesses the accumulated transform that is about to be applied to (or through) this node due to a...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.