Panda3D
 All Classes Functions Variables Enumerations
palettizer.cxx
1 // Filename: palettizer.cxx
2 // Created by: drose (01Dec00)
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 "palettizer.h"
16 #include "eggFile.h"
17 #include "textureImage.h"
18 #include "pal_string_utils.h"
19 #include "paletteGroup.h"
20 #include "filenameUnifier.h"
21 #include "textureMemoryCounter.h"
22 
23 #include "pnmImage.h"
24 #include "pnmFileTypeRegistry.h"
25 #include "pnmFileType.h"
26 #include "eggData.h"
27 #include "datagram.h"
28 #include "datagramIterator.h"
29 #include "bamReader.h"
30 #include "bamWriter.h"
31 #include "indent.h"
32 
33 Palettizer *pal = (Palettizer *)NULL;
34 
35 // This number is written out as the first number to the pi file, to
36 // indicate the version of egg-palettize that wrote it out. This
37 // allows us to easily update egg-palettize to write out additional
38 // information to its pi file, without having it increment the bam
39 // version number for all bam and boo files anywhere in the world.
40 int Palettizer::_pi_version = 20;
41 // Updated to version 8 on 3/20/03 to remove extensions from texture key names.
42 // Updated to version 9 on 4/13/03 to add a few properties in various places.
43 // Updated to version 10 on 4/15/03 to add _alpha_file_channel.
44 // Updated to version 11 on 4/30/03 to add TextureReference::_tref_name.
45 // Updated to version 12 on 9/11/03 to add _generated_image_pattern.
46 // Updated to version 13 on 9/13/03 to add _keep_format and _background.
47 // Updated to version 14 on 7/26/05 to add _omit_everything.
48 // Updated to version 15 on 8/01/05 to make TextureImages be case-insensitive.
49 // Updated to version 16 on 4/03/06 to add Palettizer::_cutout_mode et al.
50 // Updated to version 17 on 3/02/07 to add TextureImage::_txa_wrap_u etc.
51 // Updated to version 18 on 5/13/08 to add TextureProperties::_quality_level.
52 // Updated to version 19 on 7/16/09 to add PaletteGroup::_override_margin
53 // Updated to version 20 on 7/27/09 to add TexturePlacement::_swapTextures
54 
55 int Palettizer::_min_pi_version = 8;
56 // Dropped support for versions 7 and below on 7/14/03.
57 
58 int Palettizer::_read_pi_version = 0;
59 
60 TypeHandle Palettizer::_type_handle;
61 
62 ostream &operator << (ostream &out, Palettizer::RemapUV remap) {
63  switch (remap) {
64  case Palettizer::RU_never:
65  return out << "never";
66 
67  case Palettizer::RU_group:
68  return out << "per group";
69 
70  case Palettizer::RU_poly:
71  return out << "per polygon";
72 
73  case Palettizer::RU_invalid:
74  return out << "(invalid)";
75  }
76 
77  return out << "**invalid**(" << (int)remap << ")";
78 }
79 
80 
81 // This STL function object is used in report_statistics(), below.
83 public:
84  bool operator ()(PaletteGroup *a, PaletteGroup *b) {
85  if (a->get_dependency_order() != b->get_dependency_order()) {
86  return a->get_dependency_order() < b->get_dependency_order();
87  }
88  return a->get_name() < b->get_name();
89  }
90 };
91 
92 // And this one is used in report_pi().
94 public:
95  bool operator ()(PaletteGroup *a, PaletteGroup *b) {
96  return !a->is_preferred_over(*b);
97  }
98 };
99 
100 ////////////////////////////////////////////////////////////////////
101 // Function: Palettizer::Constructor
102 // Access: Public
103 // Description:
104 ////////////////////////////////////////////////////////////////////
105 Palettizer::
106 Palettizer() {
107  _is_valid = true;
108  _noabs = false;
109 
110  _generated_image_pattern = "%g_palette_%p_%i";
111  _map_dirname = "%g";
112  _shadow_dirname = "shadow";
113  _margin = 2;
114  _omit_solitary = false;
115  _omit_everything = false;
116  _coverage_threshold = 2.5;
117  _aggressively_clean_mapdir = true;
118  _force_power_2 = true;
120  _alpha_type = (PNMFileType *)NULL;
121  _shadow_color_type = (PNMFileType *)NULL;
122  _shadow_alpha_type = (PNMFileType *)NULL;
123  _pal_x_size = _pal_y_size = 512;
124  _background.set(0.0, 0.0, 0.0, 0.0);
125  _cutout_mode = EggRenderMode::AM_dual;
126  _cutout_ratio = 0.3;
127 
128  _round_uvs = true;
129  _round_unit = 0.1;
130  _round_fuzz = 0.01;
131  _remap_uv = RU_poly;
132  _remap_char_uv = RU_poly;
133 
134  get_palette_group("null");
135 }
136 
137 ////////////////////////////////////////////////////////////////////
138 // Function: Palettizer::get_noabs
139 // Access: Public
140 // Description: Returns the current setting of the noabs flag. See
141 // set_noabs().
142 ////////////////////////////////////////////////////////////////////
143 bool Palettizer::
144 get_noabs() const {
145  return _noabs;
146 }
147 
148 ////////////////////////////////////////////////////////////////////
149 // Function: Palettizer::set_noabs
150 // Access: Public
151 // Description: Changes the current setting of the noabs flag.
152 //
153 // If this flag is true, then it is an error to process
154 // an egg file that contains absolute pathname
155 // references. This flag is intended to help detect egg
156 // files that are incorrectly built within a model tree
157 // (which should use entirely relative pathnames).
158 //
159 // This flag must be set before any egg files are
160 // processed.
161 ////////////////////////////////////////////////////////////////////
162 void Palettizer::
163 set_noabs(bool noabs) {
164  _noabs = noabs;
165 }
166 
167 ////////////////////////////////////////////////////////////////////
168 // Function: Palettizer::is_valid
169 // Access: Public
170 // Description: Returns true if the palette information file was read
171 // correctly, or false if there was some error and the
172 // palettization can't continue.
173 ////////////////////////////////////////////////////////////////////
174 bool Palettizer::
175 is_valid() const {
176  return _is_valid;
177 }
178 
179 ////////////////////////////////////////////////////////////////////
180 // Function: Palettizer::report_pi
181 // Access: Public
182 // Description: Output a verbose description of all the palettization
183 // information to standard output, for the user's
184 // perusal.
185 ////////////////////////////////////////////////////////////////////
186 void Palettizer::
187 report_pi() const {
188  // Start out with the cross links and back counts; some of these are
189  // nice to report.
190  EggFiles::const_iterator efi;
191  for (efi = _egg_files.begin(); efi != _egg_files.end(); ++efi) {
192  (*efi).second->build_cross_links();
193  }
194 
195  cout
196  << "\nparams\n"
197  << " generated image pattern: " << _generated_image_pattern << "\n"
198  << " map directory: " << _map_dirname << "\n"
199  << " shadow directory: "
200  << FilenameUnifier::make_user_filename(_shadow_dirname) << "\n"
201  << " egg relative directory: "
202  << FilenameUnifier::make_user_filename(_rel_dirname) << "\n"
203  << " palettize size: " << _pal_x_size << " by " << _pal_y_size << "\n"
204  << " background: " << _background << "\n"
205  << " margin: " << _margin << "\n"
206  << " coverage threshold: " << _coverage_threshold << "\n"
207  << " force textures to power of 2: " << yesno(_force_power_2) << "\n"
208  << " aggressively clean the map directory: "
209  << yesno(_aggressively_clean_mapdir) << "\n"
210  << " omit everything: " << yesno(_omit_everything) << "\n"
211  << " round UV area: " << yesno(_round_uvs) << "\n";
212  if (_round_uvs) {
213  cout << " round UV area to nearest " << _round_unit << " with fuzz "
214  << _round_fuzz << "\n";
215  }
216  cout << " remap UV's: " << _remap_uv << "\n"
217  << " remap UV's for characters: " << _remap_char_uv << "\n";
218  cout << " alpha cutouts: " << _cutout_mode << " " << _cutout_ratio << "\n";
219 
220  if (_color_type != (PNMFileType *)NULL) {
221  cout << " generate image files of type: "
222  << _color_type->get_suggested_extension();
223  if (_alpha_type != (PNMFileType *)NULL) {
224  cout << "," << _alpha_type->get_suggested_extension();
225  }
226  cout << "\n";
227  }
228 
229  if (_shadow_color_type != (PNMFileType *)NULL) {
230  cout << " generate shadow palette files of type: "
231  << _shadow_color_type->get_suggested_extension();
232  if (_shadow_alpha_type != (PNMFileType *)NULL) {
233  cout << "," << _shadow_alpha_type->get_suggested_extension();
234  }
235  cout << "\n";
236  }
237 
238  cout << "\ntexture source pathnames and assignments\n";
239  Textures::const_iterator ti;
240  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
241  TextureImage *texture = (*ti).second;
242  if (texture->is_used()) {
243  cout << " " << texture->get_name() << ":\n";
244  texture->write_source_pathnames(cout, 4);
245  }
246  }
247 
248  cout << "\negg files and textures referenced\n";
249  EggFiles::const_iterator ei;
250  for (ei = _egg_files.begin(); ei != _egg_files.end(); ++ei) {
251  EggFile *egg_file = (*ei).second;
252  egg_file->write_description(cout, 2);
253  egg_file->write_texture_refs(cout, 4);
254  }
255 
256  // Sort the palette groups into order of preference, so that the
257  // more specific ones appear at the bottom.
258  pvector<PaletteGroup *> sorted_groups;
259  Groups::const_iterator gi;
260  for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
261  sorted_groups.push_back((*gi).second);
262  }
263  sort(sorted_groups.begin(), sorted_groups.end(),
265 
266  cout << "\npalette groups\n";
268  for (si = sorted_groups.begin(); si != sorted_groups.end(); ++si) {
269  PaletteGroup *group = (*si);
270  if (si != sorted_groups.begin()) {
271  cout << "\n";
272  }
273  cout << " " << group->get_name()
274  // << " (" << group->get_dirname_order() << "," << group->get_dependency_order() << ")"
275  << ": " << group->get_groups() << "\n";
276  group->write_image_info(cout, 4);
277  }
278 
279  cout << "\ntextures\n";
280  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
281  TextureImage *texture = (*ti).second;
282  texture->write_scale_info(cout, 2);
283  }
284 
285  cout << "\nsurprises\n";
286  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
287  TextureImage *texture = (*ti).second;
288  if (texture->is_surprise()) {
289  cout << " " << texture->get_name() << "\n";
290  }
291  }
292  for (ei = _egg_files.begin(); ei != _egg_files.end(); ++ei) {
293  EggFile *egg_file = (*ei).second;
294  if (egg_file->is_surprise()) {
295  cout << " " << egg_file->get_name() << "\n";
296  }
297  }
298 
299  cout << "\n";
300 }
301 
302 ////////////////////////////////////////////////////////////////////
303 // Function: Palettizer::report_statistics
304 // Access: Public
305 // Description: Output a report of the palettization effectiveness,
306 // texture memory utilization, and so on.
307 ////////////////////////////////////////////////////////////////////
308 void Palettizer::
310  // Sort the groups into order by dependency order, for the user's
311  // convenience.
312  pvector<PaletteGroup *> sorted_groups;
313 
314  Groups::const_iterator gi;
315  for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
316  sorted_groups.push_back((*gi).second);
317  }
318 
319  sort(sorted_groups.begin(), sorted_groups.end(),
321 
322  Placements overall_placements;
323 
325  for (si = sorted_groups.begin();
326  si != sorted_groups.end();
327  ++si) {
328  PaletteGroup *group = (*si);
329 
330  Placements placements;
331  group->get_placements(placements);
332  if (!placements.empty()) {
333  group->get_placements(overall_placements);
334 
335  cout << "\n" << group->get_name() << ", by itself:\n";
336  compute_statistics(cout, 2, placements);
337 
338  PaletteGroups complete;
339  complete.make_complete(group->get_groups());
340 
341  if (complete.size() > 1) {
342  Placements complete_placements;
343  group->get_complete_placements(complete_placements);
344  if (complete_placements.size() != placements.size()) {
345  cout << "\n" << group->get_name()
346  << ", with dependents (" << complete << "):\n";
347  compute_statistics(cout, 2, complete_placements);
348  }
349  }
350  }
351  }
352 
353  cout << "\nOverall:\n";
354  compute_statistics(cout, 2, overall_placements);
355 
356  cout << "\n";
357 }
358 
359 
360 ////////////////////////////////////////////////////////////////////
361 // Function: Palettizer::read_txa_file
362 // Access: Public
363 // Description: Reads in the .txa file and keeps it ready for
364 // matching textures and egg files.
365 ////////////////////////////////////////////////////////////////////
366 void Palettizer::
367 read_txa_file(istream &txa_file, const string &txa_filename) {
368  // Clear out the group dependencies, in preparation for reading them
369  // again from the .txa file.
370  Groups::iterator gi;
371  for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
372  PaletteGroup *group = (*gi).second;
373  group->clear_depends();
374  group->set_dirname("");
375  }
376 
377  // Also reset _shadow_color_type.
378  _shadow_color_type = (PNMFileType *)NULL;
379  _shadow_alpha_type = (PNMFileType *)NULL;
380 
381  if (!_txa_file.read(txa_file, txa_filename)) {
382  exit(1);
383  }
384 
385  if (_color_type == (PNMFileType *)NULL) {
386  nout << "No valid output image file type available; cannot run.\n"
387  << "Use :imagetype command in .txa file.\n";
388  exit(1);
389  }
390 
391  // Compute the correct dependency level and order for each group.
392  // This will help us when we assign the textures to their groups.
393  for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
394  PaletteGroup *group = (*gi).second;
395  group->reset_dependency_level();
396  }
397 
398  for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
399  PaletteGroup *group = (*gi).second;
400  group->set_dependency_level(1);
401  }
402 
403  bool any_changed;
404  do {
405  any_changed = false;
406  for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
407  PaletteGroup *group = (*gi).second;
408  if (group->set_dependency_order()) {
409  any_changed = true;
410  }
411  }
412  } while (any_changed);
413 }
414 
415 ////////////////////////////////////////////////////////////////////
416 // Function: Palettizer::all_params_set
417 // Access: Public
418 // Description: Called after all command line parameters have been
419 // set up, this is a hook to do whatever initialization
420 // is necessary.
421 ////////////////////////////////////////////////////////////////////
422 void Palettizer::
424  // Make sure the palettes have their shadow images set up properly.
425  Groups::iterator gi;
426  for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
427  PaletteGroup *group = (*gi).second;
428  group->setup_shadow_images();
429  }
430 }
431 
432 ////////////////////////////////////////////////////////////////////
433 // Function: Palettizer::process_command_line_eggs
434 // Access: Public
435 // Description: Processes all the textures named in the
436 // _command_line_eggs, placing them on the appropriate
437 // palettes or whatever needs to be done with them.
438 //
439 // If force_texture_read is true, it forces each texture
440 // image file to be read (and thus legitimately checked
441 // for grayscaleness etc.) before placing.
442 ////////////////////////////////////////////////////////////////////
443 void Palettizer::
444 process_command_line_eggs(bool force_texture_read, const Filename &state_filename) {
445  _command_line_textures.clear();
446 
447  // Start by scanning all the egg files we read up on the command
448  // line.
449  CommandLineEggs::const_iterator ei;
450  for (ei = _command_line_eggs.begin();
451  ei != _command_line_eggs.end();
452  ++ei) {
453  EggFile *egg_file = (*ei);
454 
455  egg_file->scan_textures();
456  egg_file->get_textures(_command_line_textures);
457 
458  egg_file->pre_txa_file();
459  _txa_file.match_egg(egg_file);
460  egg_file->post_txa_file();
461  }
462 
463  // Now that all of our egg files are read in, build in all the cross
464  // links and back pointers and stuff.
465  EggFiles::const_iterator efi;
466  for (efi = _egg_files.begin(); efi != _egg_files.end(); ++efi) {
467  (*efi).second->build_cross_links();
468  }
469 
470  // Now match each of the textures mentioned in those egg files
471  // against a line in the .txa file.
472  CommandLineTextures::iterator ti;
473  for (ti = _command_line_textures.begin();
474  ti != _command_line_textures.end();
475  ++ti) {
476  TextureImage *texture = *ti;
477 
478  if (force_texture_read || texture->is_newer_than(state_filename)) {
479  // If we're forcing a redo, or the texture image has changed,
480  // re-read the complete image.
481  texture->read_source_image();
482  } else {
483  // Otherwise, just the header is sufficient.
484  texture->read_header();
485  }
486 
487  texture->mark_texture_named();
488  texture->pre_txa_file();
489  _txa_file.match_texture(texture);
490  texture->post_txa_file();
491  }
492 
493  // And now, assign each of the current set of textures to an
494  // appropriate group or groups.
495  for (ti = _command_line_textures.begin();
496  ti != _command_line_textures.end();
497  ++ti) {
498  TextureImage *texture = *ti;
499  texture->assign_groups();
500  }
501 
502  // And then the egg files need to sign up for a particular
503  // TexturePlacement, so we can determine some more properties about
504  // how the textures are placed (for instance, how big the UV range
505  // is for a particular TexturePlacement).
506  for (efi = _egg_files.begin(); efi != _egg_files.end(); ++efi) {
507  (*efi).second->choose_placements();
508  }
509 
510  // Now that *that's* done, we need to make sure the various
511  // TexturePlacements require the right size for their textures.
512  for (ti = _command_line_textures.begin();
513  ti != _command_line_textures.end();
514  ++ti) {
515  TextureImage *texture = *ti;
516  texture->determine_placement_size();
517  }
518 
519  // Now that each texture has been assigned to a suitable group,
520  // make sure the textures are placed on specific PaletteImages.
521  Groups::iterator gi;
522  for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
523  PaletteGroup *group = (*gi).second;
524  group->update_unknown_textures(_txa_file);
525  group->place_all();
526  }
527 }
528 
529 ////////////////////////////////////////////////////////////////////
530 // Function: Palettizer::process_all
531 // Access: Public
532 // Description: Reprocesses all textures known.
533 //
534 // If force_texture_read is true, it forces each texture
535 // image file to be read (and thus legitimately checked
536 // for grayscaleness etc.) before placing.
537 ////////////////////////////////////////////////////////////////////
538 void Palettizer::
539 process_all(bool force_texture_read, const Filename &state_filename) {
540  // First, clear all the basic properties on the source texture
541  // images, so we can reapply them from the complete set of egg files
542  // and thereby ensure they are up-to-date.
543  Textures::iterator ti;
544  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
545  TextureImage *texture = (*ti).second;
547  }
548 
549  // If there *were* any egg files on the command line, deal with
550  // them.
551  CommandLineEggs::const_iterator ei;
552  for (ei = _command_line_eggs.begin();
553  ei != _command_line_eggs.end();
554  ++ei) {
555  EggFile *egg_file = (*ei);
556 
557  egg_file->scan_textures();
558  egg_file->get_textures(_command_line_textures);
559  }
560 
561  // Then match up all the egg files we know about with the .txa file.
562  EggFiles::const_iterator efi;
563  for (efi = _egg_files.begin(); efi != _egg_files.end(); ++efi) {
564  EggFile *egg_file = (*efi).second;
565  egg_file->pre_txa_file();
566  _txa_file.match_egg(egg_file);
567  egg_file->post_txa_file();
568  }
569 
570  // Now that all of our egg files are read in, build in all the cross
571  // links and back pointers and stuff.
572  for (efi = _egg_files.begin(); efi != _egg_files.end(); ++efi) {
573  (*efi).second->build_cross_links();
574 
575  // Also make sure each egg file's properties are applied to the
576  // source image (since we reset all the source image properties,
577  // above).
578  (*efi).second->apply_properties_to_source();
579  }
580 
581  // Now match each of the textures in the world against a line in the
582  // .txa file.
583  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
584  TextureImage *texture = (*ti).second;
585  if (force_texture_read || texture->is_newer_than(state_filename)) {
586  texture->read_source_image();
587  }
588 
589  texture->mark_texture_named();
590  texture->pre_txa_file();
591  _txa_file.match_texture(texture);
592  texture->post_txa_file();
593 
594  // We need to do this to avoid bloating memory.
595  texture->release_source_image();
596  }
597 
598  // And now, assign each texture to an appropriate group or groups.
599  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
600  TextureImage *texture = (*ti).second;
601  texture->assign_groups();
602  }
603 
604  // And then the egg files need to sign up for a particular
605  // TexturePlacement, so we can determine some more properties about
606  // how the textures are placed (for instance, how big the UV range
607  // is for a particular TexturePlacement).
608  for (efi = _egg_files.begin(); efi != _egg_files.end(); ++efi) {
609  (*efi).second->choose_placements();
610  }
611 
612  // Now that *that's* done, we need to make sure the various
613  // TexturePlacements require the right size for their textures.
614  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
615  TextureImage *texture = (*ti).second;
616  texture->determine_placement_size();
617  }
618 
619  // Now that each texture has been assigned to a suitable group,
620  // make sure the textures are placed on specific PaletteImages.
621  Groups::iterator gi;
622  for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
623  PaletteGroup *group = (*gi).second;
624  group->update_unknown_textures(_txa_file);
625  group->place_all();
626  }
627 }
628 
629 ////////////////////////////////////////////////////////////////////
630 // Function: Palettizer::optimal_resize
631 // Access: Public
632 // Description: Attempts to resize each PalettteImage down to its
633 // smallest possible size.
634 ////////////////////////////////////////////////////////////////////
635 void Palettizer::
637  Groups::iterator gi;
638  for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
639  PaletteGroup *group = (*gi).second;
640  group->optimal_resize();
641  }
642 }
643 
644 ////////////////////////////////////////////////////////////////////
645 // Function: Palettizer::reset_images
646 // Access: Public
647 // Description: Throws away all of the current PaletteImages, so that
648 // new ones may be created (and the packing made more
649 // optimal).
650 ////////////////////////////////////////////////////////////////////
651 void Palettizer::
653  Groups::iterator gi;
654  for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
655  PaletteGroup *group = (*gi).second;
656  group->reset_images();
657  }
658 }
659 
660 ////////////////////////////////////////////////////////////////////
661 // Function: Palettizer::generate_images
662 // Access: Public
663 // Description: Actually generates the appropriate palette and
664 // unplaced texture images into the map directories. If
665 // redo_all is true, this forces a regeneration of each
666 // image file.
667 ////////////////////////////////////////////////////////////////////
668 void Palettizer::
669 generate_images(bool redo_all) {
670  Groups::iterator gi;
671  for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
672  PaletteGroup *group = (*gi).second;
673  group->update_images(redo_all);
674  }
675 
676  Textures::iterator ti;
677  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
678  TextureImage *texture = (*ti).second;
679  texture->copy_unplaced(redo_all);
680  }
681 }
682 
683 ////////////////////////////////////////////////////////////////////
684 // Function: Palettizer::read_stale_eggs
685 // Access: Public
686 // Description: Reads in any egg file that is known to be stale, even
687 // if it was not listed on the command line, so that it
688 // may be updated and written out when write_eggs() is
689 // called. If redo_all is true, this even reads egg
690 // files that were not flagged as stale.
691 //
692 // Returns true if successful, or false if there was
693 // some error.
694 ////////////////////////////////////////////////////////////////////
695 bool Palettizer::
696 read_stale_eggs(bool redo_all) {
697  bool okflag = true;
698 
699  pvector<EggFiles::iterator> invalid_eggs;
700 
701  EggFiles::iterator ei;
702  for (ei = _egg_files.begin(); ei != _egg_files.end(); ++ei) {
703  EggFile *egg_file = (*ei).second;
704  if (!egg_file->had_data() &&
705  (egg_file->is_stale() || redo_all)) {
706  if (!egg_file->read_egg(_noabs)) {
707  invalid_eggs.push_back(ei);
708 
709  } else {
710  egg_file->scan_textures();
711  egg_file->choose_placements();
712  egg_file->release_egg_data();
713  }
714  }
715  }
716 
717  // Now eliminate all the invalid egg files.
719  for (ii = invalid_eggs.begin(); ii != invalid_eggs.end(); ++ii) {
720  EggFiles::iterator ei = (*ii);
721  EggFile *egg_file = (*ei).second;
722  if (egg_file->get_source_filename().exists()) {
723  // If there is an invalid egg file, remove it; hopefully it will
724  // get rebuilt properly next time.
725  nout << "Removing invalid egg file: "
727  << "\n";
728 
729  egg_file->get_source_filename().unlink();
730  okflag = false;
731 
732  } else {
733  // If the egg file is simply missing, quietly remove any record
734  // of it from the database.
735  egg_file->remove_egg();
736  _egg_files.erase(ei);
737  }
738  }
739 
740  if (!okflag) {
741  nout << "\n"
742  << "Some errors in egg files encountered.\n"
743  << "Re-run make install or make opt-pal to try to regenerate these.\n\n";
744  }
745 
746  return okflag;
747 }
748 
749 ////////////////////////////////////////////////////////////////////
750 // Function: Palettizer::write_eggs
751 // Access: Public
752 // Description: Adjusts the egg files to reference the newly
753 // generated textures, and writes them out. Returns
754 // true if successful, or false if there was some error.
755 ////////////////////////////////////////////////////////////////////
756 bool Palettizer::
758  bool okflag = true;
759 
760  EggFiles::iterator ei;
761  for (ei = _egg_files.begin(); ei != _egg_files.end(); ++ei) {
762  EggFile *egg_file = (*ei).second;
763  if (egg_file->had_data()) {
764  if (!egg_file->has_data()) {
765  // Re-read the egg file.
766  bool read_ok = egg_file->read_egg(_noabs);
767  if (!read_ok) {
768  nout << "Error! Unable to re-read egg file.\n";
769  okflag = false;
770  }
771  }
772 
773  if (egg_file->has_data()) {
774  egg_file->update_egg();
775  if (!egg_file->write_egg()) {
776  okflag = false;
777  }
778  egg_file->release_egg_data();
779  }
780  }
781  }
782 
783  return okflag;
784 }
785 
786 ////////////////////////////////////////////////////////////////////
787 // Function: Palettizer::get_egg_file
788 // Access: Public
789 // Description: Returns the EggFile with the given name. If there is
790 // no EggFile with the indicated name, creates one.
791 // This is the key name used to sort the egg files,
792 // which is typically the basename of the filename.
793 ////////////////////////////////////////////////////////////////////
795 get_egg_file(const string &name) {
796  EggFiles::iterator ei = _egg_files.find(name);
797  if (ei != _egg_files.end()) {
798  return (*ei).second;
799  }
800 
801  EggFile *file = new EggFile;
802  file->set_name(name);
803  _egg_files.insert(EggFiles::value_type(name, file));
804  return file;
805 }
806 
807 ////////////////////////////////////////////////////////////////////
808 // Function: Palettizer::remove_egg_file
809 // Access: Public
810 // Description: Removes the named egg file from the database, if it
811 // exists. Returns true if the egg file was found,
812 // false if it was not.
813 ////////////////////////////////////////////////////////////////////
814 bool Palettizer::
815 remove_egg_file(const string &name) {
816  EggFiles::iterator ei = _egg_files.find(name);
817  if (ei != _egg_files.end()) {
818  EggFile *file = (*ei).second;
819  file->remove_egg();
820  _egg_files.erase(ei);
821  return true;
822  }
823 
824  return false;
825 }
826 
827 ////////////////////////////////////////////////////////////////////
828 // Function: Palettizer::add_command_line_egg
829 // Access: Public
830 // Description: Adds the indicated EggFile to the list of eggs that
831 // are considered to have been read on the command line.
832 // These will be processed by
833 // process_command_line_eggs().
834 ////////////////////////////////////////////////////////////////////
835 void Palettizer::
837  _command_line_eggs.push_back(egg_file);
838 }
839 
840 ////////////////////////////////////////////////////////////////////
841 // Function: Palettizer::get_palette_group
842 // Access: Public
843 // Description: Returns the PaletteGroup with the given name. If
844 // there is no PaletteGroup with the indicated name,
845 // creates one.
846 ////////////////////////////////////////////////////////////////////
848 get_palette_group(const string &name) {
849  Groups::iterator gi = _groups.find(name);
850  if (gi != _groups.end()) {
851  return (*gi).second;
852  }
853 
854  PaletteGroup *group = new PaletteGroup;
855  group->set_name(name);
856  _groups.insert(Groups::value_type(name, group));
857  return group;
858 }
859 
860 ////////////////////////////////////////////////////////////////////
861 // Function: Palettizer::test_palette_group
862 // Access: Public
863 // Description: Returns the PaletteGroup with the given name. If
864 // there is no PaletteGroup with the indicated name,
865 // returns NULL.
866 ////////////////////////////////////////////////////////////////////
868 test_palette_group(const string &name) const {
869  Groups::const_iterator gi = _groups.find(name);
870  if (gi != _groups.end()) {
871  return (*gi).second;
872  }
873 
874  return (PaletteGroup *)NULL;
875 }
876 
877 ////////////////////////////////////////////////////////////////////
878 // Function: Palettizer::get_default_group
879 // Access: Public
880 // Description: Returns the default group to which an egg file should
881 // be assigned if it is not mentioned in the .txa file.
882 ////////////////////////////////////////////////////////////////////
885  PaletteGroup *default_group = get_palette_group(_default_groupname);
886  if (!_default_groupdir.empty() && !default_group->has_dirname()) {
887  default_group->set_dirname(_default_groupdir);
888  }
889  return default_group;
890 }
891 
892 ////////////////////////////////////////////////////////////////////
893 // Function: Palettizer::get_texture
894 // Access: Public
895 // Description: Returns the TextureImage with the given name. If
896 // there is no TextureImage with the indicated name,
897 // creates one. This is the key name used to sort the
898 // textures, which is typically the basename of the
899 // primary filename.
900 ////////////////////////////////////////////////////////////////////
902 get_texture(const string &name) {
903  // Look first in the same-case name, just in case it happens to be
904  // there (from an older version of egg-palettize that did this).
905  Textures::iterator ti = _textures.find(name);
906  if (ti != _textures.end()) {
907  return (*ti).second;
908  }
909 
910  // Then look in the downcase name, since we nowadays index textures
911  // only by their downcase names (to implement case insensitivity).
912  string downcase_name = downcase(name);
913  ti = _textures.find(downcase_name);
914  if (ti != _textures.end()) {
915  return (*ti).second;
916  }
917 
918  TextureImage *image = new TextureImage;
919  image->set_name(name);
920  // image->set_filename(name);
921  _textures.insert(Textures::value_type(downcase_name, image));
922 
923  return image;
924 }
925 
926 ////////////////////////////////////////////////////////////////////
927 // Function: Palettizer::yesno
928 // Access: Private, Static
929 // Description: A silly function to return "yes" or "no" based on a
930 // bool flag for nicely formatted output.
931 ////////////////////////////////////////////////////////////////////
932 const char *Palettizer::
933 yesno(bool flag) {
934  return flag ? "yes" : "no";
935 }
936 
937 ////////////////////////////////////////////////////////////////////
938 // Function: Palettizer::string_remap
939 // Access: Public, Static
940 // Description: Returns the RemapUV code corresponding to the
941 // indicated string, or RU_invalid if the string is
942 // invalid.
943 ////////////////////////////////////////////////////////////////////
944 Palettizer::RemapUV Palettizer::
945 string_remap(const string &str) {
946  if (str == "never") {
947  return RU_never;
948 
949  } else if (str == "group") {
950  return RU_group;
951 
952  } else if (str == "poly") {
953  return RU_poly;
954 
955  } else {
956  return RU_invalid;
957  }
958 }
959 
960 ////////////////////////////////////////////////////////////////////
961 // Function: Palettizer::compute_statistics
962 // Access: Private
963 // Description: Determines how much memory, etc. is required by the
964 // indicated set of texture placements, and reports this
965 // to the indicated output stream.
966 ////////////////////////////////////////////////////////////////////
967 void Palettizer::
968 compute_statistics(ostream &out, int indent_level,
969  const Palettizer::Placements &placements) const {
970  TextureMemoryCounter counter;
971 
972  Placements::const_iterator pi;
973  for (pi = placements.begin(); pi != placements.end(); ++pi) {
974  TexturePlacement *placement = (*pi);
975  counter.add_placement(placement);
976  }
977 
978  counter.report(out, indent_level);
979 }
980 
981 ////////////////////////////////////////////////////////////////////
982 // Function: Palettizer::register_with_read_factory
983 // Access: Public, Static
984 // Description: Registers the current object as something that can be
985 // read from a Bam file.
986 ////////////////////////////////////////////////////////////////////
987 void Palettizer::
990  register_factory(get_class_type(), make_Palettizer);
991 }
992 
993 ////////////////////////////////////////////////////////////////////
994 // Function: Palettizer::write_datagram
995 // Access: Public, Virtual
996 // Description: Fills the indicated datagram up with a binary
997 // representation of the current object, in preparation
998 // for writing to a Bam file.
999 ////////////////////////////////////////////////////////////////////
1000 void Palettizer::
1001 write_datagram(BamWriter *writer, Datagram &datagram) {
1002  TypedWritable::write_datagram(writer, datagram);
1003 
1004  datagram.add_int32(_pi_version);
1005  datagram.add_string(_generated_image_pattern);
1006  datagram.add_string(_map_dirname);
1007  datagram.add_string(FilenameUnifier::make_bam_filename(_shadow_dirname));
1008  datagram.add_string(FilenameUnifier::make_bam_filename(_rel_dirname));
1009  datagram.add_int32(_pal_x_size);
1010  datagram.add_int32(_pal_y_size);
1011  datagram.add_float64(_background[0]);
1012  datagram.add_float64(_background[1]);
1013  datagram.add_float64(_background[2]);
1014  datagram.add_float64(_background[3]);
1015  datagram.add_int32(_margin);
1016  datagram.add_bool(_omit_solitary);
1017  datagram.add_bool(_omit_everything);
1018  datagram.add_float64(_coverage_threshold);
1019  datagram.add_bool(_force_power_2);
1020  datagram.add_bool(_aggressively_clean_mapdir);
1021  datagram.add_bool(_round_uvs);
1022  datagram.add_float64(_round_unit);
1023  datagram.add_float64(_round_fuzz);
1024  datagram.add_int32((int)_remap_uv);
1025  datagram.add_int32((int)_remap_char_uv);
1026  datagram.add_uint8((int)_cutout_mode);
1027  datagram.add_float64(_cutout_ratio);
1028 
1029  writer->write_pointer(datagram, _color_type);
1030  writer->write_pointer(datagram, _alpha_type);
1031  writer->write_pointer(datagram, _shadow_color_type);
1032  writer->write_pointer(datagram, _shadow_alpha_type);
1033 
1034  datagram.add_int32(_egg_files.size());
1035  EggFiles::const_iterator ei;
1036  for (ei = _egg_files.begin(); ei != _egg_files.end(); ++ei) {
1037  writer->write_pointer(datagram, (*ei).second);
1038  }
1039 
1040  // We don't write _command_line_eggs; that's specific to each
1041  // session.
1042 
1043  datagram.add_int32(_groups.size());
1044  Groups::const_iterator gi;
1045  for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
1046  writer->write_pointer(datagram, (*gi).second);
1047  }
1048 
1049  datagram.add_int32(_textures.size());
1050  Textures::const_iterator ti;
1051  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
1052  writer->write_pointer(datagram, (*ti).second);
1053  }
1054 }
1055 
1056 ////////////////////////////////////////////////////////////////////
1057 // Function: Palettizer::complete_pointers
1058 // Access: Public, Virtual
1059 // Description: Called after the object is otherwise completely read
1060 // from a Bam file, this function's job is to store the
1061 // pointers that were retrieved from the Bam file for
1062 // each pointer object written. The return value is the
1063 // number of pointers processed from the list.
1064 ////////////////////////////////////////////////////////////////////
1065 int Palettizer::
1067  int index = TypedWritable::complete_pointers(p_list, manager);
1068 
1069  if (p_list[index] != (TypedWritable *)NULL) {
1070  DCAST_INTO_R(_color_type, p_list[index], index);
1071  }
1072  index++;
1073 
1074  if (p_list[index] != (TypedWritable *)NULL) {
1075  DCAST_INTO_R(_alpha_type, p_list[index], index);
1076  }
1077  index++;
1078 
1079  if (p_list[index] != (TypedWritable *)NULL) {
1080  DCAST_INTO_R(_shadow_color_type, p_list[index], index);
1081  }
1082  index++;
1083 
1084  if (p_list[index] != (TypedWritable *)NULL) {
1085  DCAST_INTO_R(_shadow_alpha_type, p_list[index], index);
1086  }
1087  index++;
1088 
1089  int i;
1090  for (i = 0; i < _num_egg_files; i++) {
1091  EggFile *egg_file;
1092  DCAST_INTO_R(egg_file, p_list[index], index);
1093  _egg_files.insert(EggFiles::value_type(egg_file->get_name(), egg_file));
1094  index++;
1095  }
1096 
1097  for (i = 0; i < _num_groups; i++) {
1098  PaletteGroup *group;
1099  DCAST_INTO_R(group, p_list[index], index);
1100  _groups.insert(Groups::value_type(group->get_name(), group));
1101  index++;
1102  }
1103 
1104  for (i = 0; i < _num_textures; i++) {
1105  TextureImage *texture;
1106  DCAST_INTO_R(texture, p_list[index], index);
1107 
1108  string name = downcase(texture->get_name());
1109  pair<Textures::iterator, bool> result = _textures.insert(Textures::value_type(name, texture));
1110  if (!result.second) {
1111  // Two textures mapped to the same slot--probably a case error
1112  // (since we just changed this rule).
1113  _texture_conflicts.push_back(texture);
1114  }
1115  index++;
1116  }
1117 
1118  return index;
1119 }
1120 
1121 ////////////////////////////////////////////////////////////////////
1122 // Function: Palettizer::finalize
1123 // Access: Public, Virtual
1124 // Description: Called by the BamReader to perform any final actions
1125 // needed for setting up the object after all objects
1126 // have been read and all pointers have been completed.
1127 ////////////////////////////////////////////////////////////////////
1128 void Palettizer::
1129 finalize(BamReader *manager) {
1130  // Walk through the list of texture names that were in conflict.
1131  // These can only happen if there were two different names that
1132  // different only in case, which means the textures.boo file was
1133  // created before we introduced the rule that case is insignificant.
1134  TextureConflicts::iterator ci;
1135  for (ci = _texture_conflicts.begin();
1136  ci != _texture_conflicts.end();
1137  ++ci) {
1138  TextureImage *texture_b = (*ci);
1139  string downcase_name = downcase(texture_b->get_name());
1140 
1141  Textures::iterator ti = _textures.find(downcase_name);
1142  nassertv(ti != _textures.end());
1143  TextureImage *texture_a = (*ti).second;
1144  _textures.erase(ti);
1145 
1146  if (!texture_b->is_used() || !texture_a->is_used()) {
1147  // If either texture is not used, there's not really a
1148  // conflict--the other one wins.
1149  if (texture_a->is_used()) {
1150  bool inserted1 = _textures.insert(Textures::value_type(downcase_name, texture_a)).second;
1151  nassertd(inserted1) { }
1152 
1153  } else if (texture_b->is_used()) {
1154  bool inserted2 = _textures.insert(Textures::value_type(downcase_name, texture_b)).second;
1155  nassertd(inserted2) { }
1156  }
1157 
1158  } else {
1159  // If both textures are used, there *is* a conflict.
1160  nout << "Texture name conflict: \"" << texture_a->get_name()
1161  << "\" vs. \"" << texture_b->get_name() << "\"\n";
1162  if (texture_a->get_name() != downcase_name &&
1163  texture_b->get_name() != downcase_name) {
1164  // Arbitrarily pick texture_a to get the right case.
1165  bool inserted1 = _textures.insert(Textures::value_type(downcase_name, texture_a)).second;
1166  bool inserted2 = _textures.insert(Textures::value_type(texture_b->get_name(), texture_b)).second;
1167  nassertd(inserted1 && inserted2) { }
1168 
1169  } else {
1170  // One of them is already the right case.
1171  bool inserted1 = _textures.insert(Textures::value_type(texture_a->get_name(), texture_a)).second;
1172  bool inserted2 = _textures.insert(Textures::value_type(texture_b->get_name(), texture_b)).second;
1173  nassertd(inserted1 && inserted2) { }
1174  }
1175  }
1176  }
1177 }
1178 
1179 
1180 ////////////////////////////////////////////////////////////////////
1181 // Function: Palettizer::make_Palettizer
1182 // Access: Protected
1183 // Description: This method is called by the BamReader when an object
1184 // of this type is encountered in a Bam file; it should
1185 // allocate and return a new object with all the data
1186 // read.
1187 ////////////////////////////////////////////////////////////////////
1188 TypedWritable* Palettizer::
1189 make_Palettizer(const FactoryParams &params) {
1190  Palettizer *me = new Palettizer;
1191  DatagramIterator scan;
1192  BamReader *manager;
1193 
1194  parse_params(params, scan, manager);
1195  me->fillin(scan, manager);
1196  manager->register_finalize(me);
1197 
1198  return me;
1199 }
1200 
1201 ////////////////////////////////////////////////////////////////////
1202 // Function: Palettizer::fillin
1203 // Access: Protected
1204 // Description: Reads the binary data from the given datagram
1205 // iterator, which was written by a previous call to
1206 // write_datagram().
1207 ////////////////////////////////////////////////////////////////////
1208 void Palettizer::
1209 fillin(DatagramIterator &scan, BamReader *manager) {
1210  TypedWritable::fillin(scan, manager);
1211 
1212  _read_pi_version = scan.get_int32();
1213  if (_read_pi_version > _pi_version || _read_pi_version < _min_pi_version) {
1214  // Oops, we don't know how to read this palette information file.
1215  _is_valid = false;
1216  return;
1217  }
1218  if (_read_pi_version >= 12) {
1219  _generated_image_pattern = scan.get_string();
1220  }
1221  _map_dirname = scan.get_string();
1222  _shadow_dirname = FilenameUnifier::get_bam_filename(scan.get_string());
1223  _rel_dirname = FilenameUnifier::get_bam_filename(scan.get_string());
1224  FilenameUnifier::set_rel_dirname(_rel_dirname);
1225  _pal_x_size = scan.get_int32();
1226  _pal_y_size = scan.get_int32();
1227  if (_read_pi_version >= 13) {
1228  _background[0] = scan.get_float64();
1229  _background[1] = scan.get_float64();
1230  _background[2] = scan.get_float64();
1231  _background[3] = scan.get_float64();
1232  }
1233  _margin = scan.get_int32();
1234  _omit_solitary = scan.get_bool();
1235  if (_read_pi_version >= 14) {
1236  _omit_everything = scan.get_bool();
1237  }
1238  _coverage_threshold = scan.get_float64();
1239  _force_power_2 = scan.get_bool();
1240  _aggressively_clean_mapdir = scan.get_bool();
1241  _round_uvs = scan.get_bool();
1242  _round_unit = scan.get_float64();
1243  _round_fuzz = scan.get_float64();
1244  _remap_uv = (RemapUV)scan.get_int32();
1245  _remap_char_uv = (RemapUV)scan.get_int32();
1246  if (_read_pi_version >= 16) {
1247  _cutout_mode = (EggRenderMode::AlphaMode)scan.get_uint8();
1248  _cutout_ratio = scan.get_float64();
1249  }
1250 
1251  manager->read_pointer(scan); // _color_type
1252  manager->read_pointer(scan); // _alpha_type
1253  manager->read_pointer(scan); // _shadow_color_type
1254  manager->read_pointer(scan); // _shadow_alpha_type
1255 
1256  _num_egg_files = scan.get_int32();
1257  manager->read_pointers(scan, _num_egg_files);
1258 
1259  _num_groups = scan.get_int32();
1260  manager->read_pointers(scan, _num_groups);
1261 
1262  _num_textures = scan.get_int32();
1263  manager->read_pointers(scan, _num_textures);
1264 }
void setup_shadow_images()
Ensures that each PaletteImage&#39;s _shadow_image has the correct filename and image types...
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...
PNMFileType * get_type_from_extension(const string &filename) const
Tries to determine what the PNMFileType is likely to be for a particular image file based on its exte...
void update_unknown_textures(const TxaFile &txa_file)
Checks for new information on any textures within the group for which some of the saved information i...
void add_uint8(PN_uint8 value)
Adds an unsigned 8-bit integer to the datagram.
Definition: datagram.I:138
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
bool unlink() const
Permanently deletes the file associated with the filename, if possible.
Definition: filename.cxx:2554
const PaletteGroups & get_groups() const
Returns the set of groups this group depends on.
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 pre_txa_file()
Updates any internal state prior to reading the .txa file.
void scan_textures()
Scans the egg file for texture references and updates the _textures list appropriately.
Definition: eggFile.cxx:114
void add_float64(PN_float64 value)
Adds a 64-bit floating-point number to the datagram.
Definition: datagram.I:228
void optimal_resize()
Attempts to resize each PalettteImage down to its smallest possible size.
void place_all()
Once all the textures have been assigned to this group, try to place them all onto suitable PaletteIm...
bool is_newer_than(const Filename &reference_filename)
Returns true if the source image is newer than the indicated file, false otherwise.
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
void clear_source_basic_properties()
Calls clear_basic_properties() on each source texture image used by this texture, to reset the proper...
This is the main engine behind egg-palettize.
Definition: palettizer.h:43
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:37
void process_all(bool force_texture_read, const Filename &state_filename)
Reprocesses all textures known.
Definition: palettizer.cxx:539
void determine_placement_size()
Calls determine_size() on each TexturePlacement for the texture, to ensure that each TexturePlacement...
This is the highest level of grouping for TextureImages.
Definition: paletteGroup.h:47
This is the base class of a family of classes that represent particular image file types that PNMImag...
Definition: pnmFileType.h:35
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
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
virtual void finalize(BamReader *manager)
Called by the BamReader to perform any final actions needed for setting up the object after all objec...
PaletteGroup * test_palette_group(const string &name) const
Returns the PaletteGroup with the given name.
Definition: palettizer.cxx:868
EggFile * get_egg_file(const string &name)
Returns the EggFile with the given name.
Definition: palettizer.cxx:795
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
bool get_noabs() const
Returns the current setting of the noabs flag.
Definition: palettizer.cxx:144
PN_int32 get_int32()
Extracts a signed 32-bit integer.
PN_uint8 get_uint8()
Extracts an unsigned 8-bit integer.
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.
void report_statistics() const
Output a report of the palettization effectiveness, texture memory utilization, and so on...
Definition: palettizer.cxx:309
bool had_data() const
Returns true if the EggData for this EggFile has ever been loaded in this session.
Definition: eggFile.cxx:498
void write_image_info(ostream &out, int indent_level=0) const
Writes a list of the PaletteImages associated with this group, and all of their textures, to the indicated output stream.
bool remove_egg_file(const string &name)
Removes the named egg file from the database, if it exists.
Definition: palettizer.cxx:815
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 string get_suggested_extension() const
Returns a suitable filename extension (without a leading dot) to suggest for files of this type...
Definition: pnmFileType.cxx:75
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
bool is_surprise() const
Returns true if this particular texture is a &#39;surprise&#39;, i.e.
static PNMFileTypeRegistry * get_global_ptr()
Returns a pointer to the global PNMFileTypeRegistry object.
void reset_dependency_level()
Unconditionally sets the dependency level and order of this group to zero, in preparation for a later...
void read_txa_file(istream &txa_file, const string &txa_filename)
Reads in the .txa file and keeps it ready for matching textures and egg files.
Definition: palettizer.cxx:367
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:39
void choose_placements()
Once all the textures have been assigned to groups (but before they may actually be placed)...
Definition: eggFile.cxx:437
void report(ostream &out, int indent_level)
Reports the measured texture memory usage.
void release_egg_data()
Releases the memory that was loaded by a previous call to read_egg().
Definition: eggFile.cxx:625
bool is_preferred_over(const PaletteGroup &other) const
Returns true if this group should be preferred for adding textures over the other group...
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition: datagram.I:118
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...
static RemapUV string_remap(const string &str)
Returns the RemapUV code corresponding to the indicated string, or RU_invalid if the string is invali...
Definition: palettizer.cxx:945
bool match_egg(EggFile *egg_file) const
Searches for a matching line in the .txa file for the given egg file and applies its specifications...
Definition: txaFile.cxx:137
void read_header()
Causes the header part of the image to be reread, usually to confirm that its image properties (size...
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()...
bool is_used() const
Returns true if this particular texture has been placed somewhere, anywhere, or false if it is not us...
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 all_params_set()
Called after all command line parameters have been set up, this is a hook to do whatever initializati...
Definition: palettizer.cxx:423
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
static Filename get_bam_filename(Filename filename)
Returns an absolute pathname based on the given relative pathname, presumably read from the bam file ...
void reset_images()
Throws away all of the current PaletteImages, so that new ones may be created (and the packing made m...
Definition: palettizer.cxx:652
bool write_eggs()
Adjusts the egg files to reference the newly generated textures, and writes them out.
Definition: palettizer.cxx:757
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
void copy_unplaced(bool redo_all)
Copies the texture to whichever destination directories are appropriate for the groups in which it ha...
void add_placement(TexturePlacement *placement)
Adds the indicated TexturePlacement to the counter.
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 generate_images(bool redo_all)
Actually generates the appropriate palette and unplaced texture images into the map directories...
Definition: palettizer.cxx:669
void report_pi() const
Output a verbose description of all the palettization information to standard output, for the user&#39;s perusal.
Definition: palettizer.cxx:187
void update_images(bool redo_all)
Regenerates each PaletteImage on this group that needs it.
void register_finalize(TypedWritable *whom)
Should be called by an object reading itself from the Bam file to indicate that this particular objec...
Definition: bamReader.cxx:880
void assign_groups()
Assigns the texture to all of the PaletteGroups the various egg files that use it need...
int get_dependency_order() const
Returns the dependency order of this group.
void process_command_line_eggs(bool force_texture_read, const Filename &state_filename)
Processes all the textures named in the _command_line_eggs, placing them on the appropriate palettes ...
Definition: palettizer.cxx:444
void set_noabs(bool noabs)
Changes the current setting of the noabs flag.
Definition: palettizer.cxx:163
bool exists() const
Returns true if the filename exists on the disk, false otherwise.
Definition: filename.cxx:1356
void set_dependency_level(int level)
Sets the dependency level of this group to the indicated level, provided that level is not lower than...
void make_complete(const PaletteGroups &a)
Completes the set with the transitive closure of all dependencies: for each PaletteGroup already in t...
void set_dirname(const string &dirname)
Sets the directory name associated with the palette group.
This class is used to gather statistics on texture memory usage, etc.
void mark_texture_named()
Indicates that this particular texture has been named by the user for processing this session...
void reset_images()
Throws away all of the current PaletteImages, so that new ones may be created (and the packing made m...
PN_float64 get_float64()
Extracts a 64-bit floating-point number.
bool set_dependency_order()
Updates the dependency order of this group.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:213
bool read(istream &in, const string &filename)
Reads the indicated stream, and returns true if successful, or false if there is an error...
Definition: txaFile.cxx:40
const PNMImage & read_source_image()
Reads in the original image, if it has not already been read, and returns it.
void write_scale_info(ostream &out, int indent_level=0)
Writes the information about the texture&#39;s size and placement.
void get_complete_placements(pvector< TexturePlacement * > &placements) const
Adds the set of TexturePlacements associated with this group and all dependent groups to the indicate...
A set of PaletteGroups.
Definition: paletteGroups.h:31
static void register_with_read_factory()
Registers the current object as something that can be read from a Bam file.
Definition: palettizer.cxx:988
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
void add_int32(PN_int32 value)
Adds a signed 32-bit integer to the datagram.
Definition: datagram.I:159
const Filename & get_source_filename() const
Returns the filename this egg file was read from.
Definition: eggFile.cxx:100
void write_source_pathnames(ostream &out, int indent_level=0) const
Writes the list of source pathnames that might contribute to this texture to the indicated output str...
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 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
void post_txa_file()
Once the .txa file has been read and the TextureImage matched against it, considers applying the requ...
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 optimal_resize()
Attempts to resize each PalettteImage down to its smallest possible size.
Definition: palettizer.cxx:636
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
bool read_stale_eggs(bool redo_all)
Reads in any egg file that is known to be stale, even if it was not listed on the command line...
Definition: palettizer.cxx:696
void add_command_line_egg(EggFile *egg_file)
Adds the indicated EggFile to the list of eggs that are considered to have been read on the command l...
Definition: palettizer.cxx:836
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:43
TextureImage * get_texture(const string &name)
Returns the TextureImage with the given name.
Definition: palettizer.cxx:902
PaletteGroup * get_palette_group(const string &name)
Returns the PaletteGroup with the given name.
Definition: palettizer.cxx:848
bool is_stale() const
Returns true if the egg file needs to be updated, i.e.
Definition: eggFile.cxx:357
bool has_dirname() const
Returns true if the directory name has been explicitly set for this group.
void clear_depends()
Eliminates all the dependency information for this group.
bool is_valid() const
Returns true if the palette information file was read correctly, or false if there was some error and...
Definition: palettizer.cxx:175
void get_placements(pvector< TexturePlacement * > &placements) const
Adds the set of TexturePlacements associated with this group to the indicated vector.
size_type size() const
Returns the number of elements in the set.
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
static void set_rel_dirname(const Filename &rel_dirname)
Sets the name of the directory that texture filenames will be written relative to, when generating egg files.
bool match_texture(TextureImage *texture) const
Searches for a matching line in the .txa file for the given texture and applies its specifications...
Definition: txaFile.cxx:158
void release_source_image()
Frees the memory that was allocated by a previous call to read_source_image().