open_toontown_panda3d/panda/src/builder/builderFuncs.I

934 lines
26 KiB
Plaintext

// Filename: builderFuncs.I
// Created by: drose (09Sep97)
//
////////////////////////////////////////////////////////////////////
//
// 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 "builderPrim.h"
#include "mesherTempl.h"
#include "builderNormalVisualizer.h"
#include "config_builder.h"
#include "geom.h"
#include "geomprimitives.h"
#include <algorithm>
struct DecompVtx {
int index;
BuilderV coord;
struct DecompVtx *next;
};
////////////////////////////////////////////////////////////////////
// Function: decomp_concave
// Description: Decomposes a concave polygon into triangles. Returns
// true if successful, false if the polygon is
// self-intersecting.
////////////////////////////////////////////////////////////////////
template <class PrimType, class OutputIterator>
static bool
decomp_concave(const PrimType &prim, BuilderBucket &bucket,
OutputIterator result,
int asum, int x, int y) {
#define VX(p, c) p->coord[c]
pvector<PrimType> output_prims;
DecompVtx *p0, *p1, *p2, *t0, *vert;
DecompVtx *m[3];
float xmin, xmax, ymin, ymax;
int i, init, csum, chek;
float a[3], b[3], c[3], s[3];
int num_verts = prim.get_num_verts();
nassertr(num_verts >= 3, false);
/* Make linked list of verts */
vert = (DecompVtx *) alloca(sizeof(DecompVtx));
vert->index = 0;
vert->coord = prim.get_vertex(0).get_coord_value(bucket);
p1 = vert;
for (i = 1; i < num_verts; i++) {
p0 = (DecompVtx *) alloca(sizeof(DecompVtx));
p0->index = i;
p0->coord = prim.get_vertex(i).get_coord_value(bucket);
// There shouldn't be two consecutive identical vertices. If
// there are, skip one.
if (!(p0->coord == p1->coord)) {
p1->next = p0;
p1 = p0;
}
}
p1->next = vert;
p0 = vert;
p1 = p0->next;
p2 = p1->next;
m[0] = p0;
m[1] = p1;
m[2] = p2;
chek = 0;
while (p0 != p2->next) {
/* Polygon is self-intersecting so punt */
if (chek &&
m[0] == p0 &&
m[1] == p1 &&
m[2] == p2) {
// builder_cat.info() << "Could not decompose concave polygon!";
return false;
}
chek = 1;
a[0] = VX(p1, y) - VX(p2, y);
b[0] = VX(p2, x) - VX(p1, x);
a[2] = VX(p0, y) - VX(p1, y);
b[2] = VX(p1, x) - VX(p0, x);
csum = ((b[0] * a[2] - b[2] * a[0] >= 0.0) ? 1 : 0);
if (csum ^ asum) {
/* current angle is concave */
p0 = p1;
p1 = p2;
p2 = p2->next;
} else {
/* current angle is convex */
xmin = (VX(p0, x) < VX(p1, x)) ? VX(p0, x) : VX(p1, x);
if (xmin > VX(p2, x))
xmin = VX(p2, x);
xmax = (VX(p0, x) > VX(p1, x)) ? VX(p0, x) : VX(p1, x);
if (xmax < VX(p2, x))
xmax = VX(p2, x);
ymin = (VX(p0, y) < VX(p1, y)) ? VX(p0, y) : VX(p1, y);
if (ymin > VX(p2, y))
ymin = VX(p2, y);
ymax = (VX(p0, y) > VX(p1, y)) ? VX(p0, y) : VX(p1, y);
if (ymax < VX(p2, y))
ymax = VX(p2, y);
for (init = 1, t0 = p2->next; t0 != p0; t0 = t0->next) {
if (VX(t0, x) >= xmin && VX(t0, x) <= xmax &&
VX(t0, y) >= ymin && VX(t0, y) <= ymax) {
if (init) {
a[1] = VX(p2, y) - VX(p0, y);
b[1] = VX(p0, x) - VX(p2, x);
init = 0;
c[0] = VX(p1, x) * VX(p2, y) - VX(p2, x) * VX(p1, y);
c[1] = VX(p2, x) * VX(p0, y) - VX(p0, x) * VX(p2, y);
c[2] = VX(p0, x) * VX(p1, y) - VX(p1, x) * VX(p0, y);
}
s[0] = a[0] * VX(t0, x) + b[0] * VX(t0, y) + c[0];
s[1] = a[1] * VX(t0, x) + b[1] * VX(t0, y) + c[1];
s[2] = a[2] * VX(t0, x) + b[2] * VX(t0, y) + c[2];
if (asum) {
if (s[0] >= 0.0 && s[1] >= 0.0 && s[2] >= 0.0)
break;
} else {
if (s[0] <= 0.0 && s[1] <= 0.0 && s[2] <= 0.0)
break;
}
}
}
if (t0 != p0) {
p0 = p1;
p1 = p2;
p2 = p2->next;
} else {
PrimType new_prim(prim);
new_prim.set_type(BPT_tri);
new_prim.clear_vertices();
new_prim.add_vertex(prim.get_vertex(p0->index));
new_prim.add_vertex(prim.get_vertex(p1->index));
new_prim.add_vertex(prim.get_vertex(p2->index));
output_prims.push_back(new_prim);
p0->next = p1->next;
p1 = p2;
p2 = p2->next;
m[0] = p0;
m[1] = p1;
m[2] = p2;
chek = 0;
}
}
}
PrimType new_prim(prim);
new_prim.set_type(BPT_tri);
new_prim.clear_vertices();
new_prim.add_vertex(prim.get_vertex(p0->index));
new_prim.add_vertex(prim.get_vertex(p1->index));
new_prim.add_vertex(prim.get_vertex(p2->index));
output_prims.push_back(new_prim);
copy(output_prims.begin(), output_prims.end(), result);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: triangulate_poly
// Description: Breaks a (possibly concave) higher-order polygon into
// a series of constituent triangles.
////////////////////////////////////////////////////////////////////
template <class PrimType, class OutputIterator>
static bool
triangulate_poly(const PrimType &prim, BuilderBucket &bucket,
OutputIterator result) {
BuilderV p0, p1, as;
float dx1, dy1, dx2, dy2, max;
int i, flag, asum, csum, index, x, y, v0, v1, v, even;
// First see if the polygon is just a triangle
int num_verts = prim.get_num_verts();
if (num_verts == 3) {
PrimType new_prim(prim);
new_prim.set_type(BPT_tri);
*result++ = new_prim;
return true;
} else if (num_verts < 3) {
// Or if it's a degenerate polygon.
return false;
}
// calculate signed areas
as[0] = 0.0;
as[1] = 0.0;
as[2] = 0.0;
for (i = 0; i < num_verts; i++) {
p0 = prim.get_vertex(i).get_coord_value(bucket);
p1 = prim.get_vertex((i + 1) % num_verts).get_coord_value(bucket);
as[0] += p0[0] * p1[1] - p0[1] * p1[0];
as[1] += p0[0] * p1[2] - p0[2] * p1[0];
as[2] += p0[1] * p1[2] - p0[2] * p1[1];
}
/* select largest signed area */
max = 0.0;
index = 0;
flag = 0;
for (i = 0; i < 3; i++) {
if (as[i] >= 0.0) {
if (as[i] > max) {
max = as[i];
index = i;
flag = 1;
}
} else {
as[i] = -as[i];
if (as[i] > max) {
max = as[i];
index = i;
flag = 0;
}
}
}
/* pointer offsets */
switch (index) {
case 0:
x = 0;
y = 1;
break;
case 1:
x = 0;
y = 2;
break;
default: // case 2
x = 1;
y = 2;
break;
}
/* concave check */
p0 = prim.get_vertex(0).get_coord_value(bucket);
p1 = prim.get_vertex(1).get_coord_value(bucket);
dx1 = p1[x] - p0[x];
dy1 = p1[y] - p0[y];
p0 = p1;
p1 = prim.get_vertex(2).get_coord_value(bucket);
dx2 = p1[x] - p0[x];
dy2 = p1[y] - p0[y];
asum = ((dx1 * dy2 - dx2 * dy1 >= 0.0) ? 1 : 0);
for (i = 0; i < num_verts - 1; i++) {
p0 = p1;
p1 = prim.get_vertex((i+3) % num_verts).get_coord_value(bucket);
dx1 = dx2;
dy1 = dy2;
dx2 = p1[x] - p0[x];
dy2 = p1[y] - p0[y];
csum = ((dx1 * dy2 - dx2 * dy1 >= 0.0) ? 1 : 0);
if (csum ^ asum) {
return decomp_concave(prim, bucket, result, flag, x, y);
}
}
v0 = 0;
v1 = 1;
v = num_verts - 1;
even = 1;
/*
* Convert to triangles only. Do not fan out from a single vertex
* but zigzag into triangle strip.
*/
for (i = 0; i < num_verts - 2; i++) {
if (even) {
PrimType new_prim(prim);
new_prim.set_type(BPT_tri);
new_prim.clear_vertices();
new_prim.add_vertex(prim.get_vertex(v0));
new_prim.add_vertex(prim.get_vertex(v1));
new_prim.add_vertex(prim.get_vertex(v));
*result++ = new_prim;
v0 = v1;
v1 = v;
v = v0 + 1;
} else {
PrimType new_prim(prim);
new_prim.set_type(BPT_tri);
new_prim.clear_vertices();
new_prim.add_vertex(prim.get_vertex(v1));
new_prim.add_vertex(prim.get_vertex(v0));
new_prim.add_vertex(prim.get_vertex(v));
*result++ = new_prim;
v0 = v1;
v1 = v;
v = v0 - 1;
}
even = !even;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: expand_polys
// Description: Identifies a single polygon as a triangle, quad, or
// higher-order polygon, and writes it into the result
// list.
////////////////////////////////////////////////////////////////////
template <class PrimType, class OutputIterator>
static bool
expand_polys(PrimType &prim, BuilderBucket &,
OutputIterator result) {
switch (prim.get_num_verts()) {
case 0:
case 1:
case 2:
return false;
case 3:
prim.set_type(BPT_tri);
break;
case 4:
prim.set_type(BPT_quad);
break;
default:
prim.set_type(BPT_poly);
}
*result++ = prim;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: expand_points
// Description: Expands a light points primitive into its individual
// component points, with one point per primitive.
////////////////////////////////////////////////////////////////////
template <class PrimType, class OutputIterator>
static bool
expand_points(const PrimType &prim, BuilderBucket &,
OutputIterator result) {
// Each vertex goes in its own primitive.
int num_verts = prim.get_num_verts();
for (int i = 0; i < num_verts; i++) {
PrimType new_prim(prim);
new_prim.clear_vertices();
new_prim.add_vertex(prim.get_vertex(i));
*result++ = new_prim;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: expand_lines
// Description: Expands a linestrip primitive into its component line
// primitives.
////////////////////////////////////////////////////////////////////
template <class PrimType, class OutputIterator>
static bool
expand_lines(PrimType &prim, BuilderBucket &,
OutputIterator result) {
// Actually, we don't have support for meshing linestrips right now,
// so let's not break up the linestrips we're supplied with.
/*
if (bucket._subdivide_polys) {
// If we're subdividing, each line segment goes in its own
// primitive. This breaks up the linestrips already defined;
// we'll re-strip them later if the generate-tstrips flag is
// enabled.
prim.set_type(BPT_line);
int num_verts = prim.get_num_verts();
for (int i = 1; i < num_verts; i++) {
PrimType new_prim(prim);
new_prim.clear_vertices();
new_prim.add_vertex(prim.get_vertex(i-1));
new_prim.add_vertex(prim.get_vertex(i));
*result++ = new_prim;
}
return true;
}
*/
// If we're not to subdivide the polys, then just pass them through
// as they are. Two vertices is a BPT_line; more than that is a
// BPT_linestrip.
if (prim.get_num_verts() > 2) {
prim.set_type(BPT_linestrip);
} else {
prim.set_type(BPT_line);
}
*result++ = prim;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: expand
// Description: Receives a single primitive as a BuilderPrim or
// BuilderPrimI object, as input by the user. Does some
// initial processing on the primitive to verify
// internal consistency (for instance, that a quad has
// four vertices), and returns a new BuilderPrim or
// series of BuilderPrim objects, suitable for building
// with.
//
// More than one primitive might be returned because
// higher-order polygons may be broken up into
// triangles, and linestrips and points are broken into
// their component pieces. The output primitives are
// written into the STL container defined by result.
////////////////////////////////////////////////////////////////////
template <class PrimType, class OutputIterator>
bool
expand(const PrimType &prim, BuilderBucket &bucket, OutputIterator result) {
// Make a copy of the prim so we can fiddle with it.
PrimType new_prim = prim;
switch (new_prim.get_type()) {
case BPT_poly:
case BPT_tri:
case BPT_quad:
// These three types are all treated the same, as polygons. We
// don't entirely trust the user to match the polygon type with
// the number of verts, so we'll do it ourselves later.
new_prim.remove_doubled_verts(true);
if (!bucket._subdivide_polys ||
(bucket._mesh && new_prim.get_num_verts() <= 4)) {
// If we're meshing, we'd like to send quads through without
// subdividing. The mesher can take advantage of the extra
// information (and will eventually produce tris anyway).
return expand_polys(new_prim, bucket, result);
} else {
// If we're not meshing, we'll break them into tris now.
return triangulate_poly(new_prim, bucket, result);
}
case BPT_point:
new_prim.remove_doubled_verts(false);
return expand_points(new_prim, bucket, result);
case BPT_line:
case BPT_linestrip:
new_prim.remove_doubled_verts(false);
return expand_lines(new_prim, bucket, result);
default:
builder_cat.error() << "Unknown prim type\n";
return false;
}
}
////////////////////////////////////////////////////////////////////
// Function: build_geoms
// Description: Accepts a list of BuilderPrim or BuilderPrimI
// objects, defined by the iterators first and last, and
// creates corresponding geometry for them in the
// indicated GeomNode.
////////////////////////////////////////////////////////////////////
template<class InputIterator, class PrimType>
static int
build_geoms(InputIterator first, InputIterator last,
BuilderBucket &bucket, GeomNode *geom_node,
PrimType *) {
if (first==last) {
return 0;
}
// By the time we get here, we have a list of primitives that all have
// the same properties:
// 1. The BuilderBucket.
// 2. The indexed/nonindexed type.
// 3. The primitive type (polygon, line, point).
// 4. The pixel size.
// The binding of normals, colors, or texcoords: per-vertex,
// per-prim, or per-component, will generally be the same across all
// primitives, but it might not always be the same, because in
// certain special cases the mesher might have changed these
// properties when it built tristrips.
typedef TYPENAME PrimType::VType VType;
typedef TYPENAME PrimType::NType NType;
typedef TYPENAME PrimType::TType TType;
typedef TYPENAME PrimType::CType CType;
// We need to determine the common binding type for all primitives.
// For a given attribute, say normals, there are at most five cases,
// in the order of priority:
//
// 1. If at least one primitive in the list does not have normals,
// the binding will be G_OFF.
//
// 2. If at least one primitive has per-vertex normals, the binding
// will be G_PER_VERTEX.
//
// 3. If at least one primitive has per-component normals, the
// binding will be G_PER_COMPONENT.
//
// 4. If none of the first three apply, it follows that all
// primitives have an overall normal. If any primitive's
// overall normal differs from any other, the binding will be
// G_PER_PRIM.
//
// 5. If none of the above apply, the binding will be G_OVERALL.
//
// An exception to the above is for texcoords, which is either G_OFF
// (by rule 1) or G_PER_VERTEX.
GeomBindType bind_normals = G_OVERALL;
GeomBindType bind_colors = G_OVERALL;
GeomBindType bind_texcoords = G_PER_VERTEX;
NType overall_normal(0);
CType overall_color(0);
bool first_normal = true;
bool first_color = true;
InputIterator i;
for (i = first; i != last; ++i) {
// Normals.
// Test rule 1.
if (!(*i).has_any_normal()) {
bind_normals = G_OFF;
} else if (bind_normals != G_OFF) {
// Test rule 2.
if ((*i).has_vertex_normal()) {
bind_normals = G_PER_VERTEX;
} else if (bind_normals != G_PER_VERTEX) {
// Test rule 3.
if ((*i).has_component_normal()) {
bind_normals = G_PER_COMPONENT;
} else if (bind_normals != G_PER_COMPONENT) {
// Test rule 4.
nassertr((*i).has_overall_normal(), 0);
if (first_normal) {
overall_normal = (*i).get_normal();
first_normal = false;
} else if ( !((*i).get_normal() == overall_normal)) {
bind_normals = G_PER_PRIM;
}
}
}
}
// Colors.
// Test rule 1.
if (!(*i).has_any_color()) {
bind_colors = G_OFF;
} else if (bind_colors != G_OFF) {
// Test rule 2.
if ((*i).has_vertex_color()) {
bind_colors = G_PER_VERTEX;
} else if (bind_colors != G_PER_VERTEX) {
// Test rule 3.
if ((*i).has_component_color()) {
bind_colors = G_PER_COMPONENT;
} else if (bind_colors != G_PER_COMPONENT) {
// Test rule 4.
nassertr((*i).has_overall_color(), 0);
if (first_color) {
overall_color = (*i).get_color();
first_color = false;
} else if ( !((*i).get_color() == overall_color)) {
bind_colors = G_PER_PRIM;
}
}
}
}
// Texcoords.
// Test rule 1.
if (!(*i).has_any_texcoord()) {
bind_texcoords = G_OFF;
}
}
// Determine the primitive type and build the lengths array, if needed.
PTA_int lengths;
bool want_lengths = false;
int j;
Geom *geom = NULL;
BuilderPrimType type = (*first).get_type();
switch (type) {
case BPT_poly:
geom = new GeomPolygon;
want_lengths = true;
break;
case BPT_tristrip:
geom = new GeomTristrip;
want_lengths = true;
break;
case BPT_trifan:
geom = new GeomTrifan;
want_lengths = true;
break;
case BPT_line:
geom = new GeomLine;
break;
case BPT_linestrip:
geom = new GeomLinestrip;
want_lengths = true;
break;
case BPT_point:
geom = new GeomPoint;
break;
case BPT_tri:
geom = new GeomTri;
break;
case BPT_quad:
geom = new GeomQuad;
break;
default:
builder_cat.fatal() << "Invalid primitive type.\n";
abort();
}
if (geom == NULL) {
builder_cat.error() << "Unsupported primitive type " << type << "\n";
return 0;
}
// Count up the number of prims we're actually building.
int num_prims = 0;
for (i = first; i != last; ++i) {
if ((*i).is_valid()) {
num_prims++;
}
}
if (num_prims==0) {
builder_cat.error() << "All primitives were invalid!\n";
return 0;
}
if (want_lengths) {
lengths = PTA_int::empty_array(num_prims);
j = 0;
for (i = first; i != last; ++i) {
if ((*i).is_valid()) {
lengths[j++] = (*i).get_num_verts();
}
}
nassertr(j == num_prims, 0);
}
// Now build up some arrays.
PTA(VType) coords=PTA(VType)::empty_array(0);
PTA(NType) normals=PTA(NType)::empty_array(0);
PTA(TType) texcoords=PTA(TType)::empty_array(0);
PTA(CType) colors=PTA(CType)::empty_array(0);
int total_verts = 0;
int total_components = 0;
int v, num_verts;
int c, num_components;
for (i = first; i != last; ++i) {
if ((*i).is_valid()) {
num_verts = (*i).get_num_verts();
total_verts += num_verts;
for (v = 0; v < num_verts; v++) {
coords.push_back((*i).get_vertex(v).get_coord());
if (bind_normals == G_PER_VERTEX) {
normals.push_back((*i).get_vertex(v).get_normal());
}
if (bind_texcoords == G_PER_VERTEX) {
texcoords.push_back((*i).get_vertex(v).get_texcoord());
}
if (bind_colors == G_PER_VERTEX) {
colors.push_back((*i).get_vertex(v).get_color());
}
}
num_components = (*i).get_num_components();
total_components += num_components;
for (c = 0; c < num_components; c++) {
if (bind_normals == G_PER_COMPONENT) {
normals.push_back((*i).get_component(c).get_normal());
}
if (bind_colors == G_PER_COMPONENT) {
colors.push_back((*i).get_component(c).get_color());
}
}
if (bind_normals == G_PER_PRIM) {
normals.push_back((*i).get_normal());
}
if (bind_colors == G_PER_PRIM) {
colors.push_back((*i).get_color());
}
}
}
if (bind_normals == G_OVERALL) {
normals.push_back(overall_normal);
}
if (bind_colors == G_OVERALL) {
colors.push_back(overall_color);
}
// Now add all the stuff to our Geom.
geom->set_num_prims(num_prims);
if (lengths != (int *)NULL) {
geom->set_lengths(lengths);
}
PrimType::fill_geom(geom, coords,
bind_normals, normals,
bind_texcoords, texcoords,
bind_colors, colors,
bucket, num_prims,
total_components, total_verts);
/*
if ((*first).has_pixel_size()) {
// Again, we only have to test the first one in the list for a
// pixel_size attribute. If this one has it, then they all have
// the same value.
geom->setPntSize((*first).get_pixel_size());
geom->setLineWidth((*first).get_pixel_size());
}
*/
// geom->setDrawBin(bucket._drawBin);
// geom->setDrawOrder(bucket._drawOrder);
Geom *new_geom = bucket.done_geom(geom);
if (new_geom != (Geom *)NULL) {
geom_node->add_geom(new_geom, bucket._state);
}
return 1;
}
/////////////////////////////////////////////////////////////////////
// Class : PrimByType
// Description : An STL function object to sort primitives in order by
// type.
////////////////////////////////////////////////////////////////////
template<class PrimType>
class PrimByType {
public:
int operator () (const PrimType &p1, const PrimType &p2) const {
return p1.get_type() < p2.get_type();
}
};
////////////////////////////////////////////////////////////////////
// Function: __mesh_and_build
// Description: The implementation of mesh_and_build(), below. This
// extra function call is just to allow mesh_and_build()
// to infer the PrimType (BuilderPrim or BuilderPrimI)
// from the iterator's value type, and template on that.
////////////////////////////////////////////////////////////////////
template<class InputIterator, class PrimType>
static int
__mesh_and_build(InputIterator first, InputIterator last,
BuilderBucket &bucket, GeomNode *geom_node,
PrimType *) {
if (first==last) {
return 0;
}
typedef pvector<PrimType> Prims;
Prims prims;
BuilderBucket *local_bucket = NULL;
BuilderBucket *bucket_ptr = &bucket;
if (bucket._mesh) {
// Send all the prims through the mesher. First, make a copy of
// the bucket so the mesher can modify it if it wants.
local_bucket = bucket.make_copy();
bucket_ptr = local_bucket;
MesherTempl<PrimType> mesher(local_bucket);
for (InputIterator ii = first; ii != last; ++ii) {
mesher.add_prim(*ii);
}
mesher.mesh();
PrimType prim;
prim = mesher.getPrim();
while (prim.get_num_verts() > 0) {
prims.push_back(prim);
prim = mesher.getPrim();
}
} else {
// Send the prims through without meshing.
copy(first, last, back_inserter(prims));
}
// Now we have an array of prims which all share the same
// properties, except possibly type. Sort them by type and send
// them to build_geoms.
sort(prims.begin(), prims.end(), PrimByType<PrimType>());
int count = 0;
if (!prims.empty()) {
TYPENAME Prims::iterator pi, last_pi;
pi = prims.begin();
last_pi = pi;
for (++pi; pi != prims.end(); ++pi) {
if ((*pi).get_type() != (*last_pi).get_type()) {
count += build_geoms(last_pi, pi, *bucket_ptr, geom_node, (PrimType*)0);
last_pi = pi;
}
}
count += build_geoms(last_pi, pi, *bucket_ptr, geom_node, (PrimType*)0);
}
if (local_bucket!=NULL) {
delete local_bucket;
}
// Finally, if the user so requested, create some visualization for
// the normals.
#ifdef SUPPORT_SHOW_NORMALS
if (bucket._show_normals) {
BuilderNormalVisualizer bnv(bucket);
for (InputIterator ii = first; ii != last; ++ii) {
bnv.add_prim(*ii);
}
bnv.show_normals(geom_node);
}
#endif
return count;
}
////////////////////////////////////////////////////////////////////
// Function: mesh_and_build
// Description: Accepts a list of BuilderPrim or BuilderPrimI
// objects, defined by the iterators first and list,
// runs them through the mesher if specified by the
// bucket, and builds them into the indicated GeomNode.
////////////////////////////////////////////////////////////////////
template<class InputIterator, class value_type>
int
mesh_and_build(InputIterator first, InputIterator last,
BuilderBucket &bucket, GeomNode *geom_node,
value_type *value_type_ptr) {
return __mesh_and_build(first, last, bucket, geom_node, value_type_ptr);
}
////////////////////////////////////////////////////////////////////
// Function: split
// Description: Splits an STL list into two other lists, according to
// the return value from pred.
////////////////////////////////////////////////////////////////////
template <class InputIterator, class OutputIterator, class Predicate>
OutputIterator split(InputIterator first, InputIterator last,
OutputIterator true_result, OutputIterator false_result,
Predicate pred) {
while (first != last) {
if (pred(*first)) {
*true_result++ = *first++;
} else {
*false_result++ = *first++;
}
}
return true_result;
}