00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "eggFile.h"
00016 #include "textureImage.h"
00017 #include "paletteGroup.h"
00018 #include "texturePlacement.h"
00019 #include "textureReference.h"
00020 #include "sourceTextureImage.h"
00021 #include "palettizer.h"
00022 #include "filenameUnifier.h"
00023
00024 #include "eggData.h"
00025 #include "eggGroup.h"
00026 #include "eggTextureCollection.h"
00027 #include "eggComment.h"
00028 #include "datagram.h"
00029 #include "datagramIterator.h"
00030 #include "bamReader.h"
00031 #include "bamWriter.h"
00032 #include "executionEnvironment.h"
00033 #include "dSearchPath.h"
00034 #include "indirectLess.h"
00035
00036 #include <algorithm>
00037
00038 TypeHandle EggFile::_type_handle;
00039
00040
00041
00042
00043
00044
00045 EggFile::
00046 EggFile() {
00047 _data = (EggData *)NULL;
00048 _first_txa_match = false;
00049 _default_group = (PaletteGroup *)NULL;
00050 _is_surprise = true;
00051 _is_stale = true;
00052 _had_data = false;
00053 }
00054
00055
00056
00057
00058
00059
00060
00061
00062 bool EggFile::
00063 from_command_line(EggData *data,
00064 const Filename &source_filename,
00065 const Filename &dest_filename,
00066 const string &egg_comment) {
00067 _data = data;
00068 _had_data = true;
00069 remove_backstage(_data);
00070
00071
00072
00073
00074
00075 _current_directory = ExecutionEnvironment::get_cwd();
00076 _source_filename = source_filename;
00077 _source_filename.make_absolute();
00078 _dest_filename = dest_filename;
00079 _dest_filename.make_absolute();
00080
00081
00082
00083
00084 _egg_comment = egg_comment;
00085
00086
00087
00088
00089 _default_group = pal->get_default_group();
00090
00091 return true;
00092 }
00093
00094
00095
00096
00097
00098
00099 const Filename &EggFile::
00100 get_source_filename() const {
00101 return _source_filename;
00102 }
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113 void EggFile::
00114 scan_textures() {
00115 nassertv(_data != (EggData *)NULL);
00116
00117
00118 EggTextureCollection tc;
00119 tc.find_used_textures(_data);
00120
00121
00122 tc.uniquify_trefs();
00123
00124
00125
00126 Textures new_textures;
00127
00128 EggTextureCollection::iterator eti;
00129 for (eti = tc.begin(); eti != tc.end(); ++eti) {
00130 EggTexture *egg_tex = (*eti);
00131
00132 TextureReference *ref = new TextureReference;
00133 ref->from_egg(this, _data, egg_tex);
00134
00135 if (!ref->has_uvs()) {
00136
00137
00138
00139 delete ref;
00140
00141 } else {
00142 new_textures.push_back(ref);
00143 }
00144 }
00145
00146
00147
00148 sort(new_textures.begin(), new_textures.end(),
00149 IndirectLess<TextureReference>());
00150
00151
00152
00153 sort(_textures.begin(), _textures.end(),
00154 IndirectLess<TextureReference>());
00155
00156
00157 Textures combined_textures;
00158 Textures::const_iterator ai = _textures.begin();
00159 Textures::const_iterator bi = new_textures.begin();
00160
00161 while (ai != _textures.end() && bi != new_textures.end()) {
00162 TextureReference *aref = (*ai);
00163 TextureReference *bref = (*bi);
00164
00165 if ((*aref) < (*bref)) {
00166
00167
00168 delete aref;
00169 ++ai;
00170
00171 } else if ((*bref) < (*aref)) {
00172
00173
00174 combined_textures.push_back(bref);
00175 ++bi;
00176
00177 } else {
00178
00179 if (aref->is_equivalent(*bref)) {
00180
00181
00182
00183 aref->from_egg_quick(*bref);
00184 combined_textures.push_back(aref);
00185 delete bref;
00186
00187 } else {
00188
00189 combined_textures.push_back(bref);
00190 delete aref;
00191 }
00192 ++ai;
00193 ++bi;
00194 }
00195 }
00196
00197 while (bi != new_textures.end()) {
00198 TextureReference *bref = (*bi);
00199
00200
00201 combined_textures.push_back(bref);
00202 ++bi;
00203 }
00204
00205 while (ai != _textures.end()) {
00206 TextureReference *aref = (*ai);
00207
00208
00209 delete aref;
00210 ++ai;
00211 }
00212
00213 _textures.swap(combined_textures);
00214 }
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225 void EggFile::
00226 get_textures(pset<TextureImage *> &result) const {
00227 Textures::const_iterator ti;
00228 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00229 result.insert((*ti)->get_texture());
00230 }
00231 }
00232
00233
00234
00235
00236
00237
00238 void EggFile::
00239 pre_txa_file() {
00240 _is_surprise = true;
00241 _first_txa_match = true;
00242 }
00243
00244
00245
00246
00247
00248
00249
00250
00251 void EggFile::
00252 match_txa_groups(const PaletteGroups &groups) {
00253 if (_first_txa_match) {
00254
00255
00256
00257
00258
00259 _explicitly_assigned_groups.clear();
00260 _first_txa_match = false;
00261 }
00262
00263 _explicitly_assigned_groups.make_union(_explicitly_assigned_groups, groups);
00264 }
00265
00266
00267
00268
00269
00270
00271
00272
00273 void EggFile::
00274 post_txa_file() {
00275 }
00276
00277
00278
00279
00280
00281
00282
00283 const PaletteGroups &EggFile::
00284 get_explicit_groups() const {
00285 return _explicitly_assigned_groups;
00286 }
00287
00288
00289
00290
00291
00292
00293
00294
00295 PaletteGroup *EggFile::
00296 get_default_group() const {
00297 return _default_group;
00298 }
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308 const PaletteGroups &EggFile::
00309 get_complete_groups() const {
00310 return _complete_groups;
00311 }
00312
00313
00314
00315
00316
00317
00318
00319 void EggFile::
00320 clear_surprise() {
00321 _is_surprise = false;
00322 }
00323
00324
00325
00326
00327
00328
00329
00330
00331 bool EggFile::
00332 is_surprise() const {
00333 return _is_surprise;
00334 }
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344 void EggFile::
00345 mark_stale() {
00346 _is_stale = true;
00347 }
00348
00349
00350
00351
00352
00353
00354
00355
00356 bool EggFile::
00357 is_stale() const {
00358 return _is_stale;
00359 }
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372 void EggFile::
00373 build_cross_links() {
00374 if (_explicitly_assigned_groups.empty()) {
00375
00376
00377 _complete_groups.clear();
00378 _complete_groups.insert(_default_group);
00379 _complete_groups.make_complete(_complete_groups);
00380
00381 } else {
00382 _complete_groups.make_complete(_explicitly_assigned_groups);
00383 }
00384
00385 Textures::const_iterator ti;
00386 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00387 TextureReference *reference = (*ti);
00388 TextureImage *texture = reference->get_texture();
00389 nassertv(texture != (TextureImage *)NULL);
00390 texture->note_egg_file(this);
00391
00392
00393
00394
00395
00396 reference->get_source()->increment_egg_count();
00397 }
00398
00399 PaletteGroups::const_iterator gi;
00400 for (gi = _complete_groups.begin();
00401 gi != _complete_groups.end();
00402 ++gi) {
00403 (*gi)->increment_egg_count();
00404 }
00405 }
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415 void EggFile::
00416 apply_properties_to_source() {
00417 Textures::const_iterator ti;
00418 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00419 TextureReference *reference = (*ti);
00420 reference->apply_properties_to_source();
00421 }
00422 }
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436 void EggFile::
00437 choose_placements() {
00438 Textures::const_iterator ti;
00439 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00440 TextureReference *reference = (*ti);
00441 TextureImage *texture = reference->get_texture();
00442
00443 if (reference->get_placement() != (TexturePlacement *)NULL &&
00444 texture->get_groups().count(reference->get_placement()->get_group()) != 0) {
00445
00446
00447
00448 } else {
00449
00450 PaletteGroups groups;
00451 groups.make_intersection(get_complete_groups(), texture->get_groups());
00452
00453
00454
00455
00456 if (groups.empty()) {
00457
00458
00459
00460
00461 groups = texture->get_groups();
00462 }
00463
00464 if (!groups.empty()) {
00465
00466
00467 PaletteGroup *group = (*groups.begin());
00468
00469
00470
00471 TexturePlacement *placement = texture->get_placement(group);
00472 nassertv(placement != (TexturePlacement *)NULL);
00473
00474 reference->set_placement(placement);
00475 }
00476 }
00477 }
00478 }
00479
00480
00481
00482
00483
00484
00485
00486 bool EggFile::
00487 has_data() const {
00488 return (_data != (EggData *)NULL);
00489 }
00490
00491
00492
00493
00494
00495
00496
00497 bool EggFile::
00498 had_data() const {
00499 return _had_data;
00500 }
00501
00502
00503
00504
00505
00506
00507
00508
00509 void EggFile::
00510 update_egg() {
00511 nassertv(_data != (EggData *)NULL);
00512
00513 Textures::iterator ti;
00514 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00515 TextureReference *reference = (*ti);
00516 reference->update_egg();
00517 }
00518 }
00519
00520
00521
00522
00523
00524
00525
00526 void EggFile::
00527 remove_egg() {
00528 Textures::iterator ti;
00529 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00530 TextureReference *reference = (*ti);
00531 TexturePlacement *placement = reference->get_placement();
00532 placement->remove_egg(reference);
00533 }
00534 }
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548 bool EggFile::
00549 read_egg(bool noabs) {
00550 nassertr(_data == (EggData *)NULL, false);
00551 nassertr(!_source_filename.empty(), false);
00552
00553 Filename user_source_filename =
00554 FilenameUnifier::make_user_filename(_source_filename);
00555
00556 if (!_source_filename.exists()) {
00557 nout << user_source_filename << " does not exist.\n";
00558 return false;
00559 }
00560
00561 PT(EggData) data = new EggData;
00562 if (!data->read(_source_filename, user_source_filename)) {
00563
00564 return false;
00565 }
00566
00567 if (noabs && data->original_had_absolute_pathnames()) {
00568 nout << _source_filename.get_basename()
00569 << " references textures using absolute pathnames!\n";
00570 return false;
00571 }
00572
00573
00574 EggTextureCollection tc;
00575 tc.find_used_textures(data);
00576
00577
00578 tc.uniquify_trefs();
00579
00580
00581
00582 Textures new_textures;
00583
00584
00585
00586
00587
00588 DSearchPath dir;
00589 dir.append_directory(_source_filename.get_dirname());
00590 dir.append_directory(_current_directory);
00591 data->resolve_filenames(dir);
00592
00593
00594
00595 data->force_filenames(_current_directory);
00596
00597 if (!data->load_externals()) {
00598
00599 return false;
00600 }
00601
00602 _data = data;
00603 _had_data = true;
00604 remove_backstage(_data);
00605
00606
00607 PT(EggNode) comment = new EggComment("", _egg_comment);
00608 _data->insert(_data->begin(), comment);
00609
00610 if (!_textures.empty()) {
00611
00612 rescan_textures();
00613 }
00614
00615 return true;
00616 }
00617
00618
00619
00620
00621
00622
00623
00624 void EggFile::
00625 release_egg_data() {
00626 if (_data != (EggData *)NULL) {
00627 _data = NULL;
00628 }
00629 Textures::iterator ti;
00630 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00631 TextureReference *reference = (*ti);
00632 reference->release_egg_data();
00633 }
00634 }
00635
00636
00637
00638
00639
00640
00641
00642
00643 bool EggFile::
00644 write_egg() {
00645 nassertr(_data != (EggData *)NULL, false);
00646 nassertr(!_dest_filename.empty(), false);
00647
00648 _dest_filename.make_dir();
00649 nout << "Writing " << FilenameUnifier::make_user_filename(_dest_filename)
00650 << "\n";
00651 if (!_data->write_egg(_dest_filename)) {
00652
00653 _is_stale = true;
00654 return false;
00655 }
00656
00657 _is_stale = false;
00658 return true;
00659 }
00660
00661
00662
00663
00664
00665
00666
00667 void EggFile::
00668 write_description(ostream &out, int indent_level) const {
00669 indent(out, indent_level) << get_name() << ": ";
00670 if (_explicitly_assigned_groups.empty()) {
00671 if (_default_group != (PaletteGroup *)NULL) {
00672 out << _default_group->get_name();
00673 }
00674 } else {
00675 out << _explicitly_assigned_groups;
00676 }
00677
00678 if (is_stale()) {
00679 out << " (needs update)";
00680 }
00681 out << "\n";
00682 }
00683
00684
00685
00686
00687
00688
00689
00690 void EggFile::
00691 write_texture_refs(ostream &out, int indent_level) const {
00692 Textures::const_iterator ti;
00693 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00694 TextureReference *reference = (*ti);
00695 reference->write(out, indent_level);
00696 }
00697 }
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708 void EggFile::
00709 remove_backstage(EggGroupNode *node) {
00710 EggGroupNode::iterator ci;
00711 ci = node->begin();
00712 while (ci != node->end()) {
00713 EggNode *child = (*ci);
00714 bool remove_child = false;
00715
00716 if (child->is_of_type(EggGroup::get_class_type())) {
00717 EggGroup *egg_group;
00718 DCAST_INTO_V(egg_group, child);
00719 remove_child = egg_group->has_object_type("backstage");
00720 }
00721
00722 if (remove_child) {
00723 ci = node->erase(ci);
00724 } else {
00725 if (child->is_of_type(EggGroupNode::get_class_type())) {
00726
00727 remove_backstage(DCAST(EggGroupNode, child));
00728 }
00729 ++ci;
00730 }
00731 }
00732 }
00733
00734
00735
00736
00737
00738
00739
00740
00741 void EggFile::
00742 rescan_textures() {
00743 nassertv(_data != (EggData *)NULL);
00744
00745
00746 EggTextureCollection tc;
00747 tc.find_used_textures(_data);
00748
00749
00750 tc.uniquify_trefs();
00751
00752 typedef pmap<string, TextureReference *> ByTRefName;
00753 ByTRefName by_tref_name;
00754 for (Textures::const_iterator ti = _textures.begin();
00755 ti != _textures.end();
00756 ++ti) {
00757 TextureReference *ref = (*ti);
00758 by_tref_name[ref->get_tref_name()] = ref;
00759 }
00760
00761 EggTextureCollection::iterator eti;
00762 for (eti = tc.begin(); eti != tc.end(); ++eti) {
00763 EggTexture *egg_tex = (*eti);
00764
00765 ByTRefName::const_iterator tni = by_tref_name.find(egg_tex->get_name());
00766 if (tni == by_tref_name.end()) {
00767
00768 nout << _source_filename.get_basename()
00769 << " modified during session--TRef " << egg_tex->get_name()
00770 << " is new!\n";
00771
00772 } else {
00773 TextureReference *ref = (*tni).second;
00774 ref->rebind_egg_data(_data, egg_tex);
00775 }
00776 }
00777 }
00778
00779
00780
00781
00782
00783
00784
00785 void EggFile::
00786 register_with_read_factory() {
00787 BamReader::get_factory()->
00788 register_factory(get_class_type(), make_EggFile);
00789 }
00790
00791
00792
00793
00794
00795
00796
00797
00798 void EggFile::
00799 write_datagram(BamWriter *writer, Datagram &datagram) {
00800 TypedWritable::write_datagram(writer, datagram);
00801 datagram.add_string(get_name());
00802
00803
00804
00805 datagram.add_string(FilenameUnifier::make_bam_filename(_current_directory));
00806 datagram.add_string(FilenameUnifier::make_bam_filename(_source_filename));
00807 datagram.add_string(FilenameUnifier::make_bam_filename(_dest_filename));
00808 datagram.add_string(_egg_comment);
00809
00810 datagram.add_uint32(_textures.size());
00811 Textures::iterator ti;
00812 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00813 writer->write_pointer(datagram, (*ti));
00814 }
00815
00816 _explicitly_assigned_groups.write_datagram(writer, datagram);
00817 writer->write_pointer(datagram, _default_group);
00818
00819
00820
00821
00822 datagram.add_bool(_is_surprise);
00823 datagram.add_bool(_is_stale);
00824 }
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835 int EggFile::
00836 complete_pointers(TypedWritable **p_list, BamReader *manager) {
00837 int pi = TypedWritable::complete_pointers(p_list, manager);
00838
00839 int i;
00840 _textures.reserve(_num_textures);
00841 for (i = 0; i < _num_textures; i++) {
00842 TextureReference *texture;
00843 DCAST_INTO_R(texture, p_list[pi], pi);
00844 _textures.push_back(texture);
00845 pi++;
00846 }
00847
00848 pi += _explicitly_assigned_groups.complete_pointers(p_list + pi, manager);
00849
00850 if (p_list[pi] != (TypedWritable *)NULL) {
00851 DCAST_INTO_R(_default_group, p_list[pi], pi);
00852 }
00853 pi++;
00854
00855 return pi;
00856 }
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866 TypedWritable* EggFile::
00867 make_EggFile(const FactoryParams ¶ms) {
00868 EggFile *me = new EggFile();
00869 DatagramIterator scan;
00870 BamReader *manager;
00871
00872 parse_params(params, scan, manager);
00873 me->fillin(scan, manager);
00874 return me;
00875 }
00876
00877
00878
00879
00880
00881
00882
00883
00884 void EggFile::
00885 fillin(DatagramIterator &scan, BamReader *manager) {
00886 TypedWritable::fillin(scan, manager);
00887 set_name(scan.get_string());
00888 _current_directory = FilenameUnifier::get_bam_filename(scan.get_string());
00889 _source_filename = FilenameUnifier::get_bam_filename(scan.get_string());
00890 _dest_filename = FilenameUnifier::get_bam_filename(scan.get_string());
00891 if (Palettizer::_read_pi_version >= 9) {
00892 _egg_comment = scan.get_string();
00893 }
00894
00895 _num_textures = scan.get_uint32();
00896 manager->read_pointers(scan, _num_textures);
00897
00898 _explicitly_assigned_groups.fillin(scan, manager);
00899 manager->read_pointer(scan);
00900
00901 _is_surprise = scan.get_bool();
00902 _is_stale = scan.get_bool();
00903
00904 if (Palettizer::_read_pi_version < 11) {
00905
00906
00907
00908
00909 _is_stale = true;
00910 }
00911 }