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