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

panda/src/builder/mesherFanMaker.I

Go to the documentation of this file.
00001 // Filename: mesherFanMaker.I
00002 // Created by:  drose (21Sep97)
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 /* okcircular */
00020 #include "builderFuncs.h"
00021 
00022 #include <notify.h>
00023 #include <mathNumbers.h>
00024 
00025 #include <math.h>
00026 
00027 template <class PrimType>
00028 INLINE bool MesherFanMaker<PrimType>::
00029 operator < (const MesherFanMaker &other) const {
00030   return _edges.front() < other._edges.front();
00031 }
00032 
00033 template <class PrimType>
00034 INLINE bool MesherFanMaker<PrimType>::
00035 operator != (const MesherFanMaker &other) const {
00036   return !operator == (other);
00037 }
00038 
00039 template <class PrimType>
00040 INLINE bool MesherFanMaker<PrimType>::
00041 operator == (const MesherFanMaker &other) const {
00042   return _edges.front() == other._edges.front();
00043 }
00044 
00045 template <class PrimType>
00046 INLINE bool MesherFanMaker<PrimType>::
00047 is_empty() const {
00048   return (_edges.empty());
00049 }
00050 
00051 template <class PrimType>
00052 INLINE bool MesherFanMaker<PrimType>::
00053 is_valid() const {
00054   return (_edges.size() > 2);
00055 }
00056 
00057 ////////////////////////////////////////////////////////////////////
00058 //     Function: MesherFanMaker::is_coplanar_with
00059 //       Access: Public
00060 //  Description: Returns true if the strip and the other strip are
00061 //               coplanar.
00062 ////////////////////////////////////////////////////////////////////
00063 template <class PrimType>
00064 INLINE bool MesherFanMaker<PrimType>::
00065 is_coplanar_with(const MesherFanMaker &other) const {
00066   return _planar && other._planar &&
00067     _strips.front()->is_coplanar_with(*other._strips.front(),
00068                                     _bucket->_coplanar_threshold);
00069 }
00070 
00071 template <class PrimType>
00072 MesherFanMaker<PrimType>::
00073 MesherFanMaker(const Vertex *vertex, Strip *tri, Mesher *mesher) {
00074   _vertex = vertex;
00075   const Edge *edge = tri->find_opposite_edge(vertex);
00076   if (edge != (const Edge *)NULL) {
00077     _edges.push_back(edge);
00078   }
00079   _strips.push_back(tri);
00080   _planar = tri->_planar;
00081   _mesher = mesher;
00082   _bucket = _mesher->_bucket;
00083 }
00084 
00085 template <class PrimType>
00086 bool MesherFanMaker<PrimType>::
00087 join(MesherFanMaker &other) {
00088   nassertr(_vertex == other._vertex, false);
00089   nassertr(_mesher == other._mesher, false);
00090   nassertr(_bucket == other._bucket, false);
00091 
00092   nassertr(!_edges.empty() && !other._edges.empty(), false);
00093 
00094   const Edge *my_back = _edges.back();
00095   const Edge *other_front = other._edges.front();
00096   nassertr(my_back != (Edge *)NULL && other_front != (Edge *)NULL, false);
00097 
00098   const Vertex *my_back_b = my_back->_b;
00099   const Vertex *other_front_a = other_front->_a;
00100 
00101   if (my_back_b == other_front_a) {
00102     _planar = is_coplanar_with(other);
00103     _edges.splice(_edges.end(), other._edges);
00104     _strips.splice(_strips.end(), other._strips);
00105     return true;
00106   }
00107 
00108   const Edge *my_front = _edges.front();
00109   const Edge *other_back = other._edges.back();
00110   nassertr(my_front != (Edge *)NULL && other_back != (Edge *)NULL, false);
00111 
00112   const Vertex *my_front_a = my_front->_a;
00113   const Vertex *other_back_b = other_back->_b;
00114 
00115   if (my_front_a == other_back_b) {
00116     _planar = is_coplanar_with(other);
00117     _edges.splice(_edges.begin(), other._edges);
00118     _strips.splice(_strips.begin(), other._strips);
00119     return true;
00120   }
00121 
00122   return false;
00123 }
00124 
00125 
00126 template <class PrimType>
00127 float MesherFanMaker<PrimType>::
00128 compute_angle() const {
00129   // We sum up the angles of each triangle.  This is more correct than
00130   // taking the net angle from the first edge to the last (since we
00131   // may not be in a plane).
00132   nassertr(is_valid(), 0.0);
00133 
00134   double angle = 0.0;
00135   Vertexf v0 = _vertex->get_coord_value(*_bucket);
00136 
00137   TYPENAME Edges::const_iterator ei;
00138   for (ei = _edges.begin(); ei != _edges.end(); ++ei) {
00139     Normalf v1 = (*ei)->_a->get_coord_value(*_bucket) - v0;
00140     Normalf v2 = (*ei)->_b->get_coord_value(*_bucket) - v0;
00141 
00142     v1 = normalize(v1);
00143     v2 = normalize(v2);
00144     angle += acos(dot(v1, v2));
00145   }
00146 
00147   return rad_2_deg(angle);
00148 }
00149 
00150 template <class PrimType>
00151 int MesherFanMaker<PrimType>::
00152 build(pvector<Prim> &unrolled_tris) {
00153   nassertr(_edges.size() == _strips.size(), 0);
00154 
00155   int num_tris = _edges.size();
00156   float net_angle = compute_angle();
00157   float avg_angle = net_angle / num_tris;
00158 
00159   if (avg_angle > _bucket->_max_tfan_angle) {
00160     // The triangles are too loose to justify making a fan; it'll
00161     // probably make a better quadsheet.
00162     return 0;
00163   }
00164 
00165   if (_bucket->_min_tfan_tris==0 || num_tris < _bucket->_min_tfan_tris) {
00166     // Oops, not enough triangles to justify a fan.
00167     if (!_bucket->_unroll_fans) {
00168       return 0;
00169     }
00170 
00171     // However, we could (maybe) make it a few tristrips!
00172 
00173     // Each section of the fan which is made up of coplanar tris with
00174     // identical properties may be retesselated into a tristrip.  What
00175     // a sneaky trick!  To do this, we must first identify each such
00176     // qualifying section.
00177 
00178     // We define a seam as the edge between any two tris which are
00179     // noncoplanar or which do not share identical properties.  Then
00180     // we can send each piece between the seams to unroll().
00181 
00182     TYPENAME Strips::iterator si, last_si;
00183     TYPENAME Edges::iterator ei, last_ei;
00184 
00185     // First, rotate the fan so it begins at a seam.  We do this so we
00186     // won't be left out with part of one piece at the beginning and
00187     // also at the end.
00188     si = _strips.begin();
00189     last_si = si;
00190     ei = _edges.begin();
00191     last_ei = ei;
00192     int found_seam = false;
00193 
00194     for (++si, ++ei; si != _strips.end() && !found_seam; ++si, ++ei) {
00195       nassertr(ei != _edges.end(), 0);
00196       if ( !((*si)->_prims.front() == (*last_si)->_prims.front()) ||
00197            !(*si)->is_coplanar_with(*(*last_si), _bucket->_coplanar_threshold)) {
00198         // Here's a seam.  Break the fan here.
00199         found_seam = true;
00200         _edges.splice(_edges.begin(), _edges, ei, _edges.end());
00201         _strips.splice(_strips.begin(), _strips, si, _strips.end());
00202       }
00203     }
00204 
00205     // Now break the fan up along its seams and unroll each piece
00206     // separately.
00207     si = _strips.begin();
00208     last_si = si;
00209     ei = _edges.begin();
00210     last_ei = ei;
00211 
00212     int count = 0;
00213     for (++si, ++ei; si != _strips.end(); ++si, ++ei) {
00214       nassertr(ei != _edges.end(), 0);
00215       if ( !((*si)->_prims.front() == (*last_si)->_prims.front()) ||
00216            !(*si)->is_coplanar_with(*(*last_si), _bucket->_coplanar_threshold)) {
00217         // Here's the end of a run of matching pieces.
00218         count += unroll(last_si, si, last_ei, ei, unrolled_tris);
00219         last_si = si;
00220         last_ei = ei;
00221       }
00222     }
00223     count += unroll(last_si, si, last_ei, ei, unrolled_tris);
00224 
00225     return count;
00226 
00227   } else {
00228     Strip new_fan;
00229     new_fan._type = BPT_trifan;
00230     new_fan._verts.push_back(_vertex);
00231 
00232     new_fan._verts.push_back(_edges.front()->_a);
00233     TYPENAME Edges::iterator ei;
00234     for (ei = _edges.begin(); ei != _edges.end(); ++ei) {
00235       new_fan._verts.push_back((*ei)->_b);
00236     }
00237 
00238     TYPENAME Strips::iterator si;
00239     for (si = _strips.begin(); si != _strips.end(); ++si) {
00240       new_fan._prims.splice(new_fan._prims.end(), (*si)->_prims);
00241       (*si)->remove_all_edges();
00242       (*si)->_verts.clear();
00243       (*si)->_status = MS_dead;
00244     }
00245 
00246     // If we'd built our list of edges and strips right, this sum should
00247     // come out so that there are two more vertices than triangles in
00248     // the new fan.
00249     nassertr(new_fan._verts.size() == new_fan._prims.size() + 2, 0);
00250 
00251     // Now we've built a fan, and it won't be able to mate with
00252     // anything else, so add it to the done list.
00253     _mesher->_done.push_back(new_fan);
00254   }
00255 
00256   return 1;
00257 }
00258 
00259 
00260 
00261 template <class PrimType>
00262 int MesherFanMaker<PrimType>::
00263 unroll(TYPENAME Strips::iterator strip_begin, TYPENAME Strips::iterator strip_end,
00264        TYPENAME Edges::iterator edge_begin, TYPENAME Edges::iterator edge_end,
00265        pvector<Prim> &unrolled_tris) {
00266   TYPENAME Edges::iterator ei;
00267   TYPENAME Strips::iterator si;
00268 
00269   int num_tris = 0;
00270   for (ei = edge_begin; ei != edge_end; ++ei) {
00271     num_tris++;
00272   }
00273 
00274   if (num_tris < 3) {
00275     // Don't even bother.
00276     return 0;
00277   }
00278 
00279   Prim poly;
00280 
00281   // Now we build an n-sided polygon.  We'll decompose it into tris
00282   // in a second.
00283   poly.set_type(BPT_poly);
00284   poly.set_attrib((*strip_begin)->_prims.front());
00285 
00286   ei = edge_end;
00287   --ei;
00288   if ( !((*ei)->_b == (*edge_begin)->_a)) {
00289     // If the fan is less than a full circle, we need to keep the
00290     // hub vertex and initial vertex in the poly.  Otherwise, we'll
00291     // discard them.
00292     poly.add_vertex(*_vertex);
00293     poly.add_vertex(*(*edge_begin)->_a);
00294   }
00295 
00296   for (ei = edge_begin; ei != edge_end; ++ei) {
00297     poly.add_vertex(*(*ei)->_b);
00298   }
00299 
00300   int result = true;
00301 
00302   if (_bucket->_show_quads) {
00303     // If we're showing quads, also show retesselated triangles.
00304 
00305     // We can't add it directly to the mesher, that's unsafe; instead,
00306     // we'll just add it to the end of the unrolled_tris list.  This
00307     // does mean we won't be able to color it a fancy color, but too
00308     // bad.
00309     //_mesher->add_prim(poly, MO_fanpoly);
00310     unrolled_tris.push_back(poly);
00311 
00312   } else {
00313     // Now decompose the new polygon into triangles.
00314     pvector<Prim> tris;
00315     result = expand(poly, *_bucket, back_inserter(tris));
00316 
00317     if (result) {
00318       unrolled_tris.insert(unrolled_tris.end(),
00319                            tris.begin(), tris.end());
00320     }
00321   }
00322 
00323   if (result) {
00324     // Now that we've created a new poly, kill off all the old ones.
00325     for (si = strip_begin; si != strip_end; ++si) {
00326       (*si)->remove_all_edges();
00327       (*si)->_verts.clear();
00328       (*si)->_prims.clear();
00329       (*si)->_status = MS_dead;
00330     }
00331     return 1;
00332   } else {
00333     return 0;
00334   }
00335 
00336 }
00337 
00338 template <class PrimType>
00339 ostream &MesherFanMaker<PrimType>::
00340 output(ostream &out) const {
00341   out << *_vertex << ":[";
00342   if (!_edges.empty()) {
00343     TYPENAME Edges::const_iterator ei;
00344     for (ei = _edges.begin(); ei != _edges.end(); ++ei) {
00345       out << " " << *(*ei)->_a;
00346     }
00347     out << " " << *_edges.back()->_b;
00348   }
00349   out << " ]";
00350 
00351   if (_planar) {
00352     out << " (planar)";
00353   }
00354   return out;
00355 }

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