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::
70 register_filter(TexturePoolFilter *filter) {
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.
95 PNMFileTypeRegistry *pnm_reg = PNMFileTypeRegistry::get_global_ptr();
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
121 PNMFileTypeRegistry *pnm_reg = PNMFileTypeRegistry::get_global_ptr();
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 */
145 TexturePool *TexturePool::
146 get_global_ptr() {
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
231 BamCache *cache = BamCache::get_global_ptr();
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().
247 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
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
394 BamCache *cache = BamCache::get_global_ptr();
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
513 BamCache *cache = BamCache::get_global_ptr();
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
615 BamCache *cache = BamCache::get_global_ptr();
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
717 BamCache *cache = BamCache::get_global_ptr();
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
1047 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
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()) {
1121 tex->generate_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 {
1166 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
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 }
bamCacheRecord.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bamCache.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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:36
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
BamCacheRecord::set_data
set_data
Stores a new data object on the record.
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
BamCache::get_cache_textures
get_cache_textures
Returns whether texture files (e.g.
Definition: bamCache.h:90
BamCache::store
bool store(BamCacheRecord *record)
Flushes a cache entry to disk.
Definition: bamCache.cxx:194
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
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
ConfigVariableFilename
This is a convenience class to specialize ConfigVariable as a Filename type.
Definition: configVariableFilename.h:27
ConfigVariableList
This class is similar to ConfigVariable, but it reports its value as a list of strings.
Definition: configVariableList.h:31
CycleDataReader
This template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
Definition: cycleDataReader.h:35
Filename
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
Filename::get_basename
std::string get_basename() const
Returns the basename part of the filename.
Definition: filename.I:367
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
Filename::get_fullpath
std::string get_fullpath() const
Returns the entire filename: directory, basename, extension.
Definition: filename.I:338
Filename::get_extension
std::string get_extension() const
Returns the file extension.
Definition: filename.I:400
Filename::is_local
bool is_local() const
Returns true if the filename is local, e.g.
Definition: filename.I:549
Filename::set_pattern
void set_pattern(bool pattern)
Sets the flag indicating whether this is a filename pattern.
Definition: filename.I:503
GlobPattern
This class can be used to test for string matches against standard Unix- shell filename globbing conv...
Definition: globPattern.h:32
LoaderOptions
Specifies parameters that may be passed to the loader.
Definition: loaderOptions.h:23
MutexHolder
A lightweight C++ object whose constructor calls acquire() and whose destructor calls release() on a ...
Definition: mutexHolder.h:25
PNMFileTypeRegistry
This class maintains the set of all known PNMFileTypes in the universe.
Definition: pnmFileTypeRegistry.h:28
PNMFileTypeRegistry::get_global_ptr
static PNMFileTypeRegistry * get_global_ptr()
Returns a pointer to the global PNMFileTypeRegistry object.
Definition: pnmFileTypeRegistry.cxx:277
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
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
PNMFileType
This is the base class of a family of classes that represent particular image file types that PNMImag...
Definition: pnmFileType.h:32
ReferenceCount::get_ref_count
get_ref_count
Returns the current reference count.
Definition: referenceCount.h:53
TextureCollection
Manages a list of Texture objects, as returned by TexturePool::find_all_textures().
Definition: textureCollection.h:25
TextureCollection::add_texture
void add_texture(Texture *texture)
Adds a new Texture to the collection.
Definition: textureCollection.cxx:45
TexturePoolFilter
This is an abstract base class, a placeholder for any number of different classes that may wish to im...
Definition: texturePoolFilter.h:42
TexturePool
This is the preferred interface for loading textures from image files.
Definition: texturePool.h:37
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
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
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
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
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_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:445
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:447
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:471
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
Texture::get_y_size
get_y_size
Returns the height of the texture image in texels.
Definition: texture.h:346
Texture::clear_ram_image
void clear_ram_image()
Discards the current system-RAM image.
Definition: texture.I:1439
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
Texture::get_fullpath
get_fullpath
Returns the fullpath that has been set.
Definition: texture.h:332
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:517
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:572
Texture::get_x_size
get_x_size
Returns the width of the texture image in texels.
Definition: texture.h:342
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
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:1324
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:472
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:573
VirtualFileSystem
A hierarchy of directories and files that appears to be one continuous file system,...
Definition: virtualFileSystem.h:40
VirtualFileSystem::exists
bool exists(const Filename &filename) const
Convenience function; returns true if the named file exists.
Definition: virtualFileSystem.I:18
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:640
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:866
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:515
VirtualFileSystem::get_global_ptr
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
Definition: virtualFileSystem.cxx:741
VirtualFile
The abstract base class for a file or directory within the VirtualFileSystem.
Definition: virtualFile.h:35
configVariableList.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
config_express.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
config_gobj.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
config_putil.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
dcast.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
load_dso.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
mutexHolder.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pnmFileTypeRegistry.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
downcase
string downcase(const string &s)
Returns the input string with all uppercase letters converted to lowercase.
Definition: string_utils.cxx:71
string_utils.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
texturePoolFilter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PT
PT(Texture) TexturePool
Creates a new Texture object of the appropriate type for the indicated filename extension,...
Definition: texturePool.cxx:1011
texturePool.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtualFileSystem.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.