Panda3D
|
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 ©) { 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 ¶m = 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 }