Panda3D
textureImage.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 textureImage.cxx
10  * @author drose
11  * @date 2000-11-29
12  */
13 
14 #include "textureImage.h"
15 #include "sourceTextureImage.h"
16 #include "destTextureImage.h"
17 #include "eggFile.h"
18 #include "paletteGroup.h"
19 #include "paletteImage.h"
20 #include "texturePlacement.h"
21 #include "filenameUnifier.h"
22 #include "string_utils.h"
23 #include "indent.h"
24 #include "datagram.h"
25 #include "datagramIterator.h"
26 #include "bamReader.h"
27 #include "bamWriter.h"
28 #include "pnmFileType.h"
29 #include "indirectCompareNames.h"
30 #include "pvector.h"
31 
32 #include <iterator>
33 
34 using std::string;
35 
36 TypeHandle TextureImage::_type_handle;
37 
38 /**
39  *
40  */
41 TextureImage::
42 TextureImage() {
43  _preferred_source = nullptr;
44  _read_source_image = false;
45  _allow_release_source_image = true;
46  _is_surprise = true;
47  _ever_read_image = false;
48  _forced_grayscale = false;
49  _alpha_bits = 0;
50  _mid_pixel_ratio = 0.0;
51  _is_cutout = false;
52  _alpha_mode = EggRenderMode::AM_unspecified;
53  _txa_wrap_u = EggTexture::WM_unspecified;
54  _txa_wrap_v = EggTexture::WM_unspecified;
55  _texture_named = false;
56  _got_txa_file = false;
57 }
58 
59 /**
60  * Records that a particular egg file references this texture. This is
61  * essential to know when deciding how to assign the TextureImage to the
62  * various PaletteGroups.
63  */
64 void TextureImage::
65 note_egg_file(EggFile *egg_file) {
66  nassertv(!egg_file->get_complete_groups().empty());
67  _egg_files.insert(egg_file);
68 }
69 
70 /**
71  * Assigns the texture to all of the PaletteGroups the various egg files that
72  * use it need. Attempts to choose the minimum set of PaletteGroups that
73  * satisfies all of the egg files.
74  */
75 void TextureImage::
77  if (_egg_files.empty()) {
78  // If we're not referenced by any egg files any more, assign us to no
79  // groups.
80  PaletteGroups empty;
81  assign_to_groups(empty);
82  return;
83  }
84 
85  PaletteGroups definitely_in;
86 
87  // First, we need to eliminate from consideration all the egg files that are
88  // already taken care of by the user's explicit group assignments for this
89  // texture.
90  WorkingEggs needed_eggs;
91 
92  if (_explicitly_assigned_groups.empty()) {
93  // If we have no explicit group assignments, we must consider all the egg
94  // files.
95  std::copy(_egg_files.begin(), _egg_files.end(), std::back_inserter(needed_eggs));
96 
97  } else {
98  // Otherwise, we only need to consider the egg files that don't have any
99  // groups in common with our explicit assignments.
100 
101  EggFiles::const_iterator ei;
102  for (ei = _egg_files.begin(); ei != _egg_files.end(); ++ei) {
103  PaletteGroups intersect;
104  intersect.make_intersection(_explicitly_assigned_groups, (*ei)->get_complete_groups());
105  if (!intersect.empty()) {
106  // This egg file is satisfied by one of the texture's explicit
107  // assignments.
108 
109  // We must use at least one of the explicitly-assigned groups that
110  // satisfied the egg file. We don't need to use all of them, however,
111  // and we choose the first one arbitrarily.
112  definitely_in.insert(*intersect.begin());
113 
114  } else {
115  // This egg file was not satisfied by any of the texture's explicit
116  // assignments. Therefore, we'll need to choose some additional group
117  // to assign the texture to, to make the egg file happy. Defer this a
118  // bit.
119  needed_eggs.push_back(*ei);
120  }
121  }
122  }
123 
124  while (!needed_eggs.empty()) {
125  // We need to know the complete set of groups that we need to consider
126  // adding the texture to. This is the union of all the egg files'
127  // requested groups.
128  PaletteGroups total;
129  WorkingEggs::const_iterator ei;
130  for (ei = needed_eggs.begin(); ei != needed_eggs.end(); ++ei) {
131  total.make_union(total, (*ei)->get_complete_groups());
132  }
133 
134  // We don't count the "null" group for texture assignment.
135  total.remove_null();
136  if (total.empty()) {
137  break;
138  }
139 
140  // Now, find the group that will satisfy the most egg files. If two
141  // groups satisfy the same number of egg files, choose (a) the most
142  // specific one, i.e. with the lowest dirname_level, or the lowest
143  // dependency_level if the dirname_levels are equal, and (b) the one that
144  // has the fewest egg files sharing it.
145  PaletteGroups::iterator gi = total.begin();
146  PaletteGroup *best = (*gi);
147  int best_egg_count = compute_egg_count(best, needed_eggs);
148  ++gi;
149  while (gi != total.end()) {
150  PaletteGroup *group = (*gi);
151 
152  // Do we prefer this group to our current 'best'?
153  bool prefer_group = false;
154  int group_egg_count = compute_egg_count(group, needed_eggs);
155  if (group_egg_count != best_egg_count) {
156  prefer_group = (group_egg_count > best_egg_count);
157 
158  } else {
159  prefer_group = group->is_preferred_over(*best);
160  }
161 
162  if (prefer_group) {
163  best = group;
164  best_egg_count = group_egg_count;
165  }
166  ++gi;
167  }
168 
169  // Okay, now we've picked the best group. Eliminate all the eggs from
170  // consideration that are satisfied by this group, and repeat.
171  definitely_in.insert(best);
172 
173  WorkingEggs next_needed_eggs;
174  for (ei = needed_eggs.begin(); ei != needed_eggs.end(); ++ei) {
175  if ((*ei)->get_complete_groups().count(best) == 0) {
176  // This one wasn't eliminated.
177  next_needed_eggs.push_back(*ei);
178  }
179  }
180  needed_eggs.swap(next_needed_eggs);
181  }
182 
183  // Finally, now that we've computed the set of groups we need to assign the
184  // texture to, we need to reconcile this with the set of groups we've
185  // assigned the texture to previously.
186  assign_to_groups(definitely_in);
187 }
188 
189 /**
190  * Once assign_groups() has been called, this returns the actual set of groups
191  * the TextureImage has been assigned to.
192  */
194 get_groups() const {
195  return _actual_assigned_groups;
196 }
197 
198 /**
199  * Gets the TexturePlacement object which represents the assignment of this
200  * texture to the indicated group. If the texture has not been assigned to
201  * the indicated group, returns NULL.
202  */
205  Placement::const_iterator pi;
206  pi = _placement.find(group);
207  if (pi == _placement.end()) {
208  return nullptr;
209  }
210 
211  return (*pi).second;
212 }
213 
214 /**
215  * Removes the texture from any PaletteImages it is assigned to, but does not
216  * remove it from the groups. It will be re-placed within each group when
217  * PaletteGroup::place_all() is called.
218  */
219 void TextureImage::
221  Placement::iterator pi;
222  for (pi = _placement.begin(); pi != _placement.end(); ++pi) {
223  (*pi).second->force_replace();
224  }
225 }
226 
227 /**
228  * Marks all the egg files that reference this texture stale. Should be
229  * called only when the texture properties change in some catastrophic way
230  * that will require every egg file referencing it to be regenerated, even if
231  * it is not palettized.
232  */
233 void TextureImage::
235  Placement::iterator pi;
236  for (pi = _placement.begin(); pi != _placement.end(); ++pi) {
237  (*pi).second->mark_eggs_stale();
238  }
239 }
240 
241 /**
242  * Indicates that this particular texture has been named by the user for
243  * processing this session, normally by listing an egg file on the command
244  * line that references it.
245  */
246 void TextureImage::
248  _texture_named = true;
249 }
250 
251 /**
252  * Returns true if this particular texture has been named by the user for
253  * procession this session, for instance by listing an egg file on the command
254  * line that references it.
255  */
256 bool TextureImage::
258  return _texture_named;
259 }
260 
261 /**
262  * Updates any internal state prior to reading the .txa file.
263  */
264 void TextureImage::
266  // Save our current properties, so we can note if they change.
267  _pre_txa_properties = _properties;
268 
269  // Get our properties from the actual image for this texture. It's possible
270  // the .txa file will update them further.
272  if (source != nullptr) {
273  _properties = source->get_properties();
274  }
275 
276  _pre_txa_alpha_mode = _alpha_mode;
277  _alpha_mode = EggRenderMode::AM_unspecified;
278 
279  _request.pre_txa_file();
280  _is_surprise = true;
281 }
282 
283 /**
284  * Once the .txa file has been read and the TextureImage matched against it,
285  * considers applying the requested size change. Updates the TextureImage's
286  * size with the size the texture ought to be, if this can be determined.
287  */
288 void TextureImage::
290  _got_txa_file = true;
291 
292  // First, get the actual size of the texture.
294  if (source != nullptr) {
295  if (source->get_size()) {
296  _size_known = true;
297  _x_size = source->get_x_size();
298  _y_size = source->get_y_size();
299  _properties.set_num_channels(source->get_num_channels());
300  }
301  }
302 
303  // Now update this with a particularly requested size.
304  if (_request._got_size) {
305  _size_known = true;
306  _x_size = _request._x_size;
307  _y_size = _request._y_size;
308  }
309 
310  if (_txa_wrap_u != _request._wrap_u ||
311  _txa_wrap_v != _request._wrap_v) {
312  _txa_wrap_u = _request._wrap_u;
313  _txa_wrap_v = _request._wrap_v;
314 
315  // If the explicit wrap mode changes, we may need to regenerate the egg
316  // files, andor refill the palettes.
317  mark_eggs_stale();
318 
319  Placement::iterator pi;
320  for (pi = _placement.begin(); pi != _placement.end(); ++pi) {
321  TexturePlacement *placement = (*pi).second;
322  placement->mark_unfilled();
323  }
324  }
325 
326  if (_properties.has_num_channels() && !_request._keep_format) {
327  int num_channels = _properties.get_num_channels();
328  // Examine the image to determine if we can downgrade the number of
329  // channels, for instance from color to grayscale.
330  if (num_channels == 3 || num_channels == 4) {
331  consider_grayscale();
332  }
333 
334  // Also consider the alpha properties, and whether we should downgrade
335  // from alpha to non-alpha.
336  if (num_channels == 2 || num_channels == 4) {
337  consider_alpha();
338  }
339  }
340 
341  // However, if we got an explicit request for channels, honor that.
342  if (_request._got_num_channels) {
343  _properties.set_num_channels(_request._num_channels);
344  }
345 
346  _properties._generic_format = _request._generic_format;
347  _properties._keep_format = _request._keep_format;
348 
349  if (_request._format != EggTexture::F_unspecified) {
350  _properties._format = _request._format;
351  _properties._force_format = _request._force_format;
352  }
353 
354  if (_request._minfilter != EggTexture::FT_unspecified) {
355  _properties._minfilter = _request._minfilter;
356  }
357  if (_request._magfilter != EggTexture::FT_unspecified) {
358  _properties._magfilter = _request._magfilter;
359  }
360 
361  _properties._anisotropic_degree = _request._anisotropic_degree;
362 
363  if (_properties._color_type == nullptr) {
364  _properties._color_type = _request._properties._color_type;
365  _properties._alpha_type = _request._properties._alpha_type;
366  }
367 
368  // Finally, make sure our properties are fully defined.
369  _properties.fully_define();
370 
371  // Now, if our properties have changed in all that from our previous
372  // session, we need to re-place ourself in all palette groups.
373  if (_properties != _pre_txa_properties) {
374  force_replace();
375 
376  // The above will mark the egg files stale when the texture is palettized
377  // (since the UV's will certainly need to be recomputed), but sometimes we
378  // need to mark the egg files stale even when the texture is not
379  // palettized (if a critical property has changed). The following
380  // accomplishes this:
381  if (!_properties.egg_properties_match(_pre_txa_properties)) {
382  mark_eggs_stale();
383  }
384  }
385 
386  // The alpha mode isn't stored in the properties, because it doesn't affect
387  // which textures may be associated into a common palette.
388  if (_request._alpha_mode != EggRenderMode::AM_unspecified) {
389  _alpha_mode = _request._alpha_mode;
390  }
391 
392  // On the other hand, if we don't have an alpha channel, we shouldn't have
393  // an alpha mode.
394  if (_properties.has_num_channels()) {
395  int num_channels = _properties.get_num_channels();
396  if (num_channels == 1 || num_channels == 3) {
397  _alpha_mode = EggRenderMode::AM_unspecified;
398  }
399  }
400 
401  // If we've changed the alpha mode, we should also mark the eggs stale.
402  if (_pre_txa_alpha_mode != _alpha_mode) {
403  mark_eggs_stale();
404  }
405 }
406 
407 /**
408  * Returns true if this TextureImage has been looked up in the .txa file this
409  * session, false otherwise.
410  */
411 bool TextureImage::
412 got_txa_file() const {
413  return _got_txa_file;
414 }
415 
416 /**
417  * Calls determine_size() on each TexturePlacement for the texture, to ensure
418  * that each TexturePlacement is still requesting the best possible size for
419  * the texture.
420  */
421 void TextureImage::
423  Placement::iterator pi;
424  for (pi = _placement.begin(); pi != _placement.end(); ++pi) {
425  TexturePlacement *placement = (*pi).second;
426  placement->determine_size();
427  }
428 }
429 
430 /**
431  * Returns true if the user specifically requested to omit this texture via
432  * the "omit" keyword in the .txa file, or false otherwise.
433  */
434 bool TextureImage::
435 get_omit() const {
436  return _request._omit;
437 }
438 
439 /**
440  * Returns the appropriate coverage threshold for this texture. This is
441  * either the Palettizer::_coverage_threshold parameter, given globally via
442  * -r, or a particular value for this texture as supplied by the "coverage"
443  * keyword in the .txa file.
444  */
445 double TextureImage::
447  return _request._coverage_threshold;
448 }
449 
450 /**
451  * Returns the appropriate margin for this texture. This is either the
452  * Palettizer::_margin parameter, or a particular value for this texture as
453  * supplied by the "margin" keyword in the .txa file.
454  */
455 int TextureImage::
456 get_margin() const {
457  return _request._margin;
458 }
459 
460 /**
461  * Returns true if this particular texture is a 'surprise', i.e. it wasn't
462  * matched by a line in the .txa file that didn't include the keyword 'cont'.
463  */
464 bool TextureImage::
465 is_surprise() const {
466  if (_placement.empty()) {
467  // A texture that is not actually placed anywhere is not considered a
468  // surprise.
469  return false;
470  }
471 
472  return _is_surprise;
473 }
474 
475 /**
476  * Returns true if this particular texture has been placed somewhere,
477  * anywhere, or false if it is not used.
478  */
479 bool TextureImage::
480 is_used() const {
481  return !_placement.empty();
482 }
483 
484 /**
485  * Returns the alpha mode that should be used to render objects with this
486  * texture, as specified by the user or as determined from examining the
487  * texture's alpha channel.
488  */
489 EggRenderMode::AlphaMode TextureImage::
490 get_alpha_mode() const {
491  return _alpha_mode;
492 }
493 
494 /**
495  * Returns the wrap mode specified in the u direction in the txa file, or
496  * WM_unspecified.
497  */
498 EggTexture::WrapMode TextureImage::
499 get_txa_wrap_u() const {
500  return _txa_wrap_u;
501 }
502 
503 /**
504  * Returns the wrap mode specified in the v direction in the txa file, or
505  * WM_unspecified.
506  */
507 EggTexture::WrapMode TextureImage::
508 get_txa_wrap_v() const {
509  return _txa_wrap_v;
510 }
511 
512 
513 /**
514  * Returns the SourceTextureImage corresponding to the given filename(s). If
515  * the given filename has never been used as a SourceTexture for this
516  * particular texture, creates a new SourceTextureImage and returns that.
517  */
519 get_source(const Filename &filename, const Filename &alpha_filename,
520  int alpha_file_channel) {
521  string key = get_source_key(filename, alpha_filename, alpha_file_channel);
522 
523  Sources::iterator si;
524  si = _sources.find(key);
525  if (si != _sources.end()) {
526  return (*si).second;
527  }
528 
529  SourceTextureImage *source =
530  new SourceTextureImage(this, filename, alpha_filename, alpha_file_channel);
531  _sources.insert(Sources::value_type(key, source));
532 
533  // Clear out the preferred source image to force us to rederive this next
534  // time someone asks.
535  _preferred_source = nullptr;
536  _read_source_image = false;
537 
538  return source;
539 }
540 
541 /**
542  * Determines the preferred source image for examining size and reading
543  * pixels, etc. This is the largest and most recent of all the available
544  * source images.
545  */
548  if (_preferred_source != nullptr) {
549  return _preferred_source;
550  }
551 
552  // Now examine all of the various source images available to us and pick the
553  // most suitable. We base this on the following criteria:
554 
555  // (1) A suitable source image must be referenced by at least one egg file,
556  // unless no source images are referenced by any egg file.
557 
558  // (2) A larger source image is preferable to a smaller one.
559 
560  // (3) Given two source images of the same size, the more recent one is
561  // preferable.
562 
563  // Are any source images referenced by an egg file?
564 
565  bool any_referenced = false;
566  Sources::iterator si;
567  for (si = _sources.begin(); si != _sources.end() && !any_referenced; ++si) {
568  SourceTextureImage *source = (*si).second;
569  if (source->get_egg_count() > 0) {
570  any_referenced = true;
571  }
572  }
573 
574  SourceTextureImage *best = nullptr;
575  int best_size = 0;
576 
577  for (si = _sources.begin(); si != _sources.end(); ++si) {
578  SourceTextureImage *source = (*si).second;
579 
580  if (source->get_egg_count() > 0 || !any_referenced) {
581  // Rule (1) passes.
582 
583  if (source->exists() && source->get_size()) {
584  int source_size = source->get_x_size() * source->get_y_size();
585  if (best == nullptr) {
586  best = source;
587  best_size = source_size;
588 
589  } else if (source_size > best_size) {
590  // Rule (2) passes.
591  best = source;
592  best_size = source_size;
593 
594  } else if (source_size == best_size &&
595  source->get_filename().compare_timestamps(best->get_filename()) > 0) {
596  // Rule (3) passes.
597  best = source;
598  best_size = source_size;
599  }
600  }
601  }
602  }
603 
604  if (best == nullptr && !_sources.empty()) {
605  // If we didn't pick any that pass, it must be that all of them are
606  // unreadable. In this case, it really doesn't matter which one we pick,
607  // but we should at least pick one that has an egg reference, if any of
608  // them do.
609  if (any_referenced) {
610  for (si = _sources.begin();
611  si != _sources.end() && best == nullptr;
612  ++si) {
613  SourceTextureImage *source = (*si).second;
614  if (source->get_egg_count() > 0) {
615  best = source;
616  }
617  }
618  } else {
619  best = (*_sources.begin()).second;
620  }
621  }
622 
623  _preferred_source = best;
624  return _preferred_source;
625 }
626 
627 /**
628  * Calls clear_basic_properties() on each source texture image used by this
629  * texture, to reset the properties in preparation for re-applying them from
630  * the set of all known egg files.
631  */
632 void TextureImage::
634  Sources::iterator si;
635  for (si = _sources.begin(); si != _sources.end(); ++si) {
636  SourceTextureImage *source = (*si).second;
637  source->clear_basic_properties();
638  }
639 }
640 
641 /**
642  * Copies the texture to whichever destination directories are appropriate for
643  * the groups in which it has been unplaced. Also removes the old filenames
644  * for previous sessions where it was unplaced, but is no longer.
645  *
646  * If redo_all is true, this recopies the texture whether it needed to or not.
647  */
648 void TextureImage::
649 copy_unplaced(bool redo_all) {
650  // First, we need to build up the set of DestTextureImages that represents
651  // the files we need to generate.
652  Dests generate;
653 
654  // Go through all the TexturePlacements and note the ones for which we're
655  // unplaced. We check get_omit_reason() and not is_placed(), because we
656  // want to consider solitary images to be unplaced in this case.
657  Placement::iterator pi;
658  for (pi = _placement.begin(); pi != _placement.end(); ++pi) {
659  TexturePlacement *placement = (*pi).second;
660  if (placement->get_omit_reason() != OR_none &&
661  placement->get_omit_reason() != OR_unknown) {
662  DestTextureImage *dest = new DestTextureImage(placement);
663  Filename filename = dest->get_filename();
665 
666  std::pair<Dests::iterator, bool> insert_result = generate.insert
667  (Dests::value_type(filename, dest));
668  if (!insert_result.second) {
669  // At least two DestTextureImages map to the same filename, no sweat.
670  delete dest;
671  dest = (*insert_result.first).second;
672  }
673 
674  placement->set_dest(dest);
675 
676  } else {
677  placement->set_dest(nullptr);
678  }
679  }
680 
681  if (redo_all) {
682  // If we're redoing everything, we remove everything first and then recopy
683  // it again.
684  Dests empty;
685  remove_old_dests(empty, _dests);
686  copy_new_dests(generate, empty);
687 
688  } else {
689  // Otherwise, we only remove and recopy the things that changed between
690  // this time and last time.
691  remove_old_dests(generate, _dests);
692  copy_new_dests(generate, _dests);
693  }
694 
695  // Clean up the old set.
696  Dests::iterator di;
697  for (di = _dests.begin(); di != _dests.end(); ++di) {
698  delete (*di).second;
699  }
700 
701  _dests.swap(generate);
702 }
703 
704 /**
705  * Reads in the original image, if it has not already been read, and returns
706  * it.
707  */
710  if (!_read_source_image) {
712  if (source != nullptr) {
713  source->read(_source_image);
714  }
715  _read_source_image = true;
716  _allow_release_source_image = true;
717  _ever_read_image = true;
718  }
719 
720  return _source_image;
721 }
722 
723 /**
724  * Frees the memory that was allocated by a previous call to
725  * read_source_image(). The next time read_source_image() is called, it will
726  * have to read the disk again.
727  */
728 void TextureImage::
730  if (_read_source_image && _allow_release_source_image) {
731  _source_image.clear();
732  _read_source_image = false;
733  }
734 }
735 
736 /**
737  * Accepts the indicated source image as if it had been read from disk. This
738  * image is copied into the structure, and will be returned by future calls to
739  * read_source_image().
740  */
741 void TextureImage::
742 set_source_image(const PNMImage &image) {
743  _source_image = image;
744  _allow_release_source_image = false;
745  _read_source_image = true;
746  _ever_read_image = true;
747 }
748 
749 /**
750  * Causes the header part of the image to be reread, usually to confirm that
751  * its image properties (size, number of channels, etc.) haven't changed.
752  */
753 void TextureImage::
755  if (!_read_source_image) {
757  if (source != nullptr) {
758  source->read_header();
759  }
760  }
761 }
762 
763 /**
764  * Returns true if the source image is newer than the indicated file, false
765  * otherwise. If the image has already been read, this always returns false.
766  */
767 bool TextureImage::
768 is_newer_than(const Filename &reference_filename) {
769  if (!_read_source_image) {
771  if (source != nullptr) {
772  const Filename &source_filename = source->get_filename();
773  return source_filename.compare_timestamps(reference_filename) >= 0;
774  }
775  }
776 
777  return false;
778 }
779 
780 /**
781  * Writes the list of source pathnames that might contribute to this texture
782  * to the indicated output stream, one per line.
783  */
784 void TextureImage::
785 write_source_pathnames(std::ostream &out, int indent_level) const {
786  Sources::const_iterator si;
787  for (si = _sources.begin(); si != _sources.end(); ++si) {
788  SourceTextureImage *source = (*si).second;
789 
790  if (source->get_egg_count() > 0) {
791  indent(out, indent_level);
792  source->output_filename(out);
793  if (!source->is_size_known()) {
794  out << " (unknown size)";
795 
796  } else {
797  out << " " << source->get_x_size() << " "
798  << source->get_y_size();
799 
800  if (source->get_properties().has_num_channels()) {
801  out << " " << source->get_properties().get_num_channels();
802  }
803  }
804  out << "\n";
805  }
806  }
807 
808  if (_is_cutout) {
809  indent(out, indent_level)
810  << "Cutout image (ratio " << (PN_stdfloat)_mid_pixel_ratio << ")\n";
811  }
812 
813  // Now write out the group assignments.
814  if (!_egg_files.empty()) {
815  // Sort the egg files into order by name for output.
816  pvector<EggFile *> egg_vector;
817  egg_vector.reserve(_egg_files.size());
818  EggFiles::const_iterator ei;
819  for (ei = _egg_files.begin(); ei != _egg_files.end(); ++ei) {
820  egg_vector.push_back(*ei);
821  }
822  sort(egg_vector.begin(), egg_vector.end(),
824 
825  indent(out, indent_level)
826  << "Used by:\n";
828  for (evi = egg_vector.begin(); evi != egg_vector.end(); ++evi) {
829  EggFile *egg = (*evi);
830  indent(out, indent_level + 2)
831  << egg->get_name() << " (";
832  if (egg->get_explicit_groups().empty()) {
833  out << *egg->get_default_group();
834  } else {
835  out << egg->get_explicit_groups();
836  }
837  out << ")\n";
838  }
839  }
840  if (!_explicitly_assigned_groups.empty()) {
841  indent(out, indent_level)
842  << "Explicitly assigned to " << _explicitly_assigned_groups << " in .txa\n";
843  }
844 
845  if (_placement.empty()) {
846  indent(out, indent_level)
847  << "Not used.\n";
848  } else {
849  indent(out, indent_level)
850  << "Assigned to " << _actual_assigned_groups << "\n";
851  }
852 }
853 
854 /**
855  * Writes the information about the texture's size and placement.
856  */
857 void TextureImage::
858 write_scale_info(std::ostream &out, int indent_level) {
860  indent(out, indent_level) << get_name();
861 
862  // Write the list of groups we're placed in.
863  if (_placement.empty()) {
864  out << " (not used)";
865  } else {
866  Placement::const_iterator pi;
867  pi = _placement.begin();
868  out << " (" << (*pi).second->get_group()->get_name();
869  ++pi;
870  while (pi != _placement.end()) {
871  out << " " << (*pi).second->get_group()->get_name();
872  ++pi;
873  }
874  out << ")";
875  }
876 
877  out << " orig ";
878 
879  if (source == nullptr ||
880  !source->is_size_known()) {
881  out << "unknown";
882  } else {
883  out << source->get_x_size() << " " << source->get_y_size()
884  << " " << source->get_num_channels();
885  }
886 
887  if (!_placement.empty() && is_size_known()) {
888  out << " new " << get_x_size() << " " << get_y_size()
889  << " " << get_num_channels();
890 
891  if (source != nullptr &&
892  source->is_size_known()) {
893  double scale =
894  100.0 * (((double)get_x_size() / (double)source->get_x_size()) +
895  ((double)get_y_size() / (double)source->get_y_size())) / 2.0;
896  out << " scale " << scale << "%";
897  }
898  }
899  out << "\n";
900 
901  // Also cross-reference the placed and unplaced information.
902  Placement::iterator pi;
903  for (pi = _placement.begin(); pi != _placement.end(); ++pi) {
904  TexturePlacement *placement = (*pi).second;
905  if (placement->get_omit_reason() == OR_none) {
906  PaletteImage *image = placement->get_image();
907  nassertv(image != nullptr);
908  indent(out, indent_level + 2)
909  << "placed on "
911  << "\n";
912 
913  } else if (placement->get_omit_reason() == OR_unknown) {
914  indent(out, indent_level + 2)
915  << "not placed because unknown.\n";
916 
917  } else {
918  DestTextureImage *image = placement->get_dest();
919  nassertv(image != nullptr);
920  indent(out, indent_level + 2)
921  << "copied to "
923  if (image->is_size_known() && is_size_known() &&
924  (image->get_x_size() != get_x_size() ||
925  image->get_y_size() != get_y_size())) {
926  out << " at size " << image->get_x_size() << " "
927  << image->get_y_size();
928  if (source != nullptr &&
929  source->is_size_known()) {
930  double scale =
931  100.0 * (((double)image->get_x_size() / (double)source->get_x_size()) +
932  ((double)image->get_y_size() / (double)source->get_y_size())) / 2.0;
933  out << " scale " << scale << "%";
934  }
935  }
936  out << "\n";
937  }
938  }
939 }
940 
941 /**
942  * Counts the number of egg files in the indicated set that will be satisfied
943  * if a texture is assigned to the indicated group.
944  */
945 int TextureImage::
946 compute_egg_count(PaletteGroup *group,
947  const TextureImage::WorkingEggs &egg_files) {
948  int count = 0;
949 
950  WorkingEggs::const_iterator ei;
951  for (ei = egg_files.begin(); ei != egg_files.end(); ++ei) {
952  if ((*ei)->get_complete_groups().count(group) != 0) {
953  count++;
954  }
955  }
956 
957  return count;
958 }
959 
960 /**
961  * Assigns the texture to the indicated set of groups. If the texture was
962  * previously assigned to any of these groups, keeps the same TexturePlacement
963  * object for the assignment; at the same time, deletes any TexturePlacement
964  * objects that represent groups we are no longer assigned to.
965  */
966 void TextureImage::
967 assign_to_groups(const PaletteGroups &groups) {
968  PaletteGroups::const_iterator gi;
969  Placement::const_iterator pi;
970 
971  Placement new_placement;
972 
973  gi = groups.begin();
974  pi = _placement.begin();
975 
976  while (gi != groups.end() && pi != _placement.end()) {
977  PaletteGroup *a = (*gi);
978  PaletteGroup *b = (*pi).first;
979 
980  if (a < b) {
981  // Here's a group we're now assigned to that we weren't assigned to
982  // previously.
983  TexturePlacement *place = a->prepare(this);
984  new_placement.insert
985  (new_placement.end(), Placement::value_type(a, place));
986  ++gi;
987 
988  } else if (b < a) {
989  // Here's a group we're no longer assigned to.
990  TexturePlacement *place = (*pi).second;
991  delete place;
992  ++pi;
993 
994  } else { // b == a
995  // Here's a group we're still assigned to.
996  TexturePlacement *place = (*pi).second;
997  new_placement.insert
998  (new_placement.end(), Placement::value_type(a, place));
999  ++gi;
1000  ++pi;
1001  }
1002  }
1003 
1004  while (gi != groups.end()) {
1005  // Here's a group we're now assigned to that we weren't assigned to
1006  // previously.
1007  PaletteGroup *a = (*gi);
1008  TexturePlacement *place = a->prepare(this);
1009  new_placement.insert
1010  (new_placement.end(), Placement::value_type(a, place));
1011  ++gi;
1012  }
1013 
1014  while (pi != _placement.end()) {
1015  // Here's a group we're no longer assigned to.
1016  TexturePlacement *place = (*pi).second;
1017  delete place;
1018  ++pi;
1019  }
1020 
1021  _placement.swap(new_placement);
1022  _actual_assigned_groups = groups;
1023 }
1024 
1025 /**
1026  * Examines the actual contents of the image to determine if it should maybe
1027  * be considered a grayscale image (even though it has separate rgb
1028  * components).
1029  */
1030 void TextureImage::
1031 consider_grayscale() {
1032  // Since this isn't likely to change for a particular texture after its
1033  // creation, we save a bit of time by not performing this check unless this
1034  // is the first time we've ever seen this texture. This will save us from
1035  // having to load the texture images each time we look at them. On the
1036  // other hand, if we've already loaded up the image, then go ahead.
1037  if (!_read_source_image && _ever_read_image) {
1038  if (_forced_grayscale) {
1039  _properties.force_grayscale();
1040  }
1041  return;
1042  }
1043 
1044  const PNMImage &source = read_source_image();
1045  if (!source.is_valid()) {
1046  return;
1047  }
1048 
1049  for (int y = 0; y < source.get_y_size(); y++) {
1050  for (int x = 0; x < source.get_x_size(); x++) {
1051  const xel &v = source.get_xel_val(x, y);
1052  if (PPM_GETR(v) != PPM_GETG(v) || PPM_GETR(v) != PPM_GETB(v)) {
1053  // Here's a colored pixel. We can't go grayscale.
1054  _forced_grayscale = false;
1055  return;
1056  }
1057  }
1058  }
1059 
1060  // All pixels in the image were grayscale!
1061  _properties.force_grayscale();
1062  _forced_grayscale = true;
1063 }
1064 
1065 /**
1066  * Examines the actual contents of the image to determine what alpha
1067  * properties it has.
1068  */
1069 void TextureImage::
1070 consider_alpha() {
1071  // As above, we don't bother doing this if we've already done this in a
1072  // previous session.
1073 
1074  // _alpha_bits == -1 indicates we have read an older textures.boo file that
1075  // didn't define these bits.
1076  if (_read_source_image || !_ever_read_image || _alpha_bits == -1) {
1077  _alpha_bits = 0;
1078  int num_mid_pixels = 0;
1079 
1080  const PNMImage &source = read_source_image();
1081  if (source.is_valid() && source.has_alpha()) {
1082  xelval maxval = source.get_maxval();
1083  for (int y = 0; y < source.get_y_size(); y++) {
1084  for (int x = 0; x < source.get_x_size(); x++) {
1085  xelval alpha_val = source.get_alpha_val(x, y);
1086  if (alpha_val == 0) {
1087  _alpha_bits |= AB_zero;
1088  } else if (alpha_val == maxval) {
1089  _alpha_bits |= AB_one;
1090  } else {
1091  _alpha_bits |= AB_mid;
1092  ++num_mid_pixels;
1093  }
1094  }
1095  }
1096  }
1097 
1098  int num_pixels = source.get_x_size() * source.get_y_size();
1099  _mid_pixel_ratio = 0.0;
1100  if (num_pixels != 0) {
1101  _mid_pixel_ratio = (double)num_mid_pixels / (double)num_pixels;
1102  }
1103  }
1104 
1105  _is_cutout = false;
1106 
1107  if (_alpha_bits != 0) {
1108  if (_alpha_bits == AB_one) {
1109  // All alpha pixels are white; drop the alpha channel.
1110  _properties.force_nonalpha();
1111 
1112  } else if (_alpha_bits == AB_zero) {
1113  // All alpha pixels are invisible; this is probably a mistake. Drop the
1114  // alpha channel and complain.
1115  _properties.force_nonalpha();
1116  if (_read_source_image) {
1117  nout << *this << " has an all-zero alpha channel; dropping alpha.\n";
1118  }
1119 
1120  } else if (_alpha_mode == EggRenderMode::AM_unspecified) {
1121  // Consider fiddling with the alpha mode, if the user hasn't specified a
1122  // particular alpha mode in the txa file.
1123  if ((_alpha_bits & AB_mid) == 0) {
1124  // No middle range bits: a binary alpha image.
1125  _alpha_mode = EggRenderMode::AM_binary;
1126 
1127  } else if ((_alpha_bits & AB_one) != 0 && _mid_pixel_ratio < pal->_cutout_ratio) {
1128  // At least some opaque bits, and relatively few middle range bits: a
1129  // cutout image.
1130  _alpha_mode = pal->_cutout_mode;
1131  _is_cutout = true;
1132 
1133  } else {
1134  // No opaque bits; just use regular alpha blending.
1135  _alpha_mode = EggRenderMode::AM_blend;
1136  }
1137  }
1138  }
1139 }
1140 
1141 /**
1142  * Removes all of the filenames named in b that are not also named in a.
1143  */
1144 void TextureImage::
1145 remove_old_dests(const TextureImage::Dests &a, const TextureImage::Dests &b) {
1146  Dests::const_iterator ai = a.begin();
1147  Dests::const_iterator bi = b.begin();
1148 
1149  while (ai != a.end() && bi != b.end()) {
1150  const string &astr = (*ai).first;
1151  const string &bstr = (*bi).first;
1152 
1153  if (astr < bstr) {
1154  // Here's a filename in a, not in b.
1155  ++ai;
1156 
1157  } else if (bstr < astr) {
1158  // Here's a filename in b, not in a.
1159  (*bi).second->unlink();
1160  ++bi;
1161 
1162  } else { // bstr == astr
1163  // Here's a filename in both a and b.
1164  ++ai;
1165  ++bi;
1166  }
1167  }
1168 
1169  while (bi != b.end()) {
1170  // Here's a filename in b, not in a.
1171  (*bi).second->unlink();
1172  ++bi;
1173  }
1174 
1175  while (ai != a.end()) {
1176  ++ai;
1177  }
1178 }
1179 
1180 /**
1181  * Copies a resized texture into each filename named in a that is not also
1182  * listed in b, or whose corresponding listing in b is out of date.
1183  */
1184 void TextureImage::
1185 copy_new_dests(const TextureImage::Dests &a, const TextureImage::Dests &b) {
1186  Dests::const_iterator ai = a.begin();
1187  Dests::const_iterator bi = b.begin();
1188 
1189  while (ai != a.end() && bi != b.end()) {
1190  const string &astr = (*ai).first;
1191  const string &bstr = (*bi).first;
1192 
1193  if (astr < bstr) {
1194  // Here's a filename in a, not in b.
1195  (*ai).second->copy(this);
1196  ++ai;
1197 
1198  } else if (bstr < astr) {
1199  // Here's a filename in b, not in a.
1200  ++bi;
1201 
1202  } else { // bstr == astr
1203  // Here's a filename in both a and b.
1204  (*ai).second->copy_if_stale((*bi).second, this);
1205  ++ai;
1206  ++bi;
1207  }
1208  }
1209 
1210  while (ai != a.end()) {
1211  // Here's a filename in a, not in b.
1212  (*ai).second->copy(this);
1213  ++ai;
1214  }
1215 }
1216 
1217 /**
1218  * Returns the key that a SourceTextureImage should be stored in, given its
1219  * one or two filenames.
1220  */
1221 string TextureImage::
1222 get_source_key(const Filename &filename, const Filename &alpha_filename,
1223  int alpha_file_channel) {
1225  Filename a = FilenameUnifier::make_bam_filename(alpha_filename);
1226 
1227  return f.get_fullpath() + ":" + a.get_fullpath() + ":" +
1228  format_string(alpha_file_channel);
1229 }
1230 
1231 /**
1232  * Registers the current object as something that can be read from a Bam file.
1233  */
1234 void TextureImage::
1237  register_factory(get_class_type(), make_TextureImage);
1238 }
1239 
1240 /**
1241  * Fills the indicated datagram up with a binary representation of the current
1242  * object, in preparation for writing to a Bam file.
1243  */
1244 void TextureImage::
1245 write_datagram(BamWriter *writer, Datagram &datagram) {
1246  ImageFile::write_datagram(writer, datagram);
1247  datagram.add_string(get_name());
1248 
1249  // We don't write out _request; this is re-read from the .txa file each
1250  // time.
1251 
1252  // We don't write out _pre_txa_properties; this is transitional.
1253 
1254  // We don't write out _preferred_source; this is redetermined each session.
1255 
1256  datagram.add_bool(_is_surprise);
1257  datagram.add_bool(_ever_read_image);
1258  datagram.add_bool(_forced_grayscale);
1259  datagram.add_uint8(_alpha_bits);
1260  datagram.add_int16((int)_alpha_mode);
1261  datagram.add_float64(_mid_pixel_ratio);
1262  datagram.add_bool(_is_cutout);
1263  datagram.add_uint8((int)_txa_wrap_u);
1264  datagram.add_uint8((int)_txa_wrap_v);
1265 
1266  // We don't write out _explicitly_assigned_groups; this is re-read from the
1267  // .txa file each time.
1268 
1269  _actual_assigned_groups.write_datagram(writer, datagram);
1270 
1271  // We don't write out _egg_files; this is redetermined each session.
1272 
1273  datagram.add_uint32(_placement.size());
1274  Placement::const_iterator pi;
1275  for (pi = _placement.begin(); pi != _placement.end(); ++pi) {
1276  writer->write_pointer(datagram, (*pi).first);
1277  writer->write_pointer(datagram, (*pi).second);
1278  }
1279 
1280  datagram.add_uint32(_sources.size());
1281  Sources::const_iterator si;
1282  for (si = _sources.begin(); si != _sources.end(); ++si) {
1283  writer->write_pointer(datagram, (*si).second);
1284  }
1285 
1286  datagram.add_uint32(_dests.size());
1287  Dests::const_iterator di;
1288  for (di = _dests.begin(); di != _dests.end(); ++di) {
1289  writer->write_pointer(datagram, (*di).second);
1290  }
1291 }
1292 
1293 /**
1294  * Called after the object is otherwise completely read from a Bam file, this
1295  * function's job is to store the pointers that were retrieved from the Bam
1296  * file for each pointer object written. The return value is the number of
1297  * pointers processed from the list.
1298  */
1299 int TextureImage::
1301  int pi = ImageFile::complete_pointers(p_list, manager);
1302 
1303  pi += _actual_assigned_groups.complete_pointers(p_list + pi, manager);
1304 
1305  int i;
1306  for (i = 0; i < _num_placement; i++) {
1307  PaletteGroup *group;
1308  TexturePlacement *placement;
1309  DCAST_INTO_R(group, p_list[pi++], pi);
1310  DCAST_INTO_R(placement, p_list[pi++], pi);
1311  _placement.insert(Placement::value_type(group, placement));
1312  }
1313 
1314  for (i = 0; i < _num_sources; i++) {
1315  SourceTextureImage *source;
1316  DCAST_INTO_R(source, p_list[pi++], pi);
1317  string key = get_source_key(source->get_filename(),
1318  source->get_alpha_filename(),
1319  source->get_alpha_file_channel());
1320 
1321  bool inserted = _sources.insert(Sources::value_type(key, source)).second;
1322  if (!inserted) {
1323  nout << "Warning: texture key " << key
1324  << " is nonunique; texture lost.\n";
1325  }
1326  }
1327 
1328  for (i = 0; i < _num_dests; i++) {
1329  DestTextureImage *dest;
1330  DCAST_INTO_R(dest, p_list[pi++], pi);
1331  bool inserted = _dests.insert(Dests::value_type(dest->get_filename(), dest)).second;
1332  if (!inserted) {
1333  nout << "Warning: dest filename " << dest->get_filename()
1334  << " is nonunique; texture lost.\n";
1335  }
1336  }
1337 
1338  return pi;
1339 }
1340 
1341 /**
1342  * This method is called by the BamReader when an object of this type is
1343  * encountered in a Bam file; it should allocate and return a new object with
1344  * all the data read.
1345  */
1346 TypedWritable *TextureImage::
1347 make_TextureImage(const FactoryParams &params) {
1348  TextureImage *me = new TextureImage;
1349  DatagramIterator scan;
1350  BamReader *manager;
1351 
1352  parse_params(params, scan, manager);
1353  me->fillin(scan, manager);
1354  return me;
1355 }
1356 
1357 /**
1358  * Reads the binary data from the given datagram iterator, which was written
1359  * by a previous call to write_datagram().
1360  */
1361 void TextureImage::
1362 fillin(DatagramIterator &scan, BamReader *manager) {
1363  ImageFile::fillin(scan, manager);
1364  set_name(scan.get_string());
1365 
1366  _is_surprise = scan.get_bool();
1367  _ever_read_image = scan.get_bool();
1368  _forced_grayscale = scan.get_bool();
1369  _alpha_bits = scan.get_uint8();
1370  _alpha_mode = (EggRenderMode::AlphaMode)scan.get_int16();
1371  if (pal->_read_pi_version >= 16) {
1372  _mid_pixel_ratio = scan.get_float64();
1373  _is_cutout = scan.get_bool();
1374  } else {
1375  // Force a re-read of the image if we are upgrading to pi version 16.
1376  _ever_read_image = false;
1377  _mid_pixel_ratio = 0.0;
1378  _is_cutout = false;
1379  }
1380  if (pal->_read_pi_version >= 17) {
1381  _txa_wrap_u = (EggTexture::WrapMode)scan.get_uint8();
1382  _txa_wrap_v = (EggTexture::WrapMode)scan.get_uint8();
1383  }
1384 
1385  _actual_assigned_groups.fillin(scan, manager);
1386 
1387  _num_placement = scan.get_uint32();
1388  manager->read_pointers(scan, _num_placement * 2);
1389 
1390  _num_sources = scan.get_uint32();
1391  manager->read_pointers(scan, _num_sources);
1392  _num_dests = scan.get_uint32();
1393  manager->read_pointers(scan, _num_dests);
1394 }
destTextureImage.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TextureImage::got_txa_file
bool got_txa_file() const
Returns true if this TextureImage has been looked up in the .txa file this session,...
Definition: textureImage.cxx:412
ImageFile::complete_pointers
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...
Definition: imageFile.cxx:454
PaletteGroups::make_union
void make_union(const PaletteGroups &a, const PaletteGroups &b)
Computes the union of PaletteGroups a and b, and stores the result in this object.
Definition: paletteGroups.cxx:91
DatagramIterator::get_string
std::string get_string()
Extracts a variable-length string.
Definition: datagramIterator.cxx:26
indent
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
ImageFile::get_y_size
int get_y_size() const
Returns the size of the image file in pixels in the Y direction.
Definition: imageFile.cxx:92
TextureImage::get_source
SourceTextureImage * get_source(const Filename &filename, const Filename &alpha_filename, int alpha_file_channel)
Returns the SourceTextureImage corresponding to the given filename(s).
Definition: textureImage.cxx:519
PaletteImage
This is a single palette image, one of several within a PalettePage, which is in turn one of several ...
Definition: paletteImage.h:32
TextureImage::assign_groups
void assign_groups()
Assigns the texture to all of the PaletteGroups the various egg files that use it need.
Definition: textureImage.cxx:76
TexturePlacement::set_dest
void set_dest(DestTextureImage *dest)
Sets the DestTextureImage that corresponds to this texture as it was copied to the install directory.
Definition: texturePlacement.cxx:173
TextureImage::read_header
void read_header()
Causes the header part of the image to be reread, usually to confirm that its image properties (size,...
Definition: textureImage.cxx:754
ImageFile::write_datagram
virtual void write_datagram(BamWriter *writer, Datagram &datagram)
Fills the indicated datagram up with a binary representation of the current object,...
Definition: imageFile.cxx:436
PaletteGroup
This is the highest level of grouping for TextureImages.
Definition: paletteGroup.h:43
EggFile
This represents a single egg file known to the palettizer.
Definition: eggFile.h:36
PaletteGroups::write_datagram
virtual void write_datagram(BamWriter *writer, Datagram &datagram)
Fills the indicated datagram up with a binary representation of the current object,...
Definition: paletteGroups.cxx:291
pvector< EggFile * >
DatagramIterator::get_int16
int16_t get_int16()
Extracts a signed 16-bit integer.
Definition: datagramIterator.I:88
FilenameUnifier::make_bam_filename
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...
Definition: filenameUnifier.cxx:61
PaletteGroups::complete_pointers
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...
Definition: paletteGroups.cxx:308
TextureImage::get_coverage_threshold
double get_coverage_threshold() const
Returns the appropriate coverage threshold for this texture.
Definition: textureImage.cxx:446
SourceTextureImage::get_egg_count
int get_egg_count() const
Returns the number of egg files that share this SourceTextureImage.
Definition: sourceTextureImage.cxx:75
TextureImage::complete_pointers
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...
Definition: textureImage.cxx:1300
string_utils.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PNMImage::clear
void clear()
Frees all memory allocated for the image, and clears all its parameters (size, color,...
Definition: pnmImage.cxx:48
pvector.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ImageFile::get_filename
const Filename & get_filename() const
Returns the primary filename of the image file.
Definition: imageFile.cxx:225
PNMImage::get_alpha_val
xelval get_alpha_val(int x, int y) const
Returns the alpha component color at the indicated pixel.
Definition: pnmImage.I:494
PNMImage::is_valid
bool is_valid() const
Returns true if the image has been read in or correctly initialized with a height and width.
Definition: pnmImage.I:342
Datagram::add_uint8
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
Definition: datagram.I:50
DatagramIterator
A class to retrieve the individual data elements previously stored in a Datagram.
Definition: datagramIterator.h:27
pmap< std::string, DestTextureImage * >
BamReader
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
TextureRequest::pre_txa_file
void pre_txa_file()
Sets some state up that must be set prior to reading the .txa file.
Definition: textureRequest.cxx:46
ImageFile::output_filename
void output_filename(std::ostream &out) const
Writes the filename (or pair of filenames) to the indicated output stream.
Definition: imageFile.cxx:424
EggFile::get_complete_groups
const PaletteGroups & get_complete_groups() const
Returns the complete set of PaletteGroups that the egg file is assigned to.
Definition: eggFile.cxx:276
IndirectCompareNames
An STL function object class, this is intended to be used on any ordered collection of pointers to cl...
Definition: indirectCompareNames.h:26
TextureImage::mark_eggs_stale
void mark_eggs_stale()
Marks all the egg files that reference this texture stale.
Definition: textureImage.cxx:234
PNMImageHeader::get_maxval
get_maxval
Returns the maximum channel value allowable for any pixel in this image; for instance,...
Definition: pnmImageHeader.h:70
TextureProperties::get_num_channels
int get_num_channels() const
Returns the number of channels (1 through 4) associated with the image.
Definition: textureProperties.cxx:117
BamWriter
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
TextureImage::pre_txa_file
void pre_txa_file()
Updates any internal state prior to reading the .txa file.
Definition: textureImage.cxx:265
BamWriter::write_pointer
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
Definition: bamWriter.cxx:317
texturePlacement.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PaletteGroups::empty
bool empty() const
Returns true if the set is empty, false otherwise.
Definition: paletteGroups.cxx:184
BamReader::get_factory
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
PaletteGroup::is_preferred_over
bool is_preferred_over(const PaletteGroup &other) const
Returns true if this group should be preferred for adding textures over the other group,...
Definition: paletteGroup.cxx:292
ImageFile::get_num_channels
int get_num_channels() const
Returns the number of channels of the image.
Definition: imageFile.cxx:111
bamReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TextureImage::read_source_image
const PNMImage & read_source_image()
Reads in the original image, if it has not already been read, and returns it.
Definition: textureImage.cxx:709
textureImage.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PNMImage::get_xel_val
xel & get_xel_val(int x, int y)
Returns the RGB color at the indicated pixel.
Definition: pnmImage.I:398
TypedWritable
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
PNMImage
The name of this class derives from the fact that we originally implemented it as a layer on top of t...
Definition: pnmImage.h:58
Datagram
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
PNMImageHeader::get_x_size
int get_x_size() const
Returns the number of pixels in the X direction.
Definition: pnmImageHeader.I:144
DatagramIterator::get_float64
PN_float64 get_float64()
Extracts a 64-bit floating-point number.
Definition: datagramIterator.I:221
SourceTextureImage
This is a texture image reference as it appears in an egg file: the source image of the texture.
Definition: sourceTextureImage.h:28
TextureImage::post_txa_file
void post_txa_file()
Once the .txa file has been read and the TextureImage matched against it, considers applying the requ...
Definition: textureImage.cxx:289
EggFile::get_default_group
PaletteGroup * get_default_group() const
Returns the PaletteGroup that was specified as the default group on the command line at the time the ...
Definition: eggFile.cxx:266
TextureImage::get_omit
bool get_omit() const
Returns true if the user specifically requested to omit this texture via the "omit" keyword in the ....
Definition: textureImage.cxx:435
ImageFile::get_alpha_filename
const Filename & get_alpha_filename() const
Returns the alpha filename of the image file.
Definition: imageFile.cxx:235
Datagram::add_string
void add_string(const std::string &str)
Adds a variable-length string to the datagram.
Definition: datagram.I:219
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
ImageFile::exists
bool exists() const
Returns true if the file or files named by the image file exist, false otherwise.
Definition: imageFile.cxx:256
PaletteGroups::remove_null
void remove_null()
Removes the special "null" group from the set.
Definition: paletteGroups.cxx:162
TexturePlacement::get_omit_reason
OmitReason get_omit_reason() const
Returns the reason the texture has been omitted from a palette image, or OR_none if it has not.
Definition: texturePlacement.cxx:401
paletteImage.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PaletteGroups::insert
void insert(PaletteGroup *group)
Inserts a new group to the set, if it is not already there.
Definition: paletteGroups.cxx:55
ImageFile::get_alpha_file_channel
int get_alpha_file_channel() const
Returns the particular channel number of the alpha image file from which the alpha channel should be ...
Definition: imageFile.cxx:246
BamReader::read_pointers
void read_pointers(DatagramIterator &scan, int count)
A convenience function to read a contiguous list of pointers.
Definition: bamReader.cxx:653
filenameUnifier.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
DatagramIterator::get_bool
bool get_bool()
Extracts a boolean value.
Definition: datagramIterator.I:48
FactoryParams
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
TextureImage::is_surprise
bool is_surprise() const
Returns true if this particular texture is a 'surprise', i.e.
Definition: textureImage.cxx:465
SourceTextureImage::get_size
bool get_size()
Determines the size of the SourceTextureImage, if it is not already known.
Definition: sourceTextureImage.cxx:87
PNMImageHeader::get_y_size
int get_y_size() const
Returns the number of pixels in the Y direction.
Definition: pnmImageHeader.I:153
TexturePlacement::get_image
PaletteImage * get_image() const
Returns the particular PaletteImage on which the texture has been placed.
Definition: texturePlacement.cxx:456
TextureProperties::has_num_channels
bool has_num_channels() const
Returns true if the number of channels is known.
Definition: textureProperties.cxx:108
FilenameUnifier::make_canonical
static void make_canonical(Filename &filename)
Does the same thing as Filename::make_canonical()–it converts the filename to its canonical form–but ...
Definition: filenameUnifier.cxx:111
ImageFile::get_properties
const TextureProperties & get_properties() const
Returns the grouping properties of the image.
Definition: imageFile.cxx:119
ImageFile::read
bool read(PNMImage &image) const
Reads in the image (or images, if the alpha_filename is separate) and stores it in the indicated PNMI...
Definition: imageFile.cxx:277
TextureImage::note_egg_file
void note_egg_file(EggFile *egg_file)
Records that a particular egg file references this texture.
Definition: textureImage.cxx:65
TextureImage::get_groups
const PaletteGroups & get_groups() const
Once assign_groups() has been called, this returns the actual set of groups the TextureImage has been...
Definition: textureImage.cxx:194
EggFile::get_explicit_groups
const PaletteGroups & get_explicit_groups() const
Returns the set of PaletteGroups that the egg file has been explicitly assigned to in the ....
Definition: eggFile.cxx:257
PaletteGroups::begin
iterator begin() const
Returns an iterator suitable for traversing the set.
Definition: paletteGroups.cxx:200
TextureImage::release_source_image
void release_source_image()
Frees the memory that was allocated by a previous call to read_source_image().
Definition: textureImage.cxx:729
Filename::get_fullpath
std::string get_fullpath() const
Returns the entire filename: directory, basename, extension.
Definition: filename.I:338
SourceTextureImage::read_header
bool read_header()
Reads the actual image header to determine the image properties, like its size.
Definition: sourceTextureImage.cxx:102
pnmFileType.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Datagram::add_int16
void add_int16(int16_t value)
Adds a signed 16-bit integer to the datagram.
Definition: datagram.I:58
TextureImage::set_source_image
void set_source_image(const PNMImage &image)
Accepts the indicated source image as if it had been read from disk.
Definition: textureImage.cxx:742
datagram.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TexturePlacement::mark_unfilled
void mark_unfilled()
Marks the texture as unfilled, so that it will need to be copied into the palette image again.
Definition: texturePlacement.cxx:685
TextureImage::is_used
bool is_used() const
Returns true if this particular texture has been placed somewhere, anywhere, or false if it is not us...
Definition: textureImage.cxx:480
TextureImage::clear_source_basic_properties
void clear_source_basic_properties()
Calls clear_basic_properties() on each source texture image used by this texture, to reset the proper...
Definition: textureImage.cxx:633
TextureImage::force_replace
void force_replace()
Removes the texture from any PaletteImages it is assigned to, but does not remove it from the groups.
Definition: textureImage.cxx:220
sourceTextureImage.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TextureImage::is_newer_than
bool is_newer_than(const Filename &reference_filename)
Returns true if the source image is newer than the indicated file, false otherwise.
Definition: textureImage.cxx:768
PNMImageHeader::has_alpha
static bool has_alpha(ColorType color_type)
This static variant of has_alpha() returns true if the indicated image type includes an alpha channel...
Definition: pnmImageHeader.I:106
pixel
Definition: pnmimage_base.h:41
PaletteGroups::make_intersection
void make_intersection(const PaletteGroups &a, const PaletteGroups &b)
Computes the intersection of PaletteGroups a and b, and stores the result in this object.
Definition: paletteGroups.cxx:132
ImageFile::clear_basic_properties
void clear_basic_properties()
Resets the properties to a neutral state, for instance in preparation for calling update_properties()...
Definition: imageFile.cxx:128
FilenameUnifier::make_user_filename
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...
Definition: filenameUnifier.cxx:97
TextureImage::write_scale_info
void write_scale_info(std::ostream &out, int indent_level=0)
Writes the information about the texture's size and placement.
Definition: textureImage.cxx:858
Datagram::add_uint32
void add_uint32(uint32_t value)
Adds an unsigned 32-bit integer to the datagram.
Definition: datagram.I:94
TexturePlacement
This corresponds to a particular assignment of a TextureImage with a PaletteGroup,...
Definition: texturePlacement.h:41
TextureImage::write_datagram
virtual void write_datagram(BamWriter *writer, Datagram &datagram)
Fills the indicated datagram up with a binary representation of the current object,...
Definition: textureImage.cxx:1245
TextureImage::get_txa_wrap_u
EggTexture::WrapMode get_txa_wrap_u() const
Returns the wrap mode specified in the u direction in the txa file, or WM_unspecified.
Definition: textureImage.cxx:499
Datagram::add_bool
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition: datagram.I:34
TextureImage::get_placement
TexturePlacement * get_placement(PaletteGroup *group) const
Gets the TexturePlacement object which represents the assignment of this texture to the indicated gro...
Definition: textureImage.cxx:204
TextureImage::get_txa_wrap_v
EggTexture::WrapMode get_txa_wrap_v() const
Returns the wrap mode specified in the v direction in the txa file, or WM_unspecified.
Definition: textureImage.cxx:508
TextureImage::copy_unplaced
void copy_unplaced(bool redo_all)
Copies the texture to whichever destination directories are appropriate for the groups in which it ha...
Definition: textureImage.cxx:649
ImageFile::is_size_known
bool is_size_known() const
Returns true if the size of the image file is known, false otherwise.
Definition: imageFile.cxx:73
TextureImage::determine_placement_size
void determine_placement_size()
Calls determine_size() on each TexturePlacement for the texture, to ensure that each TexturePlacement...
Definition: textureImage.cxx:422
Filename::compare_timestamps
int compare_timestamps(const Filename &other, bool this_missing_is_old=true, bool other_missing_is_old=true) const
Returns a number less than zero if the file named by this object is older than the given file,...
Definition: filename.cxx:1417
ImageFile::get_x_size
int get_x_size() const
Returns the size of the image file in pixels in the X direction.
Definition: imageFile.cxx:82
datagramIterator.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TextureImage::register_with_read_factory
static void register_with_read_factory()
Registers the current object as something that can be read from a Bam file.
Definition: textureImage.cxx:1235
indent.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TexturePlacement::get_dest
DestTextureImage * get_dest() const
Returns the DestTextureImage that corresponds to this texture as it was copied to the install directo...
Definition: texturePlacement.cxx:182
DatagramIterator::get_uint32
uint32_t get_uint32()
Extracts an unsigned 32-bit integer.
Definition: datagramIterator.I:164
DatagramIterator::get_uint8
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
Definition: datagramIterator.I:72
TextureImage::get_margin
int get_margin() const
Returns the appropriate margin for this texture.
Definition: textureImage.cxx:456
bamWriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PaletteGroups
A set of PaletteGroups.
Definition: paletteGroups.h:28
eggFile.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PaletteGroup::prepare
TexturePlacement * prepare(TextureImage *texture)
Marks the indicated Texture as ready for placing somewhere within this group, and returns a placehold...
Definition: paletteGroup.cxx:347
DestTextureImage
This represents a texture filename as it has been resized and copied to the map directory (e....
Definition: destTextureImage.h:28
TextureImage::write_source_pathnames
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...
Definition: textureImage.cxx:785
TextureImage::get_preferred_source
SourceTextureImage * get_preferred_source()
Determines the preferred source image for examining size and reading pixels, etc.
Definition: textureImage.cxx:547
TextureImage::mark_texture_named
void mark_texture_named()
Indicates that this particular texture has been named by the user for processing this session,...
Definition: textureImage.cxx:247
TextureImage::get_alpha_mode
EggRenderMode::AlphaMode get_alpha_mode() const
Returns the alpha mode that should be used to render objects with this texture, as specified by the u...
Definition: textureImage.cxx:490
paletteGroup.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Datagram::add_float64
void add_float64(PN_float64 value)
Adds a 64-bit floating-point number to the datagram.
Definition: datagram.I:123
parse_params
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
PaletteGroups::end
iterator end() const
Returns an iterator suitable for traversing the set.
Definition: paletteGroups.cxx:208
TextureImage::is_texture_named
bool is_texture_named() const
Returns true if this particular texture has been named by the user for procession this session,...
Definition: textureImage.cxx:257
TexturePlacement::determine_size
bool determine_size()
Attempts to determine the appropriate size of the texture for the given placement.
Definition: texturePlacement.cxx:196
TextureImage
This represents a single source texture that is referenced by one or more egg files.
Definition: textureImage.h:46
Filename
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
PaletteGroups::fillin
void fillin(DatagramIterator &scan, BamReader *manager)
Reads the binary data from the given datagram iterator, which was written by a previous call to write...
Definition: paletteGroups.cxx:339
indirectCompareNames.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.