Panda3D
 All Classes Functions Variables Enumerations
eggFile.cxx
1 // Filename: eggFile.cxx
2 // Created by: drose (29Nov00)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "eggFile.h"
16 #include "textureImage.h"
17 #include "paletteGroup.h"
18 #include "texturePlacement.h"
19 #include "textureReference.h"
20 #include "sourceTextureImage.h"
21 #include "palettizer.h"
22 #include "filenameUnifier.h"
23 
24 #include "eggData.h"
25 #include "eggGroup.h"
26 #include "eggTextureCollection.h"
27 #include "eggComment.h"
28 #include "datagram.h"
29 #include "datagramIterator.h"
30 #include "bamReader.h"
31 #include "bamWriter.h"
32 #include "executionEnvironment.h"
33 #include "dSearchPath.h"
34 #include "indirectLess.h"
35 
36 #include <algorithm>
37 
38 TypeHandle EggFile::_type_handle;
39 
40 ////////////////////////////////////////////////////////////////////
41 // Function: EggFile::Constructor
42 // Access: Public
43 // Description:
44 ////////////////////////////////////////////////////////////////////
45 EggFile::
46 EggFile() {
47  _data = (EggData *)NULL;
48  _first_txa_match = false;
49  _default_group = (PaletteGroup *)NULL;
50  _is_surprise = true;
51  _is_stale = true;
52  _had_data = false;
53 }
54 
55 ////////////////////////////////////////////////////////////////////
56 // Function: EggFile::from_command_line
57 // Access: Public
58 // Description: Accepts the information about the egg file as
59 // supplied from the command line. Returns true if the
60 // egg file is valid, false otherwise.
61 ////////////////////////////////////////////////////////////////////
62 bool EggFile::
64  const Filename &source_filename,
65  const Filename &dest_filename,
66  const string &egg_comment) {
67  _data = data;
68  _had_data = true;
69  remove_backstage(_data);
70 
71  // We save the current directory at the time the egg file appeared
72  // on the command line, so that we'll later be able to properly
73  // resolve external references (like textures) that might be
74  // relative to this directory.
75  _current_directory = ExecutionEnvironment::get_cwd();
76  _source_filename = source_filename;
77  _source_filename.make_absolute();
78  _dest_filename = dest_filename;
79  _dest_filename.make_absolute();
80 
81  // We also save the command line that loaded this egg file, so we
82  // can continue to write it as a comment to the beginning of the egg
83  // file, should we need to rewrite it later.
84  _egg_comment = egg_comment;
85 
86  // We save the default PaletteGroup at this point, because the egg
87  // file inherits the default group that was in effect when it was
88  // specified on the command line.
89  _default_group = pal->get_default_group();
90 
91  return true;
92 }
93 
94 ////////////////////////////////////////////////////////////////////
95 // Function: EggFile::get_source_filename
96 // Access: Public
97 // Description: Returns the filename this egg file was read from.
98 ////////////////////////////////////////////////////////////////////
99 const Filename &EggFile::
101  return _source_filename;
102 }
103 
104 
105 ////////////////////////////////////////////////////////////////////
106 // Function: EggFile::scan_textures
107 // Access: Public
108 // Description: Scans the egg file for texture references and updates
109 // the _textures list appropriately. This assumes the
110 // egg file was supplied on the command line and thus
111 // the _data member is available.
112 ////////////////////////////////////////////////////////////////////
113 void EggFile::
115  nassertv(_data != (EggData *)NULL);
116 
117  // Extract the set of textures referenced by this egg file.
119  tc.find_used_textures(_data);
120 
121  // Make sure each tref name is unique within a given file.
122  tc.uniquify_trefs();
123 
124  // Now build up a list of new TextureReference objects that
125  // represent the textures actually used and their uv range, etc.
126  Textures new_textures;
127 
128  EggTextureCollection::iterator eti;
129  for (eti = tc.begin(); eti != tc.end(); ++eti) {
130  EggTexture *egg_tex = (*eti);
131 
133  ref->from_egg(this, _data, egg_tex);
134 
135  if (!ref->has_uvs()) {
136  // This texture isn't *really* referenced. (Usually this
137  // happens if the texture is only referenced by "backstage"
138  // geometry, which we don't care about.)
139  delete ref;
140 
141  } else {
142  new_textures.push_back(ref);
143  }
144  }
145 
146  // Sort the new references into order so we can compare them with
147  // the original references.
148  sort(new_textures.begin(), new_textures.end(),
150 
151  // Sort the original references too. This should already be sorted
152  // from the previous run, but we might as well be neurotic about it.
153  sort(_textures.begin(), _textures.end(),
155 
156  // Now go through and merge the lists.
157  Textures combined_textures;
158  Textures::const_iterator ai = _textures.begin();
159  Textures::const_iterator bi = new_textures.begin();
160 
161  while (ai != _textures.end() && bi != new_textures.end()) {
162  TextureReference *aref = (*ai);
163  TextureReference *bref = (*bi);
164 
165  if ((*aref) < (*bref)) {
166  // Here's a texture reference in the original list, but not in
167  // the new list. Remove it.
168  delete aref;
169  ++ai;
170 
171  } else if ((*bref) < (*aref)) {
172  // Here's a texture reference in the new list, but not in the
173  // original list. Add it.
174  combined_textures.push_back(bref);
175  ++bi;
176 
177  } else { // (*bref) == (*aref)
178  // Here's a texture reference that was in both lists. Compare it.
179  if (aref->is_equivalent(*bref)) {
180  // It hasn't changed substantially, so keep the original
181  // (which still has the placement references from a previous
182  // pass).
183  aref->from_egg_quick(*bref);
184  combined_textures.push_back(aref);
185  delete bref;
186 
187  } else {
188  // It has changed, so drop the original and keep the new one.
189  combined_textures.push_back(bref);
190  delete aref;
191  }
192  ++ai;
193  ++bi;
194  }
195  }
196 
197  while (bi != new_textures.end()) {
198  TextureReference *bref = (*bi);
199  // Here's a texture reference in the new list, but not in the
200  // original list. Add it.
201  combined_textures.push_back(bref);
202  ++bi;
203  }
204 
205  while (ai != _textures.end()) {
206  TextureReference *aref = (*ai);
207  // Here's a texture reference in the original list, but not in
208  // the new list. Remove it.
209  delete aref;
210  ++ai;
211  }
212 
213  _textures.swap(combined_textures);
214 }
215 
216 ////////////////////////////////////////////////////////////////////
217 // Function: EggFile::get_textures
218 // Access: Public
219 // Description: Fills up the indicated set with the set of textures
220 // referenced by this egg file. It is the user's
221 // responsibility to ensure the set is empty before
222 // making this call; otherwise, the new textures will be
223 // appended to the existing set.
224 ////////////////////////////////////////////////////////////////////
225 void EggFile::
227  Textures::const_iterator ti;
228  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
229  result.insert((*ti)->get_texture());
230  }
231 }
232 
233 ////////////////////////////////////////////////////////////////////
234 // Function: EggFile::pre_txa_file
235 // Access: Public
236 // Description: Does some processing prior to scanning the .txa file.
237 ////////////////////////////////////////////////////////////////////
238 void EggFile::
240  _is_surprise = true;
241  _first_txa_match = true;
242 }
243 
244 ////////////////////////////////////////////////////////////////////
245 // Function: EggFile::match_txa_groups
246 // Access: Public
247 // Description: Adds the indicated set of groups, read from the .txa
248 // file, to the set of groups to which the egg file is
249 // assigned.
250 ////////////////////////////////////////////////////////////////////
251 void EggFile::
253  if (_first_txa_match) {
254  // If this is the first line we matched in the .txa file, clear
255  // the set of groups we'd matched from before. We don't clear
256  // until we match a line in the .txa file, because if we don't
257  // match any lines we still want to remember what groups we used
258  // to be assigned to.
259  _explicitly_assigned_groups.clear();
260  _first_txa_match = false;
261  }
262 
263  _explicitly_assigned_groups.make_union(_explicitly_assigned_groups, groups);
264 }
265 
266 ////////////////////////////////////////////////////////////////////
267 // Function: EggFile::post_txa_file
268 // Access: Public
269 // Description: Once the egg file has been matched against all of the
270 // matching lines the .txa file, do whatever adjustment
271 // is necessary.
272 ////////////////////////////////////////////////////////////////////
273 void EggFile::
275 }
276 
277 ////////////////////////////////////////////////////////////////////
278 // Function: EggFile::get_explicit_groups
279 // Access: Public
280 // Description: Returns the set of PaletteGroups that the egg file
281 // has been explicitly assigned to in the .txa file.
282 ////////////////////////////////////////////////////////////////////
285  return _explicitly_assigned_groups;
286 }
287 
288 ////////////////////////////////////////////////////////////////////
289 // Function: EggFile::get_default_group
290 // Access: Public
291 // Description: Returns the PaletteGroup that was specified as the
292 // default group on the command line at the time the egg
293 // file last appeared on the command line.
294 ////////////////////////////////////////////////////////////////////
297  return _default_group;
298 }
299 
300 ////////////////////////////////////////////////////////////////////
301 // Function: EggFile::get_complete_groups
302 // Access: Public
303 // Description: Returns the complete set of PaletteGroups that the
304 // egg file is assigned to. This is the set of all the
305 // groups it is explicitly assigned to, plus all the
306 // groups that these groups depend on.
307 ////////////////////////////////////////////////////////////////////
310  return _complete_groups;
311 }
312 
313 ////////////////////////////////////////////////////////////////////
314 // Function: EggFile::clear_surprise
315 // Access: Public
316 // Description: Removes the 'surprise' flag; this file has been
317 // successfully matched against a line in the .txa file.
318 ////////////////////////////////////////////////////////////////////
319 void EggFile::
321  _is_surprise = false;
322 }
323 
324 ////////////////////////////////////////////////////////////////////
325 // Function: EggFile::is_surprise
326 // Access: Public
327 // Description: Returns true if this particular egg file is a
328 // 'surprise', i.e. it wasn't matched by a line in the
329 // .txa file that didn't include the keyword 'cont'.
330 ////////////////////////////////////////////////////////////////////
331 bool EggFile::
332 is_surprise() const {
333  return _is_surprise;
334 }
335 
336 ////////////////////////////////////////////////////////////////////
337 // Function: EggFile::mark_stale
338 // Access: Public
339 // Description: Marks this particular egg file as stale, meaning that
340 // something has changed, such as the location of a
341 // texture within its palette, which causes the egg file
342 // to need to be regenerated.
343 ////////////////////////////////////////////////////////////////////
344 void EggFile::
346  _is_stale = true;
347 }
348 
349 ////////////////////////////////////////////////////////////////////
350 // Function: EggFile::is_stale
351 // Access: Public
352 // Description: Returns true if the egg file needs to be updated,
353 // i.e. some palettizations have changed affecting it,
354 // or false otherwise.
355 ////////////////////////////////////////////////////////////////////
356 bool EggFile::
357 is_stale() const {
358  return _is_stale;
359 }
360 
361 ////////////////////////////////////////////////////////////////////
362 // Function: EggFile::build_cross_links
363 // Access: Public
364 // Description: Calls TextureImage::note_egg_file() and
365 // SourceTextureImage::increment_egg_count() for each
366 // texture the egg file references, and
367 // PaletteGroup::increment_egg_count() for each palette
368 // group it wants. This sets up some of the back
369 // references to support determining an ideal texture
370 // assignment.
371 ////////////////////////////////////////////////////////////////////
372 void EggFile::
374  if (_explicitly_assigned_groups.empty()) {
375  // If the egg file has been assigned to no groups, we have to
376  // assign it to something.
377  _complete_groups.clear();
378  _complete_groups.insert(_default_group);
379  _complete_groups.make_complete(_complete_groups);
380 
381  } else {
382  _complete_groups.make_complete(_explicitly_assigned_groups);
383  }
384 
385  Textures::const_iterator ti;
386  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
387  TextureReference *reference = (*ti);
388  TextureImage *texture = reference->get_texture();
389  nassertv(texture != (TextureImage *)NULL);
390  texture->note_egg_file(this);
391 
392  // Actually, this may count the same egg file multiple times for a
393  // particular SourceTextureImage, since a given texture may be
394  // referenced multiples times within an egg file. No harm done,
395  // however.
396  reference->get_source()->increment_egg_count();
397  }
398 
399  PaletteGroups::const_iterator gi;
400  for (gi = _complete_groups.begin();
401  gi != _complete_groups.end();
402  ++gi) {
403  (*gi)->increment_egg_count();
404  }
405 }
406 
407 ////////////////////////////////////////////////////////////////////
408 // Function: EggFile::apply_properties_to_source
409 // Access: Public
410 // Description: Calls apply_properties_to_source() for each texture
411 // reference, updating all the referenced source
412 // textures with the complete set of property
413 // information from this egg file.
414 ////////////////////////////////////////////////////////////////////
415 void EggFile::
417  Textures::const_iterator ti;
418  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
419  TextureReference *reference = (*ti);
420  reference->apply_properties_to_source();
421  }
422 }
423 
424 ////////////////////////////////////////////////////////////////////
425 // Function: EggFile::choose_placements
426 // Access: Public
427 // Description: Once all the textures have been assigned to groups
428 // (but before they may actually be placed), chooses a
429 // suitable TexturePlacement for each texture that
430 // appears in the egg file. This will be necessary to
431 // do at some point before writing out the egg file
432 // anyway, and doing it before the textures are placed
433 // allows us to decide what the necessary UV range is
434 // for each to-be-placed texture.
435 ////////////////////////////////////////////////////////////////////
436 void EggFile::
438  Textures::const_iterator ti;
439  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
440  TextureReference *reference = (*ti);
441  TextureImage *texture = reference->get_texture();
442 
443  if (reference->get_placement() != (TexturePlacement *)NULL &&
444  texture->get_groups().count(reference->get_placement()->get_group()) != 0) {
445  // The egg file is already using a TexturePlacement that is
446  // suitable. Don't bother changing it.
447 
448  } else {
449  // We need to select a new TexturePlacement.
450  PaletteGroups groups;
451  groups.make_intersection(get_complete_groups(), texture->get_groups());
452 
453  // Now groups is the set of groups that the egg file requires,
454  // which also happen to include the texture.
455 
456  if (groups.empty()) {
457  // It might be empty if the egg file was assigned only to the
458  // "null" group (since this group is not propagated to the
459  // textures). In this case, choose from the wider set of
460  // groups available to the texture.
461  groups = texture->get_groups();
462  }
463 
464  if (!groups.empty()) {
465  // It doesn't really matter which group in the set we choose, so
466  // we arbitrarily choose the first one.
467  PaletteGroup *group = (*groups.begin());
468 
469  // Now get the TexturePlacement object that corresponds to the
470  // placement of this texture into this group.
471  TexturePlacement *placement = texture->get_placement(group);
472  nassertv(placement != (TexturePlacement *)NULL);
473 
474  reference->set_placement(placement);
475  }
476  }
477  }
478 }
479 
480 ////////////////////////////////////////////////////////////////////
481 // Function: EggFile::has_data
482 // Access: Public
483 // Description: Returns true if the EggData for this EggFile has
484 // been loaded, and not yet released.
485 ////////////////////////////////////////////////////////////////////
486 bool EggFile::
487 has_data() const {
488  return (_data != (EggData *)NULL);
489 }
490 
491 ////////////////////////////////////////////////////////////////////
492 // Function: EggFile::had_data
493 // Access: Public
494 // Description: Returns true if the EggData for this EggFile has ever
495 // been loaded in this session.
496 ////////////////////////////////////////////////////////////////////
497 bool EggFile::
498 had_data() const {
499  return _had_data;
500 }
501 
502 ////////////////////////////////////////////////////////////////////
503 // Function: EggFile::update_egg
504 // Access: Public
505 // Description: Once all textures have been placed appropriately,
506 // updates the egg file with all the information to
507 // reference the new textures.
508 ////////////////////////////////////////////////////////////////////
509 void EggFile::
511  nassertv(_data != (EggData *)NULL);
512 
513  Textures::iterator ti;
514  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
515  TextureReference *reference = (*ti);
516  reference->update_egg();
517  }
518 }
519 
520 ////////////////////////////////////////////////////////////////////
521 // Function: EggFile::remove_egg
522 // Access: Public
523 // Description: Removes this egg file from all things that reference
524 // it, in preparation for removing it from the database.
525 ////////////////////////////////////////////////////////////////////
526 void EggFile::
528  Textures::iterator ti;
529  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
530  TextureReference *reference = (*ti);
531  TexturePlacement *placement = reference->get_placement();
532  placement->remove_egg(reference);
533  }
534 }
535 
536 ////////////////////////////////////////////////////////////////////
537 // Function: EggFile::read_egg
538 // Access: Public
539 // Description: Reads in the egg file from its _source_filename. It
540 // is only valid to call this if it has not already been
541 // read in, e.g. from the command line. Returns true if
542 // successful, false if there is an error.
543 //
544 // This may also be called after a previous call to
545 // release_egg_data(), in order to re-read the same egg
546 // file.
547 ////////////////////////////////////////////////////////////////////
548 bool EggFile::
549 read_egg(bool noabs) {
550  nassertr(_data == (EggData *)NULL, false);
551  nassertr(!_source_filename.empty(), false);
552 
553  Filename user_source_filename =
554  FilenameUnifier::make_user_filename(_source_filename);
555 
556  if (!_source_filename.exists()) {
557  nout << user_source_filename << " does not exist.\n";
558  return false;
559  }
560 
561  PT(EggData) data = new EggData;
562  if (!data->read(_source_filename, user_source_filename)) {
563  // Failure reading.
564  return false;
565  }
566 
567  if (noabs && data->original_had_absolute_pathnames()) {
568  nout << _source_filename.get_basename()
569  << " references textures using absolute pathnames!\n";
570  return false;
571  }
572 
573  // Extract the set of textures referenced by this egg file.
575  tc.find_used_textures(data);
576 
577  // Make sure each tref name is unique within a given file.
578  tc.uniquify_trefs();
579 
580  // Now build up a list of new TextureReference objects that
581  // represent the textures actually used and their uv range, etc.
582  Textures new_textures;
583 
584  // We want to search for filenames based on the egg directory, and
585  // also on our current directory from which we originally loaded the
586  // egg file. This is important because it's possible the egg file
587  // referenced some textures or something relative to that directory.
588  DSearchPath dir;
589  dir.append_directory(_source_filename.get_dirname());
590  dir.append_directory(_current_directory);
591  data->resolve_filenames(dir);
592 
593  // If any relative filenames remain, they are relative to the source
594  // directory, by convention.
595  data->force_filenames(_current_directory);
596 
597  if (!data->load_externals()) {
598  // Failure reading an external.
599  return false;
600  }
601 
602  _data = data;
603  _had_data = true;
604  remove_backstage(_data);
605 
606  // Insert a comment that shows how we first generated the egg file.
607  PT(EggNode) comment = new EggComment("", _egg_comment);
608  _data->insert(_data->begin(), comment);
609 
610  if (!_textures.empty()) {
611  // If we already have textures, assume we're re-reading the file.
612  rescan_textures();
613  }
614 
615  return true;
616 }
617 
618 ////////////////////////////////////////////////////////////////////
619 // Function: EggFile::release_egg_data
620 // Access: Public
621 // Description: Releases the memory that was loaded by a previous
622 // call to read_egg().
623 ////////////////////////////////////////////////////////////////////
624 void EggFile::
626  if (_data != (EggData *)NULL) {
627  _data = NULL;
628  }
629  Textures::iterator ti;
630  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
631  TextureReference *reference = (*ti);
632  reference->release_egg_data();
633  }
634 }
635 
636 ////////////////////////////////////////////////////////////////////
637 // Function: EggFile::write_egg
638 // Access: Public
639 // Description: Writes out the egg file to its _dest_filename.
640 // Returns true if successful, false if there is an
641 // error.
642 ////////////////////////////////////////////////////////////////////
643 bool EggFile::
645  nassertr(_data != (EggData *)NULL, false);
646  nassertr(!_dest_filename.empty(), false);
647 
648  _dest_filename.make_dir();
649  nout << "Writing " << FilenameUnifier::make_user_filename(_dest_filename)
650  << "\n";
651  if (!_data->write_egg(_dest_filename)) {
652  // Some error while writing. Most unusual.
653  _is_stale = true;
654  return false;
655  }
656 
657  _is_stale = false;
658  return true;
659 }
660 
661 ////////////////////////////////////////////////////////////////////
662 // Function: EggFile::write_description
663 // Access: Public
664 // Description: Writes a one-line description of the egg file and its
665 // group assignments to the indicated output stream.
666 ////////////////////////////////////////////////////////////////////
667 void EggFile::
668 write_description(ostream &out, int indent_level) const {
669  indent(out, indent_level) << get_name() << ": ";
670  if (_explicitly_assigned_groups.empty()) {
671  if (_default_group != (PaletteGroup *)NULL) {
672  out << _default_group->get_name();
673  }
674  } else {
675  out << _explicitly_assigned_groups;
676  }
677 
678  if (is_stale()) {
679  out << " (needs update)";
680  }
681  out << "\n";
682 }
683 
684 ////////////////////////////////////////////////////////////////////
685 // Function: EggFile::write_texture_refs
686 // Access: Public
687 // Description: Writes the list of texture references to the
688 // indicated output stream, one per line.
689 ////////////////////////////////////////////////////////////////////
690 void EggFile::
691 write_texture_refs(ostream &out, int indent_level) const {
692  Textures::const_iterator ti;
693  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
694  TextureReference *reference = (*ti);
695  reference->write(out, indent_level);
696  }
697 }
698 
699 ////////////////////////////////////////////////////////////////////
700 // Function: EggFile::remove_backstage
701 // Access: Private
702 // Description: Recursively walks the egg hierarchy and removes any
703 // "backstage" nodes found from the scene graph
704 // completely. These aren't part of the egg scene
705 // anyway, and removing them early helps reduce
706 // confusion.
707 ////////////////////////////////////////////////////////////////////
708 void EggFile::
709 remove_backstage(EggGroupNode *node) {
710  EggGroupNode::iterator ci;
711  ci = node->begin();
712  while (ci != node->end()) {
713  EggNode *child = (*ci);
714  bool remove_child = false;
715 
716  if (child->is_of_type(EggGroup::get_class_type())) {
717  EggGroup *egg_group;
718  DCAST_INTO_V(egg_group, child);
719  remove_child = egg_group->has_object_type("backstage");
720  }
721 
722  if (remove_child) {
723  ci = node->erase(ci);
724  } else {
725  if (child->is_of_type(EggGroupNode::get_class_type())) {
726  // Recurse on children.
727  remove_backstage(DCAST(EggGroupNode, child));
728  }
729  ++ci;
730  }
731  }
732 }
733 
734 ////////////////////////////////////////////////////////////////////
735 // Function: EggFile::rescan_textures
736 // Access: Private
737 // Description: After reloading the egg file for the second time in a
738 // given session, rematches the texture pointers with
739 // the TextureReference objects.
740 ////////////////////////////////////////////////////////////////////
741 void EggFile::
742 rescan_textures() {
743  nassertv(_data != (EggData *)NULL);
744 
745  // Extract the set of textures referenced by this egg file.
747  tc.find_used_textures(_data);
748 
749  // Make sure each tref name is unique within a given file.
750  tc.uniquify_trefs();
751 
752  typedef pmap<string, TextureReference *> ByTRefName;
753  ByTRefName by_tref_name;
754  for (Textures::const_iterator ti = _textures.begin();
755  ti != _textures.end();
756  ++ti) {
757  TextureReference *ref = (*ti);
758  by_tref_name[ref->get_tref_name()] = ref;
759  }
760 
761  EggTextureCollection::iterator eti;
762  for (eti = tc.begin(); eti != tc.end(); ++eti) {
763  EggTexture *egg_tex = (*eti);
764 
765  ByTRefName::const_iterator tni = by_tref_name.find(egg_tex->get_name());
766  if (tni == by_tref_name.end()) {
767  // We didn't find this TRef name last time around!
768  nout << _source_filename.get_basename()
769  << " modified during session--TRef " << egg_tex->get_name()
770  << " is new!\n";
771 
772  } else {
773  TextureReference *ref = (*tni).second;
774  ref->rebind_egg_data(_data, egg_tex);
775  }
776  }
777 }
778 
779 ////////////////////////////////////////////////////////////////////
780 // Function: EggFile::register_with_read_factory
781 // Access: Public, Static
782 // Description: Registers the current object as something that can be
783 // read from a Bam file.
784 ////////////////////////////////////////////////////////////////////
785 void EggFile::
788  register_factory(get_class_type(), make_EggFile);
789 }
790 
791 ////////////////////////////////////////////////////////////////////
792 // Function: EggFile::write_datagram
793 // Access: Public, Virtual
794 // Description: Fills the indicated datagram up with a binary
795 // representation of the current object, in preparation
796 // for writing to a Bam file.
797 ////////////////////////////////////////////////////////////////////
798 void EggFile::
799 write_datagram(BamWriter *writer, Datagram &datagram) {
800  TypedWritable::write_datagram(writer, datagram);
801  datagram.add_string(get_name());
802 
803  // We don't write out _data; that needs to be reread each session.
804 
805  datagram.add_string(FilenameUnifier::make_bam_filename(_current_directory));
806  datagram.add_string(FilenameUnifier::make_bam_filename(_source_filename));
807  datagram.add_string(FilenameUnifier::make_bam_filename(_dest_filename));
808  datagram.add_string(_egg_comment);
809 
810  datagram.add_uint32(_textures.size());
811  Textures::iterator ti;
812  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
813  writer->write_pointer(datagram, (*ti));
814  }
815 
816  _explicitly_assigned_groups.write_datagram(writer, datagram);
817  writer->write_pointer(datagram, _default_group);
818 
819  // We don't write out _complete_groups; that is recomputed each
820  // session.
821 
822  datagram.add_bool(_is_surprise);
823  datagram.add_bool(_is_stale);
824 }
825 
826 ////////////////////////////////////////////////////////////////////
827 // Function: EggFile::complete_pointers
828 // Access: Public, Virtual
829 // Description: Called after the object is otherwise completely read
830 // from a Bam file, this function's job is to store the
831 // pointers that were retrieved from the Bam file for
832 // each pointer object written. The return value is the
833 // number of pointers processed from the list.
834 ////////////////////////////////////////////////////////////////////
835 int EggFile::
837  int pi = TypedWritable::complete_pointers(p_list, manager);
838 
839  int i;
840  _textures.reserve(_num_textures);
841  for (i = 0; i < _num_textures; i++) {
842  TextureReference *texture;
843  DCAST_INTO_R(texture, p_list[pi], pi);
844  _textures.push_back(texture);
845  pi++;
846  }
847 
848  pi += _explicitly_assigned_groups.complete_pointers(p_list + pi, manager);
849 
850  if (p_list[pi] != (TypedWritable *)NULL) {
851  DCAST_INTO_R(_default_group, p_list[pi], pi);
852  }
853  pi++;
854 
855  return pi;
856 }
857 
858 ////////////////////////////////////////////////////////////////////
859 // Function: EggFile::make_EggFile
860 // Access: Protected
861 // Description: This method is called by the BamReader when an object
862 // of this type is encountered in a Bam file; it should
863 // allocate and return a new object with all the data
864 // read.
865 ////////////////////////////////////////////////////////////////////
866 TypedWritable* EggFile::
867 make_EggFile(const FactoryParams &params) {
868  EggFile *me = new EggFile();
869  DatagramIterator scan;
870  BamReader *manager;
871 
872  parse_params(params, scan, manager);
873  me->fillin(scan, manager);
874  return me;
875 }
876 
877 ////////////////////////////////////////////////////////////////////
878 // Function: EggFile::fillin
879 // Access: Protected
880 // Description: Reads the binary data from the given datagram
881 // iterator, which was written by a previous call to
882 // write_datagram().
883 ////////////////////////////////////////////////////////////////////
884 void EggFile::
885 fillin(DatagramIterator &scan, BamReader *manager) {
886  TypedWritable::fillin(scan, manager);
887  set_name(scan.get_string());
888  _current_directory = FilenameUnifier::get_bam_filename(scan.get_string());
889  _source_filename = FilenameUnifier::get_bam_filename(scan.get_string());
890  _dest_filename = FilenameUnifier::get_bam_filename(scan.get_string());
891  if (Palettizer::_read_pi_version >= 9) {
892  _egg_comment = scan.get_string();
893  }
894 
895  _num_textures = scan.get_uint32();
896  manager->read_pointers(scan, _num_textures);
897 
898  _explicitly_assigned_groups.fillin(scan, manager);
899  manager->read_pointer(scan); // _default_group
900 
901  _is_surprise = scan.get_bool();
902  _is_stale = scan.get_bool();
903 
904  if (Palettizer::_read_pi_version < 11) {
905  // If this file was written by a version of egg-palettize prior to
906  // 11, we didn't store the tref names on the texture references.
907  // Since we need that information now, it follows that every egg
908  // file is stale.
909  _is_stale = true;
910  }
911 }
void increment_egg_count()
Increments by one the number of egg files that are known to reference this SourceTextureImage.
void make_intersection(const PaletteGroups &a, const PaletteGroups &b)
Computes the intersection of PaletteGroups a and b, and stores the result in this object...
void from_egg_quick(const TextureReference &other)
Sets up the pointers within the TextureReference to the same egg file pointers indicated by the other...
const PaletteGroups & get_complete_groups() const
Returns the complete set of PaletteGroups that the egg file is assigned to.
Definition: eggFile.cxx:309
static Filename make_bam_filename(Filename filename)
Returns a new filename that&#39;s made relative to the bam file itself, suitable for writing to the bam f...
bool make_dir() const
Creates all the directories in the path to the file specified in the filename, except for the basenam...
Definition: filename.cxx:2730
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Called after the object is otherwise completely read from a Bam file, this function&#39;s job is to store...
void set_placement(TexturePlacement *placement)
Sets the particular TexturePlacement that is appropriate for this egg file.
void uniquify_trefs()
Guarantees that each texture in the collection has a unique TRef name.
This is our own Panda specialization on the default STL map.
Definition: pmap.h:52
void post_txa_file()
Once the egg file has been matched against all of the matching lines the .txa file, do whatever adjustment is necessary.
Definition: eggFile.cxx:274
void update_egg()
Updates the egg file with all the relevant information to reference the texture in its new home...
void apply_properties_to_source()
Applies the texture properties as read from the egg file to the source image&#39;s properties.
bool get_bool()
Extracts a boolean value.
void add_string(const string &str)
Adds a variable-length string to the datagram.
Definition: datagram.I:351
void scan_textures()
Scans the egg file for texture references and updates the _textures list appropriately.
Definition: eggFile.cxx:114
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:122
bool has_data() const
Returns true if the EggData for this EggFile has been loaded, and not yet released.
Definition: eggFile.cxx:487
virtual void write_datagram(BamWriter *writer, Datagram &datagram)
Fills the indicated datagram up with a binary representation of the current object, in preparation for writing to a Bam file.
This is the particular reference of a texture filename by an egg file.
A base class for nodes in the hierarchy that are not leaf nodes.
Definition: eggGroupNode.h:51
A comment that appears in an egg file within a &lt;Comment&gt; entry.
Definition: eggComment.h:27
Defines a texture map that may be applied to geometry.
Definition: eggTexture.h:33
void clear_surprise()
Removes the &#39;surprise&#39; flag; this file has been successfully matched against a line in the ...
Definition: eggFile.cxx:320
void mark_stale()
Marks this particular egg file as stale, meaning that something has changed, such as the location of ...
Definition: eggFile.cxx:345
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:37
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:63
This is the highest level of grouping for TextureImages.
Definition: paletteGroup.h:47
void remove_egg()
Removes this egg file from all things that reference it, in preparation for removing it from the data...
Definition: eggFile.cxx:527
iterator end() const
Returns an iterator suitable for traversing the set.
void pre_txa_file()
Does some processing prior to scanning the .txa file.
Definition: eggFile.cxx:239
bool read_egg(bool noabs)
Reads in the egg file from its _source_filename.
Definition: eggFile.cxx:549
void fillin(DatagramIterator &scan, BamReader *manager)
Reads the binary data from the given datagram iterator, which was written by a previous call to write...
void clear()
Empties the set.
This is a collection of textures by TRef name.
bool empty() const
Returns true if the set is empty, false otherwise.
SourceTextureImage * get_source() const
Returns the SourceTextureImage that this object refers to.
void get_textures(pset< TextureImage * > &result) const
Fills up the indicated set with the set of textures referenced by this egg file.
Definition: eggFile.cxx:226
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:73
string get_dirname() const
Returns the directory part of the filename.
Definition: filename.I:424
void append_directory(const Filename &directory)
Adds a new directory to the end of the search list.
void apply_properties_to_source()
Calls apply_properties_to_source() for each texture reference, updating all the referenced source tex...
Definition: eggFile.cxx:416
This is the primary interface into all the egg data, and the root of the egg file structure...
Definition: eggData.h:41
PN_uint32 get_uint32()
Extracts an unsigned 32-bit integer.
bool had_data() const
Returns true if the EggData for this EggFile has ever been loaded in this session.
Definition: eggFile.cxx:498
string get_string()
Extracts a variable-length string.
virtual void fillin(DatagramIterator &scan, BamReader *manager)
This internal function is intended to be called by each class&#39;s make_from_bam() method to read in all...
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
void note_egg_file(EggFile *egg_file)
Records that a particular egg file references this texture.
An STL function object class, this is intended to be used on any ordered collection of pointers to cl...
Definition: indirectLess.h:28
void choose_placements()
Once all the textures have been assigned to groups (but before they may actually be placed)...
Definition: eggFile.cxx:437
TexturePlacement * get_placement(PaletteGroup *group) const
Gets the TexturePlacement object which represents the assignment of this texture to the indicated gro...
void release_egg_data()
Releases the memory that was loaded by a previous call to read_egg().
Definition: eggFile.cxx:625
The main glue of the egg hierarchy, this corresponds to the &lt;Group&gt;, &lt;Instance&gt;, and &lt;Joint&gt; type nod...
Definition: eggGroup.h:36
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition: datagram.I:118
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Called after the object is otherwise completely read from a Bam file, this function&#39;s job is to store...
Definition: eggFile.cxx:836
bool is_equivalent(const TextureReference &other) const
Returns true if all essential properties of this TextureReference are the same as that of the other...
static Filename make_user_filename(Filename filename)
Returns a new filename that&#39;s made relative to the current directory, suitable for reporting to the u...
void match_txa_groups(const PaletteGroups &groups)
Adds the indicated set of groups, read from the .txa file, to the set of groups to which the egg file...
Definition: eggFile.cxx:252
bool write_egg()
Writes out the egg file to its _dest_filename.
Definition: eggFile.cxx:644
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Receives an array of pointers, one for each time manager-&gt;read_pointer() was called in fillin()...
void write_texture_refs(ostream &out, int indent_level=0) const
Writes the list of texture references to the indicated output stream, one per line.
Definition: eggFile.cxx:691
void update_egg()
Once all textures have been placed appropriately, updates the egg file with all the information to re...
Definition: eggFile.cxx:510
void read_pointers(DatagramIterator &scan, int count)
A convenience function to read a contiguous list of pointers.
Definition: bamReader.cxx:694
void rebind_egg_data(EggData *data, EggTexture *egg_tex)
After an EggData has previously been released via release_egg_data(), this can be called to indicate ...
static Filename get_bam_filename(Filename filename)
Returns an absolute pathname based on the given relative pathname, presumably read from the bam file ...
static void register_with_read_factory()
Registers the current object as something that can be read from a Bam file.
Definition: eggFile.cxx:786
TextureImage * get_texture() const
Returns the TextureImage that this object refers to.
bool is_surprise() const
Returns true if this particular egg file is a &#39;surprise&#39;, i.e.
Definition: eggFile.cxx:332
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:40
const PaletteGroups & get_explicit_groups() const
Returns the set of PaletteGroups that the egg file has been explicitly assigned to in the ...
Definition: eggFile.cxx:284
PaletteGroup * get_default_group() const
Returns the PaletteGroup that was specified as the default group on the command line at the time the ...
Definition: eggFile.cxx:296
This corresponds to a particular assignment of a TextureImage with a PaletteGroup, and specifically describes which PaletteImage (if any), and where on the PaletteImage, the TextureImage has been assigned to.
void from_egg(EggFile *egg_file, EggData *data, EggTexture *egg_tex)
Sets up the TextureReference using information extracted from an egg file.
const PaletteGroups & get_groups() const
Once assign_groups() has been called, this returns the actual set of groups the TextureImage has been...
int find_used_textures(EggNode *node)
Walks the egg hierarchy beginning at the indicated node, looking for textures that are referenced by ...
bool from_command_line(EggData *data, const Filename &source_filename, const Filename &dest_filename, const string &egg_comment)
Accepts the information about the egg file as supplied from the command line.
Definition: eggFile.cxx:63
bool exists() const
Returns true if the filename exists on the disk, false otherwise.
Definition: filename.cxx:1356
PaletteGroup * get_group() const
Returns the group that this placement represents.
bool has_object_type(const string &object_type) const
Returns true if the indicated object type has been added to the group, or false otherwise.
Definition: eggGroup.cxx:157
const string & get_tref_name() const
Returns the name of the EggTexture entry that references this texture.
void make_complete(const PaletteGroups &a)
Completes the set with the transitive closure of all dependencies: for each PaletteGroup already in t...
void make_absolute()
Converts the filename to a fully-qualified pathname from the root (if it is a relative pathname)...
Definition: filename.cxx:1019
void make_union(const PaletteGroups &a, const PaletteGroups &b)
Computes the union of PaletteGroups a and b, and stores the result in this object.
string get_basename() const
Returns the basename part of the filename.
Definition: filename.I:436
void remove_egg(TextureReference *reference)
Notes that a particular egg file is no longer using this particular TexturePlacement.
void insert(PaletteGroup *group)
Inserts a new group to the set, if it is not already there.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:213
virtual void write_datagram(BamWriter *writer, Datagram &datagram)
Fills the indicated datagram up with a binary representation of the current object, in preparation for writing to a Bam file.
Definition: eggFile.cxx:799
void add_uint32(PN_uint32 value)
Adds an unsigned 32-bit integer to the datagram.
Definition: datagram.I:192
A set of PaletteGroups.
Definition: paletteGroups.h:31
A base class for things that may be directly added into the egg hierarchy.
Definition: eggNode.h:38
This class stores a list of directories that can be searched, in order, to locate a particular file...
Definition: dSearchPath.h:32
static Filename get_cwd()
Returns the name of the current working directory.
PaletteGroup * get_default_group()
Returns the default group to which an egg file should be assigned if it is not mentioned in the ...
Definition: palettizer.cxx:884
const Filename & get_source_filename() const
Returns the filename this egg file was read from.
Definition: eggFile.cxx:100
A class to retrieve the individual data elements previously stored in a Datagram. ...
This represents a single source texture that is referenced by one or more egg files.
Definition: textureImage.h:51
void build_cross_links()
Calls TextureImage::note_egg_file() and SourceTextureImage::increment_egg_count() for each texture th...
Definition: eggFile.cxx:373
size_type count(PaletteGroup *group) const
Returns the number of times the given group appears in the set.
void write_description(ostream &out, int indent_level=0) const
Writes a one-line description of the egg file and its group assignments to the indicated output strea...
Definition: eggFile.cxx:668
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:43
bool is_stale() const
Returns true if the egg file needs to be updated, i.e.
Definition: eggFile.cxx:357
bool has_uvs() const
Returns true if this TextureReference actually uses the texture on geometry, with UV&#39;s and everything...
void release_egg_data()
Called to indicate that the EggData previously passed to from_egg() is about to be deallocated...
This represents a single egg file known to the palettizer.
Definition: eggFile.h:39
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
Definition: bamWriter.cxx:279
void read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:652
TexturePlacement * get_placement() const
Returns the particular TexturePlacement that is appropriate for this egg file.
iterator begin() const
Returns an iterator suitable for traversing the set.