Panda3D
|
00001 // Filename: qtessInputFile.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 "qtessInputFile.h" 00016 #include "config_egg_qtess.h" 00017 #include "string_utils.h" 00018 00019 //////////////////////////////////////////////////////////////////// 00020 // Function: QtessInputFile::Constructor 00021 // Access: Public 00022 // Description: 00023 //////////////////////////////////////////////////////////////////// 00024 QtessInputFile:: 00025 QtessInputFile() { 00026 } 00027 00028 //////////////////////////////////////////////////////////////////// 00029 // Function: QtessInputFile::read 00030 // Access: Public 00031 // Description: reads the input file. 00032 //////////////////////////////////////////////////////////////////// 00033 bool QtessInputFile:: 00034 read(const Filename &filename) { 00035 _filename = Filename::text_filename(filename); 00036 _entries.clear(); 00037 00038 ifstream input; 00039 if (!_filename.open_read(input)) { 00040 qtess_cat.error() 00041 << "Unable to open input file " << _filename << "\n"; 00042 return false; 00043 } 00044 00045 string complete_line; 00046 00047 int line_number = 0; 00048 string line; 00049 while (getline(input, line)) { 00050 line_number++; 00051 00052 // Eliminate comments. We have to scan the line repeatedly until 00053 // we find the first hash mark that's preceded by whitespace. 00054 size_t comment = line.find('#'); 00055 while (comment != string::npos) { 00056 if (comment == 0 || isspace(line[comment - 1])) { 00057 line = line.substr(0, comment); 00058 comment = string::npos; 00059 00060 } else { 00061 comment = line.find('#', comment + 1); 00062 } 00063 } 00064 00065 // Check for a trailing backslash: continuation character. 00066 line = trim_right(line); 00067 if (!line.empty() && line[line.size() - 1] == '\\') { 00068 // We have a continuation character; go back and read some more. 00069 complete_line += line.substr(0, line.size() - 1); 00070 00071 } else { 00072 // It's a complete line. Begin parsing. 00073 line = trim(complete_line + line); 00074 complete_line = string(); 00075 00076 if (!line.empty()) { 00077 QtessInputEntry entry; 00078 00079 // Scan for the first colon followed by whitespace. 00080 size_t colon = line.find(": "); 00081 if (colon == string::npos) { 00082 qtess_cat.error() 00083 << _filename << ": line " << line_number 00084 << " has no colon followed by whitespace.\n"; 00085 return false; 00086 } 00087 if (colon == 0) { 00088 qtess_cat.error() 00089 << _filename << ": line " << line_number 00090 << " has no nodes.\n"; 00091 return false; 00092 } 00093 00094 // Split the line into two groups of words at the colon: names 00095 // before the colon, and params following it. 00096 vector_string names, params; 00097 extract_words(line.substr(0, colon), names); 00098 extract_words(line.substr(colon + 1), params); 00099 00100 vector_string::const_iterator ni; 00101 for (ni = names.begin(); ni != names.end(); ++ni) { 00102 entry.add_node_name(*ni); 00103 } 00104 00105 // Scan for things like ap, ad, ar, and pull them out of the 00106 // stream. 00107 vector_string::iterator ci, cnext; 00108 ci = params.begin(); 00109 while (ci != params.end()) { 00110 cnext = ci; 00111 ++cnext; 00112 00113 string param = *ci; 00114 bool invert = false; 00115 if (param[0] == '!' && param.size() > 1) { 00116 invert = true; 00117 param = param.substr(1); 00118 } 00119 if (tolower(param[0]) == 'a' && param.size() > 1) { 00120 switch (tolower(param[1])) { 00121 case 'p': 00122 entry._auto_place = !invert; 00123 break; 00124 00125 case 'd': 00126 entry._auto_distribute = !invert; 00127 break; 00128 00129 case 'r': 00130 if (!string_to_double(param.substr(2), entry._curvature_ratio)) { 00131 qtess_cat.error() 00132 << _filename << ": line " << line_number 00133 << " - invalid field " << param << "\n"; 00134 return false; 00135 } 00136 break; 00137 00138 default: 00139 qtess_cat.error() 00140 << _filename << ": invalid parameters at line " 00141 << line_number << ".\n"; 00142 return false; 00143 } 00144 params.erase(ci); 00145 } else { 00146 ci = cnext; 00147 } 00148 } 00149 00150 if (!params.empty()) { 00151 bool okflag = true; 00152 if (cmp_nocase(params[0], "omit")==0) { 00153 entry.set_omit(); 00154 00155 } else if (cmp_nocase(params[0], "matchuu")==0) { 00156 entry.set_match_uu(); 00157 if (params.size() > 1 && cmp_nocase(params[1], "matchvv")==0) { 00158 entry.set_match_vv(); 00159 } 00160 00161 } else if (cmp_nocase(params[0], "matchvv")==0) { 00162 entry.set_match_vv(); 00163 if (params.size() > 1 && cmp_nocase(params[1], "matchuu")==0) { 00164 entry.set_match_uu(); 00165 } 00166 00167 } else if (cmp_nocase(params[0], "matchuv")==0) { 00168 entry.set_match_uv(); 00169 if (params.size() > 1 && cmp_nocase(params[1], "matchvu")==0) { 00170 entry.set_match_vu(); 00171 } 00172 00173 } else if (cmp_nocase(params[0], "matchvu")==0) { 00174 entry.set_match_vu(); 00175 if (params.size() > 1 && cmp_nocase(params[1], "matchuv")==0) { 00176 entry.set_match_uv(); 00177 } 00178 00179 } else if (cmp_nocase(params[0], "minu")==0) { 00180 // minu #: minimum tesselation in U. 00181 if (params.size() < 2) { 00182 okflag = false; 00183 } else { 00184 int value = 0; 00185 okflag = string_to_int(params[1], value); 00186 entry.set_min_u(value); 00187 } 00188 00189 } else if (cmp_nocase(params[0], "minv")==0) { 00190 // minu #: minimum tesselation in V. 00191 if (params.size() < 2) { 00192 okflag = false; 00193 } else { 00194 int value = 0; 00195 okflag = string_to_int(params[1], value); 00196 entry.set_min_v(value); 00197 } 00198 00199 } else if (tolower(params[0][0]) == 'i') { 00200 // "i#": per-isoparam tesselation. 00201 int value = 0; 00202 okflag = string_to_int(params[0].substr(1), value); 00203 entry.set_per_isoparam(value); 00204 00205 } else if (params[0][params[0].length() - 1] == '%') { 00206 double value = 0.0; 00207 okflag = string_to_double(params[0].substr(0, params[0].length() - 1), value); 00208 entry.set_importance(value / 100.0); 00209 00210 } else if (params.size() == 1) { 00211 // One numeric parameter: the number of triangles. 00212 int value = 0; 00213 okflag = string_to_int(params[0], value); 00214 entry.set_num_tris(value); 00215 00216 } else if (params.size() >= 2) { 00217 // Two or more numeric parameters: the number of u by v quads, 00218 // followed by an optional list of specific isoparams. 00219 int u = 0, v = 0; 00220 okflag = string_to_int(params[0], u) && string_to_int(params[1], v); 00221 entry.set_uv(u, v, ¶ms[2], params.size() - 2); 00222 00223 } else { 00224 okflag = false; 00225 } 00226 00227 if (!okflag) { 00228 qtess_cat.error() 00229 << _filename << ": invalid parameters at line " 00230 << line_number << ".\n"; 00231 return false; 00232 } 00233 } 00234 _entries.push_back(entry); 00235 } 00236 } 00237 } 00238 00239 if (qtess_cat.is_info()) { 00240 qtess_cat.info() 00241 << "read qtess parameter file " << _filename << ".\n"; 00242 if (qtess_cat.is_debug()) { 00243 write(qtess_cat.debug(false)); 00244 } 00245 } 00246 00247 add_default_entry(); 00248 00249 return true; 00250 } 00251 00252 //////////////////////////////////////////////////////////////////// 00253 // Function: QtessInputFile::get_default_entry 00254 // Access: Public 00255 // Description: Returns a reference to the last entry on the list, 00256 // which is the "default" entry that will match any 00257 // surface that does not get explicitly named in the 00258 // input file. 00259 //////////////////////////////////////////////////////////////////// 00260 QtessInputEntry &QtessInputFile:: 00261 get_default_entry() { 00262 if (_entries.empty()) { 00263 // No entries; create one. 00264 add_default_entry(); 00265 } 00266 return _entries.back(); 00267 } 00268 00269 00270 //////////////////////////////////////////////////////////////////// 00271 // Function: QtessInputFile::match 00272 // Access: Public 00273 // Description: Attempts to find a match for the given surface in the 00274 // user input entries. Searches in the order in which 00275 // the entries were defined, and chooses the first 00276 // match. 00277 // 00278 // When a match is found, the surface is added to the 00279 // entry's set of matched surfaces. Returns the type of 00280 // the matching node if a match is found, or T_undefined 00281 // otherwise. 00282 //////////////////////////////////////////////////////////////////// 00283 QtessInputEntry::Type QtessInputFile:: 00284 match(QtessSurface *surface) { 00285 QtessInputEntry::Type type; 00286 00287 if (_entries.empty()) { 00288 // No entries; create one. 00289 add_default_entry(); 00290 } 00291 00292 Entries::iterator ei; 00293 for (ei = _entries.begin(); ei != _entries.end(); ++ei) { 00294 type = (*ei).match(surface); 00295 if (type != QtessInputEntry::T_undefined) { 00296 return type; 00297 } 00298 } 00299 return QtessInputEntry::T_undefined; 00300 } 00301 00302 //////////////////////////////////////////////////////////////////// 00303 // Function: QtessInputFile::count_tris 00304 // Access: Public 00305 // Description: Determines the tesselation u,v amounts of each 00306 // attached surface, and stores this information in the 00307 // surface pointer. Returns the total number of tris 00308 // that will be produced. 00309 //////////////////////////////////////////////////////////////////// 00310 int QtessInputFile:: 00311 count_tris() { 00312 int total_tris = 0; 00313 00314 Entries::iterator ei; 00315 for (ei = _entries.begin(); ei != _entries.end(); ++ei) { 00316 total_tris += (*ei).count_tris(); 00317 } 00318 return total_tris; 00319 } 00320 00321 //////////////////////////////////////////////////////////////////// 00322 // Function: QtessInputFile::write 00323 // Access: Public 00324 // Description: 00325 //////////////////////////////////////////////////////////////////// 00326 void QtessInputFile:: 00327 write(ostream &out, int indent_level) const { 00328 Entries::const_iterator ei; 00329 for (ei = _entries.begin(); ei != _entries.end(); ++ei) { 00330 (*ei).write(out, indent_level); 00331 } 00332 } 00333 00334 //////////////////////////////////////////////////////////////////// 00335 // Function: QtessInputFile::add_default_entry 00336 // Access: Private 00337 // Description: Adds one more entry to the end of the list, to catch 00338 // all of the surfaces that didn't get explicitly named. 00339 //////////////////////////////////////////////////////////////////// 00340 void QtessInputFile:: 00341 add_default_entry() { 00342 QtessInputEntry entry("*"); 00343 entry.set_omit(); 00344 _entries.push_back(entry); 00345 }