qtessInputEntry.cxx

00001 // Filename: qtessInputEntry.cxx
00002 // Created by:  drose (13Oct03)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "qtessInputEntry.h"
00016 #include "qtessSurface.h"
00017 #include "qtessGlobals.h"
00018 #include "config_egg_qtess.h"
00019 #include "indent.h"
00020 #include "string_utils.h"
00021 
00022 #include <ctype.h>
00023 #include <algorithm>
00024 
00025 ////////////////////////////////////////////////////////////////////
00026 //     Function: QtessInputEntry::Constructor
00027 //       Access: Public
00028 //  Description:
00029 ////////////////////////////////////////////////////////////////////
00030 QtessInputEntry::
00031 QtessInputEntry(const string &name) {
00032   _type = T_undefined;
00033   _num_patches = 0.0;
00034   _auto_place = QtessGlobals::_auto_place;
00035   _auto_distribute = QtessGlobals::_auto_distribute;
00036   _curvature_ratio = QtessGlobals::_curvature_ratio;
00037   if (!name.empty()) {
00038     add_node_name(name);
00039   }
00040 }
00041 
00042 ////////////////////////////////////////////////////////////////////
00043 //     Function: QtessInputEntry::Copy Assignment Operator
00044 //       Access: Public
00045 //  Description:
00046 ////////////////////////////////////////////////////////////////////
00047 void QtessInputEntry::
00048 operator = (const QtessInputEntry &copy) {
00049   _node_names = copy._node_names;
00050   _type = copy._type;
00051   _num_tris = copy._num_tris;
00052   _num_u = copy._num_u;
00053   _num_v = copy._num_v;
00054   _per_isoparam = copy._per_isoparam;
00055   _iso_u = copy._iso_u;
00056   _iso_v = copy._iso_v;
00057   _surfaces = copy._surfaces;
00058   _num_patches = copy._num_patches;
00059   _auto_place = copy._auto_place;
00060   _auto_distribute = copy._auto_distribute;
00061   _curvature_ratio = copy._curvature_ratio;
00062   _importance = copy._importance;
00063   _constrain_u = copy._constrain_u;
00064   _constrain_v = copy._constrain_v;
00065 }
00066 
00067 ////////////////////////////////////////////////////////////////////
00068 //       Class : DoublesAlmostEqual
00069 // Description : An STL function object to determine if two doubles
00070 //               are very nearly equal.  Used in set_uv(), below.
00071 ////////////////////////////////////////////////////////////////////
00072 class DoublesAlmostEqual {
00073 public:
00074   int operator ()(double a, double b) const {
00075     return fabs(a - b) < 0.00001;
00076   }
00077 };
00078 
00079 ////////////////////////////////////////////////////////////////////
00080 //       Class : DoubleAlmostMatches
00081 // Description : An STL function object to determine if a double
00082 //               is vert nearly equal the supplied value .  Used in
00083 //               set_uv(), below.
00084 ////////////////////////////////////////////////////////////////////
00085 class DoubleAlmostMatches {
00086 public:
00087   DoubleAlmostMatches(double v) : _v(v) {}
00088   int operator ()(double a) const {
00089     return fabs(a - _v) < 0.00001;
00090   }
00091   double _v;
00092 };
00093 
00094 
00095 ////////////////////////////////////////////////////////////////////
00096 //     Function: QtessInputEntry::set_uv
00097 //       Access: Public
00098 //  Description: Sets specific tesselation.  The tesselation will be u
00099 //               by v quads, with the addition of any isoparams
00100 //               described in the list of params.
00101 ////////////////////////////////////////////////////////////////////
00102 void QtessInputEntry::
00103 set_uv(int u, int v, const string params[], int num_params) {
00104   _num_u = u;
00105   _num_v = v;
00106 
00107   // First, fill up the arrays with the defaults.
00108   int i;
00109   for (i = 0; i <= _num_u; i++) {
00110     _iso_u.push_back(i);
00111   }
00112   for (i = 0; i <= _num_v; i++) {
00113     _iso_v.push_back(i);
00114   }
00115 
00116   // Then get out all the additional entries.
00117   for (i = 0; i < num_params; i++) {
00118     const string &param = params[i];
00119 
00120     if (param[0] == '!' && param.size() > 2) {
00121       double value;
00122       if (!string_to_double(param.substr(2), value)) {
00123         qtess_cat.warning()
00124           << "Ignoring invalid parameter: " << param << "\n";
00125       } else {
00126         switch (tolower(param[1])) {
00127         case 'u':
00128           _auto_place = false;
00129           _iso_u.erase(remove_if(_iso_u.begin(), _iso_u.end(), 
00130                                  DoubleAlmostMatches(value)),
00131                        _iso_u.end());
00132           break;
00133           
00134         case 'v':
00135           _auto_place = false;
00136           _iso_v.erase(remove_if(_iso_v.begin(), _iso_v.end(),
00137                                  DoubleAlmostMatches(value)),
00138                        _iso_v.end());
00139           break;
00140 
00141         default:
00142           qtess_cat.warning()
00143             << "Ignoring invalid parameter: " << params[i] << "\n";
00144         }
00145       }
00146     } else {
00147       double value;
00148       if (!string_to_double(param.substr(1), value)) {
00149         qtess_cat.warning()
00150           << "Ignoring invalid parameter: " << param << "\n";
00151       } else {
00152         switch (tolower(param[0])) {
00153         case 'u':
00154           _auto_place = false;
00155           _iso_u.push_back(value);
00156           break;
00157           
00158         case 'v':
00159           _auto_place = false;
00160           _iso_v.push_back(value);
00161           break;
00162           
00163         default:
00164           qtess_cat.warning()
00165             << "Ignoring invalid parameter: " << params[i] << "\n";
00166         }
00167       }
00168     }
00169   }
00170 
00171   // Now sort them into ascending order and remove duplicates.
00172   sort(_iso_u.begin(), _iso_u.end());
00173   sort(_iso_v.begin(), _iso_v.end());
00174   _iso_u.erase(unique(_iso_u.begin(), _iso_u.end(), DoublesAlmostEqual()), _iso_u.end());
00175   _iso_v.erase(unique(_iso_v.begin(), _iso_v.end(), DoublesAlmostEqual()), _iso_v.end());
00176 
00177   _type = T_uv;
00178 }
00179 
00180 
00181 ////////////////////////////////////////////////////////////////////
00182 //     Function: QtessInputEntry::add_extra_u_isoparam
00183 //       Access: Public
00184 //  Description: May be called a number of times before set_uv() to add
00185 //               specific additional isoparams to the tesselation.
00186 ////////////////////////////////////////////////////////////////////
00187 void QtessInputEntry::
00188 add_extra_u_isoparam(double u) {
00189   _iso_u.push_back(u);
00190 }
00191 
00192 ////////////////////////////////////////////////////////////////////
00193 //     Function: QtessInputEntry::add_extra_v_isoparam
00194 //       Access: Public
00195 //  Description: May be called a number of times before set_uv() to add
00196 //               specific additional isoparams to the tesselation.
00197 ////////////////////////////////////////////////////////////////////
00198 void QtessInputEntry::
00199 add_extra_v_isoparam(double v) {
00200   _iso_v.push_back(v);
00201 }
00202 
00203 ////////////////////////////////////////////////////////////////////
00204 //     Function: QtessInputEntry::match
00205 //       Access: Public
00206 //  Description: Tests the surface to see if it matches any of the
00207 //               regular expressions that define this node entry.  If
00208 //               so, adds it to the set of matched surfaces and
00209 //               returns the type of the matching entry.  If no match
00210 //               is found, returns T_undefined.
00211 ////////////////////////////////////////////////////////////////////
00212 QtessInputEntry::Type QtessInputEntry::
00213 match(QtessSurface *surface) {
00214   const string &name = surface->get_name();
00215 
00216   NodeNames::const_iterator nni;
00217   for (nni = _node_names.begin();
00218        nni != _node_names.end();
00219        ++nni) {
00220     const GlobPattern &pattern = (*nni);
00221     if (pattern.matches(name)) {
00222       // We have a winner!
00223       switch (_type) {
00224       case T_importance:
00225         // A type of "Importance" is a special case.  This entry
00226         // doesn't specify any kind of tesselation on the surface, and
00227         // in fact doesn't preclude the surface from matching anything
00228         // later.  It just specifies the relative importance of the
00229         // surface to all the other surfaces.
00230         if (qtess_cat.is_debug()) {
00231           qtess_cat.debug() 
00232             << "Assigning importance of " << _importance*100.0 
00233             << "% to " << name << "\n";
00234         }
00235         surface->set_importance(_importance);
00236         return T_undefined;
00237 
00238       case T_match_uu:
00239       case T_match_uv:
00240         // Similarly for type "matchUU".  This indicates that all the
00241         // surfaces that match this one must all share the
00242         // U-tesselation with whichever surface first matched against
00243         // the first node name.
00244         if (nni == _node_names.begin() && _constrain_u==NULL) {
00245           // This is the lucky surface that dominates!
00246           _constrain_u = surface;
00247         } else {
00248           if (_type == T_match_uu) {
00249             surface->set_match_u(&_constrain_u, true);
00250           } else {
00251             surface->set_match_v(&_constrain_u, false);
00252           }
00253         }
00254         return T_undefined;
00255 
00256       case T_match_vv:
00257       case T_match_vu:
00258         // Ditto for "matchVV".
00259         if (nni == _node_names.begin() && _constrain_v==NULL) {
00260           // This is the lucky surface that dominates!
00261           _constrain_v = surface;
00262         } else {
00263           if (_type == T_match_vv) {
00264             surface->set_match_v(&_constrain_v, true);
00265           } else {
00266             surface->set_match_u(&_constrain_v, false);
00267           }
00268         }
00269         return T_undefined;
00270 
00271       case T_min_u:
00272         // And for min U and V.
00273         if (qtess_cat.is_debug()) {
00274           qtess_cat.debug()
00275             << "Assigning minimum of " << _num_u << " in U to "
00276             << name << "\n";
00277         }
00278         surface->set_min_u(_num_u);
00279         return T_undefined;
00280 
00281       case T_min_v:
00282         if (qtess_cat.is_debug()) {
00283           qtess_cat.debug()
00284             << "Assigning minimum of " << _num_v << " in V to "
00285             << name << "\n";
00286         }
00287         surface->set_min_v(_num_v);
00288         return T_undefined;
00289 
00290       default:
00291         _surfaces.push_back(surface);
00292         if (_auto_distribute) {
00293           _num_patches += surface->get_score(_curvature_ratio);
00294         } else {
00295           _num_patches += surface->count_patches();
00296         }
00297         return _type;
00298       }
00299     }
00300   }
00301 
00302   return T_undefined;
00303 }
00304 
00305 ////////////////////////////////////////////////////////////////////
00306 //     Function: QtessInputEntry::count_tris
00307 //       Access: Public
00308 //  Description: Determines the tesselation u,v amounts of each
00309 //               attached surface, and stores this information in the
00310 //               surface pointer.  Returns the total number of tris
00311 //               that will be produced.
00312 ////////////////////////////////////////////////////////////////////
00313 int QtessInputEntry::
00314 count_tris(double tri_factor, int attempts) {
00315   int total_tris = 0;
00316   bool aim_for_tris = false;
00317 
00318   if (_type == T_num_tris && _num_patches > 0.0) {
00319     // If we wanted to aim for a particular number of triangles for
00320     // the group, choose a per-isoparam setting that will approximately
00321     // achieve this.
00322     if (_auto_distribute) {
00323       set_per_score(sqrt(0.5 * (double)_num_tris / _num_patches / tri_factor));
00324     } else {
00325       set_per_isoparam(sqrt(0.5 * (double)_num_tris / _num_patches / tri_factor));
00326     }
00327     aim_for_tris = true;
00328   }
00329 
00330   Surfaces::iterator si;
00331   for (si = _surfaces.begin(); si != _surfaces.end(); ++si) {
00332     QtessSurface *surface = (*si);
00333 
00334     switch (_type) {
00335     case T_undefined:
00336     case T_omit:
00337       surface->omit();
00338       break;
00339       
00340     case T_uv:
00341       if (!_iso_u.empty() && !_iso_v.empty() && !_auto_place) {
00342         surface->tesselate_specific(_iso_u, _iso_v);
00343       } else {
00344         surface->tesselate_uv(_num_u, _num_v, _auto_place, _curvature_ratio);
00345       }
00346       break;
00347       
00348     case T_per_isoparam:
00349       surface->tesselate_per_isoparam(_per_isoparam, _auto_place, _curvature_ratio);
00350       break;
00351       
00352     case T_per_score:
00353       surface->tesselate_per_score(_per_isoparam, _auto_place, _curvature_ratio);
00354       break;
00355 
00356     default:
00357       break;
00358     }
00359 
00360     total_tris += surface->count_tris();
00361   }
00362 
00363   if (aim_for_tris && attempts < 10 && 
00364       (double)total_tris / (double)_num_tris > 1.1) {
00365     // We'd like to get within 10% of the requested number of
00366     // triangles, if possible.  Keep trying until we do, or until we
00367     // just need to give up.
00368     set_num_tris(_num_tris);
00369     return count_tris(tri_factor * total_tris / _num_tris, attempts + 1);
00370   }
00371 
00372   return total_tris;
00373 }
00374 
00375 
00376 ////////////////////////////////////////////////////////////////////
00377 //     Function: QtessInputEntry::output_extra
00378 //       Access: Public, Static
00379 //  Description: This function is used to identify the extra isoparams
00380 //               in the list added by user control.
00381 ////////////////////////////////////////////////////////////////////
00382 void QtessInputEntry::
00383 output_extra(ostream &out, const pvector<double> &iso, char axis) {
00384   pvector<double>::const_iterator di;
00385   int expect = 0;
00386   for (di = iso.begin(); di != iso.end(); ++di) {
00387     while ((*di) > (double)expect) {
00388       // Didn't find one we were expecting.  Omit it.
00389       out << " !" << axis << expect;
00390     }
00391     if ((*di)==(double)expect) {
00392       // Here's one we were expecting; ignore it.
00393       expect++;
00394     } else {
00395       // Here's a new one.  Write it.
00396       out << " " << axis << *di;
00397     }
00398   }
00399 }
00400 
00401 ////////////////////////////////////////////////////////////////////
00402 //     Function: QtessInputEntry::output
00403 //       Access: Public
00404 //  Description:
00405 ////////////////////////////////////////////////////////////////////
00406 void QtessInputEntry::
00407 output(ostream &out) const {
00408   NodeNames::const_iterator nni;
00409   for (nni = _node_names.begin();
00410        nni != _node_names.end();
00411        ++nni) {
00412     out << (*nni) << " ";
00413   }
00414   out << ": ";
00415 
00416   bool show_auto = false;
00417 
00418   switch (_type) {
00419   case T_undefined:
00420     break;
00421 
00422   case T_omit:
00423     out << "omit";
00424     break;
00425 
00426   case T_num_tris:
00427     out << _num_tris;
00428     show_auto = true;
00429     break;
00430     
00431   case T_uv:
00432     out << _num_u << " " << _num_v;
00433     output_extra(out, _iso_u, 'u');
00434     output_extra(out, _iso_v, 'v');
00435     show_auto = true;
00436     break;
00437 
00438   case T_per_isoparam:
00439   case T_per_score:
00440     out << "i" << _per_isoparam;
00441     show_auto = true;
00442     break;
00443 
00444   case T_importance:
00445     out << _importance * 100.0 << "%";
00446     break;
00447 
00448   case T_match_uu:
00449     out << "matchuu";
00450     break;
00451 
00452   case T_match_vv:
00453     out << "matchvv";
00454     break;
00455 
00456   case T_match_uv:
00457     out << "matchuv";
00458     break;
00459 
00460   case T_match_vu:
00461     out << "matchvu";
00462     break;
00463 
00464   case T_min_u:
00465     out << "minu " << _num_u;
00466     break;
00467 
00468   case T_min_v:
00469     out << "minv " << _num_v;
00470     break;
00471 
00472   default:
00473     out << "Invalid!";
00474   }
00475 
00476   if (show_auto) {
00477     out << " " << (_auto_place?"":"!") << "ap"
00478         << " " << (_auto_distribute?"":"!") << "ad";
00479     if (_auto_place || _auto_distribute) {
00480       out << " ar" << _curvature_ratio;
00481     }
00482   }
00483 }
00484 
00485 ////////////////////////////////////////////////////////////////////
00486 //     Function: QtessInputEntry::output
00487 //       Access: Public
00488 //  Description:
00489 ////////////////////////////////////////////////////////////////////
00490 void QtessInputEntry::
00491 write(ostream &out, int indent_level) const {
00492   indent(out, indent_level) << (*this) << "\n";
00493 }