59 vector_string::const_iterator wi;
60 for (wi = words.begin(); wi != words.end(); ++wi) {
61 _type_registry[*wi] = func;
74 <<
"Registering Texture filter " << *filter <<
"\n";
75 _filter_registry.push_back(filter);
88 TypeRegistry::const_iterator ti;
89 ti = _type_registry.find(c);
90 if (ti != _type_registry.end()) {
97 if (type !=
nullptr || c ==
"txo" || c ==
"dds" || c ==
"ktx") {
99 ((
TexturePool *)
this)->_type_registry[c] = Texture::make_texture;
100 return Texture::make_texture;
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";
122 pnm_reg->
write(out, indent_level);
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;
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";
147 if (_global_ptr ==
nullptr) {
152 _global_ptr->load_filters();
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 "
170 _fake_texture_image = fake_texture_image;
177 ns_has_texture(
const Filename &orig_filename) {
181 resolve_filename(key._fullpath, orig_filename,
false,
LoaderOptions());
183 Textures::const_iterator ti;
184 ti = _textures.find(key);
185 if (ti != _textures.end()) {
191 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
192 if (ti->first._fullpath == key._fullpath) {
204 ns_load_texture(
const Filename &orig_filename,
int primary_file_num_channels,
207 key._primary_file_num_channels = primary_file_num_channels;
210 resolve_filename(key._fullpath, orig_filename, read_mipmaps, options);
212 Textures::const_iterator ti;
213 ti = _textures.find(key);
214 if (ti != _textures.end()) {
225 bool store_record =
false;
228 tex = pre_load(orig_filename,
Filename(), primary_file_num_channels, 0,
229 read_mipmaps, options);
232 bool compressed_cache_record =
false;
233 try_load_cache(tex, cache, key._fullpath, record, compressed_cache_record,
236 if (tex ==
nullptr) {
240 <<
"Loading texture " << key._fullpath <<
"\n";
242 string ext =
downcase(key._fullpath.get_extension());
243 if (ext ==
"txo" || ext ==
"bam") {
249 key._fullpath.set_binary();
251 if (file ==
nullptr) {
254 <<
"Could not find " << key._fullpath <<
"\n";
258 if (gobj_cat.is_debug()) {
260 <<
"Reading texture object " << key._fullpath <<
"\n";
263 istream *in = file->open_read_file(
true);
264 tex = Texture::make_from_txo(*in, key._fullpath);
267 if (tex ==
nullptr) {
270 tex->set_fullpath(key._fullpath);
271 tex->clear_alpha_fullpath();
272 tex->set_keep_ram_image(
false);
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)) {
280 report_texture_unreadable(key._fullpath);
285 if (options.get_texture_flags() & LoaderOptions::TF_preload_simple) {
286 tex->generate_simple_ram_image();
289 store_record = (record !=
nullptr);
294 bool needs_driver_compression =
true;
296 bool needs_driver_compression = driver_compress_textures;
297 #endif // HAVE_SQUISH
298 if (needs_driver_compression) {
301 store_record =
false;
302 if (!compressed_cache_record) {
303 tex->set_post_load_store_cache(
true);
309 store_record =
false;
313 nassertr(tex !=
nullptr,
nullptr);
314 tex->set_filename(orig_filename);
315 tex->set_fullpath(key._fullpath);
316 tex->_texture_pool_key = key._fullpath;
323 Textures::const_iterator ti;
324 ti = _textures.find(key);
325 if (ti != _textures.end()) {
332 _textures[std::move(key)] = tex;
335 if (store_record && tex->is_cacheable()) {
338 cache->
store(record);
341 if (!(options.get_texture_flags() & LoaderOptions::TF_preload)) {
343 tex->clear_ram_image();
346 nassertr(!tex->get_fullpath().empty(), tex);
349 tex = post_load(tex);
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,
363 if (!_fake_texture_image.empty()) {
364 return ns_load_texture(_fake_texture_image, primary_file_num_channels,
365 read_mipmaps, options);
369 key._primary_file_num_channels = primary_file_num_channels;
370 key._alpha_file_channel = alpha_file_channel;
373 resolve_filename(key._fullpath, orig_filename, read_mipmaps, options);
374 resolve_filename(key._alpha_fullpath, orig_alpha_filename, read_mipmaps, options);
376 Textures::const_iterator ti;
377 ti = _textures.find(key);
378 if (ti != _textures.end()) {
388 bool store_record =
false;
391 tex = pre_load(orig_filename, orig_alpha_filename, primary_file_num_channels,
392 alpha_file_channel, read_mipmaps, options);
395 bool compressed_cache_record =
false;
396 try_load_cache(tex, cache, key._fullpath, record, compressed_cache_record,
399 if (tex ==
nullptr) {
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,
410 report_texture_unreadable(key._fullpath);
414 if (options.get_texture_flags() & LoaderOptions::TF_preload_simple) {
415 tex->generate_simple_ram_image();
418 store_record = (record !=
nullptr);
423 bool needs_driver_compression =
true;
425 bool needs_driver_compression = driver_compress_textures;
426 #endif // HAVE_SQUISH
427 if (needs_driver_compression) {
430 store_record =
false;
431 if (!compressed_cache_record) {
432 tex->set_post_load_store_cache(
true);
438 store_record =
false;
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;
453 Textures::const_iterator ti;
454 ti = _textures.find(key);
455 if (ti != _textures.end()) {
462 _textures[std::move(key)] = tex;
465 if (store_record && tex->is_cacheable()) {
468 cache->
store(record);
471 if (!(options.get_texture_flags() & LoaderOptions::TF_preload)) {
473 tex->clear_ram_image();
476 nassertr(!tex->get_fullpath().empty(), tex);
479 tex = post_load(tex);
488 ns_load_3d_texture(
const Filename &filename_pattern,
490 Filename orig_filename(filename_pattern);
494 key._texture_type = Texture::TT_3d_texture;
497 resolve_filename(key._fullpath, orig_filename, read_mipmaps, options);
499 Textures::const_iterator ti;
500 ti = _textures.find(key);
501 if (ti != _textures.end()) {
511 bool store_record =
false;
514 bool compressed_cache_record =
false;
515 try_load_cache(tex, cache, key._fullpath, record, compressed_cache_record,
518 if (tex ==
nullptr ||
519 tex->get_texture_type() != Texture::TT_3d_texture) {
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)) {
528 report_texture_unreadable(key._fullpath);
531 store_record = (record !=
nullptr);
536 bool needs_driver_compression =
true;
538 bool needs_driver_compression = driver_compress_textures;
539 #endif // HAVE_SQUISH
540 if (needs_driver_compression) {
543 store_record =
false;
544 if (!compressed_cache_record) {
545 tex->set_post_load_store_cache(
true);
551 store_record =
false;
555 nassertr(tex !=
nullptr,
nullptr);
556 tex->set_filename(filename_pattern);
557 tex->set_fullpath(key._fullpath);
558 tex->_texture_pool_key = key._fullpath;
564 Textures::const_iterator ti;
565 ti = _textures.find(key);
566 if (ti != _textures.end()) {
573 _textures[std::move(key)] = tex;
576 if (store_record && tex->is_cacheable()) {
579 cache->
store(record);
582 nassertr(!tex->get_fullpath().empty(), tex);
590 ns_load_2d_texture_array(
const Filename &filename_pattern,
592 Filename orig_filename(filename_pattern);
596 key._texture_type = Texture::TT_2d_texture_array;
599 resolve_filename(key._fullpath, orig_filename, read_mipmaps, options);
601 Textures::const_iterator ti;
602 ti = _textures.find(key);
603 if (ti != _textures.end()) {
613 bool store_record =
false;
616 bool compressed_cache_record =
false;
617 try_load_cache(tex, cache, key._fullpath, record, compressed_cache_record,
620 if (tex ==
nullptr ||
621 tex->get_texture_type() != Texture::TT_2d_texture_array) {
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)) {
630 report_texture_unreadable(key._fullpath);
633 store_record = (record !=
nullptr);
638 bool needs_driver_compression =
true;
640 bool needs_driver_compression = driver_compress_textures;
641 #endif // HAVE_SQUISH
642 if (needs_driver_compression) {
645 store_record =
false;
646 if (!compressed_cache_record) {
647 tex->set_post_load_store_cache(
true);
653 store_record =
false;
657 nassertr(tex !=
nullptr,
nullptr);
658 tex->set_filename(filename_pattern);
659 tex->set_fullpath(key._fullpath);
660 tex->_texture_pool_key = key._fullpath;
666 Textures::const_iterator ti;
667 ti = _textures.find(key);
668 if (ti != _textures.end()) {
675 _textures[std::move(key)] = tex;
678 if (store_record && tex->is_cacheable()) {
681 cache->
store(record);
684 nassertr(!tex->get_fullpath().empty(), tex);
692 ns_load_cube_map(
const Filename &filename_pattern,
bool read_mipmaps,
694 Filename orig_filename(filename_pattern);
698 key._texture_type = Texture::TT_cube_map;
701 resolve_filename(key._fullpath, orig_filename, read_mipmaps, options);
703 Textures::const_iterator ti;
704 ti = _textures.find(key);
705 if (ti != _textures.end()) {
715 bool store_record =
false;
718 bool compressed_cache_record =
false;
719 try_load_cache(tex, cache, key._fullpath, record, compressed_cache_record,
722 if (tex ==
nullptr ||
723 tex->get_texture_type() != Texture::TT_cube_map) {
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)) {
732 report_texture_unreadable(key._fullpath);
735 store_record = (record !=
nullptr);
740 bool needs_driver_compression =
true;
742 bool needs_driver_compression = driver_compress_textures;
743 #endif // HAVE_SQUISH
744 if (needs_driver_compression) {
747 store_record =
false;
748 if (!compressed_cache_record) {
749 tex->set_post_load_store_cache(
true);
755 store_record =
false;
759 nassertr(tex !=
nullptr,
nullptr);
760 tex->set_filename(filename_pattern);
761 tex->set_fullpath(key._fullpath);
762 tex->_texture_pool_key = key._fullpath;
768 Textures::const_iterator ti;
769 ti = _textures.find(key);
770 if (ti != _textures.end()) {
777 _textures[std::move(key)] = tex;
780 if (store_record && tex->is_cacheable()) {
783 cache->
store(record);
786 nassertr(!tex->get_fullpath().empty(), tex);
794 ns_get_normalization_cube_map(
int size) {
797 if (_normalization_cube_map ==
nullptr) {
798 _normalization_cube_map =
new Texture(
"normalization_cube_map");
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);
805 return _normalization_cube_map;
812 ns_get_alpha_scale_map() {
815 if (_alpha_scale_map ==
nullptr) {
816 _alpha_scale_map =
new Texture(
"alpha_scale_map");
817 _alpha_scale_map->generate_alpha_scale_map();
820 return _alpha_scale_map;
831 if (!tex->_texture_pool_key.empty()) {
832 ns_release_texture(tex);
836 if (tex_cdata->_fullpath.empty()) {
837 gobj_cat.error() <<
"Attempt to call add_texture() on an unnamed texture.\n";
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;
848 tex->_texture_pool_key = key._fullpath;
849 _textures[key] = tex;
856 ns_release_texture(
Texture *tex) {
859 Textures::iterator ti;
860 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
861 if (tex == (*ti).second) {
863 tex->_texture_pool_key = string();
869 _relpath_lookup.clear();
876 ns_release_all_textures() {
879 Textures::iterator ti;
880 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
882 tex->_texture_pool_key = string();
886 _normalization_cube_map =
nullptr;
889 _relpath_lookup.clear();
896 ns_garbage_collect() {
899 int num_released = 0;
902 Textures::iterator ti;
903 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
906 if (gobj_cat.is_debug()) {
908 <<
"Releasing " << (*ti).first._fullpath <<
"\n";
911 tex->_texture_pool_key = string();
913 new_set.insert(new_set.end(), *ti);
917 _textures.swap(new_set);
919 if (_normalization_cube_map !=
nullptr &&
920 _normalization_cube_map->get_ref_count() == 1) {
921 if (gobj_cat.is_debug()) {
923 <<
"Releasing normalization cube map\n";
926 _normalization_cube_map =
nullptr;
936 ns_list_contents(ostream &out)
const {
941 Textures::const_iterator ti;
943 out <<
"texture pool contents:\n";
947 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
949 out << (*ti).first._fullpath <<
"\n";
956 nassertv(tex->_texture_pool_key == (*ti).first._fullpath);
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";
971 ns_find_texture(
const string &name)
const {
975 Textures::const_iterator ti;
976 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
978 if (glob.matches(tex->get_name())) {
990 ns_find_all_textures(
const string &name)
const {
995 Textures::const_iterator ti;
996 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
998 if (glob.matches(tex->get_name())) {
1012 ns_make_texture(
const string &extension)
const {
1014 if (func !=
nullptr) {
1031 if (!_fake_texture_image.empty()) {
1032 new_filename = _fake_texture_image;
1036 RelpathLookup::iterator rpi = _relpath_lookup.find(orig_filename);
1037 if (rpi != _relpath_lookup.end()) {
1038 new_filename = (*rpi).second;
1042 new_filename = orig_filename;
1043 if (read_mipmaps || (options.get_texture_flags() & LoaderOptions::TF_multiview)) {
1050 _relpath_lookup[orig_filename] = new_filename;
1060 if (tex ==
nullptr) {
1070 PT(
Texture) dummy = ns_make_texture(ext);
1071 dummy->ensure_loader_type(filename);
1074 record = cache->lookup(filename,
"txo");
1075 if (record !=
nullptr) {
1076 if (record->has_data()) {
1085 if (gobj_cat.is_debug()) {
1087 <<
"Not caching uncompressed texture " << *tex <<
"\n";
1098 if (gobj_cat.is_debug()) {
1100 <<
"Cached texture " << *tex <<
" has size "
1102 <<
" instead of " << x_size <<
" x " << y_size
1103 <<
"; dropping cache.\n";
1109 if (gobj_cat.is_debug()) {
1111 <<
"Cached texture " << *tex
1112 <<
" is compressed in cache; dropping cache.\n";
1118 <<
"Texture " << filename <<
" found in disk cache.\n";
1119 if ((options.get_texture_flags() & LoaderOptions::TF_preload_simple) &&
1123 if (!(options.get_texture_flags() & LoaderOptions::TF_preload)) {
1129 if (tex->consider_auto_process_ram_image(tex->
uses_mipmaps(),
true)) {
1131 if (!was_compressed && is_compressed &&
1137 cache->
store(record);
1138 compressed_cache_record =
true;
1149 if (gobj_cat.is_debug()) {
1151 <<
"Not caching uncompressed texture\n";
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)) {
1173 <<
"Unable to find texture \"" << filename <<
"\""
1174 <<
" on model-path " << get_model_path() <<
"\n";
1179 <<
"Texture \"" << filename <<
"\" does not exist.\n";
1186 <<
"Texture \"" << filename <<
"\" exists but cannot be read.\n";
1191 <<
"Texture \"" << filename <<
"\" cannot be read.\n";
1196 if (func ==
nullptr) {
1199 <<
"\" is unknown. Supported texture types:\n";
1211 pre_load(
const Filename &orig_filename,
const Filename &orig_alpha_filename,
1212 int primary_file_num_channels,
int alpha_file_channel,
1218 FilterRegistry::iterator fi;
1219 for (fi = _filter_registry.begin();
1220 fi != _filter_registry.end();
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) {
1242 FilterRegistry::iterator fi;
1243 for (fi = _filter_registry.begin();
1244 fi != _filter_registry.end();
1246 result = (*fi)->post_load(result);
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."));
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);
1269 Filename dlname = Filename::dso_filename(
"lib" + name +
".so");
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) {
1275 <<
"Unable to load: " << load_dso_error() << std::endl;