egg triagle fans

This commit is contained in:
David Rose 2005-03-23 15:32:35 +00:00
parent 18169d527e
commit 634a498588
19 changed files with 961 additions and 59 deletions

View File

@ -25,6 +25,7 @@
eggMaterialCollection.h \
eggMesher.h eggMesher.I \
eggMesherEdge.h eggMesherEdge.I \
eggMesherFanMaker.h eggMesherFanMaker.I \
eggMesherStrip.h eggMesherStrip.I \
eggMiscFuncs.I eggMiscFuncs.h \
eggMorph.I eggMorph.h eggMorphList.I eggMorphList.h \
@ -38,6 +39,7 @@
eggSAnimData.I eggSAnimData.h eggSurface.I eggSurface.h \
eggSwitchCondition.h eggTable.I eggTable.h eggTexture.I \
eggTexture.h eggTextureCollection.I eggTextureCollection.h \
eggTriangleFan.I eggTriangleFan.h \
eggTriangleStrip.I eggTriangleStrip.h \
eggTransform3d.I eggTransform3d.h \
eggUserData.I eggUserData.h \
@ -61,6 +63,7 @@
eggMaterialCollection.cxx \
eggMesher.cxx \
eggMesherEdge.cxx \
eggMesherFanMaker.cxx \
eggMesherStrip.cxx \
eggMiscFuncs.cxx eggMorphList.cxx \
eggNamedObject.cxx eggNameUniquifier.cxx eggNode.cxx \
@ -70,6 +73,7 @@
eggSAnimData.cxx eggSurface.cxx eggSwitchCondition.cxx \
eggTable.cxx eggTexture.cxx eggTextureCollection.cxx \
eggTransform3d.cxx \
eggTriangleFan.cxx \
eggTriangleStrip.cxx \
eggUserData.cxx \
eggUtilities.cxx eggVertex.cxx eggVertexPool.cxx eggVertexUV.cxx \
@ -101,6 +105,7 @@
eggSwitchCondition.h eggTable.I eggTable.h eggTexture.I \
eggTexture.h eggTextureCollection.I eggTextureCollection.h \
eggTransform3d.I eggTransform3d.h \
eggTriangleFan.I eggTriangleFan.h \
eggTriangleStrip.I eggTriangleStrip.h \
eggUserData.I eggUserData.h \
eggUtilities.I eggUtilities.h eggVertex.I eggVertex.h \

View File

@ -47,6 +47,7 @@
#include "eggSwitchCondition.h"
#include "eggTable.h"
#include "eggTexture.h"
#include "eggTriangleFan.h"
#include "eggTriangleStrip.h"
#include "eggUserData.h"
#include "eggVertex.h"
@ -75,27 +76,79 @@ ConfigVariableBool egg_support_old_anims
"had the convention that the order \"phr\" implied a reversed roll."));
ConfigVariableBool egg_mesh
("egg-mesh", true);
("egg-mesh", true,
PRC_DESC("Set this true to convert triangles and higher-order polygons "
"into triangle strips and triangle fans when an egg file is "
"loaded or converted to bam. Set this false just to triangulate "
"everything into independent triangles."));
ConfigVariableBool egg_retesselate_coplanar
("egg-retesselate-coplanar", true);
("egg-retesselate-coplanar", true,
PRC_DESC("If this is true, the egg loader may reverse the "
"tesselation direction of a single pair of planar triangles that "
"share the same properties, if that will help get a better "
"triangle strip. In some rare cases, doing so can distort the "
"UV's on a face; turning this off should eliminate that artifact "
"(at the cost of less-effective triangle stripping)."));
ConfigVariableBool egg_unroll_fans
("egg-unroll-fans", true);
("egg-unroll-fans", true,
PRC_DESC("Set this true to allow the egg loader to convert weak triangle "
"fans--triangles that share the same vertex but aren't "
"connected enough to justify making a triangle fan primitive "
"from them--into a series of zig-zag triangles that can make "
"a triangle strip that might connect better with its neighbors."));
ConfigVariableBool egg_show_tstrips
("egg-show-tstrips", false);
("egg-show-tstrips", false,
PRC_DESC("Set this true to color each triangle strip a random color, with "
"the leading triangle a little bit darker, so you can visually "
"observe the quality of the triangle stripping algorithm."));
ConfigVariableBool egg_show_qsheets
("egg-show-qsheets", false);
("egg-show-qsheets", false,
PRC_DESC("Set this true to color each quadsheet a random color, so you "
"can visually observe the quadsheet algorithm."));
ConfigVariableBool egg_show_quads
("egg-show-quads", false);
("egg-show-quads", false,
PRC_DESC("Set this true to color each detected quad a random color, so "
"you can visually observe the algorithm that unifies pairs of "
"triangles into quads (prior to generating triangle strips)."));
ConfigVariableBool egg_subdivide_polys
("egg-subdivide-polys", true);
("egg-subdivide-polys", true,
PRC_DESC("This is obsolete. In the old Geom implementation, it used to "
"be true to force higher-order polygons that were not otherwise "
"meshed to be subdivided into triangles. In the new experimental "
"Geom implementation, this happens anyway."));
ConfigVariableBool egg_consider_fans
("egg-consider-fans", true);
("egg-consider-fans", true,
PRC_DESC("Set this true to enable the egg mesher to consider making "
"triangle fans out of triangles that are connected at a common "
"vertex. This may help if your scene involves lots of such "
"connected triangles, but it can also make the overall stripping "
"less effective (by interfering with triangle strips)."));
ConfigVariableDouble egg_max_tfan_angle
("egg-max-tfan-angle", 40.0);
("egg-max-tfan-angle", 40.0,
PRC_DESC("The maximum average angle per triangle to allow in a triangle "
"fan. If triangles are larger than this--that is, more loosely "
"packed--then we figure a triangle strip is likely to do a "
"more effective job than a triangle fan, and the fan maker leaves "
"it alone."));
ConfigVariableInt egg_min_tfan_tris
("egg-min-tfan-tris", 4);
("egg-min-tfan-tris", 4,
PRC_DESC("The minimum number of triangles that must be involved in order "
"to generate a triangle fan. Fewer than this is just interrupting "
"a triangle strip."));
ConfigVariableDouble egg_coplanar_threshold
("egg-coplanar-threshold", 0.01);
("egg-coplanar-threshold", 0.01,
PRC_DESC("The numerical threshold below which polygons are considered "
"to be coplanar. Determined empirically."));
////////////////////////////////////////////////////////////////////
// Function: init_libegg
@ -145,6 +198,7 @@ init_libegg() {
EggSwitchConditionDistance::init_type();
EggTable::init_type();
EggTexture::init_type();
EggTriangleFan::init_type();
EggTriangleStrip::init_type();
EggUserData::init_type();
EggVertex::init_type();

View File

@ -157,15 +157,32 @@ unify_attributes(EggPrimitive::Shading shading) {
shading = get_shading();
}
// Not having a color is implicitly white.
if (!has_color() && shading != S_overall) {
set_color(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
}
switch (shading) {
case S_per_vertex:
// Propagate everything to the vertices.
{
Components::iterator ci;
for (ci = _components.begin(); ci != _components.end(); ++ci) {
EggAttributes *component = (*ci);
if (component->has_normal()) {
if (!has_normal()) {
copy_normal(*component);
}
component->clear_normal();
}
if (component->has_color()) {
if (!has_color()) {
copy_color(*component);
}
component->clear_color();
}
}
// Not having a color is implicitly white.
if (!has_color()) {
set_color(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
}
iterator pi;
for (pi = begin(); pi != end(); ++pi) {
EggVertex *orig_vertex = (*pi);
@ -182,11 +199,6 @@ unify_attributes(EggPrimitive::Shading shading) {
vertex = vertex_pool->create_unique_vertex(*vertex);
replace(pi, vertex);
}
Components::iterator ci;
for (ci = _components.begin(); ci != _components.end(); ++ci) {
(*ci)->clear_normal();
(*ci)->clear_color();
}
clear_normal();
clear_color();
}
@ -195,20 +207,17 @@ unify_attributes(EggPrimitive::Shading shading) {
case S_per_face:
// Propagate everything to the components.
{
Components::iterator ci;
for (ci = _components.begin(); ci != _components.end(); ++ci) {
EggAttributes *component = (*ci);
if (!component->has_normal() && has_normal()) {
component->copy_normal(*this);
}
if (!component->has_color() && has_color()) {
component->copy_color(*this);
}
}
iterator pi;
for (pi = begin(); pi != end(); ++pi) {
EggVertex *orig_vertex = (*pi);
if (orig_vertex->has_normal() || orig_vertex->has_color()) {
if (orig_vertex->has_normal() && !has_normal()) {
copy_normal(*orig_vertex);
}
if (orig_vertex->has_color() && !has_color()) {
copy_color(*orig_vertex);
}
PT(EggVertex) vertex = new EggVertex(*orig_vertex);
vertex->clear_normal();
vertex->clear_color();
@ -219,6 +228,22 @@ unify_attributes(EggPrimitive::Shading shading) {
replace(pi, vertex);
}
}
// Not having a color is implicitly white.
if (!has_color()) {
set_color(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
}
Components::iterator ci;
for (ci = _components.begin(); ci != _components.end(); ++ci) {
EggAttributes *component = (*ci);
if (!component->has_normal() && has_normal()) {
component->copy_normal(*this);
}
if (!component->has_color() && has_color()) {
component->copy_color(*this);
}
}
clear_normal();
clear_color();
}
@ -259,16 +284,17 @@ unify_attributes(EggPrimitive::Shading shading) {
component->clear_color();
}
}
// Not having a color is implicitly white.
if (!has_color()) {
set_color(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
}
}
break;
case S_unknown:
break;
}
if (!has_color() && shading == S_overall) {
set_color(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
}
}
////////////////////////////////////////////////////////////////////

View File

@ -17,6 +17,7 @@
////////////////////////////////////////////////////////////////////
#include "eggMesher.h"
#include "eggMesherFanMaker.h"
#include "eggPolygon.h"
#include "eggCompositePrimitive.h"
#include "eggTriangleStrip.h"
@ -80,7 +81,7 @@ mesh(EggGroupNode *group) {
add_polygon(poly, EggMesherStrip::MO_user);
} else {
// A different vertex pool; save this one for next pass.
// A different vertex pool; save this one for the next pass.
next_children->add_child(poly);
}
@ -320,8 +321,8 @@ get_prim(EggMesherStrip &strip) {
Colorf color1, color2;
if (egg_prim->is_of_type(EggTriangleStrip::get_class_type()) /*||
egg_prim->is_of_type(EggTriangleFan::get_class_type())*/) {
if (egg_prim->is_of_type(EggTriangleStrip::get_class_type()) ||
egg_prim->is_of_type(EggTriangleFan::get_class_type())) {
make_random_color(color2);
color1 = (color2 * 0.8); // somewhat darker.
@ -621,8 +622,7 @@ build_sheets() {
////////////////////////////////////////////////////////////////////
void EggMesher::
find_fans() {
#if 0
pvector<Prim> unrolled_tris;
PT(EggGroupNode) unrolled_tris = new EggGroup;
// Consider all vertices. Any vertex with over a certain number of
// edges connected to it is eligible to become a fan.
@ -639,22 +639,21 @@ find_fans() {
// the quadsheets anyway. We bump this up to 14 because some
// quadsheets are defined with triangles flipped here and there.
if (edges.size() > 6) {
const Vertex &v = (*vi).first;
int v = (*vi).first;
// Build up a list of far fan edges.
typedef pvector<FanMaker> FanMakers;
typedef pvector<EggMesherFanMaker> FanMakers;
FanMakers fans;
EdgePtrs::iterator ei;
Edge::Strips::iterator si;
EggMesherEdge::Strips::iterator si;
for (ei = edges.begin(); ei != edges.end(); ++ei) {
for (si = (*ei)->_strips.begin();
si != (*ei)->_strips.end();
++si) {
EggMesherStrip *strip = *si;
if (strip->_type == EggMesherStrip::PT_tri) {
FanMaker fan(&v, strip, this);
EggMesherFanMaker fan(v, strip, this);
if (!fan._edges.empty()) {
fans.push_back(fan);
}
@ -670,7 +669,7 @@ find_fans() {
FanMakers::iterator fi, fi2;
// Now pull out connected edges.
int joined_any;
bool joined_any;
do {
joined_any = false;
for (fi = fans.begin(); fi != fans.end(); ++fi) {
@ -698,11 +697,10 @@ find_fans() {
// until we're done traversing all the vertices and primitives we
// had in the first place (since adding them will affect the edge
// lists).
pvector<Prim>::iterator ti;
for (ti = unrolled_tris.begin(); ti != unrolled_tris.end(); ++ti) {
add_prim(*ti);
EggGroupNode::iterator ti;
for (ti = unrolled_tris->begin(); ti != unrolled_tris->end(); ++ti) {
add_polygon(DCAST(EggPolygon, (*ti)), EggMesherStrip::MO_fanpoly);
}
#endif
}
////////////////////////////////////////////////////////////////////

View File

@ -22,7 +22,6 @@
#include "pandabase.h"
#include "eggMesherEdge.h"
#include "eggMesherStrip.h"
//#include "eggMesherFanMaker.h"
#include "eggPolygon.h"
#include "pvector.h"
#include "plist.h"
@ -31,8 +30,6 @@
#include <algorithm>
class MesherFanMaker;
///////////////////////////////////////////////////////////////////
// Class : EggMesher
// Description : Collects together unrelated EggPrimitives, determines

View File

@ -0,0 +1,93 @@
// Filename: eggMesherFanMaker.I
// Created by: drose (22Mar05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: EggMesherFanMaker::operator <
// Access: Public
// Description: Provides a unique ordering between different fan
// makers based on the leading edge.
////////////////////////////////////////////////////////////////////
INLINE bool EggMesherFanMaker::
operator < (const EggMesherFanMaker &other) const {
nassertr(!_edges.empty() && !other._edges.empty(), false);
return _edges.front() < other._edges.front();
}
////////////////////////////////////////////////////////////////////
// Function: EggMesherFanMaker::operator !=
// Access: Public
// Description: Provides a unique ordering between different fan
// makers based on the leading edge.
////////////////////////////////////////////////////////////////////
INLINE bool EggMesherFanMaker::
operator != (const EggMesherFanMaker &other) const {
return !operator == (other);
}
////////////////////////////////////////////////////////////////////
// Function: EggMesherFanMaker::operator ==
// Access: Public
// Description: Provides a unique ordering between different fan
// makers based on the leading edge.
////////////////////////////////////////////////////////////////////
INLINE bool EggMesherFanMaker::
operator == (const EggMesherFanMaker &other) const {
return _edges.front() == other._edges.front();
}
////////////////////////////////////////////////////////////////////
// Function: EggMesherFanMaker::is_empty
// Access: Public
// Description: Returns true if the fan maker has no edges, false
// otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool EggMesherFanMaker::
is_empty() const {
return (_edges.empty());
}
////////////////////////////////////////////////////////////////////
// Function: EggMesherFanMaker::is_valid
// Access: Public
// Description: Returns true if the fan maker has enough edges to
// define at least one fan, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool EggMesherFanMaker::
is_valid() const {
return (_edges.size() > 2);
}
////////////////////////////////////////////////////////////////////
// Function: EggMesherFanMaker::is_coplanar_with
// Access: Public
// Description: Returns true if the strip and the other strip are
// coplanar.
////////////////////////////////////////////////////////////////////
INLINE bool EggMesherFanMaker::
is_coplanar_with(const EggMesherFanMaker &other) const {
return _planar && other._planar &&
_strips.front()->is_coplanar_with(*other._strips.front(),
egg_coplanar_threshold);
}
INLINE ostream &
operator << (ostream &out, const EggMesherFanMaker &fm) {
fm.output(out);
return out;
}

View File

@ -0,0 +1,371 @@
// Filename: eggMesherFanMaker.cxx
// Created by: drose (22Mar05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "eggMesherFanMaker.h"
////////////////////////////////////////////////////////////////////
// Function: EggMesherFanMaker::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
EggMesherFanMaker::
EggMesherFanMaker(int vertex, EggMesherStrip *tri,
EggMesher *mesher) {
_vertex = vertex;
const EggMesherEdge *edge = tri->find_opposite_edge(vertex);
if (edge != (const EggMesherEdge *)NULL) {
_edges.push_back(edge);
}
_strips.push_back(tri);
_planar = tri->_planar;
_mesher = mesher;
}
////////////////////////////////////////////////////////////////////
// Function: EggMesherFanMaker::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
EggMesherFanMaker::
EggMesherFanMaker(const EggMesherFanMaker &copy) :
_vertex(copy._vertex),
_edges(copy._edges),
_strips(copy._strips),
_planar(copy._planar),
_mesher(copy._mesher)
{
}
////////////////////////////////////////////////////////////////////
// Function: EggMesherFanMaker::Copy Assignment Operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void EggMesherFanMaker::
operator = (const EggMesherFanMaker &copy) {
_vertex = copy._vertex;
_edges = copy._edges;
_strips = copy._strips;
_planar = copy._planar;
_mesher = copy._mesher;
}
////////////////////////////////////////////////////////////////////
// Function: EggMesherFanMaker::join
// Access: Public
// Description: Attempts to connect two fans end-to-end. They must
// both share the same common vertex and a common edge.
//
// The return value is true if the fans were
// successfully joined, or false if they could not be.
////////////////////////////////////////////////////////////////////
bool EggMesherFanMaker::
join(EggMesherFanMaker &other) {
nassertr(_vertex == other._vertex, false);
nassertr(_mesher == other._mesher, false);
nassertr(!_edges.empty() && !other._edges.empty(), false);
const EggMesherEdge *my_back = _edges.back();
const EggMesherEdge *other_front = other._edges.front();
nassertr(my_back != (EggMesherEdge *)NULL &&
other_front != (EggMesherEdge *)NULL, false);
int my_back_b = my_back->_vi_b;
int other_front_a = other_front->_vi_a;
if (my_back_b == other_front_a) {
_planar = is_coplanar_with(other);
_edges.splice(_edges.end(), other._edges);
_strips.splice(_strips.end(), other._strips);
return true;
}
const EggMesherEdge *my_front = _edges.front();
const EggMesherEdge *other_back = other._edges.back();
nassertr(my_front != (EggMesherEdge *)NULL &&
other_back != (EggMesherEdge *)NULL, false);
int my_front_a = my_front->_vi_a;
int other_back_b = other_back->_vi_b;
if (my_front_a == other_back_b) {
_planar = is_coplanar_with(other);
_edges.splice(_edges.begin(), other._edges);
_strips.splice(_strips.begin(), other._strips);
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: EggMesherFanMaker::compute_angle
// Access: Public
// Description: Returns the overall angle subtended by the fan, from
// the leading edge to the trailing edge, in degrees.
////////////////////////////////////////////////////////////////////
double EggMesherFanMaker::
compute_angle() const {
// We sum up the angles of each triangle. This is more correct than
// taking the net angle from the first edge to the last (since we
// may not be in a plane).
nassertr(is_valid(), 0.0);
EggVertexPool *vertex_pool = _mesher->_vertex_pool;
double angle = 0.0;
LPoint3d v0 = vertex_pool->get_vertex(_vertex)->get_pos3();
Edges::const_iterator ei;
for (ei = _edges.begin(); ei != _edges.end(); ++ei) {
LVector3d v1 = vertex_pool->get_vertex((*ei)->_vi_a)->get_pos3() - v0;
LVector3d v2 = vertex_pool->get_vertex((*ei)->_vi_b)->get_pos3() - v0;
v1 = normalize(v1);
v2 = normalize(v2);
angle += acos(dot(v1, v2));
}
return rad_2_deg(angle);
}
////////////////////////////////////////////////////////////////////
// Function: EggMesherFanMaker::build
// Access: Public
// Description: Begins the fanning process. Searches for triangles
// and connects them into a fan.
//
// In certain cases, if egg_unroll_fans is enabled, the
// resulting fan may be retesselated into a series of
// zig-zag triangles, which are stored in unrolled_tris.
// Otherwise, an EggMesherStrip (representing the fan)
// is created and added to the mesher.
//
// The return value is (loosely) the number of
// primitives created.
////////////////////////////////////////////////////////////////////
int EggMesherFanMaker::
build(EggGroupNode *unrolled_tris) {
nassertr(_edges.size() == _strips.size(), 0);
int num_tris = _edges.size();
double net_angle = compute_angle();
double avg_angle = net_angle / (double)num_tris;
if (avg_angle > egg_max_tfan_angle) {
// The triangles are too loose to justify making a fan; it'll
// probably make a better quadsheet.
return 0;
}
if (egg_min_tfan_tris == 0 || num_tris < egg_min_tfan_tris) {
// Oops, not enough triangles to justify a fan.
if (!egg_unroll_fans) {
return 0;
}
// However, we could (maybe) make it a few tristrips!
// Each section of the fan which is made up of coplanar tris, with
// identical properties, may be retesselated into a tristrip.
// What a sneaky trick! To do this, we must first identify each
// such qualifying section.
// We define a seam as the edge between any two tris which are
// noncoplanar or have different properties. Then we can send
// each piece between the seams to unroll().
Strips::iterator si, last_si;
Edges::iterator ei, last_ei;
// First, rotate the fan so it begins at a seam. We do this so we
// won't be left out with part of one piece at the beginning and
// also at the end.
si = _strips.begin();
last_si = si;
ei = _edges.begin();
last_ei = ei;
int found_seam = false;
for (++si, ++ei; si != _strips.end() && !found_seam; ++si, ++ei) {
nassertr(ei != _edges.end(), 0);
if ( ((*si)->_prims.front()->compare_to(*(*last_si)->_prims.front()) != 0) ||
!(*si)->is_coplanar_with(*(*last_si), egg_coplanar_threshold)) {
// Here's a seam. Break the fan here.
found_seam = true;
_edges.splice(_edges.begin(), _edges, ei, _edges.end());
_strips.splice(_strips.begin(), _strips, si, _strips.end());
}
}
// Now break the fan up along its seams and unroll each piece
// separately.
si = _strips.begin();
last_si = si;
ei = _edges.begin();
last_ei = ei;
int count = 0;
for (++si, ++ei; si != _strips.end(); ++si, ++ei) {
nassertr(ei != _edges.end(), 0);
if ( ((*si)->_prims.front()->compare_to(*(*last_si)->_prims.front()) != 0) ||
!(*si)->is_coplanar_with(*(*last_si), egg_coplanar_threshold)) {
// Here's the end of a run of matching pieces.
count += unroll(last_si, si, last_ei, ei, unrolled_tris);
last_si = si;
last_ei = ei;
}
}
count += unroll(last_si, si, last_ei, ei, unrolled_tris);
return count;
} else {
EggMesherStrip new_fan;
new_fan._type = EggMesherStrip::PT_trifan;
new_fan._origin = EggMesherStrip::MO_fanpoly;
new_fan._verts.push_back(_vertex);
new_fan._verts.push_back(_edges.front()->_vi_a);
Edges::iterator ei;
for (ei = _edges.begin(); ei != _edges.end(); ++ei) {
new_fan._verts.push_back((*ei)->_vi_b);
}
Strips::iterator si;
for (si = _strips.begin(); si != _strips.end(); ++si) {
new_fan._prims.splice(new_fan._prims.end(), (*si)->_prims);
(*si)->remove_all_edges();
(*si)->_verts.clear();
(*si)->_status = EggMesherStrip::MS_dead;
}
// If we'd built our list of edges and strips right, this sum should
// come out so that there are two more vertices than triangles in
// the new fan.
nassertr(new_fan._verts.size() == new_fan._prims.size() + 2, 0);
// Now we've built a fan, and it won't be able to mate with
// anything else, so add it to the done list.
_mesher->_done.push_back(new_fan);
}
return 1;
}
////////////////////////////////////////////////////////////////////
// Function: EggMesherFanMaker::unroll
// Access: Public
// Description: Unrolls a planar subset of the current working fan,
// defined by the given iterators, into a series of
// triangles that zig-zag back and forth for better
// tristripping properties. The new triangles are added
// to unrolled_tris; the return value is 1 if
// successful, or 0 otherwise.
////////////////////////////////////////////////////////////////////
int EggMesherFanMaker::
unroll(Strips::iterator strip_begin, Strips::iterator strip_end,
Edges::iterator edge_begin, Edges::iterator edge_end,
EggGroupNode *unrolled_tris) {
Edges::iterator ei;
Strips::iterator si;
int num_tris = 0;
for (ei = edge_begin; ei != edge_end; ++ei) {
num_tris++;
}
if (num_tris < 3) {
// Don't even bother.
return 0;
}
PT(EggPolygon) poly = new EggPolygon;
// Now we build an n-sided polygon the same shape as the fan. We'll
// decompose it into tris in a second.
poly->copy_attributes(*(*strip_begin)->_prims.front());
EggVertexPool *vertex_pool = _mesher->_vertex_pool;
ei = edge_end;
--ei;
if ((*ei)->_vi_b != (*edge_begin)->_vi_a) {
// If the fan is less than a full circle, we need to keep the
// hub vertex and initial vertex in the poly. Otherwise, we'll
// discard them.
poly->add_vertex(vertex_pool->get_vertex(_vertex));
poly->add_vertex(vertex_pool->get_vertex((*edge_begin)->_vi_a));
}
for (ei = edge_begin; ei != edge_end; ++ei) {
poly->add_vertex(vertex_pool->get_vertex((*ei)->_vi_b));
}
bool result = true;
if (egg_show_quads) {
// If we're showing quads, also show retesselated triangles.
// We can't add it directly to the mesher, that's unsafe; instead,
// we'll just add it to the end of the unrolled_tris list. This
// does mean we won't be able to color it a fancy color, but too
// bad.
//_mesher->add_polygon(poly, EggMesherStrip::MO_fanpoly);
unrolled_tris->add_child(poly);
} else {
// Now decompose the new polygon into triangles.
result = poly->triangulate_into(unrolled_tris, true);
}
if (result) {
// Now that we've created a new poly, kill off all the old ones.
for (si = strip_begin; si != strip_end; ++si) {
(*si)->remove_all_edges();
(*si)->_verts.clear();
(*si)->_prims.clear();
(*si)->_status = EggMesherStrip::MS_dead;
}
return 1;
} else {
return 0;
}
}
////////////////////////////////////////////////////////////////////
// Function: EggMesherFanMaker::output
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void EggMesherFanMaker::
output(ostream &out) const {
out << _vertex << ":[";
if (!_edges.empty()) {
Edges::const_iterator ei;
for (ei = _edges.begin(); ei != _edges.end(); ++ei) {
out << " " << (*ei)->_vi_a;
}
out << " " << _edges.back()->_vi_b;
}
out << " ]";
if (_planar) {
out << " (planar)";
}
}

View File

@ -0,0 +1,80 @@
// Filename: eggMesherFanMaker.h
// Created by: drose (22Mar05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef EGGMESHERFANMAKER_H
#define EGGMESHERFANMAKER_H
#include "pandabase.h"
#include "eggMesherEdge.h"
#include "eggMesherStrip.h"
#include "plist.h"
#include "pvector.h"
#include "notify.h"
#include "mathNumbers.h"
class EggMesher;
///////////////////////////////////////////////////////////////////
// Class : EggMesherFanMaker
// Description : This class is used by EggMesher::find_fans() to
// attempt to make an EggTriangleFan out of the polygons
// connected to the indicated vertex.
////////////////////////////////////////////////////////////////////
class EggMesherFanMaker {
public:
typedef plist<const EggMesherEdge *> Edges;
typedef plist<EggMesherStrip *> Strips;
EggMesherFanMaker(int vertex, EggMesherStrip *tri,
EggMesher *mesher);
EggMesherFanMaker(const EggMesherFanMaker &copy);
void operator = (const EggMesherFanMaker &copy);
INLINE bool operator < (const EggMesherFanMaker &other) const;
INLINE bool operator != (const EggMesherFanMaker &other) const;
INLINE bool operator == (const EggMesherFanMaker &other) const;
INLINE bool is_empty() const;
INLINE bool is_valid() const;
INLINE bool is_coplanar_with(const EggMesherFanMaker &other) const;
bool join(EggMesherFanMaker &other);
double compute_angle() const;
int build(EggGroupNode *unrolled_tris);
int unroll(Strips::iterator strip_begin, Strips::iterator strip_end,
Edges::iterator edge_begin, Edges::iterator edge_end,
EggGroupNode *unrolled_tris);
void output(ostream &out) const;
int _vertex;
Edges _edges;
Strips _strips;
bool _planar;
EggMesher *_mesher;
};
INLINE ostream &operator << (ostream &out, const EggMesherFanMaker &fm);
#include "eggMesherFanMaker.I"
#endif

View File

@ -19,6 +19,7 @@
#include "eggMesherStrip.h"
#include "eggMesherEdge.h"
#include "eggPrimitive.h"
#include "eggTriangleFan.h"
#include "eggTriangleStrip.h"
#include "eggPolygon.h"
#include "dcast.h"
@ -115,7 +116,11 @@ make_prim(const EggVertexPool *vertex_pool) {
} else {
// The harder case: a tristrip of some kind.
convert_to_type(dest_type);
prim = new EggTriangleStrip;
if (dest_type == PT_trifan) {
prim = new EggTriangleFan;
} else {
prim = new EggTriangleStrip;
}
prim->copy_attributes(*_prims.front());
// Now store all the vertices. Each individual triangle's

View File

@ -142,7 +142,7 @@ public:
int _index;
MesherStatus _status;
int _planar;
bool _planar;
Normald _plane_normal;
float _plane_offset;
int _row_id, _row_distance;

View File

@ -0,0 +1,47 @@
// Filename: eggTriangleFan.I
// Created by: drose (23Mar05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: EggTriangleFan::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE EggTriangleFan::
EggTriangleFan(const string &name) : EggCompositePrimitive(name) {
}
////////////////////////////////////////////////////////////////////
// Function: EggTriangleFan::Copy constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE EggTriangleFan::
EggTriangleFan(const EggTriangleFan &copy) : EggCompositePrimitive(copy) {
}
////////////////////////////////////////////////////////////////////
// Function: EggTriangleFan::Copy assignment operator
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE EggTriangleFan &EggTriangleFan::
operator = (const EggTriangleFan &copy) {
EggCompositePrimitive::operator = (copy);
return *this;
}

View File

@ -0,0 +1,133 @@
// Filename: eggTriangleFan.cxx
// Created by: drose (23Mar05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "eggTriangleFan.h"
#include "eggGroupNode.h"
#include "eggPolygon.h"
#include "indent.h"
TypeHandle EggTriangleFan::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: EggTriangleFan::Destructor
// Access: Published, Virtual
// Description:
////////////////////////////////////////////////////////////////////
EggTriangleFan::
~EggTriangleFan() {
clear();
}
////////////////////////////////////////////////////////////////////
// Function: EggTriangleFan::write
// Access: Published, Virtual
// Description: Writes the triangle fan to the indicated output
// stream in Egg format.
////////////////////////////////////////////////////////////////////
void EggTriangleFan::
write(ostream &out, int indent_level) const {
write_header(out, indent_level, "<TriangleFan>");
write_body(out, indent_level+2);
indent(out, indent_level) << "}\n";
}
////////////////////////////////////////////////////////////////////
// Function: EggTriangleFan::apply_first_attribute
// Access: Published, Virtual
// Description: Sets the first vertex of the triangle (or each
// component) to the primitive normal and/or color, if
// the primitive is flat-shaded. This reflects the
// DirectX convention of storing flat-shaded properties
// on the first vertex, although it is not usually a
// convention in Egg.
//
// This may introduce redundant vertices to the vertex
// pool.
////////////////////////////////////////////////////////////////////
void EggTriangleFan::
apply_first_attribute() {
// In the case of a triangle fan, the first vertex of the fan is the
// common vertex, so we consider the second vertex to be the key
// vertex of the first triangle, and move from there.
for (int i = 0; i < get_num_components(); i++) {
EggAttributes *component = get_component(i);
do_apply_flat_attribute(i + 1, component);
}
}
////////////////////////////////////////////////////////////////////
// Function: EggTriangleFan::get_num_lead_vertices
// Access: Protected, Virtual
// Description: Returns the number of initial vertices that are not
// used in defining any component; the first component
// is defined by the (n + 1)th vertex, and then a new
// component at each vertex thereafter.
////////////////////////////////////////////////////////////////////
int EggTriangleFan::
get_num_lead_vertices() const {
return 2;
}
////////////////////////////////////////////////////////////////////
// Function: EggTriangleFan::triangulate_poly
// Access: Protected, Virtual
// Description: Fills the container up with EggPolygons that
// represent the component triangles of this triangle
// fan.
//
// It is assumed that the EggTriangleFan is not
// already a child of any other group when this function
// is called.
//
// Returns true if the triangulation is successful, or
// false if there was some error (in which case the
// container may contain some partial triangulation).
////////////////////////////////////////////////////////////////////
bool EggTriangleFan::
do_triangulate(EggGroupNode *container) const {
if (size() < 3) {
return false;
}
const_iterator vi = begin();
EggVertex *v0 = (*vi);
++vi;
EggVertex *v1 = (*vi);
++vi;
for (int i = 0; i < (int)size() - 2; i++) {
PT(EggPolygon) poly = new EggPolygon;
poly->copy_attributes(*this);
const EggAttributes *attrib = get_component(i);
if (attrib->has_color()) {
poly->set_color(attrib->get_color());
}
if (attrib->has_normal()) {
poly->set_normal(attrib->get_normal());
}
poly->add_vertex(v0);
poly->add_vertex(v1);
poly->add_vertex(*vi);
v1 = *vi;
container->add_child(poly);
++vi;
}
return true;
}

View File

@ -0,0 +1,66 @@
// Filename: eggTriangleFan.h
// Created by: drose (23Mar05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef EGGTRIANGLEFAN_H
#define EGGTRIANGLEFAN_H
#include "pandabase.h"
#include "eggCompositePrimitive.h"
////////////////////////////////////////////////////////////////////
// Class : EggTriangleFan
// Description : A connected fan of triangles. This does not
// normally appear in an egg file; it is typically
// generated as a result of meshing.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEGG EggTriangleFan : public EggCompositePrimitive {
PUBLISHED:
INLINE EggTriangleFan(const string &name = "");
INLINE EggTriangleFan(const EggTriangleFan &copy);
INLINE EggTriangleFan &operator = (const EggTriangleFan &copy);
virtual ~EggTriangleFan();
virtual void write(ostream &out, int indent_level) const;
virtual void apply_first_attribute();
protected:
virtual int get_num_lead_vertices() const;
virtual bool do_triangulate(EggGroupNode *container) const;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
EggCompositePrimitive::init_type();
register_type(_type_handle, "EggTriangleFan",
EggCompositePrimitive::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
#include "eggTriangleFan.I"
#endif

View File

@ -19,12 +19,8 @@
#include "eggTriangleStrip.h"
#include "eggGroupNode.h"
#include "eggPolygon.h"
#include "plane.h"
#include "indent.h"
#include <algorithm>
TypeHandle EggTriangleStrip::_type_handle;

View File

@ -18,6 +18,7 @@
#include "eggMaterialCollection.cxx"
#include "eggMesher.cxx"
#include "eggMesherEdge.cxx"
#include "eggMesherFanMaker.cxx"
#include "eggMesherStrip.cxx"
#include "eggMiscFuncs.cxx"
#include "eggMorphList.cxx"

View File

@ -13,6 +13,7 @@
#include "eggTexture.cxx"
#include "eggTextureCollection.cxx"
#include "eggTransform3d.cxx"
#include "eggTriangleFan.cxx"
#include "eggTriangleStrip.cxx"
#include "eggUserData.cxx"
#include "eggUtilities.cxx"

View File

@ -16,6 +16,7 @@
#include "eggVertexUV.h"
#include "eggPolygon.h"
#include "eggCompositePrimitive.h"
#include "eggTriangleFan.h"
#include "eggTriangleStrip.h"
#include "eggPoint.h"
#include "eggLine.h"
@ -182,6 +183,7 @@ egg_cleanup_parser() {
%type <_egg> joint
%type <_egg> line
%type <_egg> polygon
%type <_egg> trianglefan
%type <_egg> trianglestrip
%type <_egg> point_light
%type <_egg> nurbs_surface
@ -252,6 +254,7 @@ node:
| joint
| instance
| polygon
| trianglefan
| trianglestrip
| point_light
| line
@ -1596,6 +1599,25 @@ polygon:
}
;
/*
* trianglefan
*
* enter:
* exit: returns a new EggTriangleFan.
*
*/
trianglefan:
TRIANGLEFAN optional_name
{
egg_stack.push_back(new EggTriangleFan($2));
}
'{' primitive_body '}'
{
$$ = egg_stack.back();
egg_stack.pop_back();
}
;
/*
* trianglestrip
*

View File

@ -40,6 +40,7 @@
#include "qpgeom.h"
#include "qpgeomTriangles.h"
#include "qpgeomTristrips.h"
#include "qpgeomTrifans.h"
#include "qpgeomLines.h"
#include "qpgeomLinestrips.h"
#include "qpgeomPoints.h"
@ -61,6 +62,7 @@
#include "eggGroup.h"
#include "eggPolygon.h"
#include "eggTriangleStrip.h"
#include "eggTriangleFan.h"
#include "eggBin.h"
#include "eggTable.h"
#include "eggBinner.h"
@ -2000,6 +2002,9 @@ make_primitive(const EggRenderState *render_state, EggPrimitive *egg_prim,
} else if (egg_prim->is_of_type(EggTriangleStrip::get_class_type())) {
primitive = new qpGeomTristrips(qpGeomUsageHint::UH_static);
} else if (egg_prim->is_of_type(EggTriangleFan::get_class_type())) {
primitive = new qpGeomTrifans(qpGeomUsageHint::UH_static);
} else if (egg_prim->is_of_type(EggLine::get_class_type())) {
if (egg_prim->size() == 2) {
primitive = new qpGeomLines(qpGeomUsageHint::UH_static);

View File

@ -125,6 +125,8 @@ decompose_impl() const {
triangles->add_vertex(v0);
triangles->add_vertex(v1);
triangles->add_vertex(vertices[vi]);
nassertr(vi < (int)vertices.size(), this);
v1 = vertices[vi];
triangles->close_primitive();
++vi;
}