From 9d62ca9f98b29995f770fbfd083b5760ef52e523 Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 4 May 2010 22:39:40 +0000 Subject: [PATCH] one override per TextureStage, instead of a global override per TextureAttrib --- panda/src/egg2pg/eggLoader.cxx | 3 +- panda/src/gobj/Sources.pp | 3 + panda/src/gobj/gobj_composite2.cxx | 1 + panda/src/gobj/materialPool.I | 27 +- panda/src/gobj/materialPool.cxx | 31 +- panda/src/gobj/materialPool.h | 9 +- panda/src/gobj/textureStage.I | 40 +- panda/src/gobj/textureStage.cxx | 116 +++++ panda/src/gobj/textureStage.h | 8 +- panda/src/gobj/textureStagePool.I | 115 +++++ panda/src/gobj/textureStagePool.cxx | 332 ++++++++++++++ panda/src/gobj/textureStagePool.h | 93 ++++ panda/src/pgraph/nodePath.cxx | 20 +- panda/src/pgraph/renderAttrib.I | 4 +- panda/src/pgraph/renderAttrib.cxx | 2 +- panda/src/pgraph/renderAttrib.h | 2 + panda/src/pgraph/textureAttrib.I | 83 ++-- panda/src/pgraph/textureAttrib.cxx | 461 ++++++++------------ panda/src/pgraph/textureAttrib.h | 36 +- panda/src/pgraph/textureStageCollection.I | 11 + panda/src/pgraph/textureStageCollection.cxx | 2 +- panda/src/pgraph/textureStageCollection.h | 6 + panda/src/putil/bam.h | 3 +- 23 files changed, 1038 insertions(+), 370 deletions(-) create mode 100644 panda/src/gobj/textureStagePool.I create mode 100644 panda/src/gobj/textureStagePool.cxx create mode 100644 panda/src/gobj/textureStagePool.h diff --git a/panda/src/egg2pg/eggLoader.cxx b/panda/src/egg2pg/eggLoader.cxx index 8f6838acfc..1173844e70 100644 --- a/panda/src/egg2pg/eggLoader.cxx +++ b/panda/src/egg2pg/eggLoader.cxx @@ -91,6 +91,7 @@ #include "bitArray.h" #include "thread.h" #include "uvScrollNode.h" +#include "textureStagePool.h" #include #include @@ -1568,7 +1569,7 @@ make_texture_stage(const EggTexture *egg_tex) { stage->set_color(egg_tex->get_color()); } - return stage; + return TextureStagePool::get_stage(stage); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/gobj/Sources.pp b/panda/src/gobj/Sources.pp index 2a518f13b0..0e6b0cdeda 100644 --- a/panda/src/gobj/Sources.pp +++ b/panda/src/gobj/Sources.pp @@ -63,6 +63,7 @@ texturePoolFilter.I texturePoolFilter.h \ textureReloadRequest.I textureReloadRequest.h \ textureStage.I textureStage.h \ + textureStagePool.I textureStagePool.h \ transformBlend.I transformBlend.h \ transformBlendTable.I transformBlendTable.h \ transformTable.I transformTable.h \ @@ -131,6 +132,7 @@ texturePoolFilter.cxx \ textureReloadRequest.cxx \ textureStage.cxx \ + textureStagePool.cxx \ transformBlend.cxx \ transformBlendTable.cxx \ transformTable.cxx \ @@ -201,6 +203,7 @@ texturePoolFilter.I texturePoolFilter.h \ textureReloadRequest.I textureReloadRequest.h \ textureStage.I textureStage.h \ + textureStagePool.I textureStagePool.h \ transformBlend.I transformBlend.h \ transformBlendTable.I transformBlendTable.h \ transformTable.I transformTable.h \ diff --git a/panda/src/gobj/gobj_composite2.cxx b/panda/src/gobj/gobj_composite2.cxx index 44489c29c4..0238604980 100644 --- a/panda/src/gobj/gobj_composite2.cxx +++ b/panda/src/gobj/gobj_composite2.cxx @@ -20,6 +20,7 @@ #include "texturePoolFilter.cxx" #include "textureReloadRequest.cxx" #include "textureStage.cxx" +#include "textureStagePool.cxx" #include "transformBlend.cxx" #include "transformBlendTable.cxx" #include "transformTable.cxx" diff --git a/panda/src/gobj/materialPool.I b/panda/src/gobj/materialPool.I index 678ee99150..0fc4774f0f 100644 --- a/panda/src/gobj/materialPool.I +++ b/panda/src/gobj/materialPool.I @@ -35,7 +35,28 @@ //////////////////////////////////////////////////////////////////// INLINE Material *MaterialPool:: get_material(Material *temp) { - return get_ptr()->ns_get_material(temp); + return get_global_ptr()->ns_get_material(temp); +} + +//////////////////////////////////////////////////////////////////// +// Function: MaterialPool::release_material +// Access: Published, Static +// Description: Removes the indicated material from the pool. +//////////////////////////////////////////////////////////////////// +INLINE void MaterialPool:: +release_material(Material *material) { + get_global_ptr()->ns_release_material(material); +} + +//////////////////////////////////////////////////////////////////// +// Function: MaterialPool::release_all_materials +// Access: Published, Static +// Description: Releases all materials in the pool and restores the +// pool to the empty state. +//////////////////////////////////////////////////////////////////// +INLINE void MaterialPool:: +release_all_materials() { + get_global_ptr()->ns_release_all_materials(); } //////////////////////////////////////////////////////////////////// @@ -48,7 +69,7 @@ get_material(Material *temp) { //////////////////////////////////////////////////////////////////// INLINE int MaterialPool:: garbage_collect() { - return get_ptr()->ns_garbage_collect(); + return get_global_ptr()->ns_garbage_collect(); } //////////////////////////////////////////////////////////////////// @@ -59,7 +80,7 @@ garbage_collect() { //////////////////////////////////////////////////////////////////// INLINE void MaterialPool:: list_contents(ostream &out) { - get_ptr()->ns_list_contents(out); + get_global_ptr()->ns_list_contents(out); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/gobj/materialPool.cxx b/panda/src/gobj/materialPool.cxx index 193892a90e..464f3a73d2 100644 --- a/panda/src/gobj/materialPool.cxx +++ b/panda/src/gobj/materialPool.cxx @@ -27,7 +27,7 @@ MaterialPool *MaterialPool::_global_ptr = (MaterialPool *)NULL; //////////////////////////////////////////////////////////////////// void MaterialPool:: write(ostream &out) { - get_ptr()->ns_list_contents(out); + get_global_ptr()->ns_list_contents(out); } //////////////////////////////////////////////////////////////////// @@ -53,6 +53,31 @@ ns_get_material(Material *temp) { return (*mi).second; } +//////////////////////////////////////////////////////////////////// +// Function: MaterialPool::ns_release_material +// Access: Private +// Description: The nonstatic implementation of release_material(). +//////////////////////////////////////////////////////////////////// +void MaterialPool:: +ns_release_material(Material *temp) { + LightMutexHolder holder(_lock); + + CPT(Material) cpttemp = temp; + _materials.erase(cpttemp); +} + +//////////////////////////////////////////////////////////////////// +// Function: MaterialPool::ns_release_all_materials +// Access: Private +// Description: The nonstatic implementation of release_all_materials(). +//////////////////////////////////////////////////////////////////// +void MaterialPool:: +ns_release_all_materials() { + LightMutexHolder holder(_lock); + + _materials.clear(); +} + //////////////////////////////////////////////////////////////////// // Function: MaterialPool::ns_garbage_collect // Access: Private @@ -104,13 +129,13 @@ ns_list_contents(ostream &out) const { } //////////////////////////////////////////////////////////////////// -// Function: MaterialPool::get_ptr +// Function: MaterialPool::get_global_ptr // Access: Private, Static // Description: Initializes and/or returns the global pointer to the // one MaterialPool object in the system. //////////////////////////////////////////////////////////////////// MaterialPool *MaterialPool:: -get_ptr() { +get_global_ptr() { if (_global_ptr == (MaterialPool *)NULL) { _global_ptr = new MaterialPool; } diff --git a/panda/src/gobj/materialPool.h b/panda/src/gobj/materialPool.h index 354e0be876..8f879c3284 100644 --- a/panda/src/gobj/materialPool.h +++ b/panda/src/gobj/materialPool.h @@ -42,18 +42,25 @@ class EXPCL_PANDA_GOBJ MaterialPool { PUBLISHED: INLINE static Material *get_material(Material *temp); + INLINE static void release_material(Material *temp); + INLINE static void release_all_materials(); + INLINE static int garbage_collect(); INLINE static void list_contents(ostream &out); + static void write(ostream &out); private: INLINE MaterialPool(); Material *ns_get_material(Material *temp); + void ns_release_material(Material *temp); + void ns_release_all_materials(); + int ns_garbage_collect(); void ns_list_contents(ostream &out) const; - static MaterialPool *get_ptr(); + static MaterialPool *get_global_ptr(); static MaterialPool *_global_ptr; diff --git a/panda/src/gobj/textureStage.I b/panda/src/gobj/textureStage.I index 3e924c55f8..15fcc61296 100755 --- a/panda/src/gobj/textureStage.I +++ b/panda/src/gobj/textureStage.I @@ -114,16 +114,6 @@ get_priority() const { return _priority; } -//////////////////////////////////////////////////////////////////// -// Function: TextureStage::opertor < -// Access: Published -// Description: Compare if the sort order is lower -//////////////////////////////////////////////////////////////////// -INLINE bool TextureStage:: -operator < (const TextureStage &other) const { - return (_sort < other._sort); -} - //////////////////////////////////////////////////////////////////// // Function: TextureStage::set_texcoord_name // Access: Published @@ -673,6 +663,36 @@ uses_last_saved_result() const { return _uses_last_saved_result; } +//////////////////////////////////////////////////////////////////// +// Function: TextureStage::operator == +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE bool TextureStage:: +operator == (const TextureStage &other) const { + return compare_to(other) == 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureStage::operator != +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE bool TextureStage:: +operator != (const TextureStage &other) const { + return compare_to(other) != 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureStage::operator < +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE bool TextureStage:: +operator < (const TextureStage &other) const { + return compare_to(other) < 0; +} + //////////////////////////////////////////////////////////////////// // Function: TextureStage::get_default // Access: Published, Static diff --git a/panda/src/gobj/textureStage.cxx b/panda/src/gobj/textureStage.cxx index ccfd1f8342..31c7534af5 100755 --- a/panda/src/gobj/textureStage.cxx +++ b/panda/src/gobj/textureStage.cxx @@ -104,6 +104,122 @@ TextureStage:: ~TextureStage() { } +//////////////////////////////////////////////////////////////////// +// Function: TextureStage::compare_to +// Access: Published +// Description: Returns a number less than zero if this TextureStage +// sorts before the other one, greater than zero if it +// sorts after, or zero if they are equivalent. The +// sorting order is arbitrary and largely meaningless, +// except to differentiate different stages. +//////////////////////////////////////////////////////////////////// +int TextureStage:: +compare_to(const TextureStage &other) const { + // We put the sort parameter first, so that we sorting a list of + // TextureStages will happen to put them in sorted order, even + // though we don't promise to do that. But there's no reason not to + // do so, and it might be more convenient for the developer. + if (get_sort() != other.get_sort()) { + return get_sort() < other.get_sort() ? -1 : 1; + } + + // The remaining parameters are arbitrary. We start with the name, + // because that's most likely to be consistent between similar + // TextureStages, and different between different TextureStages. + int compare = strcmp(get_name().c_str(), other.get_name().c_str()); + if (compare != 0) { + return compare; + } + + if (get_priority() != other.get_priority()) { + return get_priority() < other.get_priority() ? -1 : 1; + } + if (get_texcoord_name() != other.get_texcoord_name()) { + return get_texcoord_name() < other.get_texcoord_name() ? -1 : 1; + } + if (get_mode() != other.get_mode()) { + return get_mode() < other.get_mode() ? -1 : 1; + } + if (get_rgb_scale() != other.get_rgb_scale()) { + return get_rgb_scale() < other.get_rgb_scale() ? -1 : 1; + } + if (get_alpha_scale() != other.get_alpha_scale()) { + return get_alpha_scale() < other.get_alpha_scale() ? -1 : 1; + } + if (get_saved_result() != other.get_saved_result()) { + return get_saved_result() < other.get_saved_result() ? -1 : 1; + } + if (get_mode() != other.get_mode()) { + return get_mode() < other.get_mode() ? -1 : 1; + } + if (get_mode() == M_combine) { + if (get_combine_rgb_mode() != other.get_combine_rgb_mode()) { + return get_combine_rgb_mode() < other.get_combine_rgb_mode() ? -1 : 1; + } + + if (get_num_combine_rgb_operands() != other.get_num_combine_rgb_operands()) { + return get_num_combine_rgb_operands() < other.get_num_combine_rgb_operands() ? -1 : 1; + } + if (get_num_combine_rgb_operands() >= 1) { + if (get_combine_rgb_source0() != other.get_combine_rgb_source0()) { + return get_combine_rgb_source0() < other.get_combine_rgb_source0() ? -1 : 1; + } + if (get_combine_rgb_operand0() != other.get_combine_rgb_operand0()) { + return get_combine_rgb_operand0() < other.get_combine_rgb_operand0() ? -1 : 1; + } + } + if (get_num_combine_rgb_operands() >= 2) { + if (get_combine_rgb_source1() != other.get_combine_rgb_source1()) { + return get_combine_rgb_source1() < other.get_combine_rgb_source1() ? -1 : 1; + } + if (get_combine_rgb_operand1() != other.get_combine_rgb_operand1()) { + return get_combine_rgb_operand1() < other.get_combine_rgb_operand1() ? -1 : 1; + } + } + if (get_num_combine_rgb_operands() >= 3) { + if (get_combine_rgb_source2() != other.get_combine_rgb_source2()) { + return get_combine_rgb_source2() < other.get_combine_rgb_source2() ? -1 : 1; + } + if (get_combine_rgb_operand2() != other.get_combine_rgb_operand2()) { + return get_combine_rgb_operand2() < other.get_combine_rgb_operand2() ? -1 : 1; + } + } + if (get_combine_alpha_mode() != other.get_combine_alpha_mode()) { + return get_combine_alpha_mode() < other.get_combine_alpha_mode() ? -1 : 1; + } + + if (get_num_combine_alpha_operands() != other.get_num_combine_alpha_operands()) { + return get_num_combine_alpha_operands() < other.get_num_combine_alpha_operands() ? -1 : 1; + } + if (get_num_combine_alpha_operands() >= 1) { + if (get_combine_alpha_source0() != other.get_combine_alpha_source0()) { + return get_combine_alpha_source0() < other.get_combine_alpha_source0() ? -1 : 1; + } + if (get_combine_alpha_operand0() != other.get_combine_alpha_operand0()) { + return get_combine_alpha_operand0() < other.get_combine_alpha_operand0() ? -1 : 1; + } + } + if (get_num_combine_alpha_operands() >= 2) { + if (get_combine_alpha_source1() != other.get_combine_alpha_source1()) { + return get_combine_alpha_source1() < other.get_combine_alpha_source1() ? -1 : 1; + } + if (get_combine_alpha_operand1() != other.get_combine_alpha_operand1()) { + return get_combine_alpha_operand1() < other.get_combine_alpha_operand1() ? -1 : 1; + } + } + if (get_num_combine_alpha_operands() >= 3) { + if (get_combine_alpha_source2() != other.get_combine_alpha_source2()) { + return get_combine_alpha_source2() < other.get_combine_alpha_source2() ? -1 : 1; + } + if (get_combine_alpha_operand2() != other.get_combine_alpha_operand2()) { + return get_combine_alpha_operand2() < other.get_combine_alpha_operand2() ? -1 : 1; + } + } + } + + return 0; +} + //////////////////////////////////////////////////////////////////// // Function: TextureStage::Destructor // Access: Published diff --git a/panda/src/gobj/textureStage.h b/panda/src/gobj/textureStage.h index 0daac24745..c9712c6613 100644 --- a/panda/src/gobj/textureStage.h +++ b/panda/src/gobj/textureStage.h @@ -109,8 +109,6 @@ PUBLISHED: INLINE void set_priority(int priority); INLINE int get_priority() const; - INLINE bool operator < (const TextureStage &other) const; - INLINE void set_texcoord_name(InternalName *name); INLINE void set_texcoord_name(const string &texcoord_name); INLINE InternalName *get_texcoord_name() const; @@ -173,6 +171,12 @@ PUBLISHED: INLINE bool uses_primary_color() const; INLINE bool uses_last_saved_result() const; + INLINE bool operator == (const TextureStage &other) const; + INLINE bool operator != (const TextureStage &other) const; + INLINE bool operator < (const TextureStage &other) const; + + int compare_to(const TextureStage &other) const; + void write(ostream &out) const; void output(ostream &out) const; diff --git a/panda/src/gobj/textureStagePool.I b/panda/src/gobj/textureStagePool.I new file mode 100644 index 0000000000..f3de30f915 --- /dev/null +++ b/panda/src/gobj/textureStagePool.I @@ -0,0 +1,115 @@ +// Filename: textureStagePool.I +// Created by: drose (03May10) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: TextureStagePool::get_stage +// Access: Public, Static +// Description: Returns a TextureStage pointer that represents the +// same TextureStage described by temp, except that it is a +// shared pointer. +// +// Each call to get_stage() passing an equivalent +// TextureStage pointer will return the same shared pointer. +// +// If you modify the shared pointer, it will +// automatically disassociate it from the pool. +// +// Also, the return value may be a different pointer +// than that passed in, or it may be the same pointer. +// In either case, the passed in pointer has now been +// sacrificed to the greater good and should not be used +// again (like any other PointerTo, it will be freed +// when the last reference count is removed). +//////////////////////////////////////////////////////////////////// +INLINE TextureStage *TextureStagePool:: +get_stage(TextureStage *temp) { + return get_global_ptr()->ns_get_stage(temp); +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureStagePool::release_stage +// Access: Published, Static +// Description: Removes the indicated TextureStage from the pool. +//////////////////////////////////////////////////////////////////// +INLINE void TextureStagePool:: +release_stage(TextureStage *stage) { + get_global_ptr()->ns_release_stage(stage); +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureStagePool::release_all_stages +// Access: Published, Static +// Description: Releases all TextureStages in the pool and restores the +// pool to the empty state. +//////////////////////////////////////////////////////////////////// +INLINE void TextureStagePool:: +release_all_stages() { + get_global_ptr()->ns_release_all_stages(); +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureStagePool::set_mode +// Access: Published, Static +// Description: Specifies the fundamental operating mode of the +// TextureStagePool. +// +// If this is M_none, each call to get_stage() returns +// the same TextureStage pointer that was passed in (the +// pool is effectively disabled). If this is M_name, +// each call to get_stage() returns the last +// TextureStage passed in with the same name, whether it +// has different properties or not. If this is +// M_unique, then each call to get_stage() returns only +// TextureStages with identical properties. +//////////////////////////////////////////////////////////////////// +INLINE void TextureStagePool:: +set_mode(TextureStagePool::Mode mode) { + get_global_ptr()->ns_set_mode(mode); +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureStagePool::get_mode +// Access: Published, Static +// Description: Returns the fundamental operating mode of the +// TextureStagePool. See set_mode(). +//////////////////////////////////////////////////////////////////// +INLINE TextureStagePool::Mode TextureStagePool:: +get_mode() { + return get_global_ptr()->ns_get_mode(); +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureStagePool::garbage_collect +// Access: Public, Static +// Description: Releases only those TextureStages in the pool that have a +// reference count of exactly 1; i.e. only those +// TextureStages that are not being used outside of the pool. +// Returns the number of TextureStages released. +//////////////////////////////////////////////////////////////////// +INLINE int TextureStagePool:: +garbage_collect() { + return get_global_ptr()->ns_garbage_collect(); +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureStagePool::list_contents +// Access: Public, Static +// Description: Lists the contents of the TextureStage pool to the +// indicated output stream. +//////////////////////////////////////////////////////////////////// +INLINE void TextureStagePool:: +list_contents(ostream &out) { + get_global_ptr()->ns_list_contents(out); +} diff --git a/panda/src/gobj/textureStagePool.cxx b/panda/src/gobj/textureStagePool.cxx new file mode 100644 index 0000000000..fd5e4942e8 --- /dev/null +++ b/panda/src/gobj/textureStagePool.cxx @@ -0,0 +1,332 @@ +// Filename: textureStagePool.cxx +// Created by: drose (03May10) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + + +#include "textureStagePool.h" +#include "config_gobj.h" +#include "mutexHolder.h" +#include "configVariableEnum.h" + +TextureStagePool *TextureStagePool::_global_ptr = (TextureStagePool *)NULL; + + +//////////////////////////////////////////////////////////////////// +// Function: TextureStagePool::write +// Access: Published, Static +// Description: Lists the contents of the TextureStage pool to the +// indicated output stream. +//////////////////////////////////////////////////////////////////// +void TextureStagePool:: +write(ostream &out) { + get_global_ptr()->ns_list_contents(out); +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureStagePool::Constructor +// Access: Private +// Description: The constructor is not intended to be called +// directly; there's only supposed to be one TextureStagePool +// in the universe and it constructs itself. +//////////////////////////////////////////////////////////////////// +TextureStagePool:: +TextureStagePool() { + ConfigVariableEnum texture_stage_pool_mode + ("texture-stage-pool-mode", M_none, + PRC_DESC("Defines the initial value of TextureStagePool::set_mode(). " + "Set this to 'none' to disable the use of the TextureStagePool, " + "to 'name' to group TextureStages by name only, or 'unique' " + "to group together only identical TextureStages.")); + _mode = texture_stage_pool_mode.get_value(); +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureStagePool::ns_get_stage +// Access: Public +// Description: The nonstatic implementation of get_stage(). +//////////////////////////////////////////////////////////////////// +TextureStage *TextureStagePool:: +ns_get_stage(TextureStage *temp) { + MutexHolder holder(_lock); + + switch (_mode) { + case M_none: + return temp; + + case M_name: + { + StagesByName::iterator ni = _stages_by_name.find(temp->get_name()); + if (ni == _stages_by_name.end()) { + ni = _stages_by_name.insert(StagesByName::value_type(temp->get_name(), temp)).first; + } else { + if ((*ni).first != (*ni).second->get_name()) { + // The pointer no longer matches the original name. Save a + // new one. + (*ni).second = temp; + } + } + return (*ni).second; + } + + case M_unique: + { + CPT(TextureStage) cpttemp = temp; + StagesByProperties::iterator si = _stages_by_properties.find(cpttemp); + if (si == _stages_by_properties.end()) { + si = _stages_by_properties.insert(StagesByProperties::value_type(new TextureStage(*temp), temp)).first; + } else { + if (*(*si).first != *(*si).second) { + // The pointer no longer matches its original value. Save a new + // one. + (*si).second = temp; + } + } + return (*si).second; + } + } + + return NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureStagePool::ns_release_stage +// Access: Private +// Description: The nonstatic implementation of release_stage(). +//////////////////////////////////////////////////////////////////// +void TextureStagePool:: +ns_release_stage(TextureStage *temp) { + MutexHolder holder(_lock); + + switch (_mode) { + case M_none: + break; + + case M_name: + _stages_by_name.erase(temp->get_name()); + break; + + case M_unique: + { + CPT(TextureStage) cpttemp = temp; + _stages_by_properties.erase(cpttemp); + } + break; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureStagePool::ns_release_all_stages +// Access: Private +// Description: The nonstatic implementation of release_all_stages(). +//////////////////////////////////////////////////////////////////// +void TextureStagePool:: +ns_release_all_stages() { + MutexHolder holder(_lock); + + _stages_by_name.clear(); + _stages_by_properties.clear(); +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureStagePool::ns_set_mode +// Access: Private +// Description: +//////////////////////////////////////////////////////////////////// +void TextureStagePool:: +ns_set_mode(TextureStagePool::Mode mode) { + MutexHolder holder(_lock); + + if (_mode != mode) { + _stages_by_name.clear(); + _stages_by_properties.clear(); + _mode = mode; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureStagePool::ns_get_mode +// Access: Private +// Description: +//////////////////////////////////////////////////////////////////// +TextureStagePool::Mode TextureStagePool:: +ns_get_mode() { + MutexHolder holder(_lock); + + return _mode; +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureStagePool::ns_garbage_collect +// Access: Private +// Description: The nonstatic implementation of garbage_collect(). +//////////////////////////////////////////////////////////////////// +int TextureStagePool:: +ns_garbage_collect() { + MutexHolder holder(_lock); + + switch (_mode) { + case M_none: + return 0; + + case M_name: + { + int num_released = 0; + StagesByName new_set; + + StagesByName::iterator ni; + for (ni = _stages_by_name.begin(); ni != _stages_by_name.end(); ++ni) { + const string &name = (*ni).first; + TextureStage *ts2 = (*ni).second; + if (name != ts2->get_name() || ts2->get_ref_count() == 1) { + if (gobj_cat.is_debug()) { + gobj_cat.debug() + << "Releasing " << name << "\n"; + } + ++num_released; + } else { + new_set.insert(new_set.end(), *ni); + } + } + + _stages_by_name.swap(new_set); + return num_released; + } + + case M_unique: + { + int num_released = 0; + StagesByProperties new_set; + + StagesByProperties::iterator si; + for (si = _stages_by_properties.begin(); si != _stages_by_properties.end(); ++si) { + const TextureStage *ts1 = (*si).first; + TextureStage *ts2 = (*si).second; + if ((*ts1) != (*ts2) || ts2->get_ref_count() == 1) { + if (gobj_cat.is_debug()) { + gobj_cat.debug() + << "Releasing " << *ts1 << "\n"; + } + ++num_released; + } else { + new_set.insert(new_set.end(), *si); + } + } + + _stages_by_properties.swap(new_set); + return num_released; + } + } + + return 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureStagePool::ns_list_contents +// Access: Private +// Description: The nonstatic implementation of list_contents(). +//////////////////////////////////////////////////////////////////// +void TextureStagePool:: +ns_list_contents(ostream &out) const { + MutexHolder holder(_lock); + + out << "TextureStagePool in mode " << _mode << "\n"; + + switch (_mode) { + case M_none: + break; + + case M_name: + { + out << _stages_by_name.size() << " TextureStages:\n"; + StagesByName::const_iterator ni; + for (ni = _stages_by_name.begin(); ni != _stages_by_name.end(); ++ni) { + const string &name = (*ni).first; + TextureStage *ts2 = (*ni).second; + out << " " << name + << " (count = " << ts2->get_ref_count() << ")\n"; + } + } + break; + + case M_unique: + { + out << _stages_by_properties.size() << " TextureStages:\n"; + StagesByProperties::const_iterator si; + for (si = _stages_by_properties.begin(); si != _stages_by_properties.end(); ++si) { + const TextureStage *ts1 = (*si).first; + TextureStage *ts2 = (*si).second; + out << " " << *ts1 + << " (count = " << ts2->get_ref_count() << ")\n"; + } + } + break; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureStagePool::get_global_ptr +// Access: Private, Static +// Description: Initializes and/or returns the global pointer to the +// one TextureStagePool object in the system. +//////////////////////////////////////////////////////////////////// +TextureStagePool *TextureStagePool:: +get_global_ptr() { + if (_global_ptr == (TextureStagePool *)NULL) { + _global_ptr = new TextureStagePool; + } + return _global_ptr; +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureStagePool::Mode output operator +// Description: +//////////////////////////////////////////////////////////////////// +ostream & +operator << (ostream &out, TextureStagePool::Mode mode) { + switch (mode) { + case TextureStagePool::M_none: + return out << "none"; + + case TextureStagePool::M_name: + return out << "name"; + + case TextureStagePool::M_unique: + return out << "unique"; + } + + return out << "**invalid mode (" << (int)mode << ")**"; +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureStagePool::Mode input operator +// Description: +//////////////////////////////////////////////////////////////////// +istream & +operator >> (istream &in, TextureStagePool::Mode &mode) { + string word; + in >> word; + + if (cmp_nocase(word, "none") == 0) { + mode = TextureStagePool::M_none; + } else if (cmp_nocase(word, "name") == 0) { + mode = TextureStagePool::M_name; + } else if (cmp_nocase(word, "unique") == 0) { + mode = TextureStagePool::M_unique; + + } else { + gobj_cat->error() << "Invalid TextureStagePool mode value: " << word << "\n"; + mode = TextureStagePool::M_none; + } + + return in; +} diff --git a/panda/src/gobj/textureStagePool.h b/panda/src/gobj/textureStagePool.h new file mode 100644 index 0000000000..f34f10af70 --- /dev/null +++ b/panda/src/gobj/textureStagePool.h @@ -0,0 +1,93 @@ +// Filename: textureStagePool.h +// Created by: drose (03May10) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#ifndef TEXTURESTAGEPOOL_H +#define TEXTURESTAGEPOOL_H + +#include "pandabase.h" +#include "textureStage.h" +#include "pointerTo.h" +#include "pmutex.h" +#include "pset.h" + +//////////////////////////////////////////////////////////////////// +// Class : TextureStagePool +// Description : The TextureStagePool (there is only one in the universe) +// serves to unify different pointers to the same +// TextureStage, mainly to help developers use a common +// pointer to access things that are loaded from +// different model files. +// +// It runs in one of three different modes, according to +// set_mode(). See that method for more information. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA_GOBJ TextureStagePool { +PUBLISHED: + enum Mode { + M_none, + M_name, + M_unique, + }; + + INLINE static TextureStage *get_stage(TextureStage *temp); + INLINE static void release_stage(TextureStage *temp); + INLINE static void release_all_stages(); + + INLINE static void set_mode(Mode mode); + INLINE static Mode get_mode(); + + INLINE static int garbage_collect(); + INLINE static void list_contents(ostream &out); + static void write(ostream &out); + +private: + TextureStagePool(); + + TextureStage *ns_get_stage(TextureStage *temp); + void ns_release_stage(TextureStage *temp); + void ns_release_all_stages(); + + void ns_set_mode(Mode mode); + Mode ns_get_mode(); + + int ns_garbage_collect(); + void ns_list_contents(ostream &out) const; + + static TextureStagePool *get_global_ptr(); + + static TextureStagePool *_global_ptr; + + Mutex _lock; + + // We store a map of CPT(TextureStage) to PT(TextureStage). These are two + // equivalent structures, but different pointers. The first pointer + // never leaves this class. If the second pointer changes value, + // we'll notice it and return a new one. + typedef pmap > StagesByProperties; + StagesByProperties _stages_by_properties; + + typedef pmap StagesByName; + StagesByName _stages_by_name; + + Mode _mode; +}; + +EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, TextureStagePool::Mode mode); +EXPCL_PANDA_GOBJ istream &operator >> (istream &in, TextureStagePool::Mode &mode); + +#include "textureStagePool.I" + +#endif + + diff --git a/panda/src/pgraph/nodePath.cxx b/panda/src/pgraph/nodePath.cxx index 22fe320f86..6bebd2cce3 100644 --- a/panda/src/pgraph/nodePath.cxx +++ b/panda/src/pgraph/nodePath.cxx @@ -3420,26 +3420,21 @@ set_texture(Texture *tex, int priority) { void NodePath:: set_texture(TextureStage *stage, Texture *tex, int priority) { nassertv_always(!is_empty()); - if (tex->get_texture_type() == Texture::TT_2d_texture_array){ - pgraph_cat.error() << "Texture::TT_2d_texture_array is not supported by" << \ - " the fixed pipeline.\n"; - return; - } + const RenderAttrib *attrib = node()->get_attrib(TextureAttrib::get_class_slot()); if (attrib != (const RenderAttrib *)NULL) { - priority = max(priority, - node()->get_state()->get_override(TextureAttrib::get_class_slot())); const TextureAttrib *tsa = DCAST(TextureAttrib, attrib); + int sg_priority = node()->get_state()->get_override(TextureAttrib::get_class_slot()); // Modify the existing TextureAttrib to add the indicated // texture. - node()->set_attrib(tsa->add_on_stage(stage, tex), priority); + node()->set_attrib(tsa->add_on_stage(stage, tex, priority), sg_priority); } else { // Create a new TextureAttrib for this node. CPT(TextureAttrib) tsa = DCAST(TextureAttrib, TextureAttrib::make()); - node()->set_attrib(tsa->add_on_stage(stage, tex), priority); + node()->set_attrib(tsa->add_on_stage(stage, tex, priority)); } } @@ -3476,20 +3471,19 @@ set_texture_off(TextureStage *stage, int priority) { const RenderAttrib *attrib = node()->get_attrib(TextureAttrib::get_class_slot()); if (attrib != (const RenderAttrib *)NULL) { - priority = max(priority, - node()->get_state()->get_override(TextureAttrib::get_class_slot())); const TextureAttrib *tsa = DCAST(TextureAttrib, attrib); + int sg_priority = node()->get_state()->get_override(TextureAttrib::get_class_slot()); // Modify the existing TextureAttrib to add the indicated texture // to the "off" list. This also, incidentally, removes it from // the "on" list if it is there. - node()->set_attrib(tsa->add_off_stage(stage), priority); + node()->set_attrib(tsa->add_off_stage(stage, priority), sg_priority); } else { // Create a new TextureAttrib for this node that turns off the // indicated stage. CPT(TextureAttrib) tsa = DCAST(TextureAttrib, TextureAttrib::make()); - node()->set_attrib(tsa->add_off_stage(stage), priority); + node()->set_attrib(tsa->add_off_stage(stage, priority)); } } diff --git a/panda/src/pgraph/renderAttrib.I b/panda/src/pgraph/renderAttrib.I index f7124875fc..bd1b95787d 100644 --- a/panda/src/pgraph/renderAttrib.I +++ b/panda/src/pgraph/renderAttrib.I @@ -15,7 +15,7 @@ //////////////////////////////////////////////////////////////////// // Function: RenderAttrib::compose -// Access: Public +// Access: Published // Description: Returns a new RenderAttrib object that represents the // composition of this attrib with the other attrib. In // most cases, this is the same as the other attrib; a @@ -30,7 +30,7 @@ compose(const RenderAttrib *other) const { //////////////////////////////////////////////////////////////////// // Function: RenderAttrib::invert_compose -// Access: Public +// Access: Published // Description: Returns a new RenderAttrib object that represents the // composition of the inverse of this attrib with the // other attrib. In most cases, this is the same as the diff --git a/panda/src/pgraph/renderAttrib.cxx b/panda/src/pgraph/renderAttrib.cxx index a103502893..f8d1d30911 100644 --- a/panda/src/pgraph/renderAttrib.cxx +++ b/panda/src/pgraph/renderAttrib.cxx @@ -80,7 +80,7 @@ RenderAttrib:: // // This should return false if a RenderAttrib on a // higher node will compose into a RenderAttrib on a -// lower node that has a higher override value, or false +// lower node that has a higher override value, or true // if the lower RenderAttrib will completely replace the // state. // diff --git a/panda/src/pgraph/renderAttrib.h b/panda/src/pgraph/renderAttrib.h index d8d4e6001c..78440a20f0 100644 --- a/panda/src/pgraph/renderAttrib.h +++ b/panda/src/pgraph/renderAttrib.h @@ -65,10 +65,12 @@ private: public: virtual ~RenderAttrib(); +PUBLISHED: INLINE CPT(RenderAttrib) compose(const RenderAttrib *other) const; INLINE CPT(RenderAttrib) invert_compose(const RenderAttrib *other) const; virtual bool lower_attrib_can_override() const; +public: INLINE bool always_reissue() const; virtual bool has_cull_callback() const; diff --git a/panda/src/pgraph/textureAttrib.I b/panda/src/pgraph/textureAttrib.I index 8e3e997f0d..97a294d5d5 100644 --- a/panda/src/pgraph/textureAttrib.I +++ b/panda/src/pgraph/textureAttrib.I @@ -37,13 +37,11 @@ TextureAttrib() { INLINE TextureAttrib:: TextureAttrib(const TextureAttrib ©) : _on_stages(copy._on_stages), - _on_ptr_stages(copy._on_ptr_stages), - _on_ff_stages(copy._on_ff_stages), - _ff_tc_index(copy._ff_tc_index), + _render_stages(copy._render_stages), + _render_ff_stages(copy._render_ff_stages), _next_implicit_sort(copy._next_implicit_sort), _off_stages(copy._off_stages), _off_all_stages(copy._off_all_stages), - _on_textures(copy._on_textures), _sort_seq(copy._sort_seq), _filtered_seq(UpdateSeq::old()) { @@ -92,7 +90,7 @@ get_texture() const { INLINE int TextureAttrib:: get_num_on_stages() const { check_sorted(); - return _on_stages.size(); + return _render_stages.size(); } //////////////////////////////////////////////////////////////////// @@ -103,8 +101,8 @@ get_num_on_stages() const { //////////////////////////////////////////////////////////////////// INLINE TextureStage *TextureAttrib:: get_on_stage(int n) const { - nassertr(n >= 0 && n < (int)_on_stages.size(), (TextureStage *)NULL); - return _on_stages[n]._stage; + nassertr(n >= 0 && n < (int)_render_stages.size(), (TextureStage *)NULL); + return _render_stages[n]->_stage; } //////////////////////////////////////////////////////////////////// @@ -117,11 +115,11 @@ get_on_stage(int n) const { INLINE int TextureAttrib:: get_num_on_ff_stages() const { check_sorted(); - return _on_ff_stages.size(); + return _render_ff_stages.size(); } //////////////////////////////////////////////////////////////////// -// Function: TextureAttrib::get_on_ff_stage +// Function: TextureAttrib::get_render_ff_stage // Access: Published // Description: Returns the nth stage turned on by the attribute, // sorted in render order, including only those relevant @@ -130,8 +128,8 @@ get_num_on_ff_stages() const { //////////////////////////////////////////////////////////////////// INLINE TextureStage *TextureAttrib:: get_on_ff_stage(int n) const { - nassertr(n >= 0 && n < (int)_on_ff_stages.size(), (TextureStage *)NULL); - return _on_ff_stages[n]._stage; + nassertr(n >= 0 && n < (int)_render_ff_stages.size(), (TextureStage *)NULL); + return _render_ff_stages[n]->_stage; } //////////////////////////////////////////////////////////////////// @@ -141,13 +139,13 @@ get_on_ff_stage(int n) const { // this returns a unique index number for the texture // coordinate name used by that TextureStage. It is // guaranteed to remain the same index number for each -// texcoord name, even if the texture render order -// changes. +// texcoord name (for a given set of TextureStages), +// even if the texture render order changes. //////////////////////////////////////////////////////////////////// INLINE int TextureAttrib:: get_ff_tc_index(int n) const { - nassertr(n >= 0 && n < (int)_ff_tc_index.size(), 0); - return _ff_tc_index[n]; + nassertr(n >= 0 && n < (int)_render_ff_stages.size(), -1); + return _render_ff_stages[n]->_ff_tc_index; } //////////////////////////////////////////////////////////////////// @@ -158,7 +156,7 @@ get_ff_tc_index(int n) const { //////////////////////////////////////////////////////////////////// INLINE bool TextureAttrib:: has_on_stage(TextureStage *stage) const { - return _on_textures.find(stage) != _on_textures.end(); + return _on_stages.find(StageNode(stage)) != _on_stages.end(); } //////////////////////////////////////////////////////////////////// @@ -169,10 +167,10 @@ has_on_stage(TextureStage *stage) const { //////////////////////////////////////////////////////////////////// INLINE Texture *TextureAttrib:: get_on_texture(TextureStage *stage) const { - OnTextures::const_iterator ti; - ti = _on_textures.find(stage); - if (ti != _on_textures.end()) { - return (*ti).second; + Stages::const_iterator si; + si = _on_stages.find(StageNode(stage)); + if (si != _on_stages.end()) { + return (*si)._texture; } return NULL; } @@ -197,7 +195,7 @@ get_num_off_stages() const { INLINE TextureStage *TextureAttrib:: get_off_stage(int n) const { nassertr(n >= 0 && n < (int)_off_stages.size(), (TextureStage *)NULL); - return _off_stages[n]; + return _off_stages[n]._stage; } //////////////////////////////////////////////////////////////////// @@ -208,7 +206,7 @@ get_off_stage(int n) const { //////////////////////////////////////////////////////////////////// INLINE bool TextureAttrib:: has_off_stage(TextureStage *stage) const { - return _off_stages.find(stage) != _off_stages.end() || + return _off_stages.find(StageNode(stage)) != _off_stages.end() || (_off_all_stages && !has_on_stage(stage)); } @@ -252,14 +250,17 @@ check_sorted() const { } //////////////////////////////////////////////////////////////////// -// Function: TextureAttrib::OnStageNode::Constructor +// Function: TextureAttrib::StageNode::Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// -INLINE TextureAttrib::OnStageNode:: -OnStageNode(TextureStage *stage, unsigned int implicit_sort) : - _stage(stage), - _implicit_sort(implicit_sort) +INLINE TextureAttrib::StageNode:: +StageNode(const TextureStage *stage, unsigned int implicit_sort, int override) : + // Yeah, we cast away the constness here. Just too much trouble to + // deal with it properly. + _stage((TextureStage *)stage), + _implicit_sort(implicit_sort), + _override(override) { } @@ -272,15 +273,15 @@ OnStageNode(TextureStage *stage, unsigned int implicit_sort) : // within priority, within order by sort. //////////////////////////////////////////////////////////////////// INLINE bool TextureAttrib::CompareTextureStagePriorities:: -operator () (const TextureAttrib::OnStageNode &a, - const TextureAttrib::OnStageNode &b) const { - if (a._stage->get_priority() != b._stage->get_priority()) { - return a._stage->get_priority() > b._stage->get_priority(); +operator () (const TextureAttrib::StageNode *a, + const TextureAttrib::StageNode *b) const { + if (a->_stage->get_priority() != b->_stage->get_priority()) { + return a->_stage->get_priority() > b->_stage->get_priority(); } - if (a._stage->get_sort() != b._stage->get_sort()) { - return a._stage->get_sort() < b._stage->get_sort(); + if (a->_stage->get_sort() != b->_stage->get_sort()) { + return a->_stage->get_sort() < b->_stage->get_sort(); } - return a._implicit_sort < b._implicit_sort; + return a->_implicit_sort < b->_implicit_sort; } //////////////////////////////////////////////////////////////////// @@ -290,12 +291,12 @@ operator () (const TextureAttrib::OnStageNode &a, // texture stages in order by sort. //////////////////////////////////////////////////////////////////// INLINE bool TextureAttrib::CompareTextureStageSort:: -operator () (const TextureAttrib::OnStageNode &a, - const TextureAttrib::OnStageNode &b) const { - if (a._stage->get_sort() != b._stage->get_sort()) { - return a._stage->get_sort() < b._stage->get_sort(); +operator () (const TextureAttrib::StageNode *a, + const TextureAttrib::StageNode *b) const { + if (a->_stage->get_sort() != b->_stage->get_sort()) { + return a->_stage->get_sort() < b->_stage->get_sort(); } - return a._implicit_sort < b._implicit_sort; + return a->_implicit_sort < b->_implicit_sort; } //////////////////////////////////////////////////////////////////// @@ -305,7 +306,7 @@ operator () (const TextureAttrib::OnStageNode &a, // texture stages in order by pointer. //////////////////////////////////////////////////////////////////// INLINE bool TextureAttrib::CompareTextureStagePointer:: -operator () (const TextureAttrib::OnStageNode &a, - const TextureAttrib::OnStageNode &b) const { +operator () (const TextureAttrib::StageNode &a, + const TextureAttrib::StageNode &b) const { return a._stage < b._stage; } diff --git a/panda/src/pgraph/textureAttrib.cxx b/panda/src/pgraph/textureAttrib.cxx index 120680bff3..47634b7a9e 100644 --- a/panda/src/pgraph/textureAttrib.cxx +++ b/panda/src/pgraph/textureAttrib.cxx @@ -20,6 +20,7 @@ #include "datagram.h" #include "datagramIterator.h" #include "dcast.h" +#include "textureStagePool.h" CPT(RenderAttrib) TextureAttrib::_empty_attrib; CPT(RenderAttrib) TextureAttrib::_all_off_attrib; @@ -108,10 +109,9 @@ make_default() { //////////////////////////////////////////////////////////////////// int TextureAttrib:: find_on_stage(const TextureStage *stage) const { - for (int n = 0; n < (int)_on_stages.size(); ++n) { - if (_on_stages[n]._stage == stage) { - return n; - } + Stages::const_iterator si = _on_stages.find(StageNode(stage)); + if (si != _on_stages.end()) { + return (int)(si - _on_stages.begin()); } return -1; @@ -125,37 +125,15 @@ find_on_stage(const TextureStage *stage) const { // turned on by this attrib. //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) TextureAttrib:: -add_on_stage(TextureStage *stage, Texture *tex) const { +add_on_stage(TextureStage *stage, Texture *tex, int override) const { TextureAttrib *attrib = new TextureAttrib(*this); - pair insert_result = - attrib->_on_textures.insert(OnTextures::value_type(stage, tex)); - if (insert_result.second) { - // If the insert was successful--we have added a new stage that - // wasn't present before--then add the stage to the linear list - // also. - attrib->_on_stages.push_back(OnStageNode(stage, attrib->_next_implicit_sort)); - ++(attrib->_next_implicit_sort); + Stages::iterator si = attrib->_on_stages.insert(StageNode(stage)).first; + (*si)._override = override; + (*si)._texture = tex; + (*si)._implicit_sort = attrib->_next_implicit_sort; + ++(attrib->_next_implicit_sort); - // Also ensure it is removed from the off_stages list. - attrib->_off_stages.erase(stage); - - } else { - // If the insert was unsuccessful, it means there was already a - // definition for that stage. Replace it. - (*insert_result.first).second = tex; - - // Also update the implicit sort. - OnStages::iterator si; - for (si = attrib->_on_stages.begin(); si != attrib->_on_stages.end(); ++si) { - if ((*si)._stage == stage) { - (*si)._implicit_sort = attrib->_next_implicit_sort; - ++(attrib->_next_implicit_sort); - break; - } - } - } - - // In either case, we now need to re-sort the attrib list. + // We now need to re-sort the attrib list. attrib->_sort_seq = UpdateSeq::old(); attrib->_filtered_seq = UpdateSeq::old(); @@ -173,17 +151,9 @@ CPT(RenderAttrib) TextureAttrib:: remove_on_stage(TextureStage *stage) const { TextureAttrib *attrib = new TextureAttrib(*this); - OnTextures::iterator ti = attrib->_on_textures.find(stage); - if (ti != attrib->_on_textures.end()) { - attrib->_on_textures.erase(ti); - - OnStages::iterator si; - for (si = attrib->_on_stages.begin(); si != attrib->_on_stages.end(); ++si) { - if ((*si)._stage == stage) { - attrib->_on_stages.erase(si); - break; - } - } + Stages::iterator si = attrib->_on_stages.find(StageNode(stage)); + if (si != attrib->_on_stages.end()) { + attrib->_on_stages.erase(si); attrib->_sort_seq = UpdateSeq::old(); attrib->_filtered_seq = UpdateSeq::old(); @@ -200,23 +170,17 @@ remove_on_stage(TextureStage *stage) const { // turned off by this attrib. //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) TextureAttrib:: -add_off_stage(TextureStage *stage) const { +add_off_stage(TextureStage *stage, int override) const { TextureAttrib *attrib = new TextureAttrib(*this); if (!_off_all_stages) { - attrib->_off_stages.insert(stage); + StageNode sn(stage); + Stages::iterator sfi = attrib->_off_stages.insert(sn).first; + (*sfi)._override = override; // Also ensure it is removed from the on_stages list. - OnTextures::iterator ti = attrib->_on_textures.find(stage); - if (ti != attrib->_on_textures.end()) { - attrib->_on_textures.erase(ti); - - OnStages::iterator si; - for (si = attrib->_on_stages.begin(); si != attrib->_on_stages.end(); ++si) { - if ((*si)._stage == stage) { - attrib->_on_stages.erase(si); - break; - } - } + Stages::iterator si = attrib->_on_stages.find(sn); + if (si != attrib->_on_stages.end()) { + attrib->_on_stages.erase(si); attrib->_sort_seq = UpdateSeq::old(); attrib->_filtered_seq = UpdateSeq::old(); } @@ -234,7 +198,7 @@ add_off_stage(TextureStage *stage) const { CPT(RenderAttrib) TextureAttrib:: remove_off_stage(TextureStage *stage) const { TextureAttrib *attrib = new TextureAttrib(*this); - attrib->_off_stages.erase(stage); + attrib->_off_stages.erase(StageNode(stage)); return return_new(attrib); } @@ -253,41 +217,35 @@ unify_texture_stages(TextureStage *stage) const { attrib->_off_all_stages = _off_all_stages; bool any_changed = false; - OnStages::const_iterator si; + Stages::const_iterator si; for (si = _on_stages.begin(); si != _on_stages.end(); ++si) { TextureStage *this_stage = (*si)._stage; - Texture *tex = get_on_texture(this_stage); - nassertr(tex != (Texture *)NULL, this); if (this_stage->get_name() == stage->get_name()) { this_stage = stage; any_changed = true; } - bool inserted = attrib->_on_textures.insert(OnTextures::value_type(this_stage, tex)).second; - if (inserted) { - // If the texture was successfully inserted, it was the first - // appearance of this stage. Add it to the on_stages list. - attrib->_on_stages.push_back(OnStageNode(this_stage, (*si)._implicit_sort)); - } else { - // If the texture was not successfully inserted, it was a - // duplicate texture stage. This should only be possible if we - // have just collapsed a stage. - nassertr(this_stage == stage, this); - } + Stages::iterator osi = attrib->_on_stages.insert(StageNode(this_stage)).first; + (*osi)._texture = (*si)._texture; + (*osi)._ff_tc_index = (*si)._ff_tc_index; + (*osi)._implicit_sort = (*si)._implicit_sort; + (*osi)._override = (*si)._override; } attrib->_next_implicit_sort = _next_implicit_sort; - OffStages::const_iterator fsi; + Stages::const_iterator fsi; for (fsi = _off_stages.begin(); fsi != _off_stages.end(); ++fsi) { - if ((*fsi) != stage && - (*fsi)->get_name() == stage->get_name()) { - attrib->_off_stages.insert(stage); + TextureStage *this_stage = (*fsi)._stage; + + if (this_stage != stage && + this_stage->get_name() == stage->get_name()) { + this_stage = stage; any_changed = true; - } else { - attrib->_off_stages.insert(*fsi); } + + attrib->_off_stages.insert(StageNode(this_stage)); } if (!any_changed) { @@ -330,7 +288,7 @@ filter_to_max(int max_texture_stages) const { // case of equal priority, we prefer the stage with the lower sort. check_sorted(); - OnStages priority_stages = _on_stages; + RenderStages priority_stages = _render_stages; // This sort function uses the STL function object defined above. sort(priority_stages.begin(), priority_stages.end(), @@ -343,13 +301,11 @@ filter_to_max(int max_texture_stages) const { // And create a new attrib reflecting these stages. PT(TextureAttrib) attrib = new TextureAttrib; - OnStages::const_iterator si; - for (si = priority_stages.begin(); si != priority_stages.end(); ++si) { - TextureStage *stage = (*si)._stage; - attrib->_on_textures[stage] = get_on_texture(stage); + RenderStages::const_iterator ri; + for (ri = priority_stages.begin(); ri != priority_stages.end(); ++ri) { + attrib->_on_stages.insert(*(*ri)); } - attrib->_on_stages.swap(priority_stages); attrib->_next_implicit_sort = _next_implicit_sort; CPT(RenderAttrib) new_attrib = return_new(attrib); @@ -388,10 +344,13 @@ output(ostream &out) const { } else { out << "off"; - OffStages::const_iterator fi; + Stages::const_iterator fi; for (fi = _off_stages.begin(); fi != _off_stages.end(); ++fi) { - TextureStage *stage = (*fi); + TextureStage *stage = (*fi)._stage; out << " " << stage->get_name(); + if ((*fi)._override != 0) { + out << "^" << (*fi)._override; + } } if (!_on_stages.empty()) { @@ -399,16 +358,19 @@ output(ostream &out) const { } } - OnStages::const_iterator si; - for (si = _on_stages.begin(); si != _on_stages.end(); ++si) { - TextureStage *stage = (*si)._stage; - OnTextures::const_iterator ti = _on_textures.find(stage); - if (ti != _on_textures.end()) { - Texture *tex = (*ti).second; + RenderStages::const_iterator ri; + for (ri = _render_stages.begin(); ri != _render_stages.end(); ++ri) { + const StageNode &sn = *(*ri); + TextureStage *stage = sn._stage; + Texture *tex = sn._texture; + if (tex != NULL) { out << " " << stage->get_name() << ":" << tex->get_name(); } else { out << " " << stage->get_name(); } + if (sn._override != 0) { + out << "^" << sn._override; + } } } @@ -423,9 +385,9 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// bool TextureAttrib:: has_cull_callback() const { - OnTextures::const_iterator nti; - for (nti = _on_textures.begin(); nti != _on_textures.end(); ++nti) { - Texture *texture = (*nti).second; + Stages::const_iterator si; + for (si = _on_stages.begin(); si != _on_stages.end(); ++si) { + Texture *texture = (*si)._texture; if (texture->has_cull_callback()) { return true; } @@ -449,9 +411,9 @@ has_cull_callback() const { //////////////////////////////////////////////////////////////////// bool TextureAttrib:: cull_callback(CullTraverser *trav, const CullTraverserData &data) const { - OnTextures::const_iterator nti; - for (nti = _on_textures.begin(); nti != _on_textures.end(); ++nti) { - Texture *texture = (*nti).second; + Stages::const_iterator si; + for (si = _on_stages.begin(); si != _on_stages.end(); ++si) { + Texture *texture = (*si)._texture; if (!texture->cull_callback(trav, data)) { return false; } @@ -484,52 +446,10 @@ compare_to_impl(const RenderAttrib *other) const { return (int)_off_all_stages - (int)ta->_off_all_stages; } - // First, verify that the texture assigned to each stage is the - // same. - OnTextures::const_iterator li = _on_textures.begin(); - OnTextures::const_iterator oli = ta->_on_textures.begin(); + Stages::const_iterator si = _on_stages.begin(); + Stages::const_iterator osi = ta->_on_stages.begin(); - while (li != _on_textures.end() && oli != ta->_on_textures.end()) { - TextureStage *stage = (*li).first; - TextureStage *other_stage = (*oli).first; - - if (stage != other_stage) { - return stage < other_stage ? -1 : 1; - } - - Texture *tex = (*li).second; - Texture *other_tex = (*oli).second; - - if (tex != other_tex) { - return tex < other_tex ? -1 : 1; - } - - ++li; - ++oli; - } - - if (li != _on_textures.end()) { - return 1; - } - if (oli != ta->_on_textures.end()) { - return -1; - } - - // Then, we also have to check the linear list of texture stages, to - // ensure primarily that the implicit sort numbers match between the - // two attribs. (If they did not, then a later call to - // texture_stage->set_sort() might make these attribs apply textures - // differently, even if they are the same now.) - check_sorted(); - ta->check_sorted(); - - nassertr(_on_ptr_stages.size() == _on_stages.size() && - ta->_on_ptr_stages.size() == ta->_on_stages.size(), 0) - - OnStages::const_iterator si = _on_ptr_stages.begin(); - OnStages::const_iterator osi = ta->_on_ptr_stages.begin(); - - while (si != _on_ptr_stages.end() && osi != ta->_on_ptr_stages.end()) { + while (si != _on_stages.end() && osi != ta->_on_stages.end()) { TextureStage *stage = (*si)._stage; TextureStage *other_stage = (*osi)._stage; @@ -537,6 +457,13 @@ compare_to_impl(const RenderAttrib *other) const { return stage < other_stage ? -1 : 1; } + Texture *texture = (*si)._texture; + Texture *other_texture = (*osi)._texture; + + if (texture != other_texture) { + return texture < other_texture ? -1 : 1; + } + int implicit_sort = (*si)._implicit_sort; int other_implicit_sort = (*osi)._implicit_sort; @@ -544,29 +471,43 @@ compare_to_impl(const RenderAttrib *other) const { return implicit_sort < other_implicit_sort ? -1 : 1; } + int override = (*si)._override; + int other_override = (*osi)._override; + + if (override != other_override) { + return override < other_override ? -1 : 1; + } + ++si; ++osi; } - if (si != _on_ptr_stages.end()) { + if (si != _on_stages.end()) { return 1; } - if (osi != ta->_on_ptr_stages.end()) { + if (osi != ta->_on_stages.end()) { return -1; } // Finally, ensure that the set of off stages is the same. - OffStages::const_iterator fi = _off_stages.begin(); - OffStages::const_iterator ofi = ta->_off_stages.begin(); + Stages::const_iterator fi = _off_stages.begin(); + Stages::const_iterator ofi = ta->_off_stages.begin(); while (fi != _off_stages.end() && ofi != ta->_off_stages.end()) { - TextureStage *stage = (*fi); - TextureStage *other_stage = (*ofi); + TextureStage *stage = (*fi)._stage; + TextureStage *other_stage = (*ofi)._stage; if (stage != other_stage) { return stage < other_stage ? -1 : 1; } + int override = (*fi)._override; + int other_override = (*ofi)._override; + + if (override != other_override) { + return override < other_override ? -1 : 1; + } + ++fi; ++ofi; } @@ -612,145 +553,120 @@ compose_impl(const RenderAttrib *other) const { // This is a three-way merge between ai, bi, and ci, except that bi // and ci should have no intersection and therefore needn't be // compared to each other. - OnTextures::const_iterator ai = _on_textures.begin(); - OnTextures::const_iterator bi = ta->_on_textures.begin(); - OffStages::const_iterator ci = ta->_off_stages.begin(); - - // TextureStages that are kept from the original attrib are inserted - // into a_stages. Those that are inherited from the secondary - // attrib are inserted into b_stages. - pset a_stages; - pset b_stages; + Stages::const_iterator ai = _on_stages.begin(); + Stages::const_iterator bi = ta->_on_stages.begin(); + Stages::const_iterator ci = ta->_off_stages.begin(); // Create a new TextureAttrib that will hold the result. TextureAttrib *attrib = new TextureAttrib; - while (ai != _on_textures.end() && - bi != ta->_on_textures.end() && + while (ai != _on_stages.end() && + bi != ta->_on_stages.end() && ci != ta->_off_stages.end()) { - if ((*ai).first < (*bi).first) { - if ((*ai).first < (*ci)) { + if ((*ai)._stage < (*bi)._stage) { + if ((*ai)._stage < (*ci)._stage) { // Here is a stage that we have in the original, which is not // present in the secondary. - attrib->_on_textures.insert(attrib->_on_textures.end(), *ai); - a_stages.insert((*ai).first); + attrib->_on_stages.insert(attrib->_on_stages.end(), *ai); ++ai; - } else if ((*ci) < (*ai).first) { + } else if ((*ci)._stage < (*ai)._stage) { // Here is a stage that is turned off in the secondary, but // was not present in the original. ++ci; - } else { // (*ci) == (*ai).first + } else { // (*ci)._stage == (*ai)._stage // Here is a stage that is turned off in the secondary, and // was present in the original. + if ((*ai)._override > (*ci)._override) { + // But never mind, keep it anyway. + attrib->_on_stages.insert(attrib->_on_stages.end(), *ai); + } + ++ai; ++ci; } - } else if ((*bi).first < (*ai).first) { + } else if ((*bi)._stage < (*ai)._stage) { // Here is a new stage we have in the secondary, that was not // present in the original. - attrib->_on_textures.insert(attrib->_on_textures.end(), *bi); - b_stages.insert((*bi).first); + attrib->_on_stages.insert(attrib->_on_stages.end(), *bi); ++bi; - } else { // (*bi).first == (*ai).first + } else { // (*bi)._stage == (*ai)._stage // Here is a stage we have in both. - attrib->_on_textures.insert(attrib->_on_textures.end(), *bi); - b_stages.insert((*bi).first); + if ((*ai)._override > (*bi)._override) { + attrib->_on_stages.insert(attrib->_on_stages.end(), *ai); + } else { + attrib->_on_stages.insert(attrib->_on_stages.end(), *bi); + } ++ai; ++bi; } } - while (ai != _on_textures.end() && bi != ta->_on_textures.end()) { - if ((*ai).first < (*bi).first) { + while (ai != _on_stages.end() && bi != ta->_on_stages.end()) { + if ((*ai)._stage < (*bi)._stage) { // Here is a stage that we have in the original, which is not // present in the secondary. - attrib->_on_textures.insert(attrib->_on_textures.end(), *ai); - a_stages.insert((*ai).first); + attrib->_on_stages.insert(attrib->_on_stages.end(), *ai); ++ai; - } else if ((*bi).first < (*ai).first) { + } else if ((*bi)._stage < (*ai)._stage) { // Here is a new stage we have in the secondary, that was not // present in the original. - attrib->_on_textures.insert(attrib->_on_textures.end(), *bi); - b_stages.insert((*bi).first); + attrib->_on_stages.insert(attrib->_on_stages.end(), *bi); ++bi; } else { // Here is a stage we have in both. - attrib->_on_textures.insert(attrib->_on_textures.end(), *bi); - b_stages.insert((*bi).first); + if ((*ai)._override > (*bi)._override) { + attrib->_on_stages.insert(attrib->_on_stages.end(), *ai); + } else { + attrib->_on_stages.insert(attrib->_on_stages.end(), *bi); + } ++ai; ++bi; } } - while (ai != _on_textures.end() && ci != ta->_off_stages.end()) { - if ((*ai).first < (*ci)) { + while (ai != _on_stages.end() && ci != ta->_off_stages.end()) { + if ((*ai)._stage < (*ci)._stage) { // Here is a stage that we have in the original, which is not // present in the secondary. - attrib->_on_textures.insert(attrib->_on_textures.end(), *ai); - a_stages.insert((*ai).first); + attrib->_on_stages.insert(attrib->_on_stages.end(), *ai); ++ai; - } else if ((*ci) < (*ai).first) { + } else if ((*ci)._stage < (*ai)._stage) { // Here is a stage that is turned off in the secondary, but // was not present in the original. ++ci; - } else { // (*ci) == (*ai).first + } else { // (*ci)._stage == (*ai)._stage // Here is a stage that is turned off in the secondary, and // was present in the original. + if ((*ai)._override > (*ci)._override) { + // But never mind, keep it anyway. + attrib->_on_stages.insert(attrib->_on_stages.end(), *ai); + } ++ai; ++ci; } } - while (ai != _on_textures.end()) { - attrib->_on_textures.insert(attrib->_on_textures.end(), *ai); - a_stages.insert((*ai).first); + while (ai != _on_stages.end()) { + attrib->_on_stages.insert(attrib->_on_stages.end(), *ai); ++ai; } - while (bi != ta->_on_textures.end()) { - attrib->_on_textures.insert(attrib->_on_textures.end(), *bi); - b_stages.insert((*bi).first); + while (bi != ta->_on_stages.end()) { + attrib->_on_stages.insert(attrib->_on_stages.end(), *bi); ++bi; } - // Now we need to build up the linear list. We must put this in - // order so that the original stages are first, followed by the - // secondary stages. If a texture stage is listed in both, it - // receives the secondary sort. - - OnStages::const_iterator asi; - for (asi = _on_stages.begin(); asi != _on_stages.end(); ++asi) { - TextureStage *stage = (*asi)._stage; - - if (a_stages.find(stage) != a_stages.end()) { - // This stage came from the original, and thus receives the - // original sort. - int implicit_sort = (*asi)._implicit_sort; - attrib->_on_stages.push_back(OnStageNode(stage, implicit_sort)); - } - } - - OnStages::const_iterator bsi; - for (bsi = ta->_on_stages.begin(); bsi != ta->_on_stages.end(); ++bsi) { - TextureStage *stage = (*bsi)._stage; - - if (b_stages.find(stage) != b_stages.end()) { - // This stage was inherited from the secondary, and thus - // receives the secondary sort. - int implicit_sort = _next_implicit_sort + (*bsi)._implicit_sort; - attrib->_on_stages.push_back(OnStageNode(stage, implicit_sort)); - } - } - attrib->_next_implicit_sort = _next_implicit_sort + ta->_next_implicit_sort; + attrib->_sort_seq = UpdateSeq::old(); + attrib->_filtered_seq = UpdateSeq::old(); return return_new(attrib); } @@ -796,23 +712,24 @@ write_datagram(BamWriter *manager, Datagram &dg) { // Write the off_stages information dg.add_bool(_off_all_stages); dg.add_uint16(get_num_off_stages()); - OffStages::const_iterator fi; + Stages::const_iterator fi; for (fi = _off_stages.begin(); fi != _off_stages.end(); ++fi) { - TextureStage *stage = (*fi); + TextureStage *stage = (*fi)._stage; manager->write_pointer(dg, stage); } // Write the on_stages information dg.add_uint16(get_num_on_stages()); - OnStages::const_iterator si; + Stages::const_iterator si; for (si = _on_stages.begin(); si != _on_stages.end(); ++si) { TextureStage *stage = (*si)._stage; - Texture *tex = get_on_texture(stage); + Texture *tex = (*si)._texture; nassertv(tex != (Texture *)NULL); manager->write_pointer(dg, stage); manager->write_pointer(dg, tex); dg.add_uint16((*si)._implicit_sort); + dg.add_int32((*si)._override); } } @@ -827,27 +744,33 @@ int TextureAttrib:: complete_pointers(TypedWritable **p_list, BamReader *manager) { int pi = RenderAttrib::complete_pointers(p_list, manager); - OffStages::iterator ci; + Stages::iterator ci; for (ci = _off_stages.begin(); ci != _off_stages.end(); ++ci) { TextureStage *ts = DCAST(TextureStage, p_list[pi++]); - *ci = ts; + *ci = StageNode(ts); } - size_t sn = 0; - while (sn < _on_stages.size()) { - TextureStage *ts = DCAST(TextureStage, p_list[pi++]); + size_t sni = 0; + while (sni < _on_stages.size()) { + // Filter the TextureStage through the TextureStagePool. + PT(TextureStage) ts = DCAST(TextureStage, p_list[pi++]); + ts = TextureStagePool::get_stage(ts); + + // The Texture pointer filters itself through the TexturePool, so + // we don't have to do anything special here. Texture *tex = DCAST(Texture, p_list[pi++]); if (tex != (Texture *)NULL) { - _on_textures[ts] = tex; - _on_stages[sn]._stage = ts; - ++sn; + StageNode &sn = _on_stages[sni]; + sn._stage = ts; + sn._texture = tex; + ++sni; } else { // If we couldn't load a texture pointer, turn off that // particular texture stage. - _off_stages.push_back(ts); - _on_stages.erase(_on_stages.begin() + sn); + _off_stages.push_back(StageNode(ts)); + _on_stages.erase(_on_stages.begin() + sni); } } _sort_seq = UpdateSeq::old(); @@ -897,7 +820,7 @@ fillin(DatagramIterator &scan, BamReader *manager) { _off_stages.reserve(num_off_stages); for (i = 0; i < num_off_stages; i++) { manager->read_pointer(scan); - _off_stages.push_back(NULL); + _off_stages.push_back(StageNode(NULL)); } // Read the _on_stages data. @@ -917,8 +840,14 @@ fillin(DatagramIterator &scan, BamReader *manager) { } else { implicit_sort = (unsigned int)i; } + int override = 0; + if (manager->get_file_minor_ver() >= 23) { + override = scan.get_int32(); + } + _next_implicit_sort = max(_next_implicit_sort, implicit_sort + 1); - _on_stages.push_back(OnStageNode(NULL, implicit_sort)); + _on_stages.push_back(StageNode(NULL, _next_implicit_sort, override)); + ++_next_implicit_sort; } } @@ -931,25 +860,17 @@ fillin(DatagramIterator &scan, BamReader *manager) { //////////////////////////////////////////////////////////////////// void TextureAttrib:: sort_on_stages() { - // First, we have to build up the tc_index mapping. We need a - // unique number for each different texcoord name for the various - // TextureStages. - - // It's important that this assignment not be based on the whims of - // render order--it mustn't change arbitrarily--so we must first - // sort the on_stages list into pointer order for this purpose. - _on_ptr_stages = _on_stages; - sort(_on_ptr_stages.begin(), _on_ptr_stages.end(), CompareTextureStagePointer()); - typedef pmap UsedTexcoordIndex; UsedTexcoordIndex used_texcoord_index; - typedef pmap TexcoordMap; - TexcoordMap tc_map; + _render_stages.clear(); + _render_ff_stages.clear(); - OnStages::const_iterator si; - for (si = _on_ptr_stages.begin(); si != _on_ptr_stages.end(); ++si) { - TextureStage *stage = (*si)._stage; + Stages::iterator si; + for (si = _on_stages.begin(); si != _on_stages.end(); ++si) { + StageNode &sn = (*si); + TextureStage *stage = sn._stage; + nassertv(stage != NULL); if (stage->is_fixed_function()) { const InternalName *name = stage->get_texcoord_name(); @@ -958,32 +879,24 @@ sort_on_stages() { // particular texcoord name; otherwise, it will return the same // index number it returned before. UsedTexcoordIndex::iterator ti = used_texcoord_index.insert(UsedTexcoordIndex::value_type(name, (int)used_texcoord_index.size())).first; - int texcoord_index = (*ti).second; + (*si)._ff_tc_index = (*ti).second; - tc_map[stage] = texcoord_index; + _render_ff_stages.push_back(&sn); + } else { + (*si)._ff_tc_index = -1; } + + _render_stages.push_back(&sn); } - // Now we can sort the on_stages list into render order. - sort(_on_stages.begin(), _on_stages.end(), CompareTextureStageSort()); + sort(_render_stages.begin(), _render_stages.end(), CompareTextureStageSort()); + sort(_render_ff_stages.begin(), _render_ff_stages.end(), CompareTextureStageSort()); - _on_ff_stages.clear(); - _ff_tc_index.clear(); - - for (si = _on_stages.begin(); si != _on_stages.end(); ++si) { - TextureStage *stage = (*si)._stage; - if (stage->is_fixed_function()) { - _on_ff_stages.push_back(*si); - int texcoord_index = tc_map[stage]; - _ff_tc_index.push_back(texcoord_index); - } - } - - // We'd like to clear the _filtered map, in case the priority orders - // have changed as well, but we can't do that here: too dangerous. - // Clearing _filtered might cause TextureAttribs to be deleted, and - // hence removed from the map that we might be in the middle of - // traversing! + // We'd like to clear the _filtered map, in case the TextureStage + // priority values have changed as well, but we can't do that here: + // it's too dangerous. Clearing _filtered might cause + // TextureAttribs to be deleted, and hence removed from the map that + // we might be in the middle of traversing! _sort_seq = TextureStage::get_sort_seq(); } diff --git a/panda/src/pgraph/textureAttrib.h b/panda/src/pgraph/textureAttrib.h index 9b8b8f75c8..5daa1b3382 100644 --- a/panda/src/pgraph/textureAttrib.h +++ b/panda/src/pgraph/textureAttrib.h @@ -72,9 +72,9 @@ PUBLISHED: INLINE bool is_identity() const; - CPT(RenderAttrib) add_on_stage(TextureStage *stage, Texture *tex) const; + CPT(RenderAttrib) add_on_stage(TextureStage *stage, Texture *tex, int override = 0) const; CPT(RenderAttrib) remove_on_stage(TextureStage *stage) const; - CPT(RenderAttrib) add_off_stage(TextureStage *stage) const; + CPT(RenderAttrib) add_off_stage(TextureStage *stage, int override = 0) const; CPT(RenderAttrib) remove_off_stage(TextureStage *stage) const; CPT(RenderAttrib) unify_texture_stages(TextureStage *stage) const; @@ -96,43 +96,45 @@ private: void sort_on_stages(); private: - class OnStageNode { + class StageNode { public: - INLINE OnStageNode(TextureStage *stage, unsigned int implicit_sort); + INLINE StageNode(const TextureStage *stage, + unsigned int implicit_sort = 0, + int override = 0); PT(TextureStage) _stage; + PT(Texture) _texture; + int _ff_tc_index; unsigned int _implicit_sort; + int _override; }; class CompareTextureStagePriorities { public: - INLINE bool operator () (const TextureAttrib::OnStageNode &a, const TextureAttrib::OnStageNode &b) const; + INLINE bool operator () (const TextureAttrib::StageNode *a, const TextureAttrib::StageNode *b) const; }; class CompareTextureStageSort { public: - INLINE bool operator () (const TextureAttrib::OnStageNode &a, const TextureAttrib::OnStageNode &b) const; + INLINE bool operator () (const TextureAttrib::StageNode *a, const TextureAttrib::StageNode *b) const; }; class CompareTextureStagePointer { public: - INLINE bool operator () (const TextureAttrib::OnStageNode &a, const TextureAttrib::OnStageNode &b) const; + INLINE bool operator () (const TextureAttrib::StageNode &a, const TextureAttrib::StageNode &b) const; }; - typedef pvector OnStages; - OnStages _on_stages; // list of all "on" stages, sorted in render order. - OnStages _on_ptr_stages; // above, sorted in pointer order. - OnStages _on_ff_stages; // fixed-function stages only, in render order. - vector_int _ff_tc_index; + typedef ov_set Stages; + Stages _on_stages; // set of all "on" stages, indexed by pointer. + + typedef pvector RenderStages; + RenderStages _render_stages; // all "on" stages, sorted in render order. + RenderStages _render_ff_stages; // fixed-function stages only, in render order. unsigned int _next_implicit_sort; - typedef ov_set OffStages; - OffStages _off_stages; + Stages _off_stages; bool _off_all_stages; - typedef pmap OnTextures; - OnTextures _on_textures; - typedef pmap< int, CPT(TextureAttrib) > Filtered; Filtered _filtered; diff --git a/panda/src/pgraph/textureStageCollection.I b/panda/src/pgraph/textureStageCollection.I index 746f965b6d..1f0a2589e1 100644 --- a/panda/src/pgraph/textureStageCollection.I +++ b/panda/src/pgraph/textureStageCollection.I @@ -44,3 +44,14 @@ operator + (const TextureStageCollection &other) const { a += other; return a; } + +//////////////////////////////////////////////////////////////////// +// Function: TextureStageCollection::CompareTextureStageSort::operator () +// Access: Public +// Description: This STL function object is used to sort a list of +// texture stages in order by sort. +//////////////////////////////////////////////////////////////////// +INLINE bool TextureStageCollection::CompareTextureStageSort:: +operator () (const TextureStage *a, const TextureStage *b) const { + return a->get_sort() < b->get_sort(); +} diff --git a/panda/src/pgraph/textureStageCollection.cxx b/panda/src/pgraph/textureStageCollection.cxx index b49f24ab65..fc84113863 100644 --- a/panda/src/pgraph/textureStageCollection.cxx +++ b/panda/src/pgraph/textureStageCollection.cxx @@ -272,7 +272,7 @@ size() const { void TextureStageCollection:: sort() { ::sort(_texture_stages.begin(), _texture_stages.end(), - IndirectLess()); + CompareTextureStageSort()); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/textureStageCollection.h b/panda/src/pgraph/textureStageCollection.h index b13359c319..d34872810d 100644 --- a/panda/src/pgraph/textureStageCollection.h +++ b/panda/src/pgraph/textureStageCollection.h @@ -56,6 +56,12 @@ PUBLISHED: private: typedef PTA(PT(TextureStage)) TextureStages; TextureStages _texture_stages; + + class CompareTextureStageSort { + public: + INLINE bool operator () (const TextureStage *a, const TextureStage *b) const; + }; + }; INLINE ostream &operator << (ostream &out, const TextureStageCollection &col) { diff --git a/panda/src/putil/bam.h b/panda/src/putil/bam.h index 13db5de629..c43324fb57 100644 --- a/panda/src/putil/bam.h +++ b/panda/src/putil/bam.h @@ -33,7 +33,7 @@ static const unsigned short _bam_major_ver = 6; // Bumped to major version 6 on 2/11/06 to factor out PandaNode::CData. static const unsigned short _bam_first_minor_ver = 14; -static const unsigned short _bam_minor_ver = 22; +static const unsigned short _bam_minor_ver = 23; // Bumped to minor version 14 on 12/19/07 to change default ColorAttrib. // Bumped to minor version 15 on 4/9/08 to add TextureAttrib::_implicit_sort. // Bumped to minor version 16 on 5/13/08 to add Texture::_quality_level. @@ -43,6 +43,7 @@ static const unsigned short _bam_minor_ver = 22; // Bumped to minor version 20 on 4/21/09 to add MovingPartBase::_forced_channel. // Bumped to minor version 21 on 2/26/08 to add BamEnums::BamObjectCode. // Bumped to minor version 22 on 7/31/09 to add UvScrollNode R speed. +// Bumped to minor version 23 on 5/4/10 to add internal TextureAttrib overrides. #endif