diff --git a/panda/src/dxgsg9/dxShaderContext9.cxx b/panda/src/dxgsg9/dxShaderContext9.cxx index e39a004aa4..2fe81544bf 100644 --- a/panda/src/dxgsg9/dxShaderContext9.cxx +++ b/panda/src/dxgsg9/dxShaderContext9.cxx @@ -487,17 +487,13 @@ update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg) } InternalName *name = _shader->_var_spec[i]._name; int texslot = _shader->_var_spec[i]._append_uv; - if (texslot >= 0) { - const Geom::ActiveTextureStages &active_stages = - gsg->_state._texture->get_on_stages(); - if (texslot < (int)active_stages.size()) { - TextureStage *stage = active_stages[texslot]; - InternalName *texname = stage->get_texcoord_name(); - if (name == InternalName::get_texcoord()) { - name = texname; - } else if (texname != InternalName::get_texcoord()) { - name = name->append(texname->get_basename()); - } + if (texslot >= 0 && texslot < gsg->_state._texture->get_num_on_stages()) { + TextureStage *stage = gsg->_state._texture->get_on_stage(texslot); + InternalName *texname = stage->get_texcoord_name(); + if (name == InternalName::get_texcoord()) { + name = texname; + } else if (texname != InternalName::get_texcoord()) { + name = name->append(texname->get_basename()); } } if (gsg->_data_reader->get_array_info(name, array_reader, num_values, numeric_type, start, stride)) { diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index a132267427..fa61316b58 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -1988,16 +1988,11 @@ update_standard_vertex_arrays(bool force) { // Now set up each of the active texture coordinate stages--or at // least those for which we're not generating texture coordinates // automatically. - const Geom::ActiveTextureStages &active_stages = - _effective_texture->get_on_ff_stages(); - const Geom::NoTexCoordStages &no_texcoords = - _effective_tex_gen->get_no_texcoords(); - - int max_stage_index = (int)active_stages.size(); + int max_stage_index = _effective_texture->get_num_on_ff_stages(); int stage_index = 0; while (stage_index < max_stage_index) { - TextureStage *stage = active_stages[stage_index]; - if (no_texcoords.find(stage) == no_texcoords.end()) { + TextureStage *stage = _effective_texture->get_on_ff_stage(stage_index); + if (!_effective_tex_gen->has_gen_texcoord_stage(stage)) { // This stage is not one of the stages that doesn't need // texcoords issued for it. const InternalName *name = stage->get_texcoord_name(); @@ -2089,17 +2084,12 @@ update_standard_vertex_arrays(bool force) { // Now set up each of the active texture coordinate stages--or at // least those for which we're not generating texture coordinates // automatically. - const Geom::ActiveTextureStages &active_stages = - _effective_texture->get_on_ff_stages(); - const Geom::NoTexCoordStages &no_texcoords = - _effective_tex_gen->get_no_texcoords(); - - int max_stage_index = (int)active_stages.size(); + int max_stage_index = _effective_texture->get_num_on_ff_stages(); int stage_index = 0; while (stage_index < max_stage_index) { _glClientActiveTexture(GL_TEXTURE0 + stage_index); - TextureStage *stage = active_stages[stage_index]; - if (no_texcoords.find(stage) == no_texcoords.end()) { + TextureStage *stage = _effective_texture->get_on_ff_stage(stage_index); + if (!_effective_tex_gen->has_gen_texcoord_stage(stage)) { // This stage is not one of the stages that doesn't need // texcoords issued for it. const InternalName *name = stage->get_texcoord_name(); diff --git a/panda/src/glstuff/glShaderContext_src.cxx b/panda/src/glstuff/glShaderContext_src.cxx index d72d12c9b9..20a0d41e04 100755 --- a/panda/src/glstuff/glShaderContext_src.cxx +++ b/panda/src/glstuff/glShaderContext_src.cxx @@ -260,17 +260,13 @@ update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg, if (p == 0) continue; InternalName *name = _shader->_var_spec[i]._name; int texslot = _shader->_var_spec[i]._append_uv; - if (texslot >= 0) { - const Geom::ActiveTextureStages &active_stages = - gsg->_state._texture->get_on_stages(); - if (texslot < (int)active_stages.size()) { - TextureStage *stage = active_stages[texslot]; - InternalName *texname = stage->get_texcoord_name(); - if (name == InternalName::get_texcoord()) { - name = texname; - } else if (texname != InternalName::get_texcoord()) { - name = name->append(texname->get_basename()); - } + if (texslot >= 0 && texslot < gsg->_state._texture->get_num_on_stages()) { + TextureStage *stage = gsg->_state._texture->get_on_stage(texslot); + InternalName *texname = stage->get_texcoord_name(); + if (name == InternalName::get_texcoord()) { + name = texname; + } else if (texname != InternalName::get_texcoord()) { + name = name->append(texname->get_basename()); } } if (gsg->_data_reader->get_array_info(name, diff --git a/panda/src/gobj/geom.h b/panda/src/gobj/geom.h index 78618d4783..e64c090ac6 100644 --- a/panda/src/gobj/geom.h +++ b/panda/src/gobj/geom.h @@ -158,10 +158,6 @@ public: static UpdateSeq get_next_modified(); -public: - typedef pvector< PT(TextureStage) > ActiveTextureStages; - typedef pset NoTexCoordStages; - private: class CData; diff --git a/panda/src/mesadisplay/mesagsg.h b/panda/src/mesadisplay/mesagsg.h index 2afdd86a06..15edf7d4ad 100644 --- a/panda/src/mesadisplay/mesagsg.h +++ b/panda/src/mesadisplay/mesagsg.h @@ -26,6 +26,10 @@ #include "pandabase.h" #include "config_mesadisplay.h" +// This stuff seems to crash with Mesa. +#undef HAVE_CG +#undef HAVE_CGGL + #ifdef MESA_MGL #define GLP(name) mgl##name #define GLUP(name) mglu##name diff --git a/panda/src/pgraph/texGenAttrib.I b/panda/src/pgraph/texGenAttrib.I index 48fa8723d4..7577ba590d 100755 --- a/panda/src/pgraph/texGenAttrib.I +++ b/panda/src/pgraph/texGenAttrib.I @@ -66,20 +66,6 @@ get_geom_rendering(int geom_rendering) const { return geom_rendering | _geom_rendering; } -//////////////////////////////////////////////////////////////////// -// Function: TexGenAttrib::get_no_texcoords -// Access: Public -// Description: Returns the set of TextureStages that have texture -// coordinates computed for them, and hence do not need -// to have texture coordinates sent from the Geom. This -// is, of course, the set of TextureStages that is -// listed in the attrib (except for those listed with M_off). -//////////////////////////////////////////////////////////////////// -INLINE const Geom::NoTexCoordStages &TexGenAttrib:: -get_no_texcoords() const { - return _no_texcoords; -} - //////////////////////////////////////////////////////////////////// // Function: TexGenAttrib::get_light_vectors // Access: Public diff --git a/panda/src/pgraph/texGenAttrib.cxx b/panda/src/pgraph/texGenAttrib.cxx index 34c48e56d8..32a0900e1d 100755 --- a/panda/src/pgraph/texGenAttrib.cxx +++ b/panda/src/pgraph/texGenAttrib.cxx @@ -216,6 +216,20 @@ get_mode(TextureStage *stage) const { return M_off; } +//////////////////////////////////////////////////////////////////// +// Function: TexGenAttrib::has_gen_texcoord_stage +// Access: Published +// Description: Returns true if the indicated TextureStage will have +// texture coordinates generated for it automatically +// (and thus there is no need to upload the texture +// coordinates encoded in the vertices). +//////////////////////////////////////////////////////////////////// +bool TexGenAttrib:: +has_gen_texcoord_stage(TextureStage *stage) const { + NoTexCoordStages::const_iterator mi = _no_texcoords.find(stage); + return (mi != _no_texcoords.end()); +} + //////////////////////////////////////////////////////////////////// // Function: TexGenAttrib::get_source_name // Access: Published diff --git a/panda/src/pgraph/texGenAttrib.h b/panda/src/pgraph/texGenAttrib.h index 2d5cd8e38e..a79072c489 100755 --- a/panda/src/pgraph/texGenAttrib.h +++ b/panda/src/pgraph/texGenAttrib.h @@ -64,6 +64,7 @@ PUBLISHED: bool is_empty() const; bool has_stage(TextureStage *stage) const; Mode get_mode(TextureStage *stage) const; + bool has_gen_texcoord_stage(TextureStage *stage) const; string get_source_name(TextureStage *stage) const; NodePath get_light(TextureStage *stage) const; const TexCoord3f &get_constant_value(TextureStage *stage) const; @@ -71,8 +72,6 @@ PUBLISHED: INLINE int get_geom_rendering(int geom_rendering) const; public: - INLINE const Geom::NoTexCoordStages &get_no_texcoords() const; - typedef pset LightVectors; INLINE const LightVectors &get_light_vectors() const; @@ -106,7 +105,8 @@ private: // coordinates will not be needed from the Geom. It's redundant; // it's almost the same set that is listed in _stages, above. It's // just here as an optimization during rendering. - Geom::NoTexCoordStages _no_texcoords; + typedef pset NoTexCoordStages; + NoTexCoordStages _no_texcoords; // This is another optimization during rendering; it lists the // texture stages (if any) that use M_light_vector. diff --git a/panda/src/pgraph/textureAttrib.I b/panda/src/pgraph/textureAttrib.I index 01299848d3..edd2d5f6bb 100644 --- a/panda/src/pgraph/textureAttrib.I +++ b/panda/src/pgraph/textureAttrib.I @@ -25,6 +25,7 @@ //////////////////////////////////////////////////////////////////// INLINE TextureAttrib:: TextureAttrib() { + _next_implicit_sort = 0; _off_all_stages = false; _sort_seq = UpdateSeq::old(); } @@ -39,6 +40,9 @@ TextureAttrib() { INLINE TextureAttrib:: TextureAttrib(const TextureAttrib ©) : _on_stages(copy._on_stages), + _on_ff_stages(copy._on_ff_stages), + _ff_tc_index(copy._ff_tc_index), + _next_implicit_sort(copy._next_implicit_sort), _off_stages(copy._off_stages), _off_all_stages(copy._off_all_stages), _on_textures(copy._on_textures), @@ -101,7 +105,7 @@ 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]; + return _on_stages[n]._stage; } //////////////////////////////////////////////////////////////////// @@ -128,7 +132,7 @@ 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]; + return _on_ff_stages[n]._stage; } //////////////////////////////////////////////////////////////////// @@ -231,32 +235,6 @@ is_identity() const { return _on_stages.empty() && _off_stages.empty() && !_off_all_stages; } -//////////////////////////////////////////////////////////////////// -// Function: TextureAttrib::get_on_stages -// Access: Public -// Description: Returns the complete list of stages defined within -// this TextureAttrib, suitable for passing to -// Geom::setup_multitexcoord_iterator(). -//////////////////////////////////////////////////////////////////// -INLINE const Geom::ActiveTextureStages &TextureAttrib:: -get_on_stages() const { - return _on_stages; -} - -//////////////////////////////////////////////////////////////////// -// Function: TextureAttrib::get_on_ff_stages -// Access: Public -// Description: Returns the complete list of stages defined within -// this TextureAttrib, including only those which are -// relevant to the classic fixed-function pipeline. -// The result is suitable for passing to -// Geom::setup_multitexcoord_iterator(). -//////////////////////////////////////////////////////////////////// -INLINE const Geom::ActiveTextureStages &TextureAttrib:: -get_on_ff_stages() const { - return _on_ff_stages; -} - //////////////////////////////////////////////////////////////////// // Function: TextureAttrib::check_sorted // Access: Private @@ -273,3 +251,29 @@ check_sorted() const { ((TextureAttrib *)this)->sort_on_stages(); } } + +//////////////////////////////////////////////////////////////////// +// Function: TextureAttrib::OnStageNode::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE TextureAttrib::OnStageNode:: +OnStageNode(TextureStage *stage, unsigned int implicit_sort) : + _stage(stage), + _implicit_sort(implicit_sort) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureAttrib::OnStageNode::Comparison Operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE bool TextureAttrib::OnStageNode:: +operator < (const TextureAttrib::OnStageNode &other) const { + if (_stage->get_sort() != other._stage->get_sort()) { + return _stage->get_sort() < other._stage->get_sort(); + } + return _implicit_sort < other._implicit_sort; +} + diff --git a/panda/src/pgraph/textureAttrib.cxx b/panda/src/pgraph/textureAttrib.cxx index 88767e970b..4a99c6a798 100644 --- a/panda/src/pgraph/textureAttrib.cxx +++ b/panda/src/pgraph/textureAttrib.cxx @@ -33,16 +33,17 @@ TypeHandle TextureAttrib::_type_handle; // This STL Function object is used in filter_to_max(), below, to sort // a list of TextureStages in reverse order by priority and, within // priority, in order by sort. -class CompareTextureStagePriorities { -public: - bool operator ()(const TextureStage *a, const TextureStage *b) const { - if (a->get_priority() != b->get_priority()) { - return a->get_priority() > b->get_priority(); - } - return a->get_sort() < b->get_sort(); +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(); } -}; - + 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; +} //////////////////////////////////////////////////////////////////// @@ -115,7 +116,7 @@ make_all_off() { int TextureAttrib:: find_on_stage(const TextureStage *stage) const { for (int n = 0; n < (int)_on_stages.size(); ++n) { - if (_on_stages[n] == stage) { + if (_on_stages[n]._stage == stage) { return n; } } @@ -139,7 +140,8 @@ add_on_stage(TextureStage *stage, Texture *tex) const { // 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(stage); + attrib->_on_stages.push_back(OnStageNode(stage, attrib->_next_implicit_sort)); + ++(attrib->_next_implicit_sort); // Also ensure it is removed from the off_stages list. attrib->_off_stages.erase(stage); @@ -148,6 +150,16 @@ add_on_stage(TextureStage *stage, Texture *tex) const { // 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. @@ -170,13 +182,16 @@ remove_on_stage(TextureStage *stage) const { OnTextures::iterator ti = attrib->_on_textures.find(stage); if (ti != attrib->_on_textures.end()) { attrib->_on_textures.erase(ti); - OnStages::iterator si = - find(attrib->_on_stages.begin(), attrib->_on_stages.end(), - PT(TextureStage)(stage)); - if (si != attrib->_on_stages.end()) { - attrib->_on_stages.erase(si); - attrib->_sort_seq = UpdateSeq::old(); + + 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; + } } + + attrib->_sort_seq = UpdateSeq::old(); } return return_new(attrib); @@ -199,13 +214,15 @@ add_off_stage(TextureStage *stage) const { OnTextures::iterator ti = attrib->_on_textures.find(stage); if (ti != attrib->_on_textures.end()) { attrib->_on_textures.erase(ti); - OnStages::iterator si = - find(attrib->_on_stages.begin(), attrib->_on_stages.end(), - PT(TextureStage)(stage)); - if (si != attrib->_on_stages.end()) { - attrib->_on_stages.erase(si); - attrib->_sort_seq = UpdateSeq::old(); + + 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; + } } + attrib->_sort_seq = UpdateSeq::old(); } } return return_new(attrib); @@ -240,25 +257,31 @@ unify_texture_stages(TextureStage *stage) const { attrib->_off_all_stages = _off_all_stages; bool any_changed = false; - OnTextures::const_iterator nti; - for (nti = _on_textures.begin(); nti != _on_textures.end(); ++nti) { - if ((*nti).first != stage && - (*nti).first->get_name() == stage->get_name()) { - attrib->_on_textures[stage] = (*nti).second; + OnStages::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 { - attrib->_on_textures.insert(*nti); + // 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); } } - // Now copy from _on_textures to the _on_stages list. We can't do - // this as we walk through the list the first pass, since we might - // have collapsed together multiple different stages. - for (nti = attrib->_on_textures.begin(); - nti != attrib->_on_textures.end(); - ++nti) { - attrib->_on_stages.push_back((*nti).first); - } + attrib->_next_implicit_sort = _next_implicit_sort; OffStages::const_iterator fsi; for (fsi = _off_stages.begin(); fsi != _off_stages.end(); ++fsi) { @@ -323,11 +346,12 @@ filter_to_max(int max_texture_stages) const { OnStages::const_iterator si; for (si = priority_stages.begin(); si != priority_stages.end(); ++si) { - TextureStage *stage = (*si); + TextureStage *stage = (*si)._stage; attrib->_on_textures[stage] = get_on_texture(stage); } attrib->_on_stages.swap(priority_stages); + attrib->_next_implicit_sort = _next_implicit_sort; CPT(RenderAttrib) new_attrib = return_new(attrib); @@ -376,9 +400,9 @@ output(ostream &out) const { } } - OnStages::const_iterator li; - for (li = _on_stages.begin(); li != _on_stages.end(); ++li) { - TextureStage *stage = (*li); + 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; @@ -461,6 +485,8 @@ 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(); @@ -489,6 +515,43 @@ compare_to_impl(const RenderAttrib *other) const { 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(); + + OnStages::const_iterator si = _on_stages.begin(); + OnStages::const_iterator osi = ta->_on_stages.begin(); + + while (si != _on_stages.end() && osi != ta->_on_stages.end()) { + TextureStage *stage = (*si)._stage; + TextureStage *other_stage = (*osi)._stage; + + if (stage != other_stage) { + return stage < other_stage ? -1 : 1; + } + + int implicit_sort = (*si)._implicit_sort; + int other_implicit_sort = (*osi)._implicit_sort; + if (implicit_sort != other_implicit_sort) { + return implicit_sort < other_implicit_sort ? -1 : 1; + } + + ++si; + ++osi; + } + + if (si != _on_stages.end()) { + return 1; + } + 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(); @@ -549,8 +612,14 @@ compose_impl(const RenderAttrib *other) const { 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; + // Create a new TextureAttrib that will hold the result. - TextureAttrib *new_attrib = new TextureAttrib; + TextureAttrib *attrib = new TextureAttrib; while (ai != _on_textures.end() && bi != ta->_on_textures.end() && @@ -559,8 +628,8 @@ compose_impl(const RenderAttrib *other) const { if ((*ai).first < (*ci)) { // Here is a stage that we have in the original, which is not // present in the secondary. - new_attrib->_on_textures.insert(new_attrib->_on_textures.end(), *ai); - new_attrib->_on_stages.push_back((*ai).first); + attrib->_on_textures.insert(attrib->_on_textures.end(), *ai); + a_stages.insert((*ai).first); ++ai; } else if ((*ci) < (*ai).first) { @@ -578,14 +647,14 @@ compose_impl(const RenderAttrib *other) const { } else if ((*bi).first < (*ai).first) { // Here is a new stage we have in the secondary, that was not // present in the original. - new_attrib->_on_textures.insert(new_attrib->_on_textures.end(), *bi); - new_attrib->_on_stages.push_back((*bi).first); + attrib->_on_textures.insert(attrib->_on_textures.end(), *bi); + b_stages.insert((*bi).first); ++bi; } else { // (*bi).first == (*ai).first // Here is a stage we have in both. - new_attrib->_on_textures.insert(new_attrib->_on_textures.end(), *bi); - new_attrib->_on_stages.push_back((*ai).first); + attrib->_on_textures.insert(attrib->_on_textures.end(), *bi); + b_stages.insert((*bi).first); ++ai; ++bi; } @@ -595,21 +664,21 @@ compose_impl(const RenderAttrib *other) const { if ((*ai).first < (*bi).first) { // Here is a stage that we have in the original, which is not // present in the secondary. - new_attrib->_on_textures.insert(new_attrib->_on_textures.end(), *ai); - new_attrib->_on_stages.push_back((*ai).first); + attrib->_on_textures.insert(attrib->_on_textures.end(), *ai); + a_stages.insert((*ai).first); ++ai; } else if ((*bi).first < (*ai).first) { // Here is a new stage we have in the secondary, that was not // present in the original. - new_attrib->_on_textures.insert(new_attrib->_on_textures.end(), *bi); - new_attrib->_on_stages.push_back((*bi).first); + attrib->_on_textures.insert(attrib->_on_textures.end(), *bi); + b_stages.insert((*bi).first); ++bi; } else { // Here is a stage we have in both. - new_attrib->_on_textures.insert(new_attrib->_on_textures.end(), *bi); - new_attrib->_on_stages.push_back((*ai).first); + attrib->_on_textures.insert(attrib->_on_textures.end(), *bi); + b_stages.insert((*bi).first); ++ai; ++bi; } @@ -619,8 +688,8 @@ compose_impl(const RenderAttrib *other) const { if ((*ai).first < (*ci)) { // Here is a stage that we have in the original, which is not // present in the secondary. - new_attrib->_on_textures.insert(new_attrib->_on_textures.end(), *ai); - new_attrib->_on_stages.push_back((*ai).first); + attrib->_on_textures.insert(attrib->_on_textures.end(), *ai); + a_stages.insert((*ai).first); ++ai; } else if ((*ci) < (*ai).first) { @@ -637,18 +706,49 @@ compose_impl(const RenderAttrib *other) const { } while (ai != _on_textures.end()) { - new_attrib->_on_textures.insert(new_attrib->_on_textures.end(), *ai); - new_attrib->_on_stages.push_back((*ai).first); + attrib->_on_textures.insert(attrib->_on_textures.end(), *ai); + a_stages.insert((*ai).first); ++ai; } while (bi != ta->_on_textures.end()) { - new_attrib->_on_textures.insert(new_attrib->_on_textures.end(), *bi); - new_attrib->_on_stages.push_back((*bi).first); + attrib->_on_textures.insert(attrib->_on_textures.end(), *bi); + b_stages.insert((*bi).first); ++bi; } - return return_new(new_attrib); + // 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; + + return return_new(attrib); } //////////////////////////////////////////////////////////////////// @@ -716,31 +816,27 @@ void TextureAttrib:: write_datagram(BamWriter *manager, Datagram &dg) { RenderAttrib::write_datagram(manager, dg); -#if 1 - // TODO: write the multitexture data. - // write the boolean if _off_all_stages + // Write the off_stages information dg.add_bool(_off_all_stages); - // write the number of off_stages dg.add_uint16(get_num_off_stages()); - // write the off stages pointers if any OffStages::const_iterator fi; for (fi = _off_stages.begin(); fi != _off_stages.end(); ++fi) { TextureStage *stage = (*fi); manager->write_pointer(dg, stage); } - // write the number of on stages + + // Write the on_stages information dg.add_uint16(get_num_on_stages()); - // write the on stages pointers if any - OnTextures::const_iterator nti; - for (nti = _on_textures.begin(); nti != _on_textures.end(); ++nti) { - TextureStage *stage = (*nti).first; + OnStages::const_iterator si; + for (si = _on_stages.begin(); si != _on_stages.end(); ++si) { + TextureStage *stage = (*si)._stage; + Texture *tex = get_on_texture(stage); + nassertv(tex != (Texture *)NULL); + manager->write_pointer(dg, stage); - Texture *texture = (*nti).second; - manager->write_pointer(dg,texture); + manager->write_pointer(dg, tex); + dg.add_uint16((*si)._implicit_sort); } -#else - manager->write_pointer(dg, get_texture()); -#endif } //////////////////////////////////////////////////////////////////// @@ -754,27 +850,27 @@ int TextureAttrib:: complete_pointers(TypedWritable **p_list, BamReader *manager) { int pi = RenderAttrib::complete_pointers(p_list, manager); - OffStages::iterator ci = _off_stages.begin(); - while (ci != _off_stages.end()) { + OffStages::iterator ci; + for (ci = _off_stages.begin(); ci != _off_stages.end(); ++ci) { TextureStage *ts = DCAST(TextureStage, p_list[pi++]); *ci = ts; - ++ci; } - - // read the pointers of the on_textures - _on_stages.reserve(_num_on_textures); - - for (int i = 0; i < _num_on_textures; ++i) { + + size_t sn = 0; + while (sn < _on_stages.size()) { TextureStage *ts = DCAST(TextureStage, p_list[pi++]); - Texture *tx = DCAST(Texture, p_list[pi++]); - if (tx != (Texture *)NULL) { - _on_textures[ts] = tx; - _on_stages.push_back(ts); + Texture *tex = DCAST(Texture, p_list[pi++]); + + if (tex != (Texture *)NULL) { + _on_textures[ts] = tex; + _on_stages[sn]._stage = ts; + ++sn; } 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); } } _sort_seq = UpdateSeq::old(); @@ -813,9 +909,8 @@ void TextureAttrib:: fillin(DatagramIterator &scan, BamReader *manager) { RenderAttrib::fillin(scan, manager); - // read the boolean if _off_all_stages + // read the _off_stages data. _off_all_stages = scan.get_bool(); - // read the number of off_stages int num_off_stages = scan.get_uint16(); // Push back a NULL pointer for each off TextureStage for now, until @@ -826,15 +921,26 @@ fillin(DatagramIterator &scan, BamReader *manager) { manager->read_pointer(scan); _off_stages.push_back(NULL); } - // read the number of on stages - _num_on_textures = scan.get_uint16(); - // just read the pointers, all allocation will happen from - // complete_pointers because it is a map template we get the actual - // list of pointers later in complete_pointers(). - for (i = 0; i < _num_on_textures; i++) { + // Read the _on_stages data. + int num_on_stages = scan.get_uint16(); + + // Push back a NULL pointer for each off TextureStage and Texture + // for now, until we get the actual list of pointers later in + // complete_pointers(). + _on_stages.reserve(num_on_stages); + _next_implicit_sort = 0; + for (i = 0; i < num_on_stages; i++) { manager->read_pointer(scan); manager->read_pointer(scan); + unsigned int implicit_sort; + if (manager->get_file_minor_ver() >= 15) { + implicit_sort = scan.get_uint16(); + } else { + implicit_sort = (unsigned int)i; + } + _next_implicit_sort = max(_next_implicit_sort, implicit_sort + 1); + _on_stages.push_back(OnStageNode(NULL, implicit_sort)); } } @@ -862,9 +968,9 @@ sort_on_stages() { typedef pmap TexcoordMap; TexcoordMap tc_map; - OnStages::const_iterator osi; - for (osi = _on_stages.begin(); osi != _on_stages.end(); ++osi) { - TextureStage *stage = (*osi); + OnStages::const_iterator si; + for (si = _on_stages.begin(); si != _on_stages.end(); ++si) { + TextureStage *stage = (*si)._stage; if (stage->is_fixed_function()) { const InternalName *name = stage->get_texcoord_name(); @@ -880,17 +986,17 @@ sort_on_stages() { } // Now we can sort the on_stages map into render order. - sort(_on_stages.begin(), _on_stages.end(), IndirectLess()); + sort(_on_stages.begin(), _on_stages.end()); _sort_seq = TextureStage::get_sort_seq(); _on_ff_stages.clear(); _ff_tc_index.clear(); - for (osi = _on_stages.begin(); osi != _on_stages.end(); ++osi) { - TextureStage *stage = (*osi); + for (si = _on_stages.begin(); si != _on_stages.end(); ++si) { + TextureStage *stage = (*si)._stage; if (stage->is_fixed_function()) { - _on_ff_stages.push_back(stage); + _on_ff_stages.push_back(*si); int texcoord_index = tc_map[stage]; _ff_tc_index.push_back(texcoord_index); } diff --git a/panda/src/pgraph/textureAttrib.h b/panda/src/pgraph/textureAttrib.h index 5fff1c4243..4957aea721 100644 --- a/panda/src/pgraph/textureAttrib.h +++ b/panda/src/pgraph/textureAttrib.h @@ -25,16 +25,14 @@ #include "texture.h" #include "textureStage.h" #include "updateSeq.h" -#include "indirectLess.h" -#include "geom.h" #include "ordered_vector.h" #include "vector_int.h" //////////////////////////////////////////////////////////////////// // Class : TextureAttrib -// Description : Indicates which texture should be applied as the -// primary texture. Also see TextureAttrib2 for the -// secondary texture. +// Description : Indicates the set of TextureStages and their +// associated Textures that should be applied to (or +// removed from) a node. //////////////////////////////////////////////////////////////////// class EXPCL_PANDA_PGRAPH TextureAttrib : public RenderAttrib { protected: @@ -81,8 +79,6 @@ PUBLISHED: CPT(RenderAttrib) unify_texture_stages(TextureStage *stage) const; public: - INLINE const Geom::ActiveTextureStages &get_on_stages() const; - INLINE const Geom::ActiveTextureStages &get_on_ff_stages() const; CPT(TextureAttrib) filter_to_max(int max_texture_stages) const; virtual void output(ostream &out) const; @@ -102,10 +98,25 @@ private: void sort_on_stages(); private: - typedef Geom::ActiveTextureStages OnStages; + class OnStageNode { + public: + INLINE OnStageNode(TextureStage *stage, unsigned int implicit_sort); + INLINE bool operator < (const OnStageNode &other) const; + + PT(TextureStage) _stage; + unsigned int _implicit_sort; + }; + + class CompareTextureStagePriorities { + public: + bool operator () (const TextureAttrib::OnStageNode &a, const TextureAttrib::OnStageNode &b) const; + }; + + typedef pvector OnStages; OnStages _on_stages; OnStages _on_ff_stages; vector_int _ff_tc_index; + unsigned int _next_implicit_sort; typedef ov_set OffStages; OffStages _off_stages; @@ -119,8 +130,6 @@ private: UpdateSeq _sort_seq; - int _num_on_textures; //temporary count to complete_pointers from fill_in - static CPT(RenderAttrib) _empty_attrib; static CPT(RenderAttrib) _all_off_attrib; diff --git a/panda/src/putil/bam.h b/panda/src/putil/bam.h index 56ee27e53a..e18d5ca954 100644 --- a/panda/src/putil/bam.h +++ b/panda/src/putil/bam.h @@ -36,7 +36,7 @@ static const unsigned short _bam_major_ver = 6; // Bumped to major version 5 on 5/6/05 for new Geom implementation. // Bumped to major version 6 on 2/11/06 to factor out PandaNode::CData. -static const unsigned short _bam_minor_ver = 14; +static const unsigned short _bam_minor_ver = 15; // Bumped to minor version 1 on 3/12/06 to add Texture::_compression. // Bumped to minor version 2 on 3/17/06 to add PandaNode::_draw_control_mask. // Bumped to minor version 3 on 3/21/06 to add Texture::_ram_images. @@ -51,6 +51,7 @@ static const unsigned short _bam_minor_ver = 14; // Bumped to minor version 12 on 7/3/07 to rework control/frozen joints more. // Bumped to minor version 13 on 8/15/07 to reverse CollisionPolygon vertices. // 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. #endif