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