open_toontown_panda3d/panda/src/builder/mesherTempl.I

670 lines
19 KiB
Plaintext

// Filename: mesherTempl.I
// Created by: drose (15Sep97)
//
////////////////////////////////////////////////////////////////////
//
// 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 "builderMisc.h"
#include "mesherStrip.h"
#include "mesherFanMaker.h"
#include "config_builder.h"
#include <algorithm>
template <class PrimType>
MesherTempl<PrimType>::
MesherTempl(BuilderBucket *bucket) {
_bucket = bucket;
_stripIndex = 0;
_next_strip = _done.end();
}
template <class PrimType>
int MesherTempl<PrimType>::
add_prim(const Prim &prim, MesherStripOrigin origin) {
if (!prim.is_valid()) {
return false;
}
// Define an initial strip (probably of length 1) for the prim.
Strip temp_strip(prim, _stripIndex++, *_bucket);
Strips &list = choose_strip_list(temp_strip);
list.push_back(temp_strip);
Strip &strip = list.back();
strip._origin = origin;
int i;
int num_verts = prim.get_num_verts();
const Vertex **vptrs = (const Vertex **)alloca(num_verts * sizeof(Vertex *));
EdgePtrs **eptrs = (EdgePtrs **)alloca(num_verts * sizeof(EdgePtrs *));
// Get the common vertex pointers for the primitive's vertices.
for (i = 0; i < num_verts; i++) {
Verts::iterator n =
_verts.insert(Verts::value_type(prim.get_vertex(i), EdgePtrs())).first;
vptrs[i] = &(*n).first;
eptrs[i] = &(*n).second;
strip._verts.push_back(vptrs[i]);
}
// Now identify the common edges.
if (prim.get_type() == BPT_tri || prim.get_type() == BPT_quad) {
// Polygons of arbitrary size don't get meshed, and so therefore
// don't have any edges in common with anything else. Only tris
// and quads can be meshed. (The builder normally breaks up
// larger polygons into tris, though the user can choose to defeat
// this.)
for (i = 0; i < num_verts; i++) {
// Define an inner and outer edge. A polygon shares an edge with a
// neighbor only when one of its inner edges matches a neighbor's
// outer edge (and vice-versa).
Edge inner(vptrs[i], vptrs[(i+1) % num_verts]);
Edge outer(vptrs[(i+1) % num_verts], vptrs[i]);
// Add it to the list and get its common pointer.
Edge &inner_ref = (Edge &)*_edges.insert(inner).first;
Edge &outer_ref = (Edge &)*_edges.insert(outer).first;
// Tell the edges about each other.
inner_ref._opposite = &outer_ref;
outer_ref._opposite = &inner_ref;
// Associate the common edge to the strip.
strip._edges.push_back(&inner_ref);
// Associate the strip, as well as the original prim, to the edge.
outer_ref._strips.push_back(&strip);
// Associate the common edge with the vertices that share it.
// Edge *edge_ptr = inner_ref.common_ptr();
eptrs[i]->insert(&outer_ref);
eptrs[(i+1) % num_verts]->insert(&outer_ref);
}
}
return true;
}
template <class PrimType>
void MesherTempl<PrimType>::
mesh() {
if (_bucket->_consider_fans) {
find_fans();
}
// First, we try to make all the best quads we can.
if (_bucket->_retesselate_coplanar) {
make_quads();
}
// Then, we do the rest of the tris.
meshList(_tris);
if (_bucket->_show_quads) {
// If we're showing quads, we shouldn't do any more meshing.
Strips::iterator si;
for (si = _quads.begin(); si != _quads.end(); ++si) {
if ((*si)._status == MS_alive) {
(*si)._status = MS_done;
}
}
for (si = _strips.begin(); si != _strips.end(); ++si) {
if ((*si)._status == MS_alive) {
(*si)._status = MS_done;
}
}
}
// Then, build quads into sheets where possible.
build_sheets();
// Pick up any quads that might have been left behind.
meshList(_quads);
// Finally, do the longer strips.
meshList(_strips);
// Get ready to walk through the results.
_next_strip = _done.begin();
}
template <class PrimType>
PrimType MesherTempl<PrimType>::
getPrim() {
if (_next_strip == _done.end()) {
// End of the list, return a primitive with no vertices.
finalize();
return Prim();
}
Strip &strip = (*_next_strip++);
BuilderPrimType orig_type = strip._type;
Prim prim = strip.make_prim(*_bucket);
if (_bucket->_show_tstrips) {
// If we have _show_tstrips enabled, it means we need to color
// every primitive according to which, if any, tristrip it is in.
// We use the _colors array--and later make a copy in shared
// memory for the bucket to point to--in case the primitives are
// indexed. If the primitives are nonindexed, we'll still
// allocate the _colors array and its copy in shared memory, but
// it will be deleted when the bucket destructs.
if (_colors.empty()) {
// We need one entry for not-a-tristrip, indicated by white.
_colors.push_back(Colorf(0.85, 0.85, 0.85, 1.0));
}
ushort i1, i2;
Colorf color1, color2;;
switch (prim.get_type()) {
case BPT_tristrip:
case BPT_trifan:
make_random_color(color2);
color1 = (color2 * 0.8); // somewhat darker.
i1 = _colors.size();
i2 = i1+1;
_colors.push_back(color1);
_colors.push_back(color2);
break;
default:
// not-a-tristrip.
i1 = i2 = 0;
}
// Now i1 and i2 index into the colors array to indicate the color
// for the first triangle and the rest of the primitive,
// respectively.
int num_components = prim.get_num_components();
if (num_components > 0) {
prim.get_component(0).set_color_value(&_colors[0], i1);
for (int i = 1; i < num_components; i++) {
prim.get_component(i).set_color_value(&_colors[0], i2);
}
} else {
prim.set_color_value(&_colors[0], i1);
}
} else if (_bucket->_show_qsheets) {
// _show_qsheets means to color every primitive according to
// which, if any, quadsheet it is in. This is a bit easier,
// because the entire primitive gets the same color.
if (_colors.empty()) {
// We need one entry for not-a-qsheet, indicated by white.
_colors.push_back(Colorf(0.85, 0.85, 0.85, 1.0));
}
// Is this a quadsheet?
ushort i1 = 0;
if (strip._row_id < 0) {
// Yep! Assign a new color, if it doesn't already have one.
ColorSheetMap::iterator ci = _color_sheets.find(strip._row_id);
if (ci == _color_sheets.end()) {
Colorf color1;
make_random_color(color1);
i1 = _colors.size();
_colors.push_back(color1);
_color_sheets[strip._row_id] = i1;
} else {
i1 = (*ci).second;
}
}
// Now i1 is the color we want to assign to the whole primitive.
// Just set all vertices to the same color.
int num_verts = prim.get_num_verts();
for (int i = 0; i < num_verts; i++) {
prim.get_vertex(i).set_color_value(&_colors[0], i1);
}
} else if (_bucket->_show_quads) {
// _show_quads means to show the assembling of tris into quads and fans.
// We use the following color convention:
// white: unchanged; as supplied by user.
// dark blue: quads made in the initial pass. These are more certain.
// light blue: quads made in the second pass. These are less certain.
// very light blue: quadstrips. These are unlikely to appear.
// random shades of red: triangles and tristrips.
// green: fans and retesselated fan polygons.
if (_colors.empty()) {
// We need a handful of entries.
_colors.push_back(Colorf(0.85, 0.85, 0.85, 1.0)); // default: white
_colors.push_back(Colorf(0.0, 0.0, 0.75, 1.0)); // dark blue
_colors.push_back(Colorf(0.4, 0.4, 0.8, 1.0)); // light blue
_colors.push_back(Colorf(0.6, 0.6, 1.0, 1.0)); // very light blue
_colors.push_back(Colorf(0.2, 0.8, 0.2, 1.0)); // green
}
ushort i1;
Colorf color1;
if (strip._origin == MO_user) {
i1 = 0;
} else if (strip._origin == MO_firstquad) {
i1 = 1;
} else if (strip._origin == MO_fanpoly) {
i1 = 4;
} else {
switch (orig_type) {
case BPT_quad:
i1 = 2;
break;
case BPT_quadstrip:
i1 = 3;
break;
case BPT_tristrip:
make_random_color(color1);
// Make it a shade of red.
if (color1[0] < color1[1]) {
float t = color1[0];
color1[0] = color1[1];
color1[1] = t;
}
color1[2] = color1[1];
i1 = _colors.size();
_colors.push_back(color1);
break;
case BPT_trifan:
make_random_color(color1);
// Make it a shade of green.
if (color1[0] > color1[1]) {
float t = color1[0];
color1[0] = color1[1];
color1[1] = t;
}
color1[2] = color1[0];
i1 = _colors.size();
_colors.push_back(color1);
break;
default:
i1 = 0;
}
}
// Now i1 is the color we want to assign to the whole primitive.
// Just set all vertices to the same color.
int num_verts = prim.get_num_verts();
for (int i = 0; i < num_verts; i++) {
prim.get_vertex(i).set_color_value(&_colors[0], i1);
}
}
return prim;
}
template <class PrimType>
void MesherTempl<PrimType>::
finalize() {
if (!_colors.empty()) {
// Create an array in the bucket we might use to add to geoms.
PTA_Colorf colors(_colors.size());
for (int i = 0; i < (int)_colors.size(); i++) {
colors[i] = _colors[i];
}
_bucket->set_colors(colors);
_colors.clear();
_color_sheets.clear();
}
}
template <class PrimType>
void MesherTempl<PrimType>::
show(ostream &out) {
/*
out << _edges.size() << " edges:\n";
copy(_edges.begin(), _edges.end(), ostream_iterator<Edge>(out, "\n"));
*/
out << _verts.size() << " verts:\n";
Verts::const_iterator vi;
for (vi = _verts.begin(); vi != _verts.end(); ++vi) {
const Vertex &v = (*vi).first;
const EdgePtrs &edges = (*vi).second;
out << v << " shares " << count_vert_edges(edges) << " edges:\n";
EdgePtrs::const_iterator ei;
for (ei = edges.begin(); ei != edges.end(); ++ei) {
if (!(*ei)->_strips.empty() || !(*ei)->_opposite->_strips.empty()) {
out << " " << **ei << "\n";
}
}
}
out << _tris.size() << " tris:\n";
copy(_tris.begin(), _tris.end(), ostream_iterator<Strip>(out, "\n"));
out << _quads.size() << " quads:\n";
copy(_quads.begin(), _quads.end(), ostream_iterator<Strip>(out, "\n"));
out << _strips.size() << " strips:\n";
copy(_strips.begin(), _strips.end(), ostream_iterator<Strip>(out, "\n"));
}
template <class PrimType>
int MesherTempl<PrimType>::
count_vert_edges(const EdgePtrs &edges) const {
int count = 0;
EdgePtrs::const_iterator ei;
for (ei = edges.begin(); ei != edges.end(); ++ei) {
count += (!(*ei)->_strips.empty() || !(*ei)->_opposite->_strips.empty());
}
return count;
}
template <class PrimType>
list<MesherTempl<PrimType>::Strip> &MesherTempl<PrimType>::
choose_strip_list(const Strip &strip) {
switch (strip._status) {
case MS_done:
return _done;
case MS_dead:
return _dead;
case MS_alive:
switch (strip._type) {
case BPT_tri:
return _tris;
case BPT_quad:
return _quads;
default:
return _strips;
}
default:
builder_cat.fatal() << "Invalid strip status!\n";
abort();
}
return _strips; // Unreachable; this is just to make the compiler happy.
}
template <class PrimType>
void MesherTempl<PrimType>::
build_sheets() {
int first_row_id = 1;
// First, move all the quads to our own internal list.
Strips pre_sheeted;
pre_sheeted.splice(pre_sheeted.end(), _quads);
while (!pre_sheeted.empty()) {
// Pick the first quad on the list.
Strips::iterator best = pre_sheeted.begin();
// If the row_id is negative, we've already built a sheet out of
// this quad. Leave it alone. We also need to leave it be if it
// has no available edges.
if ((*best)._row_id >= 0 &&
(*best)._status == MS_alive &&
!(*best)._edges.empty()) {
// There are two possible sheets we could make from this quad,
// in two different orientations. Measure them both and figure
// out which one is best.
const Edge *edge_a = (*best)._edges.front();
const Edge *edge_b = (*best).find_adjacent_edge(edge_a);
int num_prims_a = 0;
int num_rows_a = 0;
int first_row_id_a = first_row_id;
(*best).measure_sheet(edge_a, true, num_prims_a, num_rows_a,
first_row_id_a, 0, 0);
first_row_id += num_rows_a;
double avg_length_a = (double)num_prims_a / (double)num_rows_a;
int num_prims_b = 0;
int num_rows_b = 0;
int first_row_id_b = first_row_id;
double avg_length_b;
if (edge_b != NULL) {
(*best).measure_sheet(edge_b, true, num_prims_b, num_rows_b,
first_row_id_b, 0, 0);
first_row_id += num_rows_b;
avg_length_b = (double)num_prims_b / (double)num_rows_b;
}
// Which sheet is better?
if (edge_b != NULL && avg_length_b >= avg_length_a) {
// Sheet b. That's easy.
(*best).cut_sheet(first_row_id_b, true, *_bucket);
} else {
// Nope, sheet a is better. This is a bit of a nuisance
// because we've unfortunately wiped out the information we
// stored when we measured sheet a. We'll have to do it
// again.
num_prims_a = 0;
num_rows_a = 0;
first_row_id_a = first_row_id;
(*best).measure_sheet(edge_a, true, num_prims_a, num_rows_a,
first_row_id_a, 0, 0);
first_row_id += num_rows_a;
// Now we can cut it.
(*best).cut_sheet(first_row_id_a, true, *_bucket);
}
}
// Now put it somewhere. We'll never see this quad again in
// build_sheets().
Strips &list = choose_strip_list(*best);
list.splice(list.end(), pre_sheeted, best);
}
}
template <class PrimType>
void MesherTempl<PrimType>::
find_fans() {
#ifdef SUPPORT_FANS
// Consider all vertices. Any vertex with over a certain number of
// edges connected to it is eligible to become a fan.
Verts::iterator vi;
for (vi = _verts.begin(); vi != _verts.end(); ++vi) {
EdgePtrs &edges = (*vi).second;
// 14 is the magic number of edges. 12 edges or fewer are likely
// to be found on nearly every vertex in a quadsheet (six edges
// times two, one each way). We don't want to waste time fanning
// out each vertex of a quadsheet, and we don't want to break up
// 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;
// Build up a list of far fan edges.
typedef vector<FanMaker> FanMakers;
FanMakers fans;
EdgePtrs::iterator ei;
Edge::Strips::iterator si;
for (ei = edges.begin(); ei != edges.end(); ++ei) {
for (si = (*ei)->_strips.begin();
si != (*ei)->_strips.end();
++si) {
Strip *strip = *si;
if (strip->_type == BPT_tri) {
fans.push_back(FanMaker(&v, strip, this));
}
}
}
// Sort the fans list by edge pointers, and remove duplicates.
sort(fans.begin(), fans.end());
fans.erase(unique(fans.begin(), fans.end()),
fans.end());
FanMakers::iterator fi, fi2;
// Now pull out connected edges.
int joined_any;
do {
joined_any = false;
for (fi = fans.begin(); fi != fans.end(); ++fi) {
if (!(*fi).is_empty()) {
fi2 = fi;
for (++fi2; fi2 != fans.end(); ++fi2) {
if (!(*fi2).is_empty()) {
joined_any = (*fi).join(*fi2);
}
}
}
}
} while (joined_any);
for (fi = fans.begin(); fi != fans.end(); ++fi) {
if ((*fi).is_valid()) {
(*fi).build();
}
}
}
}
#endif
}
////////////////////////////////////////////////////////////////////
// Function: MesherTempl::make_quads
// Access: Public
// Description: Attempts to join up all the single tris to its
// neighbor and reconstruct a pattern of quads, suitable
// for making into quadsheets or at least quadstrips.
////////////////////////////////////////////////////////////////////
template <class PrimType>
void MesherTempl<PrimType>::
make_quads() {
// Ideally, we want to match tris across their hypotenuse to make a
// pattern of quads. (This assumes that we are working with a
// triangulated mesh pattern, of course. If we have some other
// pattern of tris, all bets are off and it doesn't really matter
// anyway.)
// First, we'll find all the tris that have no doubt about their
// ideal mate, and pair them up right away. The others we'll get to
// later. This way, the uncertain matches won't pollute the quad
// alignment for everyone else.
typedef pair<Strip *, Strip *> Pair;
typedef pair<Pair, Edge *> Matched;
typedef vector<Matched> SoulMates;
SoulMates soulmates;
Strip *tri, *mate, *mate2;
Edge *common_edge, *common_edge2;
Strips::iterator si;
for (si = _tris.begin(); si != _tris.end(); ++si) {
tri = &(*si);
if (tri->_status == MS_alive) {
if (tri->find_ideal_mate(mate, common_edge, *_bucket)) {
// Does our chosen mate want us too?
if (mate->_type == BPT_tri && mate->_status == MS_alive &&
mate->find_ideal_mate(mate2, common_edge2, *_bucket) &&
mate2 == tri) {
// Hooray!
soulmates.push_back(Matched(Pair(tri, mate), common_edge));
// We'll temporarily mark the two tris as paired.
tri->_status = MS_paired;
mate->_status = MS_paired;
}
}
}
}
// Now that we've found all the tris that are sure about each other,
// mate them.
SoulMates::iterator mi;
for (mi = soulmates.begin(); mi != soulmates.end(); ++mi) {
tri = (*mi).first.first;
mate = (*mi).first.second;
common_edge = (*mi).second;
nassertv(tri->_status == MS_paired);
nassertv(mate->_status == MS_paired);
tri->_status = MS_alive;
mate->_status = MS_alive;
Strip::mate_pieces(common_edge, *tri, *mate, *_bucket);
tri->_origin = MO_firstquad;
}
// Now move all the strips off the tri list that no longer belong.
Strips::iterator next;
si = _tris.begin();
while (si != _tris.end()) {
next = si;
++next;
Strips &list = choose_strip_list(*si);
if (&list != &_tris) {
list.splice(list.end(), _tris, si);
}
si = next;
}
}
template <class PrimType>
void MesherTempl<PrimType>::
meshList(Strips &strips) {
while (!strips.empty()) {
// Pick the first strip on the list.
Strips::iterator best = strips.begin();
if ((*best)._status == MS_alive) {
(*best).mate(*_bucket);
}
// Put the strip back on the end of whichever list it wants. This
// might be the same list, if the strip is still alive, or it
// might be _done or _dead.
Strips &list = choose_strip_list(*best);
list.splice(list.end(), strips, best);
}
}