|
|
@@ -0,0 +1,618 @@
|
|
|
+// Filename: renderEffects.cxx
|
|
|
+// Created by: drose (14Mar02)
|
|
|
+//
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+//
|
|
|
+// PANDA 3D SOFTWARE
|
|
|
+// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
|
|
|
+//
|
|
|
+// All use of this software is subject to the terms of the Panda 3d
|
|
|
+// Software license. You should have received a copy of this license
|
|
|
+// along with this source code; you will also find a current copy of
|
|
|
+// the license at http://www.panda3d.org/license.txt .
|
|
|
+//
|
|
|
+// To contact the maintainers of this program write to
|
|
|
+// [email protected] .
|
|
|
+//
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+#include "renderEffects.h"
|
|
|
+#include "billboardEffect.h"
|
|
|
+#include "decalEffect.h"
|
|
|
+#include "config_pgraph.h"
|
|
|
+#include "bamReader.h"
|
|
|
+#include "bamWriter.h"
|
|
|
+#include "datagramIterator.h"
|
|
|
+#include "indent.h"
|
|
|
+#include "compareTo.h"
|
|
|
+
|
|
|
+RenderEffects::States RenderEffects::_states;
|
|
|
+CPT(RenderEffects) RenderEffects::_empty_state;
|
|
|
+TypeHandle RenderEffects::_type_handle;
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::Constructor
|
|
|
+// Access: Protected
|
|
|
+// Description: Actually, this could be a private constructor, since
|
|
|
+// no one inherits from RenderEffects, but gcc gives us a
|
|
|
+// spurious warning if all constructors are private.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+RenderEffects::
|
|
|
+RenderEffects() {
|
|
|
+ _saved_entry = _states.end();
|
|
|
+ _flags = 0;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::Copy Constructor
|
|
|
+// Access: Private
|
|
|
+// Description: RenderEffectss are not meant to be copied.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+RenderEffects::
|
|
|
+RenderEffects(const RenderEffects &) {
|
|
|
+ nassertv(false);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::Copy Assignment Operator
|
|
|
+// Access: Private
|
|
|
+// Description: RenderEffectss are not meant to be copied.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void RenderEffects::
|
|
|
+operator = (const RenderEffects &) {
|
|
|
+ nassertv(false);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::Destructor
|
|
|
+// Access: Public, Virtual
|
|
|
+// Description: The destructor is responsible for removing the
|
|
|
+// RenderEffects from the global set if it is there.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+RenderEffects::
|
|
|
+~RenderEffects() {
|
|
|
+ // Remove the deleted RenderEffects object from the global pool.
|
|
|
+ if (_saved_entry != _states.end()) {
|
|
|
+ _states.erase(_saved_entry);
|
|
|
+ _saved_entry = _states.end();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::operator <
|
|
|
+// Access: Public
|
|
|
+// Description: Provides an arbitrary ordering among all unique
|
|
|
+// RenderEffectss, so we can store the essentially
|
|
|
+// different ones in a big set and throw away the rest.
|
|
|
+//
|
|
|
+// This method is not needed outside of the RenderEffects
|
|
|
+// class because all equivalent RenderEffects objects are
|
|
|
+// guaranteed to share the same pointer; thus, a pointer
|
|
|
+// comparison is always sufficient.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+bool RenderEffects::
|
|
|
+operator < (const RenderEffects &other) const {
|
|
|
+ // We must compare all the properties of the effects, not just
|
|
|
+ // the type; thus, we compare them one at a time using compare_to().
|
|
|
+ return lexicographical_compare(_effects.begin(), _effects.end(),
|
|
|
+ other._effects.begin(), other._effects.end(),
|
|
|
+ CompareTo<Effect>());
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::safe_to_transform
|
|
|
+// Access: Public
|
|
|
+// Description: Returns true if all of the effects in this set can
|
|
|
+// safely be transformed, and therefore the complete set
|
|
|
+// can be transformed, by calling xform().
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+bool RenderEffects::
|
|
|
+safe_to_transform() const {
|
|
|
+ Effects::const_iterator ai;
|
|
|
+ for (ai = _effects.begin(); ai != _effects.end(); ++ai) {
|
|
|
+ const Effect &effect = (*ai);
|
|
|
+ if (!effect._effect->safe_to_transform()) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::safe_to_combine
|
|
|
+// Access: Public
|
|
|
+// Description: Returns true if all of the effects in this set can
|
|
|
+// safely be shared with a sibling node that has the
|
|
|
+// exact same set of effects, or false if this would be
|
|
|
+// bad for any of the effects.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+bool RenderEffects::
|
|
|
+safe_to_combine() const {
|
|
|
+ Effects::const_iterator ai;
|
|
|
+ for (ai = _effects.begin(); ai != _effects.end(); ++ai) {
|
|
|
+ const Effect &effect = (*ai);
|
|
|
+ if (!effect._effect->safe_to_combine()) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::xform
|
|
|
+// Access: Public, Virtual
|
|
|
+// Description: Returns a new RenderEffects transformed by the
|
|
|
+// indicated matrix.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+CPT(RenderEffects) RenderEffects::
|
|
|
+xform(const LMatrix4f &mat) const {
|
|
|
+ if (is_empty()) {
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ RenderEffects *new_state = new RenderEffects;
|
|
|
+ back_insert_iterator<Effects> result =
|
|
|
+ back_inserter(new_state->_effects);
|
|
|
+
|
|
|
+ Effects::const_iterator ai;
|
|
|
+ for (ai = _effects.begin(); ai != _effects.end(); ++ai) {
|
|
|
+ const Effect &effect = (*ai);
|
|
|
+ Effect new_effect(effect);
|
|
|
+ new_effect._effect = effect._effect->xform(mat);
|
|
|
+ *result = new_effect;
|
|
|
+ ++result;
|
|
|
+ }
|
|
|
+
|
|
|
+ return return_new(new_state);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::find_effect
|
|
|
+// Access: Published
|
|
|
+// Description: Searches for an effect with the indicated type in
|
|
|
+// the state, and returns its index if it is found, or
|
|
|
+// -1 if it is not.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+int RenderEffects::
|
|
|
+find_effect(TypeHandle type) const {
|
|
|
+ Effects::const_iterator ai = _effects.find(Effect(type));
|
|
|
+ if (ai == _effects.end()) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ return ai - _effects.begin();
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::make_empty
|
|
|
+// Access: Published, Static
|
|
|
+// Description: Returns a RenderEffects with no effects set.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+CPT(RenderEffects) RenderEffects::
|
|
|
+make_empty() {
|
|
|
+ // The empty state is asked for so often, we make it a special case
|
|
|
+ // and store a pointer forever once we find it the first time.
|
|
|
+ if (_empty_state == (RenderEffects *)NULL) {
|
|
|
+ RenderEffects *state = new RenderEffects;
|
|
|
+ _empty_state = return_new(state);
|
|
|
+ }
|
|
|
+
|
|
|
+ return _empty_state;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::make
|
|
|
+// Access: Published, Static
|
|
|
+// Description: Returns a RenderEffects with one effect set.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+CPT(RenderEffects) RenderEffects::
|
|
|
+make(const RenderEffect *effect) {
|
|
|
+ RenderEffects *state = new RenderEffects;
|
|
|
+ state->_effects.reserve(1);
|
|
|
+ state->_effects.insert(Effect(effect));
|
|
|
+ return return_new(state);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::make
|
|
|
+// Access: Published, Static
|
|
|
+// Description: Returns a RenderEffects with two effects set.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+CPT(RenderEffects) RenderEffects::
|
|
|
+make(const RenderEffect *effect1,
|
|
|
+ const RenderEffect *effect2) {
|
|
|
+ RenderEffects *state = new RenderEffects;
|
|
|
+ state->_effects.reserve(2);
|
|
|
+ state->_effects.push_back(Effect(effect1));
|
|
|
+ state->_effects.push_back(Effect(effect2));
|
|
|
+ state->_effects.sort();
|
|
|
+ return return_new(state);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::make
|
|
|
+// Access: Published, Static
|
|
|
+// Description: Returns a RenderEffects with three effects set.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+CPT(RenderEffects) RenderEffects::
|
|
|
+make(const RenderEffect *effect1,
|
|
|
+ const RenderEffect *effect2,
|
|
|
+ const RenderEffect *effect3) {
|
|
|
+ RenderEffects *state = new RenderEffects;
|
|
|
+ state->_effects.reserve(2);
|
|
|
+ state->_effects.push_back(Effect(effect1));
|
|
|
+ state->_effects.push_back(Effect(effect2));
|
|
|
+ state->_effects.push_back(Effect(effect3));
|
|
|
+ state->_effects.sort();
|
|
|
+ return return_new(state);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::make
|
|
|
+// Access: Published, Static
|
|
|
+// Description: Returns a RenderEffects with four effects set.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+CPT(RenderEffects) RenderEffects::
|
|
|
+make(const RenderEffect *effect1,
|
|
|
+ const RenderEffect *effect2,
|
|
|
+ const RenderEffect *effect3,
|
|
|
+ const RenderEffect *effect4) {
|
|
|
+ RenderEffects *state = new RenderEffects;
|
|
|
+ state->_effects.reserve(2);
|
|
|
+ state->_effects.push_back(Effect(effect1));
|
|
|
+ state->_effects.push_back(Effect(effect2));
|
|
|
+ state->_effects.push_back(Effect(effect3));
|
|
|
+ state->_effects.push_back(Effect(effect4));
|
|
|
+ state->_effects.sort();
|
|
|
+ return return_new(state);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::add_effect
|
|
|
+// Access: Published
|
|
|
+// Description: Returns a new RenderEffects object that represents the
|
|
|
+// same as the source state, with the new RenderEffect
|
|
|
+// added. If there is already a RenderEffect with the
|
|
|
+// same type, it is replaced.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+CPT(RenderEffects) RenderEffects::
|
|
|
+add_effect(const RenderEffect *effect) const {
|
|
|
+ RenderEffects *new_state = new RenderEffects;
|
|
|
+ back_insert_iterator<Effects> result =
|
|
|
+ back_inserter(new_state->_effects);
|
|
|
+
|
|
|
+ Effect new_effect(effect);
|
|
|
+ Effects::const_iterator ai = _effects.begin();
|
|
|
+
|
|
|
+ while (ai != _effects.end() && (*ai) < new_effect) {
|
|
|
+ *result = *ai;
|
|
|
+ ++ai;
|
|
|
+ ++result;
|
|
|
+ }
|
|
|
+ *result = new_effect;
|
|
|
+ ++result;
|
|
|
+
|
|
|
+ if (ai != _effects.end() && !(new_effect < (*ai))) {
|
|
|
+ // At this point we know:
|
|
|
+ // !((*ai) < new_effect) && !(new_effect < (*ai))
|
|
|
+ // which means (*ai) == new_effect--so we should leave it out,
|
|
|
+ // to avoid duplicating effects in the set.
|
|
|
+ ++ai;
|
|
|
+ }
|
|
|
+
|
|
|
+ while (ai != _effects.end()) {
|
|
|
+ *result = *ai;
|
|
|
+ ++ai;
|
|
|
+ ++result;
|
|
|
+ }
|
|
|
+
|
|
|
+ return return_new(new_state);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::remove_effect
|
|
|
+// Access: Published
|
|
|
+// Description: Returns a new RenderEffects object that represents the
|
|
|
+// same as the source state, with the indicated
|
|
|
+// RenderEffect removed.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+CPT(RenderEffects) RenderEffects::
|
|
|
+remove_effect(TypeHandle type) const {
|
|
|
+ RenderEffects *new_state = new RenderEffects;
|
|
|
+ back_insert_iterator<Effects> result =
|
|
|
+ back_inserter(new_state->_effects);
|
|
|
+
|
|
|
+ Effects::const_iterator ai = _effects.begin();
|
|
|
+
|
|
|
+ while (ai != _effects.end()) {
|
|
|
+ if ((*ai)._type != type) {
|
|
|
+ *result = *ai;
|
|
|
+ ++result;
|
|
|
+ }
|
|
|
+ ++ai;
|
|
|
+ }
|
|
|
+
|
|
|
+ return return_new(new_state);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::get_effect
|
|
|
+// Access: Published, Virtual
|
|
|
+// Description: Looks for a RenderEffect of the indicated type in the
|
|
|
+// state, and returns it if it is found, or NULL if it
|
|
|
+// is not.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+const RenderEffect *RenderEffects::
|
|
|
+get_effect(TypeHandle type) const {
|
|
|
+ Effects::const_iterator ai;
|
|
|
+ ai = _effects.find(Effect(type));
|
|
|
+ if (ai != _effects.end()) {
|
|
|
+ return (*ai)._effect;
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::output
|
|
|
+// Access: Published, Virtual
|
|
|
+// Description:
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void RenderEffects::
|
|
|
+output(ostream &out) const {
|
|
|
+ out << "E:";
|
|
|
+ if (_effects.empty()) {
|
|
|
+ out << "(empty)";
|
|
|
+
|
|
|
+ } else {
|
|
|
+ Effects::const_iterator ai = _effects.begin();
|
|
|
+ out << "(" << (*ai)._type;
|
|
|
+ ++ai;
|
|
|
+ while (ai != _effects.end()) {
|
|
|
+ out << " " << (*ai)._type;
|
|
|
+ ++ai;
|
|
|
+ }
|
|
|
+ out << ")";
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::write
|
|
|
+// Access: Published, Virtual
|
|
|
+// Description:
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void RenderEffects::
|
|
|
+write(ostream &out, int indent_level) const {
|
|
|
+ indent(out, indent_level) << _effects.size() << " effects:\n";
|
|
|
+ Effects::const_iterator ai;
|
|
|
+ for (ai = _effects.begin(); ai != _effects.end(); ++ai) {
|
|
|
+ const Effect &effect = (*ai);
|
|
|
+ effect._effect->write(out, indent_level + 2);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::return_new
|
|
|
+// Access: Private, Static
|
|
|
+// Description: This function is used to share a common RenderEffects
|
|
|
+// pointer for all equivalent RenderEffects objects.
|
|
|
+//
|
|
|
+// See the similar logic in RenderEffect. The idea is
|
|
|
+// to create a new RenderEffects object and pass it
|
|
|
+// through this function, which will share the pointer
|
|
|
+// with a previously-created RenderEffects object if it is
|
|
|
+// equivalent.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+CPT(RenderEffects) RenderEffects::
|
|
|
+return_new(RenderEffects *state) {
|
|
|
+ nassertr(state != (RenderEffects *)NULL, state);
|
|
|
+
|
|
|
+ // This should be a newly allocated pointer, not one that was used
|
|
|
+ // for anything else.
|
|
|
+ nassertr(state->_saved_entry == _states.end(), state);
|
|
|
+
|
|
|
+ // Save the state in a local PointerTo so that it will be freed at
|
|
|
+ // the end of this function if no one else uses it.
|
|
|
+ CPT(RenderEffects) pt_state = state;
|
|
|
+
|
|
|
+ pair<States::iterator, bool> result = _states.insert(state);
|
|
|
+ if (result.second) {
|
|
|
+ // The state was inserted; save the iterator and return the
|
|
|
+ // input state.
|
|
|
+ state->_saved_entry = result.first;
|
|
|
+ return pt_state;
|
|
|
+ }
|
|
|
+
|
|
|
+ // The state was not inserted; there must be an equivalent one
|
|
|
+ // already in the set. Return that one.
|
|
|
+ return *(result.first);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::determine_billboard
|
|
|
+// Access: Private
|
|
|
+// Description: This is the private implementation of
|
|
|
+// get_billboard().
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void RenderEffects::
|
|
|
+determine_billboard() {
|
|
|
+ const RenderEffect *effect = get_effect(BillboardEffect::get_class_type());
|
|
|
+ _billboard = (const BillboardEffect *)NULL;
|
|
|
+ if (effect != (const RenderEffect *)NULL) {
|
|
|
+ _billboard = DCAST(BillboardEffect, effect);
|
|
|
+ }
|
|
|
+ _flags |= F_checked_billboard;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::determine_decal
|
|
|
+// Access: Private
|
|
|
+// Description: This is the private implementation of has_decal().
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void RenderEffects::
|
|
|
+determine_decal() {
|
|
|
+ const RenderEffect *effect = get_effect(DecalEffect::get_class_type());
|
|
|
+ if (effect != (const RenderEffect *)NULL) {
|
|
|
+ _flags |= F_has_decal;
|
|
|
+ }
|
|
|
+ _flags |= F_checked_decal;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::register_with_read_factory
|
|
|
+// Access: Public, Static
|
|
|
+// Description: Tells the BamReader how to create objects of type
|
|
|
+// RenderEffects.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void RenderEffects::
|
|
|
+register_with_read_factory() {
|
|
|
+ BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::write_datagram
|
|
|
+// Access: Public, Virtual
|
|
|
+// Description: Writes the contents of this object to the datagram
|
|
|
+// for shipping out to a Bam file.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void RenderEffects::
|
|
|
+write_datagram(BamWriter *manager, Datagram &dg) {
|
|
|
+ TypedWritable::write_datagram(manager, dg);
|
|
|
+
|
|
|
+ int num_effects = _effects.size();
|
|
|
+ nassertv(num_effects == (int)(PN_uint16)num_effects);
|
|
|
+ dg.add_uint16(num_effects);
|
|
|
+
|
|
|
+ Effects::const_iterator ai;
|
|
|
+ for (ai = _effects.begin(); ai != _effects.end(); ++ai) {
|
|
|
+ const Effect &effect = (*ai);
|
|
|
+
|
|
|
+ manager->write_pointer(dg, effect._effect);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::complete_pointers
|
|
|
+// Access: Public, Virtual
|
|
|
+// Description: Receives an array of pointers, one for each time
|
|
|
+// manager->read_pointer() was called in fillin().
|
|
|
+// Returns the number of pointers processed.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+int RenderEffects::
|
|
|
+complete_pointers(TypedWritable **p_list, BamReader *manager) {
|
|
|
+ int pi = TypedWritable::complete_pointers(p_list, manager);
|
|
|
+
|
|
|
+ // Get the effect pointers.
|
|
|
+ Effects::iterator ai;
|
|
|
+ for (ai = _effects.begin(); ai != _effects.end(); ++ai) {
|
|
|
+ Effect &effect = (*ai);
|
|
|
+
|
|
|
+ effect._effect = DCAST(RenderEffect, p_list[pi++]);
|
|
|
+ nassertr(effect._effect != (RenderEffect *)NULL, pi);
|
|
|
+ effect._type = effect._effect->get_type();
|
|
|
+ }
|
|
|
+
|
|
|
+ // Now make sure the array is properly sorted. (It won't
|
|
|
+ // necessarily preserve its correct sort after being read from bam,
|
|
|
+ // because the sort is based on TypeHandle indices, which can change
|
|
|
+ // from session to session.)
|
|
|
+ _effects.sort();
|
|
|
+
|
|
|
+ return pi;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::change_this
|
|
|
+// Access: Public, Static
|
|
|
+// Description: Called immediately after complete_pointers(), this
|
|
|
+// gives the object a chance to adjust its own pointer
|
|
|
+// if desired. Most objects don't change pointers after
|
|
|
+// completion, but some need to.
|
|
|
+//
|
|
|
+// Once this function has been called, the old pointer
|
|
|
+// will no longer be accessed.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+TypedWritable *RenderEffects::
|
|
|
+change_this(TypedWritable *old_ptr, BamReader *manager) {
|
|
|
+ // First, uniquify the pointer.
|
|
|
+ RenderEffects *state = DCAST(RenderEffects, old_ptr);
|
|
|
+ CPT(RenderEffects) pointer = return_new(state);
|
|
|
+
|
|
|
+ // But now we have a problem, since we have to hold the reference
|
|
|
+ // count and there's no way to return a TypedWritable while still
|
|
|
+ // holding the reference count! We work around this by explicitly
|
|
|
+ // upping the count, and also setting a finalize() callback to down
|
|
|
+ // it later.
|
|
|
+ if (pointer == state) {
|
|
|
+ pointer->ref();
|
|
|
+ manager->register_finalize(state);
|
|
|
+ }
|
|
|
+
|
|
|
+ // We have to cast the pointer back to non-const, because the bam
|
|
|
+ // reader expects that.
|
|
|
+ return (RenderEffects *)pointer.p();
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::finalize
|
|
|
+// Access: Public, Virtual
|
|
|
+// Description: Called by the BamReader to perform any final actions
|
|
|
+// needed for setting up the object after all objects
|
|
|
+// have been read and all pointers have been completed.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void RenderEffects::
|
|
|
+finalize() {
|
|
|
+ // Unref the pointer that we explicitly reffed in make_from_bam().
|
|
|
+ unref();
|
|
|
+
|
|
|
+ // We should never get back to zero after unreffing our own count,
|
|
|
+ // because we expect to have been stored in a pointer somewhere. If
|
|
|
+ // we do get to zero, it's a memory leak; the way to avoid this is
|
|
|
+ // to call unref_delete() above instead of unref(), but this is
|
|
|
+ // dangerous to do from within a virtual function.
|
|
|
+ nassertv(get_ref_count() != 0);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::make_from_bam
|
|
|
+// Access: Protected, Static
|
|
|
+// Description: This function is called by the BamReader's factory
|
|
|
+// when a new object of type RenderEffects is encountered
|
|
|
+// in the Bam file. It should create the RenderEffects
|
|
|
+// and extract its information from the file.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+TypedWritable *RenderEffects::
|
|
|
+make_from_bam(const FactoryParams ¶ms) {
|
|
|
+ RenderEffects *state = new RenderEffects;
|
|
|
+ DatagramIterator scan;
|
|
|
+ BamReader *manager;
|
|
|
+
|
|
|
+ parse_params(params, scan, manager);
|
|
|
+ state->fillin(scan, manager);
|
|
|
+ manager->register_change_this(change_this, state);
|
|
|
+
|
|
|
+ return state;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: RenderEffects::fillin
|
|
|
+// Access: Protected
|
|
|
+// Description: This internal function is called by make_from_bam to
|
|
|
+// read in all of the relevant data from the BamFile for
|
|
|
+// the new RenderEffects.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void RenderEffects::
|
|
|
+fillin(DatagramIterator &scan, BamReader *manager) {
|
|
|
+ TypedWritable::fillin(scan, manager);
|
|
|
+
|
|
|
+ int num_effects = scan.get_uint16();
|
|
|
+
|
|
|
+ // Push back a NULL pointer for each effect for now, until we get
|
|
|
+ // the actual list of pointers later in complete_pointers().
|
|
|
+ _effects.reserve(num_effects);
|
|
|
+ for (int i = 0; i < num_effects; i++) {
|
|
|
+ manager->read_pointer(scan);
|
|
|
+ _effects.push_back(Effect());
|
|
|
+ }
|
|
|
+}
|