00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "txaLine.h"
00020 #include "pal_string_utils.h"
00021 #include "eggFile.h"
00022 #include "palettizer.h"
00023 #include "textureImage.h"
00024 #include "sourceTextureImage.h"
00025 #include "paletteGroup.h"
00026
00027 #include <notify.h>
00028 #include <pnmFileType.h>
00029
00030
00031
00032
00033
00034
00035 TxaLine::
00036 TxaLine() {
00037 _size_type = ST_none;
00038 _scale = 0.0;
00039 _x_size = 0;
00040 _y_size = 0;
00041 _aniso_degree = 0;
00042 _num_channels = 0;
00043 _format = EggTexture::F_unspecified;
00044 _force_format = false;
00045 _generic_format = false;
00046 _alpha_mode = EggRenderMode::AM_unspecified;
00047 _got_margin = false;
00048 _margin = 0;
00049 _got_coverage_threshold = false;
00050 _coverage_threshold = 0.0;
00051 _color_type = (PNMFileType *)NULL;
00052 _alpha_type = (PNMFileType *)NULL;
00053 }
00054
00055
00056
00057
00058
00059
00060
00061
00062 bool TxaLine::
00063 parse(const string &line) {
00064 size_t colon = line.find(':');
00065 if (colon == string::npos) {
00066 nout << "Colon required.\n";
00067 return false;
00068 }
00069
00070
00071
00072 vector_string words;
00073 extract_words(line.substr(0, colon), words);
00074
00075 vector_string::iterator wi;
00076 for (wi = words.begin(); wi != words.end(); ++wi) {
00077 string word = (*wi);
00078
00079
00080
00081
00082
00083
00084 if (word.length() > 4 && word.substr(word.length() - 4) == ".egg") {
00085 _egg_patterns.push_back(GlobPattern(word));
00086
00087 } else {
00088
00089
00090 size_t dot = word.rfind('.');
00091 if (dot != string::npos) {
00092 word = word.substr(0, dot);
00093 }
00094 _texture_patterns.push_back(GlobPattern(word));
00095 }
00096 }
00097
00098 if (_egg_patterns.empty() && _texture_patterns.empty()) {
00099 nout << "No texture or egg filenames given.\n";
00100 return false;
00101 }
00102
00103
00104
00105 words.clear();
00106 extract_words(line.substr(colon + 1), words);
00107
00108 wi = words.begin();
00109 while (wi != words.end()) {
00110 const string &word = *wi;
00111 nassertr(!word.empty(), false);
00112
00113 if (isdigit(word[0])) {
00114
00115 if (_size_type != ST_none) {
00116 nout << "Invalid repeated size request: " << word << "\n";
00117 return false;
00118 }
00119 if (word[word.length() - 1] == '%') {
00120
00121 _size_type = ST_scale;
00122
00123 string tail;
00124 _scale = string_to_double(word, tail);
00125 if (!(tail == "%")) {
00126
00127 return false;
00128 }
00129 ++wi;
00130
00131 } else {
00132
00133 pvector<int> numbers;
00134 while (wi != words.end() && isdigit((*wi)[0])) {
00135 const string &word = *wi;
00136 int num;
00137 if (!string_to_int(word, num)) {
00138 nout << "Invalid size: " << word << "\n";
00139 return false;
00140 }
00141 numbers.push_back(num);
00142 ++wi;
00143 }
00144 if (numbers.size() < 2) {
00145 nout << "At least two size numbers must be given, or a percent sign used to indicate scaling.\n";
00146 return false;
00147
00148 } else if (numbers.size() == 2) {
00149 _size_type = ST_explicit_2;
00150 _x_size = numbers[0];
00151 _y_size = numbers[1];
00152
00153 } else if (numbers.size() == 3) {
00154 _size_type = ST_explicit_3;
00155 _x_size = numbers[0];
00156 _y_size = numbers[1];
00157 _num_channels = numbers[2];
00158
00159 } else {
00160 nout << "Too many size numbers given.\n";
00161 return false;
00162 }
00163 }
00164
00165 } else {
00166
00167
00168 if (word == "omit") {
00169 _keywords.push_back(KW_omit);
00170
00171 } else if (word == "nearest") {
00172 _keywords.push_back(KW_nearest);
00173
00174 } else if (word == "linear") {
00175 _keywords.push_back(KW_linear);
00176
00177 } else if (word == "mipmap") {
00178 _keywords.push_back(KW_mipmap);
00179
00180 } else if (word == "cont") {
00181 _keywords.push_back(KW_cont);
00182
00183 } else if (word == "margin") {
00184 ++wi;
00185 if (wi == words.end()) {
00186 nout << "Argument required for 'margin'.\n";
00187 return false;
00188 }
00189
00190 const string &arg = (*wi);
00191 if (!string_to_int(arg, _margin)) {
00192 nout << "Not an integer: " << arg << "\n";
00193 return false;
00194 }
00195 if (_margin < 0) {
00196 nout << "Invalid margin: " << _margin << "\n";
00197 return false;
00198 }
00199 _got_margin = true;
00200
00201 } else if (word == "aniso") {
00202 ++wi;
00203 if (wi == words.end()) {
00204 nout << "Integer argument required for 'aniso'.\n";
00205 return false;
00206 }
00207
00208 const string &arg = (*wi);
00209 if (!string_to_int(arg, _aniso_degree)) {
00210 nout << "Not an integer: " << arg << "\n";
00211 return false;
00212 }
00213 if ((_aniso_degree < 2) || (_aniso_degree > 16)) {
00214
00215 nout << "Invalid anistropic degree (range is 2-16): " << _aniso_degree << "\n";
00216 return false;
00217 }
00218
00219 _keywords.push_back(KW_anisotropic);
00220
00221 } else if (word == "coverage") {
00222 ++wi;
00223 if (wi == words.end()) {
00224 nout << "Argument required for 'coverage'.\n";
00225 return false;
00226 }
00227
00228 const string &arg = (*wi);
00229 if (!string_to_double(arg, _coverage_threshold)) {
00230 nout << "Not a number: " << arg << "\n";
00231 return false;
00232 }
00233 if (_coverage_threshold <= 0.0) {
00234 nout << "Invalid coverage threshold: " << _coverage_threshold << "\n";
00235 return false;
00236 }
00237 _got_coverage_threshold = true;
00238
00239 } else if (word.substr(0, 6) == "force-") {
00240
00241
00242 string format_name = word.substr(6);
00243 EggTexture::Format format = EggTexture::string_format(format_name);
00244 if (format != EggTexture::F_unspecified) {
00245 _format = format;
00246 _force_format = true;
00247 } else {
00248 nout << "Unknown image format: " << format_name << "\n";
00249 return false;
00250 }
00251
00252 } else if (word == "generic") {
00253
00254
00255
00256 _generic_format = true;
00257
00258 } else {
00259
00260 PaletteGroup *group = pal->test_palette_group(word);
00261 if (group != (PaletteGroup *)NULL) {
00262 _palette_groups.insert(group);
00263
00264 } else {
00265
00266
00267
00268 EggTexture::Format format = EggTexture::string_format(word);
00269 if (format != EggTexture::F_unspecified) {
00270 if (!_force_format) {
00271 _format = format;
00272 }
00273 } else {
00274
00275 EggRenderMode::AlphaMode am = EggRenderMode::string_alpha_mode(word);
00276 if (am != EggRenderMode::AM_unspecified) {
00277 _alpha_mode = am;
00278
00279 } else {
00280
00281 if (!parse_image_type_request(word, _color_type, _alpha_type)) {
00282 return false;
00283 }
00284 }
00285 }
00286 }
00287 }
00288 ++wi;
00289 }
00290 }
00291
00292 return true;
00293 }
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306 bool TxaLine::
00307 match_egg(EggFile *egg_file) const {
00308 string name = egg_file->get_name();
00309
00310 bool matched_any = false;
00311 Patterns::const_iterator pi;
00312 for (pi = _egg_patterns.begin();
00313 pi != _egg_patterns.end() && !matched_any;
00314 ++pi) {
00315 matched_any = (*pi).matches(name);
00316 }
00317
00318 if (!matched_any) {
00319
00320 return false;
00321 }
00322
00323 bool got_cont = false;
00324 Keywords::const_iterator ki;
00325 for (ki = _keywords.begin(); ki != _keywords.end(); ++ki) {
00326 switch (*ki) {
00327 case KW_omit:
00328 break;
00329
00330 case KW_nearest:
00331 case KW_linear:
00332 case KW_mipmap:
00333 case KW_anisotropic:
00334
00335 break;
00336
00337 case KW_cont:
00338 got_cont = true;
00339 break;
00340 }
00341 }
00342
00343 egg_file->match_txa_groups(_palette_groups);
00344
00345 if (got_cont) {
00346
00347
00348 return false;
00349 }
00350
00351
00352
00353 egg_file->clear_surprise();
00354
00355 return true;
00356 }
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369 bool TxaLine::
00370 match_texture(TextureImage *texture) const {
00371 string name = texture->get_name();
00372
00373 bool matched_any = false;
00374 Patterns::const_iterator pi;
00375 for (pi = _texture_patterns.begin();
00376 pi != _texture_patterns.end() && !matched_any;
00377 ++pi) {
00378 matched_any = (*pi).matches(name);
00379 }
00380
00381 if (!matched_any) {
00382
00383 return false;
00384 }
00385
00386 SourceTextureImage *source = texture->get_preferred_source();
00387 TextureRequest &request = texture->_request;
00388
00389 if (!request._got_size) {
00390 switch (_size_type) {
00391 case ST_none:
00392 break;
00393
00394 case ST_scale:
00395 if (source != (SourceTextureImage *)NULL && source->get_size()) {
00396 request._got_size = true;
00397 request._x_size = (int)(source->get_x_size() * _scale / 100.0);
00398 request._y_size = (int)(source->get_y_size() * _scale / 100.0);
00399 }
00400 break;
00401
00402 case ST_explicit_3:
00403 request._got_num_channels = true;
00404 request._num_channels = _num_channels;
00405
00406
00407 case ST_explicit_2:
00408 request._got_size = true;
00409 request._x_size = _x_size;
00410 request._y_size = _y_size;
00411 break;
00412 }
00413 }
00414
00415 if (_got_margin) {
00416 request._margin = _margin;
00417 }
00418
00419 if (_got_coverage_threshold) {
00420 request._coverage_threshold = _coverage_threshold;
00421 }
00422
00423 if (_color_type != (PNMFileType *)NULL) {
00424 request._properties._color_type = _color_type;
00425 request._properties._alpha_type = _alpha_type;
00426 }
00427
00428 if (_format != EggTexture::F_unspecified) {
00429 request._format = _format;
00430 request._force_format = _force_format;
00431 request._generic_format = false;
00432 }
00433
00434 if (_generic_format) {
00435 request._generic_format = true;
00436 }
00437
00438 if (_alpha_mode != EggRenderMode::AM_unspecified) {
00439 request._alpha_mode = _alpha_mode;
00440 }
00441
00442 bool got_cont = false;
00443 Keywords::const_iterator ki;
00444 for (ki = _keywords.begin(); ki != _keywords.end(); ++ki) {
00445 switch (*ki) {
00446 case KW_omit:
00447 request._omit = true;
00448 break;
00449
00450 case KW_nearest:
00451 request._minfilter = EggTexture::FT_nearest;
00452 request._magfilter = EggTexture::FT_nearest;
00453 break;
00454
00455 case KW_linear:
00456 request._minfilter = EggTexture::FT_linear;
00457 request._magfilter = EggTexture::FT_linear;
00458 break;
00459
00460 case KW_mipmap:
00461 request._minfilter = EggTexture::FT_linear_mipmap_linear;
00462 request._magfilter = EggTexture::FT_linear_mipmap_linear;
00463 break;
00464
00465 case KW_anisotropic:
00466 request._anisotropic_degree = _aniso_degree;
00467 break;
00468
00469 case KW_cont:
00470 got_cont = true;
00471 break;
00472 }
00473 }
00474
00475 texture->_explicitly_assigned_groups.make_union
00476 (texture->_explicitly_assigned_groups, _palette_groups);
00477
00478 if (got_cont) {
00479
00480
00481 return false;
00482 }
00483
00484
00485
00486 texture->_is_surprise = false;
00487
00488 return true;
00489 }
00490
00491
00492
00493
00494
00495
00496 void TxaLine::
00497 output(ostream &out) const {
00498 Patterns::const_iterator pi;
00499 for (pi = _texture_patterns.begin(); pi != _texture_patterns.end(); ++pi) {
00500 out << (*pi) << " ";
00501 }
00502 for (pi = _egg_patterns.begin(); pi != _egg_patterns.end(); ++pi) {
00503 out << (*pi) << " ";
00504 }
00505 out << ":";
00506
00507 switch (_size_type) {
00508 case ST_none:
00509 break;
00510
00511 case ST_scale:
00512 out << " " << _scale << "%";
00513 break;
00514
00515 case ST_explicit_2:
00516 out << " " << _x_size << " " << _y_size;
00517 break;
00518
00519 case ST_explicit_3:
00520 out << " " << _x_size << " " << _y_size << " " << _num_channels;
00521 break;
00522 }
00523
00524 if (_got_margin) {
00525 out << " margin " << _margin;
00526 }
00527
00528 if (_got_coverage_threshold) {
00529 out << " coverage " << _coverage_threshold;
00530 }
00531
00532 Keywords::const_iterator ki;
00533 for (ki = _keywords.begin(); ki != _keywords.end(); ++ki) {
00534 switch (*ki) {
00535 case KW_omit:
00536 out << " omit";
00537 break;
00538
00539 case KW_nearest:
00540 out << " nearest";
00541 break;
00542
00543 case KW_linear:
00544 out << " linear";
00545 break;
00546
00547 case KW_mipmap:
00548 out << " mipmap";
00549 break;
00550
00551 case KW_cont:
00552 out << " cont";
00553 break;
00554
00555 case KW_anisotropic:
00556 out << " aniso " << _aniso_degree;
00557 break;
00558 }
00559 }
00560
00561 PaletteGroups::const_iterator gi;
00562 for (gi = _palette_groups.begin(); gi != _palette_groups.end(); ++gi) {
00563 out << " " << (*gi)->get_name();
00564 }
00565
00566 if (_format != EggTexture::F_unspecified) {
00567 out << " " << _format;
00568 if (_force_format) {
00569 out << " (forced)";
00570 }
00571 }
00572
00573 if (_color_type != (PNMFileType *)NULL) {
00574 out << " " << _color_type->get_suggested_extension();
00575 if (_alpha_type != (PNMFileType *)NULL) {
00576 out << "," << _alpha_type->get_suggested_extension();
00577 }
00578 }
00579 }