better GeomTransformer, flatten operations

This commit is contained in:
David Rose 2004-12-21 00:12:09 +00:00
parent 293438f83e
commit c23be69d2b
12 changed files with 312 additions and 36 deletions

View File

@ -39,6 +39,7 @@ AccumulatedAttribs(const AccumulatedAttribs &copy) :
_color(copy._color),
_color_scale(copy._color_scale),
_tex_matrix(copy._tex_matrix),
_texture(copy._texture),
_other(copy._other)
{
}
@ -54,5 +55,6 @@ operator = (const AccumulatedAttribs &copy) {
_color = copy._color;
_color_scale = copy._color_scale;
_tex_matrix = copy._tex_matrix;
_texture = copy._texture;
_other = copy._other;
}

View File

@ -23,6 +23,7 @@
#include "colorAttrib.h"
#include "colorScaleAttrib.h"
#include "texMatrixAttrib.h"
#include "textureAttrib.h"
#include "config_pgraph.h"
@ -119,9 +120,25 @@ collect(PandaNode *node, int attrib_types) {
}
node->clear_attrib(TexMatrixAttrib::get_class_type());
}
// We also need to accumulate the texture state if we are
// accumulating texture matrix.
const RenderAttrib *tex_attrib =
node->get_attrib(TextureAttrib::get_class_type());
if (tex_attrib != (const RenderAttrib *)NULL) {
if (_texture == (const RenderAttrib *)NULL) {
_texture = tex_attrib;
} else {
_texture = _texture->compose(tex_attrib);
}
// However, we don't remove the texture state from the node.
// We're just accumulating it so we can tell which texture
// coordinates are safe to flatten.
}
}
if ((attrib_types & SceneGraphReducer::TT_transform) != 0) {
if ((attrib_types & SceneGraphReducer::TT_other) != 0) {
// Collect everything else.
nassertv(_other != (RenderState *)NULL);
_other = _other->compose(node->get_state());
@ -129,6 +146,83 @@ collect(PandaNode *node, int attrib_types) {
}
}
////////////////////////////////////////////////////////////////////
// Function: AccumulatedAttribs::collect
// Access: Public
// Description: Collects the state and transform from the indicated
// node and adds it to the accumulator, removing it from
// the state (and returning a new state).
////////////////////////////////////////////////////////////////////
CPT(RenderState) AccumulatedAttribs::
collect(const RenderState *state, int attrib_types) {
CPT(RenderState) new_state = state;
if ((attrib_types & SceneGraphReducer::TT_color) != 0) {
const RenderAttrib *node_attrib =
new_state->get_attrib(ColorAttrib::get_class_type());
if (node_attrib != (const RenderAttrib *)NULL) {
// The node has a color attribute; apply it.
if (_color == (const RenderAttrib *)NULL) {
_color = node_attrib;
} else {
_color = _color->compose(node_attrib);
}
new_state = new_state->remove_attrib(ColorAttrib::get_class_type());
}
}
if ((attrib_types & SceneGraphReducer::TT_color_scale) != 0) {
const RenderAttrib *node_attrib =
new_state->get_attrib(ColorScaleAttrib::get_class_type());
if (node_attrib != (const RenderAttrib *)NULL) {
if (_color_scale == (const RenderAttrib *)NULL) {
_color_scale = node_attrib;
} else {
_color_scale = _color_scale->compose(node_attrib);
}
new_state = new_state->remove_attrib(ColorScaleAttrib::get_class_type());
}
}
if ((attrib_types & SceneGraphReducer::TT_tex_matrix) != 0) {
const RenderAttrib *node_attrib =
new_state->get_attrib(TexMatrixAttrib::get_class_type());
if (node_attrib != (const RenderAttrib *)NULL) {
if (_tex_matrix == (const RenderAttrib *)NULL) {
_tex_matrix = node_attrib;
} else {
_tex_matrix = _tex_matrix->compose(node_attrib);
}
new_state = new_state->remove_attrib(TexMatrixAttrib::get_class_type());
}
// We also need to accumulate the texture state if we are
// accumulating texture matrix.
const RenderAttrib *tex_attrib =
new_state->get_attrib(TextureAttrib::get_class_type());
if (tex_attrib != (const RenderAttrib *)NULL) {
if (_texture == (const RenderAttrib *)NULL) {
_texture = tex_attrib;
} else {
_texture = _texture->compose(tex_attrib);
}
// However, we don't remove the texture state from the node.
// We're just accumulating it so we can tell which texture
// coordinates are safe to flatten.
}
}
if ((attrib_types & SceneGraphReducer::TT_other) != 0) {
// Collect everything else.
nassertr(_other != (RenderState *)NULL, new_state);
_other = _other->compose(new_state);
new_state = RenderState::make_empty();
}
return new_state;
}
////////////////////////////////////////////////////////////////////
// Function: AccumulatedAttribs::apply_to_node
// Access: Public

View File

@ -43,12 +43,14 @@ public:
void write(ostream &out, int attrib_types, int indent_level) const;
void collect(PandaNode *node, int attrib_types);
CPT(RenderState) collect(const RenderState *state, int attrib_types);
void apply_to_node(PandaNode *node, int attrib_types);
CPT(TransformState) _transform;
CPT(RenderAttrib) _color;
CPT(RenderAttrib) _color_scale;
CPT(RenderAttrib) _tex_matrix;
CPT(RenderAttrib) _texture;
CPT(RenderState) _other;
};

View File

@ -178,3 +178,32 @@ INLINE CollideMask GeomNode::
get_default_collide_mask() {
return default_geom_node_collide_mask;
}
////////////////////////////////////////////////////////////////////
// Function: GeomNode::count_name
// Access: Private
// Description: Increments the count for the indicated TexCoordName.
////////////////////////////////////////////////////////////////////
INLINE void GeomNode::
count_name(GeomNode::NameCount &name_count, const TexCoordName *name) {
pair<NameCount::iterator, bool> result =
name_count.insert(NameCount::value_type(name, 1));
if (!result.second) {
(*result.first).second++;
}
}
////////////////////////////////////////////////////////////////////
// Function: GeomNode::get_name_count
// Access: Private
// Description: Returns the count for the indicated TexCoordName.
////////////////////////////////////////////////////////////////////
INLINE int GeomNode::
get_name_count(const GeomNode::NameCount &name_count, const TexCoordName *name) {
NameCount::const_iterator ni;
ni = name_count.find(name);
if (ni != name_count.end()) {
return (*ni).second;
}
return 0;
}

View File

@ -188,33 +188,93 @@ apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types,
transformer.transform_vertices(this, attribs._transform->get_mat());
}
}
if ((attrib_types & SceneGraphReducer::TT_color) != 0) {
if (attribs._color != (const RenderAttrib *)NULL) {
const ColorAttrib *ca = DCAST(ColorAttrib, attribs._color);
if (ca->get_color_type() == ColorAttrib::T_flat) {
transformer.set_color(this, ca->get_color());
GeomNode::CDWriter cdata(_cycler);
GeomNode::Geoms::iterator gi;
for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) {
GeomEntry &entry = (*gi);
PT(Geom) new_geom = entry._geom->make_copy();
AccumulatedAttribs geom_attribs = attribs;
entry._state = geom_attribs.collect(entry._state, attrib_types);
bool any_changed = false;
if ((attrib_types & SceneGraphReducer::TT_color) != 0) {
if (geom_attribs._color != (const RenderAttrib *)NULL) {
const ColorAttrib *ca = DCAST(ColorAttrib, geom_attribs._color);
if (ca->get_color_type() == ColorAttrib::T_flat) {
if (transformer.set_color(new_geom, ca->get_color())) {
any_changed = true;
}
}
}
}
}
if ((attrib_types & SceneGraphReducer::TT_color_scale) != 0) {
if (attribs._color_scale != (const RenderAttrib *)NULL) {
const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attribs._color_scale);
if (csa->get_scale() != LVecBase4f(1.0f, 1.0f, 1.0f, 1.0f)) {
transformer.transform_colors(this, csa->get_scale());
if ((attrib_types & SceneGraphReducer::TT_color_scale) != 0) {
if (geom_attribs._color_scale != (const RenderAttrib *)NULL) {
const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, geom_attribs._color_scale);
if (csa->get_scale() != LVecBase4f(1.0f, 1.0f, 1.0f, 1.0f)) {
if (transformer.transform_colors(new_geom, csa->get_scale())) {
any_changed = true;
}
}
}
}
}
if ((attrib_types & SceneGraphReducer::TT_tex_matrix) != 0) {
if (attribs._tex_matrix != (const RenderAttrib *)NULL) {
const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attribs._tex_matrix);
if (tma->get_mat() != LMatrix4f::ident_mat()) {
transformer.transform_texcoords(this, tma->get_mat());
if ((attrib_types & SceneGraphReducer::TT_tex_matrix) != 0) {
if (geom_attribs._tex_matrix != (const RenderAttrib *)NULL) {
// Determine which texture coordinate names are used more than
// once. This assumes we have discovered all of the textures
// that are in effect on the geomNode; this may not be true if
// there is a texture that has been applied at a node above
// that from which we started the flatten operation, but
// caveat programmer.
NameCount name_count;
if (geom_attribs._texture != (RenderAttrib *)NULL) {
const TextureAttrib *ta = DCAST(TextureAttrib, geom_attribs._texture);
int num_on_stages = ta->get_num_on_stages();
for (int si = 0; si < num_on_stages; si++) {
TextureStage *stage = ta->get_on_stage(si);
const TexCoordName *name = stage->get_texcoord_name();
count_name(name_count, name);
}
}
const TexMatrixAttrib *tma =
DCAST(TexMatrixAttrib, geom_attribs._tex_matrix);
CPT(TexMatrixAttrib) new_tma = DCAST(TexMatrixAttrib, TexMatrixAttrib::make());
int num_stages = tma->get_num_stages();
for (int i = 0; i < num_stages; i++) {
TextureStage *stage = tma->get_stage(i);
const TexCoordName *name = stage->get_texcoord_name();
if (get_name_count(name_count, name) > 1) {
// We can't transform these texcoords, since the name is
// used by more than one active stage.
new_tma = DCAST(TexMatrixAttrib, new_tma->add_stage(stage, tma->get_transform(stage)));
} else {
// It's safe to transform these texcoords; the name is
// used by no more than one active stage.
if (transformer.transform_texcoords(new_geom, name, name, tma->get_mat(stage))) {
any_changed = true;
}
}
}
if (!new_tma->is_empty()) {
entry._state = entry._state->add_attrib(new_tma);
}
}
}
}
if ((attrib_types & SceneGraphReducer::TT_other) != 0) {
if (!attribs._other->is_empty()) {
transformer.apply_state(this, attribs._other);
if (any_changed) {
entry._geom = new_geom;
}
if ((attrib_types & SceneGraphReducer::TT_other) != 0) {
entry._state = geom_attribs._other->compose(entry._state);
}
}
}

View File

@ -92,6 +92,10 @@ public:
private:
typedef pvector<GeomEntry> Geoms;
typedef pmap<const TexCoordName *, int> NameCount;
INLINE void count_name(NameCount &name_count, const TexCoordName *name);
INLINE int get_name_count(const NameCount &name_count, const TexCoordName *name);
// This is the data that must be cycled between pipeline stages.
class EXPCL_PANDA CData : public CycleData {

View File

@ -150,18 +150,16 @@ transform_vertices(GeomNode *node, const LMatrix4f &mat) {
// Geom was changed, false otherwise.
////////////////////////////////////////////////////////////////////
bool GeomTransformer::
transform_texcoords(Geom *geom, const LMatrix4f &mat) {
transform_texcoords(Geom *geom, const TexCoordName *from_name,
const TexCoordName *to_name, const LMatrix4f &mat) {
bool transformed = false;
nassertr(geom != (Geom *)NULL, false);
PTA_TexCoordf texcoords;
GeomBindType bind;
PTA_ushort index;
PTA_TexCoordf texcoords = geom->get_texcoords_array(from_name);
PTA_ushort index = geom->get_texcoords_index(from_name);
geom->get_texcoords(texcoords, bind, index);
if (bind != G_OFF) {
if (!texcoords.is_null()) {
// Look up the Geom's texcoords in our table--have we already
// transformed this array?
SourceTexCoords stc;
@ -183,7 +181,7 @@ transform_texcoords(Geom *geom, const LMatrix4f &mat) {
nassertr(new_texcoords.size() == texcoords.size(), false);
}
geom->set_texcoords(new_texcoords, bind, index);
geom->set_texcoords(to_name, new_texcoords, index);
transformed = true;
}
@ -203,7 +201,8 @@ transform_texcoords(Geom *geom, const LMatrix4f &mat) {
// false otherwise.
////////////////////////////////////////////////////////////////////
bool GeomTransformer::
transform_texcoords(GeomNode *node, const LMatrix4f &mat) {
transform_texcoords(GeomNode *node, const TexCoordName *from_name,
const TexCoordName *to_name, const LMatrix4f &mat) {
bool any_changed = false;
GeomNode::CDWriter cdata(node->_cycler);
@ -211,7 +210,7 @@ transform_texcoords(GeomNode *node, const LMatrix4f &mat) {
for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) {
GeomNode::GeomEntry &entry = (*gi);
PT(Geom) new_geom = entry._geom->make_copy();
if (transform_texcoords(new_geom, mat)) {
if (transform_texcoords(new_geom, from_name, to_name, mat)) {
entry._geom = new_geom;
any_changed = true;
}

View File

@ -26,6 +26,7 @@
class GeomNode;
class RenderState;
class TexCoordName;
///////////////////////////////////////////////////////////////////
// Class : GeomTransformer
@ -51,8 +52,12 @@ public:
bool transform_vertices(Geom *geom, const LMatrix4f &mat);
bool transform_vertices(GeomNode *node, const LMatrix4f &mat);
bool transform_texcoords(Geom *geom, const LMatrix4f &mat);
bool transform_texcoords(GeomNode *node, const LMatrix4f &mat);
bool transform_texcoords(Geom *geom, const TexCoordName *from_name,
const TexCoordName *to_name,
const LMatrix4f &mat);
bool transform_texcoords(GeomNode *node, const TexCoordName *from_name,
const TexCoordName *to_name,
const LMatrix4f &mat);
bool set_color(Geom *geom, const Colorf &color);
bool set_color(GeomNode *node, const Colorf &color);

View File

@ -24,7 +24,7 @@
// TexMatrixAttrib object.
////////////////////////////////////////////////////////////////////
INLINE TexMatrixAttrib::
TexMatrixAttrib() {
TexMatrixAttrib() : _stage_list_stale(true) {
}
////////////////////////////////////////////////////////////////////
@ -35,6 +35,20 @@ TexMatrixAttrib() {
////////////////////////////////////////////////////////////////////
INLINE TexMatrixAttrib::
TexMatrixAttrib(const TexMatrixAttrib &copy) :
_stages(copy._stages)
_stages(copy._stages),
_stage_list_stale(true)
{
}
////////////////////////////////////////////////////////////////////
// Function: TexMatrixAttrib::check_stage_list
// Access: Private
// Description: Builds the linear list of TextureStages if it needs
// to be built.
////////////////////////////////////////////////////////////////////
void TexMatrixAttrib::
check_stage_list() const {
if (_stage_list_stale) {
((TexMatrixAttrib *)this)->rebuild_stage_list();
}
}

View File

@ -61,6 +61,9 @@ make() {
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) TexMatrixAttrib::
make(const LMatrix4f &mat) {
if (mat == LMatrix4f::ident_mat()) {
return make();
}
CPT(TransformState) transform = TransformState::make_mat(mat);
return make(TextureStage::get_default(), transform);
}
@ -73,6 +76,9 @@ make(const LMatrix4f &mat) {
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) TexMatrixAttrib::
make(const TransformState *transform) {
if (transform->is_identity()) {
return make();
}
return make(TextureStage::get_default(), transform);
}
@ -84,6 +90,9 @@ make(const TransformState *transform) {
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) TexMatrixAttrib::
make(TextureStage *stage, const TransformState *transform) {
if (transform->is_identity()) {
return make();
}
TexMatrixAttrib *attrib = new TexMatrixAttrib;
attrib->_stages.insert(Stages::value_type(stage, transform));
return return_new(attrib);
@ -98,6 +107,9 @@ make(TextureStage *stage, const TransformState *transform) {
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) TexMatrixAttrib::
add_stage(TextureStage *stage, const TransformState *transform) const {
if (transform->is_identity()) {
return remove_stage(stage);
}
TexMatrixAttrib *attrib = new TexMatrixAttrib(*this);
attrib->_stages[stage] = transform;
return return_new(attrib);
@ -152,6 +164,31 @@ has_stage(TextureStage *stage) const {
return (mi != _stages.end());
}
////////////////////////////////////////////////////////////////////
// Function: TexMatrixAttrib::get_num_stages
// Access: Published
// Description: Returns the number of stages that are represented by
// this attrib.
////////////////////////////////////////////////////////////////////
int TexMatrixAttrib::
get_num_stages() const {
return _stages.size();
}
////////////////////////////////////////////////////////////////////
// Function: TexMatrixAttrib::get_stage
// Access: Published
// Description: Returns the nth stage that is represented by this
// attrib. The TextureStages are in no particular
// order.
////////////////////////////////////////////////////////////////////
TextureStage *TexMatrixAttrib::
get_stage(int n) const {
nassertr(n >= 0 && n < (int)_stages.size(), NULL);
check_stage_list();
return _stage_list[n];
}
////////////////////////////////////////////////////////////////////
// Function: TexMatrixAttrib::get_mat
// Access: Published
@ -427,6 +464,25 @@ make_default_impl() const {
return new TexMatrixAttrib;
}
////////////////////////////////////////////////////////////////////
// Function: TexMatrixAttrib::rebuild_stage_list
// Access: Private
// Description: Builds the linear list of TextureStages, the first
// time someone asks for it.
////////////////////////////////////////////////////////////////////
void TexMatrixAttrib::
rebuild_stage_list() {
_stage_list.clear();
_stage_list.reserve(_stages.size());
Stages::const_iterator si;
for (si = _stages.begin(); si != _stages.end(); ++si) {
_stage_list.push_back((*si).first);
}
_stage_list_stale = false;
}
////////////////////////////////////////////////////////////////////
// Function: TexMatrixAttrib::register_with_read_factory
// Access: Public, Static

View File

@ -53,6 +53,9 @@ PUBLISHED:
bool is_empty() const;
bool has_stage(TextureStage *stage) const;
int get_num_stages() const;
TextureStage *get_stage(int n) const;
const LMatrix4f &get_mat() const;
const LMatrix4f &get_mat(TextureStage *stage) const;
@ -69,9 +72,16 @@ protected:
virtual RenderAttrib *make_default_impl() const;
private:
INLINE void check_stage_list() const;
void rebuild_stage_list();
typedef pmap< PT(TextureStage), CPT(TransformState) > Stages;
Stages _stages;
typedef pvector<TextureStage *> StageList;
StageList _stage_list;
bool _stage_list_stale;
// This element is only used during reading from a bam file. It has
// no meaningful value any other time.
size_t _num_stages;

View File

@ -114,6 +114,7 @@ event_0(CPT_Event event, void *) {
static PT(TextureStage) ts;
if (ts == (TextureStage *)NULL) {
ts = new TextureStage("ts");
ts->set_sort(50);
}
NodePath models = framework.get_models();