diff --git a/panda/src/pgraph/accumulatedAttribs.I b/panda/src/pgraph/accumulatedAttribs.I index 3e83fa4393..bb3c74bc62 100644 --- a/panda/src/pgraph/accumulatedAttribs.I +++ b/panda/src/pgraph/accumulatedAttribs.I @@ -41,6 +41,7 @@ AccumulatedAttribs(const AccumulatedAttribs ©) : _tex_matrix(copy._tex_matrix), _texture(copy._texture), _clip_plane(copy._clip_plane), + _cull_face(copy._cull_face), _other(copy._other) { } @@ -58,5 +59,6 @@ operator = (const AccumulatedAttribs ©) { _tex_matrix = copy._tex_matrix; _texture = copy._texture; _clip_plane = copy._clip_plane; + _cull_face = copy._cull_face; _other = copy._other; } diff --git a/panda/src/pgraph/accumulatedAttribs.cxx b/panda/src/pgraph/accumulatedAttribs.cxx index 9d783232ea..8b46f37118 100644 --- a/panda/src/pgraph/accumulatedAttribs.cxx +++ b/panda/src/pgraph/accumulatedAttribs.cxx @@ -24,6 +24,7 @@ #include "texMatrixAttrib.h" #include "textureAttrib.h" #include "clipPlaneAttrib.h" +#include "cullFaceAttrib.h" #include "config_pgraph.h" @@ -65,6 +66,13 @@ write(ostream &out, int attrib_types, int indent_level) const { _clip_plane->write(out, indent_level); } } + if ((attrib_types & SceneGraphReducer::TT_cull_face) != 0) { + if (_cull_face == (const RenderAttrib *)NULL) { + indent(out, indent_level) << "no cull face\n"; + } else { + _cull_face->write(out, indent_level); + } + } if ((attrib_types & SceneGraphReducer::TT_other) != 0) { _other->write(out, indent_level); } @@ -159,6 +167,20 @@ collect(PandaNode *node, int attrib_types) { } } + if ((attrib_types & SceneGraphReducer::TT_cull_face) != 0) { + const RenderAttrib *node_attrib = + node->get_attrib(CullFaceAttrib::get_class_type()); + if (node_attrib != (const RenderAttrib *)NULL) { + // The node has a cull face attribute; apply it. + if (_cull_face == (const RenderAttrib *)NULL) { + _cull_face = node_attrib; + } else { + _cull_face = _cull_face->compose(node_attrib); + } + node->clear_attrib(CullFaceAttrib::get_class_type()); + } + } + if ((attrib_types & SceneGraphReducer::TT_other) != 0) { // Collect everything else. nassertv(_other != (RenderState *)NULL); @@ -192,6 +214,13 @@ collect(PandaNode *node, int attrib_types) { collect_state = collect_state->remove_attrib(ClipPlaneAttrib::get_class_type()); keep_state = keep_state->add_attrib(attrib, override); } + + attrib = collect_state->get_attrib(CullFaceAttrib::get_class_type()); + if (attrib != (const RenderAttrib *)NULL) { + int override = collect_state->get_override(CullFaceAttrib::get_class_type()); + collect_state = collect_state->remove_attrib(CullFaceAttrib::get_class_type()); + keep_state = keep_state->add_attrib(attrib, override); + } _other = _other->compose(collect_state); node->set_state(keep_state); @@ -278,6 +307,19 @@ collect(const RenderState *state, int attrib_types) { } } + if ((attrib_types & SceneGraphReducer::TT_cull_face) != 0) { + const RenderAttrib *node_attrib = + new_state->get_attrib(CullFaceAttrib::get_class_type()); + if (node_attrib != (const RenderAttrib *)NULL) { + if (_cull_face == (const RenderAttrib *)NULL) { + _cull_face = node_attrib; + } else { + _cull_face = _cull_face->compose(node_attrib); + } + new_state = new_state->remove_attrib(CullFaceAttrib::get_class_type()); + } + } + if ((attrib_types & SceneGraphReducer::TT_other) != 0) { // Collect everything else. nassertr(_other != (RenderState *)NULL, new_state); @@ -357,6 +399,19 @@ apply_to_node(PandaNode *node, int attrib_types) { } } + if ((attrib_types & SceneGraphReducer::TT_cull_face) != 0) { + if (_cull_face != (RenderAttrib *)NULL) { + const RenderAttrib *node_attrib = + node->get_attrib(CullFaceAttrib::get_class_type()); + if (node_attrib != (RenderAttrib *)NULL) { + node->set_attrib(_cull_face->compose(node_attrib)); + } else { + node->set_attrib(_cull_face); + } + _cull_face = (RenderAttrib *)NULL; + } + } + if ((attrib_types & SceneGraphReducer::TT_other) != 0) { node->set_state(_other->compose(node->get_state())); _other = RenderState::make_empty(); diff --git a/panda/src/pgraph/accumulatedAttribs.h b/panda/src/pgraph/accumulatedAttribs.h index f37d628c35..04bd225e9b 100644 --- a/panda/src/pgraph/accumulatedAttribs.h +++ b/panda/src/pgraph/accumulatedAttribs.h @@ -52,6 +52,7 @@ public: CPT(RenderAttrib) _tex_matrix; CPT(RenderAttrib) _texture; CPT(RenderAttrib) _clip_plane; + CPT(RenderAttrib) _cull_face; CPT(RenderState) _other; }; diff --git a/panda/src/pgraph/geomNode.cxx b/panda/src/pgraph/geomNode.cxx index d378689d13..491d12a195 100644 --- a/panda/src/pgraph/geomNode.cxx +++ b/panda/src/pgraph/geomNode.cxx @@ -114,6 +114,27 @@ apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types, } } + if ((attrib_types & SceneGraphReducer::TT_cull_face) != 0) { + if (attribs._cull_face != (const RenderAttrib *)NULL) { + const CullFaceAttrib *cfa = DCAST(CullFaceAttrib, attribs._cull_face); + CullFaceAttrib::Mode mode = cfa->get_effective_mode(); + switch (mode) { + case CullFaceAttrib::M_cull_none: + // Doublesided polys. Duplicate them. + transformer.doubleside(this); + break; + + case CullFaceAttrib::M_cull_counter_clockwise: + // Reverse winding order. + transformer.reverse(this); + break; + + default: + break; + } + } + } + Thread *current_thread = Thread::get_current_thread(); OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { CDStageWriter cdata(_cycler, pipeline_stage, current_thread); diff --git a/panda/src/pgraph/geomTransformer.cxx b/panda/src/pgraph/geomTransformer.cxx index 72234f8395..28174294d1 100644 --- a/panda/src/pgraph/geomTransformer.cxx +++ b/panda/src/pgraph/geomTransformer.cxx @@ -499,6 +499,81 @@ reverse_normals(Geom *geom) { return true; } +//////////////////////////////////////////////////////////////////// +// Function: GeomTransformer::doubleside +// Access: Public +// Description: Duplicates triangles in this GeomNode so that each +// triangle is back-to-back with another triangle facing +// in the opposite direction. If the geometry has +// vertex normals, this will also duplicate and reverse +// the normals, so that lighting will work correctly +// from both sides. Note that calling this when the +// geometry is already doublesided (with back-to-back +// polygons) will result in multiple redundant coplanar +// polygons. +// +// Also see CullFaceAttrib, which can enable rendering +// of both sides of a triangle without having to +// duplicate it (but which doesn't necessarily work in +// the presence of lighting). +// +// Returns true if any Geoms are modified, false +// otherwise. +//////////////////////////////////////////////////////////////////// +bool GeomTransformer:: +doubleside(GeomNode *node) { + int num_geoms = node->get_num_geoms(); + for (int i = 0; i < num_geoms; ++i) { + CPT(Geom) orig_geom = node->get_geom(i); + bool has_normals = (orig_geom->get_vertex_data()->has_column(InternalName::get_normal())); + if (has_normals) { + // If the geometry has normals, we have to duplicate it to + // reverse the normals on the duplicate copy. + PT(Geom) new_geom = orig_geom->reverse(); + reverse_normals(new_geom); + node->add_geom(new_geom, node->get_geom_state(i)); + + } else { + // If there are no normals, we can just doubleside it in + // place. This is preferable because we can share vertices. + orig_geom.clear(); + node->modify_geom(i)->doubleside_in_place(); + } + } + + return (num_geoms != 0); +} + + +//////////////////////////////////////////////////////////////////// +// Function: GeomTransformer::reverse +// Access: Public +// Description: Reverses the winding order of triangles in this +// GeomNode so that each triangle is facing in the +// opposite direction. If the geometry has vertex +// normals, this will also reverse the normals, so that +// lighting will work correctly. +// +// Also see CullFaceAttrib, which can effectively change +// the facing of a triangle having to modify its +// vertices (but which doesn't necessarily work in the +// presence of lighting). +// +// Returns true if any Geoms are modified, false +// otherwise. +//////////////////////////////////////////////////////////////////// +bool GeomTransformer:: +reverse(GeomNode *node) { + int num_geoms = node->get_num_geoms(); + for (int i = 0; i < num_geoms; ++i) { + PT(Geom) geom = node->modify_geom(i); + geom->reverse_in_place(); + reverse_normals(geom); + } + + return (num_geoms != 0); +} + //////////////////////////////////////////////////////////////////// // Function: GeomTransformer::collect_vertex_data // Access: Public diff --git a/panda/src/pgraph/geomTransformer.h b/panda/src/pgraph/geomTransformer.h index 77cd1811b7..1c3f242a73 100644 --- a/panda/src/pgraph/geomTransformer.h +++ b/panda/src/pgraph/geomTransformer.h @@ -76,6 +76,8 @@ public: bool remove_column(GeomNode *node, const InternalName *column); bool reverse_normals(Geom *geom); + bool doubleside(GeomNode *node); + bool reverse(GeomNode *node); int collect_vertex_data(Geom *geom, int collect_bits); int collect_vertex_data(GeomNode *node, int collect_bits); diff --git a/panda/src/pgraph/sceneGraphReducer.cxx b/panda/src/pgraph/sceneGraphReducer.cxx index afa695556f..3205b1576b 100644 --- a/panda/src/pgraph/sceneGraphReducer.cxx +++ b/panda/src/pgraph/sceneGraphReducer.cxx @@ -29,8 +29,6 @@ PStatCollector SceneGraphReducer::_flatten_collector("*:Flatten:flatten"); PStatCollector SceneGraphReducer::_apply_collector("*:Flatten:apply"); PStatCollector SceneGraphReducer::_remove_column_collector("*:Flatten:remove column"); -PStatCollector SceneGraphReducer::_doubleside_collector("*:Flatten:doubleside"); -PStatCollector SceneGraphReducer::_reverse_collector("*:Flatten:reverse"); PStatCollector SceneGraphReducer::_collect_collector("*:Flatten:collect"); PStatCollector SceneGraphReducer::_make_nonindexed_collector("*:Flatten:make nonindexed"); PStatCollector SceneGraphReducer::_unify_collector("*:Flatten:unify"); @@ -145,52 +143,6 @@ remove_column(PandaNode *root, const InternalName *column) { return r_remove_column(root, column, _transformer); } -//////////////////////////////////////////////////////////////////// -// Function: SceneGraphReducer::doubleside -// Access: Published -// Description: Duplicates triangles in the GeomNodes at this level -// and below so that each triangle is back-to-back with -// another triangle facing in the opposite direction. -// If the geometry has vertex normals, this will also -// duplicate and reverse the normals, so that lighting -// will work correctly from both sides. Note that -// calling this when the geometry is already doublesided -// (with back-to-back polygons) will result in multiple -// redundant coplanar polygons. -// -// Also see CullFaceAttrib, which can enable rendering -// of both sides of a triangle without having to -// duplicate it (but which doesn't necessarily work in -// the presence of lighting). -// -// Returns the number of GeomNodes modified. -//////////////////////////////////////////////////////////////////// -int SceneGraphReducer:: -doubleside(PandaNode *root) { - PStatTimer timer(_doubleside_collector); - return r_doubleside(root, _transformer); -} - -//////////////////////////////////////////////////////////////////// -// Function: SceneGraphReducer::reverse -// Access: Published -// Description: Reverses the winding order in the GeomNodes at this -// level and below so that each triangle is facing in -// the opposite direction it was originally. If the -// geometry has vertex normals, the normals will be -// reversed as well. -// -// Also see CullFaceAttrib, which can change the visible -// direction of a triangle without having to duplicate -// it (but which doesn't necessarily work in the -// presence of lighting). -//////////////////////////////////////////////////////////////////// -int SceneGraphReducer:: -reverse(PandaNode *root) { - PStatTimer timer(_reverse_collector); - return r_reverse(root, _transformer); -} - //////////////////////////////////////////////////////////////////// // Function: SceneGraphReducer::unify // Access: Published @@ -763,84 +715,6 @@ r_remove_column(PandaNode *node, const InternalName *column, return num_changed; } -//////////////////////////////////////////////////////////////////// -// Function: SceneGraphReducer::r_doubleside -// Access: Private -// Description: The recursive implementation of doubleside(). -//////////////////////////////////////////////////////////////////// -int SceneGraphReducer:: -r_doubleside(PandaNode *node, GeomTransformer &transformer) { - int num_changed = 0; - - if (node->is_geom_node()) { - PT(GeomNode) gnode = DCAST(GeomNode, node); - int num_geoms = gnode->get_num_geoms(); - for (int i = 0; i < num_geoms; ++i) { - CPT(Geom) orig_geom = gnode->get_geom(i); - bool has_normals = (orig_geom->get_vertex_data()->has_column(InternalName::get_normal())); - if (has_normals) { - // If the geometry has normals, we have to duplicate it to - // reverse the normals on the duplicate copy. - PT(Geom) new_geom = orig_geom->reverse(); - transformer.reverse_normals(new_geom); - gnode->add_geom(new_geom, gnode->get_geom_state(i)); - - } else { - // If there are no normals, we can just doubleside it in - // place. This is preferable because we can share vertices. - orig_geom.clear(); - gnode->modify_geom(i)->doubleside_in_place(); - } - } - - if (num_geoms != 0) { - ++num_changed; - } - } - - PandaNode::Children children = node->get_children(); - int num_children = children.get_num_children(); - for (int i = 0; i < num_children; ++i) { - num_changed += - r_doubleside(children.get_child(i), transformer); - } - - return num_changed; -} - -//////////////////////////////////////////////////////////////////// -// Function: SceneGraphReducer::r_reverse -// Access: Private -// Description: The recursive implementation of reverse(). -//////////////////////////////////////////////////////////////////// -int SceneGraphReducer:: -r_reverse(PandaNode *node, GeomTransformer &transformer) { - int num_changed = 0; - - if (node->is_geom_node()) { - PT(GeomNode) gnode = DCAST(GeomNode, node); - int num_geoms = gnode->get_num_geoms(); - for (int i = 0; i < num_geoms; ++i) { - PT(Geom) geom = gnode->modify_geom(i); - geom->reverse_in_place(); - transformer.reverse_normals(geom); - } - - if (num_geoms != 0) { - ++num_changed; - } - } - - PandaNode::Children children = node->get_children(); - int num_children = children.get_num_children(); - for (int i = 0; i < num_children; ++i) { - num_changed += - r_reverse(children.get_child(i), transformer); - } - - return num_changed; -} - //////////////////////////////////////////////////////////////////// // Function: SceneGraphReducer::r_collect_vertex_data // Access: Private diff --git a/panda/src/pgraph/sceneGraphReducer.h b/panda/src/pgraph/sceneGraphReducer.h index 97540c526d..6a625fa06f 100644 --- a/panda/src/pgraph/sceneGraphReducer.h +++ b/panda/src/pgraph/sceneGraphReducer.h @@ -55,7 +55,8 @@ PUBLISHED: TT_color_scale = 0x004, TT_tex_matrix = 0x008, TT_clip_plane = 0x010, - TT_other = 0x020, + TT_cull_face = 0x020, + TT_other = 0x040, }; enum CombineSiblings { @@ -129,15 +130,13 @@ 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); + INLINE void apply_attribs(PandaNode *node, int attrib_types = ~(TT_clip_plane | TT_cull_face)); INLINE void apply_attribs(PandaNode *node, const AccumulatedAttribs &attribs, int attrib_types, GeomTransformer &transformer); int flatten(PandaNode *root, int combine_siblings_bits); int remove_column(PandaNode *root, const InternalName *column); - int doubleside(PandaNode *root); - int reverse(PandaNode *root); INLINE int collect_vertex_data(PandaNode *root, int collect_bits = ~0); INLINE int make_nonindexed(PandaNode *root, int nonindexed_bits = ~0); @@ -172,8 +171,6 @@ protected: int r_remove_column(PandaNode *node, const InternalName *column, GeomTransformer &transformer); - int r_doubleside(PandaNode *node, GeomTransformer &transformer); - int r_reverse(PandaNode *node, GeomTransformer &transformer); int r_collect_vertex_data(PandaNode *node, int collect_bits, GeomTransformer &transformer); @@ -190,8 +187,6 @@ private: static PStatCollector _flatten_collector; static PStatCollector _apply_collector; static PStatCollector _remove_column_collector; - static PStatCollector _doubleside_collector; - static PStatCollector _reverse_collector; static PStatCollector _collect_collector; static PStatCollector _make_nonindexed_collector; static PStatCollector _unify_collector;