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
18using std::string;
19
20/**
21 *
22 */
23QtessInputFile::
24QtessInputFile() {
25}
26
27/**
28 * reads the input file.
29 */
31read(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 */
272QtessInputEntry::Type QtessInputFile::
273match(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 */
297count_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 */
310void QtessInputFile::
311write(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 */
322void QtessInputFile::
323add_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.