1653 lines
50 KiB
Plaintext
1653 lines
50 KiB
Plaintext
// Filename: mesherStrip.I
|
|
// Created by: drose (16Sep97)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
|
|
//
|
|
// To contact the maintainers of this program write to
|
|
// panda3d@yahoogroups.com .
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "config_builder.h"
|
|
|
|
template <class PrimType>
|
|
INLINE MesherStrip<PrimType>::
|
|
MesherStrip(const MesherStrip ©) :
|
|
_prims(copy._prims),
|
|
_edges(copy._edges),
|
|
_verts(copy._verts),
|
|
_type(copy._type),
|
|
_index(copy._index),
|
|
_status(copy._status),
|
|
_planar(copy._planar),
|
|
_plane_normal(copy._plane_normal),
|
|
_plane_offset(copy._plane_offset),
|
|
_row_id(copy._row_id)
|
|
{
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::is_coplanar_with
|
|
// Access: Public
|
|
// Description: Returns true if the strip and the other strip are
|
|
// coplanar.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
INLINE bool MesherStrip<PrimType>::
|
|
is_coplanar_with(const MesherStrip &other, float threshold) const {
|
|
return (coplanarity(other) <= threshold);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::coplanarity
|
|
// Access: Public
|
|
// Description: Returns the degree to which the two strips are
|
|
// coplanar. 0.0 is exactly coplanar; numbers somewhat
|
|
// larger than zero indicate less coplanar. 1.0 is
|
|
// at right angles; 2.0 is exactly backfacing. If
|
|
// either strip is not itself planar, 3.0 is returned.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
INLINE float MesherStrip<PrimType>::
|
|
coplanarity(const MesherStrip &other) const {
|
|
if (_planar && other._planar) {
|
|
return 1.0 - dot(_plane_normal, other._plane_normal);
|
|
} else {
|
|
return 3.0;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::type_category
|
|
// Access: Public
|
|
// Description: Returns an integer which gives a heuristic about the
|
|
// similarity of different strip types. In general,
|
|
// closer numbers are more similar.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
INLINE int MesherStrip<PrimType>::
|
|
type_category() const {
|
|
switch (_type) {
|
|
case BPT_tri:
|
|
return 1;
|
|
|
|
case BPT_tristrip:
|
|
return 2;
|
|
|
|
case BPT_quad:
|
|
case BPT_quadstrip:
|
|
return 5;
|
|
|
|
default:
|
|
return 10;
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::rotate_forward
|
|
// Access: Public
|
|
// Description: Rotates a triangle or quad by bringing its second
|
|
// vertex to the front.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
INLINE void MesherStrip<PrimType>::
|
|
rotate_forward() {
|
|
_verts.push_back(_verts.front());
|
|
_verts.pop_front();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::rotate_back
|
|
// Access: Public
|
|
// Description: Rotates a triangle or quad by bringing its second
|
|
// vertex to the front.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
INLINE void MesherStrip<PrimType>::
|
|
rotate_back() {
|
|
_verts.push_front(_verts.back());
|
|
_verts.pop_back();
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::get_head_edge
|
|
// Access: Public
|
|
// Description: Returns an Edge which represents the leading edge in
|
|
// the quadstrip or tristrip. This Edge will not have
|
|
// pointer equality with any shared Edge.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
INLINE MesherStrip<PrimType>::Edge MesherStrip<PrimType>::
|
|
get_head_edge() const {
|
|
Verts::const_iterator vi = _verts.begin();
|
|
return Edge(_verts.front(), *++vi);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::get_tail_edge
|
|
// Access: Public
|
|
// Description: Returns an Edge which represents the trailing edge in
|
|
// the quadstrip or tristrip. This Edge will not have
|
|
// pointer equality with any shared Edge.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
INLINE MesherStrip<PrimType>::Edge MesherStrip<PrimType>::
|
|
get_tail_edge() const {
|
|
Verts::const_reverse_iterator vi = _verts.rbegin();
|
|
return Edge(*++vi, _verts.back());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::operator ==
|
|
// Access: Public
|
|
// Description: Defines equality for strips. This actually tests
|
|
// only pointer equality; it's used only when removing a
|
|
// strip from the list.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
INLINE bool MesherStrip<PrimType>::
|
|
operator == (const MesherStrip &other) const {
|
|
return this == &other;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::operator !=
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
INLINE bool MesherStrip<PrimType>::
|
|
operator != (const MesherStrip &other) const {
|
|
return !operator == (other);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::Constructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
MesherStrip<PrimType>::
|
|
MesherStrip(const PrimType &prim, int index, const BuilderBucket &bucket) {
|
|
_index = index;
|
|
_row_id = 0;
|
|
_status = MS_alive;
|
|
_origin = MO_unknown;
|
|
prim.has_overall_normal(); // Force the prim to update its overall flags.
|
|
_type = prim.get_type();
|
|
|
|
// We save only the prim's overall properties in the _prims
|
|
// array. The vertices get re-added later by Mesher::add_prim().
|
|
_prims.push_back(prim);
|
|
|
|
if (_type == BPT_poly) {
|
|
switch (prim.get_num_verts()) {
|
|
case 3:
|
|
_type = BPT_tri;
|
|
break;
|
|
|
|
case 4:
|
|
_type = BPT_quad;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (_type == BPT_quad) {
|
|
// A quad has two internal triangles; we therefore push the prim
|
|
// properties twice.
|
|
_prims.push_back(prim);
|
|
}
|
|
|
|
_planar = false;
|
|
|
|
if (prim.get_num_verts() >= 3) {
|
|
// However, we will examine the vertices to determine the plane equation.
|
|
Vertexf p1 = prim.get_vertex(0).get_coord_value(bucket);
|
|
Vertexf p2 = prim.get_vertex(1).get_coord_value(bucket);
|
|
Vertexf p3 = prim.get_vertex(2).get_coord_value(bucket);
|
|
_plane_normal = cross(p1-p2, p2-p3);
|
|
float l = length(_plane_normal);
|
|
|
|
if (l != 0.0) {
|
|
_plane_normal /= l;
|
|
_planar = true;
|
|
_plane_offset = -dot(_plane_normal, p1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::make_prim
|
|
// Access: Public
|
|
// Description: Creates a PrimType element corresponding to the strip
|
|
// represented by this node.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
PrimType MesherStrip<PrimType>::
|
|
make_prim(const BuilderBucket &bucket) {
|
|
Prim p;
|
|
BuilderPrimType dest_type;
|
|
|
|
switch (_type) {
|
|
case BPT_quad:
|
|
dest_type = bucket._show_quads ? BPT_poly : BPT_tristrip;
|
|
break;
|
|
|
|
case BPT_tristrip:
|
|
case BPT_quadstrip:
|
|
dest_type = BPT_tristrip;
|
|
break;
|
|
|
|
case BPT_trifan:
|
|
dest_type = BPT_trifan;
|
|
break;
|
|
|
|
default:
|
|
dest_type = _type;
|
|
}
|
|
|
|
if (dest_type != BPT_tristrip && dest_type != BPT_trifan) {
|
|
// The easy case: a simple primitive.
|
|
p.set_attrib(_prims.front());
|
|
Verts::iterator vi;
|
|
for (vi = _verts.begin(); vi != _verts.end(); ++vi) {
|
|
const Vertex *v = *vi;
|
|
nassertr(v != (Vertex *)NULL, p);
|
|
p.add_vertex(*v);
|
|
}
|
|
p.set_type(dest_type);
|
|
|
|
} else {
|
|
// The harder case: a tristrip of some kind.
|
|
convert_to_type(dest_type);
|
|
p.set_attrib(_prims.front());
|
|
|
|
BuilderPrimType type = dest_type;
|
|
|
|
// Now store all the vertices, as well as each individual
|
|
// triangle's attributes.
|
|
Verts::iterator vi;
|
|
Prims::iterator pi;
|
|
pi = _prims.begin();
|
|
int count = 0;
|
|
for (vi = _verts.begin();
|
|
vi != _verts.end() && pi != _prims.end();
|
|
++vi) {
|
|
const Vertex *v = *vi;
|
|
nassertr(v != (Vertex *)NULL, p);
|
|
|
|
if (++count >= 3) {
|
|
// Beginning with the third vertex, we increment pi. Thus, the
|
|
// first two vertices stand alone, then each vertex beginning
|
|
// with the third completes a triangle.
|
|
p.add_component(*pi);
|
|
++pi;
|
|
}
|
|
p.add_vertex(*v);
|
|
}
|
|
|
|
p.set_type(type);
|
|
|
|
// If either of these fail, there weren't num_prims + 2 vertices in
|
|
// the tristrip!
|
|
nassertr(vi==_verts.end(), p);
|
|
nassertr(pi==_prims.end(), p);
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::measure_sheet
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
void MesherStrip<PrimType>::
|
|
measure_sheet(const Edge *edge, int new_row, int &num_prims, int &num_rows,
|
|
int first_row_id, int this_row_id, int this_row_distance) {
|
|
if (new_row) {
|
|
// If we would create a new row by stepping here, we won't stay if
|
|
// there was any other row already defined here.
|
|
if (_row_id >= first_row_id) {
|
|
return;
|
|
}
|
|
} else {
|
|
// On the other hand, if this is a continuation of the current
|
|
// row, we'll stay if the other row had to travel farther to get
|
|
// here.
|
|
if (_row_id >= first_row_id && _row_distance <= this_row_distance) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
num_prims += _prims.size();
|
|
if (new_row) {
|
|
++num_rows;
|
|
this_row_id = first_row_id + num_rows - 1;
|
|
}
|
|
|
|
_row_id = this_row_id;
|
|
|
|
Edges::iterator ei;
|
|
Edge::Strips::iterator si;
|
|
|
|
if (_type == BPT_quad) {
|
|
// If this is a quad, it has four neighbors: two in the direction
|
|
// we are testing, and two in an orthagonal direction.
|
|
|
|
const Vertex *a = edge->_a;
|
|
const Vertex *b = edge->_b;
|
|
|
|
// We use these vertices to differentiate the edges that run in
|
|
// our primary direction from those in the secondary direction.
|
|
// For each edge, we count the number of vertices that the edge
|
|
// shares with our starting edge. There are then three cases:
|
|
|
|
// (a) The edge shares two vertices. It is the direction we came
|
|
// from; forget it.
|
|
|
|
// (b) The edge shares one vertex. It is at right angles to our
|
|
// starting edge. This is the primary direction if new_row is
|
|
// true, and the secondary direction if new_row is false.
|
|
|
|
// (c) The edge shares no vertices. It is directly opposite our
|
|
// starting edge. This is the primary direction if new_row is
|
|
// false, and the secondary direction if new_row is true.
|
|
|
|
|
|
// Here's a silly little for loop that executes the following code
|
|
// twice: once with secondary == 0, and once with secondary == 1.
|
|
// This is because we want to find all the primary edges first,
|
|
// and then all the secondary edges.
|
|
|
|
for (int secondary = 0; secondary <= 1; secondary++) {
|
|
// How many common vertices are we looking for this pass (see
|
|
// above)?
|
|
|
|
int want_count;
|
|
if (secondary) {
|
|
want_count = new_row ? 0 : 1;
|
|
} else {
|
|
want_count = new_row ? 1 : 0;
|
|
}
|
|
|
|
for (ei = _edges.begin(); ei != _edges.end(); ++ei) {
|
|
int common_verts =
|
|
((*ei)->_a == a || (*ei)->_a == b) +
|
|
((*ei)->_b == a || (*ei)->_b == b);
|
|
|
|
if (common_verts == want_count) {
|
|
// Here's the edge. Look at all its connections. Hopefully,
|
|
// there will only be one besides ourselves, but there may be
|
|
// more. Pick the best.
|
|
|
|
Edge::Strips &strips = (*ei)->_strips;
|
|
MesherStrip *mate = NULL;
|
|
for (si = strips.begin(); si != strips.end(); ++si) {
|
|
if ((*si)->_row_id < first_row_id) {
|
|
if (mate==NULL || pick_sheet_mate(**si, *mate)) {
|
|
mate = *si;
|
|
}
|
|
}
|
|
}
|
|
if (mate!=NULL) {
|
|
mate->measure_sheet(*ei, secondary, num_prims, num_rows,
|
|
first_row_id, this_row_id,
|
|
this_row_distance + secondary);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} else {
|
|
// Otherwise, this is not a quad. It's certainly not a triangle,
|
|
// because we've built all the single triangles already.
|
|
nassertv(_type != BPT_tri);
|
|
|
|
// Therefore, it must be a tristrip or quadstrip.
|
|
nassertv(_type == BPT_tristrip || _type == BPT_quadstrip);
|
|
|
|
// Since it's a strip, it only has two neighbors: the one we came
|
|
// from, and the other one. Find the other one.
|
|
|
|
for (ei = _edges.begin(); ei != _edges.end(); ++ei) {
|
|
if (!(*ei)->matches(*edge)) {
|
|
// Here's the edge. Same drill as above.
|
|
|
|
Edge::Strips &strips = (*ei)->_strips;
|
|
MesherStrip *mate = NULL;
|
|
for (si = strips.begin(); si != strips.end(); ++si) {
|
|
if ((*si)->_row_id < first_row_id) {
|
|
if (mate==NULL || pick_sheet_mate(**si, *mate)) {
|
|
mate = *si;
|
|
}
|
|
}
|
|
}
|
|
if (mate!=NULL) {
|
|
mate->measure_sheet(*ei, false, num_prims, num_rows,
|
|
first_row_id, this_row_id, this_row_distance);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::cut_sheet
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
void MesherStrip<PrimType>::
|
|
cut_sheet(int first_row_id, int do_mate, const BuilderBucket &bucket) {
|
|
Edges::iterator ei;
|
|
Edge::Strips::iterator si;
|
|
|
|
// First, start the process going on any neighbors that belong to a
|
|
// later row. (We must do these first, because we'll change our
|
|
// neighbor list when we start to mate.)
|
|
|
|
// We need to build a temporary list of neighbors first, because
|
|
// calling cut_sheet() recursively will start things mating, and
|
|
// could damage our edge list.
|
|
|
|
typedef plist<MesherStrip *> StripPtrs;
|
|
StripPtrs strip_ptrs;
|
|
|
|
for (ei = _edges.begin(); ei != _edges.end(); ++ei) {
|
|
Edge::Strips &strips = (*ei)->_strips;
|
|
for (si = strips.begin(); si != strips.end(); ++si) {
|
|
if ((*si)->_row_id > _row_id) {
|
|
// Here's a different row in the sheet!
|
|
strip_ptrs.push_back(*si);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now walk the temporary list and do some damage. We pass do_mate
|
|
// = true to each of these neighbors, because as far as we know,
|
|
// they're the first nodes of a particular row.
|
|
StripPtrs::iterator spi;
|
|
for (spi = strip_ptrs.begin(); spi != strip_ptrs.end(); ++spi) {
|
|
if ((*spi)->_status == MS_alive) {
|
|
(*spi)->cut_sheet(first_row_id, true, bucket);
|
|
}
|
|
}
|
|
|
|
|
|
if (do_mate && _status == MS_alive) {
|
|
// Now mate like a bunny until we don't have any more eligible mates.
|
|
int not_any;
|
|
do {
|
|
not_any = true;
|
|
|
|
ei = _edges.begin();
|
|
while (ei != _edges.end() && not_any) {
|
|
Edge::Strips &strips = (*ei)->_strips;
|
|
si = strips.begin();
|
|
while (si != strips.end() && not_any) {
|
|
if (*si != this && (*si)->_row_id == _row_id) {
|
|
// Here's one!
|
|
not_any = false;
|
|
MesherStrip *mate = *si;
|
|
|
|
// We also recurse on these guys so they can spread the
|
|
// word to their own neighbors. This time we don't need
|
|
// to build a temporary list, because we'll be restarting
|
|
// from the beginning of our edge list after we do this.
|
|
// We also pass do_mate = false to these guys because
|
|
// we're the ones doing the mating here.
|
|
mate->cut_sheet(first_row_id, false, bucket);
|
|
|
|
if (_status == MS_alive && mate->_status == MS_alive) {
|
|
// Now mate. This will either succeed or fail. It ought
|
|
// to succeed, but if it doesn't, no harm done; it will
|
|
// simply remove the common edge and return. We'll go
|
|
// around again and not encounter this neighbor next time.
|
|
mate_pieces(*ei, *this, *mate, bucket);
|
|
}
|
|
}
|
|
if (not_any) {
|
|
++si;
|
|
}
|
|
}
|
|
if (not_any) {
|
|
++ei;
|
|
}
|
|
}
|
|
} while (!not_any);
|
|
|
|
// All done. Mark this one as down for the count.
|
|
_row_id = -first_row_id;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::mate
|
|
// Access: Public
|
|
// Description: Finds a neighboring strip and joins up with it to
|
|
// make a larger strip. Returns true if mating was
|
|
// successful or at least possible, false if the strip
|
|
// has no neighbors.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
bool MesherStrip<PrimType>::
|
|
mate(const BuilderBucket &bucket) {
|
|
// We must walk through the list of our neighbors and choose our
|
|
// best mate.
|
|
nassertr(_status == MS_alive, false);
|
|
|
|
MesherStrip *mate;
|
|
Edge *common_edge;
|
|
|
|
if (!find_ideal_mate(mate, common_edge, bucket)) {
|
|
// We have no more eligible neighbors. Call us done.
|
|
_status = MS_done;
|
|
|
|
return false;
|
|
}
|
|
|
|
nassertr(!mate->_prims.empty(), false);
|
|
nassertr(!mate->_verts.empty(), false);
|
|
|
|
mate_pieces(common_edge, *this, *mate, bucket);
|
|
|
|
// Whether the mate failed or not, the strip still (probably) has
|
|
// other neighbors to consider. Return true regardless.
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::find_ideal_mate
|
|
// Access: Public
|
|
// Description: Searches our neighbors for the most suitable mate.
|
|
// Returns true if one is found, false if we have no
|
|
// neighbors.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
bool MesherStrip<PrimType>::
|
|
find_ideal_mate(MesherStrip *&mate, Edge *&common_edge,
|
|
const BuilderBucket &bucket) {
|
|
Edges::iterator ei;
|
|
|
|
mate = NULL;
|
|
common_edge = NULL;
|
|
|
|
for (ei = _edges.begin(); ei != _edges.end(); ++ei) {
|
|
Edge::Strips &strips = (*ei)->_strips;
|
|
Edge::Strips::iterator si;
|
|
for (si = strips.begin(); si != strips.end(); ++si) {
|
|
if (*si != this) {
|
|
if (mate==NULL || pick_mate(**si, *mate, **ei, *common_edge,
|
|
bucket)) {
|
|
mate = *si;
|
|
common_edge = *ei;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return (mate!=NULL);
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::mate_pieces
|
|
// Access: Public, Static
|
|
// Description: Connects two pieces of arbitrary type, if possible.
|
|
// Returns true if successful, false if failure.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
bool MesherStrip<PrimType>::
|
|
mate_pieces(Edge *common_edge, MesherStrip &front, MesherStrip &back,
|
|
const BuilderBucket &bucket) {
|
|
nassertr(front._status == MS_alive, false);
|
|
nassertr(back._status == MS_alive, false);
|
|
nassertr(&front != &back, false);
|
|
|
|
bool success = true;
|
|
// remove_sides tracks whether we want to remove all but the leading
|
|
// edges of the newly joined piece if we succeed.
|
|
bool remove_sides = true;
|
|
|
|
bool is_coplanar = front.is_coplanar_with(back, bucket._coplanar_threshold);
|
|
|
|
if (front._type==BPT_tri && back._type==BPT_tri) {
|
|
|
|
if (is_coplanar && bucket._retesselate_coplanar &&
|
|
front._prims.front() == back._prims.front() &&
|
|
convex_quad(common_edge, front, back, bucket)) {
|
|
|
|
// If we're joining two equivalent coplanar triangles, call it a
|
|
// quad.
|
|
front._type = BPT_quad;
|
|
|
|
// We add one additional vertex for the new triangle, the one
|
|
// vertex we didn't already share.
|
|
const Vertex *new_vert = back.find_uncommon_vertex(common_edge);
|
|
|
|
// Now we just need to find the right place to insert it. It
|
|
// belongs in the middle of the common edge, i.e. after the first
|
|
// vertex that is on the common edge and before the second vertex.
|
|
Verts::iterator a = front._verts.begin();
|
|
Verts::iterator b = a;
|
|
++b;
|
|
|
|
if (common_edge->contains_vertex(*a)) {
|
|
if (common_edge->contains_vertex(*b)) {
|
|
// It goes between a and b.
|
|
front._verts.insert(b, new_vert);
|
|
} else {
|
|
// It goes at the end.
|
|
front._verts.push_back(new_vert);
|
|
}
|
|
} else {
|
|
// It goes between b and c.
|
|
++b;
|
|
front._verts.insert(b, new_vert);
|
|
}
|
|
|
|
front._prims.splice(front._prims.end(), back._prims);
|
|
back._verts.clear();
|
|
|
|
// We leave all four surrounding edges for now, since the quad
|
|
// might still be joined up in any direction.
|
|
remove_sides = false;
|
|
|
|
} else {
|
|
// Otherwise, connect the two tris into a tristrip.
|
|
front._type = BPT_tristrip;
|
|
|
|
const Vertex *new_vert = back.find_uncommon_vertex(common_edge);
|
|
front.rotate_to_back(common_edge);
|
|
|
|
front._verts.push_back(new_vert);
|
|
front._prims.splice(front._prims.end(), back._prims);
|
|
back._verts.clear();
|
|
}
|
|
|
|
} else if ((front._type==BPT_quad || front._type==BPT_quadstrip) &&
|
|
(back._type==BPT_quad || back._type==BPT_quadstrip)) {
|
|
// Joining two quads, two quadstrips, or a quad and a quadstrip.
|
|
// This makes another quadstrip.
|
|
|
|
// We expect this to succeed every time with quadstrips.
|
|
success = mate_strips(common_edge, front, back, BPT_quadstrip);
|
|
|
|
if (!success) {
|
|
// Although it might fail in rare circumstances (specifically,
|
|
// if the two strips we attempted to join were backfacing to
|
|
// each other). If so, remove the adjoining edge so these two
|
|
// don't get tried again.
|
|
common_edge->remove(&front);
|
|
common_edge->remove(&back);
|
|
}
|
|
|
|
} else {
|
|
|
|
// Otherwise. This might be two tristrips, a quad and a tristrip,
|
|
// a triangle and a quad, a triangle and a tristrip, a triangle
|
|
// and a quadstrip, or a tristrip and a quadstrip. In any case,
|
|
// we'll end up with a tristrip.
|
|
|
|
// This might fail if the tristrips don't match polarity.
|
|
success = mate_strips(common_edge, front, back, BPT_tristrip);
|
|
|
|
if (!success) {
|
|
// If it does fail, we'll try reversing the connection. This
|
|
// makes sense if we are joining a tri or tristrip to a quad or
|
|
// quadstrip, which might fail in one direction but succeed in
|
|
// the other.
|
|
success = mate_strips(common_edge, back, front, BPT_tristrip);
|
|
|
|
if (success) {
|
|
// Yay! Now return all the stuff to front.
|
|
front._verts.splice(front._verts.end(), back._verts);
|
|
front._prims.splice(front._prims.end(), back._prims);
|
|
} else {
|
|
// A miserable failure. Never try to join these two again.
|
|
|
|
common_edge->remove(&front);
|
|
common_edge->remove(&back);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (success) {
|
|
front.combine_edges(back, remove_sides);
|
|
if (!remove_sides) {
|
|
// If we didn't want to remove the side edges, at least remove
|
|
// the join edge, which is now internal.
|
|
common_edge->remove(&front);
|
|
}
|
|
|
|
nassertr(back._prims.empty(), false);
|
|
nassertr(back._verts.empty(), false);
|
|
|
|
// Strip back is no more.
|
|
back._status = MS_dead;
|
|
|
|
// The result is planar if and only if we joined two coplanar
|
|
// pieces.
|
|
front._planar = is_coplanar;
|
|
front._origin = MO_mate;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::mate_strips
|
|
// Access: Public, Static
|
|
// Description: Stitches two strips together, producing in "front" a
|
|
// new strip of the indicated type (quadstrip or
|
|
// tristrip). The front strip stores the result, and
|
|
// the back strip is emptied on success.
|
|
//
|
|
// Returns true if successful, false if failure
|
|
// (generally because of incorrect polarity of
|
|
// tristrips), in which case nothing has changed (or at
|
|
// least, not much).
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
bool MesherStrip<PrimType>::
|
|
mate_strips(Edge *common_edge, MesherStrip &front, MesherStrip &back,
|
|
BuilderPrimType type) {
|
|
// If we start with a quad or tri, rotate the vertices around so we
|
|
// start with the common edge.
|
|
if (front._type==BPT_tri || front._type==BPT_quad) {
|
|
front.rotate_to_back(common_edge);
|
|
}
|
|
if (back._type==BPT_tri || back._type==BPT_quad) {
|
|
back.rotate_to_front(common_edge);
|
|
}
|
|
|
|
bool reverse_front = common_edge->matches(front.get_head_edge());
|
|
bool reverse_back = !common_edge->matches(back.get_head_edge());
|
|
|
|
bool invert_front = false;
|
|
bool invert_back = false;
|
|
|
|
if (reverse_front && front.is_odd()) {
|
|
// If we're going to reverse the front strip, we have to be
|
|
// careful. This will also reverse the facing direction if it has
|
|
// an odd number of prims.
|
|
if (!front.can_invert()) {
|
|
return false;
|
|
}
|
|
invert_front = true;
|
|
}
|
|
|
|
if (must_invert(front, back, reverse_back, type)) {
|
|
if (!back.can_invert()) {
|
|
return false;
|
|
}
|
|
invert_back = true;
|
|
back.invert();
|
|
}
|
|
|
|
if (invert_front) {
|
|
front.invert();
|
|
}
|
|
|
|
if (reverse_front) {
|
|
reverse(front._verts.begin(), front._verts.end());
|
|
reverse(front._prims.begin(), front._prims.end());
|
|
}
|
|
|
|
if (reverse_back) {
|
|
reverse(back._verts.begin(), back._verts.end());
|
|
reverse(back._prims.begin(), back._prims.end());
|
|
}
|
|
|
|
bool will_reverse = front.would_reverse_tail(type);
|
|
bool is_headtotail = (front.get_tail_edge() == back.get_head_edge());
|
|
if (will_reverse == is_headtotail) {
|
|
// Instead of crapping out, for now we'll just recover and carry on.
|
|
// builder_cat.info() << "Recovering from attempt to join backfacing strips.\n";
|
|
if (reverse_back) {
|
|
reverse(back._verts.begin(), back._verts.end());
|
|
reverse(back._prims.begin(), back._prims.end());
|
|
}
|
|
if (invert_back) {
|
|
back.invert();
|
|
}
|
|
if (reverse_front) {
|
|
reverse(front._verts.begin(), front._verts.end());
|
|
reverse(front._prims.begin(), front._prims.end());
|
|
}
|
|
if (invert_front) {
|
|
front.invert();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
front.convert_to_type(type);
|
|
back.convert_to_type(type);
|
|
|
|
/*
|
|
if (! (front.get_tail_edge() == back.get_head_edge()) ) {
|
|
builder_cat.error()
|
|
<< "\nFailure, trying to connect " << front
|
|
<< "\nto " << back
|
|
<< "\nreverse_front = " << reverse_front
|
|
<< " reverse_back = " << reverse_back
|
|
<< " invert_front = " << invert_front
|
|
<< "\n";
|
|
Edges::iterator ei;
|
|
|
|
nout << "\nFront edges:\n";
|
|
for (ei = front._edges.begin(); ei != front._edges.end(); ++ei) {
|
|
nout << **ei << "\n";
|
|
}
|
|
|
|
nout << "\nBack edges:\n";
|
|
for (ei = back._edges.begin(); ei != back._edges.end(); ++ei) {
|
|
nout << **ei << "\n";
|
|
}
|
|
}
|
|
*/
|
|
|
|
// If this assertion fails, we were misinformed about our ability to
|
|
// join these two strips. Either the must_invert() call returned the
|
|
// incorrect value, or our edge-detection logic failed and we
|
|
// attempted to join two oppositely-facing strips.
|
|
//nassertr(front.get_tail_edge() == back.get_head_edge(), false);
|
|
|
|
front._verts.pop_back();
|
|
front._verts.pop_back();
|
|
front._verts.splice(front._verts.end(), back._verts);
|
|
front._prims.splice(front._prims.end(), back._prims);
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::must_invert
|
|
// Access: Public, Static
|
|
// Description: Returns false if the strips can be mated as they
|
|
// currently are. Returns true if the back strip must
|
|
// be inverted first.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
bool MesherStrip<PrimType>::
|
|
must_invert(const MesherStrip &front, const MesherStrip &back,
|
|
bool will_reverse_back, BuilderPrimType type) {
|
|
bool invert = false;
|
|
|
|
if ((front._type == BPT_quad || front._type == BPT_quadstrip) &&
|
|
type == BPT_tristrip) {
|
|
// If we'll be converting from quads to tris, the tail edge of the
|
|
// front strip will always be even.
|
|
|
|
} else if (front.is_odd()) {
|
|
// Otherwise, we have to flip if the tail edge is odd.
|
|
invert = !invert;
|
|
}
|
|
|
|
if (will_reverse_back) {
|
|
// With the back strip, we don't care about what will happen to
|
|
// its tail edge when we convert it, but we do care what happens
|
|
// to its front edge if we reverse it.
|
|
if (back.is_odd()) {
|
|
// Specifically, the front edge will be reversed when the strip
|
|
// is reversed only if the strip is odd.
|
|
invert = !invert;
|
|
}
|
|
}
|
|
|
|
return invert;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::convex_quad
|
|
// Access: Public, Static
|
|
// Description: Returns true if the quad that would be formed by
|
|
// connecting coplanar tris front and back along
|
|
// common_edge is convex, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
bool MesherStrip<PrimType>::
|
|
convex_quad(Edge *common_edge, MesherStrip &front, MesherStrip &back,
|
|
const BuilderBucket &bucket) {
|
|
// Find the edge from the apex of one triangle to the apex of the
|
|
// other. This is the "other" diagonal of the quad-to-be, other
|
|
// than the common_edge.
|
|
const Vertex *a = front.find_uncommon_vertex(common_edge);
|
|
const Vertex *b = back.find_uncommon_vertex(common_edge);
|
|
nassertr(a!=NULL && b!=NULL, false);
|
|
|
|
Vertexf a3, b3, c3, d3;
|
|
a3 = a->get_coord_value(bucket);
|
|
b3 = b->get_coord_value(bucket);
|
|
|
|
c3 = common_edge->_a->get_coord_value(bucket);
|
|
d3 = common_edge->_b->get_coord_value(bucket);
|
|
|
|
// Project both edges into the 2-d axis plane most nearly
|
|
// perpendicular to the normal. We're assuming both tris have the
|
|
// same normal.
|
|
|
|
nassertr(front._planar, false);
|
|
|
|
LVector3f &n = front._plane_normal;
|
|
int xi, yi;
|
|
|
|
// Find the largest dimension of the normal.
|
|
if (fabs(n[0]) > fabs(n[1])) {
|
|
if (fabs(n[0]) > fabs(n[2])) {
|
|
xi = 1;
|
|
yi = 2;
|
|
} else {
|
|
xi = 0;
|
|
yi = 1;
|
|
}
|
|
} else {
|
|
if (fabs(n[1]) > fabs(n[2])) {
|
|
xi = 0;
|
|
yi = 2;
|
|
} else {
|
|
xi = 0;
|
|
yi = 1;
|
|
}
|
|
}
|
|
|
|
LVecBase2f a2, b2, c2, d2;
|
|
a2.set(a3[xi], a3[yi]);
|
|
b2.set(b3[xi], b3[yi]);
|
|
c2.set(c3[xi], c3[yi]);
|
|
d2.set(d3[xi], d3[yi]);
|
|
|
|
// Now (c2-d2) is the common edge, and (a2-b2) is the new edge. The
|
|
// quad is convex iff (c2-d2) intersects (a2-b2). We actually only
|
|
// need to test whether (c2-d2) intersects the infinite line passing
|
|
// through (a2-b2).
|
|
|
|
// The equation for the infinite line containing (a2-b2):
|
|
// Ax + By + C = 0
|
|
double A = (b2[1] - a2[1]);
|
|
double B = (a2[0] - b2[0]);
|
|
double C = -(A*b2[0] + B*b2[1]);
|
|
|
|
// The parametric equations for the line segment (c2-d2):
|
|
// x = c2[0] + (d2[0]-c2[0])t
|
|
// y = c2[1] + (d2[1]-c2[1])t
|
|
|
|
// Solved for t:
|
|
double t = - ((A*c2[0] + B*c2[1]) + C) / (A*(d2[0]-c2[0]) + B*(d2[1]-c2[1]));
|
|
|
|
// Now the lines intersect if t is in [0, 1].
|
|
return (0.0 <= t && t <= 1.0);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::count_neighbors
|
|
// Access: Public
|
|
// Description: Returns the number of neighbors the strip shares.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
int MesherStrip<PrimType>::
|
|
count_neighbors() const {
|
|
int count = 0;
|
|
Edges::const_iterator ei;
|
|
|
|
for (ei = _edges.begin(); ei != _edges.end(); ++ei) {
|
|
count += (*ei)->_strips.size();
|
|
}
|
|
return count;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::show_neighbors
|
|
// Access: Public
|
|
// Description: Writes all the neighbor indexes to the ostream.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
ostream &MesherStrip<PrimType>::
|
|
show_neighbors(ostream &out) const {
|
|
Edges::const_iterator ei;
|
|
Edge::Strips::const_iterator si;
|
|
|
|
for (ei = _edges.begin(); ei != _edges.end(); ++ei) {
|
|
for (si = (*ei)->_strips.begin();
|
|
si != (*ei)->_strips.end();
|
|
++si) {
|
|
out << " " << (*si)->_index;
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::find_uncommon_vertex
|
|
// Access: Public
|
|
// Description: Returns the first vertex found that is not shared by
|
|
// the given edge.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
const MesherStrip<PrimType>::Vertex *MesherStrip<PrimType>::
|
|
find_uncommon_vertex(const Edge *edge) const {
|
|
const Vertex *a = edge->_a;
|
|
const Vertex *b = edge->_b;
|
|
|
|
Edges::const_iterator ei;
|
|
for (ei = _edges.begin(); ei != _edges.end(); ++ei) {
|
|
Edge *e = (*ei);
|
|
|
|
if (e->_a != a && e->_a != b) {
|
|
return e->_a;
|
|
} else if (e->_b != a && e->_b != b) {
|
|
return e->_b;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::find_opposite_edge
|
|
// Access: Public
|
|
// Description: Returns the first edge found that does not contain
|
|
// the given vertex. In a tri, this will be the edge
|
|
// opposite the given vertex.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
const MesherStrip<PrimType>::Edge *MesherStrip<PrimType>::
|
|
find_opposite_edge(const Vertex *vertex) const {
|
|
Edges::const_iterator ei;
|
|
for (ei = _edges.begin(); ei != _edges.end(); ++ei) {
|
|
Edge *e = (*ei);
|
|
if (!e->contains_vertex(vertex)) {
|
|
return e;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::find_opposite_edge
|
|
// Access: Public
|
|
// Description: Returns the first edge found that shares no vertices
|
|
// with the given edge. In a quad, this will be the
|
|
// edge opposite the given edge.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
const MesherStrip<PrimType>::Edge *MesherStrip<PrimType>::
|
|
find_opposite_edge(const Edge *edge) const {
|
|
const Vertex *a = edge->_a;
|
|
const Vertex *b = edge->_b;
|
|
|
|
Edges::const_iterator ei;
|
|
for (ei = _edges.begin(); ei != _edges.end(); ++ei) {
|
|
Edge *e = (*ei);
|
|
if (!e->contains_vertex(a) && !e->contains_vertex(b)) {
|
|
return e;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::find_adjacent_edge
|
|
// Access: Public
|
|
// Description: Returns the first edge found that shares exactly one
|
|
// vertex with the given edge. In a quad, this will be
|
|
// one of two edges adjacent to the given edge.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
const MesherStrip<PrimType>::Edge *MesherStrip<PrimType>::
|
|
find_adjacent_edge(const Edge *edge) const {
|
|
const Vertex *a = edge->_a;
|
|
const Vertex *b = edge->_b;
|
|
|
|
Edges::const_iterator ei;
|
|
for (ei = _edges.begin(); ei != _edges.end(); ++ei) {
|
|
Edge *e = (*ei);
|
|
if (e->contains_vertex(a) != e->contains_vertex(b)) {
|
|
return e;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::rotate_to_front
|
|
// Access: Public
|
|
// Description: Rotates a triangle or quad so that the given edge is
|
|
// first in the vertex list.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
void MesherStrip<PrimType>::
|
|
rotate_to_front(const Edge *edge) {
|
|
const Vertex *a = edge->_a;
|
|
const Vertex *b = edge->_b;
|
|
|
|
// See if we're already there.
|
|
if (_verts.front() == a || _verts.front() == b) {
|
|
Verts::iterator vi = _verts.begin();
|
|
++vi;
|
|
if (*vi == a || *vi == b) {
|
|
// Yes!
|
|
return;
|
|
}
|
|
|
|
// No, we must be right on the line. Roll back one.
|
|
rotate_back();
|
|
|
|
} else {
|
|
// Roll forward until it comes into view.
|
|
int num_verts = _verts.size();
|
|
while (_verts.front() != a && _verts.front() != b) {
|
|
// Make sure either vertex exists.
|
|
num_verts--;
|
|
nassertv(num_verts > 0);
|
|
rotate_forward();
|
|
}
|
|
}
|
|
|
|
// Now make sure the edge actually exists.
|
|
Verts::iterator vi = _verts.begin();
|
|
++vi;
|
|
nassertv(*vi == a || *vi == b);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::rotate_to_back
|
|
// Access: Public
|
|
// Description: Rotates a triangle or quad so that the given edge is
|
|
// last in the vertex list.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
void MesherStrip<PrimType>::
|
|
rotate_to_back(const Edge *edge) {
|
|
const Vertex *a = edge->_a;
|
|
const Vertex *b = edge->_b;
|
|
|
|
// See if we're already there.
|
|
if (_verts.back() == a || _verts.back() == b) {
|
|
Verts::reverse_iterator vi = _verts.rbegin();
|
|
++vi;
|
|
if (*vi == a || *vi == b) {
|
|
// Yes!
|
|
return;
|
|
}
|
|
|
|
// No, we must be right on the line. Roll forward one.
|
|
rotate_forward();
|
|
|
|
} else {
|
|
// Roll backward until it comes into view.
|
|
int num_verts = _verts.size();
|
|
while (_verts.back() != a && _verts.back() != b) {
|
|
// Make sure either vertex exists.
|
|
num_verts--;
|
|
nassertv(num_verts > 0);
|
|
rotate_back();
|
|
}
|
|
}
|
|
|
|
// Now make sure the edge actually exists.
|
|
Verts::reverse_iterator vi = _verts.rbegin();
|
|
++vi;
|
|
nassertv(*vi == a || *vi == b);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::can_invert
|
|
// Access: Public
|
|
// Description: Returns true if the strip can be inverted (reverse
|
|
// its facing direction). Generally, this is true for
|
|
// quadstrips and false for tristrips.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
bool MesherStrip<PrimType>::
|
|
can_invert() const {
|
|
return (_type==BPT_quadstrip || _type==BPT_quad);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::invert
|
|
// Access: Public
|
|
// Description: Reverses the facing of a quadstrip by reversing pairs
|
|
// of vertices. Returns true if successful, false if
|
|
// failure (for instance, on a tristrip).
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
bool MesherStrip<PrimType>::
|
|
invert() {
|
|
if (!can_invert()) {
|
|
return false;
|
|
}
|
|
Verts::iterator vi, vi2;
|
|
vi = _verts.begin();
|
|
while (vi != _verts.end()) {
|
|
vi2 = vi;
|
|
++vi2;
|
|
nassertr(vi2 != _verts.end(), false);
|
|
|
|
// Exchange vi and vi2
|
|
const Vertex *t = *vi2;
|
|
*vi2 = *vi;
|
|
*vi = t;
|
|
|
|
// Increment
|
|
vi = vi2;
|
|
++vi;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::is_odd
|
|
// Access: Public
|
|
// Description: Returns true if the tristrip or quadstrip contains an
|
|
// odd number of pieces.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
bool MesherStrip<PrimType>::
|
|
is_odd() const {
|
|
if (_type==BPT_quadstrip || _type==BPT_quad) {
|
|
// If a quadstrip has a multiple of four vertices, it has an
|
|
// odd number of quads.
|
|
return (_verts.size()%4 == 0);
|
|
} else {
|
|
// If a tristrip has an odd number of vertices, it has an odd
|
|
// number of tris.
|
|
return (_verts.size()%2 == 1);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::would_reverse_tail
|
|
// Access: Public
|
|
// Description: Returns true if convert_to_type() would reverse the
|
|
// tail edge of the given strip, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
bool MesherStrip<PrimType>::
|
|
would_reverse_tail(BuilderPrimType wantType) const {
|
|
bool reverse = false;
|
|
|
|
if (_type==wantType) {
|
|
return false;
|
|
}
|
|
if (wantType==BPT_tristrip) {
|
|
switch (_type) {
|
|
case BPT_tri:
|
|
case BPT_tristrip:
|
|
break;
|
|
|
|
case BPT_quad:
|
|
case BPT_quadstrip:
|
|
// When we convert a quadstrip to a tristrip, we reverse the
|
|
// tail edge if we have a multiple of four verts.
|
|
reverse = (_verts.size()%4==0);
|
|
break;
|
|
|
|
default:
|
|
builder_cat.fatal() << "Invalid conversion!\n";
|
|
abort();
|
|
break;
|
|
}
|
|
|
|
} else if (wantType==BPT_quadstrip) {
|
|
switch (_type) {
|
|
case BPT_quad:
|
|
case BPT_quadstrip:
|
|
break;
|
|
|
|
case BPT_tri:
|
|
case BPT_tristrip:
|
|
// We don't convert tristrips to quadstrips; fall through.
|
|
|
|
default:
|
|
builder_cat.fatal() << "Invalid conversion!\n";
|
|
abort();
|
|
break;
|
|
}
|
|
}
|
|
|
|
return reverse;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::convert_to_type
|
|
// Access: Public
|
|
// Description: Converts the MesherStrip from whatever form it
|
|
// is--triangle, quad, or quadstrip--into a tristrip or
|
|
// quadstrip.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
void MesherStrip<PrimType>::
|
|
convert_to_type(BuilderPrimType wantType) {
|
|
Verts::iterator vi, vi2;
|
|
int even;
|
|
|
|
if (_type==wantType) {
|
|
return;
|
|
}
|
|
if (wantType==BPT_tristrip) {
|
|
switch (_type) {
|
|
case BPT_tri:
|
|
case BPT_tristrip:
|
|
break;
|
|
|
|
case BPT_quad:
|
|
case BPT_quadstrip:
|
|
// To convert from quad/quadstrip to tristrip, we reverse every other
|
|
// pair of vertices.
|
|
|
|
vi = _verts.begin();
|
|
even = 0;
|
|
while (vi != _verts.end()) {
|
|
vi2 = vi;
|
|
++vi2;
|
|
nassertv(vi2 != _verts.end());
|
|
|
|
// vi and vi2 are a pair. Should we reverse them?
|
|
if (even) {
|
|
const Vertex *t = *vi2;
|
|
*vi2 = *vi;
|
|
*vi = t;
|
|
}
|
|
|
|
// Increment
|
|
vi = vi2;
|
|
++vi;
|
|
even = !even;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
builder_cat.fatal() << "Invalid conversion!\n";
|
|
abort();
|
|
}
|
|
|
|
} else if (wantType==BPT_quadstrip) {
|
|
switch (_type) {
|
|
case BPT_quad:
|
|
case BPT_quadstrip:
|
|
break;
|
|
|
|
case BPT_tri:
|
|
case BPT_tristrip:
|
|
// We don't convert tristrips to quadstrips; fall through.
|
|
|
|
default:
|
|
builder_cat.fatal() << "Invalid conversion!\n";
|
|
abort();
|
|
}
|
|
}
|
|
|
|
_type = wantType;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::combine_edges
|
|
// Access: Public
|
|
// Description: Removes the edges from the given strip and appends
|
|
// them to our own. If removeSides is true, then
|
|
// removes all the edges except the head and the tail.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
void MesherStrip<PrimType>::
|
|
combine_edges(MesherStrip<PrimType> &other, int removeSides) {
|
|
Edges::iterator ei;
|
|
for (ei = other._edges.begin(); ei != other._edges.end(); ++ei) {
|
|
(*ei)->change_strip(&other, this);
|
|
}
|
|
|
|
_edges.splice(_edges.end(), other._edges);
|
|
|
|
if (removeSides) {
|
|
// Identify the head and tail edges so we can remove everything
|
|
// else.
|
|
Edge head = get_head_edge();
|
|
Edge tail = get_tail_edge();
|
|
|
|
if (!is_odd()) {
|
|
// If the strip is odd, its true tail edge is the inverse of its
|
|
// actual edge.
|
|
tail = Edge(tail._b, tail._a);
|
|
}
|
|
|
|
Edges junk_edges;
|
|
|
|
Edges::iterator next_ei;
|
|
ei = _edges.begin();
|
|
while (ei != _edges.end()) {
|
|
next_ei = ei;
|
|
++next_ei;
|
|
|
|
// Is this edge to be saved or is it fodder?
|
|
if (!(**ei == head) && !(**ei == tail)) {
|
|
// Fodder! But we can't remove it right away, because this
|
|
// will upset the current list; instead, we'll splice it to
|
|
// junk_edges.
|
|
junk_edges.splice(junk_edges.end(), _edges, ei);
|
|
}
|
|
ei = next_ei;
|
|
}
|
|
|
|
// Now we can safely remove all the to-be-junked edges.
|
|
for (ei = junk_edges.begin(); ei != junk_edges.end(); ++ei) {
|
|
(*ei)->remove(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::remove_all_edges
|
|
// Access: Public
|
|
// Description: Removes all active edges from the strip. This
|
|
// effectively renders it ineligible to mate with
|
|
// anything else.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
void MesherStrip<PrimType>::
|
|
remove_all_edges() {
|
|
// First, move all the edges to a safe place so we can traverse the
|
|
// list without it changing on us.
|
|
Edges junk_edges;
|
|
junk_edges.splice(junk_edges.end(), _edges);
|
|
|
|
// Now we can safely remove all the to-be-junked edges.
|
|
Edges::iterator ei;
|
|
for (ei = junk_edges.begin(); ei != junk_edges.end(); ++ei) {
|
|
(*ei)->remove(this);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::pick_mate
|
|
// Access: Public
|
|
// Description: Defines an ordering to select neighbors to mate with.
|
|
// This compares strip a with strip b and returns true
|
|
// if strip a is the preferable choice, false if strip
|
|
// b.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
bool MesherStrip<PrimType>::
|
|
pick_mate(const MesherStrip &a_strip, const MesherStrip &b_strip,
|
|
const Edge &a_edge, const Edge &b_edge,
|
|
const BuilderBucket &bucket) const {
|
|
// First, try to avoid polluting quads, quadstrips, and tristrips
|
|
// with arbitrary triangles. When we mate a tri or tristrip to a
|
|
// quadstrip, we end up with a tristrip that may be less versatile
|
|
// than the original quadstrip. Better to avoid this if we can.
|
|
// Try to choose a mate that more closely matches our own type.
|
|
int a_cat = a_strip.type_category();
|
|
int b_cat = b_strip.type_category();
|
|
if (a_cat != b_cat) {
|
|
int me_cat = type_category();
|
|
return abs(a_cat - me_cat) < abs(b_cat - me_cat);
|
|
}
|
|
|
|
// Now, if we're connecting two tris, try to connect them up so they
|
|
// make good quads.
|
|
if (_type == BPT_tri && a_strip._type == BPT_tri &&
|
|
b_strip._type == BPT_tri) {
|
|
|
|
// This will depend on both coplanarity and edge length. We can't
|
|
// use just one or the other, because some tris are nearly
|
|
// isosceles, and some have more than one coplanar neighbor.
|
|
// Hopefully the combination of both factors will zero us in on
|
|
// the correct neighbor first.
|
|
|
|
double a_coplanar = coplanarity(a_strip);
|
|
double b_coplanar = coplanarity(b_strip);
|
|
double coplanar_diff = a_coplanar - b_coplanar;
|
|
|
|
double a_length = a_edge.compute_length(bucket);
|
|
double b_length = b_edge.compute_length(bucket);
|
|
double length_diff = (a_length - b_length) / (a_length + b_length);
|
|
|
|
// These weights were chosen empirically to yield fairly good results.
|
|
double sum = 4.0 * coplanar_diff - 1.0 * length_diff;
|
|
return sum < 0;
|
|
}
|
|
|
|
// Then, get the smallest strip.
|
|
if (a_strip._prims.size() != b_strip._prims.size()) {
|
|
return a_strip._prims.size() < b_strip._prims.size();
|
|
}
|
|
|
|
// Finally, get the strip with the fewest neighbors.
|
|
return a_strip.count_neighbors() < b_strip.count_neighbors();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::pick_sheet_mate
|
|
// Access: Public
|
|
// Description: Defines an ordering to select neighbors to follow
|
|
// when measuring out a quadsheet. This is only called
|
|
// when three or more prims share a single edge, which
|
|
// should be rarely--generally only when coplanar polys
|
|
// are going on.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
bool MesherStrip<PrimType>::
|
|
pick_sheet_mate(const MesherStrip &a_strip, const MesherStrip &b_strip) const {
|
|
// First, try to get the poly which is closest to our own normal.
|
|
if (_planar && a_strip._planar && b_strip._planar) {
|
|
float a_diff = dot(_plane_normal, a_strip._plane_normal);
|
|
float b_diff = dot(_plane_normal, b_strip._plane_normal);
|
|
|
|
if (fabs(a_diff - b_diff) > 0.0001) {
|
|
return a_diff > b_diff;
|
|
}
|
|
}
|
|
|
|
// Then, pick the one that's most like our own type.
|
|
int a_cat = a_strip.type_category();
|
|
int b_cat = b_strip.type_category();
|
|
if (a_cat != b_cat) {
|
|
int me_cat = type_category();
|
|
return abs(a_cat - me_cat) < abs(b_cat - me_cat);
|
|
}
|
|
|
|
// Oh, just pick any old one.
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: MesherStrip::output
|
|
// Access: Public
|
|
// Description: Formats the vertex for output in some sensible way.
|
|
////////////////////////////////////////////////////////////////////
|
|
template <class PrimType>
|
|
ostream &MesherStrip<PrimType>::
|
|
output(ostream &out) const {
|
|
switch (_status) {
|
|
case MS_alive:
|
|
break;
|
|
|
|
case MS_dead:
|
|
out << "Dead ";
|
|
break;
|
|
|
|
case MS_done:
|
|
out << "Done ";
|
|
break;
|
|
|
|
default:
|
|
out << "Unknown status ";
|
|
}
|
|
|
|
switch (_type) {
|
|
case BPT_tri:
|
|
out << "Tri";
|
|
break;
|
|
|
|
case BPT_quad:
|
|
out << "Quad";
|
|
break;
|
|
|
|
case BPT_tristrip:
|
|
out << "TriStrip";
|
|
break;
|
|
|
|
case BPT_trifan:
|
|
out << "TriFan";
|
|
break;
|
|
|
|
case BPT_quadstrip:
|
|
out << "QuadStrip";
|
|
break;
|
|
|
|
default:
|
|
out << "Unknown";
|
|
}
|
|
|
|
if (_planar) {
|
|
out << " (planar)";
|
|
}
|
|
|
|
out << " " << _index << " [";
|
|
|
|
Verts::const_iterator vi;
|
|
for (vi = _verts.begin(); vi != _verts.end(); vi++) {
|
|
out << " " << **vi;
|
|
}
|
|
out << " ]: " << _prims.size()
|
|
<< " prims, " << count_neighbors() << " neighbors";
|
|
|
|
show_neighbors(out);
|
|
|
|
out << " edges";
|
|
Edges::const_iterator ei;
|
|
for (ei = _edges.begin(); ei != _edges.end(); ei++) {
|
|
out << " " << (void *)(*ei);
|
|
}
|
|
|
|
return out << ".";
|
|
}
|
|
|