Panda3D
qtessInputFile.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file qtessInputFile.cxx
10  * @author drose
11  * @date 2003-10-13
12  */
13 
14 #include "qtessInputFile.h"
15 #include "config_egg_qtess.h"
16 #include "string_utils.h"
17 
18 using std::string;
19 
20 /**
21  *
22  */
23 QtessInputFile::
24 QtessInputFile() {
25 }
26 
27 /**
28  * reads the input file.
29  */
31 read(const Filename &filename) {
32  _filename = Filename::text_filename(filename);
33  _entries.clear();
34 
35  std::ifstream input;
36  if (!_filename.open_read(input)) {
37  qtess_cat.error()
38  << "Unable to open input file " << _filename << "\n";
39  return false;
40  }
41 
42  string complete_line;
43 
44  int line_number = 0;
45  string line;
46  while (std::getline(input, line)) {
47  line_number++;
48 
49  // Eliminate comments. We have to scan the line repeatedly until we find
50  // the first hash mark that's preceded by whitespace.
51  size_t comment = line.find('#');
52  while (comment != string::npos) {
53  if (comment == 0 || isspace(line[comment - 1])) {
54  line = line.substr(0, comment);
55  comment = string::npos;
56 
57  } else {
58  comment = line.find('#', comment + 1);
59  }
60  }
61 
62  // Check for a trailing backslash: continuation character.
63  line = trim_right(line);
64  if (!line.empty() && line[line.size() - 1] == '\\') {
65  // We have a continuation character; go back and read some more.
66  complete_line += line.substr(0, line.size() - 1);
67 
68  } else {
69  // It's a complete line. Begin parsing.
70  line = trim(complete_line + line);
71  complete_line = string();
72 
73  if (!line.empty()) {
74  QtessInputEntry entry;
75 
76  // Scan for the first colon followed by whitespace.
77  size_t colon = line.find(": ");
78  if (colon == string::npos) {
79  qtess_cat.error()
80  << _filename << ": line " << line_number
81  << " has no colon followed by whitespace.\n";
82  return false;
83  }
84  if (colon == 0) {
85  qtess_cat.error()
86  << _filename << ": line " << line_number
87  << " has no nodes.\n";
88  return false;
89  }
90 
91  // Split the line into two groups of words at the colon: names before
92  // the colon, and params following it.
93  vector_string names, params;
94  extract_words(line.substr(0, colon), names);
95  extract_words(line.substr(colon + 1), params);
96 
97  vector_string::const_iterator ni;
98  for (ni = names.begin(); ni != names.end(); ++ni) {
99  entry.add_node_name(*ni);
100  }
101 
102  // Scan for things like ap, ad, ar, and pull them out of the stream.
103  vector_string::iterator ci, cnext;
104  ci = params.begin();
105  while (ci != params.end()) {
106  cnext = ci;
107  ++cnext;
108 
109  string param = *ci;
110  bool invert = false;
111  if (param[0] == '!' && param.size() > 1) {
112  invert = true;
113  param = param.substr(1);
114  }
115  if (tolower(param[0]) == 'a' && param.size() > 1) {
116  switch (tolower(param[1])) {
117  case 'p':
118  entry._auto_place = !invert;
119  break;
120 
121  case 'd':
122  entry._auto_distribute = !invert;
123  break;
124 
125  case 'r':
126  if (!string_to_double(param.substr(2), entry._curvature_ratio)) {
127  qtess_cat.error()
128  << _filename << ": line " << line_number
129  << " - invalid field " << param << "\n";
130  return false;
131  }
132  break;
133 
134  default:
135  qtess_cat.error()
136  << _filename << ": invalid parameters at line "
137  << line_number << ".\n";
138  return false;
139  }
140  params.erase(ci);
141  } else {
142  ci = cnext;
143  }
144  }
145 
146  if (!params.empty()) {
147  bool okflag = true;
148  if (cmp_nocase(params[0], "omit")==0) {
149  entry.set_omit();
150 
151  } else if (cmp_nocase(params[0], "matchuu")==0) {
152  entry.set_match_uu();
153  if (params.size() > 1 && cmp_nocase(params[1], "matchvv")==0) {
154  entry.set_match_vv();
155  }
156 
157  } else if (cmp_nocase(params[0], "matchvv")==0) {
158  entry.set_match_vv();
159  if (params.size() > 1 && cmp_nocase(params[1], "matchuu")==0) {
160  entry.set_match_uu();
161  }
162 
163  } else if (cmp_nocase(params[0], "matchuv")==0) {
164  entry.set_match_uv();
165  if (params.size() > 1 && cmp_nocase(params[1], "matchvu")==0) {
166  entry.set_match_vu();
167  }
168 
169  } else if (cmp_nocase(params[0], "matchvu")==0) {
170  entry.set_match_vu();
171  if (params.size() > 1 && cmp_nocase(params[1], "matchuv")==0) {
172  entry.set_match_uv();
173  }
174 
175  } else if (cmp_nocase(params[0], "minu")==0) {
176  // minu #: minimum tesselation in U.
177  if (params.size() < 2) {
178  okflag = false;
179  } else {
180  int value = 0;
181  okflag = string_to_int(params[1], value);
182  entry.set_min_u(value);
183  }
184 
185  } else if (cmp_nocase(params[0], "minv")==0) {
186  // minu #: minimum tesselation in V.
187  if (params.size() < 2) {
188  okflag = false;
189  } else {
190  int value = 0;
191  okflag = string_to_int(params[1], value);
192  entry.set_min_v(value);
193  }
194 
195  } else if (tolower(params[0][0]) == 'i') {
196  // "i#": per-isoparam tesselation.
197  int value = 0;
198  okflag = string_to_int(params[0].substr(1), value);
199  entry.set_per_isoparam(value);
200 
201  } else if (params[0][params[0].length() - 1] == '%') {
202  double value = 0.0;
203  okflag = string_to_double(params[0].substr(0, params[0].length() - 1), value);
204  entry.set_importance(value / 100.0);
205 
206  } else if (params.size() == 1) {
207  // One numeric parameter: the number of triangles.
208  int value = 0;
209  okflag = string_to_int(params[0], value);
210  entry.set_num_tris(value);
211 
212  } else if (params.size() >= 2) {
213  // Two or more numeric parameters: the number of u by v quads,
214  // followed by an optional list of specific isoparams.
215  int u = 0, v = 0;
216  okflag = string_to_int(params[0], u) && string_to_int(params[1], v);
217  entry.set_uv(u, v, &params[2], params.size() - 2);
218 
219  } else {
220  okflag = false;
221  }
222 
223  if (!okflag) {
224  qtess_cat.error()
225  << _filename << ": invalid parameters at line "
226  << line_number << ".\n";
227  return false;
228  }
229  }
230  _entries.push_back(entry);
231  }
232  }
233  }
234 
235  if (qtess_cat.is_info()) {
236  qtess_cat.info()
237  << "read qtess parameter file " << _filename << ".\n";
238  if (qtess_cat.is_debug()) {
239  write(qtess_cat.debug(false));
240  }
241  }
242 
243  add_default_entry();
244 
245  return true;
246 }
247 
248 /**
249  * Returns a reference to the last entry on the list, which is the "default"
250  * entry that will match any surface that does not get explicitly named in the
251  * input file.
252  */
255  if (_entries.empty()) {
256  // No entries; create one.
257  add_default_entry();
258  }
259  return _entries.back();
260 }
261 
262 
263 /**
264  * Attempts to find a match for the given surface in the user input entries.
265  * Searches in the order in which the entries were defined, and chooses the
266  * first match.
267  *
268  * When a match is found, the surface is added to the entry's set of matched
269  * surfaces. Returns the type of the matching node if a match is found, or
270  * T_undefined otherwise.
271  */
272 QtessInputEntry::Type QtessInputFile::
273 match(QtessSurface *surface) {
274  QtessInputEntry::Type type;
275 
276  if (_entries.empty()) {
277  // No entries; create one.
278  add_default_entry();
279  }
280 
281  Entries::iterator ei;
282  for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
283  type = (*ei).match(surface);
284  if (type != QtessInputEntry::T_undefined) {
285  return type;
286  }
287  }
288  return QtessInputEntry::T_undefined;
289 }
290 
291 /**
292  * Determines the tesselation u,v amounts of each attached surface, and stores
293  * this information in the surface pointer. Returns the total number of tris
294  * that will be produced.
295  */
297 count_tris() {
298  int total_tris = 0;
299 
300  Entries::iterator ei;
301  for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
302  total_tris += (*ei).count_tris();
303  }
304  return total_tris;
305 }
306 
307 /**
308  *
309  */
310 void QtessInputFile::
311 write(std::ostream &out, int indent_level) const {
312  Entries::const_iterator ei;
313  for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
314  (*ei).write(out, indent_level);
315  }
316 }
317 
318 /**
319  * Adds one more entry to the end of the list, to catch all of the surfaces
320  * that didn't get explicitly named.
321  */
322 void QtessInputFile::
323 add_default_entry() {
324  QtessInputEntry entry("*");
325  entry.set_omit();
326  _entries.push_back(entry);
327 }
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
bool open_read(std::ifstream &stream) const
Opens the indicated ifstream for reading the file, if possible.
Definition: filename.cxx:1863
Stores one entry in the qtess input file.
QtessInputEntry & get_default_entry()
Returns a reference to the last entry on the list, which is the "default" entry that will match any s...
int count_tris()
Determines the tesselation u,v amounts of each attached surface, and stores this information in the s...
QtessInputEntry::Type match(QtessSurface *surface)
Attempts to find a match for the given surface in the user input entries.
bool read(const Filename &filename)
reads the input file.
A reference to an EggNurbsSurface in the egg file, and its parameters as set by the user input file a...
Definition: qtessSurface.h:32
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
string trim(const string &str)
Returns a new string representing the contents of the given string with both leading and trailing whi...
int extract_words(const string &str, vector_string &words)
Divides the string into a number of words according to whitespace.
string trim_right(const string &str)
Returns a new string representing the contents of the given string with the trailing whitespace remov...
double string_to_double(const string &str, string &tail)
A string-interface wrapper around the C library strtol().
int string_to_int(const string &str, string &tail)
A string-interface wrapper around the C library strtol().
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.