diff --git a/panda/src/egg2pg/eggLoader.cxx b/panda/src/egg2pg/eggLoader.cxx index 79749b06aa..a78258c7e6 100644 --- a/panda/src/egg2pg/eggLoader.cxx +++ b/panda/src/egg2pg/eggLoader.cxx @@ -410,7 +410,7 @@ make_polyset(EggBin *egg_bin, PandaNode *parent, const LMatrix4d *transform, //////////////////////////////////////////////////////////////////// // Function: EggLoader::make_transform -// Access: Public, Static +// Access: Public // Description: Creates a TransformState object corresponding to the // indicated EggTransform. //////////////////////////////////////////////////////////////////// @@ -525,7 +525,19 @@ make_transform(const EggTransform *egg_transform) { } } - return ts; + if (ts->components_given()) { + return ts; + } + + // Finally, we uniquify all the matrix-based TransformStates we + // create by complete matrix value. The TransformState class + // doesn't normally go this far, because of the cost of this + // additional uniquification step, but this is the egg loader so we + // don't mind spending a little bit of extra time here to get a more + // optimal result. + TransformStates::iterator tsi = _transform_states.insert(TransformStates::value_type(ts->get_mat(), ts)).first; + + return (*tsi).second; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/egg2pg/eggLoader.h b/panda/src/egg2pg/eggLoader.h index fb36bc38a1..e840de5cbd 100644 --- a/panda/src/egg2pg/eggLoader.h +++ b/panda/src/egg2pg/eggLoader.h @@ -81,7 +81,7 @@ public: const LMatrix4d *transform, bool is_dynamic, CharacterMaker *character_maker); - static CPT(TransformState) make_transform(const EggTransform *egg_transform); + CPT(TransformState) make_transform(const EggTransform *egg_transform); private: class TextureDef { @@ -228,6 +228,9 @@ private: typedef pmap VertexPoolData; VertexPoolData _vertex_pool_data; + typedef pmap TransformStates; + TransformStates _transform_states; + DeferredNodes _deferred_nodes; public: diff --git a/panda/src/egg2pg/eggRenderState.cxx b/panda/src/egg2pg/eggRenderState.cxx index c86d93e837..67dc18e6e0 100644 --- a/panda/src/egg2pg/eggRenderState.cxx +++ b/panda/src/egg2pg/eggRenderState.cxx @@ -527,7 +527,7 @@ get_tex_gen(const EggTexture *egg_tex) { //////////////////////////////////////////////////////////////////// // Function: EggRenderState::apply_tex_mat -// Access: Private, Static +// Access: Private // Description: Applies the texture matrix from the indicated egg // texture to the given TexMatrixAttrib, and returns the // new attrib. @@ -536,7 +536,7 @@ CPT(RenderAttrib) EggRenderState:: apply_tex_mat(CPT(RenderAttrib) tex_mat_attrib, TextureStage *stage, const EggTexture *egg_tex) { if (egg_tex->has_transform()) { - CPT(TransformState) transform = EggLoader::make_transform(egg_tex); + CPT(TransformState) transform = _loader.make_transform(egg_tex); if (tex_mat_attrib == (const RenderAttrib *)NULL) { tex_mat_attrib = TexMatrixAttrib::make(); diff --git a/panda/src/egg2pg/eggRenderState.h b/panda/src/egg2pg/eggRenderState.h index 8ff6dc8cae..3be7a672a3 100644 --- a/panda/src/egg2pg/eggRenderState.h +++ b/panda/src/egg2pg/eggRenderState.h @@ -57,7 +57,7 @@ private: bool bface); static TexGenAttrib::Mode get_tex_gen(const EggTexture *egg_tex); - static CPT(RenderAttrib) + CPT(RenderAttrib) apply_tex_mat(CPT(RenderAttrib) tex_mat_attrib, TextureStage *stage, const EggTexture *egg_tex); diff --git a/panda/src/grutil/multitexReducer.I b/panda/src/grutil/multitexReducer.I index b84e036b6f..489e6893d3 100644 --- a/panda/src/grutil/multitexReducer.I +++ b/panda/src/grutil/multitexReducer.I @@ -79,7 +79,7 @@ operator < (const MultitexReducer::StageInfo &other) const { return _tex < other._tex; } if (_tex_mat != other._tex_mat) { - return _tex_mat < other._tex_mat; + return _tex_mat->sorts_less(*other._tex_mat, true); } return false; diff --git a/panda/src/grutil/multitexReducer.cxx b/panda/src/grutil/multitexReducer.cxx index 73512408c5..93db90751f 100644 --- a/panda/src/grutil/multitexReducer.cxx +++ b/panda/src/grutil/multitexReducer.cxx @@ -328,7 +328,7 @@ flatten(GraphicsOutput *window) { // for the first texture layer to apply onto. CardMaker cm("background"); - cm.set_frame(0.0f, 1.0f, 0.0f, 1.0f); + cm.set_frame(min_uv[0], max_uv[0], min_uv[1], max_uv[1]); if (bake_in_color) { cm.set_color(geom_color); } @@ -348,7 +348,8 @@ flatten(GraphicsOutput *window) { for (si = stage_list.begin(); si != stage_list.end(); ++si) { const StageInfo &stage_info = (*si); - make_texture_layer(render, stage_info, geom_list, force_use_geom); + make_texture_layer(render, stage_info, geom_list, + min_uv, max_uv, force_use_geom); } // Now modify the geometry to apply the new texture, instead of @@ -362,7 +363,8 @@ flatten(GraphicsOutput *window) { CPT(RenderState) geom_state = geom_info._geom_node->get_geom_state(geom_info._index); - geom_state = geom_state->add_attrib(new_ta); + int override = geom_info._geom_net_state->get_override(TextureAttrib::get_class_type()); + geom_state = geom_state->add_attrib(new_ta, override); if (bake_in_color) { // If we have baked the color into the texture, we have to be @@ -475,8 +477,9 @@ scan_geom_node(GeomNode *node, const RenderState *state, // Just a single texture on the Geom; we don't really need to do // anything to flatten the textures, then. But we should ensure // that the correct TextureAttrib is applied to the Geom. + int override = geom_net_state->get_override(TextureAttrib::get_class_type()); CPT(RenderState) geom_state = node->get_geom_state(gi); - geom_state = geom_state->add_attrib(ta); + geom_state = geom_state->add_attrib(ta, override); node->set_geom_state(gi, geom_state); } else { @@ -734,6 +737,7 @@ void MultitexReducer:: make_texture_layer(const NodePath &render, const MultitexReducer::StageInfo &stage_info, const MultitexReducer::GeomList &geom_list, + const TexCoordf &min_uv, const TexCoordf &max_uv, bool force_use_geom) { CPT(RenderAttrib) cba; @@ -768,11 +772,56 @@ make_texture_layer(const NodePath &render, break; case TextureStage::M_combine: - // We don't support the texture combiner here right now. For now, - // this is the same as modulate. - cba = ColorBlendAttrib::make - (ColorBlendAttrib::M_add, ColorBlendAttrib::O_fbuffer_color, - ColorBlendAttrib::O_zero); + // We only support certain modes of M_combine. + switch (stage_info._stage->get_combine_rgb_mode()) { + case TextureStage::CM_modulate: + { + TextureStage::CombineSource source0 = stage_info._stage->get_combine_rgb_source0(); + TextureStage::CombineOperand operand0 = stage_info._stage->get_combine_rgb_operand0(); + TextureStage::CombineSource source1 = stage_info._stage->get_combine_rgb_source1(); + TextureStage::CombineOperand operand1 = stage_info._stage->get_combine_rgb_operand1(); + // Since modulate doesn't care about order, let's establish + // the convention that the lowest-numbered source + // operand is in slot 0 (just for purposes of comparison). + if (source1 < source0) { + source0 = stage_info._stage->get_combine_rgb_source1(); + operand0 = stage_info._stage->get_combine_rgb_operand1(); + source1 = stage_info._stage->get_combine_rgb_source0(); + operand1 = stage_info._stage->get_combine_rgb_operand0(); + } + + if (source0 == TextureStage::CS_primary_color && + source1 == TextureStage::CS_previous) { + // This is just a trick to re-apply the vertex (lighting) + // color on the top of the texture stack. We can ignore it, + // since the flattened texture will do this anyway. + return; + + } else if (source0 == TextureStage::CS_texture && + source1 == TextureStage::CS_constant) { + // Scaling the texture by a flat color. + cba = ColorBlendAttrib::make + (ColorBlendAttrib::M_add, ColorBlendAttrib::O_constant_color, + ColorBlendAttrib::O_zero, stage_info._stage->get_color()); + + } else if (source0 == TextureStage::CS_texture && + source1 == TextureStage::CS_previous) { + // Just an ordinary modulate. + cba = ColorBlendAttrib::make + (ColorBlendAttrib::M_add, ColorBlendAttrib::O_fbuffer_color, + ColorBlendAttrib::O_zero); + + } else { + // Some other kind of modulate; we don't support it. + return; + } + } + break; + + default: + // Ignore this stage; we don't support it. + return; + } break; case TextureStage::M_blend_color_scale: @@ -790,9 +839,9 @@ make_texture_layer(const NodePath &render, // If this TextureStage uses the target texcoords, we can just // generate a simple card the fills the entire buffer. CardMaker cm(stage_info._tex->get_name()); - cm.set_uv_range(TexCoordf(0.0f, 0.0f), TexCoordf(1.0f, 1.0f)); + cm.set_uv_range(min_uv, max_uv); cm.set_has_uvs(true); - cm.set_frame(0.0f, 1.0f, 0.0f, 1.0f); + cm.set_frame(min_uv[0], max_uv[0], min_uv[1], max_uv[1]); geom = render.attach_new_node(cm.generate()); diff --git a/panda/src/grutil/multitexReducer.h b/panda/src/grutil/multitexReducer.h index c463f24af2..b3195e38dd 100644 --- a/panda/src/grutil/multitexReducer.h +++ b/panda/src/grutil/multitexReducer.h @@ -138,6 +138,7 @@ private: void make_texture_layer(const NodePath &render, const StageInfo &stage_info, const GeomList &geom_list, + const TexCoordf &min_uv, const TexCoordf &max_uv, bool force_use_geom); void transfer_geom(GeomNode *geom_node, const InternalName *texcoord_name, const GeomList &geom_list, bool preserve_color); diff --git a/panda/src/pgraph/transformState.I b/panda/src/pgraph/transformState.I index e72146153c..8441edafcc 100644 --- a/panda/src/pgraph/transformState.I +++ b/panda/src/pgraph/transformState.I @@ -17,6 +17,22 @@ //////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// +// Function: TransformState::operator < +// Access: Published +// Description: Provides an arbitrary ordering among all unique +// TransformStates, so we can store the essentially +// different ones in a big set and throw away the rest. +// +// This is the same as sorts_less(), except the +// uniquify_matrix value is implicit from the Config.prc +// file. +//////////////////////////////////////////////////////////////////// +INLINE bool TransformState:: +operator < (const TransformState &other) const { + return sorts_less(other, uniquify_matrix); +} + //////////////////////////////////////////////////////////////////// // Function: TransformState::make_pos // Access: Published, Static diff --git a/panda/src/pgraph/transformState.cxx b/panda/src/pgraph/transformState.cxx index 72b633187a..40432c8824 100644 --- a/panda/src/pgraph/transformState.cxx +++ b/panda/src/pgraph/transformState.cxx @@ -110,14 +110,20 @@ TransformState:: } //////////////////////////////////////////////////////////////////// -// Function: TransformState::operator < +// Function: TransformState::sorts_less // Access: Published // Description: Provides an arbitrary ordering among all unique // TransformStates, so we can store the essentially // different ones in a big set and throw away the rest. +// +// If uniquify_matrix is true, then matrix-defined +// TransformStates are also uniqified. If +// uniquify_matrix is false, then only component-defined +// TransformStates are uniquified, which is less +// expensive. //////////////////////////////////////////////////////////////////// bool TransformState:: -operator < (const TransformState &other) const { +sorts_less(const TransformState &other, bool uniquify_matrix) const { static const int significant_flags = (F_is_invalid | F_is_identity | F_components_given | F_hpr_given | F_quat_given | F_is_2d); diff --git a/panda/src/pgraph/transformState.h b/panda/src/pgraph/transformState.h index eaccd84100..453536ecba 100644 --- a/panda/src/pgraph/transformState.h +++ b/panda/src/pgraph/transformState.h @@ -30,6 +30,7 @@ #include "pStatCollector.h" #include "geomEnums.h" #include "reMutex.h" +#include "config_pgraph.h" class GraphicsStateGuardianBase; class FactoryParams; @@ -68,7 +69,8 @@ public: virtual ~TransformState(); PUBLISHED: - bool operator < (const TransformState &other) const; + INLINE bool operator < (const TransformState &other) const; + bool sorts_less(const TransformState &other, bool uniquify_matrix) const; size_t get_hash() const; static CPT(TransformState) make_identity();