00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "txaFile.h"
00016 #include "pal_string_utils.h"
00017 #include "palettizer.h"
00018 #include "paletteGroup.h"
00019 #include "textureImage.h"
00020
00021 #include "pnotify.h"
00022 #include "pnmFileTypeRegistry.h"
00023
00024
00025
00026
00027
00028
00029 TxaFile::
00030 TxaFile() {
00031 }
00032
00033
00034
00035
00036
00037
00038
00039 bool TxaFile::
00040 read(istream &in, const string &filename) {
00041 string line;
00042 int line_number = 1;
00043
00044 int ch = get_line_or_semicolon(in, line);
00045 while (ch != EOF || !line.empty()) {
00046 bool okflag = true;
00047
00048
00049 size_t hash = line.find('#');
00050 if (hash != string::npos) {
00051 line = line.substr(0, hash);
00052 }
00053 line = trim_left(line);
00054 if (line.empty()) {
00055
00056
00057 } else if (line[0] == ':') {
00058
00059 vector_string words;
00060 extract_words(line, words);
00061 if (words[0] == ":group") {
00062 okflag = parse_group_line(words);
00063
00064 } else if (words[0] == ":palette") {
00065 okflag = parse_palette_line(words);
00066
00067 } else if (words[0] == ":margin") {
00068 okflag = parse_margin_line(words);
00069
00070 } else if (words[0] == ":background") {
00071 okflag = parse_background_line(words);
00072
00073 } else if (words[0] == ":coverage") {
00074 okflag = parse_coverage_line(words);
00075
00076 } else if (words[0] == ":powertwo") {
00077 okflag = parse_powertwo_line(words);
00078
00079 } else if (words[0] == ":imagetype") {
00080 okflag = parse_imagetype_line(words);
00081
00082 } else if (words[0] == ":shadowtype") {
00083 okflag = parse_shadowtype_line(words);
00084
00085 } else if (words[0] == ":round") {
00086 okflag = parse_round_line(words);
00087
00088 } else if (words[0] == ":remap") {
00089 okflag = parse_remap_line(words);
00090
00091 } else if (words[0] == ":cutout") {
00092 okflag = parse_cutout_line(words);
00093
00094 } else if (words[0] == ":textureswap") {
00095 okflag = parse_textureswap_line(words);
00096
00097 } else {
00098 nout << "Invalid keyword " << words[0] << "\n";
00099 okflag = false;
00100 }
00101
00102 } else {
00103 _lines.push_back(TxaLine());
00104 TxaLine &txa_line = _lines.back();
00105
00106 okflag = txa_line.parse(line);
00107 }
00108
00109 if (!okflag) {
00110 nout << "Error on line " << line_number << " of " << filename << "\n";
00111 return false;
00112 }
00113 if (ch == '\n') {
00114 line_number++;
00115 }
00116 ch = get_line_or_semicolon(in, line);
00117 }
00118
00119 if (!in.eof()) {
00120 nout << "I/O error reading " << filename << "\n";
00121 return false;
00122 }
00123
00124 return true;
00125 }
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136 bool TxaFile::
00137 match_egg(EggFile *egg_file) const {
00138 Lines::const_iterator li;
00139 for (li = _lines.begin(); li != _lines.end(); ++li) {
00140 if ((*li).match_egg(egg_file)) {
00141 return true;
00142 }
00143 }
00144
00145 return false;
00146 }
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157 bool TxaFile::
00158 match_texture(TextureImage *texture) const {
00159 Lines::const_iterator li;
00160 for (li = _lines.begin(); li != _lines.end(); ++li) {
00161 if ((*li).match_texture(texture)) {
00162 return true;
00163 }
00164 }
00165
00166 return false;
00167 }
00168
00169
00170
00171
00172
00173
00174
00175
00176 void TxaFile::
00177 write(ostream &out) const {
00178 Lines::const_iterator li;
00179 for (li = _lines.begin(); li != _lines.end(); ++li) {
00180 out << (*li) << "\n";
00181 }
00182 }
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192 int TxaFile::
00193 get_line_or_semicolon(istream &in, string &line) {
00194 line = string();
00195 int ch = in.get();
00196 char semicolon = ';';
00197
00198 while (ch != EOF && ch != '\n' && ch != semicolon) {
00199 if (ch == '#') {
00200
00201
00202 semicolon = EOF;
00203 }
00204 line += ch;
00205 ch = in.get();
00206 }
00207
00208 return ch;
00209 }
00210
00211
00212
00213
00214
00215
00216
00217
00218 bool TxaFile::
00219 parse_group_line(const vector_string &words) {
00220 vector_string::const_iterator wi;
00221 wi = words.begin();
00222 assert (wi != words.end());
00223 ++wi;
00224
00225 const string &group_name = (*wi);
00226 PaletteGroup *group = pal->get_palette_group(group_name);
00227 ++wi;
00228
00229 enum State {
00230 S_none,
00231 S_on,
00232 S_includes,
00233 S_dir,
00234 S_margin,
00235 };
00236 State state = S_none;
00237
00238 bool first_on = true;
00239
00240 while (wi != words.end()) {
00241 const string &word = (*wi);
00242 if (word == "with") {
00243
00244 state = S_on;
00245
00246 } else if (word == "on") {
00247 state = S_on;
00248
00249 } else if (word == "includes") {
00250 state = S_includes;
00251
00252 } else if (word == "dir") {
00253 state = S_dir;
00254
00255 } else if (word == "margin") {
00256 state = S_margin;
00257
00258 } else {
00259 switch (state) {
00260 case S_none:
00261 nout << "Invalid keyword: " << word << "\n";
00262 return false;
00263
00264 case S_on:
00265 {
00266 PaletteGroup *on_group = pal->get_palette_group(word);
00267 if (first_on) {
00268 if (!group->has_dirname() && on_group->has_dirname()) {
00269 group->set_dirname(on_group->get_dirname());
00270 }
00271 first_on = false;
00272 }
00273 group->group_with(on_group);
00274 }
00275 break;
00276
00277 case S_includes:
00278 pal->get_palette_group(word)->group_with(group);
00279 break;
00280
00281 case S_dir:
00282 group->set_dirname(word);
00283 state = S_none;
00284 break;
00285
00286 case S_margin:
00287 int margin_override;
00288 if (string_to_int(word, margin_override)) {
00289 group->set_margin_override(margin_override);
00290 }
00291 state = S_none;
00292 break;
00293 }
00294
00295 }
00296
00297 ++wi;
00298 }
00299
00300 return true;
00301 }
00302
00303
00304
00305
00306
00307
00308
00309
00310 bool TxaFile::
00311 parse_palette_line(const vector_string &words) {
00312 if (words.size() != 3) {
00313 nout << "Exactly two parameters required for :palette, the x and y "
00314 << "size of the palette images to generate.\n";
00315 return false;
00316 }
00317
00318 if (!string_to_int(words[1], pal->_pal_x_size) ||
00319 !string_to_int(words[2], pal->_pal_y_size)) {
00320 nout << "Invalid palette size: " << words[1] << " " << words[2] << "\n";
00321 return false;
00322 }
00323
00324 if (pal->_pal_x_size <= 0 || pal->_pal_y_size <= 0) {
00325 nout << "Invalid palette size: " << pal->_pal_x_size
00326 << " " << pal->_pal_y_size << "\n";
00327 return false;
00328 }
00329
00330 return true;
00331 }
00332
00333
00334
00335
00336
00337
00338
00339
00340 bool TxaFile::
00341 parse_margin_line(const vector_string &words) {
00342 if (words.size() != 2) {
00343 nout << "Exactly one parameter required for :margin, the "
00344 << "size of the default margin to apply.\n";
00345 return false;
00346 }
00347
00348 if (!string_to_int(words[1], pal->_margin)) {
00349 nout << "Invalid margin: " << words[1] << "\n";
00350 return false;
00351 }
00352
00353 if (pal->_margin < 0) {
00354 nout << "Invalid margin: " << pal->_margin << "\n";
00355 return false;
00356 }
00357
00358 return true;
00359 }
00360
00361
00362
00363
00364
00365
00366
00367
00368 bool TxaFile::
00369 parse_background_line(const vector_string &words) {
00370 if (words.size() != 5) {
00371 nout << "Exactly four parameter required for :background: the "
00372 << "four [r g b a] components of the background color.\n";
00373 return false;
00374 }
00375
00376 if (!string_to_double(words[1], pal->_background[0]) ||
00377 !string_to_double(words[2], pal->_background[1]) ||
00378 !string_to_double(words[3], pal->_background[2]) ||
00379 !string_to_double(words[4], pal->_background[3])) {
00380 nout << "Invalid color: "
00381 << words[1] << " " << words[2] << " "
00382 << words[3] << " " << words[4] << " " << "\n";
00383 return false;
00384 }
00385
00386 return true;
00387 }
00388
00389
00390
00391
00392
00393
00394
00395
00396 bool TxaFile::
00397 parse_coverage_line(const vector_string &words) {
00398 if (words.size() != 2) {
00399 nout << "Exactly one parameter required for :coverage, the "
00400 << "value for the default coverage threshold.\n";
00401 return false;
00402 }
00403
00404
00405 if (!string_to_double(words[1], pal->_coverage_threshold)) {
00406 nout << "Invalid coverage threshold: " << words[1] << "\n";
00407 return false;
00408 }
00409
00410 if (pal->_coverage_threshold <= 0.0) {
00411 nout << "Invalid coverage threshold: " << pal->_coverage_threshold << "\n";
00412 return false;
00413 }
00414
00415 return true;
00416 }
00417
00418
00419
00420
00421
00422
00423
00424
00425 bool TxaFile::
00426 parse_powertwo_line(const vector_string &words) {
00427 if (words.size() != 2) {
00428 nout << "Exactly one parameter required for :powertwo, either a 0 "
00429 << "or a 1.\n";
00430 return false;
00431 }
00432
00433 int flag;
00434 if (!string_to_int(words[1], flag)) {
00435 nout << "Invalid powertwo flag: " << words[1] << "\n";
00436 return false;
00437 }
00438
00439 if (flag != 0 && flag != 1) {
00440 nout << "Invalid powertwo flag: " << flag << "\n";
00441 return false;
00442 }
00443
00444 pal->_force_power_2 = (flag != 0);
00445
00446 return true;
00447 }
00448
00449
00450
00451
00452
00453
00454
00455
00456 bool TxaFile::
00457 parse_imagetype_line(const vector_string &words) {
00458 if (words.size() != 2) {
00459 nout << "Exactly one parameter required for :imagetype.\n";
00460 return false;
00461 }
00462 const string &imagetype = words[1];
00463 if (!parse_image_type_request(imagetype, pal->_color_type, pal->_alpha_type)) {
00464 nout << "\nKnown image types are:\n";
00465 PNMFileTypeRegistry::get_global_ptr()->write(nout, 2);
00466 nout << "\n";
00467 return false;
00468 }
00469
00470 return true;
00471 }
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481 bool TxaFile::
00482 parse_shadowtype_line(const vector_string &words) {
00483 if (words.size() != 2) {
00484 nout << "Exactly one parameter required for :shadowtype.\n";
00485 return false;
00486 }
00487 const string &shadowtype = words[1];
00488 if (!parse_image_type_request(shadowtype, pal->_shadow_color_type,
00489 pal->_shadow_alpha_type)) {
00490 nout << "\nKnown image types are:\n";
00491 PNMFileTypeRegistry::get_global_ptr()->write(nout, 2);
00492 nout << "\n";
00493 return false;
00494 }
00495
00496 return true;
00497 }
00498
00499
00500
00501
00502
00503
00504
00505
00506 bool TxaFile::
00507 parse_round_line(const vector_string &words) {
00508 if (words.size() == 2) {
00509 if (words[1] == "no") {
00510 pal->_round_uvs = false;
00511 return true;
00512 } else {
00513 nout << "Invalid round keyword: " << words[1] << ".\n"
00514 << "Expected 'no', or a round fraction and fuzz factor.\n";
00515 return false;
00516 }
00517 }
00518
00519 if (words.size() != 3) {
00520 nout << "Exactly two parameters required for :round, the fraction "
00521 << "to round to, and the fuzz factor.\n";
00522 return false;
00523 }
00524
00525 if (!string_to_double(words[1], pal->_round_unit) ||
00526 !string_to_double(words[2], pal->_round_fuzz)) {
00527 nout << "Invalid rounding: " << words[1] << " " << words[2] << "\n";
00528 return false;
00529 }
00530
00531 if (pal->_round_unit <= 0.0 || pal->_round_fuzz < 0.0) {
00532 nout << "Invalid rounding: " << pal->_round_unit
00533 << " " << pal->_round_fuzz << "\n";
00534 return false;
00535 }
00536
00537 pal->_round_uvs = true;
00538 return true;
00539 }
00540
00541
00542
00543
00544
00545
00546
00547
00548 bool TxaFile::
00549 parse_remap_line(const vector_string &words) {
00550 int i = 1;
00551 while (i < (int)words.size()) {
00552 const string &keyword = words[i];
00553 if (keyword == "char") {
00554
00555 i++;
00556 if (i == (int)words.size()) {
00557 nout << "Keyword expected following 'char'\n";
00558 return false;
00559 }
00560 pal->_remap_char_uv = Palettizer::string_remap(words[i]);
00561 if (pal->_remap_char_uv == Palettizer::RU_invalid) {
00562 nout << "Invalid remap keyword: " << words[i] << "\n";
00563 return false;
00564 }
00565
00566 } else {
00567
00568 pal->_remap_uv = Palettizer::string_remap(words[i]);
00569 if (pal->_remap_uv == Palettizer::RU_invalid) {
00570 nout << "Invalid remap keyword: " << words[i] << "\n";
00571 return false;
00572 }
00573
00574 pal->_remap_char_uv = pal->_remap_uv;
00575 }
00576
00577 i++;
00578 }
00579
00580 return true;
00581 }
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593 bool TxaFile::
00594 parse_cutout_line(const vector_string &words) {
00595 if (words.size() < 2 || words.size() > 3) {
00596 nout << ":cutout alpha-mode [ratio]\n";
00597 return false;
00598 }
00599
00600 EggRenderMode::AlphaMode am = EggRenderMode::string_alpha_mode(words[1]);
00601 if (am == EggRenderMode::AM_unspecified) {
00602 nout << "Invalid cutout keyword: " << words[1] << "\n";
00603 return false;
00604 }
00605 pal->_cutout_mode = am;
00606
00607 if (words.size() >= 3) {
00608 if (!string_to_double(words[2], pal->_cutout_ratio)) {
00609 nout << "Invalid cutout ratio: " << words[2] << "\n";
00610 }
00611 }
00612
00613 return true;
00614 }
00615
00616
00617
00618
00619
00620
00621
00622
00623 bool TxaFile::
00624 parse_textureswap_line(const vector_string &words) {
00625 vector_string::const_iterator wi;
00626 wi = words.begin();
00627 assert (wi != words.end());
00628 ++wi;
00629
00630 const string &group_name = (*wi);
00631 PaletteGroup *group = pal->get_palette_group(group_name);
00632 ++wi;
00633
00634 string sourceTextureName = (*wi);
00635 ++wi;
00636
00637
00638
00639
00640 size_t dot = sourceTextureName.rfind('.');
00641 if (dot != string::npos) {
00642 sourceTextureName = sourceTextureName.substr(0, dot);
00643 }
00644 group->add_texture_swap_info(sourceTextureName, words);
00645
00646 return true;
00647 }