Panda3D
 All Classes Functions Variables Enumerations
qtessInputFile.cxx
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, &params[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 }
 All Classes Functions Variables Enumerations