Use apply_attribs() to doubleside or reverse triangles

This commit is contained in:
David Rose 2007-06-19 17:14:46 +00:00
parent 3a5e7bf33a
commit 3de6d5ac4f
8 changed files with 159 additions and 134 deletions

View File

@ -41,6 +41,7 @@ AccumulatedAttribs(const AccumulatedAttribs &copy) :
_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 &copy) {
_tex_matrix = copy._tex_matrix;
_texture = copy._texture;
_clip_plane = copy._clip_plane;
_cull_face = copy._cull_face;
_other = copy._other;
}

View File

@ -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();

View File

@ -52,6 +52,7 @@ public:
CPT(RenderAttrib) _tex_matrix;
CPT(RenderAttrib) _texture;
CPT(RenderAttrib) _clip_plane;
CPT(RenderAttrib) _cull_face;
CPT(RenderState) _other;
};

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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;