00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "palettizer.h"
00016 #include "eggFile.h"
00017 #include "textureImage.h"
00018 #include "pal_string_utils.h"
00019 #include "paletteGroup.h"
00020 #include "filenameUnifier.h"
00021 #include "textureMemoryCounter.h"
00022
00023 #include "pnmImage.h"
00024 #include "pnmFileTypeRegistry.h"
00025 #include "pnmFileType.h"
00026 #include "eggData.h"
00027 #include "datagram.h"
00028 #include "datagramIterator.h"
00029 #include "bamReader.h"
00030 #include "bamWriter.h"
00031 #include "indent.h"
00032
00033 Palettizer *pal = (Palettizer *)NULL;
00034
00035
00036
00037
00038
00039
00040 int Palettizer::_pi_version = 20;
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 int Palettizer::_min_pi_version = 8;
00056
00057
00058 int Palettizer::_read_pi_version = 0;
00059
00060 TypeHandle Palettizer::_type_handle;
00061
00062 ostream &operator << (ostream &out, Palettizer::RemapUV remap) {
00063 switch (remap) {
00064 case Palettizer::RU_never:
00065 return out << "never";
00066
00067 case Palettizer::RU_group:
00068 return out << "per group";
00069
00070 case Palettizer::RU_poly:
00071 return out << "per polygon";
00072
00073 case Palettizer::RU_invalid:
00074 return out << "(invalid)";
00075 }
00076
00077 return out << "**invalid**(" << (int)remap << ")";
00078 }
00079
00080
00081
00082 class SortGroupsByDependencyOrder {
00083 public:
00084 bool operator ()(PaletteGroup *a, PaletteGroup *b) {
00085 if (a->get_dependency_order() != b->get_dependency_order()) {
00086 return a->get_dependency_order() < b->get_dependency_order();
00087 }
00088 return a->get_name() < b->get_name();
00089 }
00090 };
00091
00092
00093 class SortGroupsByPreference {
00094 public:
00095 bool operator ()(PaletteGroup *a, PaletteGroup *b) {
00096 return !a->is_preferred_over(*b);
00097 }
00098 };
00099
00100
00101
00102
00103
00104
00105 Palettizer::
00106 Palettizer() {
00107 _is_valid = true;
00108 _noabs = false;
00109
00110 _generated_image_pattern = "%g_palette_%p_%i";
00111 _map_dirname = "%g";
00112 _shadow_dirname = "shadow";
00113 _margin = 2;
00114 _omit_solitary = false;
00115 _omit_everything = false;
00116 _coverage_threshold = 2.5;
00117 _aggressively_clean_mapdir = true;
00118 _force_power_2 = true;
00119 _color_type = PNMFileTypeRegistry::get_global_ptr()->get_type_from_extension("png");
00120 _alpha_type = (PNMFileType *)NULL;
00121 _shadow_color_type = (PNMFileType *)NULL;
00122 _shadow_alpha_type = (PNMFileType *)NULL;
00123 _pal_x_size = _pal_y_size = 512;
00124 _background.set(0.0, 0.0, 0.0, 0.0);
00125 _cutout_mode = EggRenderMode::AM_dual;
00126 _cutout_ratio = 0.3;
00127
00128 _round_uvs = true;
00129 _round_unit = 0.1;
00130 _round_fuzz = 0.01;
00131 _remap_uv = RU_poly;
00132 _remap_char_uv = RU_poly;
00133
00134 get_palette_group("null");
00135 }
00136
00137
00138
00139
00140
00141
00142
00143 bool Palettizer::
00144 get_noabs() const {
00145 return _noabs;
00146 }
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162 void Palettizer::
00163 set_noabs(bool noabs) {
00164 _noabs = noabs;
00165 }
00166
00167
00168
00169
00170
00171
00172
00173
00174 bool Palettizer::
00175 is_valid() const {
00176 return _is_valid;
00177 }
00178
00179
00180
00181
00182
00183
00184
00185
00186 void Palettizer::
00187 report_pi() const {
00188
00189
00190 EggFiles::const_iterator efi;
00191 for (efi = _egg_files.begin(); efi != _egg_files.end(); ++efi) {
00192 (*efi).second->build_cross_links();
00193 }
00194
00195 cout
00196 << "\nparams\n"
00197 << " generated image pattern: " << _generated_image_pattern << "\n"
00198 << " map directory: " << _map_dirname << "\n"
00199 << " shadow directory: "
00200 << FilenameUnifier::make_user_filename(_shadow_dirname) << "\n"
00201 << " egg relative directory: "
00202 << FilenameUnifier::make_user_filename(_rel_dirname) << "\n"
00203 << " palettize size: " << _pal_x_size << " by " << _pal_y_size << "\n"
00204 << " background: " << _background << "\n"
00205 << " margin: " << _margin << "\n"
00206 << " coverage threshold: " << _coverage_threshold << "\n"
00207 << " force textures to power of 2: " << yesno(_force_power_2) << "\n"
00208 << " aggressively clean the map directory: "
00209 << yesno(_aggressively_clean_mapdir) << "\n"
00210 << " omit everything: " << yesno(_omit_everything) << "\n"
00211 << " round UV area: " << yesno(_round_uvs) << "\n";
00212 if (_round_uvs) {
00213 cout << " round UV area to nearest " << _round_unit << " with fuzz "
00214 << _round_fuzz << "\n";
00215 }
00216 cout << " remap UV's: " << _remap_uv << "\n"
00217 << " remap UV's for characters: " << _remap_char_uv << "\n";
00218 cout << " alpha cutouts: " << _cutout_mode << " " << _cutout_ratio << "\n";
00219
00220 if (_color_type != (PNMFileType *)NULL) {
00221 cout << " generate image files of type: "
00222 << _color_type->get_suggested_extension();
00223 if (_alpha_type != (PNMFileType *)NULL) {
00224 cout << "," << _alpha_type->get_suggested_extension();
00225 }
00226 cout << "\n";
00227 }
00228
00229 if (_shadow_color_type != (PNMFileType *)NULL) {
00230 cout << " generate shadow palette files of type: "
00231 << _shadow_color_type->get_suggested_extension();
00232 if (_shadow_alpha_type != (PNMFileType *)NULL) {
00233 cout << "," << _shadow_alpha_type->get_suggested_extension();
00234 }
00235 cout << "\n";
00236 }
00237
00238 cout << "\ntexture source pathnames and assignments\n";
00239 Textures::const_iterator ti;
00240 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00241 TextureImage *texture = (*ti).second;
00242 if (texture->is_used()) {
00243 cout << " " << texture->get_name() << ":\n";
00244 texture->write_source_pathnames(cout, 4);
00245 }
00246 }
00247
00248 cout << "\negg files and textures referenced\n";
00249 EggFiles::const_iterator ei;
00250 for (ei = _egg_files.begin(); ei != _egg_files.end(); ++ei) {
00251 EggFile *egg_file = (*ei).second;
00252 egg_file->write_description(cout, 2);
00253 egg_file->write_texture_refs(cout, 4);
00254 }
00255
00256
00257
00258 pvector<PaletteGroup *> sorted_groups;
00259 Groups::const_iterator gi;
00260 for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00261 sorted_groups.push_back((*gi).second);
00262 }
00263 sort(sorted_groups.begin(), sorted_groups.end(),
00264 SortGroupsByPreference());
00265
00266 cout << "\npalette groups\n";
00267 pvector<PaletteGroup *>::iterator si;
00268 for (si = sorted_groups.begin(); si != sorted_groups.end(); ++si) {
00269 PaletteGroup *group = (*si);
00270 if (si != sorted_groups.begin()) {
00271 cout << "\n";
00272 }
00273 cout << " " << group->get_name()
00274
00275 << ": " << group->get_groups() << "\n";
00276 group->write_image_info(cout, 4);
00277 }
00278
00279 cout << "\ntextures\n";
00280 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00281 TextureImage *texture = (*ti).second;
00282 texture->write_scale_info(cout, 2);
00283 }
00284
00285 cout << "\nsurprises\n";
00286 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00287 TextureImage *texture = (*ti).second;
00288 if (texture->is_surprise()) {
00289 cout << " " << texture->get_name() << "\n";
00290 }
00291 }
00292 for (ei = _egg_files.begin(); ei != _egg_files.end(); ++ei) {
00293 EggFile *egg_file = (*ei).second;
00294 if (egg_file->is_surprise()) {
00295 cout << " " << egg_file->get_name() << "\n";
00296 }
00297 }
00298
00299 cout << "\n";
00300 }
00301
00302
00303
00304
00305
00306
00307
00308 void Palettizer::
00309 report_statistics() const {
00310
00311
00312 pvector<PaletteGroup *> sorted_groups;
00313
00314 Groups::const_iterator gi;
00315 for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00316 sorted_groups.push_back((*gi).second);
00317 }
00318
00319 sort(sorted_groups.begin(), sorted_groups.end(),
00320 SortGroupsByDependencyOrder());
00321
00322 Placements overall_placements;
00323
00324 pvector<PaletteGroup *>::const_iterator si;
00325 for (si = sorted_groups.begin();
00326 si != sorted_groups.end();
00327 ++si) {
00328 PaletteGroup *group = (*si);
00329
00330 Placements placements;
00331 group->get_placements(placements);
00332 if (!placements.empty()) {
00333 group->get_placements(overall_placements);
00334
00335 cout << "\n" << group->get_name() << ", by itself:\n";
00336 compute_statistics(cout, 2, placements);
00337
00338 PaletteGroups complete;
00339 complete.make_complete(group->get_groups());
00340
00341 if (complete.size() > 1) {
00342 Placements complete_placements;
00343 group->get_complete_placements(complete_placements);
00344 if (complete_placements.size() != placements.size()) {
00345 cout << "\n" << group->get_name()
00346 << ", with dependents (" << complete << "):\n";
00347 compute_statistics(cout, 2, complete_placements);
00348 }
00349 }
00350 }
00351 }
00352
00353 cout << "\nOverall:\n";
00354 compute_statistics(cout, 2, overall_placements);
00355
00356 cout << "\n";
00357 }
00358
00359
00360
00361
00362
00363
00364
00365
00366 void Palettizer::
00367 read_txa_file(istream &txa_file, const string &txa_filename) {
00368
00369
00370 Groups::iterator gi;
00371 for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00372 PaletteGroup *group = (*gi).second;
00373 group->clear_depends();
00374 group->set_dirname("");
00375 }
00376
00377
00378 _shadow_color_type = (PNMFileType *)NULL;
00379 _shadow_alpha_type = (PNMFileType *)NULL;
00380
00381 if (!_txa_file.read(txa_file, txa_filename)) {
00382 exit(1);
00383 }
00384
00385 if (_color_type == (PNMFileType *)NULL) {
00386 nout << "No valid output image file type available; cannot run.\n"
00387 << "Use :imagetype command in .txa file.\n";
00388 exit(1);
00389 }
00390
00391
00392
00393 for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00394 PaletteGroup *group = (*gi).second;
00395 group->reset_dependency_level();
00396 }
00397
00398 for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00399 PaletteGroup *group = (*gi).second;
00400 group->set_dependency_level(1);
00401 }
00402
00403 bool any_changed;
00404 do {
00405 any_changed = false;
00406 for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00407 PaletteGroup *group = (*gi).second;
00408 if (group->set_dependency_order()) {
00409 any_changed = true;
00410 }
00411 }
00412 } while (any_changed);
00413 }
00414
00415
00416
00417
00418
00419
00420
00421
00422 void Palettizer::
00423 all_params_set() {
00424
00425 Groups::iterator gi;
00426 for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00427 PaletteGroup *group = (*gi).second;
00428 group->setup_shadow_images();
00429 }
00430 }
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443 void Palettizer::
00444 process_command_line_eggs(bool force_texture_read, const Filename &state_filename) {
00445 _command_line_textures.clear();
00446
00447
00448
00449 CommandLineEggs::const_iterator ei;
00450 for (ei = _command_line_eggs.begin();
00451 ei != _command_line_eggs.end();
00452 ++ei) {
00453 EggFile *egg_file = (*ei);
00454
00455 egg_file->scan_textures();
00456 egg_file->get_textures(_command_line_textures);
00457
00458 egg_file->pre_txa_file();
00459 _txa_file.match_egg(egg_file);
00460 egg_file->post_txa_file();
00461 }
00462
00463
00464
00465 EggFiles::const_iterator efi;
00466 for (efi = _egg_files.begin(); efi != _egg_files.end(); ++efi) {
00467 (*efi).second->build_cross_links();
00468 }
00469
00470
00471
00472 CommandLineTextures::iterator ti;
00473 for (ti = _command_line_textures.begin();
00474 ti != _command_line_textures.end();
00475 ++ti) {
00476 TextureImage *texture = *ti;
00477
00478 if (force_texture_read || texture->is_newer_than(state_filename)) {
00479
00480
00481 texture->read_source_image();
00482 } else {
00483
00484 texture->read_header();
00485 }
00486
00487 texture->mark_texture_named();
00488 texture->pre_txa_file();
00489 _txa_file.match_texture(texture);
00490 texture->post_txa_file();
00491 }
00492
00493
00494
00495 for (ti = _command_line_textures.begin();
00496 ti != _command_line_textures.end();
00497 ++ti) {
00498 TextureImage *texture = *ti;
00499 texture->assign_groups();
00500 }
00501
00502
00503
00504
00505
00506 for (efi = _egg_files.begin(); efi != _egg_files.end(); ++efi) {
00507 (*efi).second->choose_placements();
00508 }
00509
00510
00511
00512 for (ti = _command_line_textures.begin();
00513 ti != _command_line_textures.end();
00514 ++ti) {
00515 TextureImage *texture = *ti;
00516 texture->determine_placement_size();
00517 }
00518
00519
00520
00521 Groups::iterator gi;
00522 for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00523 PaletteGroup *group = (*gi).second;
00524 group->update_unknown_textures(_txa_file);
00525 group->place_all();
00526 }
00527 }
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538 void Palettizer::
00539 process_all(bool force_texture_read, const Filename &state_filename) {
00540
00541
00542
00543 Textures::iterator ti;
00544 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00545 TextureImage *texture = (*ti).second;
00546 texture->clear_source_basic_properties();
00547 }
00548
00549
00550
00551 CommandLineEggs::const_iterator ei;
00552 for (ei = _command_line_eggs.begin();
00553 ei != _command_line_eggs.end();
00554 ++ei) {
00555 EggFile *egg_file = (*ei);
00556
00557 egg_file->scan_textures();
00558 egg_file->get_textures(_command_line_textures);
00559 }
00560
00561
00562 EggFiles::const_iterator efi;
00563 for (efi = _egg_files.begin(); efi != _egg_files.end(); ++efi) {
00564 EggFile *egg_file = (*efi).second;
00565 egg_file->pre_txa_file();
00566 _txa_file.match_egg(egg_file);
00567 egg_file->post_txa_file();
00568 }
00569
00570
00571
00572 for (efi = _egg_files.begin(); efi != _egg_files.end(); ++efi) {
00573 (*efi).second->build_cross_links();
00574
00575
00576
00577
00578 (*efi).second->apply_properties_to_source();
00579 }
00580
00581
00582
00583 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00584 TextureImage *texture = (*ti).second;
00585 if (force_texture_read || texture->is_newer_than(state_filename)) {
00586 texture->read_source_image();
00587 }
00588
00589 texture->mark_texture_named();
00590 texture->pre_txa_file();
00591 _txa_file.match_texture(texture);
00592 texture->post_txa_file();
00593
00594
00595 texture->release_source_image();
00596 }
00597
00598
00599 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00600 TextureImage *texture = (*ti).second;
00601 texture->assign_groups();
00602 }
00603
00604
00605
00606
00607
00608 for (efi = _egg_files.begin(); efi != _egg_files.end(); ++efi) {
00609 (*efi).second->choose_placements();
00610 }
00611
00612
00613
00614 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00615 TextureImage *texture = (*ti).second;
00616 texture->determine_placement_size();
00617 }
00618
00619
00620
00621 Groups::iterator gi;
00622 for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00623 PaletteGroup *group = (*gi).second;
00624 group->update_unknown_textures(_txa_file);
00625 group->place_all();
00626 }
00627 }
00628
00629
00630
00631
00632
00633
00634
00635 void Palettizer::
00636 optimal_resize() {
00637 Groups::iterator gi;
00638 for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00639 PaletteGroup *group = (*gi).second;
00640 group->optimal_resize();
00641 }
00642 }
00643
00644
00645
00646
00647
00648
00649
00650
00651 void Palettizer::
00652 reset_images() {
00653 Groups::iterator gi;
00654 for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00655 PaletteGroup *group = (*gi).second;
00656 group->reset_images();
00657 }
00658 }
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668 void Palettizer::
00669 generate_images(bool redo_all) {
00670 Groups::iterator gi;
00671 for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00672 PaletteGroup *group = (*gi).second;
00673 group->update_images(redo_all);
00674 }
00675
00676 Textures::iterator ti;
00677 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00678 TextureImage *texture = (*ti).second;
00679 texture->copy_unplaced(redo_all);
00680 }
00681 }
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695 bool Palettizer::
00696 read_stale_eggs(bool redo_all) {
00697 bool okflag = true;
00698
00699 pvector<EggFiles::iterator> invalid_eggs;
00700
00701 EggFiles::iterator ei;
00702 for (ei = _egg_files.begin(); ei != _egg_files.end(); ++ei) {
00703 EggFile *egg_file = (*ei).second;
00704 if (!egg_file->had_data() &&
00705 (egg_file->is_stale() || redo_all)) {
00706 if (!egg_file->read_egg(_noabs)) {
00707 invalid_eggs.push_back(ei);
00708
00709 } else {
00710 egg_file->scan_textures();
00711 egg_file->choose_placements();
00712 egg_file->release_egg_data();
00713 }
00714 }
00715 }
00716
00717
00718 pvector<EggFiles::iterator>::iterator ii;
00719 for (ii = invalid_eggs.begin(); ii != invalid_eggs.end(); ++ii) {
00720 EggFiles::iterator ei = (*ii);
00721 EggFile *egg_file = (*ei).second;
00722 if (egg_file->get_source_filename().exists()) {
00723
00724
00725 nout << "Removing invalid egg file: "
00726 << FilenameUnifier::make_user_filename(egg_file->get_source_filename())
00727 << "\n";
00728
00729 egg_file->get_source_filename().unlink();
00730 okflag = false;
00731
00732 } else {
00733
00734
00735 egg_file->remove_egg();
00736 _egg_files.erase(ei);
00737 }
00738 }
00739
00740 if (!okflag) {
00741 nout << "\n"
00742 << "Some errors in egg files encountered.\n"
00743 << "Re-run make install or make opt-pal to try to regenerate these.\n\n";
00744 }
00745
00746 return okflag;
00747 }
00748
00749
00750
00751
00752
00753
00754
00755
00756 bool Palettizer::
00757 write_eggs() {
00758 bool okflag = true;
00759
00760 EggFiles::iterator ei;
00761 for (ei = _egg_files.begin(); ei != _egg_files.end(); ++ei) {
00762 EggFile *egg_file = (*ei).second;
00763 if (egg_file->had_data()) {
00764 if (!egg_file->has_data()) {
00765
00766 bool read_ok = egg_file->read_egg(_noabs);
00767 if (!read_ok) {
00768 nout << "Error! Unable to re-read egg file.\n";
00769 okflag = false;
00770 }
00771 }
00772
00773 if (egg_file->has_data()) {
00774 egg_file->update_egg();
00775 if (!egg_file->write_egg()) {
00776 okflag = false;
00777 }
00778 egg_file->release_egg_data();
00779 }
00780 }
00781 }
00782
00783 return okflag;
00784 }
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794 EggFile *Palettizer::
00795 get_egg_file(const string &name) {
00796 EggFiles::iterator ei = _egg_files.find(name);
00797 if (ei != _egg_files.end()) {
00798 return (*ei).second;
00799 }
00800
00801 EggFile *file = new EggFile;
00802 file->set_name(name);
00803 _egg_files.insert(EggFiles::value_type(name, file));
00804 return file;
00805 }
00806
00807
00808
00809
00810
00811
00812
00813
00814 bool Palettizer::
00815 remove_egg_file(const string &name) {
00816 EggFiles::iterator ei = _egg_files.find(name);
00817 if (ei != _egg_files.end()) {
00818 EggFile *file = (*ei).second;
00819 file->remove_egg();
00820 _egg_files.erase(ei);
00821 return true;
00822 }
00823
00824 return false;
00825 }
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835 void Palettizer::
00836 add_command_line_egg(EggFile *egg_file) {
00837 _command_line_eggs.push_back(egg_file);
00838 }
00839
00840
00841
00842
00843
00844
00845
00846
00847 PaletteGroup *Palettizer::
00848 get_palette_group(const string &name) {
00849 Groups::iterator gi = _groups.find(name);
00850 if (gi != _groups.end()) {
00851 return (*gi).second;
00852 }
00853
00854 PaletteGroup *group = new PaletteGroup;
00855 group->set_name(name);
00856 _groups.insert(Groups::value_type(name, group));
00857 return group;
00858 }
00859
00860
00861
00862
00863
00864
00865
00866
00867 PaletteGroup *Palettizer::
00868 test_palette_group(const string &name) const {
00869 Groups::const_iterator gi = _groups.find(name);
00870 if (gi != _groups.end()) {
00871 return (*gi).second;
00872 }
00873
00874 return (PaletteGroup *)NULL;
00875 }
00876
00877
00878
00879
00880
00881
00882
00883 PaletteGroup *Palettizer::
00884 get_default_group() {
00885 PaletteGroup *default_group = get_palette_group(_default_groupname);
00886 if (!_default_groupdir.empty() && !default_group->has_dirname()) {
00887 default_group->set_dirname(_default_groupdir);
00888 }
00889 return default_group;
00890 }
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901 TextureImage *Palettizer::
00902 get_texture(const string &name) {
00903
00904
00905 Textures::iterator ti = _textures.find(name);
00906 if (ti != _textures.end()) {
00907 return (*ti).second;
00908 }
00909
00910
00911
00912 string downcase_name = downcase(name);
00913 ti = _textures.find(downcase_name);
00914 if (ti != _textures.end()) {
00915 return (*ti).second;
00916 }
00917
00918 TextureImage *image = new TextureImage;
00919 image->set_name(name);
00920
00921 _textures.insert(Textures::value_type(downcase_name, image));
00922
00923 return image;
00924 }
00925
00926
00927
00928
00929
00930
00931
00932 const char *Palettizer::
00933 yesno(bool flag) {
00934 return flag ? "yes" : "no";
00935 }
00936
00937
00938
00939
00940
00941
00942
00943
00944 Palettizer::RemapUV Palettizer::
00945 string_remap(const string &str) {
00946 if (str == "never") {
00947 return RU_never;
00948
00949 } else if (str == "group") {
00950 return RU_group;
00951
00952 } else if (str == "poly") {
00953 return RU_poly;
00954
00955 } else {
00956 return RU_invalid;
00957 }
00958 }
00959
00960
00961
00962
00963
00964
00965
00966
00967 void Palettizer::
00968 compute_statistics(ostream &out, int indent_level,
00969 const Palettizer::Placements &placements) const {
00970 TextureMemoryCounter counter;
00971
00972 Placements::const_iterator pi;
00973 for (pi = placements.begin(); pi != placements.end(); ++pi) {
00974 TexturePlacement *placement = (*pi);
00975 counter.add_placement(placement);
00976 }
00977
00978 counter.report(out, indent_level);
00979 }
00980
00981
00982
00983
00984
00985
00986
00987 void Palettizer::
00988 register_with_read_factory() {
00989 BamReader::get_factory()->
00990 register_factory(get_class_type(), make_Palettizer);
00991 }
00992
00993
00994
00995
00996
00997
00998
00999
01000 void Palettizer::
01001 write_datagram(BamWriter *writer, Datagram &datagram) {
01002 TypedWritable::write_datagram(writer, datagram);
01003
01004 datagram.add_int32(_pi_version);
01005 datagram.add_string(_generated_image_pattern);
01006 datagram.add_string(_map_dirname);
01007 datagram.add_string(FilenameUnifier::make_bam_filename(_shadow_dirname));
01008 datagram.add_string(FilenameUnifier::make_bam_filename(_rel_dirname));
01009 datagram.add_int32(_pal_x_size);
01010 datagram.add_int32(_pal_y_size);
01011 datagram.add_float64(_background[0]);
01012 datagram.add_float64(_background[1]);
01013 datagram.add_float64(_background[2]);
01014 datagram.add_float64(_background[3]);
01015 datagram.add_int32(_margin);
01016 datagram.add_bool(_omit_solitary);
01017 datagram.add_bool(_omit_everything);
01018 datagram.add_float64(_coverage_threshold);
01019 datagram.add_bool(_force_power_2);
01020 datagram.add_bool(_aggressively_clean_mapdir);
01021 datagram.add_bool(_round_uvs);
01022 datagram.add_float64(_round_unit);
01023 datagram.add_float64(_round_fuzz);
01024 datagram.add_int32((int)_remap_uv);
01025 datagram.add_int32((int)_remap_char_uv);
01026 datagram.add_uint8((int)_cutout_mode);
01027 datagram.add_float64(_cutout_ratio);
01028
01029 writer->write_pointer(datagram, _color_type);
01030 writer->write_pointer(datagram, _alpha_type);
01031 writer->write_pointer(datagram, _shadow_color_type);
01032 writer->write_pointer(datagram, _shadow_alpha_type);
01033
01034 datagram.add_int32(_egg_files.size());
01035 EggFiles::const_iterator ei;
01036 for (ei = _egg_files.begin(); ei != _egg_files.end(); ++ei) {
01037 writer->write_pointer(datagram, (*ei).second);
01038 }
01039
01040
01041
01042
01043 datagram.add_int32(_groups.size());
01044 Groups::const_iterator gi;
01045 for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
01046 writer->write_pointer(datagram, (*gi).second);
01047 }
01048
01049 datagram.add_int32(_textures.size());
01050 Textures::const_iterator ti;
01051 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
01052 writer->write_pointer(datagram, (*ti).second);
01053 }
01054 }
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065 int Palettizer::
01066 complete_pointers(TypedWritable **p_list, BamReader *manager) {
01067 int index = TypedWritable::complete_pointers(p_list, manager);
01068
01069 if (p_list[index] != (TypedWritable *)NULL) {
01070 DCAST_INTO_R(_color_type, p_list[index], index);
01071 }
01072 index++;
01073
01074 if (p_list[index] != (TypedWritable *)NULL) {
01075 DCAST_INTO_R(_alpha_type, p_list[index], index);
01076 }
01077 index++;
01078
01079 if (p_list[index] != (TypedWritable *)NULL) {
01080 DCAST_INTO_R(_shadow_color_type, p_list[index], index);
01081 }
01082 index++;
01083
01084 if (p_list[index] != (TypedWritable *)NULL) {
01085 DCAST_INTO_R(_shadow_alpha_type, p_list[index], index);
01086 }
01087 index++;
01088
01089 int i;
01090 for (i = 0; i < _num_egg_files; i++) {
01091 EggFile *egg_file;
01092 DCAST_INTO_R(egg_file, p_list[index], index);
01093 _egg_files.insert(EggFiles::value_type(egg_file->get_name(), egg_file));
01094 index++;
01095 }
01096
01097 for (i = 0; i < _num_groups; i++) {
01098 PaletteGroup *group;
01099 DCAST_INTO_R(group, p_list[index], index);
01100 _groups.insert(Groups::value_type(group->get_name(), group));
01101 index++;
01102 }
01103
01104 for (i = 0; i < _num_textures; i++) {
01105 TextureImage *texture;
01106 DCAST_INTO_R(texture, p_list[index], index);
01107
01108 string name = downcase(texture->get_name());
01109 pair<Textures::iterator, bool> result = _textures.insert(Textures::value_type(name, texture));
01110 if (!result.second) {
01111
01112
01113 _texture_conflicts.push_back(texture);
01114 }
01115 index++;
01116 }
01117
01118 return index;
01119 }
01120
01121
01122
01123
01124
01125
01126
01127
01128 void Palettizer::
01129 finalize(BamReader *manager) {
01130
01131
01132
01133
01134 TextureConflicts::iterator ci;
01135 for (ci = _texture_conflicts.begin();
01136 ci != _texture_conflicts.end();
01137 ++ci) {
01138 TextureImage *texture_b = (*ci);
01139 string downcase_name = downcase(texture_b->get_name());
01140
01141 Textures::iterator ti = _textures.find(downcase_name);
01142 nassertv(ti != _textures.end());
01143 TextureImage *texture_a = (*ti).second;
01144 _textures.erase(ti);
01145
01146 if (!texture_b->is_used() || !texture_a->is_used()) {
01147
01148
01149 if (texture_a->is_used()) {
01150 bool inserted1 = _textures.insert(Textures::value_type(downcase_name, texture_a)).second;
01151 nassertd(inserted1) { }
01152
01153 } else if (texture_b->is_used()) {
01154 bool inserted2 = _textures.insert(Textures::value_type(downcase_name, texture_b)).second;
01155 nassertd(inserted2) { }
01156 }
01157
01158 } else {
01159
01160 nout << "Texture name conflict: \"" << texture_a->get_name()
01161 << "\" vs. \"" << texture_b->get_name() << "\"\n";
01162 if (texture_a->get_name() != downcase_name &&
01163 texture_b->get_name() != downcase_name) {
01164
01165 bool inserted1 = _textures.insert(Textures::value_type(downcase_name, texture_a)).second;
01166 bool inserted2 = _textures.insert(Textures::value_type(texture_b->get_name(), texture_b)).second;
01167 nassertd(inserted1 && inserted2) { }
01168
01169 } else {
01170
01171 bool inserted1 = _textures.insert(Textures::value_type(texture_a->get_name(), texture_a)).second;
01172 bool inserted2 = _textures.insert(Textures::value_type(texture_b->get_name(), texture_b)).second;
01173 nassertd(inserted1 && inserted2) { }
01174 }
01175 }
01176 }
01177 }
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188 TypedWritable* Palettizer::
01189 make_Palettizer(const FactoryParams ¶ms) {
01190 Palettizer *me = new Palettizer;
01191 DatagramIterator scan;
01192 BamReader *manager;
01193
01194 parse_params(params, scan, manager);
01195 me->fillin(scan, manager);
01196 manager->register_finalize(me);
01197
01198 return me;
01199 }
01200
01201
01202
01203
01204
01205
01206
01207
01208 void Palettizer::
01209 fillin(DatagramIterator &scan, BamReader *manager) {
01210 TypedWritable::fillin(scan, manager);
01211
01212 _read_pi_version = scan.get_int32();
01213 if (_read_pi_version > _pi_version || _read_pi_version < _min_pi_version) {
01214
01215 _is_valid = false;
01216 return;
01217 }
01218 if (_read_pi_version >= 12) {
01219 _generated_image_pattern = scan.get_string();
01220 }
01221 _map_dirname = scan.get_string();
01222 _shadow_dirname = FilenameUnifier::get_bam_filename(scan.get_string());
01223 _rel_dirname = FilenameUnifier::get_bam_filename(scan.get_string());
01224 FilenameUnifier::set_rel_dirname(_rel_dirname);
01225 _pal_x_size = scan.get_int32();
01226 _pal_y_size = scan.get_int32();
01227 if (_read_pi_version >= 13) {
01228 _background[0] = scan.get_float64();
01229 _background[1] = scan.get_float64();
01230 _background[2] = scan.get_float64();
01231 _background[3] = scan.get_float64();
01232 }
01233 _margin = scan.get_int32();
01234 _omit_solitary = scan.get_bool();
01235 if (_read_pi_version >= 14) {
01236 _omit_everything = scan.get_bool();
01237 }
01238 _coverage_threshold = scan.get_float64();
01239 _force_power_2 = scan.get_bool();
01240 _aggressively_clean_mapdir = scan.get_bool();
01241 _round_uvs = scan.get_bool();
01242 _round_unit = scan.get_float64();
01243 _round_fuzz = scan.get_float64();
01244 _remap_uv = (RemapUV)scan.get_int32();
01245 _remap_char_uv = (RemapUV)scan.get_int32();
01246 if (_read_pi_version >= 16) {
01247 _cutout_mode = (EggRenderMode::AlphaMode)scan.get_uint8();
01248 _cutout_ratio = scan.get_float64();
01249 }
01250
01251 manager->read_pointer(scan);
01252 manager->read_pointer(scan);
01253 manager->read_pointer(scan);
01254 manager->read_pointer(scan);
01255
01256 _num_egg_files = scan.get_int32();
01257 manager->read_pointers(scan, _num_egg_files);
01258
01259 _num_groups = scan.get_int32();
01260 manager->read_pointers(scan, _num_groups);
01261
01262 _num_textures = scan.get_int32();
01263 manager->read_pointers(scan, _num_textures);
01264 }