Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/builder/mesherTempl.I

Go to the documentation of this file.
00001 // Filename: mesherTempl.I
00002 // Created by:  drose (15Sep97)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "builderMisc.h"
00020 #include "mesherStrip.h"
00021 #include "mesherFanMaker.h"
00022 #include "config_builder.h"
00023 
00024 #include <algorithm>
00025 
00026 template <class PrimType>
00027 MesherTempl<PrimType>::
00028 MesherTempl(BuilderBucket *bucket) {
00029   _bucket = bucket;
00030   _stripIndex = 0;
00031   _next_strip = _done.end();
00032 }
00033 
00034 template <class PrimType>
00035 int MesherTempl<PrimType>::
00036 add_prim(const Prim &prim, MesherStripOrigin origin) {
00037   if (!prim.is_valid()) {
00038     return false;
00039   }
00040 
00041   // Define an initial strip (probably of length 1) for the prim.
00042   Strip temp_strip(prim, _stripIndex++, *_bucket);
00043   Strips &list = choose_strip_list(temp_strip);
00044   list.push_back(temp_strip);
00045   Strip &strip = list.back();
00046   strip._origin = origin;
00047 
00048   int i;
00049   int num_verts = prim.get_num_verts();
00050 
00051   const Vertex **vptrs = (const Vertex **)alloca(num_verts * sizeof(Vertex *));
00052   EdgePtrs **eptrs = (EdgePtrs **)alloca(num_verts * sizeof(EdgePtrs *));
00053 
00054   // Get the common vertex pointers for the primitive's vertices.
00055   for (i = 0; i < num_verts; i++) {
00056     TYPENAME Verts::iterator n =
00057       _verts.insert(Verts::value_type(prim.get_vertex(i), EdgePtrs())).first;
00058     vptrs[i] = &(*n).first;
00059     eptrs[i] = &(*n).second;
00060 
00061     strip._verts.push_back(vptrs[i]);
00062   }
00063 
00064   // Now identify the common edges.
00065   if (prim.get_type() == BPT_tri || prim.get_type() == BPT_quad) {
00066     // Polygons of arbitrary size don't get meshed, and so therefore
00067     // don't have any edges in common with anything else.  Only tris
00068     // and quads can be meshed.  (The builder normally breaks up
00069     // larger polygons into tris, though the user can choose to defeat
00070     // this.)
00071 
00072     for (i = 0; i < num_verts; i++) {
00073       // Define an inner and outer edge.  A polygon shares an edge with a
00074       // neighbor only when one of its inner edges matches a neighbor's
00075       // outer edge (and vice-versa).
00076       Edge inner(vptrs[i], vptrs[(i+1) % num_verts]);
00077       Edge outer(vptrs[(i+1) % num_verts], vptrs[i]);
00078 
00079       // Add it to the list and get its common pointer.
00080       Edge &inner_ref = (Edge &)*_edges.insert(inner).first;
00081       Edge &outer_ref = (Edge &)*_edges.insert(outer).first;
00082 
00083       // Tell the edges about each other.
00084       inner_ref._opposite = &outer_ref;
00085       outer_ref._opposite = &inner_ref;
00086 
00087       // Associate the common edge to the strip.
00088       strip._edges.push_back(&inner_ref);
00089 
00090       // Associate the strip, as well as the original prim, to the edge.
00091       outer_ref._strips.push_back(&strip);
00092 
00093       // Associate the common edge with the vertices that share it.
00094       //      Edge *edge_ptr = inner_ref.common_ptr();
00095       eptrs[i]->insert(&outer_ref);
00096       eptrs[(i+1) % num_verts]->insert(&outer_ref);
00097     }
00098   }
00099   return true;
00100 }
00101 
00102 
00103 template <class PrimType>
00104 void MesherTempl<PrimType>::
00105 mesh() {
00106   if (_bucket->_consider_fans) {
00107     find_fans();
00108   }
00109 
00110   // First, we try to make all the best quads we can.
00111   if (_bucket->_retesselate_coplanar) {
00112     make_quads();
00113   }
00114 
00115   // Then, we do the rest of the tris.
00116   meshList(_tris);
00117 
00118   if (_bucket->_show_quads) {
00119     // If we're showing quads, we shouldn't do any more meshing.
00120     TYPENAME Strips::iterator si;
00121     for (si = _quads.begin(); si != _quads.end(); ++si) {
00122       if ((*si)._status == MS_alive) {
00123         (*si)._status = MS_done;
00124       }
00125     }
00126     for (si = _strips.begin(); si != _strips.end(); ++si) {
00127       if ((*si)._status == MS_alive) {
00128         (*si)._status = MS_done;
00129       }
00130     }
00131   }
00132 
00133   // Then, build quads into sheets where possible.
00134   build_sheets();
00135 
00136   // Pick up any quads that might have been left behind.
00137   meshList(_quads);
00138 
00139   // Finally, do the longer strips.
00140   meshList(_strips);
00141 
00142   // Get ready to walk through the results.
00143   _next_strip = _done.begin();
00144 }
00145 
00146 
00147 template <class PrimType>
00148 PrimType MesherTempl<PrimType>::
00149 getPrim() {
00150   if (_next_strip == _done.end()) {
00151     // End of the list, return a primitive with no vertices.
00152     finalize();
00153     return Prim();
00154   }
00155 
00156   Strip &strip = (*_next_strip++);
00157   BuilderPrimType orig_type = strip._type;
00158   Prim prim = strip.make_prim(*_bucket);
00159 
00160   if (_bucket->_show_tstrips) {
00161     // If we have _show_tstrips enabled, it means we need to color
00162     // every primitive according to which, if any, tristrip it is in.
00163 
00164     // We use the _colors array--and later make a copy in shared
00165     // memory for the bucket to point to--in case the primitives are
00166     // indexed.  If the primitives are nonindexed, we'll still
00167     // allocate the _colors array and its copy in shared memory, but
00168     // it will be deleted when the bucket destructs.
00169 
00170     if (_colors.empty()) {
00171       // We need one entry for not-a-tristrip, indicated by white.
00172       _colors.push_back(Colorf(0.85, 0.85, 0.85, 1.0));
00173     }
00174 
00175     ushort i1, i2;
00176     Colorf color1, color2;;
00177 
00178     switch (prim.get_type()) {
00179     case BPT_tristrip:
00180     case BPT_trifan:
00181       make_random_color(color2);
00182       color1 = (color2 * 0.8);   // somewhat darker.
00183       i1 = _colors.size();
00184       i2 = i1+1;
00185       _colors.push_back(color1);
00186       _colors.push_back(color2);
00187       break;
00188 
00189     default:
00190       // not-a-tristrip.
00191       i1 = i2 = 0;
00192     }
00193 
00194     // Now i1 and i2 index into the colors array to indicate the color
00195     // for the first triangle and the rest of the primitive,
00196     // respectively.
00197     int num_components = prim.get_num_components();
00198     if (num_components > 0) {
00199       prim.get_component(0).set_color_value(&_colors[0], i1);
00200       for (int i = 1; i < num_components; i++) {
00201         prim.get_component(i).set_color_value(&_colors[0], i2);
00202       }
00203     } else {
00204       prim.set_color_value(&_colors[0], i1);
00205     }
00206 
00207   } else if (_bucket->_show_qsheets) {
00208     // _show_qsheets means to color every primitive according to
00209     // which, if any, quadsheet it is in.  This is a bit easier,
00210     // because the entire primitive gets the same color.
00211 
00212     if (_colors.empty()) {
00213       // We need one entry for not-a-qsheet, indicated by white.
00214       _colors.push_back(Colorf(0.85, 0.85, 0.85, 1.0));
00215     }
00216 
00217     // Is this a quadsheet?
00218     ushort i1 = 0;
00219     if (strip._row_id < 0) {
00220       // Yep!  Assign a new color, if it doesn't already have one.
00221       ColorSheetMap::iterator ci = _color_sheets.find(strip._row_id);
00222 
00223       if (ci == _color_sheets.end()) {
00224         Colorf color1;
00225         make_random_color(color1);
00226         i1 = _colors.size();
00227         _colors.push_back(color1);
00228         _color_sheets[strip._row_id] = i1;
00229       } else {
00230         i1 = (*ci).second;
00231       }
00232     }
00233 
00234     // Now i1 is the color we want to assign to the whole primitive.
00235     // Just set all vertices to the same color.
00236     int num_verts = prim.get_num_verts();
00237     for (int i = 0; i < num_verts; i++) {
00238       prim.get_vertex(i).set_color_value(&_colors[0], i1);
00239     }
00240 
00241   } else if (_bucket->_show_quads) {
00242     // _show_quads means to show the assembling of tris into quads and fans.
00243 
00244     // We use the following color convention:
00245 
00246     // white: unchanged; as supplied by user.
00247     // dark blue: quads made in the initial pass.  These are more certain.
00248     // light blue: quads made in the second pass.  These are less certain.
00249     // very light blue: quadstrips.  These are unlikely to appear.
00250     // random shades of red: triangles and tristrips.
00251     // green: fans and retesselated fan polygons.
00252 
00253     if (_colors.empty()) {
00254       // We need a handful of entries.
00255       _colors.push_back(Colorf(0.85, 0.85, 0.85, 1.0));  // default: white
00256       _colors.push_back(Colorf(0.0, 0.0, 0.75, 1.0));    // dark blue
00257       _colors.push_back(Colorf(0.4, 0.4, 0.8, 1.0));     // light blue
00258       _colors.push_back(Colorf(0.6, 0.6, 1.0, 1.0));     // very light blue
00259       _colors.push_back(Colorf(0.2, 0.8, 0.2, 1.0));     // green
00260     }
00261 
00262     ushort i1;
00263     Colorf color1;
00264     if (strip._origin == MO_user) {
00265       i1 = 0;
00266     } else if (strip._origin == MO_firstquad) {
00267       i1 = 1;
00268     } else if (strip._origin == MO_fanpoly) {
00269       i1 = 4;
00270     } else {
00271       switch (orig_type) {
00272       case BPT_quad:
00273         i1 = 2;
00274         break;
00275 
00276       case BPT_quadstrip:
00277         i1 = 3;
00278         break;
00279 
00280       case BPT_tristrip:
00281         make_random_color(color1);
00282         // Make it a shade of red.
00283         if (color1[0] < color1[1]) {
00284           float t = color1[0];
00285           color1[0] = color1[1];
00286           color1[1] = t;
00287         }
00288         color1[2] = color1[1];
00289         i1 = _colors.size();
00290         _colors.push_back(color1);
00291         break;
00292 
00293       case BPT_trifan:
00294         make_random_color(color1);
00295         // Make it a shade of green.
00296         if (color1[0] > color1[1]) {
00297           float t = color1[0];
00298           color1[0] = color1[1];
00299           color1[1] = t;
00300         }
00301         color1[2] = color1[0];
00302         i1 = _colors.size();
00303         _colors.push_back(color1);
00304         break;
00305 
00306       default:
00307         i1 = 0;
00308       }
00309     }
00310 
00311     // Now i1 is the color we want to assign to the whole primitive.
00312     // Just set all vertices to the same color.
00313     int num_verts = prim.get_num_verts();
00314     for (int i = 0; i < num_verts; i++) {
00315       prim.get_vertex(i).set_color_value(&_colors[0], i1);
00316     }
00317   }
00318 
00319   return prim;
00320 }
00321 
00322 
00323 template <class PrimType>
00324 void MesherTempl<PrimType>::
00325 finalize() {
00326   if (!_colors.empty()) {
00327     // Create an array in the bucket we might use to add to geoms.
00328     PTA_Colorf colors=PTA_Colorf::empty_array(_colors.size());
00329     for (int i = 0; i < (int)_colors.size(); i++) {
00330       colors[i] = _colors[i];
00331     }
00332     _bucket->set_colors(colors);
00333 
00334     _colors.clear();
00335     _color_sheets.clear();
00336   }
00337 }
00338 
00339 
00340 
00341 template <class PrimType>
00342 void MesherTempl<PrimType>::
00343 show(ostream &out) {
00344   /*
00345   out << _edges.size() << " edges:\n";
00346   copy(_edges.begin(), _edges.end(), ostream_iterator<Edge>(out, "\n"));
00347   */
00348 
00349   out << _verts.size() << " verts:\n";
00350   TYPENAME Verts::const_iterator vi;
00351 
00352   for (vi = _verts.begin(); vi != _verts.end(); ++vi) {
00353     const Vertex &v = (*vi).first;
00354     const EdgePtrs &edges = (*vi).second;
00355     out << v << " shares " << count_vert_edges(edges) << " edges:\n";
00356     TYPENAME EdgePtrs::const_iterator ei;
00357     for (ei = edges.begin(); ei != edges.end(); ++ei) {
00358       if (!(*ei)->_strips.empty() || !(*ei)->_opposite->_strips.empty()) {
00359         out << "  " << **ei << "\n";
00360       }
00361     }
00362   }
00363 
00364   TYPENAME Strips::const_iterator si;
00365   out << _tris.size() << " tris:\n";
00366   for (si = _tris.begin(); si != _tris.end(); ++si) {
00367     out << (*si) << "\n";
00368   }
00369 
00370   out << _quads.size() << " quads:\n";
00371   for (si = _quads.begin(); si != _quads.end(); ++si) {
00372     out << (*si) << "\n";
00373   }
00374 
00375   out << _strips.size() << " strips:\n";
00376   for (si = _strips.begin(); si != _strips.end(); ++si) {
00377     out << (*si) << "\n";
00378   }
00379 }
00380 
00381 
00382 template <class PrimType>
00383 int MesherTempl<PrimType>::
00384 count_vert_edges(const EdgePtrs &edges) const {
00385   int count = 0;
00386   TYPENAME EdgePtrs::const_iterator ei;
00387   for (ei = edges.begin(); ei != edges.end(); ++ei) {
00388     count += (!(*ei)->_strips.empty() || !(*ei)->_opposite->_strips.empty());
00389   }
00390   return count;
00391 }
00392 
00393 template <class PrimType>
00394 plist<TYPENAME MesherTempl<PrimType>::Strip> &MesherTempl<PrimType>::
00395 choose_strip_list(const Strip &strip) {
00396   switch (strip._status) {
00397   case MS_done:
00398     return _done;
00399 
00400   case MS_dead:
00401     return _dead;
00402 
00403   case MS_alive:
00404     switch (strip._type) {
00405     case BPT_tri:
00406       return _tris;
00407 
00408     case BPT_quad:
00409       return _quads;
00410 
00411     default:
00412       return _strips;
00413     }
00414 
00415   default:
00416     builder_cat.fatal() << "Invalid strip status!\n";
00417     abort();
00418   }
00419 
00420   return _strips; // Unreachable; this is just to make the compiler happy.
00421 }
00422 
00423 
00424 template <class PrimType>
00425 void MesherTempl<PrimType>::
00426 build_sheets() {
00427   int first_row_id = 1;
00428 
00429   // First, move all the quads to our own internal list.
00430   Strips pre_sheeted;
00431   pre_sheeted.splice(pre_sheeted.end(), _quads);
00432 
00433   while (!pre_sheeted.empty()) {
00434     // Pick the first quad on the list.
00435 
00436     TYPENAME Strips::iterator best = pre_sheeted.begin();
00437 
00438     // If the row_id is negative, we've already built a sheet out of
00439     // this quad.  Leave it alone.  We also need to leave it be if it
00440     // has no available edges.
00441     if ((*best)._row_id >= 0 &&
00442         (*best)._status == MS_alive &&
00443         !(*best)._edges.empty()) {
00444       // There are two possible sheets we could make from this quad,
00445       // in two different orientations.  Measure them both and figure
00446       // out which one is best.
00447 
00448       const Edge *edge_a = (*best)._edges.front();
00449       const Edge *edge_b = (*best).find_adjacent_edge(edge_a);
00450 
00451       int num_prims_a = 0;
00452       int num_rows_a = 0;
00453       int first_row_id_a = first_row_id;
00454       (*best).measure_sheet(edge_a, true, num_prims_a, num_rows_a,
00455                            first_row_id_a, 0, 0);
00456       first_row_id += num_rows_a;
00457       double avg_length_a = (double)num_prims_a / (double)num_rows_a;
00458 
00459       int num_prims_b = 0;
00460       int num_rows_b = 0;
00461       int first_row_id_b = first_row_id;
00462       double avg_length_b;
00463       if (edge_b != NULL) {
00464         (*best).measure_sheet(edge_b, true, num_prims_b, num_rows_b,
00465                              first_row_id_b, 0, 0);
00466         first_row_id += num_rows_b;
00467         avg_length_b = (double)num_prims_b / (double)num_rows_b;
00468       }
00469 
00470       // Which sheet is better?
00471       if (edge_b != NULL && avg_length_b >= avg_length_a) {
00472         // Sheet b.  That's easy.
00473         (*best).cut_sheet(first_row_id_b, true, *_bucket);
00474 
00475       } else {
00476         // Nope, sheet a is better.  This is a bit of a nuisance
00477         // because we've unfortunately wiped out the information we
00478         // stored when we measured sheet a.  We'll have to do it
00479         // again.
00480 
00481         num_prims_a = 0;
00482         num_rows_a = 0;
00483         first_row_id_a = first_row_id;
00484         (*best).measure_sheet(edge_a, true, num_prims_a, num_rows_a,
00485                              first_row_id_a, 0, 0);
00486         first_row_id += num_rows_a;
00487 
00488         // Now we can cut it.
00489         (*best).cut_sheet(first_row_id_a, true, *_bucket);
00490       }
00491     }
00492 
00493     // Now put it somewhere.  We'll never see this quad again in
00494     // build_sheets().
00495     Strips &list = choose_strip_list(*best);
00496     list.splice(list.end(), pre_sheeted, best);
00497   }
00498 }
00499 
00500 
00501 template <class PrimType>
00502 void MesherTempl<PrimType>::
00503 find_fans() {
00504 #ifdef SUPPORT_FANS
00505   pvector<Prim> unrolled_tris;
00506 
00507   // Consider all vertices.  Any vertex with over a certain number of
00508   // edges connected to it is eligible to become a fan.
00509 
00510   TYPENAME Verts::iterator vi;
00511 
00512   for (vi = _verts.begin(); vi != _verts.end(); ++vi) {
00513     EdgePtrs &edges = (*vi).second;
00514 
00515     // 14 is the magic number of edges.  12 edges or fewer are likely
00516     // to be found on nearly every vertex in a quadsheet (six edges
00517     // times two, one each way).  We don't want to waste time fanning
00518     // out each vertex of a quadsheet, and we don't want to break up
00519     // the quadsheets anyway.  We bump this up to 14 because some
00520     // quadsheets are defined with triangles flipped here and there.
00521     if (edges.size() > 6) {
00522       const Vertex &v = (*vi).first;
00523 
00524       // Build up a list of far fan edges.
00525       typedef pvector<FanMaker> FanMakers;
00526 
00527       FanMakers fans;
00528 
00529       TYPENAME EdgePtrs::iterator ei;
00530       TYPENAME Edge::Strips::iterator si;
00531       for (ei = edges.begin(); ei != edges.end(); ++ei) {
00532         for (si = (*ei)->_strips.begin();
00533              si != (*ei)->_strips.end();
00534              ++si) {
00535           Strip *strip = *si;
00536           if (strip->_type == BPT_tri) {
00537             fans.push_back(FanMaker(&v, strip, this));
00538           }
00539         }
00540       }
00541 
00542       // Sort the fans list by edge pointers, and remove duplicates.
00543       sort(fans.begin(), fans.end());
00544       fans.erase(unique(fans.begin(), fans.end()),
00545                  fans.end());
00546 
00547       TYPENAME FanMakers::iterator fi, fi2;
00548 
00549       // Now pull out connected edges.
00550       int joined_any;
00551       do {
00552         joined_any = false;
00553         for (fi = fans.begin(); fi != fans.end(); ++fi) {
00554           if (!(*fi).is_empty()) {
00555             fi2 = fi;
00556             for (++fi2; fi2 != fans.end(); ++fi2) {
00557               if (!(*fi2).is_empty()) {
00558                 joined_any = (*fi).join(*fi2);
00559               }
00560             }
00561           }
00562         }
00563       } while (joined_any);
00564 
00565       for (fi = fans.begin(); fi != fans.end(); ++fi) {
00566         if ((*fi).is_valid()) {
00567           (*fi).build(unrolled_tris);
00568         }
00569       }
00570     }
00571   }
00572 
00573   // Finally, add back in the triangles we might have produced by
00574   // unrolling some of the fans.  We can't add these back in safely
00575   // until we're done traversing all the vertices and primitives we
00576   // had in the first place (since adding them will affect the edge
00577   // lists).
00578   TYPENAME pvector<Prim>::iterator ti;
00579   for (ti = unrolled_tris.begin(); ti != unrolled_tris.end(); ++ti) {
00580     add_prim(*ti);
00581   }
00582 #endif
00583 }
00584 
00585 
00586 
00587 ////////////////////////////////////////////////////////////////////
00588 //     Function: MesherTempl::make_quads
00589 //       Access: Public
00590 //  Description: Attempts to join up all the single tris to its
00591 //               neighbor and reconstruct a pattern of quads, suitable
00592 //               for making into quadsheets or at least quadstrips.
00593 ////////////////////////////////////////////////////////////////////
00594 template <class PrimType>
00595 void MesherTempl<PrimType>::
00596 make_quads() {
00597   // Ideally, we want to match tris across their hypotenuse to make a
00598   // pattern of quads.  (This assumes that we are working with a
00599   // triangulated mesh pattern, of course.  If we have some other
00600   // pattern of tris, all bets are off and it doesn't really matter
00601   // anyway.)
00602 
00603   // First, we'll find all the tris that have no doubt about their
00604   // ideal mate, and pair them up right away.  The others we'll get to
00605   // later.  This way, the uncertain matches won't pollute the quad
00606   // alignment for everyone else.
00607 
00608   typedef pair<Strip *, Strip *> Pair;
00609   typedef pair<Pair, Edge *> Matched;
00610   typedef pvector<Matched> SoulMates;
00611 
00612   SoulMates soulmates;
00613 
00614   Strip *tri, *mate, *mate2;
00615   Edge *common_edge, *common_edge2;
00616 
00617   TYPENAME Strips::iterator si;
00618   for (si = _tris.begin(); si != _tris.end(); ++si) {
00619     tri = &(*si);
00620 
00621     if (tri->_status == MS_alive) {
00622       if (tri->find_ideal_mate(mate, common_edge, *_bucket)) {
00623         // Does our chosen mate want us too?
00624         if (mate->_type == BPT_tri && mate->_status == MS_alive &&
00625             mate->find_ideal_mate(mate2, common_edge2, *_bucket) &&
00626             mate2 == tri) {
00627           // Hooray!
00628           soulmates.push_back(Matched(Pair(tri, mate), common_edge));
00629           // We'll temporarily mark the two tris as paired.
00630           tri->_status = MS_paired;
00631           mate->_status = MS_paired;
00632         }
00633       }
00634     }
00635   }
00636 
00637   // Now that we've found all the tris that are sure about each other,
00638   // mate them.
00639   TYPENAME SoulMates::iterator mi;
00640   for (mi = soulmates.begin(); mi != soulmates.end(); ++mi) {
00641     tri = (*mi).first.first;
00642     mate = (*mi).first.second;
00643     common_edge = (*mi).second;
00644 
00645     nassertv(tri->_status == MS_paired);
00646     nassertv(mate->_status == MS_paired);
00647     tri->_status = MS_alive;
00648     mate->_status = MS_alive;
00649 
00650     Strip::mate_pieces(common_edge, *tri, *mate, *_bucket);
00651     tri->_origin = MO_firstquad;
00652   }
00653 
00654   // Now move all the strips off the tri list that no longer belong.
00655   TYPENAME Strips::iterator next;
00656   si = _tris.begin();
00657   while (si != _tris.end()) {
00658     next = si;
00659     ++next;
00660 
00661     Strips &list = choose_strip_list(*si);
00662     if (&list != &_tris) {
00663       list.splice(list.end(), _tris, si);
00664     }
00665 
00666     si = next;
00667   }
00668 }
00669 
00670 template <class PrimType>
00671 void MesherTempl<PrimType>::
00672 meshList(Strips &strips) {
00673   while (!strips.empty()) {
00674     // Pick the first strip on the list.
00675 
00676     TYPENAME Strips::iterator best = strips.begin();
00677 
00678     if ((*best)._status == MS_alive) {
00679       (*best).mate(*_bucket);
00680     }
00681 
00682     // Put the strip back on the end of whichever list it wants.  This
00683     // might be the same list, if the strip is still alive, or it
00684     // might be _done or _dead.
00685     Strips &list = choose_strip_list(*best);
00686     list.splice(list.end(), strips, best);
00687   }
00688 }

Generated on Fri May 2 00:34:50 2003 for Panda by doxygen1.3