Panda3D
texturePlacement.cxx
1 // Filename: texturePlacement.cxx
2 // Created by: drose (30Nov00)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "texturePlacement.h"
16 #include "textureReference.h"
17 #include "textureImage.h"
18 #include "paletteGroup.h"
19 #include "paletteImage.h"
20 #include "palettizer.h"
21 #include "eggFile.h"
22 #include "destTextureImage.h"
23 
24 #include "indent.h"
25 #include "datagram.h"
26 #include "datagramIterator.h"
27 #include "bamReader.h"
28 #include "bamWriter.h"
29 #include "pnmImage.h"
30 
31 TypeHandle TexturePlacement::_type_handle;
32 
33 ////////////////////////////////////////////////////////////////////
34 // Function: TexturePlacement::Default Constructor
35 // Access: Private
36 // Description: The default constructor is only for the convenience
37 // of the Bam reader.
38 ////////////////////////////////////////////////////////////////////
39 TexturePlacement::
40 TexturePlacement() {
41  _texture = (TextureImage *)NULL;
42  _group = (PaletteGroup *)NULL;
43  _image = (PaletteImage *)NULL;
44  _dest = (DestTextureImage *)NULL;
45  _has_uvs = false;
46  _size_known = false;
47  _is_filled = true;
48  _omit_reason = OR_none;
49 }
50 
51 ////////////////////////////////////////////////////////////////////
52 // Function: TexturePlacement::Constructor
53 // Access: Public
54 // Description:
55 ////////////////////////////////////////////////////////////////////
56 TexturePlacement::
57 TexturePlacement(TextureImage *texture, PaletteGroup *group) :
58  _texture(texture),
59  _group(group)
60 {
61  _omit_reason = OR_working;
62 
63  if (!texture->is_size_known()) {
64  // If we were never able to figure out what size the texture
65  // actually is, then we can't place the texture on a palette.
66  _omit_reason = OR_unknown;
67  }
68 
69  _image = (PaletteImage *)NULL;
70  _dest = (DestTextureImage *)NULL;
71  _has_uvs = false;
72  _size_known = false;
73  _is_filled = false;
74 }
75 
76 ////////////////////////////////////////////////////////////////////
77 // Function: TexturePlacement::Destructor
78 // Access: Public
79 // Description:
80 ////////////////////////////////////////////////////////////////////
81 TexturePlacement::
82 ~TexturePlacement() {
83  // Make sure we tell all our egg references they're not using us any
84  // more.
85  References::iterator ri;
86  References copy_references = _references;
87  for (ri = copy_references.begin(); ri != copy_references.end(); ++ri) {
88  TextureReference *reference = (*ri);
89  nassertv(reference->get_placement() == this);
90  reference->clear_placement();
91  }
92 
93  // And also our group, etc.
94  _group->unplace(this);
95 }
96 
97 ////////////////////////////////////////////////////////////////////
98 // Function: TexturePlacement::get_name
99 // Access: Public
100 // Description: Returns the name of the texture that this placement
101 // represents.
102 ////////////////////////////////////////////////////////////////////
103 const string &TexturePlacement::
104 get_name() const {
105  return _texture->get_name();
106 }
107 
108 ////////////////////////////////////////////////////////////////////
109 // Function: TexturePlacement::get_texture
110 // Access: Public
111 // Description: Returns the texture that this placement represents.
112 ////////////////////////////////////////////////////////////////////
114 get_texture() const {
115  return _texture;
116 }
117 
118 ////////////////////////////////////////////////////////////////////
119 // Function: TexturePlacement::get_properties
120 // Access: Public
121 // Description: Returns the grouping properties of the image.
122 ////////////////////////////////////////////////////////////////////
124 get_properties() const {
125  return _texture->get_properties();
126 }
127 
128 ////////////////////////////////////////////////////////////////////
129 // Function: TexturePlacement::get_group
130 // Access: Public
131 // Description: Returns the group that this placement represents.
132 ////////////////////////////////////////////////////////////////////
134 get_group() const {
135  return _group;
136 }
137 
138 ////////////////////////////////////////////////////////////////////
139 // Function: TexturePlacement::add_egg
140 // Access: Public
141 // Description: Records the fact that a particular egg file is using
142 // this particular TexturePlacement.
143 ////////////////////////////////////////////////////////////////////
146  reference->mark_egg_stale();
147 
148  // Turns out that turning these off is a bad idea, because it may
149  // make us forget the size information halfway through processing.
150  /*
151  _has_uvs = false;
152  _size_known = false;
153  */
154  _references.insert(reference);
155 }
156 
157 ////////////////////////////////////////////////////////////////////
158 // Function: TexturePlacement::remove_egg
159 // Access: Public
160 // Description: Notes that a particular egg file is no longer using
161 // this particular TexturePlacement.
162 ////////////////////////////////////////////////////////////////////
165  reference->mark_egg_stale();
166  /*
167  _has_uvs = false;
168  _size_known = false;
169  */
170  _references.erase(reference);
171 }
172 
173 ////////////////////////////////////////////////////////////////////
174 // Function: TexturePlacement::mark_eggs_stale
175 // Access: Public
176 // Description: Marks all the egg files that reference this placement
177 // stale. Presumably this is called after moving the
178 // texture around in the palette or something.
179 ////////////////////////////////////////////////////////////////////
182  References::iterator ri;
183  for (ri = _references.begin(); ri != _references.end(); ++ri) {
184  TextureReference *reference = (*ri);
185 
186  reference->mark_egg_stale();
187  }
188 }
189 
190 ////////////////////////////////////////////////////////////////////
191 // Function: TexturePlacement::set_dest
192 // Access: Public
193 // Description: Sets the DestTextureImage that corresponds to this
194 // texture as it was copied to the install directory.
195 ////////////////////////////////////////////////////////////////////
198  _dest = dest;
199 }
200 
201 ////////////////////////////////////////////////////////////////////
202 // Function: TexturePlacement::get_dest
203 // Access: Public
204 // Description: Returns the DestTextureImage that corresponds to this
205 // texture as it was copied to the install directory.
206 ////////////////////////////////////////////////////////////////////
208 get_dest() const {
209  return _dest;
210 }
211 
212 ////////////////////////////////////////////////////////////////////
213 // Function: TexturePlacement::determine_size
214 // Access: Public
215 // Description: Attempts to determine the appropriate size of the
216 // texture for the given placement. This is based on
217 // the UV range of the egg files that reference the
218 // texture. Returns true on success, or false if the
219 // texture size cannot be determined (e.g. the texture
220 // file is unknown).
221 //
222 // After this returns true, get_x_size() and
223 // get_y_size() may safely be called.
224 ////////////////////////////////////////////////////////////////////
227  if (!_texture->is_size_known()) {
228  // Too bad.
229  force_replace();
230  _omit_reason = OR_unknown;
231  return false;
232  }
233 
234  // This seems to be unnecessary (because of omit_solitary() and
235  // not_solitary()), and in fact bitches the logic in omit_solitary()
236  // and not_solitary() so that we call mark_egg_stale()
237  // unnecessarily.
238  /*
239  if (_omit_reason == OR_solitary) {
240  // If the texture was previously 'omitted' for being solitary, we
241  // give it a second chance now.
242  _omit_reason = OR_none;
243  }
244  */
245 
246  // Determine the actual minmax of the UV's in use, as well as
247  // whether we should wrap or clamp.
248  _has_uvs = false;
249  _position._wrap_u = EggTexture::WM_clamp;
250  _position._wrap_v = EggTexture::WM_clamp;
251 
252  LTexCoordd max_uv, min_uv;
253 
254  References::iterator ri;
255  for (ri = _references.begin(); ri != _references.end(); ++ri) {
256  TextureReference *reference = (*ri);
257  if (reference->has_uvs()) {
258  const LTexCoordd &n = reference->get_min_uv();
259  const LTexCoordd &x = reference->get_max_uv();
260 
261  if (_has_uvs) {
262  min_uv.set(min(min_uv[0], n[0]), min(min_uv[1], n[1]));
263  max_uv.set(max(max_uv[0], x[0]), max(max_uv[1], x[1]));
264  } else {
265  min_uv = n;
266  max_uv = x;
267  _has_uvs = true;
268  }
269  }
270 
271  // If any reference repeats the texture, the texture repeats in
272  // the palette.
273  if (reference->get_wrap_u() == EggTexture::WM_repeat) {
274  _position._wrap_u = EggTexture::WM_repeat;
275  }
276  if (reference->get_wrap_v() == EggTexture::WM_repeat) {
277  _position._wrap_v = EggTexture::WM_repeat;
278  }
279  }
280 
281  // However, if the user specified an explicit wrap mode, allow it to
282  // apply.
283  if (_texture->get_txa_wrap_u() != EggTexture::WM_unspecified) {
284  _position._wrap_u = _texture->get_txa_wrap_u();
285  }
286  if (_texture->get_txa_wrap_v() != EggTexture::WM_unspecified) {
287  _position._wrap_v = _texture->get_txa_wrap_v();
288  }
289 
290  if (!_has_uvs) {
291  force_replace();
292  _omit_reason = OR_unused;
293  return false;
294  }
295 
296  LTexCoordd rounded_min_uv = min_uv;
297  LTexCoordd rounded_max_uv = max_uv;
298 
299  //cout << get_name() << endl;
300 
301  // If so requested, round the minmax out to the next _round_unit.
302  // This cuts down on unnecessary resizing of textures within the
303  // palettes as the egg references change in trivial amounts.
304  //cout << "rounded_min_uv: " << rounded_min_uv << endl;
305  //cout << "rounded_max_uv: " << rounded_max_uv << endl;
306 
307  if (pal->_round_uvs) {
308  rounded_max_uv[0] =
309  ceil((rounded_max_uv[0] - pal->_round_fuzz) / pal->_round_unit) *
310  pal->_round_unit;
311  rounded_max_uv[1] =
312  ceil((rounded_max_uv[1] - pal->_round_fuzz) / pal->_round_unit) *
313  pal->_round_unit;
314 
315  rounded_min_uv[0] =
316  floor((rounded_min_uv[0] + pal->_round_fuzz) / pal->_round_unit) *
317  pal->_round_unit;
318  rounded_min_uv[1] =
319  floor((rounded_min_uv[1] + pal->_round_fuzz) / pal->_round_unit) *
320  pal->_round_unit;
321 
322  //cout << "after rounded_min_uv: " << rounded_min_uv << endl;
323  //cout << "after rounded_max_uv: " << rounded_max_uv << endl;
324  }
325 
326  // Now determine the size in pixels we require based on the UV's
327  // that actually reference this texture.
328  compute_size_from_uvs(rounded_min_uv, rounded_max_uv);
329 
330  // Now, can it be placed?
331  if (_texture->get_omit()) {
332  // Not if the user says it can't.
333  force_replace();
334  _omit_reason = OR_omitted;
335 
336  } else if (get_uv_area() > _texture->get_coverage_threshold()) {
337  // If the texture repeats too many times, we can't place it.
338  force_replace();
339  _omit_reason = OR_coverage;
340 
341  } else if ((_position._x_size > pal->_pal_x_size ||
342  _position._y_size > pal->_pal_y_size) ||
343  (_position._x_size == pal->_pal_x_size &&
344  _position._y_size == pal->_pal_y_size)) {
345  // If the texture exceeds the size of an empty palette image in
346  // either dimension, or if it exactly equals the size of an empty
347  // palette image in both dimensions, we can't place it because
348  // it's too big.
349  force_replace();
350  _omit_reason = OR_size;
351 
352  } else if (pal->_omit_everything && (_group->is_none_texture_swap())) {
353  // If we're omitting everything, omit everything.
354  force_replace();
355  _omit_reason = OR_default_omit;
356 
357  } else if (_omit_reason == OR_omitted ||
358  _omit_reason == OR_default_omit ||
359  _omit_reason == OR_size ||
360  _omit_reason == OR_coverage ||
361  _omit_reason == OR_unknown) {
362  // On the other hand, if the texture was previously omitted
363  // explicitly, or because of its size or coverage, now it seems to
364  // fit.
365  force_replace();
366  mark_eggs_stale();
367  _omit_reason = OR_working;
368 
369  } else if (is_placed()) {
370  // It *can* be placed. If it was already placed previously, can
371  // we leave it where it is?
372 
373  if (_position._x_size != _placed._x_size ||
374  _position._y_size != _placed._y_size ||
375  _position._min_uv[0] < _placed._min_uv[0] ||
376  _position._min_uv[1] < _placed._min_uv[1] ||
377  _position._max_uv[0] > _placed._max_uv[0] ||
378  _position._max_uv[1] > _placed._max_uv[1]) {
379  // If the texture was previously placed but is now the wrong
380  // size, or if the area we need to cover is different, we need
381  // to re-place it.
382 
383  // However, we make a special exception: if it would have fit
384  // without rounding up the UV's, then screw rounding it up and
385  // just leave it alone.
386  if ((_position._x_size > _placed._x_size ||
387  _position._y_size > _placed._y_size) &&
388  pal->_round_uvs) {
389  compute_size_from_uvs(min_uv, max_uv);
390  if (_position._x_size <= _placed._x_size &&
391  _position._y_size <= _placed._y_size &&
392  _position._min_uv[0] >= _placed._min_uv[0] &&
393  _position._min_uv[1] >= _placed._min_uv[1] &&
394  _position._max_uv[0] <= _placed._max_uv[0] &&
395  _position._max_uv[1] <= _placed._max_uv[1]) {
396  // No problem! It fits here, so leave well enough alone.
397  } else {
398  // That's not good enough either, so go back to rounding.
399  compute_size_from_uvs(rounded_min_uv, rounded_max_uv);
400  force_replace();
401  }
402  } else {
403  force_replace();
404  }
405  }
406 
407  if (_position._wrap_u != _placed._wrap_u ||
408  _position._wrap_v != _placed._wrap_v) {
409  // The wrap mode properties have changed slightly. We may or
410  // may not need to re-place it, but we will need to update it.
411  _is_filled = false;
412  _placed._wrap_u = _position._wrap_u;
413  _placed._wrap_v = _position._wrap_v;
414  }
415  }
416 
417  return true;
418 }
419 
420 ////////////////////////////////////////////////////////////////////
421 // Function: TexturePlacement::is_size_known
422 // Access: Public
423 // Description: Returns true if the texture's size is known, false
424 // otherwise. Usually this can only be false after
425 // determine_size() has been called there is something
426 // wrong with the texture (in which case the placement
427 // will automatically omit itself from the palette
428 // anyway).
429 ////////////////////////////////////////////////////////////////////
431 is_size_known() const {
432  return _size_known;
433 }
434 
435 ////////////////////////////////////////////////////////////////////
436 // Function: TexturePlacement::get_omit_reason
437 // Access: Public
438 // Description: Returns the reason the texture has been omitted from
439 // a palette image, or OR_none if it has not.
440 ////////////////////////////////////////////////////////////////////
441 OmitReason TexturePlacement::
443  return _omit_reason;
444 }
445 
446 ////////////////////////////////////////////////////////////////////
447 // Function: TexturePlacement::get_x_size
448 // Access: Public
449 // Description: Returns the size in the X dimension, in pixels, of
450 // the texture image as it must appear in the palette.
451 // This accounts for any growing or shrinking of the
452 // texture due to the UV coordinate range.
453 ////////////////////////////////////////////////////////////////////
455 get_x_size() const {
456  nassertr(_size_known, 0);
457  return _position._x_size;
458 }
459 
460 ////////////////////////////////////////////////////////////////////
461 // Function: TexturePlacement::get_y_size
462 // Access: Public
463 // Description: Returns the size in the Y dimension, in pixels, of
464 // the texture image as it must appear in the palette.
465 // This accounts for any growing or shrinking of the
466 // texture due to the UV coordinate range.
467 ////////////////////////////////////////////////////////////////////
469 get_y_size() const {
470  nassertr(_size_known, 0);
471  return _position._y_size;
472 }
473 
474 ////////////////////////////////////////////////////////////////////
475 // Function: TexturePlacement::get_uv_area
476 // Access: Public
477 // Description: Returns the total area of the rectangle occupied by
478 // the UV minmax box, in UV coordinates. 1.0 is the
479 // entire texture; values greater than 1 imply the
480 // texture repeats.
481 ////////////////////////////////////////////////////////////////////
482 double TexturePlacement::
483 get_uv_area() const {
484  if (!_has_uvs) {
485  return 0.0;
486  }
487 
488  LTexCoordd range = _position._max_uv - _position._min_uv;
489  return range[0] * range[1];
490 }
491 
492 ////////////////////////////////////////////////////////////////////
493 // Function: TexturePlacement::is_placed
494 // Access: Public
495 // Description: Returns true if the texture has been placed on a
496 // palette image, false otherwise. This will generally
497 // be true if get_omit_reason() returns OR_none or
498 // OR_solitary and false otherwise.
499 ////////////////////////////////////////////////////////////////////
501 is_placed() const {
502  return _image != (PaletteImage *)NULL;
503 }
504 
505 ////////////////////////////////////////////////////////////////////
506 // Function: TexturePlacement::get_image
507 // Access: Public
508 // Description: Returns the particular PaletteImage on which the
509 // texture has been placed.
510 ////////////////////////////////////////////////////////////////////
512 get_image() const {
513  nassertr(is_placed(), (PaletteImage *)NULL);
514  return _image;
515 }
516 
517 ////////////////////////////////////////////////////////////////////
518 // Function: TexturePlacement::get_page
519 // Access: Public
520 // Description: Returns the particular PalettePage on which the
521 // texture has been placed.
522 ////////////////////////////////////////////////////////////////////
524 get_page() const {
525  nassertr(is_placed(), (PalettePage *)NULL);
526  return _image->get_page();
527 }
528 
529 ////////////////////////////////////////////////////////////////////
530 // Function: TexturePlacement::get_placed_x
531 // Access: Public
532 // Description: Returns the X pixel at which the texture has been
533 // placed within its PaletteImage. It is an error to
534 // call this unless is_placed() returns true.
535 ////////////////////////////////////////////////////////////////////
537 get_placed_x() const {
538  nassertr(is_placed(), 0);
539  return _placed._x;
540 }
541 
542 ////////////////////////////////////////////////////////////////////
543 // Function: TexturePlacement::get_placed_y
544 // Access: Public
545 // Description: Returns the Y pixel at which the texture has been
546 // placed within its PaletteImage. It is an error to
547 // call this unless is_placed() returns true.
548 ////////////////////////////////////////////////////////////////////
550 get_placed_y() const {
551  nassertr(is_placed(), 0);
552  return _placed._y;
553 }
554 
555 ////////////////////////////////////////////////////////////////////
556 // Function: TexturePlacement::get_placed_x_size
557 // Access: Public
558 // Description: Returns the size in the X dimension, in pixels, of
559 // the texture image as it has been placed within the
560 // palette.
561 ////////////////////////////////////////////////////////////////////
564  nassertr(is_placed(), 0);
565  return _placed._x_size;
566 }
567 
568 ////////////////////////////////////////////////////////////////////
569 // Function: TexturePlacement::get_placed_y_size
570 // Access: Public
571 // Description: Returns the size in the Y dimension, in pixels, of
572 // the texture image as it has been placed within the
573 // palette.
574 ////////////////////////////////////////////////////////////////////
577  nassertr(is_placed(), 0);
578  return _placed._y_size;
579 }
580 
581 ////////////////////////////////////////////////////////////////////
582 // Function: TexturePlacement::get_placed_uv_area
583 // Access: Public
584 // Description: Returns the total area of the rectangle occupied by
585 // the UV minmax box, as it has been placed. See also
586 // get_uv_area().
587 ////////////////////////////////////////////////////////////////////
588 double TexturePlacement::
590  nassertr(is_placed(), 0);
591  LTexCoordd range = _placed._max_uv - _placed._min_uv;
592  return range[0] * range[1];
593 }
594 
595 ////////////////////////////////////////////////////////////////////
596 // Function: TexturePlacement::place_at
597 // Access: Public
598 // Description: Assigns the texture to a particular position within
599 // the indicated PaletteImage. It is an error to call
600 // this if the texture has already been placed
601 // elsewhere.
602 ////////////////////////////////////////////////////////////////////
604 place_at(PaletteImage *image, int x, int y) {
605  nassertv(!is_placed());
606  nassertv(_size_known);
607 
608  _image = image;
609  _is_filled = false;
610  _position._x = x;
611  _position._y = y;
612  _placed = _position;
613  _omit_reason = OR_none;
614 }
615 
616 ////////////////////////////////////////////////////////////////////
617 // Function: TexturePlacement::force_replace
618 // Access: Public
619 // Description: Removes the texture from its particular PaletteImage,
620 // but does not remove it from the PaletteGroup. It
621 // will be re-placed when the PaletteGroup::place_all()
622 // is called.
623 ////////////////////////////////////////////////////////////////////
626  if (_image != (PaletteImage *)NULL) {
627  _image->unplace(this);
628  _image = (PaletteImage *)NULL;
629  }
630  if (_omit_reason == OR_none) {
631  mark_eggs_stale();
632  }
633  _omit_reason = OR_working;
634 }
635 
636 ////////////////////////////////////////////////////////////////////
637 // Function: TexturePlacement::omit_solitary
638 // Access: Public
639 // Description: Sets the omit reason (returned by get_omit()) to
640 // OR_solitary, indicating that the palettized version
641 // of the texture should not be used because it is the
642 // only texture on a PaletteImage. However, the texture
643 // is still considered placed, and is_placed() will
644 // return true.
645 ////////////////////////////////////////////////////////////////////
648  nassertv(is_placed());
649  if (_omit_reason != OR_solitary) {
650  mark_eggs_stale();
651  _omit_reason = OR_solitary;
652  }
653 }
654 
655 ////////////////////////////////////////////////////////////////////
656 // Function: TexturePlacement::not_solitary
657 // Access: Public
658 // Description: Indicates that the texture, formerly indicated as
659 // solitary, is now no longer.
660 ////////////////////////////////////////////////////////////////////
663  nassertv(is_placed());
664  if (_omit_reason != OR_none) {
665  mark_eggs_stale();
666  _omit_reason = OR_none;
667  }
668 }
669 
670 ////////////////////////////////////////////////////////////////////
671 // Function: TexturePlacement::intersects
672 // Access: Public
673 // Description: Returns true if the particular position this texture
674 // has been assigned to overlaps the rectangle whose
675 // top left corner is at x, y and whose size is given by
676 // x_size, y_size, or false otherwise.
677 ////////////////////////////////////////////////////////////////////
679 intersects(int x, int y, int x_size, int y_size) {
680  nassertr(is_placed(), false);
681 
682  int hright = x + x_size;
683  int hbot = y + y_size;
684 
685  int mright = _placed._x + _placed._x_size;
686  int mbot = _placed._y + _placed._y_size;
687 
688  return !(x >= mright || hright <= _placed._x ||
689  y >= mbot || hbot <= _placed._y);
690 }
691 
692 ////////////////////////////////////////////////////////////////////
693 // Function: TexturePlacement::compute_tex_matrix
694 // Access: Public
695 // Description: Stores in the indicated matrix the appropriate
696 // texture matrix transform for the new placement of the
697 // texture.
698 ////////////////////////////////////////////////////////////////////
701  nassertv(is_placed());
702 
703  LMatrix3d source_uvs = LMatrix3d::ident_mat();
704 
705  LTexCoordd range = _placed._max_uv - _placed._min_uv;
706  if (range[0] != 0.0 && range[1] != 0.0) {
707  source_uvs =
708  LMatrix3d::translate_mat(-_placed._min_uv) *
709  LMatrix3d::scale_mat(1.0 / range[0], 1.0 / range[1]);
710  }
711 
712  int top = _placed._y + _placed._margin;
713  int left = _placed._x + _placed._margin;
714  int x_size = _placed._x_size - _placed._margin * 2;
715  int y_size = _placed._y_size - _placed._margin * 2;
716 
717  int bottom = top + y_size;
718  int pal_x_size = _image->get_x_size();
719  int pal_y_size = _image->get_y_size();
720 
721  LVecBase2d t((double)left / (double)pal_x_size,
722  (double)(pal_y_size - bottom) / (double)pal_y_size);
723  LVecBase2d s((double)x_size / (double)pal_x_size,
724  (double)y_size / (double)pal_y_size);
725 
726  LMatrix3d dest_uvs
727  (s[0], 0.0, 0.0,
728  0.0, s[1], 0.0,
729  t[0], t[1], 1.0);
730 
731  transform = source_uvs * dest_uvs;
732 }
733 
734 ////////////////////////////////////////////////////////////////////
735 // Function: TexturePlacement::write_placed
736 // Access: Public
737 // Description: Writes the placement position information on a line
738 // by itself.
739 ////////////////////////////////////////////////////////////////////
741 write_placed(ostream &out, int indent_level) {
742  indent(out, indent_level)
743  << get_texture()->get_name();
744 
745  if (is_placed()) {
746  out << " at "
747  << get_placed_x() << " " << get_placed_y() << " to "
748  << get_placed_x() + get_placed_x_size() << " "
749  << get_placed_y() + get_placed_y_size() << " (coverage "
750  << get_placed_uv_area() << ")";
751 
752  if (_placed._wrap_u != EggTexture::WM_unspecified ||
753  _placed._wrap_v != EggTexture::WM_unspecified) {
754  if (_placed._wrap_u != _placed._wrap_v) {
755  out << " (" << _placed._wrap_u << ", " << _placed._wrap_v << ")";
756  } else {
757  out << " " << _placed._wrap_u;
758  }
759  }
760  out << "\n";
761  } else {
762  out << " not yet placed.\n";
763  }
764 };
765 
766 ////////////////////////////////////////////////////////////////////
767 // Function: TexturePlacement::is_filled
768 // Access: Public
769 // Description: Returns true if the texture has been filled
770 // (i.e. fill_image() has been called) since it was
771 // placed.
772 ////////////////////////////////////////////////////////////////////
774 is_filled() const {
775  return _is_filled;
776 }
777 
778 ////////////////////////////////////////////////////////////////////
779 // Function: TexturePlacement::mark_unfilled
780 // Access: Public
781 // Description: Marks the texture as unfilled, so that it will need
782 // to be copied into the palette image again.
783 ////////////////////////////////////////////////////////////////////
786  _is_filled = false;
787 }
788 
789 ////////////////////////////////////////////////////////////////////
790 // Function: TexturePlacement::fill_image
791 // Access: Public
792 // Description: Fills in the rectangle of the palette image
793 // represented by the texture placement with the image
794 // pixels.
795 ////////////////////////////////////////////////////////////////////
798  nassertv(is_placed());
799 
800  _is_filled = true;
801 
802  // We determine the pixels to place the source image at by
803  // transforming the unit texture box: the upper-left and lower-right
804  // corners. These corners, in the final texture coordinate space,
805  // represent where on the palette image the original texture should
806  // be located.
807 
808  LMatrix3d transform;
809  compute_tex_matrix(transform);
810  LTexCoordd ul = LTexCoordd(0.0, 1.0) * transform;
811  LTexCoordd lr = LTexCoordd(1.0, 0.0) * transform;
812 
813  // Now we convert those texture coordinates back to pixel units.
814  int pal_x_size = _image->get_x_size();
815  int pal_y_size = _image->get_y_size();
816 
817  int top = (int)floor((1.0 - ul[1]) * pal_y_size + 0.5);
818  int left = (int)floor(ul[0] * pal_x_size + 0.5);
819  int bottom = (int)floor((1.0 - lr[1]) * pal_y_size + 0.5);
820  int right = (int)floor(lr[0] * pal_x_size + 0.5);
821 
822  // And now we can determine the size to scale the image to based on
823  // that. This may not be the same as texture->size() because of
824  // margins.
825  int x_size = right - left;
826  int y_size = bottom - top;
827  nassertv(x_size >= 0 && y_size >= 0);
828 
829  // Now we get a PNMImage that represents the source texture at that
830  // size.
831  const PNMImage &source_full = _texture->read_source_image();
832  if (!source_full.is_valid()) {
833  flag_error_image(image);
834  return;
835  }
836 
837  PNMImage source(x_size, y_size, source_full.get_num_channels(),
838  source_full.get_maxval());
839  source.quick_filter_from(source_full);
840 
841  bool alpha = image.has_alpha();
842  bool source_alpha = source.has_alpha();
843 
844  // Now copy the pixels. We do this by walking through the
845  // rectangular region on the palette image that we have reserved for
846  // this texture; for each pixel in this region, we determine its
847  // appropriate color based on its relation to the actual texture
848  // image location (determined above), and on whether the texture
849  // wraps or clamps.
850  for (int y = _placed._y; y < _placed._y + _placed._y_size; y++) {
851  int sy = y - top;
852 
853  if (_placed._wrap_v == EggTexture::WM_clamp) {
854  // Clamp at [0, y_size).
855  sy = max(min(sy, y_size - 1), 0);
856 
857  } else {
858  // Wrap: sign-independent modulo.
859  sy = (sy < 0) ? y_size - 1 - ((-sy - 1) % y_size) : sy % y_size;
860  }
861 
862  for (int x = _placed._x; x < _placed._x + _placed._x_size; x++) {
863  int sx = x - left;
864 
865  if (_placed._wrap_u == EggTexture::WM_clamp) {
866  // Clamp at [0, x_size).
867  sx = max(min(sx, x_size - 1), 0);
868 
869  } else {
870  // Wrap: sign-independent modulo.
871  sx = (sx < 0) ? x_size - 1 - ((-sx - 1) % x_size) : sx % x_size;
872  }
873 
874  image.set_xel(x, y, source.get_xel(sx, sy));
875  if (alpha) {
876  if (source_alpha) {
877  image.set_alpha(x, y, source.get_alpha(sx, sy));
878  } else {
879  image.set_alpha(x, y, 1.0);
880  }
881  }
882  }
883  }
884 
885  _texture->release_source_image();
886 }
887 
888 
889 ////////////////////////////////////////////////////////////////////
890 // Function: TexturePlacement::fill_swapped_image
891 // Access: Public
892 // Description: Fills in the rectangle of the swapped palette image
893 // represented by the texture placement with the image
894 // pixels.
895 ////////////////////////////////////////////////////////////////////
897 fill_swapped_image(PNMImage &image, int index) {
898  nassertv(is_placed());
899 
900  _is_filled = true;
901 
902  // We determine the pixels to place the source image at by
903  // transforming the unit texture box: the upper-left and lower-right
904  // corners. These corners, in the final texture coordinate space,
905  // represent where on the palette image the original texture should
906  // be located.
907 
908  LMatrix3d transform;
909  compute_tex_matrix(transform);
910  LTexCoordd ul = LTexCoordd(0.0, 1.0) * transform;
911  LTexCoordd lr = LTexCoordd(1.0, 0.0) * transform;
912 
913  // Now we convert those texture coordinates back to pixel units.
914  int pal_x_size = _image->get_x_size();
915  int pal_y_size = _image->get_y_size();
916 
917  int top = (int)floor((1.0 - ul[1]) * pal_y_size + 0.5);
918  int left = (int)floor(ul[0] * pal_x_size + 0.5);
919  int bottom = (int)floor((1.0 - lr[1]) * pal_y_size + 0.5);
920  int right = (int)floor(lr[0] * pal_x_size + 0.5);
921 
922  // And now we can determine the size to scale the image to based on
923  // that. This may not be the same as texture->size() because of
924  // margins.
925  int x_size = right - left;
926  int y_size = bottom - top;
927  nassertv(x_size >= 0 && y_size >= 0);
928 
929  // Now we get a PNMImage that represents the swapped texture at that
930  // size.
931  TextureSwaps::iterator tsi;
932  tsi = _textureSwaps.begin() + index;
933  TextureImage *swapTexture = (*tsi);
934  const PNMImage &source_full = swapTexture->read_source_image();
935  if (!source_full.is_valid()) {
936  flag_error_image(image);
937  return;
938  }
939 
940  PNMImage source(x_size, y_size, source_full.get_num_channels(),
941  source_full.get_maxval());
942  source.quick_filter_from(source_full);
943 
944  bool alpha = image.has_alpha();
945  bool source_alpha = source.has_alpha();
946 
947  // Now copy the pixels. We do this by walking through the
948  // rectangular region on the palette image that we have reserved for
949  // this texture; for each pixel in this region, we determine its
950  // appropriate color based on its relation to the actual texture
951  // image location (determined above), and on whether the texture
952  // wraps or clamps.
953  for (int y = _placed._y; y < _placed._y + _placed._y_size; y++) {
954  int sy = y - top;
955 
956  if (_placed._wrap_v == EggTexture::WM_clamp) {
957  // Clamp at [0, y_size).
958  sy = max(min(sy, y_size - 1), 0);
959 
960  } else {
961  // Wrap: sign-independent modulo.
962  sy = (sy < 0) ? y_size - 1 - ((-sy - 1) % y_size) : sy % y_size;
963  }
964 
965  for (int x = _placed._x; x < _placed._x + _placed._x_size; x++) {
966  int sx = x - left;
967 
968  if (_placed._wrap_u == EggTexture::WM_clamp) {
969  // Clamp at [0, x_size).
970  sx = max(min(sx, x_size - 1), 0);
971 
972  } else {
973  // Wrap: sign-independent modulo.
974  sx = (sx < 0) ? x_size - 1 - ((-sx - 1) % x_size) : sx % x_size;
975  }
976 
977  image.set_xel(x, y, source.get_xel(sx, sy));
978  if (alpha) {
979  if (source_alpha) {
980  image.set_alpha(x, y, source.get_alpha(sx, sy));
981  } else {
982  image.set_alpha(x, y, 1.0);
983  }
984  }
985  }
986  }
987 
988  swapTexture->release_source_image();
989 }
990 
991 ////////////////////////////////////////////////////////////////////
992 // Function: TexturePlacement::flag_error_image
993 // Access: Public
994 // Description: Sets the rectangle of the palette image
995 // represented by the texture placement to red, to
996 // represent a missing texture.
997 ////////////////////////////////////////////////////////////////////
1000  nassertv(is_placed());
1001  for (int y = _placed._y; y < _placed._y + _placed._y_size; y++) {
1002  for (int x = _placed._x; x < _placed._x + _placed._x_size; x++) {
1003  image.set_xel_val(x, y, 1, 0, 0);
1004  }
1005  }
1006  if (image.has_alpha()) {
1007  for (int y = _placed._y; y < _placed._y + _placed._y_size; y++) {
1008  for (int x = _placed._x; x < _placed._x + _placed._x_size; x++) {
1009  image.set_alpha_val(x, y, 1);
1010  }
1011  }
1012  }
1013 }
1014 
1015 ////////////////////////////////////////////////////////////////////
1016 // Function: TexturePlacement::compute_size_from_uvs
1017 // Access: Private
1018 // Description: A support function for determine_size(), this
1019 // computes the appropriate size of the texture in
1020 // pixels based on the UV coverage (as well as on the
1021 // size of the source texture).
1022 ////////////////////////////////////////////////////////////////////
1023 void TexturePlacement::
1024 compute_size_from_uvs(const LTexCoordd &min_uv, const LTexCoordd &max_uv) {
1025  _position._min_uv = min_uv;
1026  _position._max_uv = max_uv;
1027 
1028  LTexCoordd range = _position._max_uv - _position._min_uv;
1029  //cout << "range: " << range << endl;
1030 
1031  //cout << "_x_size texture: " << _texture->get_x_size() << endl;
1032  //cout << "_y_size texture: " << _texture->get_y_size() << endl;
1033 
1034  _position._x_size = (int)floor(_texture->get_x_size() * range[0] + 0.5);
1035  _position._y_size = (int)floor(_texture->get_y_size() * range[1] + 0.5);
1036 
1037  //cout << "_x_size: " << _position._x_size << endl;
1038  //cout << "_y_size: " << _position._y_size << endl;
1039 
1040  // We arbitrarily require at least four pixels in each dimension.
1041  // Fewer than this may be asking for trouble.
1042  _position._x_size = max(_position._x_size, 4);
1043  _position._y_size = max(_position._y_size, 4);
1044 
1045  if(get_group()->has_margin_override()) {
1046  _position._margin = get_group()->get_margin_override();
1047  } else {
1048  _position._margin = _texture->get_margin();
1049  }
1050  //cout << "margin: " << _position._margin << endl;
1051 
1052  // Normally, we have interior margins, but if the image size is too
1053  // small--i.e. the margin size is too great a percentage of the
1054  // image size--we'll make them exterior margins so as not to overly
1055  // degrade the quality of the image.
1056  if ((double)_position._margin / (double)_position._x_size > 0.10) {
1057  _position._x_size += _position._margin * 2;
1058  }
1059  if ((double)_position._margin / (double)_position._y_size > 0.10) {
1060  _position._y_size += _position._margin * 2;
1061  }
1062 
1063  _size_known = true;
1064 }
1065 
1066 
1067 
1068 ////////////////////////////////////////////////////////////////////
1069 // Function: TexturePlacement::register_with_read_factory
1070 // Access: Public, Static
1071 // Description: Registers the current object as something that can be
1072 // read from a Bam file.
1073 ////////////////////////////////////////////////////////////////////
1074 void TexturePlacement::
1077  register_factory(get_class_type(), make_TexturePlacement);
1078 }
1079 
1080 ////////////////////////////////////////////////////////////////////
1081 // Function: TexturePlacement::write_datagram
1082 // Access: Public, Virtual
1083 // Description: Fills the indicated datagram up with a binary
1084 // representation of the current object, in preparation
1085 // for writing to a Bam file.
1086 ////////////////////////////////////////////////////////////////////
1087 void TexturePlacement::
1088 write_datagram(BamWriter *writer, Datagram &datagram) {
1089  TypedWritable::write_datagram(writer, datagram);
1090  writer->write_pointer(datagram, _texture);
1091  writer->write_pointer(datagram, _group);
1092  writer->write_pointer(datagram, _image);
1093  writer->write_pointer(datagram, _dest);
1094 
1095  datagram.add_bool(_has_uvs);
1096  datagram.add_bool(_size_known);
1097  _position.write_datagram(writer, datagram);
1098 
1099  datagram.add_bool(_is_filled);
1100  _placed.write_datagram(writer, datagram);
1101  datagram.add_int32((int)_omit_reason);
1102 
1103  datagram.add_int32(_references.size());
1104  References::const_iterator ri;
1105  for (ri = _references.begin(); ri != _references.end(); ++ri) {
1106  writer->write_pointer(datagram, (*ri));
1107  }
1108 
1109  datagram.add_int32(_textureSwaps.size());
1110  TextureSwaps::const_iterator tsi;
1111  for (tsi = _textureSwaps.begin(); tsi != _textureSwaps.end(); ++tsi) {
1112  writer->write_pointer(datagram, (*tsi));
1113  }
1114 
1115 }
1116 
1117 ////////////////////////////////////////////////////////////////////
1118 // Function: TexturePlacement::complete_pointers
1119 // Access: Public, Virtual
1120 // Description: Called after the object is otherwise completely read
1121 // from a Bam file, this function's job is to store the
1122 // pointers that were retrieved from the Bam file for
1123 // each pointer object written. The return value is the
1124 // number of pointers processed from the list.
1125 ////////////////////////////////////////////////////////////////////
1128  int index = TypedWritable::complete_pointers(p_list, manager);
1129 
1130  if (p_list[index] != (TypedWritable *)NULL) {
1131  DCAST_INTO_R(_texture, p_list[index], index);
1132  }
1133  index++;
1134 
1135  if (p_list[index] != (TypedWritable *)NULL) {
1136  DCAST_INTO_R(_group, p_list[index], index);
1137  }
1138  index++;
1139 
1140  if (p_list[index] != (TypedWritable *)NULL) {
1141  DCAST_INTO_R(_image, p_list[index], index);
1142  }
1143  index++;
1144 
1145  if (p_list[index] != (TypedWritable *)NULL) {
1146  DCAST_INTO_R(_dest, p_list[index], index);
1147  }
1148  index++;
1149 
1150  int i;
1151  for (i = 0; i < _num_references; i++) {
1152  TextureReference *reference;
1153  DCAST_INTO_R(reference, p_list[index], index);
1154  _references.insert(reference);
1155  index++;
1156  }
1157 
1158  for (i = 0; i < _num_textureSwaps; i++) {
1159  TextureImage *swapTexture;
1160  DCAST_INTO_R(swapTexture, p_list[index], index);
1161  _textureSwaps.push_back(swapTexture);
1162  index++;
1163  }
1164 
1165  return index;
1166 }
1167 
1168 ////////////////////////////////////////////////////////////////////
1169 // Function: TexturePlacement::make_TexturePlacement
1170 // Access: Protected
1171 // Description: This method is called by the BamReader when an object
1172 // of this type is encountered in a Bam file; it should
1173 // allocate and return a new object with all the data
1174 // read.
1175 ////////////////////////////////////////////////////////////////////
1176 TypedWritable* TexturePlacement::
1177 make_TexturePlacement(const FactoryParams &params) {
1179  DatagramIterator scan;
1180  BamReader *manager;
1181 
1182  parse_params(params, scan, manager);
1183  me->fillin(scan, manager);
1184  return me;
1185 }
1186 
1187 ////////////////////////////////////////////////////////////////////
1188 // Function: TexturePlacement::fillin
1189 // Access: Protected
1190 // Description: Reads the binary data from the given datagram
1191 // iterator, which was written by a previous call to
1192 // write_datagram().
1193 ////////////////////////////////////////////////////////////////////
1194 void TexturePlacement::
1195 fillin(DatagramIterator &scan, BamReader *manager) {
1196  TypedWritable::fillin(scan, manager);
1197 
1198  manager->read_pointer(scan); // _texture
1199  manager->read_pointer(scan); // _group
1200  manager->read_pointer(scan); // _image
1201  manager->read_pointer(scan); // _dest
1202 
1203  _has_uvs = scan.get_bool();
1204  _size_known = scan.get_bool();
1205  _position.fillin(scan, manager);
1206 
1207  _is_filled = scan.get_bool();
1208  _placed.fillin(scan, manager);
1209  _omit_reason = (OmitReason)scan.get_int32();
1210 
1211  _num_references = scan.get_int32();
1212  manager->read_pointers(scan, _num_references);
1213 
1214  if (Palettizer::_read_pi_version >= 20) {
1215  _num_textureSwaps = scan.get_int32();
1216  } else {
1217  _num_textureSwaps = 0;
1218  }
1219  manager->read_pointers(scan, _num_textureSwaps);
1220 }
1221 
1222 
1223 ////////////////////////////////////////////////////////////////////
1224 // Function: SortPlacementBySize::Function Operator
1225 // Access: Public
1226 // Description: Compares two TexturePlacement objects and returns
1227 // true if the first one is bigger than the second one,
1228 // false otherwise.
1229 ////////////////////////////////////////////////////////////////////
1232  if (a->get_y_size() < b->get_y_size()) {
1233  return false;
1234 
1235  } else if (b->get_y_size() < a->get_y_size()) {
1236  return true;
1237 
1238  } else if (a->get_x_size() < b->get_x_size()) {
1239  return false;
1240 
1241  } else if (b->get_x_size() < a->get_x_size()) {
1242  return true;
1243  } else if (a->get_name() < b->get_name()) {
1244  //use this fall through case to let alphabetically smaller textures show up first
1245  return true;
1246  }
1247 
1248  return false;
1249 }
bool is_filled() const
Returns true if the texture has been filled (i.e.
int get_y_size() const
Returns the size in the Y dimension, in pixels, of the texture image as it must appear in the palette...
This represents a texture filename as it has been resized and copied to the map directory (e...
void not_solitary()
Indicates that the texture, formerly indicated as solitary, is now no longer.
void flag_error_image(PNMImage &image)
Sets the rectangle of the palette image represented by the texture placement to red, to represent a missing texture.
bool determine_size()
Attempts to determine the appropriate size of the texture for the given placement.
bool get_bool()
Extracts a boolean value.
The name of this class derives from the fact that we originally implemented it as a layer on top of t...
Definition: pnmImage.h:68
EggTexture::WrapMode get_wrap_u() const
Returns the specification for the wrapping in the U direction.
void clear_placement()
Removes any reference to a TexturePlacement.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:122
int get_placed_x_size() const
Returns the size in the X dimension, in pixels, of the texture image as it has been placed within the...
const string & get_name() const
Returns the name of the texture that this placement represents.
This is the particular reference of a texture filename by an egg file.
This is the base class for all two-component vectors and points.
Definition: lvecBase2.h:1257
PaletteGroup * get_group() const
Returns the group that this placement represents.
virtual void write_datagram(BamWriter *writer, Datagram &datagram)
Fills the indicated datagram up with a binary representation of the current object, in preparation for writing to a Bam file.
void set_xel_val(int x, int y, const xel &value)
Changes the RGB color at the indicated pixel.
Definition: pnmImage.I:406
PaletteImage * get_image() const
Returns the particular PaletteImage on which the texture has been placed.
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:37
This is the highest level of grouping for TextureImages.
Definition: paletteGroup.h:47
int get_placed_x() const
Returns the X pixel at which the texture has been placed within its PaletteImage. ...
const LTexCoordd & get_min_uv() const
Returns the minimum UV coordinate in use for the texture by this reference.
double get_placed_uv_area() const
Returns the total area of the rectangle occupied by the UV minmax box, as it has been placed...
This is a two-component point in space.
Definition: lpoint2.h:424
bool operator()(TexturePlacement *a, TexturePlacement *b) const
Compares two TexturePlacement objects and returns true if the first one is bigger than the second one...
const LTexCoordd & get_max_uv() const
Returns the maximum UV coordinate in use for the texture by this reference.
double get_uv_area() const
Returns the total area of the rectangle occupied by the UV minmax box, in UV coordinates.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:73
PN_int32 get_int32()
Extracts a signed 32-bit integer.
This is a particular collection of textures, within a PaletteGroup, that all share the same TexturePr...
Definition: palettePage.h:37
static LMatrix3d translate_mat(const LVecBase2d &trans)
Returns a matrix that applies the indicated translation.
Definition: lmatrix.h:8320
EggTexture::WrapMode get_wrap_v() const
Returns the specification for the wrapping in the V direction.
void place_at(PaletteImage *image, int x, int y)
Assigns the texture to a particular position within the indicated PaletteImage.
void omit_solitary()
Sets the omit reason (returned by get_omit()) to OR_solitary, indicating that the palettized version ...
virtual void fillin(DatagramIterator &scan, BamReader *manager)
This internal function is intended to be called by each class&#39;s make_from_bam() method to read in all...
static void register_with_read_factory()
Registers the current object as something that can be read from a Bam file.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
void quick_filter_from(const PNMImage &copy, int xborder=0, int yborder=0)
Resizes from the given image, with a fixed radius of 0.5.
int get_placed_y() const
Returns the Y pixel at which the texture has been placed within its PaletteImage. ...
bool is_valid() const
Returns true if the image has been read in or correctly initialized with a height and width...
Definition: pnmImage.I:309
This is a 3-by-3 transform matrix.
Definition: lmatrix.h:4375
void force_replace()
Removes the texture from its particular PaletteImage, but does not remove it from the PaletteGroup...
void mark_unfilled()
Marks the texture as unfilled, so that it will need to be copied into the palette image again...
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition: datagram.I:118
void compute_tex_matrix(LMatrix3d &transform)
Stores in the indicated matrix the appropriate texture matrix transform for the new placement of the ...
bool is_size_known() const
Returns true if the texture&#39;s size is known, false otherwise.
bool is_size_known() const
Returns true if the size of the image file is known, false otherwise.
Definition: imageFile.cxx:81
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()...
static bool has_alpha(ColorType color_type)
This static variant of has_alpha() returns true if the indicated image type includes an alpha channel...
xelval get_maxval() const
Returns the maximum channel value allowable for any pixel in this image; for instance, 255 for a typical 8-bit-per-channel image.
void read_pointers(DatagramIterator &scan, int count)
A convenience function to read a contiguous list of pointers.
Definition: bamReader.cxx:700
const TextureProperties & get_properties() const
Returns the grouping properties of the image.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:40
PalettePage * get_page() const
Returns the particular PalettePage on which the texture has been placed.
This corresponds to a particular assignment of a TextureImage with a PaletteGroup, and specifically describes which PaletteImage (if any), and where on the PaletteImage, the TextureImage has been assigned to.
void add_egg(TextureReference *reference)
Records the fact that a particular egg file is using this particular TexturePlacement.
OmitReason get_omit_reason() const
Returns the reason the texture has been omitted from a palette image, or OR_none if it has not...
void mark_egg_stale()
Marks the egg file that shares this reference as stale.
TextureImage * get_texture() const
Returns the texture that this placement represents.
void set_alpha(int x, int y, float a)
Sets the alpha component color only at the indicated pixel.
Definition: pnmImage.I:1007
void remove_egg(TextureReference *reference)
Notes that a particular egg file is no longer using this particular TexturePlacement.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:213
const PNMImage & read_source_image()
Reads in the original image, if it has not already been read, and returns it.
int get_x_size() const
Returns the size in the X dimension, in pixels, of the texture image as it must appear in the palette...
DestTextureImage * get_dest() const
Returns the DestTextureImage that corresponds to this texture as it was copied to the install directo...
int get_num_channels() const
Returns the number of channels in the image.
static LMatrix3d scale_mat(const LVecBase2d &scale)
Returns a matrix that applies the indicated scale in each of the two axes.
Definition: lmatrix.h:8359
void fill_swapped_image(PNMImage &image, int index)
Fills in the rectangle of the swapped palette image represented by the texture placement with the ima...
This is a single palette image, one of several within a PalettePage, which is in turn one of several ...
Definition: paletteImage.h:36
bool intersects(int x, int y, int x_size, int y_size)
Returns true if the particular position this texture has been assigned to overlaps the rectangle whos...
bool has_uvs() const
Returns true if this TextureReference actually uses the texture on geometry, with UV&#39;s and everything...
void add_int32(PN_int32 value)
Adds a signed 32-bit integer to the datagram.
Definition: datagram.I:159
void set_alpha_val(int x, int y, xelval a)
Sets the alpha component color only at the indicated pixel.
Definition: pnmImage.I:585
static const LMatrix3d & ident_mat()
Returns an identity matrix.
Definition: lmatrix.h:7128
A class to retrieve the individual data elements previously stored in a Datagram. ...
This represents a single source texture that is referenced by one or more egg files.
Definition: textureImage.h:51
void set_dest(DestTextureImage *dest)
Sets the DestTextureImage that corresponds to this texture as it was copied to the install directory...
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:43
int get_placed_y_size() const
Returns the size in the Y dimension, in pixels, of the texture image as it has been placed within the...
void set_xel(int x, int y, const LRGBColorf &value)
Changes the RGB color at the indicated pixel.
Definition: pnmImage.I:641
TexturePlacement * get_placement() const
Returns the particular TexturePlacement that is appropriate for this egg file.
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Called after the object is otherwise completely read from a Bam file, this function&#39;s job is to store...
void mark_eggs_stale()
Marks all the egg files that reference this placement stale.
void write_placed(ostream &out, int indent_level=0)
Writes the placement position information on a line by itself.
void fill_image(PNMImage &image)
Fills in the rectangle of the palette image represented by the texture placement with the image pixel...
bool is_placed() const
Returns true if the texture has been placed on a palette image, false otherwise.
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
Definition: bamWriter.cxx:279
void read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:658
void release_source_image()
Frees the memory that was allocated by a previous call to read_source_image().
This is the set of characteristics of a texture that, if different from another texture, prevent the two textures from sharing a PaletteImage.