Panda3D
texturePool.cxx
1 // Filename: texturePool.cxx
2 // Created by: drose (26Apr00)
3 // Updated by: fperazzi, PandaSE(29Apr10) (added ns_load_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 "texturePool.h"
17 #include "config_gobj.h"
18 #include "config_util.h"
19 #include "config_express.h"
20 #include "string_utils.h"
21 #include "virtualFileSystem.h"
22 #include "bamCache.h"
23 #include "bamCacheRecord.h"
24 #include "pnmFileTypeRegistry.h"
25 #include "texturePoolFilter.h"
26 #include "configVariableList.h"
27 #include "load_dso.h"
28 #include "mutexHolder.h"
29 #include "dcast.h"
30 
31 TexturePool *TexturePool::_global_ptr;
32 
33 ////////////////////////////////////////////////////////////////////
34 // Function: TexturePool::write
35 // Access: Published, Static
36 // Description: Lists the contents of the texture pool to the
37 // indicated output stream.
38 // For debugging.
39 ////////////////////////////////////////////////////////////////////
40 void TexturePool::
41 write(ostream &out) {
42  get_global_ptr()->ns_list_contents(out);
43 }
44 
45 ////////////////////////////////////////////////////////////////////
46 // Function: TexturePool::register_texture_type
47 // Access: Public
48 // Description: Records a factory function that makes a Texture
49 // object of the appropriate type for one or more
50 // particular filename extensions. The string
51 // extensions may be a string that contains
52 // space-separated list of extensions, case-insensitive.
53 ////////////////////////////////////////////////////////////////////
54 void TexturePool::
55 register_texture_type(MakeTextureFunc *func, const string &extensions) {
56  MutexHolder holder(_lock);
57 
58  vector_string words;
59  extract_words(downcase(extensions), words);
60 
61  vector_string::const_iterator wi;
62  for (wi = words.begin(); wi != words.end(); ++wi) {
63  _type_registry[*wi] = func;
64  }
65 }
66 
67 ////////////////////////////////////////////////////////////////////
68 // Function: TexturePool::register_filter
69 // Access: Public
70 // Description: Records a TexturePoolFilter object that may operate
71 // on texture images as they are loaded from disk.
72 ////////////////////////////////////////////////////////////////////
73 void TexturePool::
75  MutexHolder holder(_lock);
76 
77  gobj_cat.info()
78  << "Registering Texture filter " << *filter << "\n";
79  _filter_registry.push_back(filter);
80 }
81 
82 ////////////////////////////////////////////////////////////////////
83 // Function: TexturePool::get_texture_type
84 // Access: Public
85 // Description: Returns the factory function to construct a new
86 // texture of the type appropriate for the indicated
87 // filename extension, if any, or NULL if the extension
88 // is not one of the extensions for a texture file.
89 ////////////////////////////////////////////////////////////////////
90 TexturePool::MakeTextureFunc *TexturePool::
91 get_texture_type(const string &extension) const {
92  MutexHolder holder(_lock);
93 
94  string c = downcase(extension);
95  TypeRegistry::const_iterator ti;
96  ti = _type_registry.find(c);
97  if (ti != _type_registry.end()) {
98  return (*ti).second;
99  }
100 
101  // Check the PNM type registry.
103  PNMFileType *type = pnm_reg->get_type_from_extension(c);
104  if (type != (PNMFileType *)NULL) {
105  // This is a known image type; create an ordinary Texture.
106  ((TexturePool *)this)->_type_registry[c] = Texture::make_texture;
107  return Texture::make_texture;
108  }
109 
110  // This is an unknown texture type.
111  return NULL;
112 }
113 
114 ////////////////////////////////////////////////////////////////////
115 // Function: TexturePool::write_texture_types
116 // Access: Public
117 // Description: Outputs a list of the available texture types to the
118 // indicated output stream. This is mostly the list of
119 // available image types, with maybe a few additional
120 // ones for video textures.
121 ////////////////////////////////////////////////////////////////////
122 void TexturePool::
123 write_texture_types(ostream &out, int indent_level) const {
124  MutexHolder holder(_lock);
125 
127  pnm_reg->write(out, indent_level);
128 
129  // Also output any of the additional texture types, that aren't
130  // strictly images (these are typically video textures).
131  TypeRegistry::const_iterator ti;
132  for (ti = _type_registry.begin(); ti != _type_registry.end(); ++ti) {
133  string extension = (*ti).first;
134  MakeTextureFunc *func = (*ti).second;
135 
136  if (pnm_reg->get_type_from_extension(extension) == NULL) {
137  PT(Texture) tex = func();
138  string name = tex->get_type().get_name();
139  indent(out, indent_level) << name;
140  indent(out, max(30 - (int)name.length(), 0))
141  << " ." << extension << "\n";
142  }
143  }
144 }
145 
146 ////////////////////////////////////////////////////////////////////
147 // Function: TexturePool::get_global_ptr
148 // Access: Public, Static
149 // Description: Initializes and/or returns the global pointer to the
150 // one TexturePool object in the system.
151 ////////////////////////////////////////////////////////////////////
154  if (_global_ptr == (TexturePool *)NULL) {
155  _global_ptr = new TexturePool;
156 
157  // We have to call this here, not in the constructor, so that the
158  // _global_ptr is safely assigned by the time the filters begin to
159  // load.
160  _global_ptr->load_filters();
161  }
162  return _global_ptr;
163 }
164 
165 ////////////////////////////////////////////////////////////////////
166 // Function: TexturePool::Constructor
167 // Access: Private
168 // Description: The constructor is not intended to be called
169 // directly; there's only supposed to be one TexturePool
170 // in the universe and it constructs itself.
171 ////////////////////////////////////////////////////////////////////
172 TexturePool::
173 TexturePool() {
174  ConfigVariableFilename fake_texture_image
175  ("fake-texture-image", "",
176  PRC_DESC("Set this to enable a speedy-load mode in which you don't care "
177  "what the world looks like, you just want it to load in minimal "
178  "time. This causes all texture loads via the TexturePool to use "
179  "the same texture file, which will presumably only be loaded "
180  "once."));
181  _fake_texture_image = fake_texture_image;
182 }
183 
184 ////////////////////////////////////////////////////////////////////
185 // Function: TexturePool::ns_has_texture
186 // Access: Private
187 // Description: The nonstatic implementation of has_texture().
188 ////////////////////////////////////////////////////////////////////
189 bool TexturePool::
190 ns_has_texture(const Filename &orig_filename) {
191  MutexHolder holder(_lock);
192 
193  Filename filename;
194  resolve_filename(filename, orig_filename, false, LoaderOptions());
195 
196  Textures::const_iterator ti;
197  ti = _textures.find(filename);
198  if (ti != _textures.end()) {
199  // This texture was previously loaded.
200  return true;
201  }
202 
203  return false;
204 }
205 
206 ////////////////////////////////////////////////////////////////////
207 // Function: TexturePool::ns_load_texture
208 // Access: Private
209 // Description: The nonstatic implementation of load_texture().
210 ////////////////////////////////////////////////////////////////////
211 Texture *TexturePool::
212 ns_load_texture(const Filename &orig_filename, int primary_file_num_channels,
213  bool read_mipmaps, const LoaderOptions &options) {
214  Filename filename;
215 
216  {
217  MutexHolder holder(_lock);
218  resolve_filename(filename, orig_filename, read_mipmaps, options);
219  Textures::const_iterator ti;
220  ti = _textures.find(filename);
221  if (ti != _textures.end()) {
222  // This texture was previously loaded.
223  Texture *tex = (*ti).second;
224  nassertr(!tex->get_fullpath().empty(), tex);
225  return tex;
226  }
227  }
228 
229  // The texture was not found in the pool.
230  PT(Texture) tex;
231  PT(BamCacheRecord) record;
232  bool store_record = false;
233 
234  // Can one of our texture filters supply the texture?
235  tex = pre_load(orig_filename, Filename(), primary_file_num_channels, 0,
236  read_mipmaps, options);
237 
239  bool compressed_cache_record = false;
240  try_load_cache(tex, cache, filename, record, compressed_cache_record,
241  options);
242 
243  if (tex == (Texture *)NULL) {
244  // The texture was neither in the pool, nor found in the on-disk
245  // cache; it needs to be loaded from its source image(s).
246  gobj_cat.info()
247  << "Loading texture " << filename << "\n";
248 
249  string ext = downcase(filename.get_extension());
250  if (ext == "txo" || ext == "bam") {
251  // Assume this is a txo file, which might conceivably contain a
252  // movie file or some other subclass of Texture. In that case,
253  // use make_from_txo() to load it instead of read().
255 
256  filename.set_binary();
257  PT(VirtualFile) file = vfs->get_file(filename);
258  if (file == (VirtualFile *)NULL) {
259  // No such file.
260  gobj_cat.error()
261  << "Could not find " << filename << "\n";
262  return NULL;
263  }
264 
265  if (gobj_cat.is_debug()) {
266  gobj_cat.debug()
267  << "Reading texture object " << filename << "\n";
268  }
269 
270  istream *in = file->open_read_file(true);
271  tex = Texture::make_from_txo(*in, filename);
272  vfs->close_read_file(in);
273 
274  if (tex == (Texture *)NULL) {
275  return NULL;
276  }
277  tex->set_fullpath(filename);
278  tex->clear_alpha_fullpath();
279  tex->set_keep_ram_image(false);
280 
281  } else {
282  // Read it the conventional way.
283  tex = ns_make_texture(ext);
284  if (!tex->read(filename, Filename(), primary_file_num_channels, 0,
285  0, 0, false, read_mipmaps, record, options)) {
286  // This texture was not found or could not be read.
287  report_texture_unreadable(filename);
288  return NULL;
289  }
290  }
291 
292  if (options.get_texture_flags() & LoaderOptions::TF_preload_simple) {
294  }
295 
296  store_record = (record != (BamCacheRecord *)NULL);
297  }
298 
299  if (cache->get_cache_compressed_textures() && tex->has_compression()) {
300 #ifndef HAVE_SQUISH
301  bool needs_driver_compression = true;
302 #else
303  bool needs_driver_compression = driver_compress_textures;
304 #endif // HAVE_SQUISH
305  if (needs_driver_compression) {
306  // We don't want to save the uncompressed version; we'll save the
307  // compressed version when it becomes available.
308  store_record = false;
309  if (!compressed_cache_record) {
310  tex->set_post_load_store_cache(true);
311  }
312  }
313 
314  } else if (!cache->get_cache_textures()) {
315  // We don't want to save this texture.
316  store_record = false;
317  }
318 
319  // Set the original filename, before we searched along the path.
320  nassertr(tex != (Texture *)NULL, NULL);
321  tex->set_filename(orig_filename);
322  tex->set_fullpath(filename);
323  tex->_texture_pool_key = filename;
324 
325  {
326  MutexHolder holder(_lock);
327 
328  // Now look again--someone may have just loaded this texture in
329  // another thread.
330  Textures::const_iterator ti;
331  ti = _textures.find(filename);
332  if (ti != _textures.end()) {
333  // This texture was previously loaded.
334  Texture *tex = (*ti).second;
335  nassertr(!tex->get_fullpath().empty(), tex);
336  return tex;
337  }
338 
339  _textures[filename] = tex;
340  }
341 
342  if (store_record && tex->is_cacheable()) {
343  // Store the on-disk cache record for next time.
344  record->set_data(tex, tex);
345  cache->store(record);
346  }
347 
348  if (!(options.get_texture_flags() & LoaderOptions::TF_preload)) {
349  // And now drop the RAM until we need it.
350  tex->clear_ram_image();
351  }
352 
353  nassertr(!tex->get_fullpath().empty(), tex);
354 
355  // Finally, apply any post-loading texture filters.
356  tex = post_load(tex);
357 
358  return tex;
359 }
360 
361 ////////////////////////////////////////////////////////////////////
362 // Function: TexturePool::ns_load_texture
363 // Access: Private
364 // Description: The nonstatic implementation of load_texture().
365 ////////////////////////////////////////////////////////////////////
366 Texture *TexturePool::
367 ns_load_texture(const Filename &orig_filename,
368  const Filename &orig_alpha_filename,
369  int primary_file_num_channels,
370  int alpha_file_channel,
371  bool read_mipmaps, const LoaderOptions &options) {
372  if (!_fake_texture_image.empty()) {
373  return ns_load_texture(_fake_texture_image, primary_file_num_channels,
374  read_mipmaps, options);
375  }
376 
377  Filename filename;
378  Filename alpha_filename;
379 
380  {
381  MutexHolder holder(_lock);
382  resolve_filename(filename, orig_filename, read_mipmaps, options);
383  resolve_filename(alpha_filename, orig_alpha_filename, read_mipmaps, options);
384 
385  Textures::const_iterator ti;
386  ti = _textures.find(filename);
387  if (ti != _textures.end()) {
388  // This texture was previously loaded.
389  Texture *tex = (*ti).second;
390  nassertr(!tex->get_fullpath().empty(), tex);
391  return tex;
392  }
393  }
394 
395  PT(Texture) tex;
396  PT(BamCacheRecord) record;
397  bool store_record = false;
398 
399  // Can one of our texture filters supply the texture?
400  tex = pre_load(orig_filename, alpha_filename, primary_file_num_channels,
401  alpha_file_channel, read_mipmaps, options);
402 
404  bool compressed_cache_record = false;
405  try_load_cache(tex, cache, filename, record, compressed_cache_record,
406  options);
407 
408  if (tex == (Texture *)NULL) {
409  // The texture was neither in the pool, nor found in the on-disk
410  // cache; it needs to be loaded from its source image(s).
411  gobj_cat.info()
412  << "Loading texture " << filename << " and alpha component "
413  << alpha_filename << endl;
414  tex = ns_make_texture(filename.get_extension());
415  if (!tex->read(filename, alpha_filename, primary_file_num_channels,
416  alpha_file_channel, 0, 0, false, read_mipmaps, NULL,
417  options)) {
418  // This texture was not found or could not be read.
419  report_texture_unreadable(filename);
420  return NULL;
421  }
422 
423  if (options.get_texture_flags() & LoaderOptions::TF_preload_simple) {
425  }
426 
427  store_record = (record != (BamCacheRecord *)NULL);
428  }
429 
430  if (cache->get_cache_compressed_textures() && tex->has_compression()) {
431 #ifndef HAVE_SQUISH
432  bool needs_driver_compression = true;
433 #else
434  bool needs_driver_compression = driver_compress_textures;
435 #endif // HAVE_SQUISH
436  if (needs_driver_compression) {
437  // We don't want to save the uncompressed version; we'll save the
438  // compressed version when it becomes available.
439  store_record = false;
440  if (!compressed_cache_record) {
441  tex->set_post_load_store_cache(true);
442  }
443  }
444 
445  } else if (!cache->get_cache_textures()) {
446  // We don't want to save this texture.
447  store_record = false;
448  }
449 
450  // Set the original filenames, before we searched along the path.
451  nassertr(tex != (Texture *)NULL, NULL);
452  tex->set_filename(orig_filename);
453  tex->set_fullpath(filename);
454  tex->set_alpha_filename(orig_alpha_filename);
455  tex->set_alpha_fullpath(alpha_filename);
456  tex->_texture_pool_key = filename;
457 
458  {
459  MutexHolder holder(_lock);
460 
461  // Now look again.
462  Textures::const_iterator ti;
463  ti = _textures.find(filename);
464  if (ti != _textures.end()) {
465  // This texture was previously loaded.
466  Texture *tex = (*ti).second;
467  nassertr(!tex->get_fullpath().empty(), tex);
468  return tex;
469  }
470 
471  _textures[filename] = tex;
472  }
473 
474  if (store_record && tex->is_cacheable()) {
475  // Store the on-disk cache record for next time.
476  record->set_data(tex, tex);
477  cache->store(record);
478  }
479 
480  if (!(options.get_texture_flags() & LoaderOptions::TF_preload)) {
481  // And now drop the RAM until we need it.
482  tex->clear_ram_image();
483  }
484 
485  nassertr(!tex->get_fullpath().empty(), tex);
486 
487  // Finally, apply any post-loading texture filters.
488  tex = post_load(tex);
489 
490  return tex;
491 }
492 
493 ////////////////////////////////////////////////////////////////////
494 // Function: TexturePool::ns_load_3d_texture
495 // Access: Private
496 // Description: The nonstatic implementation of load_3d_texture().
497 ////////////////////////////////////////////////////////////////////
498 Texture *TexturePool::
499 ns_load_3d_texture(const Filename &filename_pattern,
500  bool read_mipmaps, const LoaderOptions &options) {
501  Filename orig_filename(filename_pattern);
502  orig_filename.set_pattern(true);
503 
504  Filename filename;
505  {
506  MutexHolder holder(_lock);
507  resolve_filename(filename, orig_filename, read_mipmaps, options);
508 
509  Textures::const_iterator ti;
510  ti = _textures.find(filename);
511  if (ti != _textures.end()) {
512  if ((*ti).second->get_texture_type() == Texture::TT_3d_texture) {
513  // This texture was previously loaded, as a 3d texture
514  return (*ti).second;
515  }
516  }
517  }
518 
519  PT(Texture) tex;
520  PT(BamCacheRecord) record;
521  bool store_record = false;
522 
524  bool compressed_cache_record = false;
525  try_load_cache(tex, cache, filename, record, compressed_cache_record,
526  options);
527 
528  if (tex == (Texture *)NULL ||
529  tex->get_texture_type() != Texture::TT_3d_texture) {
530  // The texture was neither in the pool, nor found in the on-disk
531  // cache; it needs to be loaded from its source image(s).
532  gobj_cat.info()
533  << "Loading 3-d texture " << filename << "\n";
534  tex = ns_make_texture(filename.get_extension());
535  tex->setup_3d_texture();
536  if (!tex->read(filename, 0, 0, true, read_mipmaps, options)) {
537  // This texture was not found or could not be read.
538  report_texture_unreadable(filename);
539  return NULL;
540  }
541  store_record = (record != (BamCacheRecord *)NULL);
542  }
543 
544  if (cache->get_cache_compressed_textures() && tex->has_compression()) {
545 #ifndef HAVE_SQUISH
546  bool needs_driver_compression = true;
547 #else
548  bool needs_driver_compression = driver_compress_textures;
549 #endif // HAVE_SQUISH
550  if (needs_driver_compression) {
551  // We don't want to save the uncompressed version; we'll save the
552  // compressed version when it becomes available.
553  store_record = false;
554  if (!compressed_cache_record) {
555  tex->set_post_load_store_cache(true);
556  }
557  }
558 
559  } else if (!cache->get_cache_textures()) {
560  // We don't want to save this texture.
561  store_record = false;
562  }
563 
564  // Set the original filename, before we searched along the path.
565  nassertr(tex != (Texture *)NULL, NULL);
566  tex->set_filename(filename_pattern);
567  tex->set_fullpath(filename);
568  tex->_texture_pool_key = filename;
569 
570  {
571  MutexHolder holder(_lock);
572 
573  // Now look again.
574  Textures::const_iterator ti;
575  ti = _textures.find(filename);
576  if (ti != _textures.end()) {
577  if ((*ti).second->get_texture_type() == Texture::TT_3d_texture) {
578  // This texture was previously loaded, as a 3d texture
579  return (*ti).second;
580  }
581  }
582 
583  _textures[filename] = tex;
584  }
585 
586  if (store_record && tex->is_cacheable()) {
587  // Store the on-disk cache record for next time.
588  record->set_data(tex, tex);
589  cache->store(record);
590  }
591 
592  nassertr(!tex->get_fullpath().empty(), tex);
593  return tex;
594 }
595 
596 ////////////////////////////////////////////////////////////////////
597 // Function: TexturePool::ns_load_2d_texture_array
598 // Access: Private
599 // Description: The nonstatic implementation of load_2d_texture_array().
600 ////////////////////////////////////////////////////////////////////
601 Texture *TexturePool::
602 ns_load_2d_texture_array(const Filename &filename_pattern,
603  bool read_mipmaps, const LoaderOptions &options) {
604  Filename orig_filename(filename_pattern);
605  orig_filename.set_pattern(true);
606 
607  Filename filename;
608  Filename unique_filename; //differentiate 3d-textures from 2d-texture arrays
609  {
610  MutexHolder holder(_lock);
611  resolve_filename(filename, orig_filename, read_mipmaps, options);
612  // Differentiate from preloaded 3d textures
613  unique_filename = filename + ".2DARRAY";
614 
615  Textures::const_iterator ti;
616  ti = _textures.find(unique_filename);
617  if (ti != _textures.end()) {
618  if ((*ti).second->get_texture_type() == Texture::TT_2d_texture_array) {
619  // This texture was previously loaded, as a 2d texture array
620  return (*ti).second;
621  }
622  }
623  }
624 
625  PT(Texture) tex;
626  PT(BamCacheRecord) record;
627  bool store_record = false;
628 
630  bool compressed_cache_record = false;
631  try_load_cache(tex, cache, filename, record, compressed_cache_record,
632  options);
633 
634  if (tex == (Texture *)NULL ||
635  tex->get_texture_type() != Texture::TT_2d_texture_array) {
636  // The texture was neither in the pool, nor found in the on-disk
637  // cache; it needs to be loaded from its source image(s).
638  gobj_cat.info()
639  << "Loading 2-d texture array " << filename << "\n";
640  tex = ns_make_texture(filename.get_extension());
641  tex->setup_2d_texture_array();
642  if (!tex->read(filename, 0, 0, true, read_mipmaps, options)) {
643  // This texture was not found or could not be read.
644  report_texture_unreadable(filename);
645  return NULL;
646  }
647  store_record = (record != (BamCacheRecord *)NULL);
648  }
649 
650  if (cache->get_cache_compressed_textures() && tex->has_compression()) {
651 #ifndef HAVE_SQUISH
652  bool needs_driver_compression = true;
653 #else
654  bool needs_driver_compression = driver_compress_textures;
655 #endif // HAVE_SQUISH
656  if (needs_driver_compression) {
657  // We don't want to save the uncompressed version; we'll save the
658  // compressed version when it becomes available.
659  store_record = false;
660  if (!compressed_cache_record) {
661  tex->set_post_load_store_cache(true);
662  }
663  }
664 
665  } else if (!cache->get_cache_textures()) {
666  // We don't want to save this texture.
667  store_record = false;
668  }
669 
670  // Set the original filename, before we searched along the path.
671  nassertr(tex != (Texture *)NULL, NULL);
672  tex->set_filename(filename_pattern);
673  tex->set_fullpath(filename);
674  tex->_texture_pool_key = unique_filename;
675 
676  {
677  MutexHolder holder(_lock);
678 
679  // Now look again.
680  Textures::const_iterator ti;
681  ti = _textures.find(unique_filename);
682  if (ti != _textures.end()) {
683  if ((*ti).second->get_texture_type() == Texture::TT_2d_texture_array) {
684  // This texture was previously loaded, as a 2d texture array
685  return (*ti).second;
686  }
687  }
688 
689  _textures[unique_filename] = tex;
690  }
691 
692  if (store_record && tex->is_cacheable()) {
693  // Store the on-disk cache record for next time.
694  record->set_data(tex, tex);
695  cache->store(record);
696  }
697 
698  nassertr(!tex->get_fullpath().empty(), tex);
699  return tex;
700 }
701 
702 ////////////////////////////////////////////////////////////////////
703 // Function: TexturePool::ns_load_cube_map
704 // Access: Private
705 // Description: The nonstatic implementation of load_cube_map().
706 ////////////////////////////////////////////////////////////////////
707 Texture *TexturePool::
708 ns_load_cube_map(const Filename &filename_pattern, bool read_mipmaps,
709  const LoaderOptions &options) {
710  Filename orig_filename(filename_pattern);
711  orig_filename.set_pattern(true);
712 
713  Filename filename;
714  {
715  MutexHolder holder(_lock);
716  resolve_filename(filename, orig_filename, read_mipmaps, options);
717 
718  Textures::const_iterator ti;
719  ti = _textures.find(filename);
720  if (ti != _textures.end()) {
721  // This texture was previously loaded.
722  return (*ti).second;
723  }
724  }
725 
726  PT(Texture) tex;
727  PT(BamCacheRecord) record;
728  bool store_record = false;
729 
731  bool compressed_cache_record = false;
732  try_load_cache(tex, cache, filename, record, compressed_cache_record,
733  options);
734 
735  if (tex == (Texture *)NULL ||
736  tex->get_texture_type() != Texture::TT_cube_map) {
737  // The texture was neither in the pool, nor found in the on-disk
738  // cache; it needs to be loaded from its source image(s).
739  gobj_cat.info()
740  << "Loading cube map texture " << filename << "\n";
741  tex = ns_make_texture(filename.get_extension());
742  tex->setup_cube_map();
743  if (!tex->read(filename, 0, 0, true, read_mipmaps, options)) {
744  // This texture was not found or could not be read.
745  report_texture_unreadable(filename);
746  return NULL;
747  }
748  store_record = (record != (BamCacheRecord *)NULL);
749  }
750 
751  if (cache->get_cache_compressed_textures() && tex->has_compression()) {
752 #ifndef HAVE_SQUISH
753  bool needs_driver_compression = true;
754 #else
755  bool needs_driver_compression = driver_compress_textures;
756 #endif // HAVE_SQUISH
757  if (needs_driver_compression) {
758  // We don't want to save the uncompressed version; we'll save the
759  // compressed version when it becomes available.
760  store_record = false;
761  if (!compressed_cache_record) {
762  tex->set_post_load_store_cache(true);
763  }
764  }
765 
766  } else if (!cache->get_cache_textures()) {
767  // We don't want to save this texture.
768  store_record = false;
769  }
770 
771  // Set the original filename, before we searched along the path.
772  nassertr(tex != (Texture *)NULL, NULL);
773  tex->set_filename(filename_pattern);
774  tex->set_fullpath(filename);
775  tex->_texture_pool_key = filename;
776 
777  {
778  MutexHolder holder(_lock);
779 
780  // Now look again.
781  Textures::const_iterator ti;
782  ti = _textures.find(filename);
783  if (ti != _textures.end()) {
784  // This texture was previously loaded.
785  return (*ti).second;
786  }
787 
788  _textures[filename] = tex;
789  }
790 
791  if (store_record && tex->is_cacheable()) {
792  // Store the on-disk cache record for next time.
793  record->set_data(tex, tex);
794  cache->store(record);
795  }
796 
797  nassertr(!tex->get_fullpath().empty(), tex);
798  return tex;
799 }
800 
801 ////////////////////////////////////////////////////////////////////
802 // Function: TexturePool::ns_get_normalization_cube_map
803 // Access: Private
804 // Description: The nonstatic implementation of get_normalization_cube_map().
805 ////////////////////////////////////////////////////////////////////
806 Texture *TexturePool::
807 ns_get_normalization_cube_map(int size) {
808  MutexHolder holder(_lock);
809 
810  if (_normalization_cube_map == (Texture *)NULL) {
811  _normalization_cube_map = new Texture("normalization_cube_map");
812  }
813  if (_normalization_cube_map->get_x_size() < size ||
814  _normalization_cube_map->get_texture_type() != Texture::TT_cube_map) {
815  _normalization_cube_map->generate_normalization_cube_map(size);
816  }
817 
818  return _normalization_cube_map;
819 }
820 
821 ////////////////////////////////////////////////////////////////////
822 // Function: TexturePool::ns_get_alpha_scale_map
823 // Access: Private
824 // Description: The nonstatic implementation of get_alpha_scale_map().
825 ////////////////////////////////////////////////////////////////////
826 Texture *TexturePool::
827 ns_get_alpha_scale_map() {
828  MutexHolder holder(_lock);
829 
830  if (_alpha_scale_map == (Texture *)NULL) {
831  _alpha_scale_map = new Texture("alpha_scale_map");
832  _alpha_scale_map->generate_alpha_scale_map();
833  }
834 
835  return _alpha_scale_map;
836 }
837 
838 ////////////////////////////////////////////////////////////////////
839 // Function: TexturePool::ns_add_texture
840 // Access: Private
841 // Description: The nonstatic implementation of add_texture().
842 ////////////////////////////////////////////////////////////////////
843 void TexturePool::
844 ns_add_texture(Texture *tex) {
845  PT(Texture) keep = tex;
846  MutexHolder holder(_lock);
847 
848  if (!tex->_texture_pool_key.empty()) {
849  ns_release_texture(tex);
850  }
851  string filename = tex->get_fullpath();
852  if (filename.empty()) {
853  gobj_cat.error() << "Attempt to call add_texture() on an unnamed texture.\n";
854  }
855 
856  // We blow away whatever texture was there previously, if any.
857  tex->_texture_pool_key = filename;
858  _textures[filename] = tex;
859  nassertv(!tex->get_fullpath().empty());
860 }
861 
862 ////////////////////////////////////////////////////////////////////
863 // Function: TexturePool::ns_release_texture
864 // Access: Private
865 // Description: The nonstatic implementation of release_texture().
866 ////////////////////////////////////////////////////////////////////
867 void TexturePool::
868 ns_release_texture(Texture *tex) {
869  MutexHolder holder(_lock);
870 
871  if (!tex->_texture_pool_key.empty()) {
872  Textures::iterator ti;
873  ti = _textures.find(tex->_texture_pool_key);
874  if (ti != _textures.end() && (*ti).second == tex) {
875  _textures.erase(ti);
876  }
877  tex->_texture_pool_key = string();
878  }
879 
880  // Blow away the cache of resolved relative filenames.
881  _relpath_lookup.clear();
882 }
883 
884 ////////////////////////////////////////////////////////////////////
885 // Function: TexturePool::ns_release_all_textures
886 // Access: Private
887 // Description: The nonstatic implementation of release_all_textures().
888 ////////////////////////////////////////////////////////////////////
889 void TexturePool::
890 ns_release_all_textures() {
891  MutexHolder holder(_lock);
892 
893  Textures::iterator ti;
894  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
895  Texture *tex = (*ti).second;
896  tex->_texture_pool_key = string();
897  }
898 
899  _textures.clear();
900  _normalization_cube_map = NULL;
901 
902  // Blow away the cache of resolved relative filenames.
903  _relpath_lookup.clear();
904 }
905 
906 ////////////////////////////////////////////////////////////////////
907 // Function: TexturePool::ns_garbage_collect
908 // Access: Private
909 // Description: The nonstatic implementation of garbage_collect().
910 ////////////////////////////////////////////////////////////////////
911 int TexturePool::
912 ns_garbage_collect() {
913  MutexHolder holder(_lock);
914 
915  int num_released = 0;
916  Textures new_set;
917 
918  Textures::iterator ti;
919  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
920  Texture *tex = (*ti).second;
921  if (tex->get_ref_count() == 1) {
922  if (gobj_cat.is_debug()) {
923  gobj_cat.debug()
924  << "Releasing " << (*ti).first << "\n";
925  }
926  ++num_released;
927  tex->_texture_pool_key = string();
928  } else {
929  new_set.insert(new_set.end(), *ti);
930  }
931  }
932 
933  _textures.swap(new_set);
934 
935  if (_normalization_cube_map != (Texture *)NULL &&
936  _normalization_cube_map->get_ref_count() == 1) {
937  if (gobj_cat.is_debug()) {
938  gobj_cat.debug()
939  << "Releasing normalization cube map\n";
940  }
941  ++num_released;
942  _normalization_cube_map = NULL;
943  }
944 
945  return num_released;
946 }
947 
948 ////////////////////////////////////////////////////////////////////
949 // Function: TexturePool::ns_list_contents
950 // Access: Private
951 // Description: The nonstatic implementation of list_contents().
952 ////////////////////////////////////////////////////////////////////
953 void TexturePool::
954 ns_list_contents(ostream &out) const {
955  MutexHolder holder(_lock);
956 
957  int total_size;
958  int total_ram_size;
959  Textures::const_iterator ti;
960 
961  out << "texture pool contents:\n";
962 
963  total_size = 0;
964  total_ram_size = 0;
965  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
966  Texture *tex = (*ti).second;
967  out << (*ti).first << "\n";
968  out << " (count = " << tex->get_ref_count()
969  << ", ram = " << tex->get_ram_image_size()
970  << ", size = " << tex->get_ram_page_size()
971  << ", w = " << tex->get_x_size()
972  << ", h = " << tex->get_y_size()
973  << ")\n";
974  nassertv(tex->_texture_pool_key == (*ti).first);
975  total_ram_size += tex->get_ram_image_size();
976  total_size += tex->get_ram_page_size();
977  }
978 
979  out << "total number of textures: " << _textures.size() << "\n";
980  out << "texture pool ram : " << total_ram_size << "\n";
981  out << "texture pool size: " << total_size << "\n";
982  out << "texture pool size - texture pool ram: " << total_size - total_ram_size << "\n";
983 }
984 
985 ////////////////////////////////////////////////////////////////////
986 // Function: TexturePool::ns_find_texture
987 // Access: Private
988 // Description: The nonstatic implementation of find_texture().
989 ////////////////////////////////////////////////////////////////////
990 Texture *TexturePool::
991 ns_find_texture(const string &name) const {
992  MutexHolder holder(_lock);
993  GlobPattern glob(name);
994 
995  Textures::const_iterator ti;
996  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
997  Texture *tex = (*ti).second;
998  if (glob.matches(tex->get_name())) {
999  return tex;
1000  }
1001  }
1002 
1003  return NULL;
1004 }
1005 
1006 ////////////////////////////////////////////////////////////////////
1007 // Function: TexturePool::ns_find_all_textures
1008 // Access: Private
1009 // Description: The nonstatic implementation of find_all_textures().
1010 ////////////////////////////////////////////////////////////////////
1011 TextureCollection TexturePool::
1012 ns_find_all_textures(const string &name) const {
1013  MutexHolder holder(_lock);
1014  TextureCollection result;
1015  GlobPattern glob(name);
1016 
1017  Textures::const_iterator ti;
1018  for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
1019  Texture *tex = (*ti).second;
1020  if (glob.matches(tex->get_name())) {
1021  result.add_texture(tex);
1022  }
1023  }
1024 
1025  return result;
1026 }
1027 
1028 ////////////////////////////////////////////////////////////////////
1029 // Function: TexturePool::ns_make_texture
1030 // Access: Public
1031 // Description: Creates a new Texture object of the appropriate type
1032 // for the indicated filename extension, according to
1033 // the types that have been registered via
1034 // register_texture_type().
1035 ////////////////////////////////////////////////////////////////////
1036 PT(Texture) TexturePool::
1037 ns_make_texture(const string &extension) const {
1038  MakeTextureFunc *func = get_texture_type(extension);
1039  if (func != NULL) {
1040  return func();
1041  }
1042 
1043  // We don't know what kind of file type this is; return an ordinary
1044  // Texture in case it's an image file with no extension.
1045  return new Texture;
1046 }
1047 
1048 ////////////////////////////////////////////////////////////////////
1049 // Function: TexturePool::resolve_filename
1050 // Access: Private
1051 // Description: Searches for the indicated filename along the
1052 // model path. If the filename was previously
1053 // searched for, doesn't search again, as an
1054 // optimization. Assumes _lock is held.
1055 ////////////////////////////////////////////////////////////////////
1056 void TexturePool::
1057 resolve_filename(Filename &new_filename, const Filename &orig_filename,
1058  bool read_mipmaps, const LoaderOptions &options) {
1059  if (!_fake_texture_image.empty()) {
1060  new_filename = _fake_texture_image;
1061  return;
1062  }
1063 
1064  RelpathLookup::iterator rpi = _relpath_lookup.find(orig_filename);
1065  if (rpi != _relpath_lookup.end()) {
1066  new_filename = (*rpi).second;
1067  return;
1068  }
1069 
1070  new_filename = orig_filename;
1071  if (read_mipmaps || (options.get_texture_flags() & LoaderOptions::TF_multiview)) {
1072  new_filename.set_pattern(true);
1073  }
1074 
1076  vfs->resolve_filename(new_filename, get_model_path());
1077 
1078  _relpath_lookup[orig_filename] = new_filename;
1079 }
1080 
1081 ////////////////////////////////////////////////////////////////////
1082 // Function: TexturePool::try_load_cache
1083 // Access: Private
1084 // Description: Attempts to load the texture from the cache record.
1085 ////////////////////////////////////////////////////////////////////
1086 void TexturePool::
1087 try_load_cache(PT(Texture) &tex, BamCache *cache, const Filename &filename,
1088  PT(BamCacheRecord) &record, bool &compressed_cache_record,
1089  const LoaderOptions &options) {
1090  if (tex == (Texture *)NULL) {
1091  // The texture was not supplied by a texture filter. See if it
1092  // can be found in the on-disk cache, if it is active.
1093  if ((cache->get_cache_textures() || cache->get_cache_compressed_textures()) && !textures_header_only) {
1094 
1095  // Call ns_make_texture() on the file extension and create a
1096  // dummy texture object we can call ensure_loaded_type() on. We
1097  // don't need to keep this object around after this call, since
1098  // we'll be creating a new one below. I know this is a bit
1099  // hacky.
1100  string ext = downcase(filename.get_extension());
1101  PT(Texture) dummy = ns_make_texture(ext);
1102  dummy->ensure_loader_type(filename);
1103  dummy.clear();
1104 
1105  record = cache->lookup(filename, "txo");
1106  if (record != (BamCacheRecord *)NULL) {
1107  if (record->has_data()) {
1108  tex = DCAST(Texture, record->get_data());
1109  compressed_cache_record = (tex->get_ram_image_compression() != Texture::CM_off);
1110  int x_size = tex->get_orig_file_x_size();
1111  int y_size = tex->get_orig_file_y_size();
1112  tex->adjust_this_size(x_size, y_size, filename.get_basename(), true);
1113 
1114  if (!cache->get_cache_textures() && !compressed_cache_record) {
1115  // We're not supposed to be caching uncompressed textures.
1116  if (gobj_cat.is_debug()) {
1117  gobj_cat.debug()
1118  << "Not caching uncompressed texture " << *tex << "\n";
1119  }
1120  tex = NULL;
1121  record = NULL;
1122 
1123  } else if (x_size != tex->get_x_size() ||
1124  y_size != tex->get_y_size()) {
1125  // The cached texture no longer matches our expected size
1126  // (the resizing config variables must have changed).
1127  // We'll have to reload the texture from its original file
1128  // so we can rebuild the cache.
1129  if (gobj_cat.is_debug()) {
1130  gobj_cat.debug()
1131  << "Cached texture " << *tex << " has size "
1132  << tex->get_x_size() << " x " << tex->get_y_size()
1133  << " instead of " << x_size << " x " << y_size
1134  << "; dropping cache.\n";
1135  }
1136  tex = NULL;
1137 
1138  } else if (!tex->has_compression() && tex->get_ram_image_compression() != Texture::CM_off) {
1139  // This texture shouldn't be compressed, but it is. Go
1140  // reload it.
1141  if (gobj_cat.is_debug()) {
1142  gobj_cat.debug()
1143  << "Cached texture " << *tex
1144  << " is compressed in cache; dropping cache.\n";
1145  }
1146  tex = NULL;
1147 
1148  } else {
1149  gobj_cat.info()
1150  << "Texture " << filename << " found in disk cache.\n";
1151  if ((options.get_texture_flags() & LoaderOptions::TF_preload_simple) &&
1152  !tex->has_simple_ram_image()) {
1154  }
1155  if (!(options.get_texture_flags() & LoaderOptions::TF_preload)) {
1156  // But drop the RAM until we need it.
1157  tex->clear_ram_image();
1158 
1159  } else {
1160  bool was_compressed = (tex->get_ram_image_compression() != Texture::CM_off);
1161  if (tex->consider_auto_process_ram_image(tex->uses_mipmaps(), true)) {
1162  bool is_compressed = (tex->get_ram_image_compression() != Texture::CM_off);
1163  if (!was_compressed && is_compressed &&
1164  cache->get_cache_compressed_textures()) {
1165  // We've re-compressed the image after loading it
1166  // from the cache. To keep the cache current,
1167  // rewrite it to the cache now, in its newly
1168  // compressed form.
1169  record->set_data(tex, tex);
1170  cache->store(record);
1171  compressed_cache_record = true;
1172  }
1173  }
1174  }
1175  tex->set_keep_ram_image(false);
1176  }
1177  } else {
1178  if (!cache->get_cache_textures()) {
1179  // This texture has no actual record, and therefore no
1180  // compressed record (yet). And we're not supposed to be
1181  // caching uncompressed textures.
1182  if (gobj_cat.is_debug()) {
1183  gobj_cat.debug()
1184  << "Not caching uncompressed texture\n";
1185  }
1186  record = NULL;
1187  }
1188  }
1189  }
1190  }
1191  }
1192 }
1193 
1194 ////////////////////////////////////////////////////////////////////
1195 // Function: TexturePool::report_texture_unreadable
1196 // Access: Private
1197 // Description: Prints a suitable error message when a texture could
1198 // not be loaded.
1199 ////////////////////////////////////////////////////////////////////
1200 void TexturePool::
1201 report_texture_unreadable(const Filename &filename) const {
1203  bool has_hash = (filename.get_fullpath().find('#') != string::npos);
1204  if (!has_hash && !vfs->exists(filename)) {
1205  if (filename.is_local()) {
1206  // The file doesn't exist, and it wasn't
1207  // fully-qualified--therefore, it wasn't found along either
1208  // search path.
1209  gobj_cat.error()
1210  << "Unable to find texture \"" << filename << "\""
1211  << " on model-path " << get_model_path() <<"\n";
1212  } else {
1213  // A fully-specified filename is not searched along the path, so
1214  // don't mislead the user with the error message.
1215  gobj_cat.error()
1216  << "Texture \"" << filename << "\" does not exist.\n";
1217  }
1218 
1219  } else {
1220  // The file exists, but it couldn't be read for some reason.
1221  if (!has_hash) {
1222  gobj_cat.error()
1223  << "Texture \"" << filename << "\" exists but cannot be read.\n";
1224  } else {
1225  // If the filename contains a hash, we'll be noncommittal about
1226  // whether it exists or not.
1227  gobj_cat.error()
1228  << "Texture \"" << filename << "\" cannot be read.\n";
1229  }
1230 
1231  // Maybe the filename extension is unknown.
1232  MakeTextureFunc *func = get_texture_type(filename.get_extension());
1233  if (func == (MakeTextureFunc *)NULL) {
1234  gobj_cat.error()
1235  << "Texture extension \"" << filename.get_extension()
1236  << "\" is unknown. Supported texture types:\n";
1237  write_texture_types(gobj_cat.error(false), 2);
1238  }
1239  }
1240 }
1241 
1242 ////////////////////////////////////////////////////////////////////
1243 // Function: TexturePool::pre_load
1244 // Access: Private
1245 // Description: Invokes pre_load() on all registered filters until
1246 // one returns non-NULL; returns NULL if there are no
1247 // registered filters or if all registered filters
1248 // returned NULL.
1249 ////////////////////////////////////////////////////////////////////
1250 PT(Texture) TexturePool::
1251 pre_load(const Filename &orig_filename, const Filename &orig_alpha_filename,
1252  int primary_file_num_channels, int alpha_file_channel,
1253  bool read_mipmaps, const LoaderOptions &options) {
1254  PT(Texture) tex;
1255 
1256  MutexHolder holder(_lock);
1257 
1258  FilterRegistry::iterator fi;
1259  for (fi = _filter_registry.begin();
1260  fi != _filter_registry.end();
1261  ++fi) {
1262  tex = (*fi)->pre_load(orig_filename, orig_alpha_filename,
1263  primary_file_num_channels, alpha_file_channel,
1264  read_mipmaps, options);
1265  if (tex != (Texture *)NULL) {
1266  return tex;
1267  }
1268  }
1269 
1270  return tex;
1271 }
1272 
1273 ////////////////////////////////////////////////////////////////////
1274 // Function: TexturePool::post_load
1275 // Access: Public, Virtual
1276 // Description: Invokes post_load() on all registered filters.
1277 ////////////////////////////////////////////////////////////////////
1278 PT(Texture) TexturePool::
1279 post_load(Texture *tex) {
1280  PT(Texture) result = tex;
1281 
1282  MutexHolder holder(_lock);
1283 
1284  FilterRegistry::iterator fi;
1285  for (fi = _filter_registry.begin();
1286  fi != _filter_registry.end();
1287  ++fi) {
1288  result = (*fi)->post_load(result);
1289  }
1290 
1291  return result;
1292 }
1293 
1294 
1295 ////////////////////////////////////////////////////////////////////
1296 // Function: TexturePool::load_filters
1297 // Access: Private
1298 // Description: Loads up all of the dll's named by the texture-filter
1299 // Config.prc variable.
1300 ////////////////////////////////////////////////////////////////////
1301 void TexturePool::
1302 load_filters() {
1303  ConfigVariableList texture_filter
1304  ("texture-filter",
1305  PRC_DESC("Names one or more external libraries that should be loaded for the "
1306  "purposes of performing texture filtering. This variable may be repeated several "
1307  "times. As in load-display, the actual library filename is derived by "
1308  "prefixing 'lib' to the specified name."));
1309 
1310  int num_aux = texture_filter.get_num_unique_values();
1311  for (int i = 0; i < num_aux; i++) {
1312  string name = texture_filter.get_unique_value(i);
1313 
1314  Filename dlname = Filename::dso_filename("lib" + name + ".so");
1315  gobj_cat->info()
1316  << "loading texture filter: " << dlname.to_os_specific() << endl;
1317  void *tmp = load_dso(get_plugin_path().get_value(), dlname);
1318  if (tmp == (void *)NULL) {
1319  gobj_cat.info()
1320  << "Unable to load: " << load_dso_error() << endl;
1321  }
1322  }
1323 }
void set_data(TypedWritable *ptr, ReferenceCount *ref_ptr)
Stores a new data object on the record.
bool matches(const string &candidate) const
Returns true if the candidate string matches the pattern, false otherwise.
Definition: globPattern.I:157
string get_basename() const
Returns the basename part of the filename.
Definition: filename.I:436
const Filename & get_fullpath() const
Returns the fullpath that has been set.
Definition: texture.I:600
bool resolve_filename(Filename &filename, const DSearchPath &searchpath, const string &default_extension=string()) const
Searches the given search path for the filename.
TypedWritable * get_data() const
Returns a pointer to the data stored in the record, or NULL if there is no data.
TextureType get_texture_type() const
Returns the overall interpretation of the texture.
Definition: texture.I:859
size_t get_ram_image_size() const
Returns the total number of bytes used by the in-memory image, across all pages and views...
Definition: texture.I:1507
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:978
string get_fullpath() const
Returns the entire filename: directory, basename, extension.
Definition: filename.I:398
int get_orig_file_y_size() const
Returns the Y size of the original disk image that this Texture was loaded from (if it came from a di...
Definition: texture.I:805
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
This is a convenience class to specialize ConfigVariable as a Filename type.
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.
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
void set_binary()
Indicates that the filename represents a binary file.
Definition: filename.I:494
void set_post_load_store_cache(bool flag)
Sets the post_load_store_cache flag.
Definition: texture.I:2573
This is the base class of a family of classes that represent particular image file types that PNMImag...
Definition: pnmFileType.h:35
void clear_alpha_fullpath()
Removes the alpha fullpath, if it was previously set.
Definition: texture.I:2366
string get_name(TypedObject *object=(TypedObject *) NULL) const
Returns the name of the type.
Definition: typeHandle.I:132
bool get_cache_textures() const
Returns whether texture files (e.g.
Definition: bamCache.I:100
A lightweight C++ object whose constructor calls acquire() and whose destructor calls release() on a ...
Definition: mutexHolder.h:29
void add_texture(Texture *texture)
Adds a new Texture to the collection.
The abstract base class for a file or directory within the VirtualFileSystem.
Definition: virtualFile.h:37
This class is similar to ConfigVariable, but it reports its value as a list of strings.
void register_filter(TexturePoolFilter *filter)
Records a TexturePoolFilter object that may operate on texture images as they are loaded from disk...
Definition: texturePool.cxx:74
string get_extension() const
Returns the file extension.
Definition: filename.I:477
void setup_cube_map()
Sets the texture as an empty cube map texture with no dimensions.
Definition: texture.I:196
void set_alpha_fullpath(const Filename &alpha_fullpath)
Sets the full pathname to the file that contains the image&#39;s alpha channel contents, as found along the search path.
Definition: texture.I:2354
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().
void set_fullpath(const Filename &fullpath)
Sets the full pathname to the file that contains the image&#39;s contents, as found along the search path...
Definition: texture.I:2327
int get_orig_file_x_size() const
Returns the X size of the original disk image that this Texture was loaded from (if it came from a di...
Definition: texture.I:792
static PNMFileTypeRegistry * get_global_ptr()
Returns a pointer to the global PNMFileTypeRegistry object.
size_t get_ram_page_size() const
Returns the number of bytes used by the in-memory image per page, or 0 if there is no in-memory image...
Definition: texture.I:1543
bool store(BamCacheRecord *record)
Flushes a cache entry to disk.
Definition: bamCache.cxx:194
bool uses_mipmaps() const
Returns true if the minfilter settings on this texture indicate the use of mipmapping, false otherwise.
Definition: texture.I:1319
bool exists(const Filename &filename) const
Convenience function; returns true if the named file exists.
void setup_3d_texture(int z_size=1)
Sets the texture as an empty 3-d texture with no dimensions (though if you know the depth ahead of ti...
Definition: texture.I:138
void register_texture_type(MakeTextureFunc *func, const string &extensions)
Records a factory function that makes a Texture object of the appropriate type for one or more partic...
Definition: texturePool.cxx:55
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
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
An instance of this class is written to the front of a Bam or Txo file to make the file a cached inst...
MakeTextureFunc * get_texture_type(const string &extension) const
Returns the factory function to construct a new texture of the type appropriate for the indicated fil...
Definition: texturePool.cxx:91
void setup_2d_texture_array(int z_size=1)
Sets the texture as an empty 2-d texture array with no dimensions (though if you know the depth ahead...
Definition: texture.I:167
string get_unique_value(int n) const
Returns the nth unique value of the variable.
void set_keep_ram_image(bool keep_ram_image)
Sets the flag that indicates whether this Texture is eligible to have its main RAM copy of the textur...
Definition: texture.I:1731
bool has_simple_ram_image() const
Returns true if the Texture has a "simple" image available in main RAM.
Definition: texture.I:2053
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
void set_alpha_filename(const Filename &alpha_filename)
Sets the name of the file that contains the image&#39;s alpha channel contents.
Definition: texture.I:2301
Manages a list of Texture objects, as returned by TexturePool::find_all_textures().
PointerTo< VirtualFile > get_file(const Filename &filename, bool status_only=false) const
Looks up the file by the indicated name in the file system.
PNMFileType * get_type_from_extension(const string &filename) const
Tries to determine what the PNMFileType is likely to be for a particular image file based on its exte...
bool is_local() const
Returns true if the filename is local, e.g.
Definition: filename.I:664
static TexturePool * get_global_ptr()
Initializes and/or returns the global pointer to the one TexturePool object in the system...
void clear_ram_image()
Discards the current system-RAM image.
Definition: texture.I:1710
int get_ref_count() const
Returns the current reference count.
static void write(ostream &out)
Lists the contents of the texture pool to the indicated output stream.
Definition: texturePool.cxx:41
CompressionMode get_ram_image_compression() const
Returns the compression mode in which the ram image is already stored pre-compressed.
Definition: texture.I:1624
This class maintains the set of all known PNMFileTypes in the universe.
void generate_simple_ram_image()
Computes the "simple" ram image by loading the main RAM image, if it is not already available...
Definition: texture.cxx:1171
int get_y_size() const
Returns the height of the texture image in texels.
Definition: texture.I:650
int get_num_unique_values() const
Returns the number of unique values in the variable.
bool read(const Filename &fullpath, const LoaderOptions &options=LoaderOptions())
Reads the named filename into the texture.
Definition: texture.cxx:338
This is an abstract base class, a placeholder for any number of different classes that may wish to im...
This is the preferred interface for loading textures from image files.
Definition: texturePool.h:40
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
void write_texture_types(ostream &out, int indent_level) const
Outputs a list of the available texture types to the indicated output stream.
string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...
Definition: filename.cxx:1196
bool adjust_this_size(int &x_size, int &y_size, const string &name, bool for_padding) const
Works like adjust_size, but also considers the texture class.
Definition: texture.I:2604
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 write(ostream &out, int indent_level=0) const
Writes a list of supported image file types to the indicated output stream, one per line...
void set_pattern(bool pattern)
Sets the flag indicating whether this is a filename pattern.
Definition: filename.I:606
void set_filename(const Filename &filename)
Sets the name of the file that contains the image&#39;s contents.
Definition: texture.I:2267
This class can be used to test for string matches against standard Unix-shell filename globbing conve...
Definition: globPattern.h:37
int get_x_size() const
Returns the width of the texture image in texels.
Definition: texture.I:638