Panda3D
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 }
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 setup_shadow_images()
Ensures that each PaletteImage&#39;s _shadow_image has the correct filename and image types...
void report_statistics() const
Output a report of the palettization effectiveness, texture memory utilization, and so on...
Definition: palettizer.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...
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.
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 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...
PaletteGroup * test_palette_group(const string &name) const
Returns the PaletteGroup with the given name.
Definition: palettizer.cxx:868
bool get_noabs() const
Returns the current setting of the noabs flag.
Definition: palettizer.cxx:144
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
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
bool had_data() const
Returns true if the EggData for this EggFile has ever been loaded in this session.
Definition: eggFile.cxx:498
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
const Filename & get_source_filename() const
Returns the filename this egg file was read from.
Definition: eggFile.cxx:100
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...
size_type size() const
Returns the number of elements in the set.
EggFile * get_egg_file(const string &name)
Returns the EggFile with the given name.
Definition: palettizer.cxx:795
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:73
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...
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.
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 void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
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
bool is_used() const
Returns true if this particular texture has been placed somewhere, anywhere, or false if it is not us...
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
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
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
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
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->read_pointer() was called in fillin()...
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:700
static Filename get_bam_filename(Filename filename)
Returns an absolute pathname based on the given relative pathname, presumably read from the bam file ...
bool has_data() const
Returns true if the EggData for this EggFile has been loaded, and not yet released.
Definition: eggFile.cxx:487
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
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.
bool unlink() const
Permanently deletes the file associated with the filename, if possible.
Definition: filename.cxx:2554
void generate_images(bool redo_all)
Actually generates the appropriate palette and unplaced texture images into the map directories...
Definition: palettizer.cxx:669
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:886
void assign_groups()
Assigns the texture to all of the PaletteGroups the various egg files that use it need...
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
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...
bool is_surprise() const
Returns true if this particular texture is a &#39;surprise&#39;, i.e.
bool is_surprise() const
Returns true if this particular egg file is a &#39;surprise&#39;, i.e.
Definition: eggFile.cxx:332
void set_dependency_level(int level)
Sets the dependency level of this group to the indicated level, provided that level is not lower than...
bool is_stale() const
Returns true if the egg file needs to be updated, i.e.
Definition: eggFile.cxx:357
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
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.
A set of PaletteGroups.
Definition: paletteGroups.h:31
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
bool has_dirname() const
Returns true if the directory name has been explicitly set for this group.
static void register_with_read_factory()
Registers the current object as something that can be read from a Bam file.
Definition: palettizer.cxx:988
bool is_preferred_over(const PaletteGroup &other) const
Returns true if this group should be preferred for adding textures over the other group...
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
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
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 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
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
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
const PaletteGroups & get_groups() const
Returns the set of groups this group depends on.
void get_complete_placements(pvector< TexturePlacement *> &placements) const
Adds the set of TexturePlacements associated with this group and all dependent groups to the indicate...
void clear_depends()
Eliminates all the dependency information for this group.
void get_placements(pvector< TexturePlacement *> &placements) const
Adds the set of TexturePlacements associated with this group to the indicated vector.
bool exists() const
Returns true if the filename exists on the disk, false otherwise.
Definition: filename.cxx:1356
int get_dependency_order() const
Returns the dependency order of this group.
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:658
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.
void release_source_image()
Frees the memory that was allocated by a previous call to read_source_image().