Panda3D
Loading...
Searching...
No Matches
txaFile.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 txaFile.cxx
10 * @author drose
11 * @date 2000-11-30
12 */
13
14#include "txaFile.h"
15#include "pal_string_utils.h"
16#include "palettizer.h"
17#include "paletteGroup.h"
18#include "textureImage.h"
19
20#include "pnotify.h"
21#include "pnmFileTypeRegistry.h"
22
23using std::string;
24
25/**
26 *
27 */
28TxaFile::
29TxaFile() {
30}
31
32/**
33 * Reads the indicated stream, and returns true if successful, or false if
34 * there is an error.
35 */
37read(std::istream &in, const string &filename) {
38 string line;
39 int line_number = 1;
40
41 int ch = get_line_or_semicolon(in, line);
42 while (ch != EOF || !line.empty()) {
43 bool okflag = true;
44
45 // Strip off the comment.
46 size_t hash = line.find('#');
47 if (hash != string::npos) {
48 line = line.substr(0, hash);
49 }
50 line = trim_left(line);
51 if (line.empty()) {
52 // Empty lines are ignored.
53
54 } else if (line[0] == ':') {
55 // This is a keyword line.
56 vector_string words;
57 extract_words(line, words);
58 if (words[0] == ":group") {
59 okflag = parse_group_line(words);
60
61 } else if (words[0] == ":palette") {
62 okflag = parse_palette_line(words);
63
64 } else if (words[0] == ":margin") {
65 okflag = parse_margin_line(words);
66
67 } else if (words[0] == ":background") {
68 okflag = parse_background_line(words);
69
70 } else if (words[0] == ":coverage") {
71 okflag = parse_coverage_line(words);
72
73 } else if (words[0] == ":powertwo") {
74 okflag = parse_powertwo_line(words);
75
76 } else if (words[0] == ":imagetype") {
77 okflag = parse_imagetype_line(words);
78
79 } else if (words[0] == ":shadowtype") {
80 okflag = parse_shadowtype_line(words);
81
82 } else if (words[0] == ":round") {
83 okflag = parse_round_line(words);
84
85 } else if (words[0] == ":remap") {
86 okflag = parse_remap_line(words);
87
88 } else if (words[0] == ":cutout") {
89 okflag = parse_cutout_line(words);
90
91 } else if (words[0] == ":textureswap") {
92 okflag = parse_textureswap_line(words);
93
94 } else {
95 nout << "Invalid keyword " << words[0] << "\n";
96 okflag = false;
97 }
98
99 } else {
100 _lines.push_back(TxaLine());
101 TxaLine &txa_line = _lines.back();
102
103 okflag = txa_line.parse(line);
104 }
105
106 if (!okflag) {
107 nout << "Error on line " << line_number << " of " << filename << "\n";
108 return false;
109 }
110 if (ch == '\n') {
111 line_number++;
112 }
113 ch = get_line_or_semicolon(in, line);
114 }
115
116 if (!in.eof()) {
117 nout << "I/O error reading " << filename << "\n";
118 return false;
119 }
120
121 return true;
122}
123
124/**
125 * Searches for a matching line in the .txa file for the given egg file and
126 * applies its specifications. If a match is found, returns true; otherwise,
127 * returns false. Also returns false if all the matching lines for the egg
128 * file include the keyword "cont".
129 */
131match_egg(EggFile *egg_file) const {
132 Lines::const_iterator li;
133 for (li = _lines.begin(); li != _lines.end(); ++li) {
134 if ((*li).match_egg(egg_file)) {
135 return true;
136 }
137 }
138
139 return false;
140}
141
142/**
143 * Searches for a matching line in the .txa file for the given texture and
144 * applies its specifications. If a match is found, returns true; otherwise,
145 * returns false. Also returns false if all the matching lines for the
146 * texture include the keyword "cont".
147 */
149match_texture(TextureImage *texture) const {
150 Lines::const_iterator li;
151 for (li = _lines.begin(); li != _lines.end(); ++li) {
152 if ((*li).match_texture(texture)) {
153 return true;
154 }
155 }
156
157 return false;
158}
159
160/**
161 * Outputs a representation of the lines that were read in to the indicated
162 * output stream. This is primarily useful for debugging.
163 */
165write(std::ostream &out) const {
166 Lines::const_iterator li;
167 for (li = _lines.begin(); li != _lines.end(); ++li) {
168 out << (*li) << "\n";
169 }
170}
171
172/**
173 * Reads the next line, or the next semicolon-delimited phrase, from the
174 * indicated input stream. Returns the character that marks the end of the
175 * line, or EOF if the end of file has been reached.
176 */
177int TxaFile::
178get_line_or_semicolon(std::istream &in, string &line) {
179 line = string();
180 int ch = in.get();
181 char semicolon = ';';
182
183 while (ch != EOF && ch != '\n' && ch != semicolon) {
184 if (ch == '#') {
185 // We don't consider a semicolon within a comment to be a line break.
186 semicolon = EOF;
187 }
188 line += ch;
189 ch = in.get();
190 }
191
192 return ch;
193}
194
195/**
196 * Handles the line in a .txa file that begins with the keyword ":group" and
197 * indicates the relationships between one or more groups.
198 */
199bool TxaFile::
200parse_group_line(const vector_string &words) {
201 vector_string::const_iterator wi;
202 wi = words.begin();
203 assert (wi != words.end());
204 ++wi;
205
206 const string &group_name = (*wi);
207 PaletteGroup *group = pal->get_palette_group(group_name);
208 ++wi;
209
210 enum State {
211 S_none,
212 S_on,
213 S_includes,
214 S_dir,
215 S_margin,
216 };
217 State state = S_none;
218
219 bool first_on = true;
220
221 while (wi != words.end()) {
222 const string &word = (*wi);
223 if (word == "with") {
224 // Deprecated keyword: "with" means the same thing as "on".
225 state = S_on;
226
227 } else if (word == "on") {
228 state = S_on;
229
230 } else if (word == "includes") {
231 state = S_includes;
232
233 } else if (word == "dir") {
234 state = S_dir;
235
236 } else if (word == "margin") {
237 state = S_margin;
238
239 } else {
240 switch (state) {
241 case S_none:
242 nout << "Invalid keyword: " << word << "\n";
243 return false;
244
245 case S_on:
246 {
247 PaletteGroup *on_group = pal->get_palette_group(word);
248 if (first_on) {
249 if (!group->has_dirname() && on_group->has_dirname()) {
250 group->set_dirname(on_group->get_dirname());
251 }
252 first_on = false;
253 }
254 group->group_with(on_group);
255 }
256 break;
257
258 case S_includes:
259 pal->get_palette_group(word)->group_with(group);
260 break;
261
262 case S_dir:
263 group->set_dirname(word);
264 state = S_none;
265 break;
266
267 case S_margin:
268 int margin_override;
269 if (string_to_int(word, margin_override)) {
270 group->set_margin_override(margin_override);
271 }
272 state = S_none;
273 break;
274 }
275
276 }
277
278 ++wi;
279 }
280
281 return true;
282}
283
284/**
285 * Handles the line in a .txa file that begins with the keyword ":palette" and
286 * indicates the appropriate size for the palette images.
287 */
288bool TxaFile::
289parse_palette_line(const vector_string &words) {
290 if (words.size() != 3) {
291 nout << "Exactly two parameters required for :palette, the x and y "
292 << "size of the palette images to generate.\n";
293 return false;
294 }
295
296 if (!string_to_int(words[1], pal->_pal_x_size) ||
297 !string_to_int(words[2], pal->_pal_y_size)) {
298 nout << "Invalid palette size: " << words[1] << " " << words[2] << "\n";
299 return false;
300 }
301
302 if (pal->_pal_x_size <= 0 || pal->_pal_y_size <= 0) {
303 nout << "Invalid palette size: " << pal->_pal_x_size
304 << " " << pal->_pal_y_size << "\n";
305 return false;
306 }
307
308 return true;
309}
310
311/**
312 * Handles the line in a .txa file that begins with the keyword ":margin" and
313 * indicates the default margin size.
314 */
315bool TxaFile::
316parse_margin_line(const vector_string &words) {
317 if (words.size() != 2) {
318 nout << "Exactly one parameter required for :margin, the "
319 << "size of the default margin to apply.\n";
320 return false;
321 }
322
323 if (!string_to_int(words[1], pal->_margin)) {
324 nout << "Invalid margin: " << words[1] << "\n";
325 return false;
326 }
327
328 if (pal->_margin < 0) {
329 nout << "Invalid margin: " << pal->_margin << "\n";
330 return false;
331 }
332
333 return true;
334}
335
336/**
337 * Handles the line in a .txa file that begins with the keyword ":background"
338 * and indicates the palette background color.
339 */
340bool TxaFile::
341parse_background_line(const vector_string &words) {
342 if (words.size() != 5) {
343 nout << "Exactly four parameter required for :background: the "
344 << "four [r g b a] components of the background color.\n";
345 return false;
346 }
347
348 if (!string_to_double(words[1], pal->_background[0]) ||
349 !string_to_double(words[2], pal->_background[1]) ||
350 !string_to_double(words[3], pal->_background[2]) ||
351 !string_to_double(words[4], pal->_background[3])) {
352 nout << "Invalid color: "
353 << words[1] << " " << words[2] << " "
354 << words[3] << " " << words[4] << " " << "\n";
355 return false;
356 }
357
358 return true;
359}
360
361/**
362 * Handles the line in a .txa file that begins with the keyword ":coverage"
363 * and indicates the default coverage threshold.
364 */
365bool TxaFile::
366parse_coverage_line(const vector_string &words) {
367 if (words.size() != 2) {
368 nout << "Exactly one parameter required for :coverage, the "
369 << "value for the default coverage threshold.\n";
370 return false;
371 }
372
373
374 if (!string_to_double(words[1], pal->_coverage_threshold)) {
375 nout << "Invalid coverage threshold: " << words[1] << "\n";
376 return false;
377 }
378
379 if (pal->_coverage_threshold <= 0.0) {
380 nout << "Invalid coverage threshold: " << pal->_coverage_threshold << "\n";
381 return false;
382 }
383
384 return true;
385}
386
387/**
388 * Handles the line in a .txa file that begins with the keyword ":powertwo"
389 * and indicates whether textures should by default be forced to a power of
390 * two.
391 */
392bool TxaFile::
393parse_powertwo_line(const vector_string &words) {
394 if (words.size() != 2) {
395 nout << "Exactly one parameter required for :powertwo, either a 0 "
396 << "or a 1.\n";
397 return false;
398 }
399
400 int flag;
401 if (!string_to_int(words[1], flag)) {
402 nout << "Invalid powertwo flag: " << words[1] << "\n";
403 return false;
404 }
405
406 if (flag != 0 && flag != 1) {
407 nout << "Invalid powertwo flag: " << flag << "\n";
408 return false;
409 }
410
411 pal->_force_power_2 = (flag != 0);
412
413 return true;
414}
415
416/**
417 * Handles the line in a .txa file that begins with the keyword ":imagetype"
418 * and indicates the default image file type to convert palettes and textures
419 * to.
420 */
421bool TxaFile::
422parse_imagetype_line(const vector_string &words) {
423 if (words.size() != 2) {
424 nout << "Exactly one parameter required for :imagetype.\n";
425 return false;
426 }
427 const string &imagetype = words[1];
428 if (!parse_image_type_request(imagetype, pal->_color_type, pal->_alpha_type)) {
429 nout << "\nKnown image types are:\n";
431 nout << "\n";
432 return false;
433 }
434
435 return true;
436}
437
438/**
439 * Handles the line in a .txa file that begins with the keyword ":shadowtype"
440 * and indicates the image file type to convert working copies of the palette
441 * images to.
442 */
443bool TxaFile::
444parse_shadowtype_line(const vector_string &words) {
445 if (words.size() != 2) {
446 nout << "Exactly one parameter required for :shadowtype.\n";
447 return false;
448 }
449 const string &shadowtype = words[1];
450 if (!parse_image_type_request(shadowtype, pal->_shadow_color_type,
451 pal->_shadow_alpha_type)) {
452 nout << "\nKnown image types are:\n";
454 nout << "\n";
455 return false;
456 }
457
458 return true;
459}
460
461/**
462 * Handles the line in a .txa file that begins with the keyword ":round" and
463 * indicates how or whether to round up UV minmax boxes.
464 */
465bool TxaFile::
466parse_round_line(const vector_string &words) {
467 if (words.size() == 2) {
468 if (words[1] == "no") {
469 pal->_round_uvs = false;
470 return true;
471 } else {
472 nout << "Invalid round keyword: " << words[1] << ".\n"
473 << "Expected 'no', or a round fraction and fuzz factor.\n";
474 return false;
475 }
476 }
477
478 if (words.size() != 3) {
479 nout << "Exactly two parameters required for :round, the fraction "
480 << "to round to, and the fuzz factor.\n";
481 return false;
482 }
483
484 if (!string_to_double(words[1], pal->_round_unit) ||
485 !string_to_double(words[2], pal->_round_fuzz)) {
486 nout << "Invalid rounding: " << words[1] << " " << words[2] << "\n";
487 return false;
488 }
489
490 if (pal->_round_unit <= 0.0 || pal->_round_fuzz < 0.0) {
491 nout << "Invalid rounding: " << pal->_round_unit
492 << " " << pal->_round_fuzz << "\n";
493 return false;
494 }
495
496 pal->_round_uvs = true;
497 return true;
498}
499
500/**
501 * Handles the line in a .txa file that begins with the keyword ":remap" and
502 * indicates how or whether to remap UV coordinates in egg files to the unit
503 * box.
504 */
505bool TxaFile::
506parse_remap_line(const vector_string &words) {
507 int i = 1;
508 while (i < (int)words.size()) {
509 const string &keyword = words[i];
510 if (keyword == "char") {
511 // Defining how to remap UV's for characters.
512 i++;
513 if (i == (int)words.size()) {
514 nout << "Keyword expected following 'char'\n";
515 return false;
516 }
517 pal->_remap_char_uv = Palettizer::string_remap(words[i]);
518 if (pal->_remap_char_uv == Palettizer::RU_invalid) {
519 nout << "Invalid remap keyword: " << words[i] << "\n";
520 return false;
521 }
522
523 } else {
524 // Defining how to remap UV's in general.
525 pal->_remap_uv = Palettizer::string_remap(words[i]);
526 if (pal->_remap_uv == Palettizer::RU_invalid) {
527 nout << "Invalid remap keyword: " << words[i] << "\n";
528 return false;
529 }
530
531 pal->_remap_char_uv = pal->_remap_uv;
532 }
533
534 i++;
535 }
536
537 return true;
538}
539
540
541/**
542 * Handles the line in a .txa file that begins with the keyword ":cutout" and
543 * indicates how to handle alpha-cutout textures: those textures that appear
544 * to be mostly solid parts and invisible parts, with a thin border of
545 * antialiased alpha along the boundary.
546 */
547bool TxaFile::
548parse_cutout_line(const vector_string &words) {
549 if (words.size() < 2 || words.size() > 3) {
550 nout << ":cutout alpha-mode [ratio]\n";
551 return false;
552 }
553
554 EggRenderMode::AlphaMode am = EggRenderMode::string_alpha_mode(words[1]);
555 if (am == EggRenderMode::AM_unspecified) {
556 nout << "Invalid cutout keyword: " << words[1] << "\n";
557 return false;
558 }
559 pal->_cutout_mode = am;
560
561 if (words.size() >= 3) {
562 if (!string_to_double(words[2], pal->_cutout_ratio)) {
563 nout << "Invalid cutout ratio: " << words[2] << "\n";
564 }
565 }
566
567 return true;
568}
569
570/**
571 * Handles the line in a .txa file that begins with the keyword ":textureswap"
572 * and indicates the relationships between textures to be swapped.
573 */
574bool TxaFile::
575parse_textureswap_line(const vector_string &words) {
576 vector_string::const_iterator wi;
577 wi = words.begin();
578 assert (wi != words.end());
579 ++wi;
580
581 const string &group_name = (*wi);
582 PaletteGroup *group = pal->get_palette_group(group_name);
583 ++wi;
584
585 string sourceTextureName = (*wi);
586 ++wi;
587
588 // vector_string swapTextures; copy(words.begin(), words.end(),
589 // swapTextures); group->add_texture_swap_info(sourceTextureName,
590 // swapTextures);
591 size_t dot = sourceTextureName.rfind('.');
592 if (dot != string::npos) {
593 sourceTextureName = sourceTextureName.substr(0, dot);
594 }
595 group->add_texture_swap_info(sourceTextureName, words);
596
597 return true;
598}
This represents a single egg file known to the palettizer.
Definition eggFile.h:36
static AlphaMode string_alpha_mode(const std::string &string)
Returns the AlphaMode value associated with the given string representation, or AM_unspecified if the...
static PNMFileTypeRegistry * get_global_ptr()
Returns a pointer to the global PNMFileTypeRegistry object.
void write(std::ostream &out, int indent_level=0) const
Writes a list of supported image file types to the indicated output stream, one per line.
This is the highest level of grouping for TextureImages.
bool has_dirname() const
Returns true if the directory name has been explicitly set for this group.
void set_dirname(const std::string &dirname)
Sets the directory name associated with the palette group.
void group_with(PaletteGroup *other)
Indicates a dependency of this group on some other group.
void add_texture_swap_info(const std::string sourceTextureName, const vector_string &swapTextures)
Store textureswap information from textures.txa.
const std::string & get_dirname() const
Returns the directory name associated with the palette group.
void set_margin_override(const int override)
Returns the set of groups this group depends on.
PaletteGroup * get_palette_group(const std::string &name)
Returns the PaletteGroup with the given name.
static RemapUV string_remap(const std::string &str)
Returns the RemapUV code corresponding to the indicated string, or RU_invalid if the string is invali...
This represents a single source texture that is referenced by one or more egg files.
bool read(std::istream &in, const std::string &filename)
Reads the indicated stream, and returns true if successful, or false if there is an error.
Definition txaFile.cxx:37
bool match_texture(TextureImage *texture) const
Searches for a matching line in the .txa file for the given texture and applies its specifications.
Definition txaFile.cxx:149
bool match_egg(EggFile *egg_file) const
Searches for a matching line in the .txa file for the given egg file and applies its specifications.
Definition txaFile.cxx:131
void write(std::ostream &out) const
Outputs a representation of the lines that were read in to the indicated output stream.
Definition txaFile.cxx:165
This is a single matching line in the .txa file.
Definition txaLine.h:36
bool parse(const std::string &line)
Accepts a string that defines a line of the .txa file and parses it into its constinuent parts.
Definition txaLine.cxx:59
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
string trim_left(const string &str)
Returns a new string representing the contents of the given string with the leading whitespace remove...
int extract_words(const string &str, vector_string &words)
Divides the string into a number of words according to whitespace.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.