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