Panda3D
 All Classes Functions Variables Enumerations
texture.cxx
1 // Filename: texture.cxx
2 // Created by: mike (09Jan97)
3 // Updated by: fperazzi, PandaSE(29Apr10) (added TT_2d_texture_array)
4 //
5 ////////////////////////////////////////////////////////////////////
6 //
7 // PANDA 3D SOFTWARE
8 // Copyright (c) Carnegie Mellon University. All rights reserved.
9 //
10 // All use of this software is subject to the terms of the revised BSD
11 // license. You should have received a copy of this license along
12 // with this source code in a file named "LICENSE."
13 //
14 ////////////////////////////////////////////////////////////////////
15 
16 #include "pandabase.h"
17 #include "texture.h"
18 #include "config_gobj.h"
19 #include "config_util.h"
20 #include "texturePool.h"
21 #include "textureContext.h"
22 #include "bamCache.h"
23 #include "bamCacheRecord.h"
24 #include "datagram.h"
25 #include "datagramIterator.h"
26 #include "bamReader.h"
27 #include "bamWriter.h"
28 #include "string_utils.h"
29 #include "preparedGraphicsObjects.h"
30 #include "pnmImage.h"
31 #include "pnmReader.h"
32 #include "pfmFile.h"
33 #include "virtualFileSystem.h"
34 #include "datagramInputFile.h"
35 #include "datagramOutputFile.h"
36 #include "bam.h"
37 #include "zStream.h"
38 #include "indent.h"
39 #include "cmath.h"
40 #include "pStatTimer.h"
41 #include "pbitops.h"
42 #include "streamReader.h"
43 #include "texturePeeker.h"
44 #include "convert_srgb.h"
45 
46 #ifdef HAVE_SQUISH
47 #include <squish.h>
48 #endif // HAVE_SQUISH
49 
50 #include <stddef.h>
51 
53 ("texture-quality-level", Texture::QL_normal,
54  PRC_DESC("This specifies a global quality level for all textures. You "
55  "may specify either fastest, normal, or best. This actually "
56  "affects the meaning of Texture::set_quality_level(QL_default), "
57  "so it may be overridden on a per-texture basis. This generally "
58  "only has an effect when using the tinydisplay software renderer; "
59  "it has little or no effect on normal, hardware-accelerated "
60  "renderers. See Texture::set_quality_level()."));
61 
62 PStatCollector Texture::_texture_read_pcollector("*:Texture:Read");
63 TypeHandle Texture::_type_handle;
64 TypeHandle Texture::CData::_type_handle;
65 AutoTextureScale Texture::_textures_power_2 = ATS_unspecified;
66 
67 // Stuff to read and write DDS files.
68 
69 // little-endian, of course
70 #define DDS_MAGIC 0x20534444
71 
72 
73 // DDS_header.dwFlags
74 #define DDSD_CAPS 0x00000001
75 #define DDSD_HEIGHT 0x00000002
76 #define DDSD_WIDTH 0x00000004
77 #define DDSD_PITCH 0x00000008
78 #define DDSD_PIXELFORMAT 0x00001000
79 #define DDSD_MIPMAPCOUNT 0x00020000
80 #define DDSD_LINEARSIZE 0x00080000
81 #define DDSD_DEPTH 0x00800000
82 
83 // DDS_header.sPixelFormat.dwFlags
84 #define DDPF_ALPHAPIXELS 0x00000001
85 #define DDPF_FOURCC 0x00000004
86 #define DDPF_INDEXED 0x00000020
87 #define DDPF_RGB 0x00000040
88 
89 // DDS_header.sCaps.dwCaps1
90 #define DDSCAPS_COMPLEX 0x00000008
91 #define DDSCAPS_TEXTURE 0x00001000
92 #define DDSCAPS_MIPMAP 0x00400000
93 
94 // DDS_header.sCaps.dwCaps2
95 #define DDSCAPS2_CUBEMAP 0x00000200
96 #define DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400
97 #define DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800
98 #define DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000
99 #define DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000
100 #define DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000
101 #define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000
102 #define DDSCAPS2_VOLUME 0x00200000
103 
105  unsigned int pf_size;
106  unsigned int pf_flags;
107  unsigned int four_cc;
108  unsigned int rgb_bitcount;
109  unsigned int r_mask;
110  unsigned int g_mask;
111  unsigned int b_mask;
112  unsigned int a_mask;
113 };
114 
115 struct DDSCaps2 {
116  unsigned int caps1;
117  unsigned int caps2;
118  unsigned int ddsx;
119 };
120 
121 struct DDSHeader {
122  unsigned int dds_magic;
123  unsigned int dds_size;
124  unsigned int dds_flags;
125  unsigned int height;
126  unsigned int width;
127  unsigned int pitch;
128  unsigned int depth;
129  unsigned int num_levels;
130 
131  DDSPixelFormat pf;
132  DDSCaps2 caps;
133 };
134 
135 ////////////////////////////////////////////////////////////////////
136 // Function: Texture::Constructor
137 // Access: Published
138 // Description: Constructs an empty texture. The default is to set
139 // up the texture as an empty 2-d texture; follow up
140 // with one of the variants of setup_texture() if this
141 // is not what you want.
142 ////////////////////////////////////////////////////////////////////
143 Texture::
144 Texture(const string &name) :
145  Namable(name),
146  _lock(name),
147  _cvar(_lock)
148 {
149  _reloading = false;
150 
151  CDWriter cdata(_cycler, true);
152  do_set_format(cdata, F_rgb);
153  do_set_component_type(cdata, T_unsigned_byte);
154 }
155 
156 ////////////////////////////////////////////////////////////////////
157 // Function: Texture::Copy Constructor
158 // Access: Protected
159 // Description: Use Texture::make_copy() to make a duplicate copy of
160 // an existing Texture.
161 ////////////////////////////////////////////////////////////////////
162 Texture::
163 Texture(const Texture &copy) :
164  Namable(copy),
165  _cycler(copy._cycler),
166  _lock(copy.get_name()),
167  _cvar(_lock)
168 {
169  _reloading = false;
170 }
171 
172 ////////////////////////////////////////////////////////////////////
173 // Function: Texture::Copy Assignment Operator
174 // Access: Protected
175 // Description: Use Texture::make_copy() to make a duplicate copy of
176 // an existing Texture.
177 ////////////////////////////////////////////////////////////////////
178 void Texture::
179 operator = (const Texture &copy) {
180  Namable::operator = (copy);
181  _cycler = copy._cycler;
182 }
183 
184 ////////////////////////////////////////////////////////////////////
185 // Function: Texture::Destructor
186 // Access: Published, Virtual
187 // Description:
188 ////////////////////////////////////////////////////////////////////
189 Texture::
190 ~Texture() {
191  release_all();
192  nassertv(!_reloading);
193 }
194 
195 ////////////////////////////////////////////////////////////////////
196 // Function: Texture::generate_normalization_cube_map
197 // Access: Published
198 // Description: Generates a special cube map image in the texture
199 // that can be used to apply bump mapping effects: for
200 // each texel in the cube map that is indexed by the 3-d
201 // texture coordinates (x, y, z), the resulting value is
202 // the normalized vector (x, y, z) (compressed from
203 // -1..1 into 0..1).
204 ////////////////////////////////////////////////////////////////////
205 void Texture::
207  CDWriter cdata(_cycler, true);
208  do_setup_texture(cdata, TT_cube_map, size, size, 6, T_unsigned_byte, F_rgb);
209  PTA_uchar image = do_make_ram_image(cdata);
210  cdata->_keep_ram_image = true;
211 
212  cdata->inc_image_modified();
213  cdata->inc_properties_modified();
214 
215  PN_stdfloat half_size = (PN_stdfloat)size * 0.5f;
216  PN_stdfloat center = half_size - 0.5f;
217 
218  LMatrix4 scale
219  (127.5f, 0.0f, 0.0f, 0.0f,
220  0.0f, 127.5f, 0.0f, 0.0f,
221  0.0f, 0.0f, 127.5f, 0.0f,
222  127.5f, 127.5f, 127.5f, 1.0f);
223 
224  unsigned char *p = image;
225  int xi, yi;
226 
227  // Page 0: positive X.
228  for (yi = 0; yi < size; ++yi) {
229  for (xi = 0; xi < size; ++xi) {
230  LVector3 vec(half_size, center - yi, center - xi);
231  vec.normalize();
232  vec = scale.xform_point(vec);
233 
234  *p++ = (unsigned char)vec[2];
235  *p++ = (unsigned char)vec[1];
236  *p++ = (unsigned char)vec[0];
237  }
238  }
239 
240  // Page 1: negative X.
241  for (yi = 0; yi < size; ++yi) {
242  for (xi = 0; xi < size; ++xi) {
243  LVector3 vec(-half_size, center - yi, xi - center);
244  vec.normalize();
245  vec = scale.xform_point(vec);
246  *p++ = (unsigned char)vec[2];
247  *p++ = (unsigned char)vec[1];
248  *p++ = (unsigned char)vec[0];
249  }
250  }
251 
252  // Page 2: positive Y.
253  for (yi = 0; yi < size; ++yi) {
254  for (xi = 0; xi < size; ++xi) {
255  LVector3 vec(xi - center, half_size, yi - center);
256  vec.normalize();
257  vec = scale.xform_point(vec);
258  *p++ = (unsigned char)vec[2];
259  *p++ = (unsigned char)vec[1];
260  *p++ = (unsigned char)vec[0];
261  }
262  }
263 
264  // Page 3: negative Y.
265  for (yi = 0; yi < size; ++yi) {
266  for (xi = 0; xi < size; ++xi) {
267  LVector3 vec(xi - center, -half_size, center - yi);
268  vec.normalize();
269  vec = scale.xform_point(vec);
270  *p++ = (unsigned char)vec[2];
271  *p++ = (unsigned char)vec[1];
272  *p++ = (unsigned char)vec[0];
273  }
274  }
275 
276  // Page 4: positive Z.
277  for (yi = 0; yi < size; ++yi) {
278  for (xi = 0; xi < size; ++xi) {
279  LVector3 vec(xi - center, center - yi, half_size);
280  vec.normalize();
281  vec = scale.xform_point(vec);
282  *p++ = (unsigned char)vec[2];
283  *p++ = (unsigned char)vec[1];
284  *p++ = (unsigned char)vec[0];
285  }
286  }
287 
288  // Page 5: negative Z.
289  for (yi = 0; yi < size; ++yi) {
290  for (xi = 0; xi < size; ++xi) {
291  LVector3 vec(center - xi, center - yi, -half_size);
292  vec.normalize();
293  vec = scale.xform_point(vec);
294  *p++ = (unsigned char)vec[2];
295  *p++ = (unsigned char)vec[1];
296  *p++ = (unsigned char)vec[0];
297  }
298  }
299 }
300 
301 ////////////////////////////////////////////////////////////////////
302 // Function: Texture::generate_alpha_scale_map
303 // Access: Published
304 // Description: Generates a special 256x1 1-d texture that can be
305 // used to apply an arbitrary alpha scale to objects by
306 // judicious use of texture matrix. The texture is a
307 // gradient, with an alpha of 0 on the left (U = 0), and
308 // 255 on the right (U = 1).
309 ////////////////////////////////////////////////////////////////////
310 void Texture::
312  CDWriter cdata(_cycler, true);
313  do_setup_texture(cdata, TT_1d_texture, 256, 1, 1, T_unsigned_byte, F_alpha);
314  cdata->_default_sampler.set_wrap_u(SamplerState::WM_clamp);
315  cdata->_default_sampler.set_minfilter(SamplerState::FT_nearest);
316  cdata->_default_sampler.set_magfilter(SamplerState::FT_nearest);
317 
318  cdata->_compression = CM_off;
319 
320  cdata->inc_image_modified();
321  cdata->inc_properties_modified();
322 
323  PTA_uchar image = do_make_ram_image(cdata);
324  cdata->_keep_ram_image = true;
325 
326  unsigned char *p = image;
327  for (int xi = 0; xi < 256; ++xi) {
328  *p++ = xi;
329  }
330 }
331 
332 ////////////////////////////////////////////////////////////////////
333 // Function: Texture::read
334 // Access: Published
335 // Description: Reads the named filename into the texture.
336 ////////////////////////////////////////////////////////////////////
337 bool Texture::
338 read(const Filename &fullpath, const LoaderOptions &options) {
339  CDWriter cdata(_cycler, true);
340  do_clear(cdata);
341  cdata->inc_properties_modified();
342  cdata->inc_image_modified();
343  return do_read(cdata, fullpath, Filename(), 0, 0, 0, 0, false, false,
344  options, NULL);
345 }
346 
347 ////////////////////////////////////////////////////////////////////
348 // Function: Texture::read
349 // Access: Published
350 // Description: Combine a 3-component image with a grayscale image
351 // to get a 4-component image.
352 //
353 // See the description of the full-parameter read()
354 // method for the meaning of the
355 // primary_file_num_channels and alpha_file_channel
356 // parameters.
357 ////////////////////////////////////////////////////////////////////
358 bool Texture::
359 read(const Filename &fullpath, const Filename &alpha_fullpath,
360  int primary_file_num_channels, int alpha_file_channel,
361  const LoaderOptions &options) {
362  CDWriter cdata(_cycler, true);
363  do_clear(cdata);
364  cdata->inc_properties_modified();
365  cdata->inc_image_modified();
366  return do_read(cdata, fullpath, alpha_fullpath, primary_file_num_channels,
367  alpha_file_channel, 0, 0, false, false,
368  options, NULL);
369 }
370 
371 ////////////////////////////////////////////////////////////////////
372 // Function: Texture::read
373 // Access: Published
374 // Description: Reads a single file into a single page or mipmap
375 // level, or automatically reads a series of files into
376 // a series of pages and/or mipmap levels.
377 //
378 // See the description of the full-parameter read()
379 // method for the meaning of the various parameters.
380 ////////////////////////////////////////////////////////////////////
381 bool Texture::
382 read(const Filename &fullpath, int z, int n,
383  bool read_pages, bool read_mipmaps,
384  const LoaderOptions &options) {
385  CDWriter cdata(_cycler, true);
386  cdata->inc_properties_modified();
387  cdata->inc_image_modified();
388  return do_read(cdata, fullpath, Filename(), 0, 0, z, n, read_pages, read_mipmaps,
389  options, NULL);
390 }
391 
392 ////////////////////////////////////////////////////////////////////
393 // Function: Texture::read
394 // Access: Published
395 // Description: Reads the texture from the indicated filename. If
396 // primary_file_num_channels is not 0, it specifies the
397 // number of components to downgrade the image to if it
398 // is greater than this number.
399 //
400 // If the filename has the extension .txo, this
401 // implicitly reads a texture object instead of a
402 // filename (which replaces all of the texture
403 // properties). In this case, all the rest of the
404 // parameters are ignored, and the filename should not
405 // contain any hash marks; just the one named file will
406 // be read, since a single .txo file can contain all
407 // pages and mipmaps necessary to define a texture.
408 //
409 // If alpha_fullpath is not empty, it specifies the name
410 // of a file from which to retrieve the alpha. In this
411 // case, alpha_file_channel represents the numeric
412 // channel of this image file to use as the resulting
413 // texture's alpha channel; usually, this is 0 to
414 // indicate the grayscale combination of r, g, b; or it
415 // may be a one-based channel number, e.g. 1 for the red
416 // channel, 2 for the green channel, and so on.
417 //
418 // If read pages is false, then z indicates the page
419 // number into which this image will be assigned.
420 // Normally this is 0 for the first (or only) page of
421 // the texture. 3-D textures have one page for each
422 // level of depth, and cube map textures always have six
423 // pages.
424 //
425 // If read_pages is true, multiple images will be read
426 // at once, one for each page of a cube map or a 3-D
427 // texture. In this case, the filename should contain a
428 // sequence of one or more hash marks ("#") which will
429 // be filled in with the z value of each page,
430 // zero-based. In this case, the z parameter indicates
431 // the maximum z value that will be loaded, or 0 to load
432 // all filenames that exist.
433 //
434 // If read_mipmaps is false, then n indicates the mipmap
435 // level to which this image will be assigned. Normally
436 // this is 0 for the base texture image, but it is
437 // possible to load custom mipmap levels into the later
438 // images. After the base texture image is loaded (thus
439 // defining the size of the texture), you can call
440 // get_expected_num_mipmap_levels() to determine the
441 // maximum sensible value for n.
442 //
443 // If read_mipmaps is true, multiple images will be read
444 // as above, but this time the images represent the
445 // different mipmap levels of the texture image. In
446 // this case, the n parameter indicates the maximum n
447 // value that will be loaded, or 0 to load all filenames
448 // that exist (up to the expected number of mipmap
449 // levels).
450 //
451 // If both read_pages and read_mipmaps is true, then
452 // both sequences will be read; the filename should
453 // contain two sequences of hash marks, separated by
454 // some character such as a hyphen, underscore, or dot.
455 // The first hash mark sequence will be filled in with
456 // the mipmap level, while the second hash mark sequence
457 // will be the page index.
458 //
459 // This method implicitly sets keep_ram_image to false.
460 ////////////////////////////////////////////////////////////////////
461 bool Texture::
462 read(const Filename &fullpath, const Filename &alpha_fullpath,
463  int primary_file_num_channels, int alpha_file_channel,
464  int z, int n, bool read_pages, bool read_mipmaps,
465  BamCacheRecord *record,
466  const LoaderOptions &options) {
467  CDWriter cdata(_cycler, true);
468  cdata->inc_properties_modified();
469  cdata->inc_image_modified();
470  return do_read(cdata, fullpath, alpha_fullpath, primary_file_num_channels,
471  alpha_file_channel, z, n, read_pages, read_mipmaps,
472  options, record);
473 }
474 
475 ////////////////////////////////////////////////////////////////////
476 // Function: Texture::estimate_texture_memory
477 // Access: Published
478 // Description: Estimates the amount of texture memory that will be
479 // consumed by loading this texture. This returns a
480 // value that is not specific to any particular graphics
481 // card or driver; it tries to make a reasonable
482 // assumption about how a driver will load the texture.
483 // It does not account for texture compression or
484 // anything fancy. This is mainly useful for debugging
485 // and reporting purposes.
486 //
487 // Returns a value in bytes.
488 ////////////////////////////////////////////////////////////////////
489 size_t Texture::
491  CDReader cdata(_cycler);
492  size_t pixels = cdata->_x_size * cdata->_y_size;
493 
494  size_t bpp = 4;
495  switch (cdata->_format) {
496  case Texture::F_rgb332:
497  bpp = 1;
498  break;
499 
500  case Texture::F_alpha:
501  case Texture::F_red:
502  case Texture::F_green:
503  case Texture::F_blue:
504  case Texture::F_luminance:
505  case Texture::F_sluminance:
506  bpp = 1;
507  break;
508 
509  case Texture::F_luminance_alpha:
510  case Texture::F_luminance_alphamask:
511  case Texture::F_sluminance_alpha:
512  bpp = 2;
513  break;
514 
515  case Texture::F_rgba:
516  case Texture::F_rgba4:
517  case Texture::F_rgbm:
518  case Texture::F_rgb:
519  case Texture::F_rgb5:
520  case Texture::F_rgba5:
521  case Texture::F_srgb:
522  bpp = 4;
523  break;
524 
525  case Texture::F_color_index:
526  case Texture::F_rgb8:
527  case Texture::F_rgba8:
528  case Texture::F_srgb_alpha:
529  case Texture::F_rgb8i:
530  case Texture::F_rgba8i:
531  bpp = 4;
532  break;
533 
534  case Texture::F_depth_stencil:
535  bpp = 4;
536  break;
537 
538  case Texture::F_depth_component:
539  bpp = 2;
540  break;
541 
542  case Texture::F_rgba12:
543  case Texture::F_rgb12:
544  bpp = 8;
545  break;
546 
547  case Texture::F_rgba16:
548  bpp = 8;
549  break;
550  case Texture::F_rgba32:
551  bpp = 16;
552  break;
553 
554  case Texture::F_r16:
555  case Texture::F_r8i:
556  case Texture::F_rg8i:
557  bpp = 2;
558  break;
559  case Texture::F_rg16:
560  bpp = 4;
561  break;
562  case Texture::F_rgb16:
563  bpp = 8;
564  break;
565 
566  case Texture::F_r32i:
567  bpp = 4;
568  break;
569 
570  case Texture::F_r32:
571  bpp = 4;
572  break;
573  case Texture::F_rg32:
574  bpp = 8;
575  break;
576  case Texture::F_rgb32:
577  bpp = 12;
578  break;
579 
580  default:
581  break;
582  }
583 
584  size_t bytes = pixels * bpp;
585  if (uses_mipmaps()) {
586  bytes = (bytes * 4) / 3;
587  }
588 
589  return bytes;
590 }
591 
592 ////////////////////////////////////////////////////////////////////
593 // Function: Texture::set_aux_data
594 // Access: Published
595 // Description: Records an arbitrary object in the Texture,
596 // associated with a specified key. The object may
597 // later be retrieved by calling get_aux_data() with the
598 // same key.
599 //
600 // These data objects are not recorded to a bam or txo
601 // file.
602 ////////////////////////////////////////////////////////////////////
603 void Texture::
604 set_aux_data(const string &key, TypedReferenceCount *aux_data) {
605  MutexHolder holder(_lock);
606  _aux_data[key] = aux_data;
607 }
608 
609 ////////////////////////////////////////////////////////////////////
610 // Function: Texture::clear_aux_data
611 // Access: Published
612 // Description: Removes a record previously recorded via
613 // set_aux_data().
614 ////////////////////////////////////////////////////////////////////
615 void Texture::
616 clear_aux_data(const string &key) {
617  MutexHolder holder(_lock);
618  _aux_data.erase(key);
619 }
620 
621 ////////////////////////////////////////////////////////////////////
622 // Function: Texture::get_aux_data
623 // Access: Published
624 // Description: Returns a record previously recorded via
625 // set_aux_data(). Returns NULL if there was no record
626 // associated with the indicated key.
627 ////////////////////////////////////////////////////////////////////
629 get_aux_data(const string &key) const {
630  MutexHolder holder(_lock);
631  AuxData::const_iterator di;
632  di = _aux_data.find(key);
633  if (di != _aux_data.end()) {
634  return (*di).second;
635  }
636  return NULL;
637 }
638 
639 ////////////////////////////////////////////////////////////////////
640 // Function: Texture::read_txo
641 // Access: Published
642 // Description: Reads the texture from a Panda texture object. This
643 // defines the complete Texture specification, including
644 // the image data as well as all texture properties.
645 // This only works if the txo file contains a static
646 // Texture image, as opposed to a subclass of Texture
647 // such as a movie texture.
648 //
649 // Pass a real filename if it is available, or empty
650 // string if it is not.
651 ////////////////////////////////////////////////////////////////////
652 bool Texture::
653 read_txo(istream &in, const string &filename) {
654  CDWriter cdata(_cycler, true);
655  cdata->inc_properties_modified();
656  cdata->inc_image_modified();
657  return do_read_txo(cdata, in, filename);
658 }
659 
660 ////////////////////////////////////////////////////////////////////
661 // Function: Texture::make_from_txo
662 // Access: Published, Static
663 // Description: Constructs a new Texture object from the txo file.
664 // This is similar to Texture::read_txo(), but it
665 // constructs and returns a new object, which allows it
666 // to return a subclass of Texture (for instance, a
667 // movie texture).
668 //
669 // Pass a real filename if it is available, or empty
670 // string if it is not.
671 ////////////////////////////////////////////////////////////////////
672 PT(Texture) Texture::
673 make_from_txo(istream &in, const string &filename) {
674  DatagramInputFile din;
675 
676  if (!din.open(in, filename)) {
677  gobj_cat.error()
678  << "Could not read texture object: " << filename << "\n";
679  return NULL;
680  }
681 
682  string head;
683  if (!din.read_header(head, _bam_header.size())) {
684  gobj_cat.error()
685  << filename << " is not a texture object file.\n";
686  return NULL;
687  }
688 
689  if (head != _bam_header) {
690  gobj_cat.error()
691  << filename << " is not a texture object file.\n";
692  return NULL;
693  }
694 
695  BamReader reader(&din);
696  if (!reader.init()) {
697  return NULL;
698  }
699 
700  TypedWritable *object = reader.read_object();
701 
702  if (object != (TypedWritable *)NULL &&
703  object->is_exact_type(BamCacheRecord::get_class_type())) {
704  // Here's a special case: if the first object in the file is a
705  // BamCacheRecord, it's really a cache data file and not a true
706  // txo file; but skip over the cache data record and let the user
707  // treat it like an ordinary txo file.
708  object = reader.read_object();
709  }
710 
711  if (object == (TypedWritable *)NULL) {
712  gobj_cat.error()
713  << "Texture object " << filename << " is empty.\n";
714  return NULL;
715 
716  } else if (!object->is_of_type(Texture::get_class_type())) {
717  gobj_cat.error()
718  << "Texture object " << filename << " contains a "
719  << object->get_type() << ", not a Texture.\n";
720  return NULL;
721  }
722 
723  PT(Texture) other = DCAST(Texture, object);
724  if (!reader.resolve()) {
725  gobj_cat.error()
726  << "Unable to fully resolve texture object file.\n";
727  return NULL;
728  }
729 
730  return other;
731 }
732 
733 ////////////////////////////////////////////////////////////////////
734 // Function: Texture::write_txo
735 // Access: Published
736 // Description: Writes the texture to a Panda texture object. This
737 // defines the complete Texture specification, including
738 // the image data as well as all texture properties.
739 //
740 // The filename is just for reference.
741 ////////////////////////////////////////////////////////////////////
742 bool Texture::
743 write_txo(ostream &out, const string &filename) const {
744  CDReader cdata(_cycler);
745  return do_write_txo(cdata, out, filename);
746 }
747 
748 ////////////////////////////////////////////////////////////////////
749 // Function: Texture::read_dds
750 // Access: Published
751 // Description: Reads the texture from a DDS file object. This is a
752 // Microsoft-defined file format; it is similar in
753 // principle to a txo object, in that it is designed to
754 // contain the texture image in a form as similar as
755 // possible to its runtime image, and it can contain
756 // mipmaps, pre-compressed textures, and so on.
757 //
758 // As with read_txo, the filename is just for reference.
759 ////////////////////////////////////////////////////////////////////
760 bool Texture::
761 read_dds(istream &in, const string &filename, bool header_only) {
762  CDWriter cdata(_cycler, true);
763  cdata->inc_properties_modified();
764  cdata->inc_image_modified();
765  return do_read_dds(cdata, in, filename, header_only);
766 }
767 
768 ////////////////////////////////////////////////////////////////////
769 // Function: Texture::load_related
770 // Access: Published
771 // Description: Loads a texture whose filename is derived by
772 // concatenating a suffix to the filename of this
773 // texture. May return NULL, for example, if this
774 // texture doesn't have a filename.
775 ////////////////////////////////////////////////////////////////////
777 load_related(const InternalName *suffix) const {
778  MutexHolder holder(_lock);
779  CDReader cdata(_cycler);
780 
781  RelatedTextures::const_iterator ti;
782  ti = _related_textures.find(suffix);
783  if (ti != _related_textures.end()) {
784  return (*ti).second;
785  }
786  if (cdata->_fullpath.empty()) {
787  return (Texture*)NULL;
788  }
789  Filename main = cdata->_fullpath;
791  suffix->get_name());
792  PT(Texture) res;
793  if (!cdata->_alpha_fullpath.empty()) {
794  Filename alph = cdata->_alpha_fullpath;
796  suffix->get_name());
798  if (vfs->exists(alph)) {
799  // The alpha variant of the filename, with the suffix, exists.
800  // Use it to load the texture.
801  res = TexturePool::load_texture(main, alph,
802  cdata->_primary_file_num_channels,
803  cdata->_alpha_file_channel, false);
804  } else {
805  // If the alpha variant of the filename doesn't exist, just go
806  // ahead and load the related texture without alpha.
807  res = TexturePool::load_texture(main);
808  }
809 
810  } else {
811  // No alpha filename--just load the single file. It doesn't
812  // necessarily have the same number of channels as this one.
813  res = TexturePool::load_texture(main);
814  }
815 
816  // I'm casting away the const-ness of 'this' because this
817  // field is only a cache.
818  ((Texture *)this)->_related_textures.insert(RelatedTextures::value_type(suffix, res));
819  return res;
820 }
821 
822 ////////////////////////////////////////////////////////////////////
823 // Function: Texture::set_ram_image_as
824 // Access: Published
825 // Description: Replaces the current system-RAM image with the new
826 // data, converting it first if necessary from the
827 // indicated component-order format. See
828 // get_ram_image_as() for specifications about the
829 // format. This method cannot support compressed image
830 // data or sub-pages; use set_ram_image() for that.
831 ////////////////////////////////////////////////////////////////////
832 void Texture::
833 set_ram_image_as(CPTA_uchar image, const string &supplied_format) {
834  CDWriter cdata(_cycler, true);
835 
836  string format = upcase(supplied_format);
837 
838  // Make sure we can grab something that's uncompressed.
839  int imgsize = cdata->_x_size * cdata->_y_size;
840  nassertv(image.size() == (size_t)(cdata->_component_width * format.size() * imgsize));
841 
842  // Check if the format is already what we have internally.
843  if ((cdata->_num_components == 1 && format.size() == 1) ||
844  (cdata->_num_components == 2 && format.size() == 2 && format.at(1) == 'A' && format.at(0) != 'A') ||
845  (cdata->_num_components == 3 && format == "BGR") ||
846  (cdata->_num_components == 4 && format == "BGRA")) {
847  // The format string is already our format, so we just need to copy it.
848  do_set_ram_image(cdata, image);
849  return;
850  }
851 
852  // Create a new empty array that can hold our image.
853  PTA_uchar newdata = PTA_uchar::empty_array(imgsize * cdata->_num_components * cdata->_component_width, get_class_type());
854 
855  // These ifs are for optimization of commonly used image types.
856  if (cdata->_component_width == 1) {
857  if (format == "RGBA" && cdata->_num_components == 4) {
858  imgsize *= 4;
859  for (int p = 0; p < imgsize; p += 4) {
860  newdata[p + 2] = image[p ];
861  newdata[p + 1] = image[p + 1];
862  newdata[p ] = image[p + 2];
863  newdata[p + 3] = image[p + 3];
864  }
865  do_set_ram_image(cdata, newdata);
866  return;
867  }
868  if (format == "RGB" && cdata->_num_components == 3) {
869  imgsize *= 3;
870  for (int p = 0; p < imgsize; p += 3) {
871  newdata[p + 2] = image[p ];
872  newdata[p + 1] = image[p + 1];
873  newdata[p ] = image[p + 2];
874  }
875  do_set_ram_image(cdata, newdata);
876  return;
877  }
878  if (format == "A" && cdata->_num_components != 3) {
879  // We can generally rely on alpha to be the last component.
880  int component = cdata->_num_components - 1;
881  for (int p = 0; p < imgsize; ++p) {
882  newdata[component] = image[p];
883  }
884  do_set_ram_image(cdata, newdata);
885  return;
886  }
887  for (int p = 0; p < imgsize; ++p) {
888  for (uchar s = 0; s < format.size(); ++s) {
889  signed char component = -1;
890  if (format.at(s) == 'B' || (cdata->_num_components <= 2 && format.at(s) != 'A')) {
891  component = 0;
892  } else if (format.at(s) == 'G') {
893  component = 1;
894  } else if (format.at(s) == 'R') {
895  component = 2;
896  } else if (format.at(s) == 'A') {
897  nassertv(cdata->_num_components != 3);
898  component = cdata->_num_components - 1;
899  } else if (format.at(s) == '0') {
900  // Ignore.
901  } else if (format.at(s) == '1') {
902  // Ignore.
903  } else {
904  gobj_cat.error() << "Unexpected component character '"
905  << format.at(s) << "', expected one of RGBA!\n";
906  return;
907  }
908  if (component >= 0) {
909  newdata[p * cdata->_num_components + component] = image[p * format.size() + s];
910  }
911  }
912  }
913  do_set_ram_image(cdata, newdata);
914  return;
915  }
916  for (int p = 0; p < imgsize; ++p) {
917  for (uchar s = 0; s < format.size(); ++s) {
918  signed char component = -1;
919  if (format.at(s) == 'B' || (cdata->_num_components <= 2 && format.at(s) != 'A')) {
920  component = 0;
921  } else if (format.at(s) == 'G') {
922  component = 1;
923  } else if (format.at(s) == 'R') {
924  component = 2;
925  } else if (format.at(s) == 'A') {
926  nassertv(cdata->_num_components != 3);
927  component = cdata->_num_components - 1;
928  } else if (format.at(s) == '0') {
929  // Ignore.
930  } else if (format.at(s) == '1') {
931  // Ignore.
932  } else {
933  gobj_cat.error() << "Unexpected component character '"
934  << format.at(s) << "', expected one of RGBA!\n";
935  return;
936  }
937  if (component >= 0) {
938  memcpy((void*)(newdata + (p * cdata->_num_components + component) * cdata->_component_width),
939  (void*)(image + (p * format.size() + s) * cdata->_component_width),
940  cdata->_component_width);
941  }
942  }
943  }
944  do_set_ram_image(cdata, newdata);
945  return;
946 }
947 
948 ////////////////////////////////////////////////////////////////////
949 // Function: Texture::get_keep_ram_image
950 // Access: Published, Virtual
951 // Description: Returns the flag that indicates whether this Texture
952 // is eligible to have its main RAM copy of the texture
953 // memory dumped when the texture is prepared for
954 // rendering. See set_keep_ram_image().
955 ////////////////////////////////////////////////////////////////////
956 bool Texture::
958  CDReader cdata(_cycler);
959  return cdata->_keep_ram_image;
960 }
961 
962 ////////////////////////////////////////////////////////////////////
963 // Function: Texture::is_cacheable
964 // Access: Published, Virtual
965 // Description: Returns true if there is enough information in this
966 // Texture object to write it to the bam cache
967 // successfully, false otherwise. For most textures,
968 // this is the same as has_ram_image().
969 ////////////////////////////////////////////////////////////////////
970 bool Texture::
971 is_cacheable() const {
972  CDReader cdata(_cycler);
973  return do_has_bam_rawdata(cdata);
974 }
975 
976 ////////////////////////////////////////////////////////////////////
977 // Function: Texture::get_num_loadable_ram_mipmap_images
978 // Access: Published
979 // Description: Returns the number of contiguous mipmap levels that
980 // exist in RAM, up until the first gap in the sequence.
981 // It is guaranteed that at least mipmap levels [0,
982 // get_num_ram_mipmap_images()) exist.
983 //
984 // The number returned will never exceed the number of
985 // required mipmap images based on the size of the
986 // texture and its filter mode.
987 //
988 // This method is different from
989 // get_num_ram_mipmap_images() in that it returns only
990 // the number of mipmap levels that can actually be
991 // usefully loaded, regardless of the actual number that
992 // may be stored.
993 ////////////////////////////////////////////////////////////////////
994 int Texture::
996  CDReader cdata(_cycler);
997  if (cdata->_ram_images.empty() || cdata->_ram_images[0]._image.empty()) {
998  // If we don't even have a base image, the answer is none.
999  return 0;
1000  }
1001  if (!uses_mipmaps()) {
1002  // If we have a base image and don't require mipmapping, the
1003  // answer is 1.
1004  return 1;
1005  }
1006 
1007  // Check that we have enough mipmap levels to meet the size
1008  // requirements.
1009  int size = max(cdata->_x_size, max(cdata->_y_size, cdata->_z_size));
1010  int n = 0;
1011  int x = 1;
1012  while (x < size) {
1013  x = (x << 1);
1014  ++n;
1015  if (n >= (int)cdata->_ram_images.size() || cdata->_ram_images[n]._image.empty()) {
1016  return n;
1017  }
1018  }
1019 
1020  ++n;
1021  return n;
1022 }
1023 
1024 ////////////////////////////////////////////////////////////////////
1025 // Function: Texture::get_ram_mipmap_image
1026 // Access: Published
1027 // Description: Returns the system-RAM image data associated with the
1028 // nth mipmap level, if present. Returns NULL if the
1029 // nth mipmap level is not present.
1030 ////////////////////////////////////////////////////////////////////
1032 get_ram_mipmap_image(int n) const {
1033  CDReader cdata(_cycler);
1034  if (n < (int)cdata->_ram_images.size() && !cdata->_ram_images[n]._image.empty()) {
1035  return cdata->_ram_images[n]._image;
1036  }
1037  return CPTA_uchar(get_class_type());
1038 }
1039 
1040 ////////////////////////////////////////////////////////////////////
1041 // Function: Texture::get_ram_mipmap_pointer
1042 // Access: Published
1043 // Description: Similiar to get_ram_mipmap_image(), however, in this
1044 // case the void pointer for the given ram image is
1045 // returned. This will be NULL unless it has been
1046 // explicitly set.
1047 ////////////////////////////////////////////////////////////////////
1048 void *Texture::
1050  CDReader cdata(_cycler);
1051  if (n < (int)cdata->_ram_images.size()) {
1052  return cdata->_ram_images[n]._pointer_image;
1053  }
1054  return NULL;
1055 }
1056 
1057 ////////////////////////////////////////////////////////////////////
1058 // Function: Texture::set_ram_mipmap_pointer
1059 // Access: Published
1060 // Description: Sets an explicit void pointer as the texture's mipmap
1061 // image for the indicated level. This is a special
1062 // call to direct a texture to reference some external
1063 // image location, for instance from a webcam input.
1064 //
1065 // The texture will henceforth reference this pointer
1066 // directly, instead of its own internal storage; the
1067 // user is responsible for ensuring the data at this
1068 // address remains allocated and valid, and in the
1069 // correct format, during the lifetime of the texture.
1070 ////////////////////////////////////////////////////////////////////
1071 void Texture::
1072 set_ram_mipmap_pointer(int n, void *image, size_t page_size) {
1073  CDWriter cdata(_cycler, true);
1074  nassertv(cdata->_ram_image_compression != CM_off || do_get_expected_ram_mipmap_image_size(cdata, n));
1075 
1076  while (n >= (int)cdata->_ram_images.size()) {
1077  cdata->_ram_images.push_back(RamImage());
1078  }
1079 
1080  cdata->_ram_images[n]._page_size = page_size;
1081  //_ram_images[n]._image.clear(); wtf is going on?!
1082  cdata->_ram_images[n]._pointer_image = image;
1083  cdata->inc_image_modified();
1084 }
1085 
1086 ////////////////////////////////////////////////////////////////////
1087 // Function: Texture::set_ram_mipmap_pointer_from_int
1088 // Access: Published
1089 // Description: Accepts a raw pointer cast as an int, which is then
1090 // passed to set_ram_mipmap_pointer(); see the
1091 // documentation for that method.
1092 //
1093 // This variant is particularly useful to set an
1094 // external pointer from a language like Python, which
1095 // doesn't support void pointers directly.
1096 ////////////////////////////////////////////////////////////////////
1097 void Texture::
1098 set_ram_mipmap_pointer_from_int(long long pointer, int n, int page_size) {
1099  set_ram_mipmap_pointer(n, (void*)pointer, (size_t)page_size);
1100 }
1101 
1102 ////////////////////////////////////////////////////////////////////
1103 // Function: Texture::clear_ram_mipmap_image
1104 // Access: Published
1105 // Description: Discards the current system-RAM image for the nth
1106 // mipmap level.
1107 ////////////////////////////////////////////////////////////////////
1108 void Texture::
1110  CDWriter cdata(_cycler, true);
1111  if (n >= (int)cdata->_ram_images.size()) {
1112  return;
1113  }
1114  cdata->_ram_images[n]._page_size = 0;
1115  cdata->_ram_images[n]._image.clear();
1116  cdata->_ram_images[n]._pointer_image = NULL;
1117 }
1118 
1119 ////////////////////////////////////////////////////////////////////
1120 // Function: Texture::modify_simple_ram_image
1121 // Access: Published
1122 // Description: Returns a modifiable pointer to the internal "simple"
1123 // texture image. See set_simple_ram_image().
1124 ////////////////////////////////////////////////////////////////////
1125 PTA_uchar Texture::
1127  CDWriter cdata(_cycler, true);
1128  cdata->_simple_image_date_generated = (PN_int32)time(NULL);
1129  return cdata->_simple_ram_image._image;
1130 }
1131 
1132 ////////////////////////////////////////////////////////////////////
1133 // Function: Texture::new_simple_ram_image
1134 // Access: Published
1135 // Description: Creates an empty array for the simple ram image of
1136 // the indicated size, and returns a modifiable pointer
1137 // to the new array. See set_simple_ram_image().
1138 ////////////////////////////////////////////////////////////////////
1139 PTA_uchar Texture::
1140 new_simple_ram_image(int x_size, int y_size) {
1141  CDWriter cdata(_cycler, true);
1142  nassertr(cdata->_texture_type == TT_2d_texture, PTA_uchar());
1143  size_t expected_page_size = (size_t)(x_size * y_size * 4);
1144 
1145  cdata->_simple_x_size = x_size;
1146  cdata->_simple_y_size = y_size;
1147  cdata->_simple_ram_image._image = PTA_uchar::empty_array(expected_page_size);
1148  cdata->_simple_ram_image._page_size = expected_page_size;
1149  cdata->_simple_image_date_generated = (PN_int32)time(NULL);
1150  cdata->inc_simple_image_modified();
1151 
1152  return cdata->_simple_ram_image._image;
1153 }
1154 
1155 ////////////////////////////////////////////////////////////////////
1156 // Function: Texture::generate_simple_ram_image
1157 // Access: Published
1158 // Description: Computes the "simple" ram image by loading the main
1159 // RAM image, if it is not already available, and
1160 // reducing it to 16x16 or smaller. This may be an
1161 // expensive operation.
1162 ////////////////////////////////////////////////////////////////////
1163 void Texture::
1165  CDWriter cdata(_cycler, true);
1166 
1167  if (cdata->_texture_type != TT_2d_texture ||
1168  cdata->_ram_image_compression != CM_off) {
1169  return;
1170  }
1171 
1172  PNMImage pnmimage;
1173  if (!do_store_one(cdata, pnmimage, 0, 0)) {
1174  return;
1175  }
1176 
1177  // Start at the suggested size from the config file.
1178  int x_size = simple_image_size.get_word(0);
1179  int y_size = simple_image_size.get_word(1);
1180 
1181  // Limit it to no larger than the source image, and also make it a
1182  // power of two.
1183  x_size = down_to_power_2(min(x_size, cdata->_x_size));
1184  y_size = down_to_power_2(min(y_size, cdata->_y_size));
1185 
1186  // Generate a reduced image of that size.
1187  PNMImage scaled(x_size, y_size, pnmimage.get_num_channels());
1188  scaled.quick_filter_from(pnmimage);
1189 
1190  // Make sure the reduced image has 4 components, by convention.
1191  if (!scaled.has_alpha()) {
1192  scaled.add_alpha();
1193  scaled.alpha_fill(1.0);
1194  }
1195  scaled.set_num_channels(4);
1196 
1197  // Now see if we can go even smaller.
1198  bool did_anything;
1199  do {
1200  did_anything = false;
1201 
1202  // Try to reduce X.
1203  if (x_size > 1) {
1204  int new_x_size = (x_size >> 1);
1205  PNMImage smaller(new_x_size, y_size, 4);
1206  smaller.quick_filter_from(scaled);
1207  PNMImage bigger(x_size, y_size, 4);
1208  bigger.quick_filter_from(smaller);
1209 
1210  if (compare_images(scaled, bigger)) {
1211  scaled.take_from(smaller);
1212  x_size = new_x_size;
1213  did_anything = true;
1214  }
1215  }
1216 
1217  // Try to reduce Y.
1218  if (y_size > 1) {
1219  int new_y_size = (y_size >> 1);
1220  PNMImage smaller(x_size, new_y_size, 4);
1221  smaller.quick_filter_from(scaled);
1222  PNMImage bigger(x_size, y_size, 4);
1223  bigger.quick_filter_from(smaller);
1224 
1225  if (compare_images(scaled, bigger)) {
1226  scaled.take_from(smaller);
1227  y_size = new_y_size;
1228  did_anything = true;
1229  }
1230  }
1231  } while (did_anything);
1232 
1233  size_t expected_page_size = (size_t)(x_size * y_size * 4);
1234  PTA_uchar image = PTA_uchar::empty_array(expected_page_size, get_class_type());
1235  convert_from_pnmimage(image, expected_page_size, x_size, 0, 0, 0, scaled, 4, 1);
1236 
1237  do_set_simple_ram_image(cdata, image, x_size, y_size);
1238  cdata->_simple_image_date_generated = (PN_int32)time(NULL);
1239 }
1240 
1241 ////////////////////////////////////////////////////////////////////
1242 // Function: Texture::peek
1243 // Access: Published
1244 // Description: Returns a TexturePeeker object that can be used to
1245 // examine the individual texels stored within this
1246 // Texture by (u, v) coordinate.
1247 //
1248 // If the texture has a ram image resident, that image
1249 // is used. If it does not have a full ram image but
1250 // does have a simple_ram_image resident, that image is
1251 // used instead. If neither image is resident the full
1252 // image is reloaded.
1253 //
1254 // Returns NULL if the texture cannot find an image to
1255 // load, or the texture format is incompatible.
1256 ////////////////////////////////////////////////////////////////////
1257 PT(TexturePeeker) Texture::
1258 peek() {
1259  CDWriter cdata(_cycler, unlocked_ensure_ram_image(true));
1260 
1261  PT(TexturePeeker) peeker = new TexturePeeker(this, cdata);
1262  if (peeker->is_valid()) {
1263  return peeker;
1264  }
1265 
1266  return NULL;
1267 }
1268 
1269 ////////////////////////////////////////////////////////////////////
1270 // Function: Texture::prepare
1271 // Access: Published
1272 // Description: Indicates that the texture should be enqueued to be
1273 // prepared in the indicated prepared_objects at the
1274 // beginning of the next frame. This will ensure the
1275 // texture is already loaded into texture memory if it
1276 // is expected to be rendered soon.
1277 //
1278 // Use this function instead of prepare_now() to preload
1279 // textures from a user interface standpoint.
1280 ////////////////////////////////////////////////////////////////////
1281 void Texture::
1282 prepare(PreparedGraphicsObjects *prepared_objects) {
1283  prepared_objects->enqueue_texture(this);
1284 }
1285 
1286 ////////////////////////////////////////////////////////////////////
1287 // Function: Texture::is_prepared
1288 // Access: Published
1289 // Description: Returns true if the texture has already been prepared
1290 // or enqueued for preparation on the indicated GSG,
1291 // false otherwise.
1292 ////////////////////////////////////////////////////////////////////
1293 bool Texture::
1294 is_prepared(PreparedGraphicsObjects *prepared_objects) const {
1295  MutexHolder holder(_lock);
1296  PreparedViews::const_iterator pvi;
1297  pvi = _prepared_views.find(prepared_objects);
1298  if (pvi != _prepared_views.end()) {
1299  return true;
1300  }
1301  return prepared_objects->is_texture_queued(this);
1302 }
1303 
1304 ////////////////////////////////////////////////////////////////////
1305 // Function: Texture::was_image_modified
1306 // Access: Published
1307 // Description: Returns true if the texture needs to be re-loaded
1308 // onto the indicated GSG, either because its image data
1309 // is out-of-date, or because it's not fully prepared
1310 // now.
1311 ////////////////////////////////////////////////////////////////////
1312 bool Texture::
1314  MutexHolder holder(_lock);
1315  CDReader cdata(_cycler);
1316 
1317  PreparedViews::const_iterator pvi;
1318  pvi = _prepared_views.find(prepared_objects);
1319  if (pvi != _prepared_views.end()) {
1320  const Contexts &contexts = (*pvi).second;
1321  for (int view = 0; view < cdata->_num_views; ++view) {
1322  Contexts::const_iterator ci;
1323  ci = contexts.find(view);
1324  if (ci == contexts.end()) {
1325  return true;
1326  }
1327  TextureContext *tc = (*ci).second;
1328  if (tc->was_image_modified()) {
1329  return true;
1330  }
1331  }
1332  return false;
1333  }
1334  return true;
1335 }
1336 
1337 ////////////////////////////////////////////////////////////////////
1338 // Function: Texture::get_data_size_bytes
1339 // Access: Public
1340 // Description: Returns the number of bytes which the texture is
1341 // reported to consume within graphics memory, for the
1342 // indicated GSG. This may return a nonzero value even
1343 // if the texture is not currently resident; you should
1344 // also check get_resident() if you want to know how
1345 // much space the texture is actually consuming right
1346 // now.
1347 ////////////////////////////////////////////////////////////////////
1348 size_t Texture::
1350  MutexHolder holder(_lock);
1351  CDReader cdata(_cycler);
1352 
1353  PreparedViews::const_iterator pvi;
1354  size_t total_size = 0;
1355  pvi = _prepared_views.find(prepared_objects);
1356  if (pvi != _prepared_views.end()) {
1357  const Contexts &contexts = (*pvi).second;
1358  for (int view = 0; view < cdata->_num_views; ++view) {
1359  Contexts::const_iterator ci;
1360  ci = contexts.find(view);
1361  if (ci != contexts.end()) {
1362  TextureContext *tc = (*ci).second;
1363  total_size += tc->get_data_size_bytes();
1364  }
1365  }
1366  }
1367 
1368  return total_size;
1369 }
1370 
1371 ////////////////////////////////////////////////////////////////////
1372 // Function: Texture::get_active
1373 // Access: Public
1374 // Description: Returns true if this Texture was rendered in the most
1375 // recent frame within the indicated GSG.
1376 ////////////////////////////////////////////////////////////////////
1377 bool Texture::
1378 get_active(PreparedGraphicsObjects *prepared_objects) const {
1379  MutexHolder holder(_lock);
1380  CDReader cdata(_cycler);
1381 
1382  PreparedViews::const_iterator pvi;
1383  pvi = _prepared_views.find(prepared_objects);
1384  if (pvi != _prepared_views.end()) {
1385  const Contexts &contexts = (*pvi).second;
1386  for (int view = 0; view < cdata->_num_views; ++view) {
1387  Contexts::const_iterator ci;
1388  ci = contexts.find(view);
1389  if (ci != contexts.end()) {
1390  TextureContext *tc = (*ci).second;
1391  if (tc->get_active()) {
1392  return true;
1393  }
1394  }
1395  }
1396  }
1397  return false;
1398 }
1399 
1400 ////////////////////////////////////////////////////////////////////
1401 // Function: Texture::get_resident
1402 // Access: Public
1403 // Description: Returns true if this Texture is reported to be
1404 // resident within graphics memory for the indicated
1405 // GSG.
1406 ////////////////////////////////////////////////////////////////////
1407 bool Texture::
1408 get_resident(PreparedGraphicsObjects *prepared_objects) const {
1409  MutexHolder holder(_lock);
1410  CDReader cdata(_cycler);
1411 
1412  PreparedViews::const_iterator pvi;
1413  pvi = _prepared_views.find(prepared_objects);
1414  if (pvi != _prepared_views.end()) {
1415  const Contexts &contexts = (*pvi).second;
1416  for (int view = 0; view < cdata->_num_views; ++view) {
1417  Contexts::const_iterator ci;
1418  ci = contexts.find(view);
1419  if (ci != contexts.end()) {
1420  TextureContext *tc = (*ci).second;
1421  if (tc->get_resident()) {
1422  return true;
1423  }
1424  }
1425  }
1426  }
1427  return false;
1428 }
1429 
1430 ////////////////////////////////////////////////////////////////////
1431 // Function: Texture::release
1432 // Access: Published
1433 // Description: Frees the texture context only on the indicated object,
1434 // if it exists there. Returns true if it was released,
1435 // false if it had not been prepared.
1436 ////////////////////////////////////////////////////////////////////
1437 bool Texture::
1438 release(PreparedGraphicsObjects *prepared_objects) {
1439  MutexHolder holder(_lock);
1440  PreparedViews::iterator pvi;
1441  pvi = _prepared_views.find(prepared_objects);
1442  if (pvi != _prepared_views.end()) {
1443  Contexts temp;
1444  temp.swap((*pvi).second);
1445  Contexts::iterator ci;
1446  for (ci = temp.begin(); ci != temp.end(); ++ci) {
1447  TextureContext *tc = (*ci).second;
1448  if (tc != (TextureContext *)NULL) {
1449  prepared_objects->release_texture(tc);
1450  }
1451  }
1452  _prepared_views.erase(pvi);
1453  }
1454 
1455  // Maybe it wasn't prepared yet, but it's about to be.
1456  return prepared_objects->dequeue_texture(this);
1457 }
1458 
1459 ////////////////////////////////////////////////////////////////////
1460 // Function: Texture::release_all
1461 // Access: Published
1462 // Description: Frees the context allocated on all objects for which
1463 // the texture has been declared. Returns the number of
1464 // contexts which have been freed.
1465 ////////////////////////////////////////////////////////////////////
1466 int Texture::
1468  MutexHolder holder(_lock);
1469 
1470  // We have to traverse a copy of the _prepared_views list, because the
1471  // PreparedGraphicsObjects object will call clear_prepared() in response
1472  // to each release_texture(), and we don't want to be modifying the
1473  // _prepared_views list while we're traversing it.
1474  PreparedViews temp;
1475  temp.swap(_prepared_views);
1476  int num_freed = (int)temp.size();
1477 
1478  PreparedViews::iterator pvi;
1479  for (pvi = temp.begin(); pvi != temp.end(); ++pvi) {
1480  PreparedGraphicsObjects *prepared_objects = (*pvi).first;
1481  Contexts temp;
1482  temp.swap((*pvi).second);
1483  Contexts::iterator ci;
1484  for (ci = temp.begin(); ci != temp.end(); ++ci) {
1485  TextureContext *tc = (*ci).second;
1486  if (tc != (TextureContext *)NULL) {
1487  prepared_objects->release_texture(tc);
1488  }
1489  }
1490  }
1491 
1492  return num_freed;
1493 }
1494 
1495 ////////////////////////////////////////////////////////////////////
1496 // Function: Texture::write
1497 // Access: Published
1498 // Description: Not to be confused with write(Filename), this method
1499 // simply describes the texture properties.
1500 ////////////////////////////////////////////////////////////////////
1501 void Texture::
1502 write(ostream &out, int indent_level) const {
1503  CDReader cdata(_cycler);
1504  indent(out, indent_level)
1505  << cdata->_texture_type << " " << get_name();
1506  if (!cdata->_filename.empty()) {
1507  out << " (from " << cdata->_filename << ")";
1508  }
1509  out << "\n";
1510 
1511  indent(out, indent_level + 2);
1512 
1513  switch (cdata->_texture_type) {
1514  case TT_1d_texture:
1515  out << "1-d, " << cdata->_x_size;
1516  break;
1517 
1518  case TT_2d_texture:
1519  out << "2-d, " << cdata->_x_size << " x " << cdata->_y_size;
1520  break;
1521 
1522  case TT_3d_texture:
1523  out << "3-d, " << cdata->_x_size << " x " << cdata->_y_size << " x " << cdata->_z_size;
1524  break;
1525 
1526  case TT_2d_texture_array:
1527  out << "2-d array, " << cdata->_x_size << " x " << cdata->_y_size << " x " << cdata->_z_size;
1528  break;
1529 
1530  case TT_cube_map:
1531  out << "cube map, " << cdata->_x_size << " x " << cdata->_y_size;
1532  break;
1533  }
1534 
1535  if (cdata->_num_views > 1) {
1536  out << " (x " << cdata->_num_views << " views)";
1537  }
1538 
1539  out << " pixels, each " << cdata->_num_components;
1540 
1541  switch (cdata->_component_type) {
1542  case T_unsigned_byte:
1543  out << " bytes";
1544  break;
1545 
1546  case T_unsigned_short:
1547  out << " shorts";
1548  break;
1549 
1550  case T_float:
1551  out << " floats";
1552  break;
1553 
1554  case T_unsigned_int_24_8:
1555  case T_int:
1556  out << " ints";
1557  break;
1558 
1559  default:
1560  break;
1561  }
1562 
1563  out << ", ";
1564  switch (cdata->_format) {
1565  case F_color_index:
1566  out << "color_index";
1567  break;
1568  case F_depth_stencil:
1569  out << "depth_stencil";
1570  break;
1571  case F_depth_component:
1572  out << "depth_component";
1573  break;
1574  case F_depth_component16:
1575  out << "depth_component16";
1576  break;
1577  case F_depth_component24:
1578  out << "depth_component24";
1579  break;
1580  case F_depth_component32:
1581  out << "depth_component32";
1582  break;
1583 
1584  case F_rgba:
1585  out << "rgba";
1586  break;
1587  case F_rgbm:
1588  out << "rgbm";
1589  break;
1590  case F_rgba32:
1591  out << "rgba32";
1592  break;
1593  case F_rgba16:
1594  out << "rgba16";
1595  break;
1596  case F_rgba12:
1597  out << "rgba12";
1598  break;
1599  case F_rgba8:
1600  out << "rgba8";
1601  break;
1602  case F_rgba4:
1603  out << "rgba4";
1604  break;
1605 
1606  case F_rgb:
1607  out << "rgb";
1608  break;
1609  case F_rgb12:
1610  out << "rgb12";
1611  break;
1612  case F_rgb8:
1613  out << "rgb8";
1614  break;
1615  case F_rgb5:
1616  out << "rgb5";
1617  break;
1618  case F_rgba5:
1619  out << "rgba5";
1620  break;
1621  case F_rgb332:
1622  out << "rgb332";
1623  break;
1624 
1625  case F_red:
1626  out << "red";
1627  break;
1628  case F_green:
1629  out << "green";
1630  break;
1631  case F_blue:
1632  out << "blue";
1633  break;
1634  case F_alpha:
1635  out << "alpha";
1636  break;
1637  case F_luminance:
1638  out << "luminance";
1639  break;
1640  case F_luminance_alpha:
1641  out << "luminance_alpha";
1642  break;
1643  case F_luminance_alphamask:
1644  out << "luminance_alphamask";
1645  break;
1646 
1647  case F_r16:
1648  out << "r16";
1649  break;
1650  case F_rg16:
1651  out << "rg16";
1652  break;
1653  case F_rgb16:
1654  out << "rgb16";
1655  break;
1656 
1657  case F_srgb:
1658  out << "srgb";
1659  break;
1660  case F_srgb_alpha:
1661  out << "srgb_alpha";
1662  break;
1663  case F_sluminance:
1664  out << "sluminance";
1665  break;
1666  case F_sluminance_alpha:
1667  out << "sluminance_alpha";
1668  break;
1669 
1670  case F_r32i:
1671  out << "r32i";
1672  break;
1673 
1674  case F_r32:
1675  out << "r32";
1676  break;
1677  case F_rg32:
1678  out << "rg32";
1679  break;
1680  case F_rgb32:
1681  out << "rgb32";
1682  break;
1683 
1684  case F_r8i:
1685  out << "r8i";
1686  break;
1687  case F_rg8i:
1688  out << "rg8i";
1689  break;
1690  case F_rgb8i:
1691  out << "rgb8i";
1692  break;
1693  case F_rgba8i:
1694  out << "rgba8i";
1695  break;
1696  }
1697 
1698  if (cdata->_compression != CM_default) {
1699  out << ", compression " << cdata->_compression;
1700  }
1701  out << "\n";
1702 
1703  indent(out, indent_level + 2);
1704 
1705  cdata->_default_sampler.output(out);
1706 
1707  if (do_has_ram_image(cdata)) {
1708  indent(out, indent_level + 2)
1709  << do_get_ram_image_size(cdata) << " bytes in ram, compression "
1710  << cdata->_ram_image_compression << "\n";
1711 
1712  if (cdata->_ram_images.size() > 1) {
1713  int count = 0;
1714  size_t total_size = 0;
1715  for (size_t n = 1; n < cdata->_ram_images.size(); ++n) {
1716  if (!cdata->_ram_images[n]._image.empty()) {
1717  ++count;
1718  total_size += cdata->_ram_images[n]._image.size();
1719  } else {
1720  // Stop at the first gap.
1721  break;
1722  }
1723  }
1724  indent(out, indent_level + 2)
1725  << count
1726  << " mipmap levels also present in ram (" << total_size
1727  << " bytes).\n";
1728  }
1729 
1730  } else {
1731  indent(out, indent_level + 2)
1732  << "no ram image\n";
1733  }
1734 
1735  if (!cdata->_simple_ram_image._image.empty()) {
1736  indent(out, indent_level + 2)
1737  << "simple image: " << cdata->_simple_x_size << " x "
1738  << cdata->_simple_y_size << ", "
1739  << cdata->_simple_ram_image._image.size() << " bytes\n";
1740  }
1741 }
1742 
1743 
1744 ////////////////////////////////////////////////////////////////////
1745 // Function: Texture::set_size_padded
1746 // Access: Published
1747 // Description: Changes the size of the texture, padding
1748 // if necessary, and setting the pad region
1749 // as well.
1750 ////////////////////////////////////////////////////////////////////
1751 void Texture::
1752 set_size_padded(int x, int y, int z) {
1753  CDWriter cdata(_cycler, true);
1754  if (do_get_auto_texture_scale(cdata) != ATS_none) {
1755  do_set_x_size(cdata, up_to_power_2(x));
1756  do_set_y_size(cdata, up_to_power_2(y));
1757 
1758  if (cdata->_texture_type == TT_3d_texture) {
1759  // Only pad 3D textures. It does not make sense
1760  // to do so for cube maps or 2D texture arrays.
1761  do_set_z_size(cdata, up_to_power_2(z));
1762  } else {
1763  do_set_z_size(cdata, z);
1764  }
1765  } else {
1766  do_set_x_size(cdata, x);
1767  do_set_y_size(cdata, y);
1768  do_set_z_size(cdata, z);
1769  }
1770  do_set_pad_size(cdata,
1771  cdata->_x_size - x,
1772  cdata->_y_size - y,
1773  cdata->_z_size - z);
1774 }
1775 
1776 ////////////////////////////////////////////////////////////////////
1777 // Function: Texture::set_orig_file_size
1778 // Access: Published
1779 // Description: Specifies the size of the texture as it exists in its
1780 // original disk file, before any Panda scaling.
1781 ////////////////////////////////////////////////////////////////////
1782 void Texture::
1783 set_orig_file_size(int x, int y, int z) {
1784  CDWriter cdata(_cycler, true);
1785  cdata->_orig_file_x_size = x;
1786  cdata->_orig_file_y_size = y;
1787 
1788  nassertv(z == cdata->_z_size);
1789 }
1790 
1791 ////////////////////////////////////////////////////////////////////
1792 // Function: Texture::prepare_now
1793 // Access: Published
1794 // Description: Creates a context for the texture on the particular
1795 // GSG, if it does not already exist. Returns the new
1796 // (or old) TextureContext. This assumes that the
1797 // GraphicsStateGuardian is the currently active
1798 // rendering context and that it is ready to accept new
1799 // textures. If this is not necessarily the case, you
1800 // should use prepare() instead.
1801 //
1802 // Normally, this is not called directly except by the
1803 // GraphicsStateGuardian; a texture does not need to be
1804 // explicitly prepared by the user before it may be
1805 // rendered.
1806 ////////////////////////////////////////////////////////////////////
1808 prepare_now(int view,
1809  PreparedGraphicsObjects *prepared_objects,
1811  MutexHolder holder(_lock);
1812  CDReader cdata(_cycler);
1813 
1814  // Don't exceed the actual number of views.
1815  view = max(min(view, cdata->_num_views - 1), 0);
1816 
1817  // Get the list of PreparedGraphicsObjects for this view.
1818  Contexts &contexts = _prepared_views[prepared_objects];
1819  Contexts::const_iterator pvi;
1820  pvi = contexts.find(view);
1821  if (pvi != contexts.end()) {
1822  return (*pvi).second;
1823  }
1824 
1825  TextureContext *tc = prepared_objects->prepare_texture_now(this, view, gsg);
1826  contexts[view] = tc;
1827 
1828  return tc;
1829 }
1830 
1831 ////////////////////////////////////////////////////////////////////
1832 // Function: Texture::up_to_power_2
1833 // Access: Published, Static
1834 // Description: Returns the smallest power of 2 greater than or equal
1835 // to value.
1836 ////////////////////////////////////////////////////////////////////
1837 int Texture::
1838 up_to_power_2(int value) {
1839  if (value <= 1) {
1840  return 1;
1841  }
1842  int bit = get_next_higher_bit(((unsigned int)value) - 1);
1843  return (1 << bit);
1844 }
1845 
1846 ////////////////////////////////////////////////////////////////////
1847 // Function: Texture::down_to_power_2
1848 // Access: Published, Static
1849 // Description: Returns the largest power of 2 less than or equal
1850 // to value.
1851 ////////////////////////////////////////////////////////////////////
1852 int Texture::
1853 down_to_power_2(int value) {
1854  if (value <= 1) {
1855  return 1;
1856  }
1857  int bit = get_next_higher_bit(((unsigned int)value) >> 1);
1858  return (1 << bit);
1859 }
1860 
1861 ////////////////////////////////////////////////////////////////////
1862 // Function: Texture::consider_rescale
1863 // Access: Published
1864 // Description: Asks the PNMImage to change its scale when it reads
1865 // the image, according to the whims of the Config.prc
1866 // file.
1867 //
1868 // For most efficient results, this method should be
1869 // called after pnmimage.read_header() has been called,
1870 // but before pnmimage.read(). This method may also be
1871 // called after pnmimage.read(), i.e. when the pnmimage
1872 // is already loaded; in this case it will rescale the
1873 // image on the spot. Also see rescale_texture().
1874 ////////////////////////////////////////////////////////////////////
1875 void Texture::
1877  consider_rescale(pnmimage, get_name(), get_auto_texture_scale());
1878 }
1879 
1880 ////////////////////////////////////////////////////////////////////
1881 // Function: Texture::consider_rescale
1882 // Access: Published, Static
1883 // Description: Asks the PNMImage to change its scale when it reads
1884 // the image, according to the whims of the Config.prc
1885 // file.
1886 //
1887 // For most efficient results, this method should be
1888 // called after pnmimage.read_header() has been called,
1889 // but before pnmimage.read(). This method may also be
1890 // called after pnmimage.read(), i.e. when the pnmimage
1891 // is already loaded; in this case it will rescale the
1892 // image on the spot. Also see rescale_texture().
1893 ////////////////////////////////////////////////////////////////////
1894 void Texture::
1895 consider_rescale(PNMImage &pnmimage, const string &name, AutoTextureScale auto_texture_scale) {
1896  int new_x_size = pnmimage.get_x_size();
1897  int new_y_size = pnmimage.get_y_size();
1898  if (adjust_size(new_x_size, new_y_size, name, false, auto_texture_scale)) {
1899  if (pnmimage.is_valid()) {
1900  // The image is already loaded. Rescale on the spot.
1901  PNMImage new_image(new_x_size, new_y_size, pnmimage.get_num_channels(),
1902  pnmimage.get_maxval(), pnmimage.get_type(),
1903  pnmimage.get_color_space());
1904  new_image.quick_filter_from(pnmimage);
1905  pnmimage.take_from(new_image);
1906  } else {
1907  // Rescale while reading. Some image types (e.g. jpeg) can take
1908  // advantage of this.
1909  pnmimage.set_read_size(new_x_size, new_y_size);
1910  }
1911  }
1912 }
1913 
1914 ////////////////////////////////////////////////////////////////////
1915 // Function: Texture::format_texture_type
1916 // Access: Published, Static
1917 // Description: Returns the indicated TextureType converted to a
1918 // string word.
1919 ////////////////////////////////////////////////////////////////////
1920 string Texture::
1921 format_texture_type(TextureType tt) {
1922  switch (tt) {
1923  case TT_1d_texture:
1924  return "1d_texture";
1925  case TT_2d_texture:
1926  return "2d_texture";
1927  case TT_3d_texture:
1928  return "3d_texture";
1929  case TT_2d_texture_array:
1930  return "2d_texture_array";
1931  case TT_cube_map:
1932  return "cube_map";
1933  }
1934  return "**invalid**";
1935 }
1936 
1937 ////////////////////////////////////////////////////////////////////
1938 // Function: Texture::string_texture_type
1939 // Access: Published, Static
1940 // Description: Returns the TextureType corresponding to the
1941 // indicated string word.
1942 ////////////////////////////////////////////////////////////////////
1943 Texture::TextureType Texture::
1944 string_texture_type(const string &str) {
1945  if (cmp_nocase(str, "1d_texture") == 0) {
1946  return TT_1d_texture;
1947  } else if (cmp_nocase(str, "2d_texture") == 0) {
1948  return TT_2d_texture;
1949  } else if (cmp_nocase(str, "3d_texture") == 0) {
1950  return TT_3d_texture;
1951  } else if (cmp_nocase(str, "2d_texture_array") == 0) {
1952  return TT_2d_texture_array;
1953  } else if (cmp_nocase(str, "cube_map") == 0) {
1954  return TT_cube_map;
1955  }
1956 
1957  gobj_cat->error()
1958  << "Invalid Texture::TextureType value: " << str << "\n";
1959  return TT_2d_texture;
1960 }
1961 
1962 ////////////////////////////////////////////////////////////////////
1963 // Function: Texture::format_component_type
1964 // Access: Published, Static
1965 // Description: Returns the indicated ComponentType converted to a
1966 // string word.
1967 ////////////////////////////////////////////////////////////////////
1968 string Texture::
1969 format_component_type(ComponentType ct) {
1970  switch (ct) {
1971  case T_unsigned_byte:
1972  return "unsigned_byte";
1973  case T_unsigned_short:
1974  return "unsigned_short";
1975  case T_float:
1976  return "float";
1977  case T_unsigned_int_24_8:
1978  return "unsigned_int_24_8";
1979  case T_int:
1980  return "int";
1981  }
1982 
1983  return "**invalid**";
1984 }
1985 
1986 ////////////////////////////////////////////////////////////////////
1987 // Function: Texture::string_component_type
1988 // Access: Published, Static
1989 // Description: Returns the ComponentType corresponding to the
1990 // indicated string word.
1991 ////////////////////////////////////////////////////////////////////
1992 Texture::ComponentType Texture::
1993 string_component_type(const string &str) {
1994  if (cmp_nocase(str, "unsigned_byte") == 0) {
1995  return T_unsigned_byte;
1996  } else if (cmp_nocase(str, "unsigned_short") == 0) {
1997  return T_unsigned_short;
1998  } else if (cmp_nocase(str, "float") == 0) {
1999  return T_float;
2000  } else if (cmp_nocase(str, "unsigned_int_24_8") == 0) {
2001  return T_unsigned_int_24_8;
2002  } else if (cmp_nocase(str, "int") == 0) {
2003  return T_int;
2004  }
2005 
2006  gobj_cat->error()
2007  << "Invalid Texture::ComponentType value: " << str << "\n";
2008  return T_unsigned_byte;
2009 }
2010 
2011 ////////////////////////////////////////////////////////////////////
2012 // Function: Texture::format_format
2013 // Access: Published, Static
2014 // Description: Returns the indicated Format converted to a
2015 // string word.
2016 ////////////////////////////////////////////////////////////////////
2017 string Texture::
2018 format_format(Format format) {
2019  switch (format) {
2020  case F_depth_stencil:
2021  return "depth_stencil";
2022  case F_depth_component:
2023  return "depth_component";
2024  case F_depth_component16:
2025  return "depth_component16";
2026  case F_depth_component24:
2027  return "depth_component24";
2028  case F_depth_component32:
2029  return "depth_component32";
2030  case F_color_index:
2031  return "color_index";
2032  case F_red:
2033  return "red";
2034  case F_green:
2035  return "green";
2036  case F_blue:
2037  return "blue";
2038  case F_alpha:
2039  return "alpha";
2040  case F_rgb:
2041  return "rgb";
2042  case F_rgb5:
2043  return "rgb5";
2044  case F_rgb8:
2045  return "rgb8";
2046  case F_rgb12:
2047  return "rgb12";
2048  case F_rgb332:
2049  return "rgb332";
2050  case F_rgba:
2051  return "rgba";
2052  case F_rgbm:
2053  return "rgbm";
2054  case F_rgba4:
2055  return "rgba4";
2056  case F_rgba5:
2057  return "rgba5";
2058  case F_rgba8:
2059  return "rgba8";
2060  case F_rgba12:
2061  return "rgba12";
2062  case F_luminance:
2063  return "luminance";
2064  case F_luminance_alpha:
2065  return "luminance_alpha";
2066  case F_luminance_alphamask:
2067  return "luminance_alphamask";
2068  case F_rgba16:
2069  return "rgba16";
2070  case F_rgba32:
2071  return "rgba32";
2072  case F_r16:
2073  return "r16";
2074  case F_rg16:
2075  return "rg16";
2076  case F_rgb16:
2077  return "rgb16";
2078  case F_srgb:
2079  return "srgb";
2080  case F_srgb_alpha:
2081  return "srgb_alpha";
2082  case F_sluminance:
2083  return "sluminance";
2084  case F_sluminance_alpha:
2085  return "sluminance_alpha";
2086  case F_r32i:
2087  return "r32i";
2088  case F_r32:
2089  return "r32";
2090  case F_rg32:
2091  return "rg32";
2092  case F_rgb32:
2093  return "rgb32";
2094  case F_r8i:
2095  return "r8i";
2096  case F_rg8i:
2097  return "rg8i";
2098  case F_rgb8i:
2099  return "rgb8i";
2100  case F_rgba8i:
2101  return "rgba8i";
2102  }
2103  return "**invalid**";
2104 }
2105 
2106 ////////////////////////////////////////////////////////////////////
2107 // Function: Texture::string_format
2108 // Access: Published, Static
2109 // Description: Returns the Format corresponding to the
2110 // indicated string word.
2111 ////////////////////////////////////////////////////////////////////
2112 Texture::Format Texture::
2113 string_format(const string &str) {
2114  if (cmp_nocase(str, "depth_stencil") == 0) {
2115  return F_depth_stencil;
2116  } else if (cmp_nocase(str, "depth_component") == 0) {
2117  return F_depth_component;
2118  } else if (cmp_nocase(str, "depth_component16") == 0 || cmp_nocase(str, "d16") == 0) {
2119  return F_depth_component16;
2120  } else if (cmp_nocase(str, "depth_component24") == 0 || cmp_nocase(str, "d24") == 0) {
2121  return F_depth_component24;
2122  } else if (cmp_nocase(str, "depth_component32") == 0 || cmp_nocase(str, "d32") == 0) {
2123  return F_depth_component32;
2124  } else if (cmp_nocase(str, "color_index") == 0) {
2125  return F_color_index;
2126  } else if (cmp_nocase(str, "red") == 0) {
2127  return F_red;
2128  } else if (cmp_nocase(str, "green") == 0) {
2129  return F_green;
2130  } else if (cmp_nocase(str, "blue") == 0) {
2131  return F_blue;
2132  } else if (cmp_nocase(str, "alpha") == 0) {
2133  return F_alpha;
2134  } else if (cmp_nocase(str, "rgb") == 0) {
2135  return F_rgb;
2136  } else if (cmp_nocase(str, "rgb5") == 0) {
2137  return F_rgb5;
2138  } else if (cmp_nocase(str, "rgb8") == 0 || cmp_nocase(str, "r8g8b8") == 0) {
2139  return F_rgb8;
2140  } else if (cmp_nocase(str, "rgb12") == 0) {
2141  return F_rgb12;
2142  } else if (cmp_nocase(str, "rgb332") == 0 || cmp_nocase(str, "r3g3b2") == 0) {
2143  return F_rgb332;
2144  } else if (cmp_nocase(str, "rgba") == 0) {
2145  return F_rgba;
2146  } else if (cmp_nocase(str, "rgbm") == 0) {
2147  return F_rgbm;
2148  } else if (cmp_nocase(str, "rgba4") == 0) {
2149  return F_rgba4;
2150  } else if (cmp_nocase(str, "rgba5") == 0) {
2151  return F_rgba5;
2152  } else if (cmp_nocase(str, "rgba8") == 0 || cmp_nocase(str, "r8g8b8a8") == 0) {
2153  return F_rgba8;
2154  } else if (cmp_nocase(str, "rgba12") == 0) {
2155  return F_rgba12;
2156  } else if (cmp_nocase(str, "luminance") == 0) {
2157  return F_luminance;
2158  } else if (cmp_nocase(str, "luminance_alpha") == 0) {
2159  return F_luminance_alpha;
2160  } else if (cmp_nocase(str, "luminance_alphamask") == 0) {
2161  return F_luminance_alphamask;
2162  } else if (cmp_nocase(str, "rgba16") == 0 || cmp_nocase(str, "r16g16b16a16") == 0) {
2163  return F_rgba16;
2164  } else if (cmp_nocase(str, "rgba32") == 0 || cmp_nocase(str, "r32g32b32a32") == 0) {
2165  return F_rgba32;
2166  } else if (cmp_nocase(str, "r16") == 0 || cmp_nocase(str, "red16") == 0) {
2167  return F_r16;
2168  } else if (cmp_nocase(str, "rg16") == 0 || cmp_nocase(str, "r16g16") == 0) {
2169  return F_rg16;
2170  } else if (cmp_nocase(str, "rgb16") == 0 || cmp_nocase(str, "r16g16b16") == 0) {
2171  return F_rgb16;
2172  } else if (cmp_nocase(str, "srgb") == 0) {
2173  return F_srgb;
2174  } else if (cmp_nocase(str, "srgb_alpha") == 0) {
2175  return F_srgb_alpha;
2176  } else if (cmp_nocase(str, "sluminance") == 0) {
2177  return F_sluminance;
2178  } else if (cmp_nocase(str, "sluminance_alpha") == 0) {
2179  return F_sluminance_alpha;
2180  } else if (cmp_nocase(str, "r32i") == 0) {
2181  return F_r32i;
2182  } else if (cmp_nocase(str, "r32") == 0 || cmp_nocase(str, "red32") == 0) {
2183  return F_r32;
2184  } else if (cmp_nocase(str, "rg32") == 0 || cmp_nocase(str, "r32g32") == 0) {
2185  return F_rg32;
2186  } else if (cmp_nocase(str, "rgb32") == 0 || cmp_nocase(str, "r32g32b32") == 0) {
2187  return F_rgb32;
2188  }
2189 
2190  gobj_cat->error()
2191  << "Invalid Texture::Format value: " << str << "\n";
2192  return F_rgba;
2193 }
2194 
2195 ////////////////////////////////////////////////////////////////////
2196 // Function: Texture::format_compression_mode
2197 // Access: Published, Static
2198 // Description: Returns the indicated CompressionMode converted to a
2199 // string word.
2200 ////////////////////////////////////////////////////////////////////
2201 string Texture::
2202 format_compression_mode(CompressionMode cm) {
2203  switch (cm) {
2204  case CM_default:
2205  return "default";
2206  case CM_off:
2207  return "off";
2208  case CM_on:
2209  return "on";
2210  case CM_fxt1:
2211  return "fxt1";
2212  case CM_dxt1:
2213  return "dxt1";
2214  case CM_dxt2:
2215  return "dxt2";
2216  case CM_dxt3:
2217  return "dxt3";
2218  case CM_dxt4:
2219  return "dxt4";
2220  case CM_dxt5:
2221  return "dxt5";
2222  case CM_pvr1_2bpp:
2223  return "pvr1_2bpp";
2224  case CM_pvr1_4bpp:
2225  return "pvr1_4bpp";
2226  }
2227 
2228  return "**invalid**";
2229 }
2230 
2231 ////////////////////////////////////////////////////////////////////
2232 // Function: Texture::string_compression_mode
2233 // Access: Public
2234 // Description: Returns the CompressionMode value associated with the
2235 // given string representation.
2236 ////////////////////////////////////////////////////////////////////
2237 Texture::CompressionMode Texture::
2238 string_compression_mode(const string &str) {
2239  if (cmp_nocase_uh(str, "default") == 0) {
2240  return CM_default;
2241  } else if (cmp_nocase_uh(str, "off") == 0) {
2242  return CM_off;
2243  } else if (cmp_nocase_uh(str, "on") == 0) {
2244  return CM_on;
2245  } else if (cmp_nocase_uh(str, "fxt1") == 0) {
2246  return CM_fxt1;
2247  } else if (cmp_nocase_uh(str, "dxt1") == 0) {
2248  return CM_dxt1;
2249  } else if (cmp_nocase_uh(str, "dxt2") == 0) {
2250  return CM_dxt2;
2251  } else if (cmp_nocase_uh(str, "dxt3") == 0) {
2252  return CM_dxt3;
2253  } else if (cmp_nocase_uh(str, "dxt4") == 0) {
2254  return CM_dxt4;
2255  } else if (cmp_nocase_uh(str, "dxt5") == 0) {
2256  return CM_dxt5;
2257  } else if (cmp_nocase_uh(str, "pvr1_2bpp") == 0) {
2258  return CM_pvr1_2bpp;
2259  } else if (cmp_nocase_uh(str, "pvr1_4bpp") == 0) {
2260  return CM_pvr1_4bpp;
2261  }
2262 
2263  gobj_cat->error()
2264  << "Invalid Texture::CompressionMode value: " << str << "\n";
2265  return CM_default;
2266 }
2267 
2268 
2269 ////////////////////////////////////////////////////////////////////
2270 // Function: Texture::format_quality_level
2271 // Access: Published, Static
2272 // Description: Returns the indicated QualityLevel converted to a
2273 // string word.
2274 ////////////////////////////////////////////////////////////////////
2275 string Texture::
2276 format_quality_level(QualityLevel ql) {
2277  switch (ql) {
2278  case QL_default:
2279  return "default";
2280  case QL_fastest:
2281  return "fastest";
2282  case QL_normal:
2283  return "normal";
2284  case QL_best:
2285  return "best";
2286  }
2287 
2288  return "**invalid**";
2289 }
2290 
2291 ////////////////////////////////////////////////////////////////////
2292 // Function: Texture::string_quality_level
2293 // Access: Public
2294 // Description: Returns the QualityLevel value associated with the
2295 // given string representation.
2296 ////////////////////////////////////////////////////////////////////
2297 Texture::QualityLevel Texture::
2298 string_quality_level(const string &str) {
2299  if (cmp_nocase(str, "default") == 0) {
2300  return QL_default;
2301  } else if (cmp_nocase(str, "fastest") == 0) {
2302  return QL_fastest;
2303  } else if (cmp_nocase(str, "normal") == 0) {
2304  return QL_normal;
2305  } else if (cmp_nocase(str, "best") == 0) {
2306  return QL_best;
2307  }
2308 
2309  gobj_cat->error()
2310  << "Invalid Texture::QualityLevel value: " << str << "\n";
2311  return QL_default;
2312 }
2313 
2314 ////////////////////////////////////////////////////////////////////
2315 // Function: Texture::texture_uploaded
2316 // Access: Public
2317 // Description: This method is called by the GraphicsEngine at the
2318 // beginning of the frame *after* a texture has been
2319 // successfully uploaded to graphics memory. It is
2320 // intended as a callback so the texture can release its
2321 // RAM image, if _keep_ram_image is false.
2322 //
2323 // This is called indirectly when the GSG calls
2324 // GraphicsEngine::texture_uploaded().
2325 ////////////////////////////////////////////////////////////////////
2326 void Texture::
2328  CDLockedReader cdata(_cycler);
2329 
2330  if (!keep_texture_ram && !cdata->_keep_ram_image) {
2331  // Once we have prepared the texture, we can generally safely
2332  // remove the pixels from main RAM. The GSG is now responsible
2333  // for remembering what it looks like.
2334 
2335  CDWriter cdataw(_cycler, cdata, false);
2336  if (gobj_cat.is_debug()) {
2337  gobj_cat.debug()
2338  << "Dumping RAM for texture " << get_name() << "\n";
2339  }
2340  do_clear_ram_image(cdataw);
2341  }
2342 }
2343 
2344 ////////////////////////////////////////////////////////////////////
2345 // Function: Texture::has_cull_callback
2346 // Access: Public, Virtual
2347 // Description: Should be overridden by derived classes to return
2348 // true if cull_callback() has been defined. Otherwise,
2349 // returns false to indicate cull_callback() does not
2350 // need to be called for this node during the cull
2351 // traversal.
2352 ////////////////////////////////////////////////////////////////////
2353 bool Texture::
2355  return false;
2356 }
2357 
2358 ////////////////////////////////////////////////////////////////////
2359 // Function: Texture::cull_callback
2360 // Access: Public, Virtual
2361 // Description: If has_cull_callback() returns true, this function
2362 // will be called during the cull traversal to perform
2363 // any additional operations that should be performed at
2364 // cull time.
2365 //
2366 // This is called each time the Texture is discovered
2367 // applied to a Geom in the traversal. It should return
2368 // true if the Geom is visible, false if it should be
2369 // omitted.
2370 ////////////////////////////////////////////////////////////////////
2371 bool Texture::
2373  return true;
2374 }
2375 
2376 ////////////////////////////////////////////////////////////////////
2377 // Function: Texture::make_texture
2378 // Access: Public, Static
2379 // Description: A factory function to make a new Texture, used to
2380 // pass to the TexturePool.
2381 ////////////////////////////////////////////////////////////////////
2382 PT(Texture) Texture::
2383 make_texture() {
2384  return new Texture;
2385 }
2386 
2387 ////////////////////////////////////////////////////////////////////
2388 // Function: Texture::is_specific
2389 // Access: Public, Static
2390 // Description: Returns true if the indicated compression mode is one
2391 // of the specific compression types, false otherwise.
2392 ////////////////////////////////////////////////////////////////////
2393 bool Texture::
2394 is_specific(Texture::CompressionMode compression) {
2395  switch (compression) {
2396  case CM_default:
2397  case CM_off:
2398  case CM_on:
2399  return false;
2400 
2401  default:
2402  return true;
2403  }
2404 }
2405 
2406 ////////////////////////////////////////////////////////////////////
2407 // Function: Texture::has_alpha
2408 // Access: Public, Static
2409 // Description: Returns true if the indicated format includes alpha,
2410 // false otherwise.
2411 ////////////////////////////////////////////////////////////////////
2412 bool Texture::
2413 has_alpha(Format format) {
2414  switch (format) {
2415  case F_alpha:
2416  case F_rgba:
2417  case F_rgbm:
2418  case F_rgba4:
2419  case F_rgba5:
2420  case F_rgba8:
2421  case F_rgba12:
2422  case F_rgba16:
2423  case F_rgba32:
2424  case F_luminance_alpha:
2425  case F_luminance_alphamask:
2426  case F_srgb_alpha:
2427  case F_sluminance_alpha:
2428  return true;
2429 
2430  default:
2431  return false;
2432  }
2433 }
2434 
2435 ////////////////////////////////////////////////////////////////////
2436 // Function: Texture::has_binary_alpha
2437 // Access: Public, Static
2438 // Description: Returns true if the indicated format includes a
2439 // binary alpha only, false otherwise.
2440 ////////////////////////////////////////////////////////////////////
2441 bool Texture::
2442 has_binary_alpha(Format format) {
2443  switch (format) {
2444  case F_rgbm:
2445  return true;
2446 
2447  default:
2448  return false;
2449  }
2450 }
2451 
2452 ////////////////////////////////////////////////////////////////////
2453 // Function: Texture::is_srgb
2454 // Access: Public, Static
2455 // Description: Returns true if the indicated format is in the
2456 // sRGB color space, false otherwise.
2457 ////////////////////////////////////////////////////////////////////
2458 bool Texture::
2459 is_srgb(Format format) {
2460  switch (format) {
2461  case F_srgb:
2462  case F_srgb_alpha:
2463  case F_sluminance:
2464  case F_sluminance_alpha:
2465  return true;
2466 
2467  default:
2468  return false;
2469  }
2470 }
2471 
2472 ////////////////////////////////////////////////////////////////////
2473 // Function: Texture::adjust_size
2474 // Access: Public, Static
2475 // Description: Computes the proper size of the texture, based on the
2476 // original size, the filename, and the resizing whims
2477 // of the config file.
2478 //
2479 // x_size and y_size should be loaded with the texture
2480 // image's original size on disk. On return, they will
2481 // be loaded with the texture's in-memory target size.
2482 // The return value is true if the size has been
2483 // adjusted, or false if it is the same.
2484 ////////////////////////////////////////////////////////////////////
2485 bool Texture::
2486 adjust_size(int &x_size, int &y_size, const string &name,
2487  bool for_padding, AutoTextureScale auto_texture_scale) {
2488  bool exclude = false;
2489  int num_excludes = exclude_texture_scale.get_num_unique_values();
2490  for (int i = 0; i < num_excludes && !exclude; ++i) {
2491  GlobPattern pat(exclude_texture_scale.get_unique_value(i));
2492  if (pat.matches(name)) {
2493  exclude = true;
2494  }
2495  }
2496 
2497  int new_x_size = x_size;
2498  int new_y_size = y_size;
2499 
2500  if (!exclude) {
2501  new_x_size = (int)cfloor(new_x_size * texture_scale + 0.5);
2502  new_y_size = (int)cfloor(new_y_size * texture_scale + 0.5);
2503 
2504  // Don't auto-scale below 4 in either dimension. This causes
2505  // problems for DirectX and texture compression.
2506  new_x_size = min(max(new_x_size, (int)texture_scale_limit), x_size);
2507  new_y_size = min(max(new_y_size, (int)texture_scale_limit), y_size);
2508  }
2509 
2510  AutoTextureScale ats = auto_texture_scale;
2511  if (ats == ATS_unspecified) {
2512  ats = get_textures_power_2();
2513  }
2514  if (!for_padding && ats == ATS_pad) {
2515  // If we're not calculating the padding size--that is, we're
2516  // calculating the initial scaling size instead--then ignore
2517  // ATS_pad, and treat it the same as ATS_none.
2518  ats = ATS_none;
2519  }
2520 
2521  switch (ats) {
2522  case ATS_down:
2523  new_x_size = down_to_power_2(new_x_size);
2524  new_y_size = down_to_power_2(new_y_size);
2525  break;
2526 
2527  case ATS_up:
2528  case ATS_pad:
2529  new_x_size = up_to_power_2(new_x_size);
2530  new_y_size = up_to_power_2(new_y_size);
2531  break;
2532 
2533  case ATS_none:
2534  case ATS_unspecified:
2535  break;
2536  }
2537 
2538  ats = textures_square.get_value();
2539  if (!for_padding && ats == ATS_pad) {
2540  ats = ATS_none;
2541  }
2542  switch (ats) {
2543  case ATS_down:
2544  new_x_size = new_y_size = min(new_x_size, new_y_size);
2545  break;
2546 
2547  case ATS_up:
2548  case ATS_pad:
2549  new_x_size = new_y_size = max(new_x_size, new_y_size);
2550  break;
2551 
2552  case ATS_none:
2553  case ATS_unspecified:
2554  break;
2555  }
2556 
2557  if (!exclude) {
2558  int max_dimension = max_texture_dimension;
2559 
2560  if (max_dimension < 0) {
2562  if (gsg != (GraphicsStateGuardianBase *)NULL) {
2563  max_dimension = gsg->get_max_texture_dimension();
2564  }
2565  }
2566 
2567  if (max_dimension > 0) {
2568  new_x_size = min(new_x_size, (int)max_dimension);
2569  new_y_size = min(new_y_size, (int)max_dimension);
2570  }
2571  }
2572 
2573  if (x_size != new_x_size || y_size != new_y_size) {
2574  x_size = new_x_size;
2575  y_size = new_y_size;
2576  return true;
2577  }
2578 
2579  return false;
2580 }
2581 
2582 ////////////////////////////////////////////////////////////////////
2583 // Function: Texture::ensure_loader_type
2584 // Access: Public, Virtual
2585 // Description: May be called prior to calling read_txo() or any
2586 // bam-related Texture-creating callback, to ensure that
2587 // the proper dynamic libraries for a Texture of the
2588 // current class type, and the indicated filename, have
2589 // been already loaded.
2590 //
2591 // This is a low-level function that should not normally
2592 // need to be called directly by the user.
2593 //
2594 // Note that for best results you must first create a
2595 // Texture object of the appropriate class type for your
2596 // filename, for instance with
2597 // TexturePool::make_texture().
2598 ////////////////////////////////////////////////////////////////////
2599 void Texture::
2600 ensure_loader_type(const Filename &filename) {
2601  // For a plain Texture type, this doesn't need to do anything.
2602 }
2603 
2604 ////////////////////////////////////////////////////////////////////
2605 // Function: Texture::reconsider_dirty
2606 // Access: Protected, Virtual
2607 // Description: Called by TextureContext to give the Texture a chance
2608 // to mark itself dirty before rendering, if necessary.
2609 ////////////////////////////////////////////////////////////////////
2610 void Texture::
2611 reconsider_dirty() {
2612 }
2613 
2614 ////////////////////////////////////////////////////////////////////
2615 // Function: Texture::do_adjust_this_size
2616 // Access: Protected, Virtual
2617 // Description: Works like adjust_size, but also considers the
2618 // texture class. Movie textures, for instance, always
2619 // pad outwards, regardless of textures-power-2.
2620 ////////////////////////////////////////////////////////////////////
2621 bool Texture::
2622 do_adjust_this_size(const CData *cdata, int &x_size, int &y_size, const string &name,
2623  bool for_padding) const {
2624  return adjust_size(x_size, y_size, name, for_padding, cdata->_auto_texture_scale);
2625 }
2626 
2627 ////////////////////////////////////////////////////////////////////
2628 // Function: Texture::do_read
2629 // Access: Protected, Virtual
2630 // Description: The internal implementation of the various read()
2631 // methods.
2632 ////////////////////////////////////////////////////////////////////
2633 bool Texture::
2634 do_read(CData *cdata, const Filename &fullpath, const Filename &alpha_fullpath,
2635  int primary_file_num_channels, int alpha_file_channel,
2636  int z, int n, bool read_pages, bool read_mipmaps,
2637  const LoaderOptions &options, BamCacheRecord *record) {
2638  PStatTimer timer(_texture_read_pcollector);
2639 
2640  if (options.get_auto_texture_scale() != ATS_unspecified) {
2641  cdata->_auto_texture_scale = options.get_auto_texture_scale();
2642  }
2643 
2644  bool header_only = ((options.get_texture_flags() & (LoaderOptions::TF_preload | LoaderOptions::TF_preload_simple)) == 0);
2645  if (record != (BamCacheRecord *)NULL) {
2646  header_only = false;
2647  }
2648 
2649  if ((z == 0 || read_pages) && (n == 0 || read_mipmaps)) {
2650  // When we re-read the page 0 of the base image, we clear
2651  // everything and start over.
2652  do_clear_ram_image(cdata);
2653  }
2654 
2655  if (is_txo_filename(fullpath)) {
2656  if (record != (BamCacheRecord *)NULL) {
2657  record->add_dependent_file(fullpath);
2658  }
2659  return do_read_txo_file(cdata, fullpath);
2660  }
2661 
2662  if (is_dds_filename(fullpath)) {
2663  if (record != (BamCacheRecord *)NULL) {
2664  record->add_dependent_file(fullpath);
2665  }
2666  return do_read_dds_file(cdata, fullpath, header_only);
2667  }
2668 
2669  // If read_pages or read_mipmaps is specified, then z and n actually
2670  // indicate z_size and n_size, respectively--the numerical limits on
2671  // which to search for filenames.
2672  int z_size = z;
2673  int n_size = n;
2674 
2675  // Certain texture types have an implicit z_size. If z_size is
2676  // omitted, choose an appropriate default based on the texture
2677  // type.
2678  if (z_size == 0) {
2679  switch (cdata->_texture_type) {
2680  case TT_1d_texture:
2681  case TT_2d_texture:
2682  z_size = 1;
2683  break;
2684 
2685  case TT_cube_map:
2686  z_size = 6;
2687  break;
2688 
2689  default:
2690  break;
2691  }
2692  }
2693 
2694  int num_views = 0;
2695  if (options.get_texture_flags() & LoaderOptions::TF_multiview) {
2696  // We'll be loading a multiview texture.
2697  read_pages = true;
2698  if (options.get_texture_num_views() != 0) {
2699  num_views = options.get_texture_num_views();
2700  do_set_num_views(cdata, num_views);
2701  }
2702  }
2703 
2705 
2706  if (read_pages && read_mipmaps) {
2707  // Read a sequence of pages * mipmap levels.
2708  Filename fullpath_pattern = Filename::pattern_filename(fullpath);
2709  Filename alpha_fullpath_pattern = Filename::pattern_filename(alpha_fullpath);
2710  do_set_z_size(cdata, z_size);
2711 
2712  n = 0;
2713  while (true) {
2714  // For mipmap level 0, the total number of pages might be
2715  // determined by the number of files we find. After mipmap
2716  // level 0, though, the number of pages is predetermined.
2717  if (n != 0) {
2718  z_size = do_get_expected_mipmap_z_size(cdata, n);
2719  }
2720 
2721  z = 0;
2722 
2723  Filename n_pattern = Filename::pattern_filename(fullpath_pattern.get_filename_index(z));
2724  Filename alpha_n_pattern = Filename::pattern_filename(alpha_fullpath_pattern.get_filename_index(z));
2725 
2726  if (!n_pattern.has_hash()) {
2727  gobj_cat.error()
2728  << "Filename requires two different hash sequences: " << fullpath
2729  << "\n";
2730  return false;
2731  }
2732 
2733  Filename file = n_pattern.get_filename_index(n);
2734  Filename alpha_file = alpha_n_pattern.get_filename_index(n);
2735 
2736  if ((n_size == 0 && (vfs->exists(file) || n == 0)) ||
2737  (n_size != 0 && n < n_size)) {
2738  // Continue through the loop.
2739  } else {
2740  // We've reached the end of the mipmap sequence.
2741  break;
2742  }
2743 
2744  int num_pages = z_size * num_views;
2745  while ((num_pages == 0 && (vfs->exists(file) || z == 0)) ||
2746  (num_pages != 0 && z < num_pages)) {
2747  if (!do_read_one(cdata, file, alpha_file, z, n, primary_file_num_channels,
2748  alpha_file_channel, options, header_only, record)) {
2749  return false;
2750  }
2751  ++z;
2752 
2753  n_pattern = Filename::pattern_filename(fullpath_pattern.get_filename_index(z));
2754  file = n_pattern.get_filename_index(n);
2755  alpha_file = alpha_n_pattern.get_filename_index(n);
2756  }
2757 
2758  if (n == 0 && n_size == 0) {
2759  // If n_size is not specified, it gets implicitly set after we
2760  // read the base texture image (which determines the size of
2761  // the texture).
2762  n_size = do_get_expected_num_mipmap_levels(cdata);
2763  }
2764  ++n;
2765  }
2766  cdata->_fullpath = fullpath_pattern;
2767  cdata->_alpha_fullpath = alpha_fullpath_pattern;
2768 
2769  } else if (read_pages) {
2770  // Read a sequence of cube map or 3-D texture pages.
2771  Filename fullpath_pattern = Filename::pattern_filename(fullpath);
2772  Filename alpha_fullpath_pattern = Filename::pattern_filename(alpha_fullpath);
2773  if (!fullpath_pattern.has_hash()) {
2774  gobj_cat.error()
2775  << "Filename requires a hash mark: " << fullpath
2776  << "\n";
2777  return false;
2778  }
2779 
2780  do_set_z_size(cdata, z_size);
2781  z = 0;
2782  Filename file = fullpath_pattern.get_filename_index(z);
2783  Filename alpha_file = alpha_fullpath_pattern.get_filename_index(z);
2784 
2785  int num_pages = z_size * num_views;
2786  while ((num_pages == 0 && (vfs->exists(file) || z == 0)) ||
2787  (num_pages != 0 && z < num_pages)) {
2788  if (!do_read_one(cdata, file, alpha_file, z, 0, primary_file_num_channels,
2789  alpha_file_channel, options, header_only, record)) {
2790  return false;
2791  }
2792  ++z;
2793 
2794  file = fullpath_pattern.get_filename_index(z);
2795  alpha_file = alpha_fullpath_pattern.get_filename_index(z);
2796  }
2797  cdata->_fullpath = fullpath_pattern;
2798  cdata->_alpha_fullpath = alpha_fullpath_pattern;
2799 
2800  } else if (read_mipmaps) {
2801  // Read a sequence of mipmap levels.
2802  Filename fullpath_pattern = Filename::pattern_filename(fullpath);
2803  Filename alpha_fullpath_pattern = Filename::pattern_filename(alpha_fullpath);
2804  if (!fullpath_pattern.has_hash()) {
2805  gobj_cat.error()
2806  << "Filename requires a hash mark: " << fullpath
2807  << "\n";
2808  return false;
2809  }
2810 
2811  n = 0;
2812  Filename file = fullpath_pattern.get_filename_index(n);
2813  Filename alpha_file = alpha_fullpath_pattern.get_filename_index(n);
2814 
2815  while ((n_size == 0 && (vfs->exists(file) || n == 0)) ||
2816  (n_size != 0 && n < n_size)) {
2817  if (!do_read_one(cdata, file, alpha_file, z, n,
2818  primary_file_num_channels, alpha_file_channel,
2819  options, header_only, record)) {
2820  return false;
2821  }
2822  ++n;
2823 
2824  if (n_size == 0 && n >= do_get_expected_num_mipmap_levels(cdata)) {
2825  // Don't try to read more than the requisite number of mipmap
2826  // levels (unless the user insisted on it for some reason).
2827  break;
2828  }
2829 
2830  file = fullpath_pattern.get_filename_index(n);
2831  alpha_file = alpha_fullpath_pattern.get_filename_index(n);
2832  }
2833  cdata->_fullpath = fullpath_pattern;
2834  cdata->_alpha_fullpath = alpha_fullpath_pattern;
2835 
2836  } else {
2837  // Just an ordinary read of one file.
2838  if (!do_read_one(cdata, fullpath, alpha_fullpath, z, n,
2839  primary_file_num_channels, alpha_file_channel,
2840  options, header_only, record)) {
2841  return false;
2842  }
2843  }
2844 
2845  cdata->_has_read_pages = read_pages;
2846  cdata->_has_read_mipmaps = read_mipmaps;
2847  cdata->_num_mipmap_levels_read = cdata->_ram_images.size();
2848 
2849  if (header_only) {
2850  // If we were only supposed to be checking the image header
2851  // information, don't let the Texture think that it's got the
2852  // image now.
2853  do_clear_ram_image(cdata);
2854  } else {
2855  if ((options.get_texture_flags() & LoaderOptions::TF_preload) != 0) {
2856  // If we intend to keep the ram image around, consider
2857  // compressing it etc.
2858  bool generate_mipmaps = ((options.get_texture_flags() & LoaderOptions::TF_generate_mipmaps) != 0);
2859  do_consider_auto_process_ram_image(cdata, generate_mipmaps || uses_mipmaps(), true);
2860  }
2861  }
2862 
2863  return true;
2864 }
2865 
2866 ////////////////////////////////////////////////////////////////////
2867 // Function: Texture::do_read_one
2868 // Access: Protected, Virtual
2869 // Description: Called only from do_read(), this method reads a
2870 // single image file, either one page or one mipmap
2871 // level.
2872 ////////////////////////////////////////////////////////////////////
2873 bool Texture::
2874 do_read_one(CData *cdata, const Filename &fullpath, const Filename &alpha_fullpath,
2875  int z, int n, int primary_file_num_channels, int alpha_file_channel,
2876  const LoaderOptions &options, bool header_only, BamCacheRecord *record) {
2877  if (record != (BamCacheRecord *)NULL) {
2878  nassertr(!header_only, false);
2879  record->add_dependent_file(fullpath);
2880  }
2881 
2882  PNMImage image;
2883  PfmFile pfm;
2884  PNMReader *image_reader = image.make_reader(fullpath, NULL, false);
2885  if (image_reader == NULL) {
2886  gobj_cat.error()
2887  << "Texture::read() - couldn't read: " << fullpath << endl;
2888  return false;
2889  }
2890  image.copy_header_from(*image_reader);
2891 
2892  AutoTextureScale auto_texture_scale = do_get_auto_texture_scale(cdata);
2893 
2894  // If it's a floating-point image file, read it by default into a
2895  // floating-point texture.
2896  bool read_floating_point;
2897  int texture_load_type = (options.get_texture_flags() & (LoaderOptions::TF_integer | LoaderOptions::TF_float));
2898  switch (texture_load_type) {
2899  case LoaderOptions::TF_integer:
2900  read_floating_point = false;
2901  break;
2902 
2903  case LoaderOptions::TF_float:
2904  read_floating_point = true;
2905  break;
2906 
2907  default:
2908  // Neither TF_integer nor TF_float was specified; determine which
2909  // way the texture wants to be loaded.
2910  read_floating_point = (image_reader->is_floating_point());
2911  if (!alpha_fullpath.empty()) {
2912  read_floating_point = false;
2913  }
2914  }
2915 
2916  if (header_only || textures_header_only) {
2917  int x_size = image.get_x_size();
2918  int y_size = image.get_y_size();
2919  if (z == 0 && n == 0) {
2920  cdata->_orig_file_x_size = x_size;
2921  cdata->_orig_file_y_size = y_size;
2922  }
2923 
2924  if (textures_header_only) {
2925  // In this mode, we never intend to load the actual texture
2926  // image anyway, so we don't even need to make the size right.
2927  x_size = 1;
2928  y_size = 1;
2929 
2930  } else {
2931  adjust_size(x_size, y_size, fullpath.get_basename(), false, auto_texture_scale);
2932  }
2933 
2934  if (read_floating_point) {
2935  pfm.clear(x_size, y_size, image.get_num_channels());
2936  } else {
2937  image = PNMImage(x_size, y_size, image.get_num_channels(),
2938  image.get_maxval(), image.get_type(),
2939  image.get_color_space());
2940  image.fill(0.2, 0.3, 1.0);
2941  if (image.has_alpha()) {
2942  image.alpha_fill(1.0);
2943  }
2944  }
2945  delete image_reader;
2946 
2947  } else {
2948  if (z == 0 && n == 0) {
2949  int x_size = image.get_x_size();
2950  int y_size = image.get_y_size();
2951 
2952  cdata->_orig_file_x_size = x_size;
2953  cdata->_orig_file_y_size = y_size;
2954 
2955  if (adjust_size(x_size, y_size, fullpath.get_basename(), false, auto_texture_scale)) {
2956  image.set_read_size(x_size, y_size);
2957  }
2958  } else {
2959  image.set_read_size(do_get_expected_mipmap_x_size(cdata, n),
2960  do_get_expected_mipmap_y_size(cdata, n));
2961  }
2962 
2963  if (image.get_x_size() != image.get_read_x_size() ||
2964  image.get_y_size() != image.get_read_y_size()) {
2965  gobj_cat.info()
2966  << "Implicitly rescaling " << fullpath.get_basename() << " from "
2967  << image.get_x_size() << " by " << image.get_y_size() << " to "
2968  << image.get_read_x_size() << " by " << image.get_read_y_size()
2969  << "\n";
2970  }
2971 
2972  bool success;
2973  if (read_floating_point) {
2974  success = pfm.read(image_reader);
2975  } else {
2976  success = image.read(image_reader);
2977  }
2978 
2979  if (!success) {
2980  gobj_cat.error()
2981  << "Texture::read() - couldn't read: " << fullpath << endl;
2982  return false;
2983  }
2985  }
2986 
2987  PNMImage alpha_image;
2988  if (!alpha_fullpath.empty()) {
2989  PNMReader *alpha_image_reader = alpha_image.make_reader(alpha_fullpath, NULL, false);
2990  if (alpha_image_reader == NULL) {
2991  gobj_cat.error()
2992  << "Texture::read() - couldn't read: " << alpha_fullpath << endl;
2993  return false;
2994  }
2995  alpha_image.copy_header_from(*alpha_image_reader);
2996 
2997  if (record != (BamCacheRecord *)NULL) {
2998  record->add_dependent_file(alpha_fullpath);
2999  }
3000 
3001  if (header_only || textures_header_only) {
3002  int x_size = image.get_x_size();
3003  int y_size = image.get_y_size();
3004  alpha_image = PNMImage(x_size, y_size, alpha_image.get_num_channels(),
3005  alpha_image.get_maxval(), alpha_image.get_type(),
3006  alpha_image.get_color_space());
3007  alpha_image.fill(1.0);
3008  if (alpha_image.has_alpha()) {
3009  alpha_image.alpha_fill(1.0);
3010  }
3011  delete alpha_image_reader;
3012 
3013  } else {
3014  if (image.get_x_size() != alpha_image.get_x_size() ||
3015  image.get_y_size() != alpha_image.get_y_size()) {
3016  gobj_cat.info()
3017  << "Implicitly rescaling " << alpha_fullpath.get_basename()
3018  << " from " << alpha_image.get_x_size() << " by "
3019  << alpha_image.get_y_size() << " to " << image.get_x_size()
3020  << " by " << image.get_y_size() << "\n";
3021  alpha_image.set_read_size(image.get_x_size(), image.get_y_size());
3022  }
3023 
3024  if (!alpha_image.read(alpha_image_reader)) {
3025  gobj_cat.error()
3026  << "Texture::read() - couldn't read (alpha): " << alpha_fullpath << endl;
3027  return false;
3028  }
3030  }
3031  }
3032 
3033  if (z == 0 && n == 0) {
3034  if (!has_name()) {
3035  set_name(fullpath.get_basename_wo_extension());
3036  }
3037  if (cdata->_filename.empty()) {
3038  cdata->_filename = fullpath;
3039  cdata->_alpha_filename = alpha_fullpath;
3040 
3041  // The first time we set the filename via a read() operation, we
3042  // clear keep_ram_image. The user can always set it again later
3043  // if he needs to.
3044  cdata->_keep_ram_image = false;
3045  }
3046 
3047  cdata->_fullpath = fullpath;
3048  cdata->_alpha_fullpath = alpha_fullpath;
3049  }
3050 
3051  if (!alpha_fullpath.empty()) {
3052  // The grayscale (alpha channel) image must be the same size as
3053  // the main image. This should really have been already
3054  // guaranteed by the above.
3055  if (image.get_x_size() != alpha_image.get_x_size() ||
3056  image.get_y_size() != alpha_image.get_y_size()) {
3057  gobj_cat.info()
3058  << "Automatically rescaling " << alpha_fullpath.get_basename()
3059  << " from " << alpha_image.get_x_size() << " by "
3060  << alpha_image.get_y_size() << " to " << image.get_x_size()
3061  << " by " << image.get_y_size() << "\n";
3062 
3063  PNMImage scaled(image.get_x_size(), image.get_y_size(),
3064  alpha_image.get_num_channels(),
3065  alpha_image.get_maxval(), alpha_image.get_type(),
3066  alpha_image.get_color_space());
3067  scaled.quick_filter_from(alpha_image);
3069  alpha_image = scaled;
3070  }
3071  }
3072 
3073  if (n == 0) {
3074  consider_downgrade(image, primary_file_num_channels, get_name());
3075  cdata->_primary_file_num_channels = image.get_num_channels();
3076  cdata->_alpha_file_channel = 0;
3077  }
3078 
3079  if (!alpha_fullpath.empty()) {
3080  // Make the original image a 4-component image by taking the
3081  // grayscale value from the second image.
3082  image.add_alpha();
3083 
3084  if (alpha_file_channel == 4 ||
3085  (alpha_file_channel == 2 && alpha_image.get_num_channels() == 2)) {
3086 
3087  if (!alpha_image.has_alpha()) {
3088  gobj_cat.error()
3089  << alpha_fullpath.get_basename() << " has no channel " << alpha_file_channel << ".\n";
3090  } else {
3091  // Use the alpha channel.
3092  for (int x = 0; x < image.get_x_size(); x++) {
3093  for (int y = 0; y < image.get_y_size(); y++) {
3094  image.set_alpha(x, y, alpha_image.get_alpha(x, y));
3095  }
3096  }
3097  }
3098  cdata->_alpha_file_channel = alpha_image.get_num_channels();
3099 
3100  } else if (alpha_file_channel >= 1 && alpha_file_channel <= 3 &&
3101  alpha_image.get_num_channels() >= 3) {
3102  // Use the appropriate red, green, or blue channel.
3103  for (int x = 0; x < image.get_x_size(); x++) {
3104  for (int y = 0; y < image.get_y_size(); y++) {
3105  image.set_alpha(x, y, alpha_image.get_channel_val(x, y, alpha_file_channel - 1));
3106  }
3107  }
3108  cdata->_alpha_file_channel = alpha_file_channel;
3109 
3110  } else {
3111  // Use the grayscale channel.
3112  for (int x = 0; x < image.get_x_size(); x++) {
3113  for (int y = 0; y < image.get_y_size(); y++) {
3114  image.set_alpha(x, y, alpha_image.get_gray(x, y));
3115  }
3116  }
3117  cdata->_alpha_file_channel = 0;
3118  }
3119  }
3120 
3121  if (read_floating_point) {
3122  if (!do_load_one(cdata, pfm, fullpath.get_basename(), z, n, options)) {
3123  return false;
3124  }
3125  } else {
3126  // Now see if we want to pad the image within a larger power-of-2
3127  // image.
3128  int pad_x_size = 0;
3129  int pad_y_size = 0;
3130  if (do_get_auto_texture_scale(cdata) == ATS_pad) {
3131  int new_x_size = image.get_x_size();
3132  int new_y_size = image.get_y_size();
3133  if (do_adjust_this_size(cdata, new_x_size, new_y_size, fullpath.get_basename(), true)) {
3134  pad_x_size = new_x_size - image.get_x_size();
3135  pad_y_size = new_y_size - image.get_y_size();
3136  PNMImage new_image(new_x_size, new_y_size, image.get_num_channels(),
3137  image.get_maxval(), image.get_type(),
3138  image.get_color_space());
3139  new_image.copy_sub_image(image, 0, new_y_size - image.get_y_size());
3140  image.take_from(new_image);
3141  }
3142  }
3143 
3144  if (!do_load_one(cdata, image, fullpath.get_basename(), z, n, options)) {
3145  return false;
3146  }
3147 
3148  do_set_pad_size(cdata, pad_x_size, pad_y_size, 0);
3149  }
3150  return true;
3151 }
3152 
3153 ////////////////////////////////////////////////////////////////////
3154 // Function: Texture::do_load_one
3155 // Access: Protected, Virtual
3156 // Description: Internal method to load a single page or mipmap
3157 // level.
3158 ////////////////////////////////////////////////////////////////////
3159 bool Texture::
3160 do_load_one(CData *cdata, const PNMImage &pnmimage, const string &name, int z, int n,
3161  const LoaderOptions &options) {
3162  if (cdata->_ram_images.size() <= 1 && n == 0) {
3163  // A special case for mipmap level 0. When we load mipmap level
3164  // 0, unless we already have mipmap levels, it determines the
3165  // image properties like size and number of components.
3166  if (!do_reconsider_z_size(cdata, z, options)) {
3167  return false;
3168  }
3169  nassertr(z >= 0 && z < cdata->_z_size * cdata->_num_views, false);
3170 
3171  if (z == 0) {
3172  ComponentType component_type = T_unsigned_byte;
3173  xelval maxval = pnmimage.get_maxval();
3174  if (maxval > 255) {
3175  component_type = T_unsigned_short;
3176  }
3177 
3178  if (!do_reconsider_image_properties(cdata, pnmimage.get_x_size(), pnmimage.get_y_size(),
3179  pnmimage.get_num_channels(), component_type,
3180  z, options)) {
3181  return false;
3182  }
3183  }
3184 
3185  do_modify_ram_image(cdata);
3186  cdata->_loaded_from_image = true;
3187  }
3188 
3189  do_modify_ram_mipmap_image(cdata, n);
3190 
3191  // Ensure the PNMImage is an appropriate size.
3192  int x_size = do_get_expected_mipmap_x_size(cdata, n);
3193  int y_size = do_get_expected_mipmap_y_size(cdata, n);
3194  if (pnmimage.get_x_size() != x_size ||
3195  pnmimage.get_y_size() != y_size) {
3196  gobj_cat.info()
3197  << "Automatically rescaling " << name;
3198  if (n != 0) {
3199  gobj_cat.info(false)
3200  << " mipmap level " << n;
3201  }
3202  gobj_cat.info(false)
3203  << " from " << pnmimage.get_x_size() << " by "
3204  << pnmimage.get_y_size() << " to " << x_size << " by "
3205  << y_size << "\n";
3206 
3207  PNMImage scaled(x_size, y_size, pnmimage.get_num_channels(),
3208  pnmimage.get_maxval(), pnmimage.get_type(),
3209  pnmimage.get_color_space());
3210  scaled.quick_filter_from(pnmimage);
3212 
3213  convert_from_pnmimage(cdata->_ram_images[n]._image,
3214  do_get_expected_ram_mipmap_page_size(cdata, n),
3215  x_size, 0, 0, z, scaled,
3216  cdata->_num_components, cdata->_component_width);
3217  } else {
3218  // Now copy the pixel data from the PNMImage into our internal
3219  // cdata->_image component.
3220  convert_from_pnmimage(cdata->_ram_images[n]._image,
3221  do_get_expected_ram_mipmap_page_size(cdata, n),
3222  x_size, 0, 0, z, pnmimage,
3223  cdata->_num_components, cdata->_component_width);
3224  }
3226 
3227  return true;
3228 }
3229 
3230 ////////////////////////////////////////////////////////////////////
3231 // Function: Texture::do_load_one
3232 // Access: Protected, Virtual
3233 // Description: Internal method to load a single page or mipmap
3234 // level.
3235 ////////////////////////////////////////////////////////////////////
3236 bool Texture::
3237 do_load_one(CData *cdata, const PfmFile &pfm, const string &name, int z, int n,
3238  const LoaderOptions &options) {
3239  if (cdata->_ram_images.size() <= 1 && n == 0) {
3240  // A special case for mipmap level 0. When we load mipmap level
3241  // 0, unless we already have mipmap levels, it determines the
3242  // image properties like size and number of components.
3243  if (!do_reconsider_z_size(cdata, z, options)) {
3244  return false;
3245  }
3246  nassertr(z >= 0 && z < cdata->_z_size * cdata->_num_views, false);
3247 
3248  if (z == 0) {
3249  ComponentType component_type = T_float;
3250  if (!do_reconsider_image_properties(cdata, pfm.get_x_size(), pfm.get_y_size(),
3251  pfm.get_num_channels(), component_type,
3252  z, options)) {
3253  return false;
3254  }
3255  }
3256 
3257  do_modify_ram_image(cdata);
3258  cdata->_loaded_from_image = true;
3259  }
3260 
3261  do_modify_ram_mipmap_image(cdata, n);
3262 
3263  // Ensure the PfmFile is an appropriate size.
3264  int x_size = do_get_expected_mipmap_x_size(cdata, n);
3265  int y_size = do_get_expected_mipmap_y_size(cdata, n);
3266  if (pfm.get_x_size() != x_size ||
3267  pfm.get_y_size() != y_size) {
3268  gobj_cat.info()
3269  << "Automatically rescaling " << name;
3270  if (n != 0) {
3271  gobj_cat.info(false)
3272  << " mipmap level " << n;
3273  }
3274  gobj_cat.info(false)
3275  << " from " << pfm.get_x_size() << " by "
3276  << pfm.get_y_size() << " to " << x_size << " by "
3277  << y_size << "\n";
3278 
3279  PfmFile scaled(pfm);
3280  scaled.resize(x_size, y_size);
3282 
3283  convert_from_pfm(cdata->_ram_images[n]._image,
3284  do_get_expected_ram_mipmap_page_size(cdata, n), z,
3285  scaled, cdata->_num_components, cdata->_component_width);
3286  } else {
3287  // Now copy the pixel data from the PfmFile into our internal
3288  // cdata->_image component.
3289  convert_from_pfm(cdata->_ram_images[n]._image,
3290  do_get_expected_ram_mipmap_page_size(cdata, n), z,
3291  pfm, cdata->_num_components, cdata->_component_width);
3292  }
3294 
3295  return true;
3296 }
3297 
3298 ////////////////////////////////////////////////////////////////////
3299 // Function: Texture::do_load_sub_image
3300 // Access: Protected, Virtual
3301 // Description: Internal method to load an image into a section of
3302 // a texture page or mipmap level.
3303 ////////////////////////////////////////////////////////////////////
3304 bool Texture::
3305 do_load_sub_image(CData *cdata, const PNMImage &image, int x, int y, int z, int n) {
3306  nassertr(n >= 0 && (size_t)n < cdata->_ram_images.size(), false);
3307 
3308  int tex_x_size = do_get_expected_mipmap_x_size(cdata, n);
3309  int tex_y_size = do_get_expected_mipmap_y_size(cdata, n);
3310  int tex_z_size = do_get_expected_mipmap_z_size(cdata, n);
3311 
3312  nassertr(x >= 0 && x < tex_x_size, false);
3313  nassertr(y >= 0 && y < tex_y_size, false);
3314  nassertr(z >= 0 && z < tex_z_size, false);
3315 
3316  nassertr(image.get_x_size() + x < tex_x_size, false);
3317  nassertr(image.get_y_size() + y < tex_y_size, false);
3318 
3319  // Flip y
3320  y = cdata->_y_size - (image.get_y_size() + y);
3321 
3322  cdata->inc_image_modified();
3323  do_modify_ram_mipmap_image(cdata, n);
3324  convert_from_pnmimage(cdata->_ram_images[n]._image,
3325  do_get_expected_ram_mipmap_page_size(cdata, n),
3326  tex_x_size, x, y, z, image,
3327  cdata->_num_components, cdata->_component_width);
3328 
3329  return true;
3330 }
3331 
3332 ////////////////////////////////////////////////////////////////////
3333 // Function: Texture::do_read_txo_file
3334 // Access: Protected
3335 // Description: Called internally when read() detects a txo file.
3336 // Assumes the lock is already held.
3337 ////////////////////////////////////////////////////////////////////
3338 bool Texture::
3339 do_read_txo_file(CData *cdata, const Filename &fullpath) {
3341 
3342  Filename filename = Filename::binary_filename(fullpath);
3343  PT(VirtualFile) file = vfs->get_file(filename);
3344  if (file == (VirtualFile *)NULL) {
3345  // No such file.
3346  gobj_cat.error()
3347  << "Could not find " << fullpath << "\n";
3348  return false;
3349  }
3350 
3351  if (gobj_cat.is_debug()) {
3352  gobj_cat.debug()
3353  << "Reading texture object " << filename << "\n";
3354  }
3355 
3356  istream *in = file->open_read_file(true);
3357  bool success = do_read_txo(cdata, *in, fullpath);
3358  vfs->close_read_file(in);
3359 
3360  cdata->_fullpath = fullpath;
3361  cdata->_alpha_fullpath = Filename();
3362  cdata->_keep_ram_image = false;
3363 
3364  return success;
3365 }
3366 
3367 ////////////////////////////////////////////////////////////////////
3368 // Function: Texture::do_read_txo
3369 // Access: Protected
3370 // Description:
3371 ////////////////////////////////////////////////////////////////////
3372 bool Texture::
3373 do_read_txo(CData *cdata, istream &in, const string &filename) {
3374  PT(Texture) other = make_from_txo(in, filename);
3375  if (other == (Texture *)NULL) {
3376  return false;
3377  }
3378 
3379  CDReader cdata_other(other->_cycler);
3380  Namable::operator = (*other);
3381  do_assign(cdata, other, cdata_other);
3382 
3383  cdata->_loaded_from_image = true;
3384  cdata->_loaded_from_txo = true;
3385  cdata->_has_read_pages = false;
3386  cdata->_has_read_mipmaps = false;
3387  cdata->_num_mipmap_levels_read = 0;
3388  return true;
3389 }
3390 
3391 ////////////////////////////////////////////////////////////////////
3392 // Function: Texture::do_read_dds_file
3393 // Access: Private
3394 // Description: Called internally when read() detects a DDS file.
3395 // Assumes the lock is already held.
3396 ////////////////////////////////////////////////////////////////////
3397 bool Texture::
3398 do_read_dds_file(CData *cdata, const Filename &fullpath, bool header_only) {
3400 
3401  Filename filename = Filename::binary_filename(fullpath);
3402  PT(VirtualFile) file = vfs->get_file(filename);
3403  if (file == (VirtualFile *)NULL) {
3404  // No such file.
3405  gobj_cat.error()
3406  << "Could not find " << fullpath << "\n";
3407  return false;
3408  }
3409 
3410  if (gobj_cat.is_debug()) {
3411  gobj_cat.debug()
3412  << "Reading DDS file " << filename << "\n";
3413  }
3414 
3415  istream *in = file->open_read_file(true);
3416  bool success = do_read_dds(cdata, *in, fullpath, header_only);
3417  vfs->close_read_file(in);
3418 
3419  if (!has_name()) {
3420  set_name(fullpath.get_basename_wo_extension());
3421  }
3422 
3423  cdata->_fullpath = fullpath;
3424  cdata->_alpha_fullpath = Filename();
3425  cdata->_keep_ram_image = false;
3426 
3427  return success;
3428 }
3429 
3430 ////////////////////////////////////////////////////////////////////
3431 // Function: Texture::do_read_dds
3432 // Access: Protected
3433 // Description:
3434 ////////////////////////////////////////////////////////////////////
3435 bool Texture::
3436 do_read_dds(CData *cdata, istream &in, const string &filename, bool header_only) {
3437  StreamReader dds(in);
3438 
3439  // DDS header (19 words)
3440  DDSHeader header;
3441  header.dds_magic = dds.get_uint32();
3442  header.dds_size = dds.get_uint32();
3443  header.dds_flags = dds.get_uint32();
3444  header.height = dds.get_uint32();
3445  header.width = dds.get_uint32();
3446  header.pitch = dds.get_uint32();
3447  header.depth = dds.get_uint32();
3448  header.num_levels = dds.get_uint32();
3449  dds.skip_bytes(44);
3450 
3451  // Pixelformat (8 words)
3452  header.pf.pf_size = dds.get_uint32();
3453  header.pf.pf_flags = dds.get_uint32();
3454  header.pf.four_cc = dds.get_uint32();
3455  header.pf.rgb_bitcount = dds.get_uint32();
3456  header.pf.r_mask = dds.get_uint32();
3457  header.pf.g_mask = dds.get_uint32();
3458  header.pf.b_mask = dds.get_uint32();
3459  header.pf.a_mask = dds.get_uint32();
3460 
3461  // Caps (4 words)
3462  header.caps.caps1 = dds.get_uint32();
3463  header.caps.caps2 = dds.get_uint32();
3464  header.caps.ddsx = dds.get_uint32();
3465  dds.skip_bytes(4);
3466 
3467  // Pad out to 32 words
3468  dds.skip_bytes(4);
3469 
3470  if (header.dds_magic != DDS_MAGIC || (in.fail() || in.eof())) {
3471  gobj_cat.error()
3472  << filename << " is not a DDS file.\n";
3473  return false;
3474  }
3475 
3476  if ((header.dds_flags & DDSD_MIPMAPCOUNT) == 0) {
3477  // No bit set means only the base mipmap level.
3478  header.num_levels = 1;
3479 
3480  } else if (header.num_levels == 0) {
3481  // Some files seem to have this set to 0 for some reason--existing
3482  // readers assume 0 means 1.
3483  header.num_levels = 1;
3484  }
3485 
3486  TextureType texture_type;
3487  if (header.caps.caps2 & DDSCAPS2_CUBEMAP) {
3488  static const unsigned int all_faces =
3489  (DDSCAPS2_CUBEMAP_POSITIVEX |
3490  DDSCAPS2_CUBEMAP_POSITIVEY |
3491  DDSCAPS2_CUBEMAP_POSITIVEZ |
3492  DDSCAPS2_CUBEMAP_NEGATIVEX |
3493  DDSCAPS2_CUBEMAP_NEGATIVEY |
3494  DDSCAPS2_CUBEMAP_NEGATIVEZ);
3495  if ((header.caps.caps2 & all_faces) != all_faces) {
3496  gobj_cat.error()
3497  << filename << " is missing some cube map faces; cannot load.\n";
3498  return false;
3499  }
3500  header.depth = 6;
3501  texture_type = TT_cube_map;
3502 
3503  } else if (header.caps.caps2 & DDSCAPS2_VOLUME) {
3504  texture_type = TT_3d_texture;
3505 
3506  } else {
3507  texture_type = TT_2d_texture;
3508  header.depth = 1;
3509  }
3510 
3511  // Determine the function to use to read the DDS image.
3512  typedef PTA_uchar (*ReadDDSLevelFunc)(Texture *tex, Texture::CData *cdata,
3513  const DDSHeader &header, int n, istream &in);
3514  ReadDDSLevelFunc func = NULL;
3515 
3516  Format format = F_rgb;
3517 
3518  do_clear_ram_image(cdata);
3519  CompressionMode compression = CM_off;
3520 
3521  if (header.pf.pf_flags & DDPF_FOURCC) {
3522  // Some compressed texture format.
3523  if (texture_type == TT_3d_texture) {
3524  gobj_cat.error()
3525  << filename << ": unsupported compression on 3-d texture.\n";
3526  return false;
3527  }
3528 
3529  if (header.pf.four_cc == 0x31545844) { // 'DXT1', little-endian.
3530  compression = CM_dxt1;
3531  func = read_dds_level_dxt1;
3532  } else if (header.pf.four_cc == 0x32545844) { // 'DXT2'
3533  compression = CM_dxt2;
3534  func = read_dds_level_dxt23;
3535  } else if (header.pf.four_cc == 0x33545844) { // 'DXT3'
3536  compression = CM_dxt3;
3537  func = read_dds_level_dxt23;
3538  } else if (header.pf.four_cc == 0x34545844) { // 'DXT4'
3539  compression = CM_dxt4;
3540  func = read_dds_level_dxt45;
3541  } else if (header.pf.four_cc == 0x35545844) { // 'DXT5'
3542  compression = CM_dxt5;
3543  func = read_dds_level_dxt45;
3544  } else {
3545  gobj_cat.error()
3546  << filename << ": unsupported texture compression.\n";
3547  return false;
3548  }
3549 
3550  // All of the compressed formats support alpha, even DXT1 (to some
3551  // extent, at least).
3552  format = F_rgba;
3553 
3554  } else {
3555  // An uncompressed texture format.
3556  func = read_dds_level_generic_uncompressed;
3557 
3558  if (header.pf.pf_flags & DDPF_ALPHAPIXELS) {
3559  // An uncompressed format that involves alpha.
3560  format = F_rgba;
3561  if (header.pf.rgb_bitcount == 32 &&
3562  header.pf.r_mask == 0x000000ff &&
3563  header.pf.g_mask == 0x0000ff00 &&
3564  header.pf.b_mask == 0x00ff0000 &&
3565  header.pf.a_mask == 0xff000000U) {
3566  func = read_dds_level_abgr8;
3567  } else if (header.pf.rgb_bitcount == 32 &&
3568  header.pf.r_mask == 0x00ff0000 &&
3569  header.pf.g_mask == 0x0000ff00 &&
3570  header.pf.b_mask == 0x000000ff &&
3571  header.pf.a_mask == 0xff000000U) {
3572  func = read_dds_level_rgba8;
3573 
3574  } else if (header.pf.r_mask != 0 &&
3575  header.pf.g_mask == 0 &&
3576  header.pf.b_mask == 0) {
3577  func = read_dds_level_luminance_uncompressed;
3578  format = F_luminance_alpha;
3579  }
3580  } else {
3581  // An uncompressed format that doesn't involve alpha.
3582  if (header.pf.rgb_bitcount == 24 &&
3583  header.pf.r_mask == 0x00ff0000 &&
3584  header.pf.g_mask == 0x0000ff00 &&
3585  header.pf.b_mask == 0x000000ff) {
3586  func = read_dds_level_bgr8;
3587  } else if (header.pf.rgb_bitcount == 24 &&
3588  header.pf.r_mask == 0x000000ff &&
3589  header.pf.g_mask == 0x0000ff00 &&
3590  header.pf.b_mask == 0x00ff0000) {
3591  func = read_dds_level_rgb8;
3592 
3593  } else if (header.pf.r_mask != 0 &&
3594  header.pf.g_mask == 0 &&
3595  header.pf.b_mask == 0) {
3596  func = read_dds_level_luminance_uncompressed;
3597  format = F_luminance;
3598  }
3599  }
3600  }
3601 
3602  do_setup_texture(cdata, texture_type, header.width, header.height, header.depth,
3603  T_unsigned_byte, format);
3604 
3605  cdata->_orig_file_x_size = cdata->_x_size;
3606  cdata->_orig_file_y_size = cdata->_y_size;
3607  cdata->_compression = compression;
3608  cdata->_ram_image_compression = compression;
3609 
3610  if (!header_only) {
3611  switch (texture_type) {
3612  case TT_3d_texture:
3613  {
3614  // 3-d textures store all the depth slices for mipmap level 0,
3615  // then all the depth slices for mipmap level 1, and so on.
3616  for (int n = 0; n < (int)header.num_levels; ++n) {
3617  int z_size = do_get_expected_mipmap_z_size(cdata, n);
3618  pvector<PTA_uchar> pages;
3619  size_t page_size = 0;
3620  int z;
3621  for (z = 0; z < z_size; ++z) {
3622  PTA_uchar page = func(this, cdata, header, n, in);
3623  if (page.is_null()) {
3624  return false;
3625  }
3626  nassertr(page_size == 0 || page_size == page.size(), false);
3627  page_size = page.size();
3628  pages.push_back(page);
3629  }
3630  // Now reassemble the pages into one big image. Because
3631  // this is a Microsoft format, the images are stacked in
3632  // reverse order; re-reverse them.
3633  PTA_uchar image = PTA_uchar::empty_array(page_size * z_size);
3634  unsigned char *imagep = (unsigned char *)image.p();
3635  for (z = 0; z < z_size; ++z) {
3636  int fz = z_size - 1 - z;
3637  memcpy(imagep + z * page_size, pages[fz].p(), page_size);
3638  }
3639 
3640  do_set_ram_mipmap_image(cdata, n, image, page_size);
3641  }
3642  }
3643  break;
3644 
3645  case TT_cube_map:
3646  {
3647  // Cube maps store all the mipmap levels for face 0, then all
3648  // the mipmap levels for face 1, and so on.
3650  pages.reserve(6);
3651  int z, n;
3652  for (z = 0; z < 6; ++z) {
3653  pages.push_back(pvector<PTA_uchar>());
3654  pvector<PTA_uchar> &levels = pages.back();
3655  levels.reserve(header.num_levels);
3656 
3657  for (n = 0; n < (int)header.num_levels; ++n) {
3658  PTA_uchar image = func(this, cdata, header, n, in);
3659  if (image.is_null()) {
3660  return false;
3661  }
3662  levels.push_back(image);
3663  }
3664  }
3665 
3666  // Now, for each level, reassemble the pages into one big
3667  // image. Because this is a Microsoft format, the levels are
3668  // arranged in a rotated order.
3669  static const int level_remap[6] = {
3670  0, 1, 5, 4, 2, 3
3671  };
3672  for (n = 0; n < (int)header.num_levels; ++n) {
3673  size_t page_size = pages[0][n].size();
3674  PTA_uchar image = PTA_uchar::empty_array(page_size * 6);
3675  unsigned char *imagep = (unsigned char *)image.p();
3676  for (z = 0; z < 6; ++z) {
3677  int fz = level_remap[z];
3678  nassertr(pages[fz][n].size() == page_size, false);
3679  memcpy(imagep + z * page_size, pages[fz][n].p(), page_size);
3680  }
3681 
3682  do_set_ram_mipmap_image(cdata, n, image, page_size);
3683  }
3684  }
3685  break;
3686 
3687  default:
3688  // Normal 2-d textures simply store the mipmap levels.
3689  {
3690  for (int n = 0; n < (int)header.num_levels; ++n) {
3691  PTA_uchar image = func(this, cdata, header, n, in);
3692  if (image.is_null()) {
3693  return false;
3694  }
3695  do_set_ram_mipmap_image(cdata, n, image, 0);
3696  }
3697  }
3698  }
3699  cdata->_has_read_pages = true;
3700  cdata->_has_read_mipmaps = true;
3701  cdata->_num_mipmap_levels_read = cdata->_ram_images.size();
3702  }
3703 
3704  if (in.fail() || in.eof()) {
3705  gobj_cat.error()
3706  << filename << ": truncated DDS file.\n";
3707  return false;
3708  }
3709 
3710  cdata->_loaded_from_image = true;
3711  cdata->_loaded_from_txo = true;
3712 
3713  return true;
3714 }
3715 
3716 ////////////////////////////////////////////////////////////////////
3717 // Function: Texture::do_write
3718 // Access: Protected
3719 // Description: Internal method to write a series of pages and/or
3720 // mipmap levels to disk files.
3721 ////////////////////////////////////////////////////////////////////
3722 bool Texture::
3723 do_write(CData *cdata,
3724  const Filename &fullpath, int z, int n, bool write_pages, bool write_mipmaps) {
3725  if (is_txo_filename(fullpath)) {
3726  if (!do_has_bam_rawdata(cdata)) {
3727  do_get_bam_rawdata(cdata);
3728  }
3729  nassertr(do_has_bam_rawdata(cdata), false);
3730  return do_write_txo_file(cdata, fullpath);
3731  }
3732 
3733  if (!do_has_uncompressed_ram_image(cdata)) {
3734  do_get_uncompressed_ram_image(cdata);
3735  }
3736 
3737  nassertr(do_has_ram_mipmap_image(cdata, n), false);
3738  nassertr(cdata->_ram_image_compression == CM_off, false);
3739 
3740  if (write_pages && write_mipmaps) {
3741  // Write a sequence of pages * mipmap levels.
3742  Filename fullpath_pattern = Filename::pattern_filename(fullpath);
3743  int num_levels = cdata->_ram_images.size();
3744 
3745  for (int n = 0; n < num_levels; ++n) {
3746  int num_pages = do_get_expected_mipmap_num_pages(cdata, n);
3747 
3748  for (z = 0; z < num_pages; ++z) {
3749  Filename n_pattern = Filename::pattern_filename(fullpath_pattern.get_filename_index(z));
3750 
3751  if (!n_pattern.has_hash()) {
3752  gobj_cat.error()
3753  << "Filename requires two different hash sequences: " << fullpath
3754  << "\n";
3755  return false;
3756  }
3757 
3758  if (!do_write_one(cdata, n_pattern.get_filename_index(n), z, n)) {
3759  return false;
3760  }
3761  }
3762  }
3763 
3764  } else if (write_pages) {
3765  // Write a sequence of pages.
3766  Filename fullpath_pattern = Filename::pattern_filename(fullpath);
3767  if (!fullpath_pattern.has_hash()) {
3768  gobj_cat.error()
3769  << "Filename requires a hash mark: " << fullpath
3770  << "\n";
3771  return false;
3772  }
3773 
3774  int num_pages = cdata->_z_size * cdata->_num_views;
3775  for (z = 0; z < num_pages; ++z) {
3776  if (!do_write_one(cdata, fullpath_pattern.get_filename_index(z), z, n)) {
3777  return false;
3778  }
3779  }
3780 
3781  } else if (write_mipmaps) {
3782  // Write a sequence of mipmap images.
3783  Filename fullpath_pattern = Filename::pattern_filename(fullpath);
3784  if (!fullpath_pattern.has_hash()) {
3785  gobj_cat.error()
3786  << "Filename requires a hash mark: " << fullpath
3787  << "\n";
3788  return false;
3789  }
3790 
3791  int num_levels = cdata->_ram_images.size();
3792  for (int n = 0; n < num_levels; ++n) {
3793  if (!do_write_one(cdata, fullpath_pattern.get_filename_index(n), z, n)) {
3794  return false;
3795  }
3796  }
3797 
3798  } else {
3799  // Write a single file.
3800  if (!do_write_one(cdata, fullpath, z, n)) {
3801  return false;
3802  }
3803  }
3804 
3805  return true;
3806 }
3807 
3808 ////////////////////////////////////////////////////////////////////
3809 // Function: Texture::do_write_one
3810 // Access: Protected
3811 // Description: Internal method to write the indicated page and
3812 // mipmap level to a disk image file.
3813 ////////////////////////////////////////////////////////////////////
3814 bool Texture::
3815 do_write_one(CData *cdata, const Filename &fullpath, int z, int n) {
3816  if (!do_has_ram_mipmap_image(cdata, n)) {
3817  return false;
3818  }
3819 
3820  nassertr(cdata->_ram_image_compression == CM_off, false);
3821 
3822  bool success;
3823  if (cdata->_component_type == T_float) {
3824  // Writing a floating-point texture.
3825  PfmFile pfm;
3826  if (!do_store_one(cdata, pfm, z, n)) {
3827  return false;
3828  }
3829  success = pfm.write(fullpath);
3830  } else {
3831  // Writing a normal, integer texture.
3832  PNMImage pnmimage;
3833  if (!do_store_one(cdata, pnmimage, z, n)) {
3834  return false;
3835  }
3836  success = pnmimage.write(fullpath);
3837  }
3838 
3839  if (!success) {
3840  gobj_cat.error()
3841  << "Texture::write() - couldn't write: " << fullpath << endl;
3842  return false;
3843  }
3844 
3845  return true;
3846 }
3847 
3848 ////////////////////////////////////////////////////////////////////
3849 // Function: Texture::do_store_one
3850 // Access: Protected
3851 // Description: Internal method to copy a page and/or mipmap level to
3852 // a PNMImage.
3853 ////////////////////////////////////////////////////////////////////
3854 bool Texture::
3855 do_store_one(CData *cdata, PNMImage &pnmimage, int z, int n) {
3856  // First, reload the ram image if necessary.
3857  do_get_uncompressed_ram_image(cdata);
3858 
3859  if (!do_has_ram_mipmap_image(cdata, n)) {
3860  return false;
3861  }
3862 
3863  nassertr(z >= 0 && z < do_get_expected_mipmap_num_pages(cdata, n), false);
3864  nassertr(cdata->_ram_image_compression == CM_off, false);
3865 
3866  if (cdata->_component_type == T_float) {
3867  // PNMImage by way of PfmFile.
3868  PfmFile pfm;
3869  bool success = convert_to_pfm(pfm,
3870  do_get_expected_mipmap_x_size(cdata, n),
3871  do_get_expected_mipmap_y_size(cdata, n),
3872  cdata->_num_components, cdata->_component_width,
3873  cdata->_ram_images[n]._image,
3874  do_get_ram_mipmap_page_size(cdata, n), z);
3875  if (!success) {
3876  return false;
3877  }
3878  return pfm.store(pnmimage);
3879  }
3880 
3881  return convert_to_pnmimage(pnmimage,
3882  do_get_expected_mipmap_x_size(cdata, n),
3883  do_get_expected_mipmap_y_size(cdata, n),
3884  cdata->_num_components, cdata->_component_width,
3885  cdata->_ram_images[n]._image,
3886  do_get_ram_mipmap_page_size(cdata, n), z);
3887 }
3888 
3889 ////////////////////////////////////////////////////////////////////
3890 // Function: Texture::do_store_one
3891 // Access: Protected
3892 // Description: Internal method to copy a page and/or mipmap level to
3893 // a PfmFile.
3894 ////////////////////////////////////////////////////////////////////
3895 bool Texture::
3896 do_store_one(CData *cdata, PfmFile &pfm, int z, int n) {
3897  // First, reload the ram image if necessary.
3898  do_get_uncompressed_ram_image(cdata);
3899 
3900  if (!do_has_ram_mipmap_image(cdata, n)) {
3901  return false;
3902  }
3903 
3904  nassertr(z >= 0 && z < do_get_expected_mipmap_num_pages(cdata, n), false);
3905  nassertr(cdata->_ram_image_compression == CM_off, false);
3906 
3907  if (cdata->_component_type != T_float) {
3908  // PfmFile by way of PNMImage.
3909  PNMImage pnmimage;
3910  bool success = convert_to_pnmimage(pnmimage,
3911  do_get_expected_mipmap_x_size(cdata, n),
3912  do_get_expected_mipmap_y_size(cdata, n),
3913  cdata->_num_components, cdata->_component_width,
3914  cdata->_ram_images[n]._image,
3915  do_get_ram_mipmap_page_size(cdata, n), z);
3916  if (!success) {
3917  return false;
3918  }
3919  return pfm.load(pnmimage);
3920  }
3921 
3922  return convert_to_pfm(pfm,
3923  do_get_expected_mipmap_x_size(cdata, n),
3924  do_get_expected_mipmap_y_size(cdata, n),
3925  cdata->_num_components, cdata->_component_width,
3926  cdata->_ram_images[n]._image,
3927  do_get_ram_mipmap_page_size(cdata, n), z);
3928 }
3929 
3930 ////////////////////////////////////////////////////////////////////
3931 // Function: Texture::do_write_txo_file
3932 // Access: Private
3933 // Description: Called internally when write() detects a txo
3934 // filename.
3935 ////////////////////////////////////////////////////////////////////
3936 bool Texture::
3937 do_write_txo_file(const CData *cdata, const Filename &fullpath) const {
3939  Filename filename = Filename::binary_filename(fullpath);
3940  ostream *out = vfs->open_write_file(filename, true, true);
3941  if (out == NULL) {
3942  gobj_cat.error()
3943  << "Unable to open " << filename << "\n";
3944  return false;
3945  }
3946 
3947  bool success = do_write_txo(cdata, *out, fullpath);
3948  vfs->close_write_file(out);
3949  return success;
3950 }
3951 
3952 ////////////////////////////////////////////////////////////////////
3953 // Function: Texture::do_write_txo
3954 // Access: Protected
3955 // Description:
3956 ////////////////////////////////////////////////////////////////////
3957 bool Texture::
3958 do_write_txo(const CData *cdata, ostream &out, const string &filename) const {
3959  DatagramOutputFile dout;
3960 
3961  if (!dout.open(out, filename)) {
3962  gobj_cat.error()
3963  << "Could not write texture object: " << filename << "\n";
3964  return false;
3965  }
3966 
3967  if (!dout.write_header(_bam_header)) {
3968  gobj_cat.error()
3969  << "Unable to write to " << filename << "\n";
3970  return false;
3971  }
3972 
3973  BamWriter writer(&dout);
3974  if (!writer.init()) {
3975  return false;
3976  }
3977 
3978  writer.set_file_texture_mode(BamWriter::BTM_rawdata);
3979 
3980  if (!writer.write_object(this)) {
3981  return false;
3982  }
3983 
3984  if (!do_has_bam_rawdata(cdata)) {
3985  gobj_cat.error()
3986  << get_name() << " does not have ram image\n";
3987  return false;
3988  }
3989 
3990  return true;
3991 }
3992 
3993 ////////////////////////////////////////////////////////////////////
3994 // Function: Texture::unlocked_ensure_ram_image
3995 // Access: Protected, Virtual
3996 // Description: If the texture has a ram image already, this acquires
3997 // the CData write lock and returns it.
3998 //
3999 // If the texture lacks a ram image, this performs
4000 // do_reload_ram_image(), but without holding the lock
4001 // on this particular Texture object, to avoid holding
4002 // the lock across what might be a slow operation.
4003 // Instead, the reload is performed in a copy of the
4004 // texture object, and then the lock is acquired and the
4005 // data is copied in.
4006 //
4007 // In any case, the return value is a locked CData
4008 // object, which must be released with an explicit call
4009 // to release_write(). The CData object will have a ram
4010 // image unless for some reason do_reload_ram_image()
4011 // fails.
4012 ////////////////////////////////////////////////////////////////////
4013 Texture::CData *Texture::
4014 unlocked_ensure_ram_image(bool allow_compression) {
4015  Thread *current_thread = Thread::get_current_thread();
4016 
4017  // First, wait for any other threads that might be simultaneously
4018  // performing the same operation.
4019  MutexHolder holder(_lock);
4020  while (_reloading) {
4021  _cvar.wait();
4022  }
4023 
4024  // Then make sure we still need to reload before continuing.
4025  const CData *cdata = _cycler.read(current_thread);
4026  bool has_ram_image = do_has_ram_image(cdata);
4027  if (has_ram_image && !allow_compression && cdata->_ram_image_compression != Texture::CM_off) {
4028  // If we don't want compression, but the ram image we have is
4029  // pre-compressed, we don't consider it.
4030  has_ram_image = false;
4031  }
4032  if (has_ram_image || !do_can_reload(cdata)) {
4033  // We don't need to reload after all, or maybe we can't reload
4034  // anyway. Return, but elevate the lock first, as we promised.
4035  return _cycler.elevate_read_upstream(cdata, false, current_thread);
4036  }
4037 
4038  // We need to reload.
4039  nassertr(!_reloading, NULL);
4040  _reloading = true;
4041 
4042  PT(Texture) tex = do_make_copy(cdata);
4043  _cycler.release_read(cdata);
4044  _lock.release();
4045 
4046  // Perform the actual reload in a copy of the texture, while our
4047  // own mutex is left unlocked.
4048  CDWriter cdata_tex(tex->_cycler, true);
4049  tex->do_reload_ram_image(cdata_tex, allow_compression);
4050 
4051  _lock.acquire();
4052 
4053  CData *cdataw = _cycler.write_upstream(false, current_thread);
4054 
4055  // Rather than calling do_assign(), which would copy *all* of the
4056  // reloaded texture's properties over, we only copy in the ones
4057  // which are relevant to the ram image. This way, if the
4058  // properties have changed during the reload (for instance,
4059  // because we reloaded a txo), it won't contaminate the original
4060  // texture.
4061  cdataw->_orig_file_x_size = cdata_tex->_orig_file_x_size;
4062  cdataw->_orig_file_y_size = cdata_tex->_orig_file_y_size;
4063 
4064  // If any of *these* properties have changed, the texture has
4065  // changed in some fundamental way. Update it appropriately.
4066  if (cdata_tex->_x_size != cdataw->_x_size ||
4067  cdata_tex->_y_size != cdataw->_y_size ||
4068  cdata_tex->_z_size != cdataw->_z_size ||
4069  cdata_tex->_num_views != cdataw->_num_views ||
4070  cdata_tex->_num_components != cdataw->_num_components ||
4071  cdata_tex->_component_width != cdataw->_component_width ||
4072  cdata_tex->_texture_type != cdataw->_texture_type ||
4073  cdata_tex->_component_type != cdataw->_component_type) {
4074 
4075  cdataw->_x_size = cdata_tex->_x_size;
4076  cdataw->_y_size = cdata_tex->_y_size;
4077  cdataw->_z_size = cdata_tex->_z_size;
4078  cdataw->_num_views = cdata_tex->_num_views;
4079 
4080  cdataw->_num_components = cdata_tex->_num_components;
4081  cdataw->_component_width = cdata_tex->_component_width;
4082  cdataw->_texture_type = cdata_tex->_texture_type;
4083  cdataw->_format = cdata_tex->_format;
4084  cdataw->_component_type = cdata_tex->_component_type;
4085 
4086  cdataw->inc_properties_modified();
4087  cdataw->inc_image_modified();
4088  }
4089 
4090  cdataw->_keep_ram_image = cdata_tex->_keep_ram_image;
4091  cdataw->_ram_image_compression = cdata_tex->_ram_image_compression;
4092  cdataw->_ram_images = cdata_tex->_ram_images;
4093 
4094  nassertr(_reloading, NULL);
4095  _reloading = false;
4096 
4097  // We don't generally increment the cdata->_image_modified semaphore,
4098  // because this is just a reload, and presumably the image hasn't
4099  // changed (unless we hit the if condition above).
4100 
4101  _cvar.notify_all();
4102 
4103  // Return the still-locked cdata.
4104  return cdataw;
4105 }
4106 
4107 ////////////////////////////////////////////////////////////////////
4108 // Function: Texture::do_reload_ram_image
4109 // Access: Protected, Virtual
4110 // Description: Called when the Texture image is required but the ram
4111 // image is not available, this will reload it from disk
4112 // or otherwise do whatever is required to make it
4113 // available, if possible.
4114 //
4115 // Assumes the lock is already held. The lock will be
4116 // held during the duration of this operation.
4117 ////////////////////////////////////////////////////////////////////
4118 void Texture::
4119 do_reload_ram_image(CData *cdata, bool allow_compression) {
4121  PT(BamCacheRecord) record;
4122 
4123  if (!do_has_compression(cdata)) {
4124  allow_compression = false;
4125  }
4126 
4127  if ((cache->get_cache_textures() || (allow_compression && cache->get_cache_compressed_textures())) && !textures_header_only) {
4128  // See if the texture can be found in the on-disk cache, if it is
4129  // active.
4130 
4131  record = cache->lookup(cdata->_fullpath, "txo");
4132  if (record != (BamCacheRecord *)NULL &&
4133  record->has_data()) {
4134  PT(Texture) tex = DCAST(Texture, record->get_data());
4135 
4136  // But don't use the cache record if the config parameters have
4137  // changed, and we want a different-sized texture now.
4138  int x_size = cdata->_orig_file_x_size;
4139  int y_size = cdata->_orig_file_y_size;
4140  do_adjust_this_size(cdata, x_size, y_size, cdata->_filename.get_basename(), true);
4141  if (x_size != tex->get_x_size() || y_size != tex->get_y_size()) {
4142  if (gobj_cat.is_debug()) {
4143  gobj_cat.debug()
4144  << "Cached texture " << *this << " has size "
4145  << tex->get_x_size() << " x " << tex->get_y_size()
4146  << " instead of " << x_size << " x " << y_size
4147  << "; ignoring cache.\n";
4148  }
4149  } else {
4150  // Also don't keep the cached version if it's compressed but
4151  // we want uncompressed.
4152  if (!allow_compression && tex->get_ram_image_compression() != Texture::CM_off) {
4153  if (gobj_cat.is_debug()) {
4154  gobj_cat.debug()
4155  << "Cached texture " << *this
4156  << " is compressed in cache; ignoring cache.\n";
4157  }
4158  } else {
4159  gobj_cat.info()
4160  << "Texture " << get_name() << " reloaded from disk cache\n";
4161  // We don't want to replace all the texture parameters--for
4162  // instance, we don't want to change the filter type or the
4163  // border color or anything--we just want to get the image and
4164  // necessary associated parameters.
4165  CDReader cdata_tex(tex->_cycler);
4166  cdata->_x_size = cdata_tex->_x_size;
4167  cdata->_y_size = cdata_tex->_y_size;
4168  if (cdata->_num_components != cdata_tex->_num_components) {
4169  cdata->_num_components = cdata_tex->_num_components;
4170  cdata->_format = cdata_tex->_format;
4171  }
4172  cdata->_component_type = cdata_tex->_component_type;
4173  cdata->_compression = cdata_tex->_compression;
4174  cdata->_ram_image_compression = cdata_tex->_ram_image_compression;
4175  cdata->_ram_images = cdata_tex->_ram_images;
4176  cdata->_loaded_from_image = true;
4177 
4178  bool was_compressed = (cdata->_ram_image_compression != CM_off);
4179  if (do_consider_auto_process_ram_image(cdata, uses_mipmaps(), allow_compression)) {
4180  bool is_compressed = (cdata->_ram_image_compression != CM_off);
4181  if (!was_compressed && is_compressed &&
4182  cache->get_cache_compressed_textures()) {
4183  // We've re-compressed the image after loading it from the
4184  // cache. To keep the cache current, rewrite it to the
4185  // cache now, in its newly compressed form.
4186  record->set_data(this, this);
4187  cache->store(record);
4188  }
4189  }
4190 
4191  return;
4192  }
4193  }
4194  }
4195  }
4196 
4197  gobj_cat.info()
4198  << "Reloading texture " << get_name() << "\n";
4199 
4200  int z = 0;
4201  int n = 0;
4202 
4203  if (cdata->_has_read_pages) {
4204  z = cdata->_z_size;
4205  }
4206  if (cdata->_has_read_mipmaps) {
4207  n = cdata->_num_mipmap_levels_read;
4208  }
4209 
4210  cdata->_loaded_from_image = false;
4211  Format orig_format = cdata->_format;
4212  int orig_num_components = cdata->_num_components;
4213 
4214  LoaderOptions options;
4215  options.set_texture_flags(LoaderOptions::TF_preload);
4216  do_read(cdata, cdata->_fullpath, cdata->_alpha_fullpath,
4217  cdata->_primary_file_num_channels, cdata->_alpha_file_channel,
4218  z, n, cdata->_has_read_pages, cdata->_has_read_mipmaps, options, NULL);
4219 
4220  if (orig_num_components == cdata->_num_components) {
4221  // Restore the original format, in case it was needlessly changed
4222  // during the reload operation.
4223  cdata->_format = orig_format;
4224  }
4225 
4226  if (do_has_ram_image(cdata) && record != (BamCacheRecord *)NULL) {
4227  if (cache->get_cache_textures() || (cdata->_ram_image_compression != CM_off && cache->get_cache_compressed_textures())) {
4228  // Update the cache.
4229  if (record != (BamCacheRecord *)NULL) {
4230  record->add_dependent_file(cdata->_fullpath);
4231  }
4232  record->set_data(this, this);
4233  cache->store(record);
4234  }
4235  }
4236 }
4237 
4238 ////////////////////////////////////////////////////////////////////
4239 // Function: Texture::do_modify_ram_image
4240 // Access: Protected
4241 // Description: This is called internally to uniquify the ram image
4242 // pointer without updating cdata->_image_modified.
4243 ////////////////////////////////////////////////////////////////////
4244 PTA_uchar Texture::
4245 do_modify_ram_image(CData *cdata) {
4246  if (cdata->_ram_images.empty() || cdata->_ram_images[0]._image.empty() ||
4247  cdata->_ram_image_compression != CM_off) {
4248  do_make_ram_image(cdata);
4249  } else {
4250  do_clear_ram_mipmap_images(cdata);
4251  }
4252  return cdata->_ram_images[0]._image;
4253 }
4254 
4255 ////////////////////////////////////////////////////////////////////
4256 // Function: Texture::do_make_ram_image
4257 // Access: Protected
4258 // Description: This is called internally to make a new ram image
4259 // without updating cdata->_image_modified.
4260 ////////////////////////////////////////////////////////////////////
4261 PTA_uchar Texture::
4262 do_make_ram_image(CData *cdata) {
4263  int image_size = do_get_expected_ram_image_size(cdata);
4264  cdata->_ram_images.clear();
4265  cdata->_ram_images.push_back(RamImage());
4266  cdata->_ram_images[0]._page_size = do_get_expected_ram_page_size(cdata);
4267  cdata->_ram_images[0]._image = PTA_uchar::empty_array(image_size, get_class_type());
4268  cdata->_ram_images[0]._pointer_image = NULL;
4269  cdata->_ram_image_compression = CM_off;
4270 
4271  if (cdata->_has_clear_color) {
4272  // Fill the image with the clear color.
4273  unsigned char pixel[16];
4274  const int pixel_size = do_get_clear_data(cdata, pixel);
4275  nassertr(pixel_size > 0, cdata->_ram_images[0]._image);
4276 
4277  unsigned char *image_data = cdata->_ram_images[0]._image;
4278  for (int i = 0; i < image_size; i += pixel_size) {
4279  memcpy(image_data + i, pixel, pixel_size);
4280  }
4281  }
4282 
4283  return cdata->_ram_images[0]._image;
4284 }
4285 
4286 ////////////////////////////////////////////////////////////////////
4287 // Function: Texture::do_set_ram_image
4288 // Access: Protected
4289 // Description: Replaces the current system-RAM image with the new
4290 // data. If compression is not CM_off, it indicates
4291 // that the new data is already pre-compressed in the
4292 // indicated format.
4293 //
4294 // This does *not* affect keep_ram_image.
4295 ////////////////////////////////////////////////////////////////////
4296 void Texture::
4297 do_set_ram_image(CData *cdata, CPTA_uchar image, Texture::CompressionMode compression,
4298  size_t page_size) {
4299  nassertv(compression != CM_default);
4300  nassertv(compression != CM_off || image.size() == do_get_expected_ram_image_size(cdata));
4301  if (cdata->_ram_images.empty()) {
4302  cdata->_ram_images.push_back(RamImage());
4303  } else {
4304  do_clear_ram_mipmap_images(cdata);
4305  }
4306  if (page_size == 0) {
4307  page_size = image.size();
4308  }
4309  if (cdata->_ram_images[0]._image != image ||
4310  cdata->_ram_images[0]._page_size != page_size ||
4311  cdata->_ram_image_compression != compression) {
4312  cdata->_ram_images[0]._image = image.cast_non_const();
4313  cdata->_ram_images[0]._page_size = page_size;
4314  cdata->_ram_images[0]._pointer_image = NULL;
4315  cdata->_ram_image_compression = compression;
4316  cdata->inc_image_modified();
4317  }
4318 }
4319 
4320 ////////////////////////////////////////////////////////////////////
4321 // Function: Texture::do_modify_ram_mipmap_image
4322 // Access: Protected
4323 // Description: This is called internally to uniquify the nth mipmap
4324 // image pointer without updating cdata->_image_modified.
4325 ////////////////////////////////////////////////////////////////////
4326 PTA_uchar Texture::
4327 do_modify_ram_mipmap_image(CData *cdata, int n) {
4328  nassertr(cdata->_ram_image_compression == CM_off, PTA_uchar());
4329 
4330  if (n >= (int)cdata->_ram_images.size() ||
4331  cdata->_ram_images[n]._image.empty()) {
4332  do_make_ram_mipmap_image(cdata, n);
4333  }
4334  return cdata->_ram_images[n]._image;
4335 }
4336 
4337 ////////////////////////////////////////////////////////////////////
4338 // Function: Texture::do_make_ram_mipmap_image
4339 // Access: Protected
4340 // Description:
4341 ////////////////////////////////////////////////////////////////////
4342 PTA_uchar Texture::
4343 do_make_ram_mipmap_image(CData *cdata, int n) {
4344  nassertr(cdata->_ram_image_compression == CM_off, PTA_uchar(get_class_type()));
4345 
4346  while (n >= (int)cdata->_ram_images.size()) {
4347  cdata->_ram_images.push_back(RamImage());
4348  }
4349 
4350  size_t image_size = do_get_expected_ram_mipmap_image_size(cdata, n);
4351  cdata->_ram_images[n]._image = PTA_uchar::empty_array(image_size, get_class_type());
4352  cdata->_ram_images[n]._pointer_image = NULL;
4353  cdata->_ram_images[n]._page_size = do_get_expected_ram_mipmap_page_size(cdata, n);
4354 
4355  if (cdata->_has_clear_color) {
4356  // Fill the image with the clear color.
4357  unsigned char pixel[16];
4358  const size_t pixel_size = (size_t)do_get_clear_data(cdata, pixel);
4359  nassertr(pixel_size > 0, cdata->_ram_images[n]._image);
4360 
4361  unsigned char *image_data = cdata->_ram_images[n]._image;
4362  for (size_t i = 0; i < image_size; i += pixel_size) {
4363  memcpy(image_data + i, pixel, pixel_size);
4364  }
4365  }
4366 
4367  return cdata->_ram_images[n]._image;
4368 }
4369 
4370 ////////////////////////////////////////////////////////////////////
4371 // Function: Texture::do_set_ram_mipmap_image
4372 // Access: Published
4373 // Description:
4374 ////////////////////////////////////////////////////////////////////
4375 void Texture::
4376 do_set_ram_mipmap_image(CData *cdata, int n, CPTA_uchar image, size_t page_size) {
4377  nassertv(cdata->_ram_image_compression != CM_off || image.size() == do_get_expected_ram_mipmap_image_size(cdata, n));
4378 
4379  while (n >= (int)cdata->_ram_images.size()) {
4380  cdata->_ram_images.push_back(RamImage());
4381  }
4382  if (page_size == 0) {
4383  page_size = image.size();
4384  }
4385 
4386  if (cdata->_ram_images[n]._image != image ||
4387  cdata->_ram_images[n]._page_size != page_size) {
4388  cdata->_ram_images[n]._image = image.cast_non_const();
4389  cdata->_ram_images[n]._pointer_image = NULL;
4390  cdata->_ram_images[n]._page_size = page_size;
4391  cdata->inc_image_modified();
4392  }
4393 }
4394 
4395 ////////////////////////////////////////////////////////////////////
4396 // Function: Texture::do_get_clear_color
4397 // Access: Published
4398 // Description: Returns a string with a single pixel representing
4399 // the clear color of the texture in the format of
4400 // this texture.
4401 //
4402 // In other words, to create an uncompressed RAM
4403 // texture filled with the clear color, it should
4404 // be initialized with this string repeated for
4405 // every pixel.
4406 ////////////////////////////////////////////////////////////////////
4407 int Texture::
4408 do_get_clear_data(const CData *cdata, unsigned char *into) const {
4409  nassertr(cdata->_has_clear_color, 0);
4410  nassertr(cdata->_num_components <= 4, 0);
4411 
4412  //TODO: encode the color into the sRGB color space if used
4413  switch (cdata->_component_type) {
4414  case T_unsigned_byte:
4415  {
4416  LColor scaled = cdata->_clear_color.fmin(LColor(1)).fmax(LColor::zero());
4417  scaled *= 255;
4418  switch (cdata->_num_components) {
4419  case 2:
4420  into[1] = (unsigned char)scaled[1];
4421  case 1:
4422  into[0] = (unsigned char)scaled[0];
4423  break;
4424  case 4:
4425  into[3] = (unsigned char)scaled[3];
4426  case 3: // BGR <-> RGB
4427  into[0] = (unsigned char)scaled[2];
4428  into[1] = (unsigned char)scaled[1];
4429  into[2] = (unsigned char)scaled[0];
4430  break;
4431  }
4432  break;
4433  }
4434 
4435  case T_unsigned_short:
4436  {
4437  LColor scaled = cdata->_clear_color.fmin(LColor(1)).fmax(LColor::zero());
4438  scaled *= 65535;
4439  switch (cdata->_num_components) {
4440  case 2:
4441  ((unsigned short *)into)[1] = (unsigned short)scaled[1];
4442  case 1:
4443  ((unsigned short *)into)[0] = (unsigned short)scaled[0];
4444  break;
4445  case 4:
4446  ((unsigned short *)into)[3] = (unsigned short)scaled[3];
4447  case 3: // BGR <-> RGB
4448  ((unsigned short *)into)[0] = (unsigned short)scaled[2];
4449  ((unsigned short *)into)[1] = (unsigned short)scaled[1];
4450  ((unsigned short *)into)[2] = (unsigned short)scaled[0];
4451  break;
4452  }
4453  break;
4454  }
4455 
4456  case T_float:
4457  switch (cdata->_num_components) {
4458  case 2:
4459  ((float *)into)[1] = cdata->_clear_color[1];
4460  case 1:
4461  ((float *)into)[0] = cdata->_clear_color[0];
4462  break;
4463  case 4:
4464  ((float *)into)[3] = cdata->_clear_color[3];
4465  case 3: // BGR <-> RGB
4466  ((float *)into)[0] = cdata->_clear_color[2];
4467  ((float *)into)[1] = cdata->_clear_color[1];
4468  ((float *)into)[2] = cdata->_clear_color[0];
4469  break;
4470  }
4471  break;
4472 
4473  case T_unsigned_int_24_8:
4474  nassertr(cdata->_num_components == 1, 0);
4475  *((unsigned int *)into) =
4476  ((unsigned int)(cdata->_clear_color[0] * 16777215) << 8) +
4477  (unsigned int)max(min(cdata->_clear_color[1], (PN_stdfloat)255), (PN_stdfloat)0);
4478  break;
4479 
4480  case T_int:
4481  {
4482  // Note: there are no 32-bit UNORM textures. Therefore, we don't
4483  // do any normalization here, either.
4484  switch (cdata->_num_components) {
4485  case 2:
4486  ((int *)into)[1] = (int)cdata->_clear_color[1];
4487  case 1:
4488  ((int *)into)[0] = (int)cdata->_clear_color[0];
4489  break;
4490  case 4:
4491  ((int *)into)[3] = (int)cdata->_clear_color[3];
4492  case 3: // BGR <-> RGB
4493  ((int *)into)[0] = (int)cdata->_clear_color[2];
4494  ((int *)into)[1] = (int)cdata->_clear_color[1];
4495  ((int *)into)[2] = (int)cdata->_clear_color[0];
4496  break;
4497  }
4498  break;
4499  }
4500  }
4501 
4502  return cdata->_num_components * cdata->_component_width;
4503 }
4504 
4505 ////////////////////////////////////////////////////////////////////
4506 // Function: Texture::consider_auto_process_ram_image
4507 // Access: Protected
4508 // Description: Should be called after a texture has been loaded into
4509 // RAM, this considers generating mipmaps and/or
4510 // compressing the RAM image.
4511 //
4512 // Returns true if the image was modified by this
4513 // operation, false if it wasn't.
4514 ////////////////////////////////////////////////////////////////////
4515 bool Texture::
4516 consider_auto_process_ram_image(bool generate_mipmaps, bool allow_compression) {
4517  CDWriter cdata(_cycler, false);
4518  return do_consider_auto_process_ram_image(cdata, generate_mipmaps, allow_compression);
4519 }
4520 
4521 ////////////////////////////////////////////////////////////////////
4522 // Function: Texture::do_consider_auto_process_ram_image
4523 // Access: Protected
4524 // Description: Should be called after a texture has been loaded into
4525 // RAM, this considers generating mipmaps and/or
4526 // compressing the RAM image.
4527 //
4528 // Returns true if the image was modified by this
4529 // operation, false if it wasn't.
4530 ////////////////////////////////////////////////////////////////////
4531 bool Texture::
4532 do_consider_auto_process_ram_image(CData *cdata, bool generate_mipmaps,
4533  bool allow_compression) {
4534  bool modified = false;
4535 
4536  if (generate_mipmaps && !driver_generate_mipmaps &&
4537  cdata->_ram_images.size() == 1) {
4538  do_generate_ram_mipmap_images(cdata);
4539  modified = true;
4540  }
4541 
4542  if (allow_compression && !driver_compress_textures) {
4543  CompressionMode compression = cdata->_compression;
4544  if (compression == CM_default && compressed_textures) {
4545  compression = CM_on;
4546  }
4547  if (compression != CM_off && cdata->_ram_image_compression == CM_off) {
4549  if (do_compress_ram_image(cdata, compression, QL_default, gsg)) {
4550  if (gobj_cat.is_debug()) {
4551  gobj_cat.debug()
4552  << "Compressed " << get_name() << " with "
4553  << cdata->_ram_image_compression << "\n";
4554  }
4555  modified = true;
4556  }
4557  }
4558  }
4559 
4560  return modified;
4561 }
4562 
4563 ////////////////////////////////////////////////////////////////////
4564 // Function: Texture::do_compress_ram_image
4565 // Access: Protected
4566 // Description:
4567 ////////////////////////////////////////////////////////////////////
4568 bool Texture::
4569 do_compress_ram_image(CData *cdata, Texture::CompressionMode compression,
4570  Texture::QualityLevel quality_level,
4572  nassertr(compression != CM_off, false);
4573 
4574  if (compression == CM_on) {
4575  // Select an appropriate compression mode automatically.
4576  switch (cdata->_format) {
4577  case Texture::F_rgbm:
4578  case Texture::F_rgb:
4579  case Texture::F_rgb5:
4580  case Texture::F_rgba5:
4581  case Texture::F_rgb8:
4582  case Texture::F_rgb12:
4583  case Texture::F_rgb332:
4584  case Texture::F_rgb16:
4585  case Texture::F_rgb32:
4586  if (gsg == NULL || gsg->get_supports_compressed_texture_format(CM_dxt1)) {
4587  compression = CM_dxt1;
4588  } else if (gsg == NULL || gsg->get_supports_compressed_texture_format(CM_dxt3)) {
4589  compression = CM_dxt3;
4590  } else if (gsg == NULL || gsg->get_supports_compressed_texture_format(CM_dxt5)) {
4591  compression = CM_dxt5;
4592  }
4593  break;
4594 
4595  case Texture::F_rgba4:
4596  if (gsg == NULL || gsg->get_supports_compressed_texture_format(CM_dxt3)) {
4597  compression = CM_dxt3;
4598  } else if (gsg == NULL || gsg->get_supports_compressed_texture_format(CM_dxt5)) {
4599  compression = CM_dxt5;
4600  }
4601  break;
4602 
4603  case Texture::F_rgba:
4604  case Texture::F_rgba8:
4605  case Texture::F_rgba12:
4606  case Texture::F_rgba16:
4607  case Texture::F_rgba32:
4608  if (gsg == NULL || gsg->get_supports_compressed_texture_format(CM_dxt5)) {
4609  compression = CM_dxt5;
4610  }
4611  break;
4612 
4613  default:
4614  break;
4615  }
4616  }
4617 
4618  // Choose an appropriate quality level.
4619  if (quality_level == Texture::QL_default) {
4620  quality_level = cdata->_quality_level;
4621  }
4622  if (quality_level == Texture::QL_default) {
4623  quality_level = texture_quality_level;
4624  }
4625 
4626 #ifdef HAVE_SQUISH
4627  if (cdata->_texture_type != TT_3d_texture &&
4628  cdata->_texture_type != TT_2d_texture_array &&
4629  cdata->_component_type == T_unsigned_byte) {
4630  int squish_flags = 0;
4631  switch (compression) {
4632  case CM_dxt1:
4633  squish_flags |= squish::kDxt1;
4634  break;
4635 
4636  case CM_dxt3:
4637  squish_flags |= squish::kDxt3;
4638  break;
4639 
4640  case CM_dxt5:
4641  squish_flags |= squish::kDxt5;
4642  break;
4643 
4644  default:
4645  break;
4646  }
4647 
4648  if (squish_flags != 0) {
4649  // This compression mode is supported by squish; use it.
4650  switch (quality_level) {
4651  case QL_fastest:
4652  squish_flags |= squish::kColourRangeFit;
4653  break;
4654 
4655  case QL_normal:
4656  // ColourClusterFit is just too slow for everyday use.
4657  squish_flags |= squish::kColourRangeFit;
4658  // squish_flags |= squish::kColourClusterFit;
4659  break;
4660 
4661  case QL_best:
4662  squish_flags |= squish::kColourIterativeClusterFit;
4663  break;
4664 
4665  default:
4666  break;
4667  }
4668 
4669  if (do_squish(cdata, compression, squish_flags)) {
4670  return true;
4671  }
4672  }
4673  }
4674 #endif // HAVE_SQUISH
4675 
4676  return false;
4677 }
4678 
4679 ////////////////////////////////////////////////////////////////////
4680 // Function: Texture::do_uncompress_ram_image
4681 // Access: Protected
4682 // Description:
4683 ////////////////////////////////////////////////////////////////////
4684 bool Texture::
4685 do_uncompress_ram_image(CData *cdata) {
4686 
4687 #ifdef HAVE_SQUISH
4688  if (cdata->_texture_type != TT_3d_texture &&
4689  cdata->_texture_type != TT_2d_texture_array &&
4690  cdata->_component_type == T_unsigned_byte) {
4691  int squish_flags = 0;
4692  switch (cdata->_ram_image_compression) {
4693  case CM_dxt1:
4694  squish_flags |= squish::kDxt1;
4695  break;
4696 
4697  case CM_dxt3:
4698  squish_flags |= squish::kDxt3;
4699  break;
4700 
4701  case CM_dxt5:
4702  squish_flags |= squish::kDxt5;
4703  break;
4704 
4705  default:
4706  break;
4707  }
4708 
4709  if (squish_flags != 0) {
4710  // This compression mode is supported by squish; use it.
4711  if (do_unsquish(cdata, squish_flags)) {
4712  return true;
4713  }
4714  }
4715  }
4716 #endif // HAVE_SQUISH
4717  return false;
4718 }
4719 
4720 ////////////////////////////////////////////////////////////////////
4721 // Function: Texture::do_has_all_ram_mipmap_images
4722 // Access: Protected
4723 // Description:
4724 ////////////////////////////////////////////////////////////////////
4725 bool Texture::
4726 do_has_all_ram_mipmap_images(const CData *cdata) const {
4727  if (cdata->_ram_images.empty() || cdata->_ram_images[0]._image.empty()) {
4728  // If we don't even have a base image, the answer is no.
4729  return false;
4730  }
4731  if (!uses_mipmaps()) {
4732  // If we have a base image and don't require mipmapping, the
4733  // answer is yes.
4734  return true;
4735  }
4736 
4737  // Check that we have enough mipmap levels to meet the size
4738  // requirements.
4739  int size = max(cdata->_x_size, max(cdata->_y_size, cdata->_z_size));
4740  int n = 0;
4741  int x = 1;
4742  while (x < size) {
4743  x = (x << 1);
4744  ++n;
4745  if (n >= (int)cdata->_ram_images.size() || cdata->_ram_images[n]._image.empty()) {
4746  return false;
4747  }
4748  }
4749 
4750  return true;
4751 }
4752 
4753 ////////////////////////////////////////////////////////////////////
4754 // Function: Texture::do_reconsider_z_size
4755 // Access: Protected
4756 // Description: Considers whether the z_size (or num_views) should
4757 // automatically be adjusted when the user loads a new
4758 // page. Returns true if the z size is valid, false
4759 // otherwise.
4760 //
4761 // Assumes the lock is already held.
4762 ////////////////////////////////////////////////////////////////////
4763 bool Texture::
4764 do_reconsider_z_size(CData *cdata, int z, const LoaderOptions &options) {
4765  if (z >= cdata->_z_size * cdata->_num_views) {
4766  bool num_views_specified = true;
4767  if (options.get_texture_flags() & LoaderOptions::TF_multiview) {
4768  // This flag is false if is a multiview texture with a specified
4769  // number of views. It is true if it is not a multiview
4770  // texture, or if it is but the number of views is explicitly
4771  // specified.
4772  num_views_specified = (options.get_texture_num_views() != 0);
4773  }
4774 
4775  if (num_views_specified &&
4776  (cdata->_texture_type == Texture::TT_3d_texture ||
4777  cdata->_texture_type == Texture::TT_2d_texture_array)) {
4778  // If we're loading a page past _z_size, treat it as an implicit
4779  // request to enlarge _z_size. However, this is only legal if
4780  // this is, in fact, a 3-d texture or a 2d texture array (cube maps
4781  // always have z_size 6, and other types have z_size 1).
4782  nassertr(cdata->_num_views != 0, false);
4783  cdata->_z_size = (z / cdata->_num_views) + 1;
4784 
4785  } else if (cdata->_z_size != 0) {
4786  // In the case of a 2-d texture or cube map, or a 3-d texture
4787  // with an unspecified _num_views, assume we're loading views of
4788  // a multiview texture.
4789  cdata->_num_views = (z / cdata->_z_size) + 1;
4790 
4791  } else {
4792  // The first image loaded sets an implicit z-size.
4793  cdata->_z_size = 1;
4794  }
4795 
4796  // Increase the size of the data buffer to make room for the new
4797  // texture level.
4798  do_allocate_pages(cdata);
4799  }
4800 
4801  return true;
4802 }
4803 
4804 ////////////////////////////////////////////////////////////////////
4805 // Function: Texture::do_allocate_pages
4806 // Access: Protected, Virtual
4807 // Description: Called internally by do_reconsider_z_size() to
4808 // allocate new memory in _ram_images[0] for the new
4809 // number of pages.
4810 //
4811 // Assumes the lock is already held.
4812 ////////////////////////////////////////////////////////////////////
4813 void Texture::
4814 do_allocate_pages(CData *cdata) {
4815  size_t new_size = do_get_expected_ram_image_size(cdata);
4816  if (!cdata->_ram_images.empty() &&
4817  !cdata->_ram_images[0]._image.empty() &&
4818  new_size > cdata->_ram_images[0]._image.size()) {
4819  cdata->_ram_images[0]._image.insert(cdata->_ram_images[0]._image.end(), new_size - cdata->_ram_images[0]._image.size(), 0);
4820  nassertv(cdata->_ram_images[0]._image.size() == new_size);
4821  }
4822 }
4823 
4824 ////////////////////////////////////////////////////////////////////
4825 // Function: Texture::do_reconsider_image_properties
4826 // Access: Protected
4827 // Description: Resets the internal Texture properties when a new
4828 // image file is loaded. Returns true if the new image
4829 // is valid, false otherwise.
4830 //
4831 // Assumes the lock is already held.
4832 ////////////////////////////////////////////////////////////////////
4833 bool Texture::
4834 do_reconsider_image_properties(CData *cdata, int x_size, int y_size, int num_components,
4835  Texture::ComponentType component_type, int z,
4836  const LoaderOptions &options) {
4837  if (!cdata->_loaded_from_image || num_components != cdata->_num_components || component_type != cdata->_component_type) {
4838  // Come up with a default format based on the number of channels.
4839  // But only do this the first time the file is loaded, or if the
4840  // number of channels in the image changes on subsequent loads.
4841 
4842  //TODO: handle sRGB properly
4843  switch (num_components) {
4844  case 1:
4845  cdata->_format = F_luminance;
4846  break;
4847 
4848  case 2:
4849  cdata->_format = F_luminance_alpha;
4850  break;
4851 
4852  case 3:
4853  cdata->_format = F_rgb;
4854  break;
4855 
4856  case 4:
4857  cdata->_format = F_rgba;
4858  break;
4859 
4860  default:
4861  // Eh?
4862  nassertr(false, false);
4863  cdata->_format = F_rgb;
4864  }
4865  }
4866 
4867  if (!cdata->_loaded_from_image) {
4868  if ((options.get_texture_flags() & LoaderOptions::TF_allow_1d) &&
4869  cdata->_texture_type == TT_2d_texture && x_size != 1 && y_size == 1) {
4870  // If we're loading an Nx1 size texture, infer a 1-d texture type.
4871  cdata->_texture_type = TT_1d_texture;
4872  }
4873 
4874 #ifndef NDEBUG
4875  if (cdata->_texture_type == TT_1d_texture) {
4876  nassertr(y_size == 1, false);
4877  } else if (cdata->_texture_type == TT_cube_map) {
4878  nassertr(x_size == y_size, false);
4879  }
4880 #endif
4881  if ((cdata->_x_size != x_size)||(cdata->_y_size != y_size)) {
4882  do_set_pad_size(cdata, 0, 0, 0);
4883  }
4884  cdata->_x_size = x_size;
4885  cdata->_y_size = y_size;
4886  cdata->_num_components = num_components;
4887  do_set_component_type(cdata, component_type);
4888 
4889  } else {
4890  if (cdata->_x_size != x_size ||
4891  cdata->_y_size != y_size ||
4892  cdata->_num_components != num_components ||
4893  cdata->_component_type != component_type) {
4894  gobj_cat.error()
4895  << "Texture properties have changed for texture " << get_name()
4896  << " page " << z << ".\n";
4897  return false;
4898  }
4899  }
4900 
4901  return true;
4902 }
4903 
4904 ////////////////////////////////////////////////////////////////////
4905 // Function: Texture::do_rescale_texture
4906 // Access: Private
4907 // Description:
4908 ////////////////////////////////////////////////////////////////////
4909 bool Texture::
4910 do_rescale_texture(CData *cdata) {
4911  int new_x_size = cdata->_x_size;
4912  int new_y_size = cdata->_y_size;
4913  if (cdata->_z_size * cdata->_num_views != 1) {
4914  nassert_raise("rescale_texture() doesn't support 3-d or multiview textures.");
4915  return false;
4916  }
4917 
4918  if (do_adjust_this_size(cdata, new_x_size, new_y_size, get_name(), false)) {
4919  // OK, we have to scale the image.
4920  PNMImage orig_image;
4921  if (!do_store_one(cdata, orig_image, 0, 0)) {
4922  gobj_cat.warning()
4923  << "Couldn't get image in rescale_texture()\n";
4924  return false;
4925  }
4926 
4927  gobj_cat.info()
4928  << "Resizing " << get_name() << " to " << new_x_size << " x "
4929  << new_y_size << "\n";
4930  PNMImage new_image(new_x_size, new_y_size, orig_image.get_num_channels(),
4931  orig_image.get_maxval(), orig_image.get_type(),
4932  orig_image.get_color_space());
4933  new_image.quick_filter_from(orig_image);
4934 
4935  do_clear_ram_image(cdata);
4936  cdata->inc_image_modified();
4937  cdata->_x_size = new_x_size;
4938  cdata->_y_size = new_y_size;
4939  if (!do_load_one(cdata, new_image, get_name(), 0, 0, LoaderOptions())) {
4940  return false;
4941  }
4942 
4943  return true;
4944  }
4945 
4946  // Maybe we should pad the image.
4947  int pad_x_size = 0;
4948  int pad_y_size = 0;
4949  if (do_get_auto_texture_scale(cdata) == ATS_pad) {
4950  new_x_size = cdata->_x_size;
4951  new_y_size = cdata->_y_size;
4952  if (do_adjust_this_size(cdata, new_x_size, new_y_size, get_name(), true)) {
4953  pad_x_size = new_x_size - cdata->_x_size;
4954  pad_y_size = new_y_size - cdata->_y_size;
4955 
4956  PNMImage orig_image;
4957  if (!do_store_one(cdata, orig_image, 0, 0)) {
4958  gobj_cat.warning()
4959  << "Couldn't get image in rescale_texture()\n";
4960  return false;
4961  }
4962  PNMImage new_image(new_x_size, new_y_size, orig_image.get_num_channels(),
4963  orig_image.get_maxval(), orig_image.get_type(),
4964  orig_image.get_color_space());
4965  new_image.copy_sub_image(orig_image, 0, new_y_size - orig_image.get_y_size());
4966 
4967  do_clear_ram_image(cdata);
4968  cdata->_loaded_from_image = false;
4969  cdata->inc_image_modified();
4970  if (!do_load_one(cdata, new_image, get_name(), 0, 0, LoaderOptions())) {
4971  return false;
4972  }
4973 
4974  do_set_pad_size(cdata, pad_x_size, pad_y_size, 0);
4975  return true;
4976  }
4977  }
4978 
4979  // No changes needed.
4980  return false;
4981 }
4982 
4983 ////////////////////////////////////////////////////////////////////
4984 // Function: Texture::make_copy_impl
4985 // Access: Protected, Virtual
4986 // Description:
4987 ////////////////////////////////////////////////////////////////////
4988 PT(Texture) Texture::
4989 make_copy_impl() const {
4990  CDReader cdata(_cycler);
4991  return do_make_copy(cdata);
4992 }
4993 
4994 ////////////////////////////////////////////////////////////////////
4995 // Function: Texture::do_make_copy
4996 // Access: Protected
4997 // Description:
4998 ////////////////////////////////////////////////////////////////////
4999 PT(Texture) Texture::
5000 do_make_copy(const CData *cdata) const {
5001  PT(Texture) tex = new Texture(get_name());
5002  CDWriter cdata_tex(tex->_cycler, true);
5003  tex->do_assign(cdata_tex, this, cdata);
5004  return tex;
5005 }
5006 
5007 ////////////////////////////////////////////////////////////////////
5008 // Function: Texture::do_assign
5009 // Access: Protected
5010 // Description: The internal implementation of operator =(). Assumes
5011 // the lock is already held on both Textures.
5012 ////////////////////////////////////////////////////////////////////
5013 void Texture::
5014 do_assign(CData *cdata, const Texture *copy, const CData *cdata_copy) {
5015  cdata->do_assign(cdata_copy);
5016 }
5017 
5018 ////////////////////////////////////////////////////////////////////
5019 // Function: Texture::do_clear
5020 // Access: Protected, Virtual
5021 // Description: The protected implementation of clear(). Assumes the
5022 // lock is already held.
5023 ////////////////////////////////////////////////////////////////////
5024 void Texture::
5025 do_clear(CData *cdata) {
5026  Texture tex;
5027  tex.local_object();
5028  CDReader cdata_tex(tex._cycler);
5029  do_assign(cdata, &tex, cdata_tex);
5030 
5031  cdata->inc_properties_modified();
5032  cdata->inc_image_modified();
5033  cdata->inc_simple_image_modified();
5034 }
5035 
5036 ////////////////////////////////////////////////////////////////////
5037 // Function: Texture::do_setup_texture
5038 // Access: Protected
5039 // Description:
5040 ////////////////////////////////////////////////////////////////////
5041 void Texture::
5042 do_setup_texture(CData *cdata, Texture::TextureType texture_type,
5043  int x_size, int y_size, int z_size,
5044  Texture::ComponentType component_type,
5045  Texture::Format format) {
5046  switch (texture_type) {
5047  case TT_1d_texture:
5048  nassertv(y_size == 1 && z_size == 1);
5049  break;
5050 
5051  case TT_2d_texture:
5052  nassertv(z_size == 1);
5053  break;
5054 
5055  case TT_3d_texture:
5056  break;
5057 
5058  case TT_2d_texture_array:
5059  break;
5060 
5061  case TT_cube_map:
5062  // Cube maps must always consist of six square images.
5063  nassertv(x_size == y_size && z_size == 6);
5064 
5065  // In principle the wrap mode shouldn't mean anything to a cube
5066  // map, but some drivers seem to misbehave if it's other than
5067  // SamplerState::WM_clamp.
5068  cdata->_default_sampler.set_wrap_u(SamplerState::WM_clamp);
5069  cdata->_default_sampler.set_wrap_v(SamplerState::WM_clamp);
5070  cdata->_default_sampler.set_wrap_w(SamplerState::WM_clamp);
5071  break;
5072  }
5073 
5074  if (texture_type != TT_2d_texture) {
5075  do_clear_simple_ram_image(cdata);
5076  }
5077 
5078  cdata->_texture_type = texture_type;
5079  cdata->_x_size = x_size;
5080  cdata->_y_size = y_size;
5081  cdata->_z_size = z_size;
5082  cdata->_num_views = 1;
5083  do_set_component_type(cdata, component_type);
5084  do_set_format(cdata, format);
5085 
5086  do_clear_ram_image(cdata);
5087  do_set_pad_size(cdata, 0, 0, 0);
5088  cdata->_orig_file_x_size = 0;
5089  cdata->_orig_file_y_size = 0;
5090  cdata->_loaded_from_image = false;
5091  cdata->_loaded_from_txo = false;
5092  cdata->_has_read_pages = false;
5093  cdata->_has_read_mipmaps = false;
5094 }
5095 
5096 ////////////////////////////////////////////////////////////////////
5097 // Function: Texture::do_set_format
5098 // Access: Protected
5099 // Description:
5100 ////////////////////////////////////////////////////////////////////
5101 void Texture::
5102 do_set_format(CData *cdata, Texture::Format format) {
5103  if (format == cdata->_format) {
5104  return;
5105  }
5106  cdata->_format = format;
5107  cdata->inc_properties_modified();
5108 
5109  switch (cdata->_format) {
5110  case F_color_index:
5111  case F_depth_stencil:
5112  case F_depth_component:
5113  case F_depth_component16:
5114  case F_depth_component24:
5115  case F_depth_component32:
5116  case F_red:
5117  case F_green:
5118  case F_blue:
5119  case F_alpha:
5120  case F_luminance:
5121  case F_r16:
5122  case F_sluminance:
5123  case F_r32i:
5124  case F_r32:
5125  case F_r8i:
5126  cdata->_num_components = 1;
5127  break;
5128 
5129  case F_luminance_alpha:
5130  case F_luminance_alphamask:
5131  case F_rg16:
5132  case F_sluminance_alpha:
5133  case F_rg32:
5134  case F_rg8i:
5135  cdata->_num_components = 2;
5136  break;
5137 
5138  case F_rgb:
5139  case F_rgb5:
5140  case F_rgb8:
5141  case F_rgb12:
5142  case F_rgb332:
5143  case F_rgb16:
5144  case F_srgb:
5145  case F_rgb32:
5146  case F_rgb8i:
5147  cdata->_num_components = 3;
5148  break;
5149 
5150  case F_rgba:
5151  case F_rgbm:
5152  case F_rgba4:
5153  case F_rgba5:
5154  case F_rgba8:
5155  case F_rgba12:
5156  case F_rgba16:
5157  case F_rgba32:
5158  case F_srgb_alpha:
5159  case F_rgba8i:
5160  cdata->_num_components = 4;
5161  break;
5162  }
5163 }
5164 
5165 ////////////////////////////////////////////////////////////////////
5166 // Function: Texture::do_set_component_type
5167 // Access: Protected
5168 // Description:
5169 ////////////////////////////////////////////////////////////////////
5170 void Texture::
5171 do_set_component_type(CData *cdata, Texture::ComponentType component_type) {
5172  cdata->_component_type = component_type;
5173 
5174  switch (component_type) {
5175  case T_unsigned_byte:
5176  cdata->_component_width = 1;
5177  break;
5178 
5179  case T_unsigned_short:
5180  cdata->_component_width = 2;
5181  break;
5182 
5183  case T_float:
5184  cdata->_component_width = 4;
5185  break;
5186 
5187  case T_unsigned_int_24_8:
5188  cdata->_component_width = 4;
5189  break;
5190 
5191  case T_int:
5192  cdata->_component_width = 4;
5193  break;
5194  }
5195 }
5196 
5197 ////////////////////////////////////////////////////////////////////
5198 // Function: Texture::do_set_x_size
5199 // Access: Protected
5200 // Description:
5201 ////////////////////////////////////////////////////////////////////
5202 void Texture::
5203 do_set_x_size(CData *cdata, int x_size) {
5204  if (cdata->_x_size != x_size) {
5205  cdata->_x_size = x_size;
5206  cdata->inc_image_modified();
5207  do_clear_ram_image(cdata);
5208  do_set_pad_size(cdata, 0, 0, 0);
5209  }
5210 }
5211 
5212 ////////////////////////////////////////////////////////////////////
5213 // Function: Texture::do_set_y_size
5214 // Access: Protected
5215 // Description:
5216 ////////////////////////////////////////////////////////////////////
5217 void Texture::
5218 do_set_y_size(CData *cdata, int y_size) {
5219  if (cdata->_y_size != y_size) {
5220  nassertv(cdata->_texture_type != Texture::TT_1d_texture || y_size == 1);
5221  cdata->_y_size = y_size;
5222  cdata->inc_image_modified();
5223  do_clear_ram_image(cdata);
5224  do_set_pad_size(cdata, 0, 0, 0);
5225  }
5226 }
5227 
5228 ////////////////////////////////////////////////////////////////////
5229 // Function: Texture::do_set_z_size
5230 // Access: Protected
5231 // Description: Changes the z size indicated for the texture. This
5232 // also implicitly unloads the texture if it has already
5233 // been loaded.
5234 ////////////////////////////////////////////////////////////////////
5235 void Texture::
5236 do_set_z_size(CData *cdata, int z_size) {
5237  if (cdata->_z_size != z_size) {
5238  nassertv((cdata->_texture_type == Texture::TT_3d_texture) ||
5239  (cdata->_texture_type == Texture::TT_cube_map && z_size == 6) ||
5240  (cdata->_texture_type == Texture::TT_2d_texture_array) || (z_size == 1));
5241  cdata->_z_size = z_size;
5242  cdata->inc_image_modified();
5243  do_clear_ram_image(cdata);
5244  do_set_pad_size(cdata, 0, 0, 0);
5245  }
5246 }
5247 
5248 ////////////////////////////////////////////////////////////////////
5249 // Function: Texture::do_set_num_views
5250 // Access: Protected
5251 // Description:
5252 ////////////////////////////////////////////////////////////////////
5253 void Texture::
5254 do_set_num_views(CData *cdata, int num_views) {
5255  nassertv(num_views >= 1);
5256  if (cdata->_num_views != num_views) {
5257  cdata->_num_views = num_views;
5258  if (do_has_ram_image(cdata)) {
5259  cdata->inc_image_modified();
5260  do_clear_ram_image(cdata);
5261  }
5262  do_set_pad_size(cdata, 0, 0, 0);
5263  }
5264 }
5265 
5266 ////////////////////////////////////////////////////////////////////
5267 // Function: Texture::do_set_wrap_u
5268 // Access: Protected
5269 // Description:
5270 ////////////////////////////////////////////////////////////////////
5271 void Texture::
5272 do_set_wrap_u(CData *cdata, SamplerState::WrapMode wrap) {
5273  if (cdata->_default_sampler.get_wrap_u() != wrap) {
5274  cdata->inc_properties_modified();
5275  cdata->_default_sampler.set_wrap_u(wrap);
5276  }
5277 }
5278 
5279 ////////////////////////////////////////////////////////////////////
5280 // Function: Texture::do_set_wrap_v
5281 // Access: Protected
5282 // Description:
5283 ////////////////////////////////////////////////////////////////////
5284 void Texture::
5285 do_set_wrap_v(CData *cdata, SamplerState::WrapMode wrap) {
5286  if (cdata->_default_sampler.get_wrap_v() != wrap) {
5287  cdata->inc_properties_modified();
5288  cdata->_default_sampler.set_wrap_v(wrap);
5289  }
5290 }
5291 
5292 ////////////////////////////////////////////////////////////////////
5293 // Function: Texture::do_set_wrap_w
5294 // Access: Protected
5295 // Description:
5296 ////////////////////////////////////////////////////////////////////
5297 void Texture::
5298 do_set_wrap_w(CData *cdata, SamplerState::WrapMode wrap) {
5299  if (cdata->_default_sampler.get_wrap_w() != wrap) {
5300  cdata->inc_properties_modified();
5301  cdata->_default_sampler.set_wrap_w(wrap);
5302  }
5303 }
5304 
5305 ////////////////////////////////////////////////////////////////////
5306 // Function: Texture::do_set_minfilter
5307 // Access: Protected
5308 // Description:
5309 ////////////////////////////////////////////////////////////////////
5310 void Texture::
5311 do_set_minfilter(CData *cdata, SamplerState::FilterType filter) {
5312  if (cdata->_default_sampler.get_minfilter() != filter) {
5313  cdata->inc_properties_modified();
5314  cdata->_default_sampler.set_minfilter(filter);
5315  }
5316 }
5317 
5318 ////////////////////////////////////////////////////////////////////
5319 // Function: Texture::do_set_magfilter
5320 // Access: Protected
5321 // Description:
5322 ////////////////////////////////////////////////////////////////////
5323 void Texture::
5324 do_set_magfilter(CData *cdata, SamplerState::FilterType filter) {
5325  if (cdata->_default_sampler.get_magfilter() != filter) {
5326  cdata->inc_properties_modified();
5327  cdata->_default_sampler.set_magfilter(filter);
5328  }
5329 }
5330 
5331 ////////////////////////////////////////////////////////////////////
5332 // Function: Texture::do_set_anisotropic_degree
5333 // Access: Protected
5334 // Description:
5335 ////////////////////////////////////////////////////////////////////
5336 void Texture::
5337 do_set_anisotropic_degree(CData *cdata, int anisotropic_degree) {
5338  if (cdata->_default_sampler.get_anisotropic_degree() != anisotropic_degree) {
5339  cdata->inc_properties_modified();
5340  cdata->_default_sampler.set_anisotropic_degree(anisotropic_degree);
5341  }
5342 }
5343 
5344 ////////////////////////////////////////////////////////////////////
5345 // Function: Texture::do_set_border_color
5346 // Access: Protected
5347 // Description:
5348 ////////////////////////////////////////////////////////////////////
5349 void Texture::
5350 do_set_border_color(CData *cdata, const LColor &color) {
5351  if (cdata->_default_sampler.get_border_color() != color) {
5352  cdata->inc_properties_modified();
5353  cdata->_default_sampler.set_border_color(color);
5354  }
5355 }
5356 
5357 ////////////////////////////////////////////////////////////////////
5358 // Function: Texture::do_set_compression
5359 // Access: Protected
5360 // Description:
5361 ////////////////////////////////////////////////////////////////////
5362 void Texture::
5363 do_set_compression(CData *cdata, Texture::CompressionMode compression) {
5364  if (cdata->_compression != compression) {
5365  cdata->inc_properties_modified();
5366  cdata->_compression = compression;
5367 
5368  if (do_has_ram_image(cdata)) {
5369  bool has_compression = do_has_compression(cdata);
5370  bool has_ram_image_compression = (cdata->_ram_image_compression != CM_off);
5371  if (has_compression != has_ram_image_compression ||
5372  has_compression) {
5373  // Reload if we're turning compression on or off, or if we're
5374  // changing the compression mode to a different kind of
5375  // compression.
5376  do_reload(cdata);
5377  }
5378  }
5379  }
5380 }
5381 
5382 ////////////////////////////////////////////////////////////////////
5383 // Function: Texture::do_set_quality_level
5384 // Access: Public
5385 // Description:
5386 ////////////////////////////////////////////////////////////////////
5387 void Texture::
5388 do_set_quality_level(CData *cdata, Texture::QualityLevel quality_level) {
5389  if (cdata->_quality_level != quality_level) {
5390  cdata->inc_properties_modified();
5391  cdata->_quality_level = quality_level;
5392  }
5393 }
5394 
5395 ////////////////////////////////////////////////////////////////////
5396 // Function: Texture::do_has_compression
5397 // Access: Protected
5398 // Description:
5399 ////////////////////////////////////////////////////////////////////
5400 bool Texture::
5401 do_has_compression(const CData *cdata) const {
5402  if (cdata->_compression == CM_default) {
5403  return compressed_textures;
5404  } else {
5405  return (cdata->_compression != CM_off);
5406  }
5407 }
5408 
5409 ////////////////////////////////////////////////////////////////////
5410 // Function: Texture::do_has_ram_image
5411 // Access: Protected, Virtual
5412 // Description: The protected implementation of has_ram_image().
5413 // Assumes the lock is already held.
5414 ////////////////////////////////////////////////////////////////////
5415 bool Texture::
5416 do_has_ram_image(const CData *cdata) const {
5417  return !cdata->_ram_images.empty() && !cdata->_ram_images[0]._image.empty();
5418 }
5419 
5420 ////////////////////////////////////////////////////////////////////
5421 // Function: Texture::do_has_uncompressed_ram_image
5422 // Access: Protected, Virtual
5423 // Description: The protected implementation of
5424 // has_uncompressed_ram_image(). Assumes the lock is
5425 // already held.
5426 ////////////////////////////////////////////////////////////////////
5427 bool Texture::
5428 do_has_uncompressed_ram_image(const CData *cdata) const {
5429  return !cdata->_ram_images.empty() && !cdata->_ram_images[0]._image.empty() && cdata->_ram_image_compression == CM_off;
5430 }
5431 
5432 ////////////////////////////////////////////////////////////////////
5433 // Function: Texture::do_get_ram_image
5434 // Access: Protected
5435 // Description:
5436 ////////////////////////////////////////////////////////////////////
5437 CPTA_uchar Texture::
5438 do_get_ram_image(CData *cdata) {
5439  if (!do_has_ram_image(cdata) && do_can_reload(cdata)) {
5440  do_reload_ram_image(cdata, true);
5441 
5442  if (do_has_ram_image(cdata)) {
5443  // Normally, we don't update the cdata->_modified semaphores in a do_blah
5444  // method, but we'll make an exception in this case, because it's
5445  // easiest to modify these here, and only when we know it's
5446  // needed.
5447  cdata->inc_image_modified();
5448  cdata->inc_properties_modified();
5449  }
5450  }
5451 
5452  if (cdata->_ram_images.empty()) {
5453  return CPTA_uchar(get_class_type());
5454  }
5455 
5456  return cdata->_ram_images[0]._image;
5457 }
5458 
5459 ////////////////////////////////////////////////////////////////////
5460 // Function: Texture::do_get_uncompressed_ram_image
5461 // Access: Protected
5462 // Description:
5463 ////////////////////////////////////////////////////////////////////
5464 CPTA_uchar Texture::
5465 do_get_uncompressed_ram_image(CData *cdata) {
5466  if (!cdata->_ram_images.empty() && cdata->_ram_image_compression != CM_off) {
5467  // We have an image in-ram, but it's compressed. Try to
5468  // uncompress it first.
5469  if (do_uncompress_ram_image(cdata)) {
5470  if (gobj_cat.is_debug()) {
5471  gobj_cat.debug()
5472  << "Uncompressed " << get_name() << "\n";
5473  }
5474  return cdata->_ram_images[0]._image;
5475  }
5476  }
5477 
5478  // Couldn't uncompress the existing image. Try to reload it.
5479  if ((!do_has_ram_image(cdata) || cdata->_ram_image_compression != CM_off) && do_can_reload(cdata)) {
5480  do_reload_ram_image(cdata, false);
5481  }
5482 
5483  if (!cdata->_ram_images.empty() && cdata->_ram_image_compression != CM_off) {
5484  // Great, now we have an image.
5485  if (do_uncompress_ram_image(cdata)) {
5486  gobj_cat.info()
5487  << "Uncompressed " << get_name() << "\n";
5488  return cdata->_ram_images[0]._image;
5489  }
5490  }
5491 
5492  if (cdata->_ram_images.empty() || cdata->_ram_image_compression != CM_off) {
5493  return CPTA_uchar(get_class_type());
5494  }
5495 
5496  return cdata->_ram_images[0]._image;
5497 }
5498 
5499 ////////////////////////////////////////////////////////////////////
5500 // Function: Texture::get_ram_image_as
5501 // Access: Published
5502 // Description: Returns the uncompressed system-RAM image data
5503 // associated with the texture. Rather than
5504 // just returning a pointer to the data, like
5505 // get_uncompressed_ram_image, this function first
5506 // processes the data and reorders the components
5507 // using the specified format string, and places these
5508 // into a new char array. The 'format' argument should
5509 // specify in which order the components of the texture
5510 // must be. For example, valid format strings are
5511 // "RGBA", "GA", "ABRG" or "AAA". A component can
5512 // also be written as "0" or "1", which means an
5513 // empty/black or a full/white channel, respectively.
5514 // This function is particularly useful to
5515 // copy an image in-memory to a different library
5516 // (for example, PIL or wxWidgets) that require
5517 // a different component order than Panda's internal
5518 // format, BGRA. Note, however, that this conversion
5519 // can still be too slow if you want to do it every
5520 // frame, and should thus be avoided for that purpose.
5521 // The only requirement for the reordering is that
5522 // an uncompressed image must be available. If the
5523 // RAM image is compressed, it will attempt to re-load
5524 // the texture from disk, if it doesn't find an
5525 // uncompressed image there, it will return NULL.
5526 ////////////////////////////////////////////////////////////////////
5528 get_ram_image_as(const string &requested_format) {
5529  CDWriter cdata(_cycler, false);
5530  string format = upcase(requested_format);
5531 
5532  // Make sure we can grab something that's uncompressed.
5533  CPTA_uchar data = do_get_uncompressed_ram_image(cdata);
5534  if (data == NULL) {
5535  gobj_cat.error() << "Couldn't find an uncompressed RAM image!\n";
5536  return CPTA_uchar(get_class_type());
5537  }
5538  int imgsize = cdata->_x_size * cdata->_y_size;
5539  nassertr(cdata->_num_components > 0 && cdata->_num_components <= 4, CPTA_uchar(get_class_type()));
5540  nassertr(data.size() == (size_t)(cdata->_component_width * cdata->_num_components * imgsize), CPTA_uchar(get_class_type()));
5541 
5542  // Check if the format is already what we have internally.
5543  if ((cdata->_num_components == 1 && format.size() == 1) ||
5544  (cdata->_num_components == 2 && format.size() == 2 && format.at(1) == 'A' && format.at(0) != 'A') ||
5545  (cdata->_num_components == 3 && format == "BGR") ||
5546  (cdata->_num_components == 4 && format == "BGRA")) {
5547  // The format string is already our format, so we just need to copy it.
5548  return CPTA_uchar(data);
5549  }
5550 
5551  // Create a new empty array that can hold our image.
5552  PTA_uchar newdata = PTA_uchar::empty_array(imgsize * format.size() * cdata->_component_width, get_class_type());
5553 
5554  // These ifs are for optimization of commonly used image types.
5555  if (format == "RGBA" && cdata->_num_components == 4 && cdata->_component_width == 1) {
5556  imgsize *= 4;
5557  for (int p = 0; p < imgsize; p += 4) {
5558  newdata[p ] = data[p + 2];
5559  newdata[p + 1] = data[p + 1];
5560  newdata[p + 2] = data[p ];
5561  newdata[p + 3] = data[p + 3];
5562  }
5563  return newdata;
5564  }
5565  if (format == "RGB" && cdata->_num_components == 3 && cdata->_component_width == 1) {
5566  imgsize *= 3;
5567  for (int p = 0; p < imgsize; p += 3) {
5568  newdata[p ] = data[p + 2];
5569  newdata[p + 1] = data[p + 1];
5570  newdata[p + 2] = data[p ];
5571  }
5572  return newdata;
5573  }
5574  if (format == "A" && cdata->_component_width == 1 && cdata->_num_components != 3) {
5575  // We can generally rely on alpha to be the last component.
5576  int component = cdata->_num_components - 1;
5577  for (int p = 0; p < imgsize; ++p) {
5578  newdata[p] = data[component];
5579  }
5580  return newdata;
5581  }
5582  if (cdata->_component_width == 1) {
5583  for (int p = 0; p < imgsize; ++p) {
5584  for (uchar s = 0; s < format.size(); ++s) {
5585  signed char component = -1;
5586  if (format.at(s) == 'B' || (cdata->_num_components <= 2 && format.at(s) != 'A')) {
5587  component = 0;
5588  } else if (format.at(s) == 'G') {
5589  component = 1;
5590  } else if (format.at(s) == 'R') {
5591  component = 2;
5592  } else if (format.at(s) == 'A') {
5593  nassertr(cdata->_num_components != 3, CPTA_uchar(get_class_type()));
5594  component = cdata->_num_components - 1;
5595  } else if (format.at(s) == '0') {
5596  newdata[p * format.size() + s] = 0x00;
5597  } else if (format.at(s) == '1') {
5598  newdata[p * format.size() + s] = 0xff;
5599  } else {
5600  gobj_cat.error() << "Unexpected component character '"
5601  << format.at(s) << "', expected one of RGBA!\n";
5602  return CPTA_uchar(get_class_type());
5603  }
5604  if (component >= 0) {
5605  newdata[p * format.size() + s] = data[p * cdata->_num_components + component];
5606  }
5607  }
5608  }
5609  return newdata;
5610  }
5611  for (int p = 0; p < imgsize; ++p) {
5612  for (uchar s = 0; s < format.size(); ++s) {
5613  signed char component = -1;
5614  if (format.at(s) == 'B' || (cdata->_num_components <= 2 && format.at(s) != 'A')) {
5615  component = 0;
5616  } else if (format.at(s) == 'G') {
5617  component = 1;
5618  } else if (format.at(s) == 'R') {
5619  component = 2;
5620  } else if (format.at(s) == 'A') {
5621  nassertr(cdata->_num_components != 3, CPTA_uchar(get_class_type()));
5622  component = cdata->_num_components - 1;
5623  } else if (format.at(s) == '0') {
5624  memset((void*)(newdata + (p * format.size() + s) * cdata->_component_width), 0, cdata->_component_width);
5625  } else if (format.at(s) == '1') {
5626  memset((void*)(newdata + (p * format.size() + s) * cdata->_component_width), -1, cdata->_component_width);
5627  } else {
5628  gobj_cat.error() << "Unexpected component character '"
5629  << format.at(s) << "', expected one of RGBA!\n";
5630  return CPTA_uchar(get_class_type());
5631  }
5632  if (component >= 0) {
5633  memcpy((void*)(newdata + (p * format.size() + s) * cdata->_component_width),
5634  (void*)(data + (p * cdata->_num_components + component) * cdata->_component_width),
5635  cdata->_component_width);
5636  }
5637  }
5638  }
5639  return newdata;
5640 }
5641 
5642 ////////////////////////////////////////////////////////////////////
5643 // Function: Texture::do_set_simple_ram_image
5644 // Access: Protected
5645 // Description:
5646 ////////////////////////////////////////////////////////////////////
5647 void Texture::
5648 do_set_simple_ram_image(CData *cdata, CPTA_uchar image, int x_size, int y_size) {
5649  nassertv(cdata->_texture_type == TT_2d_texture);
5650  size_t expected_page_size = (size_t)(x_size * y_size * 4);
5651  nassertv(image.size() == expected_page_size);
5652 
5653  cdata->_simple_x_size = x_size;
5654  cdata->_simple_y_size = y_size;
5655  cdata->_simple_ram_image._image = image.cast_non_const();
5656  cdata->_simple_ram_image._page_size = image.size();
5657  cdata->_simple_image_date_generated = (PN_int32)time(NULL);
5658  cdata->inc_simple_image_modified();
5659 }
5660 
5661 ////////////////////////////////////////////////////////////////////
5662 // Function: Texture::do_get_expected_num_mipmap_levels
5663 // Access: Protected
5664 // Description:
5665 ////////////////////////////////////////////////////////////////////
5666 int Texture::
5667 do_get_expected_num_mipmap_levels(const CData *cdata) const {
5668  int size = max(cdata->_x_size, max(cdata->_y_size, cdata->_z_size));
5669  int count = 1;
5670  while (size > 1) {
5671  size >>= 1;
5672  ++count;
5673  }
5674  return count;
5675 }
5676 
5677 ////////////////////////////////////////////////////////////////////
5678 // Function: Texture::do_get_ram_mipmap_page_size
5679 // Access: Protected
5680 // Description:
5681 ////////////////////////////////////////////////////////////////////
5682 size_t Texture::
5683 do_get_ram_mipmap_page_size(const CData *cdata, int n) const {
5684  if (cdata->_ram_image_compression != CM_off) {
5685  if (n >= 0 && n < (int)cdata->_ram_images.size()) {
5686  return cdata->_ram_images[n]._page_size;
5687  }
5688  return 0;
5689  } else {
5690  return do_get_expected_ram_mipmap_page_size(cdata, n);
5691  }
5692 }
5693 
5694 ////////////////////////////////////////////////////////////////////
5695 // Function: Texture::do_get_expected_mipmap_x_size
5696 // Access: Protected
5697 // Description:
5698 ////////////////////////////////////////////////////////////////////
5699 int Texture::
5700 do_get_expected_mipmap_x_size(const CData *cdata, int n) const {
5701  int size = max(cdata->_x_size, 1);
5702  while (n > 0 && size > 1) {
5703  size >>= 1;
5704  --n;
5705  }
5706  return size;
5707 }
5708 
5709 ////////////////////////////////////////////////////////////////////
5710 // Function: Texture::do_get_expected_mipmap_y_size
5711 // Access: Protected
5712 // Description:
5713 ////////////////////////////////////////////////////////////////////
5714 int Texture::
5715 do_get_expected_mipmap_y_size(const CData *cdata, int n) const {
5716  int size = max(cdata->_y_size, 1);
5717  while (n > 0 && size > 1) {
5718  size >>= 1;
5719  --n;
5720  }
5721  return size;
5722 }
5723 
5724 ////////////////////////////////////////////////////////////////////
5725 // Function: Texture::do_get_expected_mipmap_z_size
5726 // Access: Protected
5727 // Description:
5728 ////////////////////////////////////////////////////////////////////
5729 int Texture::
5730 do_get_expected_mipmap_z_size(const CData *cdata, int n) const {
5731  // 3-D textures have a different number of pages per each mipmap
5732  // level. Other kinds of textures--especially, cube map
5733  // textures--always have the same.
5734  if (cdata->_texture_type == Texture::TT_3d_texture) {
5735  int size = max(cdata->_z_size, 1);
5736  while (n > 0 && size > 1) {
5737  size >>= 1;
5738  --n;
5739  }
5740  return size;
5741 
5742  } else {
5743  return cdata->_z_size;
5744  }
5745 }
5746 
5747 ////////////////////////////////////////////////////////////////////
5748 // Function: Texture::do_clear_simple_ram_image
5749 // Access: Protected
5750 // Description:
5751 ////////////////////////////////////////////////////////////////////
5752 void Texture::
5753 do_clear_simple_ram_image(CData *cdata) {
5754  cdata->_simple_x_size = 0;
5755  cdata->_simple_y_size = 0;
5756  cdata->_simple_ram_image._image.clear();
5757  cdata->_simple_ram_image._page_size = 0;
5758  cdata->_simple_image_date_generated = 0;
5759 
5760  // We allow this exception: we update the _simple_image_modified
5761  // here, since no one really cares much about that anyway, and it's
5762  // convenient to do it here.
5763  cdata->inc_simple_image_modified();
5764 }
5765 
5766 ////////////////////////////////////////////////////////////////////
5767 // Function: Texture::do_clear_ram_mipmap_images
5768 // Access: Protected
5769 // Description:
5770 ////////////////////////////////////////////////////////////////////
5771 void Texture::
5772 do_clear_ram_mipmap_images(CData *cdata) {
5773  if (!cdata->_ram_images.empty()) {
5774  cdata->_ram_images.erase(cdata->_ram_images.begin() + 1, cdata->_ram_images.end());
5775  }
5776 }
5777 
5778 ////////////////////////////////////////////////////////////////////
5779 // Function: Texture::do_generate_ram_mipmap_images
5780 // Access: Protected
5781 // Description:
5782 ////////////////////////////////////////////////////////////////////
5783 void Texture::
5784 do_generate_ram_mipmap_images(CData *cdata) {
5785  nassertv(do_has_ram_image(cdata));
5786 
5787  if (do_get_expected_num_mipmap_levels(cdata) == 1) {
5788  // Don't bother.
5789  return;
5790  }
5791 
5792  RamImage orig_compressed_image;
5793  CompressionMode orig_compression_mode = CM_off;
5794 
5795  if (cdata->_ram_image_compression != CM_off) {
5796  // The RAM image is compressed. This means we need to uncompress
5797  // it in order to generate mipmap images. Save the original
5798  // first, to avoid lossy recompression.
5799  orig_compressed_image = cdata->_ram_images[0];
5800  orig_compression_mode = cdata->_ram_image_compression;
5801 
5802  // Now try to get the uncompressed source image.
5803  do_get_uncompressed_ram_image(cdata);
5804 
5805  nassertv(cdata->_ram_image_compression == CM_off);
5806  }
5807 
5808  do_clear_ram_mipmap_images(cdata);
5809 
5810  if (gobj_cat.is_debug()) {
5811  gobj_cat.debug()
5812  << "Generating mipmap levels for " << *this << "\n";
5813  }
5814 
5815  if (cdata->_texture_type == Texture::TT_3d_texture && cdata->_z_size != 1) {
5816  // Eek, a 3-D texture.
5817  int x_size = cdata->_x_size;
5818  int y_size = cdata->_y_size;
5819  int z_size = cdata->_z_size;
5820  int n = 0;
5821  while (x_size > 1 || y_size > 1 || z_size > 1) {
5822  cdata->_ram_images.push_back(RamImage());
5823  do_filter_3d_mipmap_level(cdata, cdata->_ram_images[n + 1], cdata->_ram_images[n],
5824  x_size, y_size, z_size);
5825  x_size = max(x_size >> 1, 1);
5826  y_size = max(y_size >> 1, 1);
5827  z_size = max(z_size >> 1, 1);
5828  ++n;
5829  }
5830 
5831  } else {
5832  // A 1-D, 2-D, or cube map texture.
5833  int x_size = cdata->_x_size;
5834  int y_size = cdata->_y_size;
5835  int n = 0;
5836  while (x_size > 1 || y_size > 1) {
5837  cdata->_ram_images.push_back(RamImage());
5838  do_filter_2d_mipmap_pages(cdata, cdata->_ram_images[n + 1], cdata->_ram_images[n],
5839  x_size, y_size);
5840  x_size = max(x_size >> 1, 1);
5841  y_size = max(y_size >> 1, 1);
5842  ++n;
5843  }
5844  }
5845 
5846  if (orig_compression_mode != CM_off) {
5847  // Now attempt to recompress the mipmap images according to the
5848  // original compression mode. We don't need to bother compressing
5849  // the first image (it was already compressed, after all), so
5850  // temporarily remove it from the top of the mipmap stack, and
5851  // compress all of the rest of them instead.
5852  nassertv(cdata->_ram_images.size() > 1);
5853  int l0_x_size = cdata->_x_size;
5854  int l0_y_size = cdata->_y_size;
5855  int l0_z_size = cdata->_z_size;
5856  cdata->_x_size = do_get_expected_mipmap_x_size(cdata, 1);
5857  cdata->_y_size = do_get_expected_mipmap_y_size(cdata, 1);
5858  cdata->_z_size = do_get_expected_mipmap_z_size(cdata, 1);
5859  RamImage uncompressed_image = cdata->_ram_images[0];
5860  cdata->_ram_images.erase(cdata->_ram_images.begin());
5861 
5862  bool success = do_compress_ram_image(cdata, orig_compression_mode, QL_default, NULL);
5863  // Now restore the toplevel image.
5864  if (success) {
5865  cdata->_ram_images.insert(cdata->_ram_images.begin(), orig_compressed_image);
5866  } else {
5867  cdata->_ram_images.insert(cdata->_ram_images.begin(), uncompressed_image);
5868  }
5869  cdata->_x_size = l0_x_size;
5870  cdata->_y_size = l0_y_size;
5871  cdata->_z_size = l0_z_size;
5872  }
5873 }
5874 
5875 ////////////////////////////////////////////////////////////////////
5876 // Function: Texture::do_set_pad_size
5877 // Access: Protected
5878 // Description:
5879 ////////////////////////////////////////////////////////////////////
5880 void Texture::
5881 do_set_pad_size(CData *cdata, int x, int y, int z) {
5882  if (x > cdata->_x_size) {
5883  x = cdata->_x_size;
5884  }
5885  if (y > cdata->_y_size) {
5886  y = cdata->_y_size;
5887  }
5888  if (z > cdata->_z_size) {
5889  z = cdata->_z_size;
5890  }
5891 
5892  cdata->_pad_x_size = x;
5893  cdata->_pad_y_size = y;
5894  cdata->_pad_z_size = z;
5895 }
5896 
5897 ////////////////////////////////////////////////////////////////////
5898 // Function: Texture::do_can_reload
5899 // Access: Protected, Virtual
5900 // Description: Returns true if we can safely call
5901 // do_reload_ram_image() in order to make the image
5902 // available, or false if we shouldn't do this (because
5903 // we know from a priori knowledge that it wouldn't work
5904 // anyway).
5905 ////////////////////////////////////////////////////////////////////
5906 bool Texture::
5907 do_can_reload(const CData *cdata) const {
5908  return (cdata->_loaded_from_image && !cdata->_fullpath.empty());
5909 }
5910 
5911 ////////////////////////////////////////////////////////////////////
5912 // Function: Texture::do_reload
5913 // Access: Protected
5914 // Description:
5915 ////////////////////////////////////////////////////////////////////
5916 bool Texture::
5917 do_reload(CData *cdata) {
5918  if (do_can_reload(cdata)) {
5919  do_clear_ram_image(cdata);
5920  do_reload_ram_image(cdata, true);
5921  if (do_has_ram_image(cdata)) {
5922  // An explicit call to reload() should increment image_modified.
5923  cdata->inc_image_modified();
5924  return true;
5925  }
5926  return false;
5927  }
5928 
5929  // We don't have a filename to load from.
5930  return false;
5931 }
5932 
5933 ////////////////////////////////////////////////////////////////////
5934 // Function: Texture::do_has_bam_rawdata
5935 // Access: Protected, Virtual
5936 // Description: Returns true if there is a rawdata image that we have
5937 // available to write to the bam stream. For a normal
5938 // Texture, this is the same thing as
5939 // do_has_ram_image(), but a movie texture might define
5940 // it differently.
5941 ////////////////////////////////////////////////////////////////////
5942 bool Texture::
5943 do_has_bam_rawdata(const CData *cdata) const {
5944  return do_has_ram_image(cdata);
5945 }
5946 
5947 ////////////////////////////////////////////////////////////////////
5948 // Function: Texture::do_get_bam_rawdata
5949 // Access: Protected, Virtual
5950 // Description: If do_has_bam_rawdata() returned false, this attempts
5951 // to reload the rawdata image if possible.
5952 ////////////////////////////////////////////////////////////////////
5953 void Texture::
5954 do_get_bam_rawdata(CData *cdata) {
5955  do_get_ram_image(cdata);
5956 }
5957 
5958 ////////////////////////////////////////////////////////////////////
5959 // Function: Texture::convert_from_pnmimage
5960 // Access: Private, Static
5961 // Description: Internal method to convert pixel data from the
5962 // indicated PNMImage into the given ram_image.
5963 ////////////////////////////////////////////////////////////////////
5964 void Texture::
5965 convert_from_pnmimage(PTA_uchar &image, size_t page_size,
5966  int row_stride, int x, int y, int z,
5967  const PNMImage &pnmimage, int num_components,
5968  int component_width) {
5969  int x_size = pnmimage.get_x_size();
5970  int y_size = pnmimage.get_y_size();
5971  xelval maxval = pnmimage.get_maxval();
5972  int pixel_size = num_components * component_width;
5973 
5974  int row_skip = 0;
5975  if (row_stride == 0) {
5976  row_stride = x_size;
5977  } else {
5978  row_skip = (row_stride - x_size) * pixel_size;
5979  nassertv(row_skip >= 0);
5980  }
5981 
5982  bool is_grayscale = (num_components == 1 || num_components == 2);
5983  bool has_alpha = (num_components == 2 || num_components == 4);
5984  bool img_has_alpha = pnmimage.has_alpha();
5985 
5986  int idx = page_size * z;
5987  nassertv(idx + page_size <= image.size());
5988  unsigned char *p = &image[idx];
5989 
5990  if (x != 0 || y != 0) {
5991  p += (row_stride * y + x) * pixel_size;
5992  }
5993 
5994  if (maxval == 255 && component_width == 1) {
5995  // Most common case: one byte per pixel, and the source image
5996  // shows a maxval of 255. No scaling is necessary.
5997  for (int j = y_size-1; j >= 0; j--) {
5998  for (int i = 0; i < x_size; i++) {
5999  if (is_grayscale) {
6000  store_unscaled_byte(p, pnmimage.get_gray_val(i, j));
6001  } else {
6002  store_unscaled_byte(p, pnmimage.get_blue_val(i, j));
6003  store_unscaled_byte(p, pnmimage.get_green_val(i, j));
6004  store_unscaled_byte(p, pnmimage.get_red_val(i, j));
6005  }
6006  if (has_alpha) {
6007  if (img_has_alpha) {
6008  store_unscaled_byte(p, pnmimage.get_alpha_val(i, j));
6009  } else {
6010  store_unscaled_byte(p, 255);
6011  }
6012  }
6013  }
6014  p += row_skip;
6015  }
6016 
6017  } else if (maxval == 65535 && component_width == 2) {
6018  // Another possible case: two bytes per pixel, and the source
6019  // image shows a maxval of 65535. Again, no scaling is necessary.
6020  for (int j = y_size-1; j >= 0; j--) {
6021  for (int i = 0; i < x_size; i++) {
6022  if (is_grayscale) {
6023  store_unscaled_short(p, pnmimage.get_gray_val(i, j));
6024  } else {
6025  store_unscaled_short(p, pnmimage.get_blue_val(i, j));
6026  store_unscaled_short(p, pnmimage.get_green_val(i, j));
6027  store_unscaled_short(p, pnmimage.get_red_val(i, j));
6028  }
6029  if (has_alpha) {
6030  if (img_has_alpha) {
6031  store_unscaled_short(p, pnmimage.get_alpha_val(i, j));
6032  } else {
6033  store_unscaled_short(p, 65535);
6034  }
6035  }
6036  }
6037  p += row_skip;
6038  }
6039 
6040  } else if (component_width == 1) {
6041  // A less common case: one byte per pixel, but the maxval is
6042  // something other than 255. In this case, we should scale the
6043  // pixel values up to the appropriate amount.
6044  double scale = 255.0 / (double)maxval;
6045 
6046  for (int j = y_size-1; j >= 0; j--) {
6047  for (int i = 0; i < x_size; i++) {
6048  if (is_grayscale) {
6049  store_scaled_byte(p, pnmimage.get_gray_val(i, j), scale);
6050  } else {
6051  store_scaled_byte(p, pnmimage.get_blue_val(i, j), scale);
6052  store_scaled_byte(p, pnmimage.get_green_val(i, j), scale);
6053  store_scaled_byte(p, pnmimage.get_red_val(i, j), scale);
6054  }
6055  if (has_alpha) {
6056  if (img_has_alpha) {
6057  store_scaled_byte(p, pnmimage.get_alpha_val(i, j), scale);
6058  } else {
6059  store_unscaled_byte(p, 255);
6060  }
6061  }
6062  }
6063  p += row_skip;
6064  }
6065 
6066  } else { // component_width == 2
6067  // Another uncommon case: two bytes per pixel, and the maxval is
6068  // something other than 65535. Again, we must scale the pixel
6069  // values.
6070  double scale = 65535.0 / (double)maxval;
6071 
6072  for (int j = y_size-1; j >= 0; j--) {
6073  for (int i = 0; i < x_size; i++) {
6074  if (is_grayscale) {
6075  store_scaled_short(p, pnmimage.get_gray_val(i, j), scale);
6076  } else {
6077  store_scaled_short(p, pnmimage.get_blue_val(i, j), scale);
6078  store_scaled_short(p, pnmimage.get_green_val(i, j), scale);
6079  store_scaled_short(p, pnmimage.get_red_val(i, j), scale);
6080  }
6081  if (has_alpha) {
6082  if (img_has_alpha) {
6083  store_scaled_short(p, pnmimage.get_alpha_val(i, j), 1.0);
6084  } else {
6085  store_unscaled_short(p, 65535);
6086  }
6087  }
6088  }
6089  p += row_skip;
6090  }
6091  }
6092 }
6093 
6094 ////////////////////////////////////////////////////////////////////
6095 // Function: Texture::convert_from_pfm
6096 // Access: Private, Static
6097 // Description: Internal method to convert pixel data from the
6098 // indicated PfmFile into the given ram_image.
6099 ////////////////////////////////////////////////////////////////////
6100 void Texture::
6101 convert_from_pfm(PTA_uchar &image, size_t page_size, int z,
6102  const PfmFile &pfm, int num_components, int component_width) {
6103  nassertv(component_width == 4); // Currently only PN_float32 is expected.
6104  int x_size = pfm.get_x_size();
6105  int y_size = pfm.get_y_size();
6106 
6107  int idx = page_size * z;
6108  nassertv(idx + page_size <= image.size());
6109  PN_float32 *p = (PN_float32 *)&image[idx];
6110 
6111  switch (num_components) {
6112  case 1:
6113  {
6114  for (int j = y_size-1; j >= 0; j--) {
6115  for (int i = 0; i < x_size; i++) {
6116  p[0] = pfm.get_channel(i, j, 0);
6117  ++p;
6118  }
6119  }
6120  }
6121  break;
6122 
6123  case 2:
6124  {
6125  for (int j = y_size-1; j >= 0; j--) {
6126  for (int i = 0; i < x_size; i++) {
6127  p[0] = pfm.get_channel(i, j, 0);
6128  p[1] = pfm.get_channel(i, j, 1);
6129  p += 2;
6130  }
6131  }
6132  }
6133  break;
6134 
6135  case 3:
6136  {
6137  // RGB -> BGR
6138  for (int j = y_size-1; j >= 0; j--) {
6139  for (int i = 0; i < x_size; i++) {
6140  p[0] = pfm.get_channel(i, j, 2);
6141  p[1] = pfm.get_channel(i, j, 1);
6142  p[2] = pfm.get_channel(i, j, 0);
6143  p += 3;
6144  }
6145  }
6146  }
6147  break;
6148 
6149  case 4:
6150  {
6151  // RGBA -> BGRA
6152  for (int j = y_size-1; j >= 0; j--) {
6153  for (int i = 0; i < x_size; i++) {
6154  p[0] = pfm.get_channel(i, j, 2);
6155  p[1] = pfm.get_channel(i, j, 1);
6156  p[2] = pfm.get_channel(i, j, 0);
6157  p[3] = pfm.get_channel(i, j, 3);
6158  p += 4;
6159  }
6160  }
6161  }
6162  break;
6163 
6164  default:
6165  nassertv(false);
6166  }
6167 
6168  nassertv((unsigned char *)p == &image[idx] + page_size);
6169 }
6170 
6171 ////////////////////////////////////////////////////////////////////
6172 // Function: Texture::convert_to_pnmimage
6173 // Access: Private, Static
6174 // Description: Internal method to convert pixel data to the
6175 // indicated PNMImage from the given ram_image.
6176 ////////////////////////////////////////////////////////////////////
6177 bool Texture::
6178 convert_to_pnmimage(PNMImage &pnmimage, int x_size, int y_size,
6179  int num_components, int component_width,
6180  CPTA_uchar image, size_t page_size, int z) {
6181  xelval maxval = 0xff;
6182  if (component_width > 1) {
6183  maxval = 0xffff;
6184  }
6185  pnmimage.clear(x_size, y_size, num_components, maxval);
6186  bool has_alpha = pnmimage.has_alpha();
6187  bool is_grayscale = pnmimage.is_grayscale();
6188 
6189  int idx = page_size * z;
6190  nassertr(idx + page_size <= image.size(), false);
6191  const unsigned char *p = &image[idx];
6192 
6193  if (component_width == 1) {
6194  for (int j = y_size-1; j >= 0; j--) {
6195  for (int i = 0; i < x_size; i++) {
6196  if (is_grayscale) {
6197  pnmimage.set_gray(i, j, get_unsigned_byte(p));
6198  } else {
6199  pnmimage.set_blue(i, j, get_unsigned_byte(p));
6200  pnmimage.set_green(i, j, get_unsigned_byte(p));
6201  pnmimage.set_red(i, j, get_unsigned_byte(p));
6202  }
6203  if (has_alpha) {
6204  pnmimage.set_alpha(i, j, get_unsigned_byte(p));
6205  }
6206  }
6207  }
6208 
6209  } else if (component_width == 2) {
6210  for (int j = y_size-1; j >= 0; j--) {
6211  for (int i = 0; i < x_size; i++) {
6212  if (is_grayscale) {
6213  pnmimage.set_gray(i, j, get_unsigned_short(p));
6214  } else {
6215  pnmimage.set_blue(i, j, get_unsigned_short(p));
6216  pnmimage.set_green(i, j, get_unsigned_short(p));
6217  pnmimage.set_red(i, j, get_unsigned_short(p));
6218  }
6219  if (has_alpha) {
6220  pnmimage.set_alpha(i, j, get_unsigned_short(p));
6221  }
6222  }
6223  }
6224 
6225  } else {
6226  return false;
6227  }
6228 
6229  nassertr(p == &image[idx] + page_size, false);
6230  return true;
6231 }
6232 
6233 ////////////////////////////////////////////////////////////////////
6234 // Function: Texture::convert_to_pfm
6235 // Access: Private, Static
6236 // Description: Internal method to convert pixel data to the
6237 // indicated PfmFile from the given ram_image.
6238 ////////////////////////////////////////////////////////////////////
6239 bool Texture::
6240 convert_to_pfm(PfmFile &pfm, int x_size, int y_size,
6241  int num_components, int component_width,
6242  CPTA_uchar image, size_t page_size, int z) {
6243  nassertr(component_width == 4, false); // Currently only PN_float32 is expected.
6244  pfm.clear(x_size, y_size, num_components);
6245 
6246  int idx = page_size * z;
6247  nassertr(idx + page_size <= image.size(), false);
6248  const PN_float32 *p = (const PN_float32 *)&image[idx];
6249 
6250  switch (num_components) {
6251  case 1:
6252  for (int j = y_size-1; j >= 0; j--) {
6253  for (int i = 0; i < x_size; i++) {
6254  pfm.set_channel(i, j, 0, p[0]);
6255  ++p;
6256  }
6257  }
6258  break;
6259 
6260  case 2:
6261  for (int j = y_size-1; j >= 0; j--) {
6262  for (int i = 0; i < x_size; i++) {
6263  pfm.set_channel(i, j, 0, p[0]);
6264  pfm.set_channel(i, j, 1, p[1]);
6265  p += 2;
6266  }
6267  }
6268  break;
6269 
6270  case 3:
6271  // BGR -> RGB
6272  for (int j = y_size-1; j >= 0; j--) {
6273  for (int i = 0; i < x_size; i++) {
6274  pfm.set_channel(i, j, 2, p[0]);
6275  pfm.set_channel(i, j, 1, p[1]);
6276  pfm.set_channel(i, j, 0, p[2]);
6277  p += 3;
6278  }
6279  }
6280  break;
6281 
6282  case 4:
6283  // BGRA -> RGBA
6284  for (int j = y_size-1; j >= 0; j--) {
6285  for (int i = 0; i < x_size; i++) {
6286  pfm.set_channel(i, j, 2, p[0]);
6287  pfm.set_channel(i, j, 1, p[1]);
6288  pfm.set_channel(i, j, 0, p[2]);
6289  pfm.set_channel(i, j, 3, p[3]);
6290  p += 4;
6291  }
6292  }
6293  break;
6294 
6295  default:
6296  nassertr(false, false);
6297  }
6298 
6299  nassertr((unsigned char *)p == &image[idx] + page_size, false);
6300  return true;
6301 }
6302 
6303 ////////////////////////////////////////////////////////////////////
6304 // Function: Texture::read_dds_level_bgr8
6305 // Access: Private, Static
6306 // Description: Called by read_dds for a DDS file in BGR8 format.
6307 ////////////////////////////////////////////////////////////////////
6308 PTA_uchar Texture::
6309 read_dds_level_bgr8(Texture *tex, CData *cdata, const DDSHeader &header, int n, istream &in) {
6310  // This is in order B, G, R.
6311  int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
6312  int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
6313 
6314  size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
6315  size_t row_bytes = x_size * 3;
6316  PTA_uchar image = PTA_uchar::empty_array(size);
6317  for (int y = y_size - 1; y >= 0; --y) {
6318  unsigned char *p = image.p() + y * row_bytes;
6319  nassertr(p + row_bytes <= image.p() + size, PTA_uchar());
6320  in.read((char *)p, row_bytes);
6321  }
6322 
6323  return image;
6324 }
6325 
6326 ////////////////////////////////////////////////////////////////////
6327 // Function: Texture::read_dds_level_rgb8
6328 // Access: Private, Static
6329 // Description: Called by read_dds for a DDS file in RGB8 format.
6330 ////////////////////////////////////////////////////////////////////
6331 PTA_uchar Texture::
6332 read_dds_level_rgb8(Texture *tex, CData *cdata, const DDSHeader &header, int n, istream &in) {
6333  // This is in order R, G, B.
6334  int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
6335  int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
6336 
6337  size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
6338  size_t row_bytes = x_size * 3;
6339  PTA_uchar image = PTA_uchar::empty_array(size);
6340  for (int y = y_size - 1; y >= 0; --y) {
6341  unsigned char *p = image.p() + y * row_bytes;
6342  nassertr(p + row_bytes <= image.p() + size, PTA_uchar());
6343  in.read((char *)p, row_bytes);
6344 
6345  // Now reverse the r, g, b triples.
6346  for (int x = 0; x < x_size; ++x) {
6347  unsigned char r = p[0];
6348  p[0] = p[2];
6349  p[2] = r;
6350  p += 3;
6351  }
6352  nassertr(p <= image.p() + size, PTA_uchar());
6353  }
6354 
6355  return image;
6356 }
6357 
6358 ////////////////////////////////////////////////////////////////////
6359 // Function: Texture::read_dds_level_abgr8
6360 // Access: Private, Static
6361 // Description: Called by read_dds for a DDS file in ABGR8 format.
6362 ////////////////////////////////////////////////////////////////////
6363 PTA_uchar Texture::
6364 read_dds_level_abgr8(Texture *tex, CData *cdata, const DDSHeader &header, int n, istream &in) {
6365  // This is laid out in order R, G, B, A.
6366  int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
6367  int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
6368 
6369  size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
6370  size_t row_bytes = x_size * 4;
6371  PTA_uchar image = PTA_uchar::empty_array(size);
6372  for (int y = y_size - 1; y >= 0; --y) {
6373  unsigned char *p = image.p() + y * row_bytes;
6374  in.read((char *)p, row_bytes);
6375 
6376  PN_uint32 *pw = (PN_uint32 *)p;
6377  for (int x = 0; x < x_size; ++x) {
6378  PN_uint32 w = *pw;
6379 #ifdef WORDS_BIGENDIAN
6380  // bigendian: convert R, G, B, A to B, G, R, A.
6381  w = ((w & 0xff00) << 16) | ((w & 0xff000000U) >> 16) | (w & 0xff00ff);
6382 #else
6383  // littendian: convert A, B, G, R to to A, R, G, B.
6384  w = ((w & 0xff) << 16) | ((w & 0xff0000) >> 16) | (w & 0xff00ff00U);
6385 #endif
6386  *pw = w;
6387  ++pw;
6388  }
6389  nassertr((unsigned char *)pw <= image.p() + size, PTA_uchar());
6390  }
6391 
6392  return image;
6393 }
6394 
6395 ////////////////////////////////////////////////////////////////////
6396 // Function: Texture::read_dds_level_rgba8
6397 // Access: Private, Static
6398 // Description: Called by read_dds for a DDS file in RGBA8 format.
6399 ////////////////////////////////////////////////////////////////////
6400 PTA_uchar Texture::
6401 read_dds_level_rgba8(Texture *tex, CData *cdata, const DDSHeader &header, int n, istream &in) {
6402  // This is actually laid out in order B, G, R, A.
6403  int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
6404  int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
6405 
6406  size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
6407  size_t row_bytes = x_size * 4;
6408  PTA_uchar image = PTA_uchar::empty_array(size);
6409  for (int y = y_size - 1; y >= 0; --y) {
6410  unsigned char *p = image.p() + y * row_bytes;
6411  nassertr(p + row_bytes <= image.p() + size, PTA_uchar());
6412  in.read((char *)p, row_bytes);
6413  }
6414 
6415  return image;
6416 }
6417 
6418 ////////////////////////////////////////////////////////////////////
6419 // Function: Texture::read_dds_level_generic_uncompressed
6420 // Access: Private, Static
6421 // Description: Called by read_dds for a DDS file whose format isn't
6422 // one we've specifically optimized.
6423 ////////////////////////////////////////////////////////////////////
6424 PTA_uchar Texture::
6425 read_dds_level_generic_uncompressed(Texture *tex, CData *cdata, const DDSHeader &header,
6426  int n, istream &in) {
6427  int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
6428  int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
6429 
6430  int pitch = (x_size * header.pf.rgb_bitcount) / 8;
6431 
6432  // MS says the pitch can be supplied in the header file and must be
6433  // DWORD aligned, but this appears to apply to level 0 mipmaps only
6434  // (where it almost always will be anyway). Other mipmap levels
6435  // seem to be tightly packed, but there isn't a separate pitch for
6436  // each mipmap level. Weird.
6437  if (n == 0) {
6438  pitch = ((pitch + 3) / 4) * 4;
6439  if (header.dds_flags & DDSD_PITCH) {
6440  pitch = header.pitch;
6441  }
6442  }
6443 
6444  int bpp = header.pf.rgb_bitcount / 8;
6445  int skip_bytes = pitch - (bpp * x_size);
6446  nassertr(skip_bytes >= 0, PTA_uchar());
6447 
6448  unsigned int r_mask = header.pf.r_mask;
6449  unsigned int g_mask = header.pf.g_mask;
6450  unsigned int b_mask = header.pf.b_mask;
6451  unsigned int a_mask = header.pf.a_mask;
6452 
6453  // Determine the number of bits to shift each mask to the right so
6454  // that the lowest on bit is at bit 0.
6455  int r_shift = get_lowest_on_bit(r_mask);
6456  int g_shift = get_lowest_on_bit(g_mask);
6457  int b_shift = get_lowest_on_bit(b_mask);
6458  int a_shift = get_lowest_on_bit(a_mask);
6459 
6460  // Then determine the scale factor required to raise the highest
6461  // color value to 0xff000000.
6462  unsigned int r_scale = 0;
6463  if (r_mask != 0) {
6464  r_scale = 0xff000000 / (r_mask >> r_shift);
6465  }
6466  unsigned int g_scale = 0;
6467  if (g_mask != 0) {
6468  g_scale = 0xff000000 / (g_mask >> g_shift);
6469  }
6470  unsigned int b_scale = 0;
6471  if (b_mask != 0) {
6472  b_scale = 0xff000000 / (b_mask >> b_shift);
6473  }
6474  unsigned int a_scale = 0;
6475  if (a_mask != 0) {
6476  a_scale = 0xff000000 / (a_mask >> a_shift);
6477  }
6478 
6479  bool add_alpha = has_alpha(cdata->_format);
6480 
6481  size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
6482  size_t row_bytes = x_size * cdata->_num_components;
6483  PTA_uchar image = PTA_uchar::empty_array(size);
6484  for (int y = y_size - 1; y >= 0; --y) {
6485  unsigned char *p = image.p() + y * row_bytes;
6486  for (int x = 0; x < x_size; ++x) {
6487 
6488  // Read a little-endian numeric value of bpp bytes.
6489  unsigned int pixel = 0;
6490  int shift = 0;
6491  for (int bi = 0; bi < bpp; ++bi) {
6492  unsigned int ch = (unsigned char)in.get();
6493  pixel |= (ch << shift);
6494  shift += 8;
6495  }
6496 
6497  // Then break apart that value into its R, G, B, and maybe A
6498  // components.
6499  unsigned int r = (((pixel & r_mask) >> r_shift) * r_scale) >> 24;
6500  unsigned int g = (((pixel & g_mask) >> g_shift) * g_scale) >> 24;
6501  unsigned int b = (((pixel & b_mask) >> b_shift) * b_scale) >> 24;
6502 
6503  // Store the components in the Texture's image data.
6504  store_unscaled_byte(p, b);
6505  store_unscaled_byte(p, g);
6506  store_unscaled_byte(p, r);
6507  if (add_alpha) {
6508  unsigned int a = (((pixel & a_mask) >> a_shift) * a_scale) >> 24;
6509  store_unscaled_byte(p, a);
6510  }
6511  }
6512  nassertr(p <= image.p() + size, PTA_uchar());
6513  for (int bi = 0; bi < skip_bytes; ++bi) {
6514  in.get();
6515  }
6516  }
6517 
6518  return image;
6519 }
6520 
6521 ////////////////////////////////////////////////////////////////////
6522 // Function: Texture::read_dds_level_luminance_uncompressed
6523 // Access: Private, Static
6524 // Description: Called by read_dds for a DDS file in uncompressed
6525 // luminance or luminance-alpha format.
6526 ////////////////////////////////////////////////////////////////////
6527 PTA_uchar Texture::
6528 read_dds_level_luminance_uncompressed(Texture *tex, CData *cdata, const DDSHeader &header,
6529  int n, istream &in) {
6530  int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
6531  int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
6532 
6533  int pitch = (x_size * header.pf.rgb_bitcount) / 8;
6534 
6535  // MS says the pitch can be supplied in the header file and must be
6536  // DWORD aligned, but this appears to apply to level 0 mipmaps only
6537  // (where it almost always will be anyway). Other mipmap levels
6538  // seem to be tightly packed, but there isn't a separate pitch for
6539  // each mipmap level. Weird.
6540  if (n == 0) {
6541  pitch = ((pitch + 3) / 4) * 4;
6542  if (header.dds_flags & DDSD_PITCH) {
6543  pitch = header.pitch;
6544  }
6545  }
6546 
6547  int bpp = header.pf.rgb_bitcount / 8;
6548  int skip_bytes = pitch - (bpp * x_size);
6549  nassertr(skip_bytes >= 0, PTA_uchar());
6550 
6551  unsigned int r_mask = header.pf.r_mask;
6552  unsigned int a_mask = header.pf.a_mask;
6553 
6554  // Determine the number of bits to shift each mask to the right so
6555  // that the lowest on bit is at bit 0.
6556  int r_shift = get_lowest_on_bit(r_mask);
6557  int a_shift = get_lowest_on_bit(a_mask);
6558 
6559  // Then determine the scale factor required to raise the highest
6560  // color value to 0xff000000.
6561  unsigned int r_scale = 0;
6562  if (r_mask != 0) {
6563  r_scale = 0xff000000 / (r_mask >> r_shift);
6564  }
6565  unsigned int a_scale = 0;
6566  if (a_mask != 0) {
6567  a_scale = 0xff000000 / (a_mask >> a_shift);
6568  }
6569 
6570  bool add_alpha = has_alpha(cdata->_format);
6571 
6572  size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
6573  size_t row_bytes = x_size * cdata->_num_components;
6574  PTA_uchar image = PTA_uchar::empty_array(size);
6575  for (int y = y_size - 1; y >= 0; --y) {
6576  unsigned char *p = image.p() + y * row_bytes;
6577  for (int x = 0; x < x_size; ++x) {
6578 
6579  // Read a little-endian numeric value of bpp bytes.
6580  unsigned int pixel = 0;
6581  int shift = 0;
6582  for (int bi = 0; bi < bpp; ++bi) {
6583  unsigned int ch = (unsigned char)in.get();
6584  pixel |= (ch << shift);
6585  shift += 8;
6586  }
6587 
6588  unsigned int r = (((pixel & r_mask) >> r_shift) * r_scale) >> 24;
6589 
6590  // Store the components in the Texture's image data.
6591  store_unscaled_byte(p, r);
6592  if (add_alpha) {
6593  unsigned int a = (((pixel & a_mask) >> a_shift) * a_scale) >> 24;
6594  store_unscaled_byte(p, a);
6595  }
6596  }
6597  nassertr(p <= image.p() + size, PTA_uchar());
6598  for (int bi = 0; bi < skip_bytes; ++bi) {
6599  in.get();
6600  }
6601  }
6602 
6603  return image;
6604 }
6605 
6606 ////////////////////////////////////////////////////////////////////
6607 // Function: Texture::read_dds_level_dxt1
6608 // Access: Private, Static
6609 // Description: Called by read_dds for DXT1 file format.
6610 ////////////////////////////////////////////////////////////////////
6611 PTA_uchar Texture::
6612 read_dds_level_dxt1(Texture *tex, CData *cdata, const DDSHeader &header, int n, istream &in) {
6613  int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
6614  int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
6615 
6616  static const int div = 4;
6617  static const int block_bytes = 8;
6618 
6619  // The DXT1 image is divided into num_rows x num_cols blocks, where
6620  // each block represents 4x4 pixels.
6621  int num_cols = max(div, x_size) / div;
6622  int num_rows = max(div, y_size) / div;
6623  int row_length = num_cols * block_bytes;
6624  int linear_size = row_length * num_rows;
6625 
6626  if (n == 0) {
6627  if (header.dds_flags & DDSD_LINEARSIZE) {
6628  nassertr(linear_size == (int)header.pitch, PTA_uchar());
6629  }
6630  }
6631 
6632  PTA_uchar image = PTA_uchar::empty_array(linear_size);
6633 
6634  if (y_size >= 4) {
6635  // We have to flip the image as we read it, because of DirectX's
6636  // inverted sense of up. That means we (a) reverse the order of the
6637  // rows of blocks . . .
6638  for (int ri = num_rows - 1; ri >= 0; --ri) {
6639  unsigned char *p = image.p() + row_length * ri;
6640  in.read((char *)p, row_length);
6641 
6642  for (int ci = 0; ci < num_cols; ++ci) {
6643  // . . . and (b) within each block, we reverse the 4 individual
6644  // rows of 4 pixels.
6645  PN_uint32 *cells = (PN_uint32 *)p;
6646  PN_uint32 w = cells[1];
6647  w = ((w & 0xff) << 24) | ((w & 0xff00) << 8) | ((w & 0xff0000) >> 8) | ((w & 0xff000000U) >> 24);
6648  cells[1] = w;
6649 
6650  p += block_bytes;
6651  }
6652  }
6653 
6654  } else if (y_size >= 2) {
6655  // To invert a two-pixel high image, we just flip two rows within a cell.
6656  unsigned char *p = image.p();
6657  in.read((char *)p, row_length);
6658 
6659  for (int ci = 0; ci < num_cols; ++ci) {
6660  PN_uint32 *cells = (PN_uint32 *)p;
6661  PN_uint32 w = cells[1];
6662  w = ((w & 0xff) << 8) | ((w & 0xff00) >> 8);
6663  cells[1] = w;
6664 
6665  p += block_bytes;
6666  }
6667 
6668  } else if (y_size >= 1) {
6669  // No need to invert a one-pixel-high image.
6670  unsigned char *p = image.p();
6671  in.read((char *)p, row_length);
6672  }
6673 
6674  return image;
6675 }
6676 
6677 ////////////////////////////////////////////////////////////////////
6678 // Function: Texture::read_dds_level_dxt23
6679 // Access: Private, Static
6680 // Description: Called by read_dds for DXT2 or DXT3 file format.
6681 ////////////////////////////////////////////////////////////////////
6682 PTA_uchar Texture::
6683 read_dds_level_dxt23(Texture *tex, CData *cdata, const DDSHeader &header, int n, istream &in) {
6684  int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
6685  int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
6686 
6687  static const int div = 4;
6688  static const int block_bytes = 16;
6689 
6690  // The DXT3 image is divided into num_rows x num_cols blocks, where
6691  // each block represents 4x4 pixels. Unlike DXT1, each block
6692  // consists of two 8-byte chunks, representing the alpha and color
6693  // separately.
6694  int num_cols = max(div, x_size) / div;
6695  int num_rows = max(div, y_size) / div;
6696  int row_length = num_cols * block_bytes;
6697  int linear_size = row_length * num_rows;
6698 
6699  if (n == 0) {
6700  if (header.dds_flags & DDSD_LINEARSIZE) {
6701  nassertr(linear_size == (int)header.pitch, PTA_uchar());
6702  }
6703  }
6704 
6705  PTA_uchar image = PTA_uchar::empty_array(linear_size);
6706 
6707  if (y_size >= 4) {
6708  // We have to flip the image as we read it, because of DirectX's
6709  // inverted sense of up. That means we (a) reverse the order of the
6710  // rows of blocks . . .
6711  for (int ri = num_rows - 1; ri >= 0; --ri) {
6712  unsigned char *p = image.p() + row_length * ri;
6713  in.read((char *)p, row_length);
6714 
6715  for (int ci = 0; ci < num_cols; ++ci) {
6716  // . . . and (b) within each block, we reverse the 4 individual
6717  // rows of 4 pixels.
6718  PN_uint32 *cells = (PN_uint32 *)p;
6719 
6720  // Alpha. The block is four 16-bit words of pixel data.
6721  PN_uint32 w0 = cells[0];
6722  PN_uint32 w1 = cells[1];
6723  w0 = ((w0 & 0xffff) << 16) | ((w0 & 0xffff0000U) >> 16);
6724  w1 = ((w1 & 0xffff) << 16) | ((w1 & 0xffff0000U) >> 16);
6725  cells[0] = w1;
6726  cells[1] = w0;
6727 
6728  // Color. Only the second 32-bit dword of the color block
6729  // represents the pixel data.
6730  PN_uint32 w = cells[3];
6731  w = ((w & 0xff) << 24) | ((w & 0xff00) << 8) | ((w & 0xff0000) >> 8) | ((w & 0xff000000U) >> 24);
6732  cells[3] = w;
6733 
6734  p += block_bytes;
6735  }
6736  }
6737 
6738  } else if (y_size >= 2) {
6739  // To invert a two-pixel high image, we just flip two rows within a cell.
6740  unsigned char *p = image.p();
6741  in.read((char *)p, row_length);
6742 
6743  for (int ci = 0; ci < num_cols; ++ci) {
6744  PN_uint32 *cells = (PN_uint32 *)p;
6745 
6746  PN_uint32 w0 = cells[0];
6747  w0 = ((w0 & 0xffff) << 16) | ((w0 & 0xffff0000U) >> 16);
6748  cells[0] = w0;
6749 
6750  PN_uint32 w = cells[3];
6751  w = ((w & 0xff) << 8) | ((w & 0xff00) >> 8);
6752  cells[3] = w;
6753 
6754  p += block_bytes;
6755  }
6756 
6757  } else if (y_size >= 1) {
6758  // No need to invert a one-pixel-high image.
6759  unsigned char *p = image.p();
6760  in.read((char *)p, row_length);
6761  }
6762 
6763  return image;
6764 }
6765 
6766 ////////////////////////////////////////////////////////////////////
6767 // Function: Texture::read_dds_level_dxt45
6768 // Access: Private, Static
6769 // Description: Called by read_dds for DXT4 or DXT5 file format.
6770 ////////////////////////////////////////////////////////////////////
6771 PTA_uchar Texture::
6772 read_dds_level_dxt45(Texture *tex, CData *cdata, const DDSHeader &header, int n, istream &in) {
6773  int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
6774  int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
6775 
6776  static const int div = 4;
6777  static const int block_bytes = 16;
6778 
6779  // The DXT5 image is similar to DXT3, in that there each 4x4 block
6780  // of pixels consists of an alpha block and a color block, but the
6781  // layout of the alpha block is different.
6782  int num_cols = max(div, x_size) / div;
6783  int num_rows = max(div, y_size) / div;
6784  int row_length = num_cols * block_bytes;
6785  int linear_size = row_length * num_rows;
6786 
6787  if (n == 0) {
6788  if (header.dds_flags & DDSD_LINEARSIZE) {
6789  nassertr(linear_size == (int)header.pitch, PTA_uchar());
6790  }
6791  }
6792 
6793  PTA_uchar image = PTA_uchar::empty_array(linear_size);
6794 
6795  if (y_size >= 4) {
6796  // We have to flip the image as we read it, because of DirectX's
6797  // inverted sense of up. That means we (a) reverse the order of the
6798  // rows of blocks . . .
6799  for (int ri = num_rows - 1; ri >= 0; --ri) {
6800  unsigned char *p = image.p() + row_length * ri;
6801  in.read((char *)p, row_length);
6802 
6803  for (int ci = 0; ci < num_cols; ++ci) {
6804  // . . . and (b) within each block, we reverse the 4 individual
6805  // rows of 4 pixels.
6806  PN_uint32 *cells = (PN_uint32 *)p;
6807 
6808  // Alpha. The block is one 16-bit word of reference values,
6809  // followed by six words of pixel values, in 12-bit rows.
6810  // Tricky to invert.
6811  unsigned char p2 = p[2];
6812  unsigned char p3 = p[3];
6813  unsigned char p4 = p[4];
6814  unsigned char p5 = p[5];
6815  unsigned char p6 = p[6];
6816  unsigned char p7 = p[7];
6817 
6818  p[2] = ((p7 & 0xf) << 4) | ((p6 & 0xf0) >> 4);
6819  p[3] = ((p5 & 0xf) << 4) | ((p7 & 0xf0) >> 4);
6820  p[4] = ((p6 & 0xf) << 4) | ((p5 & 0xf0) >> 4);
6821  p[5] = ((p4 & 0xf) << 4) | ((p3 & 0xf0) >> 4);
6822  p[6] = ((p2 & 0xf) << 4) | ((p4 & 0xf0) >> 4);
6823  p[7] = ((p3 & 0xf) << 4) | ((p2 & 0xf0) >> 4);
6824 
6825  // Color. Only the second 32-bit dword of the color block
6826  // represents the pixel data.
6827  PN_uint32 w = cells[3];
6828  w = ((w & 0xff) << 24) | ((w & 0xff00) << 8) | ((w & 0xff0000) >> 8) | ((w & 0xff000000U) >> 24);
6829  cells[3] = w;
6830 
6831  p += block_bytes;
6832  }
6833  }
6834 
6835  } else if (y_size >= 2) {
6836  // To invert a two-pixel high image, we just flip two rows within a cell.
6837  unsigned char *p = image.p();
6838  in.read((char *)p, row_length);
6839 
6840  for (int ci = 0; ci < num_cols; ++ci) {
6841  PN_uint32 *cells = (PN_uint32 *)p;
6842 
6843  unsigned char p2 = p[2];
6844  unsigned char p3 = p[3];
6845  unsigned char p4 = p[4];
6846 
6847  p[2] = ((p4 & 0xf) << 4) | ((p3 & 0xf0) >> 4);
6848  p[3] = ((p2 & 0xf) << 4) | ((p4 & 0xf0) >> 4);
6849  p[4] = ((p3 & 0xf) << 4) | ((p2 & 0xf0) >> 4);
6850 
6851  PN_uint32 w0 = cells[0];
6852  w0 = ((w0 & 0xffff) << 16) | ((w0 & 0xffff0000U) >> 16);
6853  cells[0] = w0;
6854 
6855  PN_uint32 w = cells[3];
6856  w = ((w & 0xff) << 8) | ((w & 0xff00) >> 8);
6857  cells[3] = w;
6858 
6859  p += block_bytes;
6860  }
6861 
6862  } else if (y_size >= 1) {
6863  // No need to invert a one-pixel-high image.
6864  unsigned char *p = image.p();
6865  in.read((char *)p, row_length);
6866  }
6867 
6868  return image;
6869 }
6870 
6871 ////////////////////////////////////////////////////////////////////
6872 // Function: Texture::clear_prepared
6873 // Access: Private
6874 // Description: Removes the indicated PreparedGraphicsObjects table
6875 // from the Texture's table, without actually releasing
6876 // the texture. This is intended to be called only from
6877 // PreparedGraphicsObjects::release_texture(); it should
6878 // never be called by user code.
6879 ////////////////////////////////////////////////////////////////////
6880 void Texture::
6881 clear_prepared(int view, PreparedGraphicsObjects *prepared_objects) {
6882  PreparedViews::iterator pvi;
6883  pvi = _prepared_views.find(prepared_objects);
6884  if (pvi != _prepared_views.end()) {
6885  Contexts &contexts = (*pvi).second;
6886  Contexts::iterator ci;
6887  ci = contexts.find(view);
6888  if (ci != contexts.end()) {
6889  contexts.erase(ci);
6890  }
6891 
6892  if (contexts.empty()) {
6893  _prepared_views.erase(pvi);
6894  }
6895  }
6896 }
6897 
6898 ////////////////////////////////////////////////////////////////////
6899 // Function: Texture::consider_downgrade
6900 // Access: Private, Static
6901 // Description: Reduces the number of channels in the texture, if
6902 // necessary, according to num_channels.
6903 ////////////////////////////////////////////////////////////////////
6904 void Texture::
6905 consider_downgrade(PNMImage &pnmimage, int num_channels, const string &name) {
6906  if (num_channels != 0 && num_channels < pnmimage.get_num_channels()) {
6907  // One special case: we can't reduce from 3 to 2 components, since
6908  // that would require adding an alpha channel.
6909  if (pnmimage.get_num_channels() == 3 && num_channels == 2) {
6910  return;
6911  }
6912 
6913  gobj_cat.info()
6914  << "Downgrading " << name << " from "
6915  << pnmimage.get_num_channels() << " components to "
6916  << num_channels << ".\n";
6917  pnmimage.set_num_channels(num_channels);
6918  }
6919 }
6920 
6921 ////////////////////////////////////////////////////////////////////
6922 // Function: Texture::compare_images
6923 // Access: Private, Static
6924 // Description: Called by generate_simple_ram_image(), this compares
6925 // the two PNMImages pixel-by-pixel. If they're similar
6926 // enough (within a given threshold), returns true.
6927 ////////////////////////////////////////////////////////////////////
6928 bool Texture::
6929 compare_images(const PNMImage &a, const PNMImage &b) {
6930  nassertr(a.get_maxval() == 255 && b.get_maxval() == 255, false);
6931  nassertr(a.get_num_channels() == 4 && b.get_num_channels() == 4, false);
6932  nassertr(a.get_x_size() == b.get_x_size() &&
6933  a.get_y_size() == b.get_y_size(), false);
6934 
6935  int delta = 0;
6936  for (int yi = 0; yi < a.get_y_size(); ++yi) {
6937  for (int xi = 0; xi < a.get_x_size(); ++xi) {
6938  delta += abs(a.get_red_val(xi, yi) - b.get_red_val(xi, yi));
6939  delta += abs(a.get_green_val(xi, yi) - b.get_green_val(xi, yi));
6940  delta += abs(a.get_blue_val(xi, yi) - b.get_blue_val(xi, yi));
6941  delta += abs(a.get_alpha_val(xi, yi) - b.get_alpha_val(xi, yi));
6942  }
6943  }
6944 
6945  double average_delta = (double)delta / ((double)a.get_x_size() * (double)b.get_y_size() * (double)a.get_maxval());
6946  return (average_delta <= simple_image_threshold);
6947 }
6948 
6949 ////////////////////////////////////////////////////////////////////
6950 // Function: Texture::do_filter_2d_mipmap_pages
6951 // Access: Private
6952 // Description: Generates the next mipmap level from the previous
6953 // one. If there are multiple pages (e.g. a cube map),
6954 // generates each page independently.
6955 //
6956 // x_size and y_size are the size of the previous level.
6957 // They need not be a power of 2, or even a multiple of
6958 // 2.
6959 //
6960 // Assumes the lock is already held.
6961 ////////////////////////////////////////////////////////////////////
6962 void Texture::
6963 do_filter_2d_mipmap_pages(const CData *cdata,
6964  Texture::RamImage &to, const Texture::RamImage &from,
6965  int x_size, int y_size) const {
6966  Filter2DComponent *filter_component;
6967  Filter2DComponent *filter_alpha;
6968 
6969  if (is_srgb(cdata->_format)) {
6970  // We currently only support sRGB mipmap generation for
6971  // unsigned byte textures, due to our use of a lookup table.
6972  nassertv(cdata->_component_type == T_unsigned_byte);
6973 
6974  if (has_sse2_sRGB_encode()) {
6975  filter_component = &filter_2d_unsigned_byte_srgb_sse2;
6976  } else {
6977  filter_component = &filter_2d_unsigned_byte_srgb;
6978  }
6979 
6980  // Alpha is always linear.
6981  filter_alpha = &filter_2d_unsigned_byte;
6982 
6983  } else {
6984  switch (cdata->_component_type) {
6985  case T_unsigned_byte:
6986  filter_component = &filter_2d_unsigned_byte;
6987  break;
6988 
6989  case T_unsigned_short:
6990  filter_component = &filter_2d_unsigned_short;
6991  break;
6992 
6993  case T_float:
6994  filter_component = &filter_2d_float;
6995  break;
6996 
6997  default:
6998  gobj_cat.error()
6999  << "Unable to generate mipmaps for 2D texture with component type "
7000  << cdata->_component_type << "!";
7001  return;
7002  }
7003  filter_alpha = filter_component;
7004  }
7005 
7006  size_t pixel_size = cdata->_num_components * cdata->_component_width;
7007  size_t row_size = (size_t)x_size * pixel_size;
7008 
7009  int to_x_size = max(x_size >> 1, 1);
7010  int to_y_size = max(y_size >> 1, 1);
7011 
7012  size_t to_row_size = (size_t)to_x_size * pixel_size;
7013  to._page_size = (size_t)to_y_size * to_row_size;
7014  to._image = PTA_uchar::empty_array(to._page_size * cdata->_z_size * cdata->_num_views, get_class_type());
7015 
7016  bool alpha = has_alpha(cdata->_format);
7017  int num_color_components = cdata->_num_components;
7018  if (alpha) {
7019  --num_color_components;
7020  }
7021 
7022  int num_pages = cdata->_z_size * cdata->_num_views;
7023  for (int z = 0; z < num_pages; ++z) {
7024  // For each level.
7025  unsigned char *p = to._image.p() + z * to._page_size;
7026  nassertv(p <= to._image.p() + to._image.size() + to._page_size);
7027  const unsigned char *q = from._image.p() + z * from._page_size;
7028  nassertv(q <= from._image.p() + from._image.size() + from._page_size);
7029  if (y_size != 1) {
7030  int y;
7031  for (y = 0; y < y_size - 1; y += 2) {
7032  // For each row.
7033  nassertv(p == to._image.p() + z * to._page_size + (y / 2) * to_row_size);
7034  nassertv(q == from._image.p() + z * from._page_size + y * row_size);
7035  if (x_size != 1) {
7036  int x;
7037  for (x = 0; x < x_size - 1; x += 2) {
7038  // For each pixel.
7039  for (int c = 0; c < num_color_components; ++c) {
7040  // For each component.
7041  filter_component(p, q, pixel_size, row_size);
7042  }
7043  if (alpha) {
7044  filter_alpha(p, q, pixel_size, row_size);
7045  }
7046  q += pixel_size;
7047  }
7048  if (x < x_size) {
7049  // Skip the last odd pixel.
7050  q += pixel_size;
7051  }
7052  } else {
7053  // Just one pixel.
7054  for (int c = 0; c < num_color_components; ++c) {
7055  // For each component.
7056  filter_component(p, q, 0, row_size);
7057  }
7058  if (alpha) {
7059  filter_alpha(p, q, 0, row_size);
7060  }
7061  }
7062  q += row_size;
7064  }
7065  if (y < y_size) {
7066  // Skip the last odd row.
7067  q += row_size;
7068  }
7069  } else {
7070  // Just one row.
7071  if (x_size != 1) {
7072  int x;
7073  for (x = 0; x < x_size - 1; x += 2) {
7074  // For each pixel.
7075  for (int c = 0; c < num_color_components; ++c) {
7076  // For each component.
7077  filter_component(p, q, pixel_size, 0);
7078  }
7079  if (alpha) {
7080  filter_alpha(p, q, pixel_size, 0);
7081  }
7082  q += pixel_size;
7083  }
7084  if (x < x_size) {
7085  // Skip the last odd pixel.
7086  q += pixel_size;
7087  }
7088  } else {
7089  // Just one pixel.
7090  for (int c = 0; c < num_color_components; ++c) {
7091  // For each component.
7092  filter_component(p, q, 0, 0);
7093  }
7094  if (alpha) {
7095  filter_alpha(p, q, pixel_size, 0);
7096  }
7097  }
7098  }
7099 
7100  nassertv(p == to._image.p() + (z + 1) * to._page_size);
7101  nassertv(q == from._image.p() + (z + 1) * from._page_size);
7102  }
7103 }
7104 
7105 ////////////////////////////////////////////////////////////////////
7106 // Function: Texture::do_filter_3d_mipmap_level
7107 // Access: Private
7108 // Description: Generates the next mipmap level from the previous
7109 // one, treating all the pages of the level as a single
7110 // 3-d block of pixels.
7111 //
7112 // x_size, y_size, and z_size are the size of the
7113 // previous level. They need not be a power of 2, or
7114 // even a multiple of 2.
7115 //
7116 // Assumes the lock is already held.
7117 ////////////////////////////////////////////////////////////////////
7118 void Texture::
7119 do_filter_3d_mipmap_level(const CData *cdata,
7120  Texture::RamImage &to, const Texture::RamImage &from,
7121  int x_size, int y_size, int z_size) const {
7122  Filter3DComponent *filter_component;
7123  Filter3DComponent *filter_alpha;
7124 
7125  if (is_srgb(cdata->_format)) {
7126  // We currently only support sRGB mipmap generation for
7127  // unsigned byte textures, due to our use of a lookup table.
7128  nassertv(cdata->_component_type == T_unsigned_byte);
7129 
7130  if (has_sse2_sRGB_encode()) {
7131  filter_component = &filter_3d_unsigned_byte_srgb_sse2;
7132  } else {
7133  filter_component = &filter_3d_unsigned_byte_srgb;
7134  }
7135 
7136  // Alpha is always linear.
7137  filter_alpha = &filter_3d_unsigned_byte;
7138 
7139  } else {
7140  switch (cdata->_component_type) {
7141  case T_unsigned_byte:
7142  filter_component = &filter_3d_unsigned_byte;
7143  break;
7144 
7145  case T_unsigned_short:
7146  filter_component = &filter_3d_unsigned_short;
7147  break;
7148 
7149  case T_float:
7150  filter_component = &filter_3d_float;
7151  break;
7152 
7153  default:
7154  gobj_cat.error()
7155  << "Unable to generate mipmaps for 3D texture with component type "
7156  << cdata->_component_type << "!";
7157  return;
7158  }
7159  filter_alpha = filter_component;
7160  }
7161 
7162  size_t pixel_size = cdata->_num_components * cdata->_component_width;
7163  size_t row_size = (size_t)x_size * pixel_size;
7164  size_t page_size = (size_t)y_size * row_size;
7165  size_t view_size = (size_t)z_size * page_size;
7166 
7167  int to_x_size = max(x_size >> 1, 1);
7168  int to_y_size = max(y_size >> 1, 1);
7169  int to_z_size = max(z_size >> 1, 1);
7170 
7171  size_t to_row_size = (size_t)to_x_size * pixel_size;
7172  size_t to_page_size = (size_t)to_y_size * to_row_size;
7173  size_t to_view_size = (size_t)to_z_size * to_page_size;
7174  to._page_size = to_page_size;
7175  to._image = PTA_uchar::empty_array(to_page_size * to_z_size * cdata->_num_views, get_class_type());
7176 
7177  bool alpha = has_alpha(cdata->_format);
7178  int num_color_components = cdata->_num_components;
7179  if (alpha) {
7180  --num_color_components;
7181  }
7182 
7183  for (int view = 0; view < cdata->_num_views; ++view) {
7184  unsigned char *start_to = to._image.p() + view * to_view_size;
7185  const unsigned char *start_from = from._image.p() + view * view_size;
7186  nassertv(start_to + to_view_size <= to._image.p() + to._image.size());
7187  nassertv(start_from + view_size <= from._image.p() + from._image.size());
7188  unsigned char *p = start_to;
7189  const unsigned char *q = start_from;
7190  if (z_size != 1) {
7191  int z;
7192  for (z = 0; z < z_size - 1; z += 2) {
7193  // For each level.
7194  nassertv(p == start_to + (z / 2) * to_page_size);
7195  nassertv(q == start_from + z * page_size);
7196  if (y_size != 1) {
7197  int y;
7198  for (y = 0; y < y_size - 1; y += 2) {
7199  // For each row.
7200  nassertv(p == start_to + (z / 2) * to_page_size + (y / 2) * to_row_size);
7201  nassertv(q == start_from + z * page_size + y * row_size);
7202  if (x_size != 1) {
7203  int x;
7204  for (x = 0; x < x_size - 1; x += 2) {
7205  // For each pixel.
7206  for (int c = 0; c < num_color_components; ++c) {
7207  // For each component.
7208  filter_component(p, q, pixel_size, row_size, page_size);
7209  }
7210  if (alpha) {
7211  filter_alpha(p, q, pixel_size, row_size, page_size);
7212  }
7213  q += pixel_size;
7214  }
7215  if (x < x_size) {
7216  // Skip the last odd pixel.
7217  q += pixel_size;
7218  }
7219  } else {
7220  // Just one pixel.
7221  for (int c = 0; c < num_color_components; ++c) {
7222  // For each component.
7223  filter_component(p, q, 0, row_size, page_size);
7224  }
7225  if (alpha) {
7226  filter_alpha(p, q, 0, row_size, page_size);
7227  }
7228  }
7229  q += row_size;
7231  }
7232  if (y < y_size) {
7233  // Skip the last odd row.
7234  q += row_size;
7235  }
7236  } else {
7237  // Just one row.
7238  if (x_size != 1) {
7239  int x;
7240  for (x = 0; x < x_size - 1; x += 2) {
7241  // For each pixel.
7242  for (int c = 0; c < num_color_components; ++c) {
7243  // For each component.
7244  filter_component(p, q, pixel_size, 0, page_size);
7245  }
7246  if (alpha) {
7247  filter_alpha(p, q, pixel_size, 0, page_size);
7248  }
7249  q += pixel_size;
7250  }
7251  if (x < x_size) {
7252  // Skip the last odd pixel.
7253  q += pixel_size;
7254  }
7255  } else {
7256  // Just one pixel.
7257  for (int c = 0; c < num_color_components; ++c) {
7258  // For each component.
7259  filter_component(p, q, 0, 0, page_size);
7260  }
7261  if (alpha) {
7262  filter_alpha(p, q, 0, 0, page_size);
7263  }
7264  }
7265  }
7266  q += page_size;
7267  }
7268  if (z < z_size) {
7269  // Skip the last odd page.
7270  q += page_size;
7271  }
7272  } else {
7273  // Just one page.
7274  if (y_size != 1) {
7275  int y;
7276  for (y = 0; y < y_size - 1; y += 2) {
7277  // For each row.
7278  nassertv(p == start_to + (y / 2) * to_row_size);
7279  nassertv(q == start_from + y * row_size);
7280  if (x_size != 1) {
7281  int x;
7282  for (x = 0; x < x_size - 1; x += 2) {
7283  // For each pixel.
7284  for (int c = 0; c < num_color_components; ++c) {
7285  // For each component.
7286  filter_component(p, q, pixel_size, row_size, 0);
7287  }
7288  if (alpha) {
7289  filter_alpha(p, q, pixel_size, row_size, 0);
7290  }
7291  q += pixel_size;
7292  }
7293  if (x < x_size) {
7294  // Skip the last odd pixel.
7295  q += pixel_size;
7296  }
7297  } else {
7298  // Just one pixel.
7299  for (int c = 0; c < num_color_components; ++c) {
7300  // For each component.
7301  filter_component(p, q, 0, row_size, 0);
7302  }
7303  if (alpha) {
7304  filter_alpha(p, q, 0, row_size, 0);
7305  }
7306  }
7307  q += row_size;
7309  }
7310  if (y < y_size) {
7311  // Skip the last odd row.
7312  q += row_size;
7313  }
7314  } else {
7315  // Just one row.
7316  if (x_size != 1) {
7317  int x;
7318  for (x = 0; x < x_size - 1; x += 2) {
7319  // For each pixel.
7320  for (int c = 0; c < num_color_components; ++c) {
7321  // For each component.
7322  filter_component(p, q, pixel_size, 0, 0);
7323  }
7324  if (alpha) {
7325  filter_alpha(p, q, pixel_size, 0, 0);
7326  }
7327  q += pixel_size;
7328  }
7329  if (x < x_size) {
7330  // Skip the last odd pixel.
7331  q += pixel_size;
7332  }
7333  } else {
7334  // Just one pixel.
7335  for (int c = 0; c < num_color_components; ++c) {
7336  // For each component.
7337  filter_component(p, q, 0, 0, 0);
7338  }
7339  if (alpha) {
7340  filter_alpha(p, q, 0, 0, 0);
7341  }
7342  }
7343  }
7344  }
7345 
7346  nassertv(p == start_to + to_z_size * to_page_size);
7347  nassertv(q == start_from + z_size * page_size);
7348  }
7349 }
7350 
7351 ////////////////////////////////////////////////////////////////////
7352 // Function: Texture::filter_2d_unsigned_byte
7353 // Access: Public, Static
7354 // Description: Averages a 2x2 block of pixel components into a
7355 // single pixel component, for producing the next mipmap
7356 // level. Increments p and q to the next component.
7357 ////////////////////////////////////////////////////////////////////
7358 void Texture::
7359 filter_2d_unsigned_byte(unsigned char *&p, const unsigned char *&q,
7360  size_t pixel_size, size_t row_size) {
7361  unsigned int result = ((unsigned int)q[0] +
7362  (unsigned int)q[pixel_size] +
7363  (unsigned int)q[row_size] +
7364  (unsigned int)q[pixel_size + row_size]) >> 2;
7365  *p = (unsigned char)result;
7366  ++p;
7367  ++q;
7368 }
7369 
7370 ////////////////////////////////////////////////////////////////////
7371 // Function: Texture::filter_2d_unsigned_byte_srgb
7372 // Access: Public, Static
7373 // Description: Averages a 2x2 block of pixel components into a
7374 // single pixel component, for producing the next mipmap
7375 // level. Increments p and q to the next component.
7376 ////////////////////////////////////////////////////////////////////
7377 void Texture::
7378 filter_2d_unsigned_byte_srgb(unsigned char *&p, const unsigned char *&q,
7379  size_t pixel_size, size_t row_size) {
7380  float result = (decode_sRGB_float(q[0]) +
7381  decode_sRGB_float(q[pixel_size]) +
7382  decode_sRGB_float(q[row_size]) +
7383  decode_sRGB_float(q[pixel_size + row_size]));
7384 
7385  *p = encode_sRGB_uchar(result * 0.25f);
7386  ++p;
7387  ++q;
7388 }
7389 
7390 ////////////////////////////////////////////////////////////////////
7391 // Function: Texture::filter_2d_unsigned_byte_srgb_sse2
7392 // Access: Public, Static
7393 // Description: Averages a 2x2 block of pixel components into a
7394 // single pixel component, for producing the next mipmap
7395 // level. Increments p and q to the next component.
7396 ////////////////////////////////////////////////////////////////////
7397 void Texture::
7398 filter_2d_unsigned_byte_srgb_sse2(unsigned char *&p, const unsigned char *&q,
7399  size_t pixel_size, size_t row_size) {
7400  float result = (decode_sRGB_float(q[0]) +
7401  decode_sRGB_float(q[pixel_size]) +
7402  decode_sRGB_float(q[row_size]) +
7403  decode_sRGB_float(q[pixel_size + row_size]));
7404 
7405  *p = encode_sRGB_uchar_sse2(result * 0.25f);
7406  ++p;
7407  ++q;
7408 }
7409 
7410 ////////////////////////////////////////////////////////////////////
7411 // Function: Texture::filter_2d_unsigned_short
7412 // Access: Public, Static
7413 // Description: Averages a 2x2 block of pixel components into a
7414 // single pixel component, for producing the next mipmap
7415 // level. Increments p and q to the next component.
7416 ////////////////////////////////////////////////////////////////////
7417 void Texture::
7418 filter_2d_unsigned_short(unsigned char *&p, const unsigned char *&q,
7419  size_t pixel_size, size_t row_size) {
7420  unsigned int result = ((unsigned int)*(unsigned short *)&q[0] +
7421  (unsigned int)*(unsigned short *)&q[pixel_size] +
7422  (unsigned int)*(unsigned short *)&q[row_size] +
7423  (unsigned int)*(unsigned short *)&q[pixel_size + row_size]) >> 2;
7424  store_unscaled_short(p, result);
7425  q += 2;
7426 }
7427 
7428 ////////////////////////////////////////////////////////////////////
7429 // Function: Texture::filter_2d_float
7430 // Access: Public, Static
7431 // Description: Averages a 2x2 block of pixel components into a
7432 // single pixel component, for producing the next mipmap
7433 // level. Increments p and q to the next component.
7434 ////////////////////////////////////////////////////////////////////
7435 void Texture::
7436 filter_2d_float(unsigned char *&p, const unsigned char *&q,
7437  size_t pixel_size, size_t row_size) {
7438  *(float *)p = (*(float *)&q[0] +
7439  *(float *)&q[pixel_size] +
7440  *(float *)&q[row_size] +
7441  *(float *)&q[pixel_size + row_size]) / 4.0f;
7442  p += 4;
7443  q += 4;
7444 }
7445 
7446 ////////////////////////////////////////////////////////////////////
7447 // Function: Texture::filter_3d_unsigned_byte
7448 // Access: Public, Static
7449 // Description: Averages a 2x2x2 block of pixel components into a
7450 // single pixel component, for producing the next mipmap
7451 // level. Increments p and q to the next component.
7452 ////////////////////////////////////////////////////////////////////
7453 void Texture::
7454 filter_3d_unsigned_byte(unsigned char *&p, const unsigned char *&q,
7455  size_t pixel_size, size_t row_size, size_t page_size) {
7456  unsigned int result = ((unsigned int)q[0] +
7457  (unsigned int)q[pixel_size] +
7458  (unsigned int)q[row_size] +
7459  (unsigned int)q[pixel_size + row_size] +
7460  (unsigned int)q[page_size] +
7461  (unsigned int)q[pixel_size + page_size] +
7462  (unsigned int)q[row_size + page_size] +
7463  (unsigned int)q[pixel_size + row_size + page_size]) >> 3;
7464  *p = (unsigned char)result;
7465  ++p;
7466  ++q;
7467 }
7468 
7469 ////////////////////////////////////////////////////////////////////
7470 // Function: Texture::filter_3d_unsigned_byte_srgb
7471 // Access: Public, Static
7472 // Description: Averages a 2x2x2 block of pixel components into a
7473 // single pixel component, for producing the next mipmap
7474 // level. Increments p and q to the next component.
7475 ////////////////////////////////////////////////////////////////////
7476 void Texture::
7477 filter_3d_unsigned_byte_srgb(unsigned char *&p, const unsigned char *&q,
7478  size_t pixel_size, size_t row_size, size_t page_size) {
7479  float result = (decode_sRGB_float(q[0]) +
7480  decode_sRGB_float(q[pixel_size]) +
7481  decode_sRGB_float(q[row_size]) +
7482  decode_sRGB_float(q[pixel_size + row_size]) +
7483  decode_sRGB_float(q[page_size]) +
7484  decode_sRGB_float(q[pixel_size + page_size]) +
7485  decode_sRGB_float(q[row_size + page_size]) +
7486  decode_sRGB_float(q[pixel_size + row_size + page_size]));
7487 
7488  *p = encode_sRGB_uchar(result * 0.125f);
7489  ++p;
7490  ++q;
7491 }
7492 
7493 ////////////////////////////////////////////////////////////////////
7494 // Function: Texture::filter_3d_unsigned_byte_srgb_sse2
7495 // Access: Public, Static
7496 // Description: Averages a 2x2x2 block of pixel components into a
7497 // single pixel component, for producing the next mipmap
7498 // level. Increments p and q to the next component.
7499 ////////////////////////////////////////////////////////////////////
7500 void Texture::
7501 filter_3d_unsigned_byte_srgb_sse2(unsigned char *&p, const unsigned char *&q,
7502  size_t pixel_size, size_t row_size, size_t page_size) {
7503  float result = (decode_sRGB_float(q[0]) +
7504  decode_sRGB_float(q[pixel_size]) +
7505  decode_sRGB_float(q[row_size]) +
7506  decode_sRGB_float(q[pixel_size + row_size]) +
7507  decode_sRGB_float(q[page_size]) +
7508  decode_sRGB_float(q[pixel_size + page_size]) +
7509  decode_sRGB_float(q[row_size + page_size]) +
7510  decode_sRGB_float(q[pixel_size + row_size + page_size]));
7511 
7512  *p = encode_sRGB_uchar_sse2(result * 0.125f);
7513  ++p;
7514  ++q;
7515 }
7516 
7517 ////////////////////////////////////////////////////////////////////
7518 // Function: Texture::filter_3d_unsigned_short
7519 // Access: Public, Static
7520 // Description: Averages a 2x2x2 block of pixel components into a
7521 // single pixel component, for producing the next mipmap
7522 // level. Increments p and q to the next component.
7523 ////////////////////////////////////////////////////////////////////
7524 void Texture::
7525 filter_3d_unsigned_short(unsigned char *&p, const unsigned char *&q,
7526  size_t pixel_size, size_t row_size,
7527  size_t page_size) {
7528  unsigned int result = ((unsigned int)*(unsigned short *)&q[0] +
7529  (unsigned int)*(unsigned short *)&q[pixel_size] +
7530  (unsigned int)*(unsigned short *)&q[row_size] +
7531  (unsigned int)*(unsigned short *)&q[pixel_size + row_size] +
7532  (unsigned int)*(unsigned short *)&q[page_size] +
7533  (unsigned int)*(unsigned short *)&q[pixel_size + page_size] +
7534  (unsigned int)*(unsigned short *)&q[row_size + page_size] +
7535  (unsigned int)*(unsigned short *)&q[pixel_size + row_size + page_size]) >> 3;
7536  store_unscaled_short(p, result);
7537  q += 2;
7538 }
7539 
7540 ////////////////////////////////////////////////////////////////////
7541 // Function: Texture::filter_3d_float
7542 // Access: Public, Static
7543 // Description: Averages a 2x2x2 block of pixel components into a
7544 // single pixel component, for producing the next mipmap
7545 // level. Increments p and q to the next component.
7546 ////////////////////////////////////////////////////////////////////
7547 void Texture::
7548 filter_3d_float(unsigned char *&p, const unsigned char *&q,
7549  size_t pixel_size, size_t row_size, size_t page_size) {
7550  *(float *)p = (*(float *)&q[0] +
7551  *(float *)&q[pixel_size] +
7552  *(float *)&q[row_size] +
7553  *(float *)&q[pixel_size + row_size] +
7554  *(float *)&q[page_size] +
7555  *(float *)&q[pixel_size + page_size] +
7556  *(float *)&q[row_size + page_size] +
7557  *(float *)&q[pixel_size + row_size + page_size]) / 8.0f;
7558  p += 4;
7559  q += 4;
7560 }
7561 
7562 ////////////////////////////////////////////////////////////////////
7563 // Function: Texture::do_squish
7564 // Access: Private
7565 // Description: Invokes the squish library to compress the RAM
7566 // image(s).
7567 ////////////////////////////////////////////////////////////////////
7568 bool Texture::
7569 do_squish(CData *cdata, Texture::CompressionMode compression, int squish_flags) {
7570 #ifdef HAVE_SQUISH
7571  if (cdata->_ram_images.empty() || cdata->_ram_image_compression != CM_off) {
7572  return false;
7573  }
7574 
7575  if (!do_has_all_ram_mipmap_images(cdata)) {
7576  // If we're about to compress the RAM image, we should ensure that
7577  // we have all of the mipmap levels first.
7578  do_generate_ram_mipmap_images(cdata);
7579  }
7580 
7581  RamImages compressed_ram_images;
7582  compressed_ram_images.reserve(cdata->_ram_images.size());
7583  for (size_t n = 0; n < cdata->_ram_images.size(); ++n) {
7584  RamImage compressed_image;
7585  int x_size = do_get_expected_mipmap_x_size(cdata, n);
7586  int y_size = do_get_expected_mipmap_y_size(cdata, n);
7587  int num_pages = do_get_expected_mipmap_num_pages(cdata, n);
7588  int page_size = squish::GetStorageRequirements(x_size, y_size, squish_flags);
7589  int cell_size = squish::GetStorageRequirements(4, 4, squish_flags);
7590 
7591  compressed_image._page_size = page_size;
7592  compressed_image._image = PTA_uchar::empty_array(page_size * num_pages);
7593  for (int z = 0; z < num_pages; ++z) {
7594  unsigned char *dest_page = compressed_image._image.p() + z * page_size;
7595  unsigned const char *source_page = cdata->_ram_images[n]._image.p() + z * cdata->_ram_images[n]._page_size;
7596  unsigned const char *source_page_end = source_page + cdata->_ram_images[n]._page_size;
7597  // Convert one 4 x 4 cell at a time.
7598  unsigned char *d = dest_page;
7599  for (int y = 0; y < y_size; y += 4) {
7600  for (int x = 0; x < x_size; x += 4) {
7601  unsigned char tb[16 * 4];
7602  int mask = 0;
7603  unsigned char *t = tb;
7604  for (int i = 0; i < 16; ++i) {
7605  int xi = x + i % 4;
7606  int yi = y + i / 4;
7607  unsigned const char *s = source_page + (yi * x_size + xi) * cdata->_num_components;
7608  if (s < source_page_end) {
7609  switch (cdata->_num_components) {
7610  case 1:
7611  t[0] = s[0]; // r
7612  t[1] = s[0]; // g
7613  t[2] = s[0]; // b
7614  t[3] = 255; // a
7615  break;
7616 
7617  case 2:
7618  t[0] = s[0]; // r
7619  t[1] = s[0]; // g
7620  t[2] = s[0]; // b
7621  t[3] = s[1]; // a
7622  break;
7623 
7624  case 3:
7625  t[0] = s[2]; // r
7626  t[1] = s[1]; // g
7627  t[2] = s[0]; // b
7628  t[3] = 255; // a
7629  break;
7630 
7631  case 4:
7632  t[0] = s[2]; // r
7633  t[1] = s[1]; // g
7634  t[2] = s[0]; // b
7635  t[3] = s[3]; // a
7636  break;
7637  }
7638  mask |= (1 << i);
7639  }
7640  t += 4;
7641  }
7642  squish::CompressMasked(tb, mask, d, squish_flags);
7643  d += cell_size;
7645  }
7646  }
7647  }
7648  compressed_ram_images.push_back(compressed_image);
7649  }
7650  cdata->_ram_images.swap(compressed_ram_images);
7651  cdata->_ram_image_compression = compression;
7652  return true;
7653 
7654 #else // HAVE_SQUISH
7655  return false;
7656 
7657 #endif // HAVE_SQUISH
7658 }
7659 
7660 ////////////////////////////////////////////////////////////////////
7661 // Function: Texture::do_unsquish
7662 // Access: Private
7663 // Description: Invokes the squish library to uncompress the RAM
7664 // image(s).
7665 ////////////////////////////////////////////////////////////////////
7666 bool Texture::
7667 do_unsquish(CData *cdata, int squish_flags) {
7668 #ifdef HAVE_SQUISH
7669  if (cdata->_ram_images.empty()) {
7670  return false;
7671  }
7672  RamImages uncompressed_ram_images;
7673  uncompressed_ram_images.reserve(cdata->_ram_images.size());
7674  for (size_t n = 0; n < cdata->_ram_images.size(); ++n) {
7675  RamImage uncompressed_image;
7676  int x_size = do_get_expected_mipmap_x_size(cdata, n);
7677  int y_size = do_get_expected_mipmap_y_size(cdata, n);
7678  int num_pages = do_get_expected_mipmap_num_pages(cdata, n);
7679  int page_size = squish::GetStorageRequirements(x_size, y_size, squish_flags);
7680  int cell_size = squish::GetStorageRequirements(4, 4, squish_flags);
7681 
7682  uncompressed_image._page_size = do_get_expected_ram_mipmap_page_size(cdata, n);
7683  uncompressed_image._image = PTA_uchar::empty_array(uncompressed_image._page_size * num_pages);
7684  for (int z = 0; z < num_pages; ++z) {
7685  unsigned char *dest_page = uncompressed_image._image.p() + z * uncompressed_image._page_size;
7686  unsigned char *dest_page_end = dest_page + uncompressed_image._page_size;
7687  unsigned const char *source_page = cdata->_ram_images[n]._image.p() + z * page_size;
7688  // Unconvert one 4 x 4 cell at a time.
7689  unsigned const char *s = source_page;
7690  for (int y = 0; y < y_size; y += 4) {
7691  for (int x = 0; x < x_size; x += 4) {
7692  unsigned char tb[16 * 4];
7693  squish::Decompress(tb, s, squish_flags);
7694  s += cell_size;
7695 
7696  unsigned char *t = tb;
7697  for (int i = 0; i < 16; ++i) {
7698  int xi = x + i % 4;
7699  int yi = y + i / 4;
7700  unsigned char *d = dest_page + (yi * x_size + xi) * cdata->_num_components;
7701  if (d < dest_page_end) {
7702  switch (cdata->_num_components) {
7703  case 1:
7704  d[0] = t[1]; // g
7705  break;
7706 
7707  case 2:
7708  d[0] = t[1]; // g
7709  d[1] = t[3]; // a
7710  break;
7711 
7712  case 3:
7713  d[2] = t[0]; // r
7714  d[1] = t[1]; // g
7715  d[0] = t[2]; // b
7716  break;
7717 
7718  case 4:
7719  d[2] = t[0]; // r
7720  d[1] = t[1]; // g
7721  d[0] = t[2]; // b
7722  d[3] = t[3]; // a
7723  break;
7724  }
7725  }
7726  t += 4;
7727  }
7728  }
7730  }
7731  }
7732  uncompressed_ram_images.push_back(uncompressed_image);
7733  }
7734  cdata->_ram_images.swap(uncompressed_ram_images);
7735  cdata->_ram_image_compression = CM_off;
7736  return true;
7737 
7738 #else // HAVE_SQUISH
7739  return false;
7740 
7741 #endif // HAVE_SQUISH
7742 }
7743 
7744 ////////////////////////////////////////////////////////////////////
7745 // Function: Texture::register_with_read_factory
7746 // Access: Public, Static
7747 // Description: Factory method to generate a Texture object
7748 ////////////////////////////////////////////////////////////////////
7749 void Texture::
7751  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
7752 }
7753 
7754 ////////////////////////////////////////////////////////////////////
7755 // Function: Texture::write_datagram
7756 // Access: Public, Virtual
7757 // Description: Function to write the important information in
7758 // the particular object to a Datagram
7759 ////////////////////////////////////////////////////////////////////
7760 void Texture::
7762  CDWriter cdata(_cycler, false);
7763 
7764  bool has_rawdata = false;
7765  do_write_datagram_header(cdata, manager, me, has_rawdata);
7766  do_write_datagram_body(cdata, manager, me);
7767 
7768  // If we are also including the texture's image data, then stuff it
7769  // in here.
7770  if (has_rawdata) {
7771  do_write_datagram_rawdata(cdata, manager, me);
7772  }
7773 }
7774 
7775 ////////////////////////////////////////////////////////////////////
7776 // Function: Texture::finalize
7777 // Access: Public, Virtual
7778 // Description: Called by the BamReader to perform any final actions
7779 // needed for setting up the object after all objects
7780 // have been read and all pointers have been completed.
7781 ////////////////////////////////////////////////////////////////////
7782 void Texture::
7784  // Unref the pointer that we explicitly reffed in make_from_bam().
7785  unref();
7786 
7787  // We should never get back to zero after unreffing our own count,
7788  // because we expect to have been stored in a pointer somewhere. If
7789  // we do get to zero, it's a memory leak; the way to avoid this is
7790  // to call unref_delete() above instead of unref(), but this is
7791  // dangerous to do from within a virtual function.
7792  nassertv(get_ref_count() != 0);
7793 }
7794 
7795 
7796 ////////////////////////////////////////////////////////////////////
7797 // Function: Texture::do_write_datagram_header
7798 // Access: Protected
7799 // Description: Writes the header part of the texture to the
7800 // Datagram. This is the common part that is shared by
7801 // all Texture subclasses, and contains the filename and
7802 // rawdata flags. This method is not virtual because
7803 // all Texture subclasses must write the same data at
7804 // this step.
7805 //
7806 // This part must be read first before calling
7807 // do_fillin_body() to determine whether to load the
7808 // Texture from the TexturePool or directly from the bam
7809 // stream.
7810 //
7811 // After this call, has_rawdata will be filled with
7812 // either true or false, according to whether we expect
7813 // to write the texture rawdata to the bam stream
7814 // following the texture body.
7815 ////////////////////////////////////////////////////////////////////
7816 void Texture::
7817 do_write_datagram_header(CData *cdata, BamWriter *manager, Datagram &me, bool &has_rawdata) {
7818  // Write out the texture's raw pixel data if (a) the current Bam
7819  // Texture Mode requires that, or (b) there's no filename, so the
7820  // file can't be loaded up from disk, but the raw pixel data is
7821  // currently available in RAM.
7822 
7823  // Otherwise, we just write out the filename, and assume whoever
7824  // loads the bam file later will have access to the image file on
7825  // disk.
7826  BamWriter::BamTextureMode file_texture_mode = manager->get_file_texture_mode();
7827  has_rawdata = (file_texture_mode == BamWriter::BTM_rawdata ||
7828  (cdata->_filename.empty() && do_has_bam_rawdata(cdata)));
7829  if (has_rawdata && !do_has_bam_rawdata(cdata)) {
7830  do_get_bam_rawdata(cdata);
7831  if (!do_has_bam_rawdata(cdata)) {
7832  // No image data after all.
7833  has_rawdata = false;
7834  }
7835  }
7836 
7837  bool has_bam_dir = !manager->get_filename().empty();
7838  Filename bam_dir = manager->get_filename().get_dirname();
7839  Filename filename = cdata->_filename;
7840  Filename alpha_filename = cdata->_alpha_filename;
7841 
7843 
7844  switch (file_texture_mode) {
7845  case BamWriter::BTM_unchanged:
7846  case BamWriter::BTM_rawdata:
7847  break;
7848 
7849  case BamWriter::BTM_fullpath:
7850  filename = cdata->_fullpath;
7851  alpha_filename = cdata->_alpha_fullpath;
7852  break;
7853 
7854  case BamWriter::BTM_relative:
7855  filename = cdata->_fullpath;
7856  alpha_filename = cdata->_alpha_fullpath;
7857  bam_dir.make_absolute(vfs->get_cwd());
7858  if (!has_bam_dir || !filename.make_relative_to(bam_dir, true)) {
7859  filename.find_on_searchpath(get_model_path());
7860  }
7861  if (gobj_cat.is_debug()) {
7862  gobj_cat.debug()
7863  << "Texture file " << cdata->_fullpath
7864  << " found as " << filename << "\n";
7865  }
7866  if (!has_bam_dir || !alpha_filename.make_relative_to(bam_dir, true)) {
7867  alpha_filename.find_on_searchpath(get_model_path());
7868  }
7869  if (gobj_cat.is_debug()) {
7870  gobj_cat.debug()
7871  << "Alpha image " << cdata->_alpha_fullpath
7872  << " found as " << alpha_filename << "\n";
7873  }
7874  break;
7875 
7876  case BamWriter::BTM_basename:
7877  filename = cdata->_fullpath.get_basename();
7878  alpha_filename = cdata->_alpha_fullpath.get_basename();
7879  break;
7880 
7881  default:
7882  gobj_cat.error()
7883  << "Unsupported bam-texture-mode: " << (int)file_texture_mode << "\n";
7884  }
7885 
7886  if (filename.empty() && do_has_bam_rawdata(cdata)) {
7887  // If we don't have a filename, we have to store rawdata anyway.
7888  has_rawdata = true;
7889  }
7890 
7891  me.add_string(get_name());
7892  me.add_string(filename);
7893  me.add_string(alpha_filename);
7894  me.add_uint8(cdata->_primary_file_num_channels);
7895  me.add_uint8(cdata->_alpha_file_channel);
7896  me.add_bool(has_rawdata);
7897  me.add_uint8(cdata->_texture_type);
7898  me.add_bool(cdata->_has_read_mipmaps);
7899 }
7900 
7901 ////////////////////////////////////////////////////////////////////
7902 // Function: Texture::do_write_datagram_body
7903 // Access: Protected, Virtual
7904 // Description: Writes the body part of the texture to the
7905 // Datagram. This is generally all of the texture
7906 // parameters except for the header and the rawdata.
7907 ////////////////////////////////////////////////////////////////////
7908 void Texture::
7909 do_write_datagram_body(CData *cdata, BamWriter *manager, Datagram &me) {
7910  cdata->_default_sampler.write_datagram(me);
7911 
7912  me.add_uint8(cdata->_compression);
7913  me.add_uint8(cdata->_quality_level);
7914 
7915  me.add_uint8(cdata->_format);
7916  me.add_uint8(cdata->_num_components);
7917 
7918  me.add_uint8(cdata->_auto_texture_scale);
7919  me.add_uint32(cdata->_orig_file_x_size);
7920  me.add_uint32(cdata->_orig_file_y_size);
7921 
7922  bool has_simple_ram_image = !cdata->_simple_ram_image._image.empty();
7923  me.add_bool(has_simple_ram_image);
7924 
7925  // Write out the simple image too, so it will be available later.
7926  if (has_simple_ram_image) {
7927  me.add_uint32(cdata->_simple_x_size);
7928  me.add_uint32(cdata->_simple_y_size);
7929  me.add_int32(cdata->_simple_image_date_generated);
7930  me.add_uint32(cdata->_simple_ram_image._image.size());
7931  me.append_data(cdata->_simple_ram_image._image, cdata->_simple_ram_image._image.size());
7932  }
7933 }
7934 
7935 ////////////////////////////////////////////////////////////////////
7936 // Function: Texture::do_write_datagram_rawdata
7937 // Access: Protected, Virtual
7938 // Description: Writes the rawdata part of the texture to the
7939 // Datagram.
7940 ////////////////////////////////////////////////////////////////////
7941 void Texture::
7942 do_write_datagram_rawdata(CData *cdata, BamWriter *manager, Datagram &me) {
7943  me.add_uint32(cdata->_x_size);
7944  me.add_uint32(cdata->_y_size);
7945  me.add_uint32(cdata->_z_size);
7946 
7947  me.add_uint32(cdata->_pad_x_size);
7948  me.add_uint32(cdata->_pad_y_size);
7949  me.add_uint32(cdata->_pad_z_size);
7950 
7951  me.add_uint32(cdata->_num_views);
7952  me.add_uint8(cdata->_component_type);
7953  me.add_uint8(cdata->_component_width);
7954  me.add_uint8(cdata->_ram_image_compression);
7955  me.add_uint8(cdata->_ram_images.size());
7956  for (size_t n = 0; n < cdata->_ram_images.size(); ++n) {
7957  me.add_uint32(cdata->_ram_images[n]._page_size);
7958  me.add_uint32(cdata->_ram_images[n]._image.size());
7959  me.append_data(cdata->_ram_images[n]._image, cdata->_ram_images[n]._image.size());
7960  }
7961 }
7962 
7963 ////////////////////////////////////////////////////////////////////
7964 // Function: Texture::make_from_bam
7965 // Access: Protected, Static
7966 // Description: Factory method to generate a Texture object
7967 ////////////////////////////////////////////////////////////////////
7968 TypedWritable *Texture::
7969 make_from_bam(const FactoryParams &params) {
7970  PT(Texture) dummy = new Texture;
7971  return dummy->make_this_from_bam(params);
7972 }
7973 
7974 ////////////////////////////////////////////////////////////////////
7975 // Function: Texture::make_this_from_bam
7976 // Access: Protected, Virtual
7977 // Description: Called by make_from_bam() once the particular
7978 // subclass of Texture is known. This is called on a
7979 // newly-constructed Texture object of the appropriate
7980 // subclass. It will return either the same Texture
7981 // object (e.g. this), or a different Texture object
7982 // loaded via the TexturePool, as appropriate.
7983 ////////////////////////////////////////////////////////////////////
7984 TypedWritable *Texture::
7985 make_this_from_bam(const FactoryParams &params) {
7986  // The process of making a texture is slightly different than making
7987  // other TypedWritable objects. That is because all creation of
7988  // Textures should be done through calls to TexturePool, which
7989  // ensures that any loads of the same filename refer to the same
7990  // memory.
7991 
7992  DatagramIterator scan;
7993  BamReader *manager;
7994 
7995  parse_params(params, scan, manager);
7996 
7997  // Get the header information--the filenames and texture type--so we
7998  // can look up the file on disk first.
7999  string name = scan.get_string();
8000  Filename filename = scan.get_string();
8001  Filename alpha_filename = scan.get_string();
8002 
8003  int primary_file_num_channels = scan.get_uint8();
8004  int alpha_file_channel = scan.get_uint8();
8005  bool has_rawdata = scan.get_bool();
8006  TextureType texture_type = (TextureType)scan.get_uint8();
8007  if (manager->get_file_minor_ver() < 25) {
8008  // Between Panda3D releases 1.7.2 and 1.8.0 (bam versions 6.24 and
8009  // 6.25), we added TT_2d_texture_array, shifting the definition
8010  // for TT_cube_map.
8011  if (texture_type == TT_2d_texture_array) {
8012  texture_type = TT_cube_map;
8013  }
8014  }
8015  bool has_read_mipmaps = false;
8016  if (manager->get_file_minor_ver() >= 32) {
8017  has_read_mipmaps = scan.get_bool();
8018  }
8019 
8020  Texture *me = NULL;
8021  if (has_rawdata) {
8022  // If the raw image data is included, then just load the texture
8023  // directly from the stream, and return it. In this case we
8024  // return the "this" pointer, since it's a newly-created Texture
8025  // object of the appropriate type.
8026  me = this;
8027  me->set_name(name);
8028  CDWriter cdata_me(me->_cycler, true);
8029  cdata_me->_filename = filename;
8030  cdata_me->_alpha_filename = alpha_filename;
8031  cdata_me->_primary_file_num_channels = primary_file_num_channels;
8032  cdata_me->_alpha_file_channel = alpha_file_channel;
8033  cdata_me->_texture_type = texture_type;
8034  cdata_me->_has_read_mipmaps = has_read_mipmaps;
8035 
8036  // Read the texture attributes directly from the bam stream.
8037  me->do_fillin_body(cdata_me, scan, manager);
8038  me->do_fillin_rawdata(cdata_me, scan, manager);
8039 
8040  // To manage the reference count, explicitly ref it now, then
8041  // unref it in the finalize callback.
8042  me->ref();
8043  manager->register_finalize(me);
8044 
8045  } else {
8046  // The raw image data isn't included, so we'll be loading the
8047  // Texture via the TexturePool. In this case we use the "this"
8048  // pointer as a temporary object to read all of the attributes
8049  // from the bam stream.
8050  Texture *dummy = this;
8051  AutoTextureScale auto_texture_scale = ATS_unspecified;
8052  {
8053  CDWriter cdata_dummy(dummy->_cycler, true);
8054  dummy->do_fillin_body(cdata_dummy, scan, manager);
8055  auto_texture_scale = cdata_dummy->_auto_texture_scale;
8056  }
8057 
8058  if (filename.empty()) {
8059  // This texture has no filename; since we don't have an image to
8060  // load, we can't actually create the texture.
8061  gobj_cat.info()
8062  << "Cannot create texture '" << name << "' with no filename.\n";
8063 
8064  } else {
8065  // This texture does have a filename, so try to load it from disk.
8067  if (!manager->get_filename().empty()) {
8068  // If texture filename was given relative to the bam filename,
8069  // expand it now.
8070  Filename bam_dir = manager->get_filename().get_dirname();
8071  vfs->resolve_filename(filename, bam_dir);
8072  if (!alpha_filename.empty()) {
8073  vfs->resolve_filename(alpha_filename, bam_dir);
8074  }
8075  }
8076 
8077  LoaderOptions options = manager->get_loader_options();
8078  if (dummy->uses_mipmaps()) {
8079  options.set_texture_flags(options.get_texture_flags() | LoaderOptions::TF_generate_mipmaps);
8080  }
8081  options.set_auto_texture_scale(auto_texture_scale);
8082 
8083  switch (texture_type) {
8084  case TT_1d_texture:
8085  case TT_2d_texture:
8086  if (alpha_filename.empty()) {
8087  me = TexturePool::load_texture(filename, primary_file_num_channels,
8088  has_read_mipmaps, options);
8089  } else {
8090  me = TexturePool::load_texture(filename, alpha_filename,
8091  primary_file_num_channels,
8092  alpha_file_channel,
8093  has_read_mipmaps, options);
8094  }
8095  break;
8096 
8097  case TT_3d_texture:
8098  me = TexturePool::load_3d_texture(filename, has_read_mipmaps, options);
8099  break;
8100 
8101  case TT_2d_texture_array:
8102  me = TexturePool::load_2d_texture_array(filename, has_read_mipmaps, options);
8103  break;
8104 
8105  case TT_cube_map:
8106  me = TexturePool::load_cube_map(filename, has_read_mipmaps, options);
8107  break;
8108  }
8109  }
8110 
8111  if (me != (Texture *)NULL) {
8112  me->set_name(name);
8113  CDWriter cdata_me(me->_cycler, true);
8114  me->do_fillin_from(cdata_me, dummy);
8115 
8116  // Since in this case me was loaded from the TexturePool,
8117  // there's no need to explicitly manage the reference count.
8118  // TexturePool will hold it safely.
8119  }
8120  }
8121 
8122  return me;
8123 }
8124 
8125 ////////////////////////////////////////////////////////////////////
8126 // Function: Texture::do_fillin_body
8127 // Access: Protected, Virtual
8128 // Description: Reads in the part of the Texture that was written
8129 // with do_write_datagram_body().
8130 ////////////////////////////////////////////////////////////////////
8131 void Texture::
8132 do_fillin_body(CData *cdata, DatagramIterator &scan, BamReader *manager) {
8133  cdata->_default_sampler.read_datagram(scan, manager);
8134 
8135  if (manager->get_file_minor_ver() >= 1) {
8136  cdata->_compression = (CompressionMode)scan.get_uint8();
8137  }
8138  if (manager->get_file_minor_ver() >= 16) {
8139  cdata->_quality_level = (QualityLevel)scan.get_uint8();
8140  }
8141 
8142  cdata->_format = (Format)scan.get_uint8();
8143  cdata->_num_components = scan.get_uint8();
8144 
8145  if ((int)cdata->_texture_type == 5) {
8146  // As a kind little gesture to the people who try to load a Panda 1.10
8147  // bam in Panda 1.9.
8148  scan.get_uint8();
8149  gobj_cat.error()
8150  << "Buffer textures are not supported in this version of Panda3D.\n";
8151  }
8152 
8153  cdata->inc_properties_modified();
8154 
8155  cdata->_auto_texture_scale = ATS_unspecified;
8156  if (manager->get_file_minor_ver() >= 28) {
8157  cdata->_auto_texture_scale = (AutoTextureScale)scan.get_uint8();
8158  }
8159 
8160  bool has_simple_ram_image = false;
8161  if (manager->get_file_minor_ver() >= 18) {
8162  cdata->_orig_file_x_size = scan.get_uint32();
8163  cdata->_orig_file_y_size = scan.get_uint32();
8164 
8165  has_simple_ram_image = scan.get_bool();
8166  }
8167 
8168  if (has_simple_ram_image) {
8169  cdata->_simple_x_size = scan.get_uint32();
8170  cdata->_simple_y_size = scan.get_uint32();
8171  cdata->_simple_image_date_generated = scan.get_int32();
8172 
8173  size_t u_size = scan.get_uint32();
8174  PTA_uchar image = PTA_uchar::empty_array(u_size, get_class_type());
8175  scan.extract_bytes(image.p(), u_size);
8176 
8177  cdata->_simple_ram_image._image = image;
8178  cdata->_simple_ram_image._page_size = u_size;
8179  cdata->inc_simple_image_modified();
8180  }
8181 }
8182 
8183 ////////////////////////////////////////////////////////////////////
8184 // Function: Texture::do_fillin_rawdata
8185 // Access: Protected, Virtual
8186 // Description: Reads in the part of the Texture that was written
8187 // with do_write_datagram_rawdata().
8188 ////////////////////////////////////////////////////////////////////
8189 void Texture::
8190 do_fillin_rawdata(CData *cdata, DatagramIterator &scan, BamReader *manager) {
8191  cdata->_x_size = scan.get_uint32();
8192  cdata->_y_size = scan.get_uint32();
8193  cdata->_z_size = scan.get_uint32();
8194 
8195  if (manager->get_file_minor_ver() >= 30) {
8196  cdata->_pad_x_size = scan.get_uint32();
8197  cdata->_pad_y_size = scan.get_uint32();
8198  cdata->_pad_z_size = scan.get_uint32();
8199  } else {
8200  do_set_pad_size(cdata, 0, 0, 0);
8201  }
8202 
8203  cdata->_num_views = 1;
8204  if (manager->get_file_minor_ver() >= 26) {
8205  cdata->_num_views = scan.get_uint32();
8206  }
8207  cdata->_component_type = (ComponentType)scan.get_uint8();
8208  cdata->_component_width = scan.get_uint8();
8209  cdata->_ram_image_compression = CM_off;
8210  if (manager->get_file_minor_ver() >= 1) {
8211  cdata->_ram_image_compression = (CompressionMode)scan.get_uint8();
8212  }
8213 
8214  int num_ram_images = 1;
8215  if (manager->get_file_minor_ver() >= 3) {
8216  num_ram_images = scan.get_uint8();
8217  }
8218 
8219  cdata->_ram_images.clear();
8220  cdata->_ram_images.reserve(num_ram_images);
8221  for (int n = 0; n < num_ram_images; ++n) {
8222  cdata->_ram_images.push_back(RamImage());
8223  cdata->_ram_images[n]._page_size = get_expected_ram_page_size();
8224  if (manager->get_file_minor_ver() >= 1) {
8225  cdata->_ram_images[n]._page_size = scan.get_uint32();
8226  }
8227 
8228  // fill the cdata->_image buffer with image data
8229  size_t u_size = scan.get_uint32();
8230  PTA_uchar image = PTA_uchar::empty_array(u_size, get_class_type());
8231  scan.extract_bytes(image.p(), u_size);
8232 
8233  cdata->_ram_images[n]._image = image;
8234  }
8235  cdata->_loaded_from_image = true;
8236  cdata->inc_image_modified();
8237 }
8238 
8239 ////////////////////////////////////////////////////////////////////
8240 // Function: Texture::do_fillin_from
8241 // Access: Protected, Virtual
8242 // Description: Called in make_from_bam(), this method properly
8243 // copies the attributes from the bam stream (as stored
8244 // in dummy) into this texture, updating the modified
8245 // flags appropriately.
8246 ////////////////////////////////////////////////////////////////////
8247 void Texture::
8248 do_fillin_from(CData *cdata, const Texture *dummy) {
8249  // Use the setters instead of setting these directly, so we can
8250  // correctly avoid incrementing cdata->_properties_modified if none of
8251  // these actually change. (Otherwise, we'd have to reload the
8252  // texture to the GSG every time we loaded a new bam file that
8253  // reference the texture, since each bam file reference passes
8254  // through this function.)
8255 
8256  CDReader cdata_dummy(dummy->_cycler);
8257 
8258  do_set_wrap_u(cdata, cdata_dummy->_default_sampler.get_wrap_u());
8259  do_set_wrap_v(cdata, cdata_dummy->_default_sampler.get_wrap_v());
8260  do_set_wrap_w(cdata, cdata_dummy->_default_sampler.get_wrap_w());
8261  do_set_border_color(cdata, cdata_dummy->_default_sampler.get_border_color());
8262 
8263  if (cdata_dummy->_default_sampler.get_minfilter() != SamplerState::FT_default) {
8264  do_set_minfilter(cdata, cdata_dummy->_default_sampler.get_minfilter());
8265  }
8266  if (cdata_dummy->_default_sampler.get_magfilter() != SamplerState::FT_default) {
8267  do_set_magfilter(cdata, cdata_dummy->_default_sampler.get_magfilter());
8268  }
8269  if (cdata_dummy->_default_sampler.get_anisotropic_degree() != 0) {
8270  do_set_anisotropic_degree(cdata, cdata_dummy->_default_sampler.get_anisotropic_degree());
8271  }
8272  if (cdata_dummy->_compression != CM_default) {
8273  do_set_compression(cdata, cdata_dummy->_compression);
8274  }
8275  if (cdata_dummy->_quality_level != QL_default) {
8276  do_set_quality_level(cdata, cdata_dummy->_quality_level);
8277  }
8278 
8279  Format format = cdata_dummy->_format;
8280  int num_components = cdata_dummy->_num_components;
8281 
8282  if (num_components == cdata->_num_components) {
8283  // Only reset the format if the number of components hasn't
8284  // changed, since if the number of components has changed our
8285  // texture no longer matches what it was when the bam was
8286  // written.
8287  do_set_format(cdata, format);
8288  }
8289 
8290  if (!cdata_dummy->_simple_ram_image._image.empty()) {
8291  // Only replace the simple ram image if it was generated more
8292  // recently than the one we already have.
8293  if (cdata->_simple_ram_image._image.empty() ||
8294  cdata_dummy->_simple_image_date_generated > cdata->_simple_image_date_generated) {
8295  do_set_simple_ram_image(cdata,
8296  cdata_dummy->_simple_ram_image._image,
8297  cdata_dummy->_simple_x_size,
8298  cdata_dummy->_simple_y_size);
8299  cdata->_simple_image_date_generated = cdata_dummy->_simple_image_date_generated;
8300  }
8301  }
8302 }
8303 
8304 ////////////////////////////////////////////////////////////////////
8305 // Function: Texture::CData::Constructor
8306 // Access: Public
8307 // Description:
8308 ////////////////////////////////////////////////////////////////////
8309 Texture::CData::
8310 CData() {
8311  _primary_file_num_channels = 0;
8312  _alpha_file_channel = 0;
8313  _keep_ram_image = true;
8314  _compression = CM_default;
8315  _auto_texture_scale = ATS_unspecified;
8316  _ram_image_compression = CM_off;
8317  _render_to_texture = false;
8318  _match_framebuffer_format = false;
8319  _post_load_store_cache = false;
8320  _quality_level = QL_default;
8321 
8322  _texture_type = TT_2d_texture;
8323  _x_size = 0;
8324  _y_size = 1;
8325  _z_size = 1;
8326  _num_views = 1;
8327 
8328  // We will override the format in a moment (in the Texture
8329  // constructor), but set it to something else first to avoid the
8330  // check in do_set_format depending on an uninitialized value.
8331  _format = F_rgba;
8332 
8333  _pad_x_size = 0;
8334  _pad_y_size = 0;
8335  _pad_z_size = 0;
8336 
8337  _orig_file_x_size = 0;
8338  _orig_file_y_size = 0;
8339 
8340  _loaded_from_image = false;
8341  _loaded_from_txo = false;
8342  _has_read_pages = false;
8343  _has_read_mipmaps = false;
8344  _num_mipmap_levels_read = 0;
8345 
8346  _simple_x_size = 0;
8347  _simple_y_size = 0;
8348  _simple_ram_image._page_size = 0;
8349 
8350  _has_clear_color = false;
8351 }
8352 
8353 ////////////////////////////////////////////////////////////////////
8354 // Function: Texture::CData::Copy Constructor
8355 // Access: Public
8356 // Description:
8357 ////////////////////////////////////////////////////////////////////
8358 Texture::CData::
8359 CData(const Texture::CData &copy) {
8360  _num_mipmap_levels_read = 0;
8361 
8362  do_assign(&copy);
8363 
8364  _properties_modified = copy._properties_modified;
8365  _image_modified = copy._image_modified;
8366  _simple_image_modified = copy._simple_image_modified;
8367 }
8368 
8369 ////////////////////////////////////////////////////////////////////
8370 // Function: Texture::CData::make_copy
8371 // Access: Public, Virtual
8372 // Description:
8373 ////////////////////////////////////////////////////////////////////
8374 CycleData *Texture::CData::
8375 make_copy() const {
8376  return new CData(*this);
8377 }
8378 
8379 ////////////////////////////////////////////////////////////////////
8380 // Function: Texture::CData::do_assign
8381 // Access: Public
8382 // Description:
8383 ////////////////////////////////////////////////////////////////////
8384 void Texture::CData::
8385 do_assign(const Texture::CData *copy) {
8386  _filename = copy->_filename;
8387  _alpha_filename = copy->_alpha_filename;
8388  if (!copy->_fullpath.empty()) {
8389  // Since the fullpath is often empty on a file loaded directly
8390  // from a txo, we only assign the fullpath if it is not empty.
8391  _fullpath = copy->_fullpath;
8392  _alpha_fullpath = copy->_alpha_fullpath;
8393  }
8394  _primary_file_num_channels = copy->_primary_file_num_channels;
8395  _alpha_file_channel = copy->_alpha_file_channel;
8396  _x_size = copy->_x_size;
8397  _y_size = copy->_y_size;
8398  _z_size = copy->_z_size;
8399  _num_views = copy->_num_views;
8400  _pad_x_size = copy->_pad_x_size;
8401  _pad_y_size = copy->_pad_y_size;
8402  _pad_z_size = copy->_pad_z_size;
8403  _orig_file_x_size = copy->_orig_file_x_size;
8404  _orig_file_y_size = copy->_orig_file_y_size;
8405  _num_components = copy->_num_components;
8406  _component_width = copy->_component_width;
8407  _texture_type = copy->_texture_type;
8408  _format = copy->_format;
8409  _component_type = copy->_component_type;
8410  _loaded_from_image = copy->_loaded_from_image;
8411  _loaded_from_txo = copy->_loaded_from_txo;
8412  _has_read_pages = copy->_has_read_pages;
8413  _has_read_mipmaps = copy->_has_read_mipmaps;
8414  _num_mipmap_levels_read = copy->_num_mipmap_levels_read;
8415  _default_sampler = copy->_default_sampler;
8416  _keep_ram_image = copy->_keep_ram_image;
8417  _compression = copy->_compression;
8418  _match_framebuffer_format = copy->_match_framebuffer_format;
8419  _quality_level = copy->_quality_level;
8420  _auto_texture_scale = copy->_auto_texture_scale;
8421  _ram_image_compression = copy->_ram_image_compression;
8422  _ram_images = copy->_ram_images;
8423  _simple_x_size = copy->_simple_x_size;
8424  _simple_y_size = copy->_simple_y_size;
8425  _simple_ram_image = copy->_simple_ram_image;
8426 }
8427 
8428 ////////////////////////////////////////////////////////////////////
8429 // Function: Texture::CData::write_datagram
8430 // Access: Public, Virtual
8431 // Description: Writes the contents of this object to the datagram
8432 // for shipping out to a Bam file.
8433 ////////////////////////////////////////////////////////////////////
8434 void Texture::CData::
8435 write_datagram(BamWriter *manager, Datagram &dg) const {
8436 }
8437 
8438 ////////////////////////////////////////////////////////////////////
8439 // Function: Texture::CData::complete_pointers
8440 // Access: Public, Virtual
8441 // Description: Receives an array of pointers, one for each time
8442 // manager->read_pointer() was called in fillin().
8443 // Returns the number of pointers processed.
8444 ////////////////////////////////////////////////////////////////////
8445 int Texture::CData::
8446 complete_pointers(TypedWritable **p_list, BamReader *manager) {
8447  return 0;
8448 }
8449 
8450 ////////////////////////////////////////////////////////////////////
8451 // Function: Texture::CData::fillin
8452 // Access: Public, Virtual
8453 // Description: This internal function is called by make_from_bam to
8454 // read in all of the relevant data from the BamFile for
8455 // the new Geom.
8456 ////////////////////////////////////////////////////////////////////
8457 void Texture::CData::
8458 fillin(DatagramIterator &scan, BamReader *manager) {
8459 }
8460 
8461 ////////////////////////////////////////////////////////////////////
8462 // Function: Texture::TextureType output operator
8463 // Description:
8464 ////////////////////////////////////////////////////////////////////
8465 ostream &
8466 operator << (ostream &out, Texture::TextureType tt) {
8467  return out << Texture::format_texture_type(tt);
8468 }
8469 
8470 ////////////////////////////////////////////////////////////////////
8471 // Function: Texture::ComponentType output operator
8472 // Description:
8473 ////////////////////////////////////////////////////////////////////
8474 ostream &
8475 operator << (ostream &out, Texture::ComponentType ct) {
8476  return out << Texture::format_component_type(ct);
8477 }
8478 
8479 ////////////////////////////////////////////////////////////////////
8480 // Function: Texture::Format output operator
8481 // Description:
8482 ////////////////////////////////////////////////////////////////////
8483 ostream &
8484 operator << (ostream &out, Texture::Format f) {
8485  return out << Texture::format_format(f);
8486 }
8487 
8488 ////////////////////////////////////////////////////////////////////
8489 // Function: Texture::CompressionMode output operator
8490 // Description:
8491 ////////////////////////////////////////////////////////////////////
8492 ostream &
8493 operator << (ostream &out, Texture::CompressionMode cm) {
8494  return out << Texture::format_compression_mode(cm);
8495 }
8496 
8497 ////////////////////////////////////////////////////////////////////
8498 // Function: Texture::QualityLevel output operator
8499 // Description:
8500 ////////////////////////////////////////////////////////////////////
8501 ostream &
8502 operator << (ostream &out, Texture::QualityLevel tql) {
8503  return out << Texture::format_quality_level(tql);
8504 }
8505 
8506 ////////////////////////////////////////////////////////////////////
8507 // Function: Texture::QualityLevel input operator
8508 // Description:
8509 ////////////////////////////////////////////////////////////////////
8510 istream &
8511 operator >> (istream &in, Texture::QualityLevel &tql) {
8512  string word;
8513  in >> word;
8514 
8515  tql = Texture::string_quality_level(word);
8516  return in;
8517 }
void set_data(TypedWritable *ptr, ReferenceCount *ref_ptr)
Stores a new data object on the record.
virtual bool has_cull_callback() const
Should be overridden by derived classes to return true if cull_callback() has been defined...
Definition: texture.cxx:2354
virtual void ensure_loader_type(const Filename &filename)
May be called prior to calling read_txo() or any bam-related Texture-creating callback, to ensure that the proper dynamic libraries for a Texture of the current class type, and the indicated filename, have been already loaded.
Definition: texture.cxx:2600
static bool is_srgb(Format format)
Returns true if the indicated format is in the sRGB color space, false otherwise. ...
Definition: texture.cxx:2459
static string format_quality_level(QualityLevel tql)
Returns the indicated QualityLevel converted to a string word.
Definition: texture.cxx:2276
Texture * load_related(const InternalName *suffix) const
Loads a texture whose filename is derived by concatenating a suffix to the filename of this texture...
Definition: texture.cxx:777
bool is_texture_queued(const Texture *tex) const
Returns true if the texture has been queued on this GSG, false otherwise.
void add_uint8(PN_uint8 value)
Adds an unsigned 8-bit integer to the datagram.
Definition: datagram.I:138
void set_green(int x, int y, float g)
Sets the green component color only at the indicated pixel.
Definition: pnmImage.I:965
void enqueue_texture(Texture *tex)
Indicates that a texture would like to be put on the list to be prepared when the GSG is next ready t...
This is our own Panda specialization on the default STL map.
Definition: pmap.h:52
static string format_component_type(ComponentType ct)
Returns the indicated ComponentType converted to a string word.
Definition: texture.cxx:1969
bool write(const Filename &filename, PNMFileType *type=NULL) const
Writes the image to the indicated filename.
Definition: pnmImage.cxx:362
void copy_sub_image(const PNMImage &copy, int xto, int yto, int xfrom=0, int yfrom=0, int x_size=-1, int y_size=-1)
Copies a rectangular area of another image into a rectangular area of this image. ...
Definition: pnmImage.cxx:1119
bool get_bool()
Extracts a boolean value.
void add_string(const string &str)
Adds a variable-length string to the datagram.
Definition: datagram.I:351
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
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
static Texture * load_cube_map(const Filename &filename_pattern, bool read_mipmaps=false, const LoaderOptions &options=LoaderOptions())
Loads a cube map texture that is specified with a series of 6 pages, numbered 0 through 5...
Definition: texturePool.I:146
void release_texture(TextureContext *tc)
Indicates that a texture context, created by a previous call to prepare_texture(), is no longer needed.
static bool adjust_size(int &x_size, int &y_size, const string &name, bool for_padding, AutoTextureScale auto_texture_scale=ATS_unspecified)
Computes the proper size of the texture, based on the original size, the filename, and the resizing whims of the config file.
Definition: texture.cxx:2486
PNMFileType * get_type() const
If the file type is known (e.g.
virtual void finalize(BamReader *manager)
Called by the BamReader to perform any final actions needed for setting up the object after all objec...
Definition: texture.cxx:7783
const Filename & get_filename() const
If a BAM is a file, then the BamReader should contain the name of the file.
Definition: bamReader.I:45
void wait()
Waits on the condition.
static string format_format(Format f)
Returns the indicated Format converted to a string word.
Definition: texture.cxx:2018
void append_data(const void *data, size_t size)
Appends some more raw data to the end of the datagram.
Definition: datagram.cxx:144
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:122
void alpha_fill(float alpha=0.0)
Sets the entire alpha channel to the given level.
Definition: pnmImage.I:218
int get_num_channels() const
Returns the number of channels in the image.
void set_ram_mipmap_pointer_from_int(long long pointer, int n, int page_size)
Accepts a raw pointer cast as an int, which is then passed to set_ram_mipmap_pointer(); see the docum...
Definition: texture.cxx:1098
Specifies parameters that may be passed to the loader.
Definition: loaderOptions.h:26
This class maintains a cache of Bam and/or Txo objects generated from model files and texture images ...
Definition: bamCache.h:47
bool store(PNMImage &pnmimage) const
Copies the data to the indicated PNMImage, converting to RGB values.
Definition: pfmFile.cxx:387
A hierarchy of directories and files that appears to be one continuous file system, even though the files may originate from several different sources that may not be related to the actual OS&#39;s file system.
bool dequeue_texture(Texture *tex)
Removes a texture from the queued list of textures to be prepared.
static Filename pattern_filename(const string &filename)
Constructs a filename that represents a sequence of numbered files.
Definition: filename.I:179
This class can be used to read a binary file that consists of an arbitrary header followed by a numbe...
int release_all()
Frees the context allocated on all objects for which the texture has been declared.
Definition: texture.cxx:1467
static void register_with_read_factory()
Factory method to generate a Texture object.
Definition: texture.cxx:7750
bool read(const Filename &filename, PNMFileType *type=NULL, bool report_unknown_type=true)
Reads the indicated image filename.
Definition: pnmImage.cxx:245
A single page of data maintained by a PipelineCycler.
Definition: cycleData.h:50
bool get_resident() const
Returns the resident flag associated with this object.
Definition: bufferContext.I:61
static Format string_format(const string &str)
Returns the Format corresponding to the indicated string word.
Definition: texture.cxx:2113
virtual bool is_floating_point()
Returns true if this PNMFileType represents a floating-point image type, false if it is a normal...
Definition: pnmReader.cxx:82
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:75
PN_float32 get_channel(int x, int y, int c) const
Returns the cth channel of the point value at the indicated point.
Definition: pfmFile.I:68
xelval get_blue_val(int x, int y) const
Returns the blue component color at the indicated pixel.
Definition: pnmImage.I:474
void set_ram_image_as(CPTA_uchar image, const string &provided_format)
Replaces the current system-RAM image with the new data, converting it first if necessary from the in...
Definition: texture.cxx:833
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:37
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:63
bool write_header(const string &header)
Writes a sequence of bytes to the beginning of the datagram file.
void set_orig_file_size(int x, int y, int z=1)
Specifies the size of the texture as it exists in its original disk file, before any Panda scaling...
Definition: texture.cxx:1783
static bool is_specific(CompressionMode compression)
Returns true if the indicated compression mode is one of the specific compression types...
Definition: texture.cxx:2394
float get_gray(int x, int y) const
Returns the gray component color at the indicated pixel.
Definition: pnmImage.I:928
This is a special class object that holds all the information returned by a particular GSG to indicat...
This collects together the pieces of data that are accumulated for each node while walking the scene ...
TypedReferenceCount * get_aux_data(const string &key) const
Returns a record previously recorded via set_aux_data().
Definition: texture.cxx:629
PNMReader * make_reader(const Filename &filename, PNMFileType *type=NULL, bool report_unknown_type=true) const
Returns a newly-allocated PNMReader of the suitable type for reading from the indicated image filenam...
bool read_txo(istream &in, const string &filename="")
Reads the texture from a Panda texture object.
Definition: texture.cxx:653
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
Definition: typedObject.I:74
A base class for things which need to inherit from both TypedObject and from ReferenceCount.
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
Definition: texture.cxx:7761
PTA_uchar modify_simple_ram_image()
Returns a modifiable pointer to the internal &quot;simple&quot; texture image.
Definition: texture.cxx:1126
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
Definition: lvector3.h:100
virtual bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const
If has_cull_callback() returns true, this function will be called during the cull traversal to perfor...
Definition: texture.cxx:2372
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:34
bool is_prepared(PreparedGraphicsObjects *prepared_objects) const
Returns true if the texture has already been prepared or enqueued for preparation on the indicated GS...
Definition: texture.cxx:1294
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:73
A lightweight C++ object whose constructor calls acquire() and whose destructor calls release() on a ...
Definition: mutexHolder.h:29
string get_dirname() const
Returns the directory part of the filename.
Definition: filename.I:424
void set_basename_wo_extension(const string &s)
Replaces the basename part of the filename, without the file extension.
Definition: filename.cxx:813
PN_int32 get_int32()
Extracts a signed 32-bit integer.
void set_red(int x, int y, float r)
Sets the red component color only at the indicated pixel.
Definition: pnmImage.I:953
PN_uint8 get_uint8()
Extracts an unsigned 8-bit integer.
AutoTextureScale get_auto_texture_scale() const
See set_auto_texture_scale().
AutoTextureScale get_auto_texture_scale() const
Returns the power-of-2 texture-scaling mode that will be applied to this particular texture when it i...
Definition: texture.I:2190
bool open(const FileReference *file)
Opens the indicated filename for reading.
int get_x_size() const
Returns the number of pixels in the X direction.
PN_uint32 get_uint32()
Extracts an unsigned 32-bit integer.
static void consider_yield()
Possibly suspends the current thread for the rest of the current epoch, if it has run for enough this...
Definition: thread.I:263
CPTA_uchar get_ram_image_as(const string &requested_format)
Returns the uncompressed system-RAM image data associated with the texture.
Definition: texture.cxx:5528
The abstract base class for a file or directory within the VirtualFileSystem.
Definition: virtualFile.h:37
A table of objects that are saved within the graphics context for reference by handle later...
bool get_active(PreparedGraphicsObjects *prepared_objects) const
Returns true if this Texture was rendered in the most recent frame within the indicated GSG...
Definition: texture.cxx:1378
float get_alpha(int x, int y) const
Returns the alpha component color at the indicated pixel.
Definition: pnmImage.I:941
bool read_header(string &header, size_t num_bytes)
Reads a sequence of bytes from the beginning of the datagram file.
int get_y_size() const
Returns the number of pixels in the Y direction.
bool has_name() const
Returns true if the Namable has a nonempty name set, false if the name is empty.
Definition: namable.I:75
Texture(const string &name=string())
Constructs an empty texture.
Definition: texture.cxx:144
static void close_read_file(istream *stream)
Closes a file opened by a previous call to open_read_file().
const LoaderOptions & get_loader_options() const
Returns the LoaderOptions passed to the loader when the model was requested, if any.
Definition: bamReader.I:60
string get_string()
Extracts a variable-length string.
void * get_ram_mipmap_pointer(int n) const
Similiar to get_ram_mipmap_image(), however, in this case the void pointer for the given ram image is...
Definition: texture.cxx:1049
bool uses_mipmaps() const
Returns true if the minfilter settings on this texture indicate the use of mipmapping, false otherwise.
Definition: texture.I:1319
static CompressionMode string_compression_mode(const string &str)
Returns the CompressionMode value associated with the given string representation.
Definition: texture.cxx:2238
static Thread * get_current_thread()
Returns a pointer to the currently-executing Thread object.
Definition: thread.I:145
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.
This template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
bool open(const FileReference *file)
Opens the indicated filename for writing.
bool has_data() const
Returns true if this cache record has an in-memory data object associated–that is, the object stored in the cache.
static QualityLevel string_quality_level(const string &str)
Returns the QualityLevel value associated with the given string representation.
Definition: texture.cxx:2298
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:39
void notify_all()
Informs all of the other threads who are currently blocked on wait() that the relevant condition has ...
void clear_aux_data(const string &key)
Removes a record previously recorded via set_aux_data().
Definition: texture.cxx:616
bool release(PreparedGraphicsObjects *prepared_objects)
Frees the texture context only on the indicated object, if it exists there.
Definition: texture.cxx:1438
xelval get_green_val(int x, int y) const
Returns the green component color at the indicated pixel.
Definition: pnmImage.I:462
bool has_hash() const
Returns true if the filename is indicated to be a filename pattern (that is, set_pattern(true) was ca...
Definition: filename.I:640
void consider_rescale(PNMImage &pnmimage)
Asks the PNMImage to change its scale when it reads the image, according to the whims of the Config...
Definition: texture.cxx:1876
Filename get_cwd() const
Returns the current directory name.
void set_size_padded(int x=1, int y=1, int z=1)
Changes the size of the texture, padding if necessary, and setting the pad region as well...
Definition: texture.cxx:1752
bool store(BamCacheRecord *record)
Flushes a cache entry to disk.
Definition: bamCache.cxx:194
bool read(const Filename &fullpath)
Reads the PFM data from the indicated file, returning true on success, false on failure.
Definition: pfmFile.cxx:130
A lightweight class that represents a single element that may be timed and/or counted via stats...
static AutoTextureScale get_textures_power_2()
This flag returns ATS_none, ATS_up, or ATS_down and controls the scaling of textures in general...
Definition: texture.I:2232
bool write(const Filename &fullpath)
Writes the PFM data to the indicated file, returning true on success, false on failure.
Definition: pfmFile.cxx:222
string extract_bytes(size_t size)
Extracts the indicated number of bytes in the datagram and returns them as a string.
void generate_alpha_scale_map()
Generates a special 256x1 1-d texture that can be used to apply an arbitrary alpha scale to objects b...
Definition: texture.cxx:311
bool get_cache_textures() const
Returns whether texture files (e.g.
Definition: bamCache.I:100
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition: datagram.I:118
A base class for all things which can have a name.
Definition: namable.h:29
int get_num_loadable_ram_mipmap_images() const
Returns the number of contiguous mipmap levels that exist in RAM, up until the first gap in the seque...
Definition: texture.cxx:995
int get_texture_num_views() const
See set_texture_num_views().
void set_auto_texture_scale(AutoTextureScale scale)
Set this flag to ATS_none, ATS_up, ATS_down, or ATS_pad to control how a texture is scaled from disk ...
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
Defines a pfm file, a 2-d table of floating-point numbers, either 3-component or 1-component, or with a special extension, 2- or 4-component.
Definition: pfmFile.h:34
virtual bool unref() const
Explicitly decrements the reference count.
static bool has_alpha(ColorType color_type)
This static variant of has_alpha() returns true if the indicated image type includes an alpha channel...
size_t get_data_size_bytes() const
Returns the number of bytes previously reported for the data object.
Definition: bufferContext.I:26
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:451
An instance of this class is written to the front of a Bam or Txo file to make the file a cached inst...
static bool has_alpha(Format format)
Returns true if the indicated format includes alpha, false otherwise.
Definition: texture.cxx:2413
void set_gray(int x, int y, float gray)
Sets the gray component color at the indicated pixel.
Definition: pnmImage.I:994
void copy_header_from(const PNMImageHeader &header)
Copies just the header information into this image.
Definition: pnmImage.cxx:164
void set_blue(int x, int y, float b)
Sets the blue component color only at the indicated pixel.
Definition: pnmImage.I:977
int get_read_y_size() const
Returns the requested y_size of the image if set_read_size() has been called, or the image y_size oth...
Definition: pnmImage.I:285
int get_num_unique_values() const
Returns the number of unique values in the variable.
virtual bool is_cacheable() const
Returns true if there is enough information in this Texture object to write it to the bam cache succe...
Definition: texture.cxx:971
This template class calls PipelineCycler::read() in the constructor and PipelineCycler::release_read(...
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
static GraphicsStateGuardianBase * get_default_gsg()
Returns a pointer to the &quot;default&quot; GSG.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:40
size_t get_data_size_bytes(PreparedGraphicsObjects *prepared_objects) const
Returns the number of bytes which the texture is reported to consume within graphics memory...
Definition: texture.cxx:1349
void set_aux_data(const string &key, TypedReferenceCount *aux_data)
Records an arbitrary object in the Texture, associated with a specified key.
Definition: texture.cxx:604
This class specializes ConfigVariable as an enumerated type.
CPTA_uchar get_ram_mipmap_image(int n) const
Returns the system-RAM image data associated with the nth mipmap level, if present.
Definition: texture.cxx:1032
bool resolve_filename(Filename &filename, const DSearchPath &searchpath, const string &default_extension=string()) const
Searches the given search path for the filename.
xelval get_channel_val(int x, int y, int channel) const
Returns the nth component color at the indicated pixel.
Definition: pnmImage.cxx:850
bool read_dds(istream &in, const string &filename="", bool header_only=false)
Reads the texture from a DDS file object.
Definition: texture.cxx:761
const CycleDataType * read(Thread *current_thread) const
See PipelineCyclerBase::read().
void register_finalize(TypedWritable *whom)
Should be called by an object reading itself from the Bam file to indicate that this particular objec...
Definition: bamReader.cxx:880
static Texture * load_texture(const Filename &filename, int primary_file_num_channels=0, bool read_mipmaps=false, const LoaderOptions &options=LoaderOptions())
Loads the given filename up into a texture, if it has not already been loaded, and returns the new te...
Definition: texturePool.I:58
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
bool has_compression() const
Returns true if the texture indicates it wants to be compressed, either with CM_on or higher...
Definition: texture.I:1287
bool get_cache_compressed_textures() const
Returns whether compressed texture files will be stored in the cache, as compressed txo files...
Definition: bamCache.I:140
This is an abstract base class that defines the interface for reading image files of various types...
Definition: pnmReader.h:31
bool has_simple_ram_image() const
Returns true if the Texture has a &quot;simple&quot; image available in main RAM.
Definition: texture.I:2053
PointerToArray< Element > cast_non_const() const
Casts away the constness of the CPTA(Element), and returns an equivalent PTA(Element).
ColorSpace get_color_space() const
Returns the color space in which the image is encoded.
Definition: pnmImage.I:296
bool make_relative_to(Filename directory, bool allow_backups=true)
Adjusts this filename, which must be a fully-specified pathname beginning with a slash, to make it a relative filename, relative to the fully-specified directory indicated (which must also begin with, and may or may not end with, a slash–a terminating slash is ignored).
Definition: filename.cxx:1766
void register_factory(TypeHandle handle, CreateFunc *func)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:90
const Filename & get_filename() const
If a BAM is a file, then the BamWriter should contain the name of the file.
Definition: bamWriter.I:36
xelval get_alpha_val(int x, int y) const
Returns the alpha component color at the indicated pixel.
Definition: pnmImage.I:503
An instance of this object is returned by Texture::peek().
Definition: texturePeeker.h:30
void set_channel(int x, int y, int c, PN_float32 value)
Replaces the cth channel of the point value at the indicated point.
Definition: pfmFile.I:82
static TextureType string_texture_type(const string &str)
Returns the TextureType corresponding to the indicated string word.
Definition: texture.cxx:1944
void local_object()
This function should be called, once, immediately after creating a new instance of some ReferenceCoun...
TextureContext * prepare_now(int view, PreparedGraphicsObjects *prepared_objects, GraphicsStateGuardianBase *gsg)
Creates a context for the texture on the particular GSG, if it does not already exist.
Definition: texture.cxx:1808
bool load(const PNMImage &pnmimage)
Fills the PfmFile with the data from the indicated PNMImage, converted to floating-point values...
Definition: pfmFile.cxx:312
This is the base class for all three-component vectors and points.
Definition: lvecBase4.h:111
This class can be used to write a binary file that consists of an arbitrary header followed by a numb...
void add_alpha()
Adds an alpha channel to the image, if it does not already have one.
Definition: pnmImage.I:336
bool exists(const Filename &filename) const
Convenience function; returns true if the named file exists.
string get_basename_wo_extension() const
Returns the basename part of the filename, without the file extension.
Definition: filename.I:460
void make_absolute()
Converts the filename to a fully-qualified pathname from the root (if it is a relative pathname)...
Definition: filename.cxx:1019
void generate_simple_ram_image()
Computes the &quot;simple&quot; ram image by loading the main RAM image, if it is not already available...
Definition: texture.cxx:1164
ostream * open_write_file(const Filename &filename, bool auto_wrap, bool truncate)
Convenience function; returns a newly allocated ostream if the file exists and can be written...
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
CycleDataType * elevate_read_upstream(const CycleDataType *pointer, bool force_to_0, Thread *current_thread)
See PipelineCyclerBase::elevate_read_upstream().
void clear()
Frees all memory allocated for the image, and clears all its parameters (size, color, type, etc).
Definition: pnmImage.cxx:50
string get_basename() const
Returns the basename part of the filename.
Definition: filename.I:436
static int up_to_power_2(int value)
Returns the smallest power of 2 greater than or equal to value.
Definition: texture.cxx:1838
void set_alpha(int x, int y, float a)
Sets the alpha component color only at the indicated pixel.
Definition: pnmImage.I:1007
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:213
virtual bool get_keep_ram_image() const
Returns the flag that indicates whether this Texture is eligible to have its main RAM copy of the tex...
Definition: texture.cxx:957
PTA_uchar new_simple_ram_image(int x_size, int y_size)
Creates an empty array for the simple ram image of the indicated size, and returns a modifiable point...
Definition: texture.cxx:1140
A thread; that is, a lightweight process.
Definition: thread.h:51
void take_from(PNMImage &orig)
Move the contents of the other image into this one, and empty the other image.
Definition: pnmImage.cxx:184
TextureContext * prepare_texture_now(Texture *tex, int view, GraphicsStateGuardianBase *gsg)
Immediately creates a new TextureContext for the indicated texture and returns it.
bool was_image_modified() const
Returns true if the texture image has been modified since the last time mark_loaded() was called...
void prepare(PreparedGraphicsObjects *prepared_objects)
Indicates that the texture should be enqueued to be prepared in the indicated prepared_objects at the...
Definition: texture.cxx:1282
int find_on_searchpath(const DSearchPath &searchpath)
Performs the reverse of the resolve_filename() operation: assuming that the current filename is fully...
Definition: filename.cxx:1820
void add_uint32(PN_uint32 value)
Adds an unsigned 32-bit integer to the datagram.
Definition: datagram.I:192
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.
static string format_texture_type(TextureType tt)
Returns the indicated TextureType converted to a string word.
Definition: texture.cxx:1921
static int down_to_power_2(int value)
Returns the largest power of 2 less than or equal to value.
Definition: texture.cxx:1853
BamTextureMode get_file_texture_mode() const
Returns the BamTextureMode preference indicated by the Bam file currently being written.
Definition: bamWriter.I:81
bool has_ram_image() const
Returns true if the Texture has its image contents available in main RAM, false if it exists only in ...
Definition: texture.I:1465
void generate_normalization_cube_map(int size)
Generates a special cube map image in the texture that can be used to apply bump mapping effects: for...
Definition: texture.cxx:206
bool read(const Filename &fullpath, const LoaderOptions &options=LoaderOptions())
Reads the named filename into the texture.
Definition: texture.cxx:338
static bool is_grayscale(ColorType color_type)
This static variant of is_grayscale() returns true if the indicated image type represents a grayscale...
Filename get_filename_index(int index) const
If the pattern flag is set for this Filename and the filename string actually includes a sequence of ...
Definition: filename.cxx:873
void ref() const
Explicitly increments the reference count.
bool write_txo(ostream &out, const string &filename="") const
Writes the texture to a Panda texture object.
Definition: texture.cxx:743
string get_unique_value(int n) const
Returns the nth unique value of the variable.
void clear_ram_mipmap_image(int n)
Discards the current system-RAM image for the nth mipmap level.
Definition: texture.cxx:1109
void add_dependent_file(const Filename &pathname)
Adds the indicated file to the list of files that will be loaded to generate the data in this record...
bool get_active() const
Returns the active flag associated with this object.
Definition: bufferContext.I:49
void add_int32(PN_int32 value)
Adds a signed 32-bit integer to the datagram.
Definition: datagram.I:159
xelval get_red_val(int x, int y) const
Returns the red component color at the indicated pixel.
Definition: pnmImage.I:450
A class to retrieve the individual data elements previously stored in a Datagram. ...
void texture_uploaded()
This method is called by the GraphicsEngine at the beginning of the frame *after* a texture has been ...
Definition: texture.cxx:2327
static Texture * load_3d_texture(const Filename &filename_pattern, bool read_mipmaps=false, const LoaderOptions &options=LoaderOptions())
Loads a 3-D texture that is specified with a series of n pages, all numbered in sequence, and beginning with index 0.
Definition: texturePool.I:104
static Texture * load_2d_texture_array(const Filename &filename_pattern, bool read_mipmaps=false, const LoaderOptions &options=LoaderOptions())
Loads a 2-D texture array that is specified with a series of n pages, all numbered in sequence...
Definition: texturePool.I:125
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:105
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
static void close_write_file(ostream *stream)
Closes a file opened by a previous call to open_write_file().
void fill(float red, float green, float blue)
Sets the entire image (except the alpha channel) to the given color.
Definition: pnmImage.I:186
void set_num_channels(int num_channels)
Changes the number of channels associated with the image.
Definition: pnmImage.I:323
A class to read sequential binary data directly from an istream.
Definition: streamReader.h:30
int get_read_x_size() const
Returns the requested x_size of the image if set_read_size() has been called, or the image x_size oth...
Definition: pnmImage.I:273
void set_read_size(int x_size, int y_size)
Specifies the size to we&#39;d like to scale the image upon reading it.
Definition: pnmImage.I:238
int get_ref_count() const
Returns the current reference count.
bool normalize()
Normalizes the vector in place.
Definition: lvecBase3.h:782
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:43
static bool has_binary_alpha(Format format)
Returns true if the indicated format includes a binary alpha only, false otherwise.
Definition: texture.cxx:2442
size_t get_expected_ram_page_size() const
Returns the number of bytes that should be used per each Z page of the 3-d texture.
Definition: texture.I:1574
int get_y_size() const
Returns the height of the texture image in texels.
Definition: texture.I:650
static string format_compression_mode(CompressionMode cm)
Returns the indicated CompressionMode converted to a string word.
Definition: texture.cxx:2202
static ComponentType string_component_type(const string &str)
Returns the ComponentType corresponding to the indicated string word.
Definition: texture.cxx:1993
bool get_resident(PreparedGraphicsObjects *prepared_objects) const
Returns true if this Texture is reported to be resident within graphics memory for the indicated GSG...
Definition: texture.cxx:1408
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling...
Definition: cullTraverser.h:48
int get_x_size() const
Returns the width of the texture image in texels.
Definition: texture.I:638
static BamCache * get_global_ptr()
Returns a pointer to the global BamCache object, which is used automatically by the ModelPool and Tex...
Definition: bamCache.I:253
void clear()
Eliminates all data in the file.
Definition: pfmFile.cxx:81
LVecBase3f xform_point(const LVecBase3f &v) const
The matrix transforms a 3-component point (including translation component) and returns the result...
Definition: lmatrix.h:1667
bool was_image_modified(PreparedGraphicsObjects *prepared_objects) const
Returns true if the texture needs to be re-loaded onto the indicated GSG, either because its image da...
Definition: texture.cxx:1313
int get_word(int n) const
Returns the variable&#39;s nth value.
xelval get_gray_val(int x, int y) const
Returns the gray component color at the indicated pixel.
Definition: pnmImage.I:490
bool write(const Filename &fullpath)
Writes the texture to the named filename.
Definition: texture.I:305
This class can be used to test for string matches against standard Unix-shell filename globbing conve...
Definition: globPattern.h:37
static const LVecBase4f & zero()
Returns a zero-length vector.
Definition: lvecBase4.h:492
void set_ram_mipmap_pointer(int n, void *image, size_t page_size=0)
Sets an explicit void pointer as the texture&#39;s mipmap image for the indicated level.
Definition: texture.cxx:1072
static int size()
Returns 3: the number of components of a LVecBase3.
Definition: lvecBase3.h:452
size_t estimate_texture_memory() const
Estimates the amount of texture memory that will be consumed by loading this texture.
Definition: texture.cxx:490