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  */
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 }
int string_to_int(const string &str, string &tail)
A string-interface wrapper around the C library strtol().
A reference to an EggNurbsSurface in the egg file, and its parameters as set by the user input file a...
Definition: qtessSurface.h:32
double string_to_double(const string &str, string &tail)
A string-interface wrapper around the C library strtol().
bool open_read(std::ifstream &stream) const
Opens the indicated ifstream for reading the file, if possible.
Definition: filename.cxx:1863
QtessInputEntry::Type match(QtessSurface *surface)
Attempts to find a match for the given surface in the user input entries.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int count_tris()
Determines the tesselation u,v amounts of each attached surface, and stores this information in the s...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int extract_words(const string &str, vector_string &words)
Divides the string into a number of words according to whitespace.
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
QtessInputEntry & get_default_entry()
Returns a reference to the last entry on the list, which is the "default" entry that will match any s...
Stores one entry in the qtess input file.
string trim(const string &str)
Returns a new string representing the contents of the given string with both leading and trailing whi...
bool read(const Filename &filename)
reads the input file.
string trim_right(const string &str)
Returns a new string representing the contents of the given string with the trailing whitespace remov...