diff --git a/panda/src/gobj/geom.I b/panda/src/gobj/geom.I index ad00f0b14a..afc9e99adf 100644 --- a/panda/src/gobj/geom.I +++ b/panda/src/gobj/geom.I @@ -325,8 +325,9 @@ calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, CDReader cdata(_cycler, current_thread); do_calc_tight_bounds(min_point, max_point, found_any, - vertex_data, got_mat, mat, cdata, - current_thread); + vertex_data, got_mat, mat, + InternalName::get_vertex(), + cdata, current_thread); } //////////////////////////////////////////////////////////////////// @@ -351,6 +352,26 @@ calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, current_thread); } +//////////////////////////////////////////////////////////////////// +// Function: Geom::calc_tight_bounds +// Access: Public +// Description: Similar to calc_tight_bounds(), for UV coordinates or +// other named columns. +//////////////////////////////////////////////////////////////////// +INLINE void Geom:: +calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, + bool &found_any, + const GeomVertexData *vertex_data, + bool got_mat, const LMatrix4f &mat, + const InternalName *column_name, + Thread *current_thread) const { + CDReader cdata(_cycler, current_thread); + + do_calc_tight_bounds(min_point, max_point, found_any, + vertex_data, got_mat, mat, + column_name, cdata, current_thread); +} + //////////////////////////////////////////////////////////////////// // Function: Geom::mark_internal_bounds_stale // Access: Private diff --git a/panda/src/gobj/geom.cxx b/panda/src/gobj/geom.cxx index 9f5b998d39..0baa60967d 100644 --- a/panda/src/gobj/geom.cxx +++ b/panda/src/gobj/geom.cxx @@ -1219,7 +1219,9 @@ compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const { LPoint3f min, max; bool found_any = false; do_calc_tight_bounds(min, max, found_any, vertex_data, - false, LMatrix4f::ident_mat(), cdata, current_thread); + false, LMatrix4f::ident_mat(), + InternalName::get_vertex(), + cdata, current_thread); if (found_any) { // Then we put the bounding volume around both of those points. @@ -1268,6 +1270,7 @@ do_calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, bool &found_any, const GeomVertexData *vertex_data, bool got_mat, const LMatrix4f &mat, + const InternalName *column_name, const CData *cdata, Thread *current_thread) const { Primitives::const_iterator pi; for (pi = cdata->_primitives.begin(); @@ -1275,7 +1278,7 @@ do_calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, ++pi) { CPT(GeomPrimitive) prim = (*pi).get_read_pointer(); prim->calc_tight_bounds(min_point, max_point, found_any, vertex_data, - got_mat, mat, current_thread); + got_mat, mat, column_name, current_thread); } } diff --git a/panda/src/gobj/geom.h b/panda/src/gobj/geom.h index 5a2d279ab5..db46be2b98 100644 --- a/panda/src/gobj/geom.h +++ b/panda/src/gobj/geom.h @@ -151,6 +151,12 @@ public: Thread *current_thread) const; INLINE void calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, bool &found_any, Thread *current_thread) const; + INLINE void calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, + bool &found_any, + const GeomVertexData *vertex_data, + bool got_mat, const LMatrix4f &mat, + const InternalName *column_name, + Thread *current_thread) const; static UpdateSeq get_next_modified(); @@ -164,6 +170,7 @@ private: bool &found_any, const GeomVertexData *vertex_data, bool got_mat, const LMatrix4f &mat, + const InternalName *column_name, const CData *cdata, Thread *current_thread) const; void clear_prepared(PreparedGraphicsObjects *prepared_objects); diff --git a/panda/src/gobj/geomPrimitive.cxx b/panda/src/gobj/geomPrimitive.cxx index bc8bd7ec9a..51902f9691 100644 --- a/panda/src/gobj/geomPrimitive.cxx +++ b/panda/src/gobj/geomPrimitive.cxx @@ -1319,19 +1319,21 @@ get_highest_index_value(NumericType index_type) { // Function: GeomPrimitive::calc_tight_bounds // Access: Public, Virtual // Description: Expands min_point and max_point to include all of the -// vertices in the Geom, if any. found_any is set true -// if any points are found. It is the caller's -// responsibility to initialize min_point, max_point, -// and found_any before calling this function. +// vertices in the Geom, if any (or the data of any +// point type, for instance, texture coordinates--based +// on the column name). found_any is set true if any +// points are found. It is the caller's responsibility +// to initialize min_point, max_point, and found_any +// before calling this function. //////////////////////////////////////////////////////////////////// void GeomPrimitive:: calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, bool &found_any, const GeomVertexData *vertex_data, bool got_mat, const LMatrix4f &mat, + const InternalName *column_name, Thread *current_thread) const { - GeomVertexReader reader(vertex_data, InternalName::get_vertex(), - current_thread); + GeomVertexReader reader(vertex_data, column_name, current_thread); if (!reader.has_column()) { // No vertex data. return; diff --git a/panda/src/gobj/geomPrimitive.h b/panda/src/gobj/geomPrimitive.h index 15639bad4a..09c9dda775 100644 --- a/panda/src/gobj/geomPrimitive.h +++ b/panda/src/gobj/geomPrimitive.h @@ -198,6 +198,7 @@ public: bool &found_any, const GeomVertexData *vertex_data, bool got_mat, const LMatrix4f &mat, + const InternalName *column_name, Thread *current_thread) const; protected: diff --git a/panda/src/pgraph/geomNode.cxx b/panda/src/pgraph/geomNode.cxx index afbfbfb44d..4efac4e6f9 100644 --- a/panda/src/pgraph/geomNode.cxx +++ b/panda/src/pgraph/geomNode.cxx @@ -292,7 +292,11 @@ apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types, } CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler); - transformer.register_vertices(this); + if ((attrib_types & SceneGraphReducer::TT_apply_texture_color) != 0) { + transformer.apply_texture_colors(this, attribs._other); + } + + transformer.register_vertices(this, false); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/geomTransformer.I b/panda/src/pgraph/geomTransformer.I index 1187c273fb..ca496477cc 100644 --- a/panda/src/pgraph/geomTransformer.I +++ b/panda/src/pgraph/geomTransformer.I @@ -82,6 +82,31 @@ operator < (const GeomTransformer::SourceColors &other) const { return (_color.compare_to(other._color) < 0); } +//////////////////////////////////////////////////////////////////// +// Function: GeomTransformer::SourceTextureColors::Ordering Operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE bool GeomTransformer::SourceTextureColors:: +operator < (const GeomTransformer::SourceTextureColors &other) const { + if (_vertex_data != other._vertex_data) { + return _vertex_data < other._vertex_data; + } + if (_tex != other._tex) { + return _tex < other._tex; + } + if (_ts != other._ts) { + return _ts < other._ts; + } + if (_tma != other._tma) { + return _tma < other._tma; + } + if (_keep_vertex_color != other._keep_vertex_color) { + return (int)_keep_vertex_color < (int)other._keep_vertex_color; + } + return (_base_color.compare_to(other._base_color) < 0); +} + //////////////////////////////////////////////////////////////////// // Function: GeomTransformer::SourceFormat::Ordering Operator // Access: Public diff --git a/panda/src/pgraph/geomTransformer.cxx b/panda/src/pgraph/geomTransformer.cxx index 1c35af515b..e82d43ea03 100644 --- a/panda/src/pgraph/geomTransformer.cxx +++ b/panda/src/pgraph/geomTransformer.cxx @@ -26,12 +26,15 @@ #include "vector_int.h" #include "userVertexTransform.h" #include "geomMunger.h" +#include "texture.h" +#include "texturePeeker.h" #include "config_pgraph.h" PStatCollector GeomTransformer::_apply_vertex_collector("*:Flatten:apply:vertex"); PStatCollector GeomTransformer::_apply_texcoord_collector("*:Flatten:apply:texcoord"); PStatCollector GeomTransformer::_apply_set_color_collector("*:Flatten:apply:set color"); PStatCollector GeomTransformer::_apply_scale_color_collector("*:Flatten:apply:scale color"); +PStatCollector GeomTransformer::_apply_texture_color_collector("*:Flatten:apply:texture color"); PStatCollector GeomTransformer::_apply_set_format_collector("*:Flatten:apply:set format"); TypeHandle GeomTransformer::NewCollectedData::_type_handle; @@ -77,9 +80,12 @@ GeomTransformer:: // unused vertices. //////////////////////////////////////////////////////////////////// void GeomTransformer:: -register_vertices(Geom *geom) { +register_vertices(Geom *geom, bool might_have_unused) { VertexDataAssoc &assoc = _vdata_assoc[geom->get_vertex_data()]; assoc._geoms.push_back(geom); + if (might_have_unused) { + assoc._might_have_unused = true; + } } //////////////////////////////////////////////////////////////////// @@ -90,7 +96,7 @@ register_vertices(Geom *geom) { // unused vertices. //////////////////////////////////////////////////////////////////// void GeomTransformer:: -register_vertices(GeomNode *node) { +register_vertices(GeomNode *node, bool might_have_unused) { Thread *current_thread = Thread::get_current_thread(); OPEN_ITERATE_CURRENT_AND_UPSTREAM(node->_cycler, current_thread) { GeomNode::CDStageWriter cdata(node->_cycler, pipeline_stage, current_thread); @@ -99,7 +105,7 @@ register_vertices(GeomNode *node) { for (gi = geoms.begin(); gi != geoms.end(); ++gi) { GeomNode::GeomEntry &entry = (*gi); PT(Geom) geom = entry._geom.get_write_pointer(); - register_vertices(geom); + register_vertices(geom, might_have_unused); } } CLOSE_ITERATE_CURRENT_AND_UPSTREAM(node->_cycler); @@ -425,6 +431,272 @@ transform_colors(GeomNode *node, const LVecBase4f &scale) { } +//////////////////////////////////////////////////////////////////// +// Function: GeomTransformer::apply_texture_colors +// Access: Public +// Description: Removes textures from Geoms by applying the texture +// colors to the vertices. +// +// See apply_texure_colors(GeomNode *, RenderState *). +//////////////////////////////////////////////////////////////////// +bool GeomTransformer:: +apply_texture_colors(Geom *geom, TextureStage *ts, Texture *tex, + const TexMatrixAttrib *tma, const Colorf &base_color, + bool keep_vertex_color) { + PStatTimer timer(_apply_texture_color_collector); + + nassertr(geom != (Geom *)NULL, false); + + PT(TexturePeeker) peeker = tex->peek(); + if (peeker == (TexturePeeker *)NULL) { + return false; + } + + if (peeker->get_x_size() == 1 && + peeker->get_y_size() == 1 && + peeker->get_z_size() == 1) { + // If it's just a one-pixel texture (e.g. a simple ram image), + // don't bother scanning the UV's. Just extract the color and + // apply it. + Colorf color; + peeker->lookup(color, 0.0f, 0.0f); + color.set(color[0] * base_color[0], + color[1] * base_color[1], + color[2] * base_color[2], + color[3] * base_color[3]); + if (keep_vertex_color) { + return transform_colors(geom, color); + } else { + return set_color(geom, color); + } + } + + bool got_mat = false; + LMatrix4f mat = LMatrix4f::ident_mat(); + if (tma != (TexMatrixAttrib *)NULL && tma->has_stage(ts)) { + mat = tma->get_mat(ts); + got_mat = !mat.almost_equal(LMatrix4f::ident_mat()); + } + + // This version of the code just applied one overall flat color to + // the entire mesh. Turned out not to be good enough. Instead, + // we'll look up each vertex in the texture map and apply the + // nearest color to the vertex. + /* + // Scan the UV's to get the used range. This is particularly + // necessary for palettized textures. + + LPoint3f min_point, max_point; + bool found_any = false; + geom->calc_tight_bounds(min_point, max_point, found_any, + geom->get_vertex_data(), + got_mat, mat, + ts->get_texcoord_name(), + Thread::get_current_thread()); + if (found_any) { + // Now use that UV range to determine the overall color of the + // geom's texture. + Colorf color; + peeker->filter_rect(color, + min_point[0], min_point[1], min_point[2], + max_point[0], max_point[1], max_point[2]); + color.set(color[0] * base_color[0], + color[1] * base_color[1], + color[2] * base_color[2], + color[3] * base_color[3]); + if (keep_vertex_color) { + return transform_colors(geom, color); + } else { + return set_color(geom, color); + } + } + + return false; + */ + + SourceTextureColors stc; + stc._ts = ts; + stc._tex = tex; + stc._tma = tma; + stc._base_color = base_color; + stc._keep_vertex_color = keep_vertex_color; + stc._vertex_data = geom->get_vertex_data(); + + NewVertexData &new_data = _tex_colors[stc]; + if (new_data._vdata.is_null()) { + // We have not yet applied these texture colors. Do so now. + + PT(GeomVertexData) vdata; + + // Make sure the vdata has a color column. + if (stc._vertex_data->has_column(InternalName::get_color())) { + vdata = new GeomVertexData(*stc._vertex_data); + } else { + // Create a color column where there wasn't one before. + vdata = new GeomVertexData(*stc._vertex_data->set_color + (Colorf(1.0f, 1.0f, 1.0f, 1.0f), 1, Geom::NT_packed_dabc, Geom::C_color)); + keep_vertex_color = false; + } + + // Check whether it has 2-d or 3-d texture coordinates. + bool tex3d = false; + const GeomVertexColumn *column = vdata->get_format()->get_column(ts->get_texcoord_name()); + if (column == (GeomVertexColumn *)NULL) { + return false; + } + if (column->get_num_components() >= 3) { + tex3d = true; + } + + // Now walk through the vertices and apply each color from the + // texture as we go. + if (keep_vertex_color) { + // We want to modulate the existing vertex color. + GeomVertexReader gtexcoord(vdata, ts->get_texcoord_name()); + GeomVertexRewriter gcolor(vdata, InternalName::get_color()); + + if (got_mat || tex3d) { + while (!gtexcoord.is_at_end()) { + TexCoord3f p = gtexcoord.get_data3f(); + Colorf c = gcolor.get_data4f(); + p = p * mat; + Colorf color; + peeker->lookup(color, p[0], p[1], p[2]); + color.set(color[0] * base_color[0] * c[0], + color[1] * base_color[1] * c[1], + color[2] * base_color[2] * c[2], + color[3] * base_color[3] * c[3]); + gcolor.set_data4f(color); + } + } else { + while (!gtexcoord.is_at_end()) { + TexCoordf p = gtexcoord.get_data2f(); + Colorf c = gcolor.get_data4f(); + Colorf color; + peeker->lookup(color, p[0], p[1]); + color.set(color[0] * base_color[0] * c[0], + color[1] * base_color[1] * c[1], + color[2] * base_color[2] * c[2], + color[3] * base_color[3] * c[3]); + gcolor.set_data4f(color); + } + } + } else { + // We want to replace any existing vertex color. + GeomVertexReader gtexcoord(vdata, ts->get_texcoord_name()); + GeomVertexWriter gcolor(vdata, InternalName::get_color()); + + if (got_mat || tex3d) { + while (!gtexcoord.is_at_end()) { + TexCoord3f p = gtexcoord.get_data3f(); + p = p * mat; + Colorf color; + peeker->lookup(color, p[0], p[1], p[2]); + color.set(color[0] * base_color[0], + color[1] * base_color[1], + color[2] * base_color[2], + color[3] * base_color[3]); + gcolor.set_data4f(color); + } + } else { + while (!gtexcoord.is_at_end()) { + TexCoordf p = gtexcoord.get_data2f(); + Colorf color; + peeker->lookup(color, p[0], p[1]); + color.set(color[0] * base_color[0], + color[1] * base_color[1], + color[2] * base_color[2], + color[3] * base_color[3]); + gcolor.set_data4f(color); + } + } + } + + new_data._vdata = vdata; + } + + geom->set_vertex_data(new_data._vdata); + VertexDataAssoc &assoc = _vdata_assoc[new_data._vdata]; + if (stc._vertex_data->get_ref_count() > 1) { + _vdata_assoc[new_data._vdata]._might_have_unused = true; + _vdata_assoc[stc._vertex_data]._might_have_unused = true; + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: GeomTransformer::apply_texture_colors +// Access: Public +// Description: Removes textures from Geoms by applying the texture +// colors to the vertices. This is primarily useful to +// simplify a low-LOD model. +// +// Only the bottommost texture is used (if there is more +// than one), and it is applied as if it were +// M_modulate, and WM_repeat, regardless of its actual +// settings. If the texture has a simple_ram_image, +// this may be used if the main image isn't resident. +// +// After this call, there will be no texturing specified +// on the GeomNode level. Of course, there might still +// be texturing inherited from above. +//////////////////////////////////////////////////////////////////// +bool GeomTransformer:: +apply_texture_colors(GeomNode *node, const RenderState *state) { + bool any_changed = false; + + GeomNode::CDWriter cdata(node->_cycler); + GeomNode::GeomList::iterator gi; + GeomNode::GeomList &geoms = *(cdata->modify_geoms()); + for (gi = geoms.begin(); gi != geoms.end(); ++gi) { + GeomNode::GeomEntry &entry = (*gi); + CPT(RenderState) geom_state = state->compose(entry._state); + + const TextureAttrib *ta = geom_state->get_texture(); + if (ta != (TextureAttrib *)NULL) { + CPT(TextureAttrib) ta2 = ta->filter_to_max(1); + if (ta2->get_num_on_stages() > 0) { + TextureStage *ts = ta2->get_on_stage(0); + Texture *tex = ta2->get_on_texture(ts); + const TexMatrixAttrib *tma = geom_state->get_tex_matrix(); + + const ColorAttrib *ca = geom_state->get_color(); + Colorf base_color(1.0f, 1.0f, 1.0f, 1.0f); + bool keep_vertex_color = true; + if (ca != (ColorAttrib *)NULL && ca->get_color_type() == ColorAttrib::T_flat) { + base_color = ca->get_color(); + keep_vertex_color = false; + } + + PT(Geom) new_geom = entry._geom.get_read_pointer()->make_copy(); + if (apply_texture_colors(new_geom, ts, tex, tma, base_color, keep_vertex_color)) { + entry._geom = new_geom; + any_changed = true; + + if (new_geom->get_vertex_data()->has_column(InternalName::get_color())) { + // Ensure we have a ColorAttrib::make_vertex() attrib. + CPT(RenderState) color_state = entry._state->set_attrib(ColorAttrib::make_vertex()); + if (entry._state != color_state) { + entry._state = color_state; + any_changed = true; + } + } + } + + // Also remove any texture references from the GeomState. + CPT(RenderState) no_tex_state = entry._state->remove_attrib(TextureAttrib::get_class_type()); + if (entry._state != no_tex_state) { + entry._state = no_tex_state; + any_changed = true; + } + } + } + } + + return any_changed; +} + //////////////////////////////////////////////////////////////////// // Function: GeomTransformer::apply_state // Access: Public diff --git a/panda/src/pgraph/geomTransformer.h b/panda/src/pgraph/geomTransformer.h index b1b90e68c7..74342343fa 100644 --- a/panda/src/pgraph/geomTransformer.h +++ b/panda/src/pgraph/geomTransformer.h @@ -25,6 +25,7 @@ class GeomNode; class RenderState; class InternalName; class GeomMunger; +class Texture; //////////////////////////////////////////////////////////////////// // Class : GeomTransformer @@ -51,8 +52,8 @@ public: INLINE int get_max_collect_vertices() const; INLINE void set_max_collect_vertices(int max_collect_vertices); - void register_vertices(Geom *geom); - void register_vertices(GeomNode *node); + void register_vertices(Geom *geom, bool might_have_unused); + void register_vertices(GeomNode *node, bool might_have_unused); bool transform_vertices(Geom *geom, const LMatrix4f &mat); bool transform_vertices(GeomNode *node, const LMatrix4f &mat); @@ -68,6 +69,11 @@ public: bool transform_colors(Geom *geom, const LVecBase4f &scale); bool transform_colors(GeomNode *node, const LVecBase4f &scale); + bool apply_texture_colors(Geom *geom, TextureStage *ts, Texture *tex, + const TexMatrixAttrib *tma, + const Colorf &base_color, bool keep_vertex_color); + bool apply_texture_colors(GeomNode *node, const RenderState *state); + bool apply_state(GeomNode *node, const RenderState *state); bool set_format(Geom *geom, const GeomVertexFormat *new_format); @@ -88,6 +94,12 @@ public: PT(Geom) premunge_geom(const Geom *geom, GeomMunger *munger); +private: + static void get_texel_color(Colorf &color, float u, float v, + const unsigned char *image, + int x_size, int y_size); + + private: int _max_collect_vertices; @@ -156,6 +168,22 @@ private: // modified from the original colors (e.g. via a ColorScaleAttrib). NewColors _fcolors, _tcolors; + // The table of GeomVertexData objects whose texture colors have + // been applied. + class SourceTextureColors { + public: + INLINE bool operator < (const SourceTextureColors &other) const; + + TextureStage *_ts; + Texture *_tex; + const TexMatrixAttrib *_tma; + Colorf _base_color; + bool _keep_vertex_color; + CPT(GeomVertexData) _vertex_data; + }; + typedef pmap NewTextureColors; + NewTextureColors _tex_colors; + // The table of GeomVertexData objects whose vertex formats have // been modified. For set_format(): record (format + vertex_data) -> // vertex_data. @@ -252,6 +280,7 @@ private: static PStatCollector _apply_texcoord_collector; static PStatCollector _apply_set_color_collector; static PStatCollector _apply_scale_color_collector; + static PStatCollector _apply_texture_color_collector; static PStatCollector _apply_set_format_collector; public: diff --git a/panda/src/pgraph/nodePath.cxx b/panda/src/pgraph/nodePath.cxx index 3cac987c7a..90df06c05b 100644 --- a/panda/src/pgraph/nodePath.cxx +++ b/panda/src/pgraph/nodePath.cxx @@ -6006,6 +6006,33 @@ flatten_strong() { return num_removed; } +//////////////////////////////////////////////////////////////////// +// Function: NodePath::apply_texture_colors +// Access: Published +// Description: Removes textures from Geoms at this node and below by +// applying the texture colors to the vertices. This is +// primarily useful to simplify a low-LOD model. The +// texture colors are replaced by flat colors that +// approximate the original textures. +// +// Only the bottommost texture on each Geom is used (if +// there is more than one), and it is applied as if it +// were M_modulate, and WM_repeat, regardless of its +// actual settings. If the texture has a +// simple_ram_image, this may be used if the main image +// isn't resident. +// +// After this call, there will be no texturing specified +// at this level and below. Of course, there might +// still be texturing inherited from above. +//////////////////////////////////////////////////////////////////// +void NodePath:: +apply_texture_colors() { + nassertv_always(!is_empty()); + SceneGraphReducer gr; + gr.apply_attribs(node(), SceneGraphReducer::TT_apply_texture_color | SceneGraphReducer::TT_tex_matrix | SceneGraphReducer::TT_other); +} + //////////////////////////////////////////////////////////////////// // Function: NodePath::find_net_tag // Access: Published diff --git a/panda/src/pgraph/nodePath.h b/panda/src/pgraph/nodePath.h index 71c1df07ef..7a03cc5332 100644 --- a/panda/src/pgraph/nodePath.h +++ b/panda/src/pgraph/nodePath.h @@ -819,6 +819,7 @@ PUBLISHED: int flatten_light(); int flatten_medium(); int flatten_strong(); + void apply_texture_colors(); INLINE int clear_model_nodes(); INLINE void set_tag(const string &key, const string &value); diff --git a/panda/src/pgraph/sceneGraphReducer.cxx b/panda/src/pgraph/sceneGraphReducer.cxx index 951bbcf637..43d49b3929 100644 --- a/panda/src/pgraph/sceneGraphReducer.cxx +++ b/panda/src/pgraph/sceneGraphReducer.cxx @@ -31,6 +31,7 @@ PStatCollector SceneGraphReducer::_compatible_state_collector("*:Flatten:compati PStatCollector SceneGraphReducer::_collect_collector("*:Flatten:collect"); PStatCollector SceneGraphReducer::_make_nonindexed_collector("*:Flatten:make nonindexed"); PStatCollector SceneGraphReducer::_unify_collector("*:Flatten:unify"); +PStatCollector SceneGraphReducer::_remove_unused_collector("*:Flatten:remove unused vertices"); PStatCollector SceneGraphReducer::_premunge_collector("*:Premunge"); //////////////////////////////////////////////////////////////////// @@ -183,6 +184,25 @@ unify(PandaNode *root, bool preserve_order) { r_unify(root, max_indices, preserve_order); } +//////////////////////////////////////////////////////////////////// +// Function: SceneGraphReducer::remove_unused_vertices +// Access: Published +// Description: Removes any vertices in GeomVertexDatas that are no +// longer used at this level and below. This requires +// remapping vertex indices in all of the +// GeomPrimitives, to remove holes in the +// GeomVertexDatas. It is normally not necessary to +// call this explicitly. +//////////////////////////////////////////////////////////////////// +void SceneGraphReducer:: +remove_unused_vertices(PandaNode *root) { + PStatTimer timer(_remove_unused_collector); + + r_register_vertices(root, _transformer); + _transformer.finish_apply(); + Thread::consider_yield(); +} + //////////////////////////////////////////////////////////////////// // Function: SceneGraphReducer::decompose // Access: Published @@ -909,6 +929,27 @@ r_unify(PandaNode *node, int max_indices, bool preserve_order) { Thread::consider_yield(); } +//////////////////////////////////////////////////////////////////// +// Function: SceneGraphReducer::r_register_vertices +// Access: Private +// Description: Recursively calls +// GeomTransformer::register_vertices() on all GeomNodes +// at the indicated root and below. +//////////////////////////////////////////////////////////////////// +void SceneGraphReducer:: +r_register_vertices(PandaNode *node, GeomTransformer &transformer) { + if (node->is_geom_node()) { + GeomNode *geom_node = DCAST(GeomNode, node); + transformer.register_vertices(geom_node, true); + } + + PandaNode::Children children = node->get_children(); + int num_children = children.get_num_children(); + for (int i = 0; i < num_children; ++i) { + r_register_vertices(children.get_child(i), transformer); + } +} + //////////////////////////////////////////////////////////////////// // Function: SceneGraphReducer::r_decompose // Access: Private diff --git a/panda/src/pgraph/sceneGraphReducer.h b/panda/src/pgraph/sceneGraphReducer.h index a07ac4ec32..b73a527a39 100644 --- a/panda/src/pgraph/sceneGraphReducer.h +++ b/panda/src/pgraph/sceneGraphReducer.h @@ -46,13 +46,14 @@ PUBLISHED: INLINE ~SceneGraphReducer(); enum AttribTypes { - TT_transform = 0x001, - TT_color = 0x002, - TT_color_scale = 0x004, - TT_tex_matrix = 0x008, - TT_clip_plane = 0x010, - TT_cull_face = 0x020, - TT_other = 0x040, + TT_transform = 0x001, + TT_color = 0x002, + TT_color_scale = 0x004, + TT_tex_matrix = 0x008, + TT_clip_plane = 0x010, + TT_cull_face = 0x020, + TT_apply_texture_color = 0x040, + TT_other = 0x080, }; enum CombineSiblings { @@ -126,7 +127,7 @@ PUBLISHED: INLINE void set_combine_radius(float combine_radius); INLINE float get_combine_radius() const; - INLINE void apply_attribs(PandaNode *node, int attrib_types = ~(TT_clip_plane | TT_cull_face)); + INLINE void apply_attribs(PandaNode *node, int attrib_types = ~(TT_clip_plane | TT_cull_face | TT_apply_texture_color)); INLINE void apply_attribs(PandaNode *node, const AccumulatedAttribs &attribs, int attrib_types, GeomTransformer &transformer); @@ -142,6 +143,7 @@ PUBLISHED: INLINE int collect_vertex_data(PandaNode *root, int collect_bits = ~0); INLINE int make_nonindexed(PandaNode *root, int nonindexed_bits = ~0); void unify(PandaNode *root, bool preserve_order); + void remove_unused_vertices(PandaNode *root); INLINE void premunge(PandaNode *root, const RenderState *initial_state); @@ -179,6 +181,7 @@ protected: GeomTransformer &transformer, bool format_only); int r_make_nonindexed(PandaNode *node, int collect_bits); void r_unify(PandaNode *node, int max_indices, bool preserve_order); + void r_register_vertices(PandaNode *node, GeomTransformer &transformer); void r_decompose(PandaNode *node); void r_premunge(PandaNode *node, const RenderState *state); @@ -195,6 +198,7 @@ private: static PStatCollector _collect_collector; static PStatCollector _make_nonindexed_collector; static PStatCollector _unify_collector; + static PStatCollector _remove_unused_collector; static PStatCollector _premunge_collector; };