Panda3D
Loading...
Searching...
No Matches
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...
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,...
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...
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.
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 indent.cxx:20
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.