Panda3D
Loading...
Searching...
No Matches
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:44
bool open_read(std::ifstream &stream) const
Opens the indicated ifstream for reading the file, if possible.
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...
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.