00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "pandabase.h"
00016 #include "texture.h"
00017 #include "config_gobj.h"
00018 #include "config_util.h"
00019 #include "texturePool.h"
00020 #include "textureContext.h"
00021 #include "bamCache.h"
00022 #include "bamCacheRecord.h"
00023 #include "datagram.h"
00024 #include "datagramIterator.h"
00025 #include "bamReader.h"
00026 #include "bamWriter.h"
00027 #include "string_utils.h"
00028 #include "preparedGraphicsObjects.h"
00029 #include "pnmImage.h"
00030 #include "virtualFileSystem.h"
00031 #include "datagramInputFile.h"
00032 #include "datagramOutputFile.h"
00033 #include "bam.h"
00034 #include "zStream.h"
00035 #include "indent.h"
00036 #include "cmath.h"
00037 #include "pStatTimer.h"
00038 #include "pbitops.h"
00039 #include "streamReader.h"
00040 #include "texturePeeker.h"
00041
00042 #ifdef HAVE_SQUISH
00043 #include <squish.h>
00044 #endif // HAVE_SQUISH
00045
00046 #include <stddef.h>
00047
00048 ConfigVariableEnum<Texture::QualityLevel> texture_quality_level
00049 ("texture-quality-level", Texture::QL_normal,
00050 PRC_DESC("This specifies a global quality level for all textures. You "
00051 "may specify either fastest, normal, or best. This actually "
00052 "affects the meaning of Texture::set_quality_level(QL_default), "
00053 "so it may be overridden on a per-texture basis. This generally "
00054 "only has an effect when using the tinydisplay software renderer; "
00055 "it has little or no effect on normal, hardware-accelerated "
00056 "renderers. See Texture::set_quality_level()."));
00057
00058 ConfigVariableEnum<Texture::FilterType> texture_minfilter
00059 ("texture-minfilter", Texture::FT_linear,
00060 PRC_DESC("This specifies the default minfilter that is applied to a texture "
00061 "in the absence of a specific minfilter setting. Normally this "
00062 "is either 'linear' to disable mipmapping by default, or "
00063 "'mipmap', to enable trilinear mipmapping by default. This "
00064 "does not apply to depth textures. Note if this variable is "
00065 "changed at runtime, you may need to reload textures explicitly "
00066 "in order to change their visible properties."));
00067
00068 ConfigVariableEnum<Texture::FilterType> texture_magfilter
00069 ("texture-magfilter", Texture::FT_linear,
00070 PRC_DESC("This specifies the default magfilter that is applied to a texture "
00071 "in the absence of a specific magfilter setting. Normally this "
00072 "is 'linear' (since mipmapping does not apply to magfilters). This "
00073 "does not apply to depth textures. Note if this variable is "
00074 "changed at runtime, you may need to reload textures explicitly "
00075 "in order to change their visible properties."));
00076
00077 ConfigVariableInt texture_anisotropic_degree
00078 ("texture-anisotropic-degree", 1,
00079 PRC_DESC("This specifies the default anisotropic degree that is applied "
00080 "to a texture in the absence of a particular anisotropic degree "
00081 "setting (that is, a texture for which the anisotropic degree "
00082 "is 0, meaning the default setting). It should be 1 to disable "
00083 "anisotropic filtering, or a higher number to enable it. "
00084 "Note if this variable is "
00085 "changed at runtime, you may need to reload textures explicitly "
00086 "in order to change their visible properties."));
00087
00088 PStatCollector Texture::_texture_read_pcollector("*:Texture:Read");
00089 TypeHandle Texture::_type_handle;
00090 AutoTextureScale Texture::_textures_power_2 = ATS_UNSPECIFIED;
00091
00092
00093
00094
00095 #define DDS_MAGIC 0x20534444
00096
00097
00098
00099 #define DDSD_CAPS 0x00000001
00100 #define DDSD_HEIGHT 0x00000002
00101 #define DDSD_WIDTH 0x00000004
00102 #define DDSD_PITCH 0x00000008
00103 #define DDSD_PIXELFORMAT 0x00001000
00104 #define DDSD_MIPMAPCOUNT 0x00020000
00105 #define DDSD_LINEARSIZE 0x00080000
00106 #define DDSD_DEPTH 0x00800000
00107
00108
00109 #define DDPF_ALPHAPIXELS 0x00000001
00110 #define DDPF_FOURCC 0x00000004
00111 #define DDPF_INDEXED 0x00000020
00112 #define DDPF_RGB 0x00000040
00113
00114
00115 #define DDSCAPS_COMPLEX 0x00000008
00116 #define DDSCAPS_TEXTURE 0x00001000
00117 #define DDSCAPS_MIPMAP 0x00400000
00118
00119
00120 #define DDSCAPS2_CUBEMAP 0x00000200
00121 #define DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400
00122 #define DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800
00123 #define DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000
00124 #define DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000
00125 #define DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000
00126 #define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000
00127 #define DDSCAPS2_VOLUME 0x00200000
00128
00129 struct DDSPixelFormat {
00130 unsigned int pf_size;
00131 unsigned int pf_flags;
00132 unsigned int four_cc;
00133 unsigned int rgb_bitcount;
00134 unsigned int r_mask;
00135 unsigned int g_mask;
00136 unsigned int b_mask;
00137 unsigned int a_mask;
00138 };
00139
00140 struct DDSCaps2 {
00141 unsigned int caps1;
00142 unsigned int caps2;
00143 unsigned int ddsx;
00144 };
00145
00146 struct DDSHeader {
00147 unsigned int dds_magic;
00148 unsigned int dds_size;
00149 unsigned int dds_flags;
00150 unsigned int height;
00151 unsigned int width;
00152 unsigned int pitch;
00153 unsigned int depth;
00154 unsigned int num_levels;
00155
00156 DDSPixelFormat pf;
00157 DDSCaps2 caps;
00158 };
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168 Texture::
00169 Texture(const string &name) :
00170 Namable(name),
00171 _lock(name),
00172 _cvar(_lock)
00173 {
00174 _reloading = false;
00175 _primary_file_num_channels = 0;
00176 _alpha_file_channel = 0;
00177 _magfilter = FT_default;
00178 _minfilter = FT_default;
00179 _wrap_u = WM_repeat;
00180 _wrap_v = WM_repeat;
00181 _wrap_w = WM_repeat;
00182 _anisotropic_degree = 0;
00183 _keep_ram_image = true;
00184 _border_color.set(0.0f, 0.0f, 0.0f, 1.0f);
00185 _compression = CM_default;
00186 _ram_image_compression = CM_off;
00187 _render_to_texture = false;
00188 _match_framebuffer_format = false;
00189 _post_load_store_cache = false;
00190 _quality_level = QL_default;
00191
00192 _texture_type = TT_2d_texture;
00193 _x_size = 0;
00194 _y_size = 1;
00195 _z_size = 1;
00196 do_set_format(F_rgb);
00197 do_set_component_type(T_unsigned_byte);
00198
00199 _pad_x_size = 0;
00200 _pad_y_size = 0;
00201 _pad_z_size = 0;
00202
00203 _orig_file_x_size = 0;
00204 _orig_file_y_size = 0;
00205
00206 _loaded_from_image = false;
00207 _loaded_from_txo = false;
00208 _has_read_pages = false;
00209 _has_read_mipmaps = false;
00210 _num_mipmap_levels_read = 0;
00211
00212 _simple_x_size = 0;
00213 _simple_y_size = 0;
00214 _simple_ram_image._page_size = 0;
00215 }
00216
00217
00218
00219
00220
00221
00222
00223 Texture::
00224 Texture(const Texture ©) :
00225 Namable(copy),
00226 _lock(copy.get_name()),
00227 _cvar(_lock)
00228 {
00229 _reloading = false;
00230 _has_read_pages = false;
00231 _has_read_mipmaps = false;
00232 _num_mipmap_levels_read = 0;
00233
00234 operator = (copy);
00235 }
00236
00237
00238
00239
00240
00241
00242
00243 void Texture::
00244 operator = (const Texture ©) {
00245 Namable::operator = (copy);
00246
00247 MutexHolder holder(_lock);
00248 {
00249 MutexHolder holder2(copy._lock);
00250 do_assign(copy);
00251 }
00252
00253 ++_properties_modified;
00254 ++_image_modified;
00255 ++_simple_image_modified;
00256 }
00257
00258
00259
00260
00261
00262
00263 Texture::
00264 ~Texture() {
00265 release_all();
00266 nassertv(!_reloading);
00267 }
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279 void Texture::
00280 generate_normalization_cube_map(int size) {
00281 MutexHolder holder(_lock);
00282 do_setup_texture(TT_cube_map, size, size, 6, T_unsigned_byte, F_rgb);
00283 PTA_uchar image = do_make_ram_image();
00284 _keep_ram_image = true;
00285
00286 ++_image_modified;
00287 ++_properties_modified;
00288
00289 float half_size = (float)size * 0.5f;
00290 float center = half_size - 0.5f;
00291
00292 LMatrix4f scale
00293 (127.5f, 0.0f, 0.0f, 0.0f,
00294 0.0f, 127.5f, 0.0f, 0.0f,
00295 0.0f, 0.0f, 127.5f, 0.0f,
00296 127.5f, 127.5f, 127.5f, 1.0f);
00297
00298 unsigned char *p = image;
00299 int xi, yi;
00300
00301
00302 for (yi = 0; yi < size; ++yi) {
00303 for (xi = 0; xi < size; ++xi) {
00304 LVector3f vec(half_size, center - yi, center - xi);
00305 vec.normalize();
00306 vec = scale.xform_point(vec);
00307
00308 *p++ = (unsigned char)vec[2];
00309 *p++ = (unsigned char)vec[1];
00310 *p++ = (unsigned char)vec[0];
00311 }
00312 }
00313
00314
00315 for (yi = 0; yi < size; ++yi) {
00316 for (xi = 0; xi < size; ++xi) {
00317 LVector3f vec(-half_size, center - yi, xi - center);
00318 vec.normalize();
00319 vec = scale.xform_point(vec);
00320 *p++ = (unsigned char)vec[2];
00321 *p++ = (unsigned char)vec[1];
00322 *p++ = (unsigned char)vec[0];
00323 }
00324 }
00325
00326
00327 for (yi = 0; yi < size; ++yi) {
00328 for (xi = 0; xi < size; ++xi) {
00329 LVector3f vec(xi - center, half_size, yi - center);
00330 vec.normalize();
00331 vec = scale.xform_point(vec);
00332 *p++ = (unsigned char)vec[2];
00333 *p++ = (unsigned char)vec[1];
00334 *p++ = (unsigned char)vec[0];
00335 }
00336 }
00337
00338
00339 for (yi = 0; yi < size; ++yi) {
00340 for (xi = 0; xi < size; ++xi) {
00341 LVector3f vec(xi - center, -half_size, center - yi);
00342 vec.normalize();
00343 vec = scale.xform_point(vec);
00344 *p++ = (unsigned char)vec[2];
00345 *p++ = (unsigned char)vec[1];
00346 *p++ = (unsigned char)vec[0];
00347 }
00348 }
00349
00350
00351 for (yi = 0; yi < size; ++yi) {
00352 for (xi = 0; xi < size; ++xi) {
00353 LVector3f vec(xi - center, center - yi, half_size);
00354 vec.normalize();
00355 vec = scale.xform_point(vec);
00356 *p++ = (unsigned char)vec[2];
00357 *p++ = (unsigned char)vec[1];
00358 *p++ = (unsigned char)vec[0];
00359 }
00360 }
00361
00362
00363 for (yi = 0; yi < size; ++yi) {
00364 for (xi = 0; xi < size; ++xi) {
00365 LVector3f vec(center - xi, center - yi, -half_size);
00366 vec.normalize();
00367 vec = scale.xform_point(vec);
00368 *p++ = (unsigned char)vec[2];
00369 *p++ = (unsigned char)vec[1];
00370 *p++ = (unsigned char)vec[0];
00371 }
00372 }
00373 }
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384 void Texture::
00385 generate_alpha_scale_map() {
00386 MutexHolder holder(_lock);
00387 do_setup_texture(TT_1d_texture, 256, 1, 1, T_unsigned_byte, F_alpha);
00388 _wrap_u = WM_clamp;
00389 _minfilter = FT_nearest;
00390 _magfilter = FT_nearest;
00391 _compression = CM_off;
00392
00393 ++_image_modified;
00394 ++_properties_modified;
00395
00396 PTA_uchar image = do_make_ram_image();
00397 _keep_ram_image = true;
00398
00399 unsigned char *p = image;
00400 for (int xi = 0; xi < 256; ++xi) {
00401 *p++ = xi;
00402 }
00403 }
00404
00405
00406
00407
00408
00409
00410 bool Texture::
00411 read(const Filename &fullpath, const LoaderOptions &options) {
00412 MutexHolder holder(_lock);
00413 do_clear();
00414 ++_properties_modified;
00415 ++_image_modified;
00416 return do_read(fullpath, Filename(), 0, 0, 0, 0, false, false,
00417 options, NULL);
00418 }
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431 bool Texture::
00432 read(const Filename &fullpath, const Filename &alpha_fullpath,
00433 int primary_file_num_channels, int alpha_file_channel,
00434 const LoaderOptions &options) {
00435 MutexHolder holder(_lock);
00436 do_clear();
00437 ++_properties_modified;
00438 ++_image_modified;
00439 return do_read(fullpath, alpha_fullpath, primary_file_num_channels,
00440 alpha_file_channel, 0, 0, false, false,
00441 options, NULL);
00442 }
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454 bool Texture::
00455 read(const Filename &fullpath, int z, int n,
00456 bool read_pages, bool read_mipmaps,
00457 const LoaderOptions &options) {
00458 MutexHolder holder(_lock);
00459 ++_properties_modified;
00460 ++_image_modified;
00461 return do_read(fullpath, Filename(), 0, 0, z, n, read_pages, read_mipmaps,
00462 options, NULL);
00463 }
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534 bool Texture::
00535 read(const Filename &fullpath, const Filename &alpha_fullpath,
00536 int primary_file_num_channels, int alpha_file_channel,
00537 int z, int n, bool read_pages, bool read_mipmaps,
00538 BamCacheRecord *record,
00539 const LoaderOptions &options) {
00540 MutexHolder holder(_lock);
00541 ++_properties_modified;
00542 ++_image_modified;
00543 return do_read(fullpath, alpha_fullpath, primary_file_num_channels,
00544 alpha_file_channel, z, n, read_pages, read_mipmaps,
00545 options, record);
00546 }
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562 size_t Texture::
00563 estimate_texture_memory() const {
00564 MutexHolder holder(_lock);
00565 size_t pixels = _x_size * _y_size;
00566
00567 size_t bpp = 4;
00568 switch (_format) {
00569 case Texture::F_rgb332:
00570 bpp = 1;
00571 break;
00572
00573 case Texture::F_alpha:
00574 case Texture::F_red:
00575 case Texture::F_green:
00576 case Texture::F_blue:
00577 case Texture::F_luminance:
00578 case Texture::F_luminance_alpha:
00579 case Texture::F_luminance_alphamask:
00580 bpp = 4;
00581 break;
00582
00583 case Texture::F_rgba:
00584 case Texture::F_rgba4:
00585 case Texture::F_rgbm:
00586 case Texture::F_rgb:
00587 case Texture::F_rgb5:
00588 case Texture::F_rgba5:
00589 bpp = 4;
00590 break;
00591
00592 case Texture::F_color_index:
00593 case Texture::F_rgb8:
00594 case Texture::F_rgba8:
00595 bpp = 4;
00596 break;
00597
00598 case Texture::F_depth_stencil:
00599 case Texture::F_depth_component:
00600 bpp = 32;
00601 break;
00602
00603 case Texture::F_rgba12:
00604 case Texture::F_rgb12:
00605 bpp = 6;
00606 break;
00607
00608 case Texture::F_rgba16:
00609 bpp = 8;
00610 break;
00611 case Texture::F_rgba32:
00612 bpp = 16;
00613 break;
00614
00615 default:
00616 break;
00617 }
00618
00619 size_t bytes = pixels * bpp;
00620 if (uses_mipmaps()) {
00621 bytes = (bytes * 4) / 3;
00622 }
00623
00624 return bytes;
00625 }
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638 void Texture::
00639 set_aux_data(const string &key, TypedReferenceCount *aux_data) {
00640 MutexHolder holder(_lock);
00641 _aux_data[key] = aux_data;
00642 }
00643
00644
00645
00646
00647
00648
00649
00650 void Texture::
00651 clear_aux_data(const string &key) {
00652 MutexHolder holder(_lock);
00653 _aux_data.erase(key);
00654 }
00655
00656
00657
00658
00659
00660
00661
00662
00663 TypedReferenceCount *Texture::
00664 get_aux_data(const string &key) const {
00665 MutexHolder holder(_lock);
00666 AuxData::const_iterator di;
00667 di = _aux_data.find(key);
00668 if (di != _aux_data.end()) {
00669 return (*di).second;
00670 }
00671 return NULL;
00672 }
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683 bool Texture::
00684 read_txo(istream &in, const string &filename) {
00685 MutexHolder holder(_lock);
00686 ++_properties_modified;
00687 ++_image_modified;
00688 return do_read_txo(in, filename);
00689 }
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700 bool Texture::
00701 write_txo(ostream &out, const string &filename) const {
00702 MutexHolder holder(_lock);
00703 return do_write_txo(out, filename);
00704 }
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718 bool Texture::
00719 read_dds(istream &in, const string &filename, bool header_only) {
00720 MutexHolder holder(_lock);
00721 ++_properties_modified;
00722 ++_image_modified;
00723 return do_read_dds(in, filename, header_only);
00724 }
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734 Texture *Texture::
00735 load_related(const InternalName *suffix) const {
00736 MutexHolder holder(_lock);
00737 RelatedTextures::const_iterator ti;
00738 ti = _related_textures.find(suffix);
00739 if (ti != _related_textures.end()) {
00740 return (*ti).second;
00741 }
00742 if (_fullpath.empty()) {
00743 return (Texture*)NULL;
00744 }
00745 Filename main = _fullpath;
00746 main.set_basename_wo_extension(main.get_basename_wo_extension() +
00747 suffix->get_name());
00748 PT(Texture) res;
00749 if (!_alpha_fullpath.empty()) {
00750 Filename alph = _alpha_fullpath;
00751 alph.set_basename_wo_extension(alph.get_basename_wo_extension() +
00752 suffix->get_name());
00753 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00754 if (vfs->exists(alph)) {
00755
00756
00757 res = TexturePool::load_texture(main, alph,
00758 _primary_file_num_channels,
00759 _alpha_file_channel, false);
00760 } else {
00761
00762
00763 res = TexturePool::load_texture(main);
00764 }
00765
00766 } else {
00767
00768
00769 res = TexturePool::load_texture(main);
00770 }
00771
00772
00773
00774 ((Texture *)this)->_related_textures.insert(RelatedTextures::value_type(suffix, res));
00775 return res;
00776 }
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786 Texture::FilterType Texture::
00787 get_effective_minfilter() const {
00788 if (_minfilter != FT_default) {
00789 return _minfilter;
00790 }
00791 if (_format == Texture::F_depth_stencil ||
00792 _format == Texture::F_depth_component) {
00793 return FT_nearest;
00794 }
00795 return texture_minfilter;
00796 }
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806 Texture::FilterType Texture::
00807 get_effective_magfilter() const {
00808 if (_magfilter != FT_default) {
00809 return _magfilter;
00810 }
00811 if (_format == Texture::F_depth_stencil ||
00812 _format == Texture::F_depth_component) {
00813 return FT_nearest;
00814 }
00815 return texture_magfilter;
00816 }
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828 void Texture::
00829 set_ram_image(CPTA_uchar image, Texture::CompressionMode compression,
00830 size_t page_size) {
00831 MutexHolder holder(_lock);
00832 nassertv(compression != CM_default);
00833 nassertv(compression != CM_off || image.size() == do_get_expected_ram_image_size());
00834 if (_ram_images.empty()) {
00835 _ram_images.push_back(RamImage());
00836 } else {
00837 do_clear_ram_mipmap_images();
00838 }
00839 if (page_size == 0) {
00840 page_size = image.size();
00841 }
00842 if (_ram_images[0]._image != image ||
00843 _ram_images[0]._page_size != page_size ||
00844 _ram_image_compression != compression) {
00845 _ram_images[0]._image = image.cast_non_const();
00846 _ram_images[0]._page_size = page_size;
00847 _ram_images[0]._pointer_image = NULL;
00848 _ram_image_compression = compression;
00849 ++_image_modified;
00850 }
00851 }
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861 bool Texture::
00862 get_keep_ram_image() const {
00863 return _keep_ram_image;
00864 }
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884 int Texture::
00885 get_num_loadable_ram_mipmap_images() const {
00886 MutexHolder holder(_lock);
00887 if (_ram_images.empty() || _ram_images[0]._image.empty()) {
00888
00889 return 0;
00890 }
00891 if (!uses_mipmaps()) {
00892
00893
00894 return 1;
00895 }
00896
00897
00898
00899 int size = max(_x_size, max(_y_size, _z_size));
00900 int n = 0;
00901 int x = 1;
00902 while (x < size) {
00903 x = (x << 1);
00904 ++n;
00905 if (n >= (int)_ram_images.size() || _ram_images[n]._image.empty()) {
00906 return n;
00907 }
00908 }
00909
00910 ++n;
00911 return n;
00912 }
00913
00914
00915
00916
00917
00918
00919
00920
00921 CPTA_uchar Texture::
00922 get_ram_mipmap_image(int n) {
00923 MutexHolder holder(_lock);
00924 if (n < (int)_ram_images.size() && !_ram_images[n]._image.empty()) {
00925 return _ram_images[n]._image;
00926 }
00927 return CPTA_uchar(get_class_type());
00928 }
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938 void *Texture::
00939 get_ram_mipmap_pointer(int n) {
00940 MutexHolder holder(_lock);
00941 if (n < (int)_ram_images.size()) {
00942 return _ram_images[n]._pointer_image;
00943 }
00944 return NULL;
00945 }
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961 void Texture::
00962 set_ram_mipmap_pointer(int n, void *image, size_t page_size) {
00963 MutexHolder holder(_lock);
00964 nassertv(_ram_image_compression != CM_off || do_get_expected_ram_mipmap_image_size(n));
00965
00966 while (n >= (int)_ram_images.size()) {
00967 _ram_images.push_back(RamImage());
00968 }
00969
00970 _ram_images[n]._page_size = page_size;
00971
00972 _ram_images[n]._pointer_image = image;
00973 ++_image_modified;
00974 }
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987 void Texture::
00988 set_ram_mipmap_pointer_from_int(long long pointer, int n, int page_size) {
00989 set_ram_mipmap_pointer(n, (void*)pointer, (size_t)page_size);
00990 }
00991
00992
00993
00994
00995
00996
00997
00998 void Texture::
00999 clear_ram_mipmap_image(int n) {
01000 MutexHolder holder(_lock);
01001 if (n >= (int)_ram_images.size()) {
01002 return;
01003 }
01004 _ram_images[n]._page_size = 0;
01005 _ram_images[n]._image.clear();
01006 _ram_images[n]._pointer_image = NULL;
01007 }
01008
01009
01010
01011
01012
01013
01014
01015 PTA_uchar Texture::
01016 modify_simple_ram_image() {
01017 MutexHolder holder(_lock);
01018 _simple_image_date_generated = (PN_int32)time(NULL);
01019 return _simple_ram_image._image;
01020 }
01021
01022
01023
01024
01025
01026
01027
01028
01029 PTA_uchar Texture::
01030 new_simple_ram_image(int x_size, int y_size) {
01031 MutexHolder holder(_lock);
01032 nassertr(_texture_type == TT_2d_texture, PTA_uchar());
01033 size_t expected_page_size = (size_t)(x_size * y_size * 4);
01034
01035 _simple_x_size = x_size;
01036 _simple_y_size = y_size;
01037 _simple_ram_image._image = PTA_uchar::empty_array(expected_page_size);
01038 _simple_ram_image._page_size = expected_page_size;
01039 _simple_image_date_generated = (PN_int32)time(NULL);
01040 ++_simple_image_modified;
01041
01042 return _simple_ram_image._image;
01043 }
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053 void Texture::
01054 generate_simple_ram_image() {
01055 MutexHolder holder(_lock);
01056
01057 if (_texture_type != TT_2d_texture ||
01058 _ram_image_compression != CM_off) {
01059 return;
01060 }
01061
01062 PNMImage pnmimage;
01063 if (!do_store_one(pnmimage, 0, 0)) {
01064 return;
01065 }
01066
01067
01068 int x_size = simple_image_size.get_word(0);
01069 int y_size = simple_image_size.get_word(1);
01070
01071
01072
01073 x_size = down_to_power_2(min(x_size, _x_size));
01074 y_size = down_to_power_2(min(y_size, _y_size));
01075
01076
01077 PNMImage scaled(x_size, y_size, pnmimage.get_num_channels());
01078 scaled.quick_filter_from(pnmimage);
01079
01080
01081 if (!scaled.has_alpha()) {
01082 scaled.add_alpha();
01083 scaled.alpha_fill(1.0);
01084 }
01085 scaled.set_num_channels(4);
01086
01087
01088 bool did_anything;
01089 do {
01090 did_anything = false;
01091
01092
01093 if (x_size > 1) {
01094 int new_x_size = (x_size >> 1);
01095 PNMImage smaller(new_x_size, y_size, 4);
01096 smaller.quick_filter_from(scaled);
01097 PNMImage bigger(x_size, y_size, 4);
01098 bigger.quick_filter_from(smaller);
01099
01100 if (compare_images(scaled, bigger)) {
01101 scaled.take_from(smaller);
01102 x_size = new_x_size;
01103 did_anything = true;
01104 }
01105 }
01106
01107
01108 if (y_size > 1) {
01109 int new_y_size = (y_size >> 1);
01110 PNMImage smaller(x_size, new_y_size, 4);
01111 smaller.quick_filter_from(scaled);
01112 PNMImage bigger(x_size, y_size, 4);
01113 bigger.quick_filter_from(smaller);
01114
01115 if (compare_images(scaled, bigger)) {
01116 scaled.take_from(smaller);
01117 y_size = new_y_size;
01118 did_anything = true;
01119 }
01120 }
01121 } while (did_anything);
01122
01123 size_t expected_page_size = (size_t)(x_size * y_size * 4);
01124 PTA_uchar image = PTA_uchar::empty_array(expected_page_size, get_class_type());
01125 convert_from_pnmimage(image, expected_page_size, 0, scaled, 4, 1);
01126
01127 do_set_simple_ram_image(image, x_size, y_size);
01128 _simple_image_date_generated = (PN_int32)time(NULL);
01129 }
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147 PT(TexturePeeker) Texture::
01148 peek() {
01149 MutexHolder holder(_lock);
01150
01151 PT(TexturePeeker) peeker = new TexturePeeker(this);
01152 if (peeker->is_valid()) {
01153 return peeker;
01154 }
01155
01156 return NULL;
01157 }
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171 void Texture::
01172 prepare(PreparedGraphicsObjects *prepared_objects) {
01173 prepared_objects->enqueue_texture(this);
01174 }
01175
01176
01177
01178
01179
01180
01181
01182
01183 bool Texture::
01184 is_prepared(PreparedGraphicsObjects *prepared_objects) const {
01185 MutexHolder holder(_lock);
01186 Contexts::const_iterator ci;
01187 ci = _contexts.find(prepared_objects);
01188 if (ci != _contexts.end()) {
01189 return true;
01190 }
01191 return prepared_objects->is_texture_queued(this);
01192 }
01193
01194
01195
01196
01197
01198
01199
01200
01201
01202 bool Texture::
01203 was_image_modified(PreparedGraphicsObjects *prepared_objects) const {
01204 MutexHolder holder(_lock);
01205 Contexts::const_iterator ci;
01206 ci = _contexts.find(prepared_objects);
01207 if (ci != _contexts.end()) {
01208 TextureContext *tc = (*ci).second;
01209 return tc->was_image_modified();
01210 }
01211 return true;
01212 }
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225 size_t Texture::
01226 get_data_size_bytes(PreparedGraphicsObjects *prepared_objects) const {
01227 MutexHolder holder(_lock);
01228 Contexts::const_iterator ci;
01229 ci = _contexts.find(prepared_objects);
01230 if (ci != _contexts.end()) {
01231 TextureContext *tc = (*ci).second;
01232 return tc->get_data_size_bytes();
01233 }
01234 return 0;
01235 }
01236
01237
01238
01239
01240
01241
01242
01243 bool Texture::
01244 get_active(PreparedGraphicsObjects *prepared_objects) const {
01245 MutexHolder holder(_lock);
01246 Contexts::const_iterator ci;
01247 ci = _contexts.find(prepared_objects);
01248 if (ci != _contexts.end()) {
01249 TextureContext *tc = (*ci).second;
01250 return tc->get_active();
01251 }
01252 return false;
01253 }
01254
01255
01256
01257
01258
01259
01260
01261
01262 bool Texture::
01263 get_resident(PreparedGraphicsObjects *prepared_objects) const {
01264 MutexHolder holder(_lock);
01265 Contexts::const_iterator ci;
01266 ci = _contexts.find(prepared_objects);
01267 if (ci != _contexts.end()) {
01268 TextureContext *tc = (*ci).second;
01269 return tc->get_resident();
01270 }
01271 return false;
01272 }
01273
01274
01275
01276
01277
01278
01279
01280
01281 bool Texture::
01282 release(PreparedGraphicsObjects *prepared_objects) {
01283 MutexHolder holder(_lock);
01284 Contexts::iterator ci;
01285 ci = _contexts.find(prepared_objects);
01286 if (ci != _contexts.end()) {
01287 TextureContext *tc = (*ci).second;
01288 if (tc != (TextureContext *)NULL) {
01289 prepared_objects->release_texture(tc);
01290 } else {
01291 _contexts.erase(ci);
01292 }
01293 return true;
01294 }
01295
01296
01297 return prepared_objects->dequeue_texture(this);
01298 }
01299
01300
01301
01302
01303
01304
01305
01306
01307 int Texture::
01308 release_all() {
01309 MutexHolder holder(_lock);
01310
01311
01312
01313
01314 Contexts temp = _contexts;
01315 int num_freed = (int)_contexts.size();
01316
01317 Contexts::const_iterator ci;
01318 for (ci = temp.begin(); ci != temp.end(); ++ci) {
01319 PreparedGraphicsObjects *prepared_objects = (*ci).first;
01320 TextureContext *tc = (*ci).second;
01321 if (tc != (TextureContext *)NULL) {
01322 prepared_objects->release_texture(tc);
01323 }
01324 }
01325
01326
01327
01328 _contexts.clear();
01329
01330 return num_freed;
01331 }
01332
01333
01334
01335
01336
01337
01338
01339 void Texture::
01340 write(ostream &out, int indent_level) const {
01341 MutexHolder holder(_lock);
01342 indent(out, indent_level)
01343 << _texture_type << " " << get_name();
01344 if (!_filename.empty()) {
01345 out << " (from " << _filename << ")";
01346 }
01347 out << "\n";
01348
01349 indent(out, indent_level + 2);
01350
01351 switch (_texture_type) {
01352 case TT_1d_texture:
01353 out << "1-d, " << _x_size;
01354 break;
01355
01356 case TT_2d_texture:
01357 out << "2-d, " << _x_size << " x " << _y_size;
01358 break;
01359
01360 case TT_3d_texture:
01361 out << "3-d, " << _x_size << " x " << _y_size << " x " << _z_size;
01362 break;
01363
01364 case TT_cube_map:
01365 out << "cube map, " << _x_size << " x " << _y_size;
01366 break;
01367 }
01368
01369 out << " pixels, each " << _num_components;
01370
01371 switch (_component_type) {
01372 case T_unsigned_byte:
01373 out << " bytes";
01374 break;
01375
01376 case T_unsigned_short:
01377 out << " shorts";
01378 break;
01379
01380 case T_float:
01381 out << " floats";
01382 break;
01383
01384 default:
01385 break;
01386 }
01387
01388 out << ", ";
01389 switch (_format) {
01390 case F_color_index:
01391 out << "color_index";
01392 break;
01393 case F_depth_stencil:
01394 out << "depth_stencil";
01395 break;
01396 case F_depth_component:
01397 out << "depth_component";
01398 break;
01399 case F_depth_component16:
01400 out << "depth_component16";
01401 break;
01402 case F_depth_component24:
01403 out << "depth_component24";
01404 break;
01405 case F_depth_component32:
01406 out << "depth_component32";
01407 break;
01408
01409 case F_rgba:
01410 out << "rgba";
01411 break;
01412 case F_rgbm:
01413 out << "rgbm";
01414 break;
01415 case F_rgba32:
01416 out << "rgba32";
01417 break;
01418 case F_rgba16:
01419 out << "rgba16";
01420 break;
01421 case F_rgba12:
01422 out << "rgba12";
01423 break;
01424 case F_rgba8:
01425 out << "rgba8";
01426 break;
01427 case F_rgba4:
01428 out << "rgba4";
01429 break;
01430
01431 case F_rgb:
01432 out << "rgb";
01433 break;
01434 case F_rgb12:
01435 out << "rgb12";
01436 break;
01437 case F_rgb8:
01438 out << "rgb8";
01439 break;
01440 case F_rgb5:
01441 out << "rgb5";
01442 break;
01443 case F_rgba5:
01444 out << "rgba5";
01445 break;
01446 case F_rgb332:
01447 out << "rgb332";
01448 break;
01449
01450 case F_red:
01451 out << "red";
01452 break;
01453 case F_green:
01454 out << "green";
01455 break;
01456 case F_blue:
01457 out << "blue";
01458 break;
01459 case F_alpha:
01460 out << "alpha";
01461 break;
01462 case F_luminance:
01463 out << "luminance";
01464 break;
01465 case F_luminance_alpha:
01466 out << "luminance_alpha";
01467 break;
01468 case F_luminance_alphamask:
01469 out << "luminance_alphamask";
01470 break;
01471 }
01472
01473 if (_compression != CM_default) {
01474 out << ", compression " << _compression;
01475 }
01476 out << "\n";
01477
01478 indent(out, indent_level + 2);
01479
01480 switch (_texture_type) {
01481 case TT_1d_texture:
01482 out << _wrap_u << ", ";
01483 break;
01484
01485 case TT_2d_texture:
01486 out << _wrap_u << " x " << _wrap_v << ", ";
01487 break;
01488
01489 case TT_3d_texture:
01490 out << _wrap_u << " x " << _wrap_v << " x " << _wrap_w << ", ";
01491 break;
01492
01493 case TT_cube_map:
01494 break;
01495 }
01496
01497 out << "min " << _minfilter
01498 << ", mag " << _magfilter
01499 << ", aniso " << _anisotropic_degree
01500 << ", border " << _border_color
01501 << "\n";
01502
01503 if (do_has_ram_image()) {
01504 indent(out, indent_level + 2)
01505 << do_get_ram_image_size() << " bytes in ram, compression "
01506 << _ram_image_compression << "\n";
01507
01508 if (_ram_images.size() > 1) {
01509 int count = 0;
01510 size_t total_size = 0;
01511 for (size_t n = 1; n < _ram_images.size(); ++n) {
01512 if (!_ram_images[n]._image.empty()) {
01513 ++count;
01514 total_size += _ram_images[n]._image.size();
01515 } else {
01516
01517 break;
01518 }
01519 }
01520 indent(out, indent_level + 2)
01521 << count
01522 << " mipmap levels also present in ram (" << total_size
01523 << " bytes).\n";
01524 }
01525
01526 } else {
01527 indent(out, indent_level + 2)
01528 << "no ram image\n";
01529 }
01530
01531 if (!_simple_ram_image._image.empty()) {
01532 indent(out, indent_level + 2)
01533 << "simple image: " << _simple_x_size << " x "
01534 << _simple_y_size << ", "
01535 << _simple_ram_image._image.size() << " bytes\n";
01536 }
01537 }
01538
01539
01540
01541
01542
01543
01544
01545
01546
01547 void Texture::
01548 set_size_padded(int x, int y, int z) {
01549 MutexHolder holder(_lock);
01550 if (get_textures_power_2() != ATS_none) {
01551 do_set_x_size(up_to_power_2(x));
01552 do_set_y_size(up_to_power_2(y));
01553 do_set_z_size(up_to_power_2(z));
01554 } else {
01555 do_set_x_size(x);
01556 do_set_y_size(y);
01557 do_set_z_size(z);
01558 }
01559 do_set_pad_size(_x_size - x,
01560 _y_size - y,
01561 _z_size - z);
01562 }
01563
01564
01565
01566
01567
01568
01569
01570 void Texture::
01571 set_orig_file_size(int x, int y, int z) {
01572 MutexHolder holder(_lock);
01573 _orig_file_x_size = x;
01574 _orig_file_y_size = y;
01575
01576 nassertv(z == _z_size);
01577 }
01578
01579
01580
01581
01582
01583
01584
01585 bool Texture::
01586 is_mipmap(FilterType filter_type) {
01587 switch (filter_type) {
01588 case FT_nearest_mipmap_nearest:
01589 case FT_linear_mipmap_nearest:
01590 case FT_nearest_mipmap_linear:
01591 case FT_linear_mipmap_linear:
01592 return true;
01593
01594 default:
01595 return false;
01596 }
01597 }
01598
01599
01600
01601
01602
01603
01604
01605
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615 TextureContext *Texture::
01616 prepare_now(PreparedGraphicsObjects *prepared_objects,
01617 GraphicsStateGuardianBase *gsg) {
01618 MutexHolder holder(_lock);
01619 Contexts::const_iterator ci;
01620 ci = _contexts.find(prepared_objects);
01621 if (ci != _contexts.end()) {
01622 return (*ci).second;
01623 }
01624
01625 TextureContext *tc = prepared_objects->prepare_texture_now(this, gsg);
01626 _contexts[prepared_objects] = tc;
01627
01628 return tc;
01629 }
01630
01631
01632
01633
01634
01635
01636
01637 int Texture::
01638 up_to_power_2(int value) {
01639 if (value <= 1) {
01640 return 1;
01641 }
01642 int bit = get_next_higher_bit(((unsigned int)value) - 1);
01643 return (1 << bit);
01644 }
01645
01646
01647
01648
01649
01650
01651
01652 int Texture::
01653 down_to_power_2(int value) {
01654 if (value <= 1) {
01655 return 1;
01656 }
01657 int bit = get_next_higher_bit(((unsigned int)value) >> 1);
01658 return (1 << bit);
01659 }
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672 void Texture::
01673 consider_rescale(PNMImage &pnmimage) {
01674 consider_rescale(pnmimage, get_name());
01675 }
01676
01677
01678
01679
01680
01681
01682
01683
01684
01685
01686
01687
01688 void Texture::
01689 consider_rescale(PNMImage &pnmimage, const string &name) {
01690 int new_x_size = pnmimage.get_x_size();
01691 int new_y_size = pnmimage.get_y_size();
01692 if (adjust_size(new_x_size, new_y_size, name)) {
01693 pnmimage.set_read_size(new_x_size, new_y_size);
01694 }
01695 }
01696
01697
01698
01699
01700
01701
01702
01703
01704
01705
01706
01707
01708
01709
01710 void Texture::
01711 texture_uploaded() {
01712 MutexHolder holder(_lock);
01713
01714 if (!keep_texture_ram && !_keep_ram_image) {
01715
01716
01717
01718
01719 if (gobj_cat.is_debug()) {
01720 gobj_cat.debug()
01721 << "Dumping RAM for texture " << get_name() << "\n";
01722 }
01723 do_clear_ram_image();
01724 }
01725 }
01726
01727
01728
01729
01730
01731
01732
01733
01734
01735
01736 bool Texture::
01737 has_cull_callback() const {
01738 return false;
01739 }
01740
01741
01742
01743
01744
01745
01746
01747
01748
01749
01750
01751
01752
01753
01754 bool Texture::
01755 cull_callback(CullTraverser *, const CullTraverserData &) const {
01756 return true;
01757 }
01758
01759
01760
01761
01762
01763
01764
01765
01766 Texture::WrapMode Texture::
01767 string_wrap_mode(const string &string) {
01768 if (cmp_nocase_uh(string, "repeat") == 0) {
01769 return WM_repeat;
01770 } else if (cmp_nocase_uh(string, "clamp") == 0) {
01771 return WM_clamp;
01772 } else if (cmp_nocase_uh(string, "mirror") == 0) {
01773 return WM_clamp;
01774 } else if (cmp_nocase_uh(string, "mirror_once") == 0) {
01775 return WM_clamp;
01776 } else if (cmp_nocase_uh(string, "border_color") == 0) {
01777 return WM_border_color;
01778 } else {
01779 return WM_invalid;
01780 }
01781 }
01782
01783
01784
01785
01786
01787
01788
01789
01790 Texture::FilterType Texture::
01791 string_filter_type(const string &string) {
01792 if (cmp_nocase_uh(string, "nearest") == 0) {
01793 return FT_nearest;
01794 } else if (cmp_nocase_uh(string, "linear") == 0) {
01795 return FT_linear;
01796 } else if (cmp_nocase_uh(string, "nearest_mipmap_nearest") == 0) {
01797 return FT_nearest_mipmap_nearest;
01798 } else if (cmp_nocase_uh(string, "linear_mipmap_nearest") == 0) {
01799 return FT_linear_mipmap_nearest;
01800 } else if (cmp_nocase_uh(string, "nearest_mipmap_linear") == 0) {
01801 return FT_nearest_mipmap_linear;
01802 } else if (cmp_nocase_uh(string, "linear_mipmap_linear") == 0) {
01803 return FT_linear_mipmap_linear;
01804 } else if (cmp_nocase_uh(string, "mipmap") == 0) {
01805 return FT_linear_mipmap_linear;
01806 } else if (cmp_nocase_uh(string, "shadow") == 0) {
01807 return FT_shadow;
01808 } else if (cmp_nocase_uh(string, "default") == 0) {
01809 return FT_default;
01810 } else {
01811 return FT_invalid;
01812 }
01813 }
01814
01815
01816
01817
01818
01819
01820
01821 PT(Texture) Texture::
01822 make_texture() {
01823 return new Texture;
01824 }
01825
01826
01827
01828
01829
01830
01831
01832 bool Texture::
01833 is_specific(Texture::CompressionMode compression) {
01834 switch (compression) {
01835 case CM_default:
01836 case CM_off:
01837 case CM_on:
01838 return false;
01839
01840 default:
01841 return true;
01842 }
01843 }
01844
01845
01846
01847
01848
01849
01850
01851 bool Texture::
01852 has_alpha(Format format) {
01853 switch (format) {
01854 case F_alpha:
01855 case F_rgba:
01856 case F_rgbm:
01857 case F_rgba4:
01858 case F_rgba5:
01859 case F_rgba8:
01860 case F_rgba12:
01861 case F_rgba16:
01862 case F_rgba32:
01863 case F_luminance_alpha:
01864 case F_luminance_alphamask:
01865 return true;
01866
01867 default:
01868 return false;
01869 }
01870 }
01871
01872
01873
01874
01875
01876
01877
01878 bool Texture::
01879 has_binary_alpha(Format format) {
01880 switch (format) {
01881 case F_rgbm:
01882 return true;
01883
01884 default:
01885 return false;
01886 }
01887 }
01888
01889
01890
01891
01892
01893
01894
01895
01896
01897
01898
01899
01900
01901
01902 bool Texture::
01903 adjust_size(int &x_size, int &y_size, const string &name) {
01904 bool exclude = false;
01905 int num_excludes = exclude_texture_scale.get_num_unique_values();
01906 for (int i = 0; i < num_excludes && !exclude; ++i) {
01907 GlobPattern pat(exclude_texture_scale.get_unique_value(i));
01908 if (pat.matches(name)) {
01909 exclude = true;
01910 }
01911 }
01912
01913 int new_x_size = x_size;
01914 int new_y_size = y_size;
01915
01916 if (!exclude) {
01917 new_x_size = (int)cfloor(new_x_size * texture_scale + 0.5);
01918 new_y_size = (int)cfloor(new_y_size * texture_scale + 0.5);
01919
01920
01921
01922 new_x_size = min(max(new_x_size, (int)texture_scale_limit), x_size);
01923 new_y_size = min(max(new_y_size, (int)texture_scale_limit), y_size);
01924 }
01925
01926 switch (get_textures_power_2()) {
01927 case ATS_down:
01928 new_x_size = down_to_power_2(new_x_size);
01929 new_y_size = down_to_power_2(new_y_size);
01930 break;
01931
01932 case ATS_up:
01933 new_x_size = up_to_power_2(new_x_size);
01934 new_y_size = up_to_power_2(new_y_size);
01935 break;
01936
01937 case ATS_none:
01938 case ATS_UNSPECIFIED:
01939 break;
01940 }
01941
01942 switch (textures_square.get_value()) {
01943 case ATS_down:
01944 new_x_size = new_y_size = min(new_x_size, new_y_size);
01945 break;
01946
01947 case ATS_up:
01948 new_x_size = new_y_size = max(new_x_size, new_y_size);
01949 break;
01950
01951 case ATS_none:
01952 case ATS_UNSPECIFIED:
01953 break;
01954 }
01955
01956 if (!exclude) {
01957 int max_dimension = max_texture_dimension;
01958
01959 if (max_dimension < 0) {
01960 GraphicsStateGuardianBase *gsg = GraphicsStateGuardianBase::get_default_gsg();
01961 if (gsg != (GraphicsStateGuardianBase *)NULL) {
01962 max_dimension = gsg->get_max_texture_dimension();
01963 }
01964 }
01965
01966 if (max_dimension > 0) {
01967 new_x_size = min(new_x_size, (int)max_dimension);
01968 new_y_size = min(new_y_size, (int)max_dimension);
01969 }
01970 }
01971
01972 if (x_size != new_x_size || y_size != new_y_size) {
01973 x_size = new_x_size;
01974 y_size = new_y_size;
01975 return true;
01976 }
01977
01978 return false;
01979 }
01980
01981
01982
01983
01984
01985
01986
01987 void Texture::
01988 reconsider_dirty() {
01989 }
01990
01991
01992
01993
01994
01995
01996
01997 bool Texture::
01998 do_read(const Filename &fullpath, const Filename &alpha_fullpath,
01999 int primary_file_num_channels, int alpha_file_channel,
02000 int z, int n, bool read_pages, bool read_mipmaps,
02001 const LoaderOptions &options, BamCacheRecord *record) {
02002 PStatTimer timer(_texture_read_pcollector);
02003
02004 bool header_only = ((options.get_texture_flags() & (LoaderOptions::TF_preload | LoaderOptions::TF_preload_simple)) == 0);
02005 if (record != (BamCacheRecord *)NULL) {
02006 header_only = false;
02007 }
02008
02009 if ((z == 0 || read_pages) && (n == 0 || read_mipmaps)) {
02010
02011
02012 do_clear_ram_image();
02013 }
02014
02015 if (is_txo_filename(fullpath)) {
02016 if (record != (BamCacheRecord *)NULL) {
02017 record->add_dependent_file(fullpath);
02018 }
02019 return do_read_txo_file(fullpath);
02020 }
02021
02022 if (is_dds_filename(fullpath)) {
02023 if (record != (BamCacheRecord *)NULL) {
02024 record->add_dependent_file(fullpath);
02025 }
02026 return do_read_dds_file(fullpath, header_only);
02027 }
02028
02029
02030
02031
02032 int z_size = z;
02033 int n_size = n;
02034
02035
02036
02037
02038 if (z_size == 0) {
02039 switch (_texture_type) {
02040 case TT_1d_texture:
02041 case TT_2d_texture:
02042 z_size = 1;
02043 break;
02044
02045 case TT_cube_map:
02046 z_size = 6;
02047 break;
02048
02049 default:
02050 break;
02051 }
02052 }
02053
02054 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
02055
02056 if (read_pages && read_mipmaps) {
02057
02058 Filename fullpath_pattern = Filename::pattern_filename(fullpath);
02059 Filename alpha_fullpath_pattern = Filename::pattern_filename(alpha_fullpath);
02060 do_set_z_size(z_size);
02061
02062 n = 0;
02063 while (true) {
02064
02065
02066
02067 if (n != 0) {
02068 z_size = do_get_expected_mipmap_z_size(n);
02069 }
02070
02071 z = 0;
02072
02073 Filename n_pattern = Filename::pattern_filename(fullpath_pattern.get_filename_index(z));
02074 Filename alpha_n_pattern = Filename::pattern_filename(alpha_fullpath_pattern.get_filename_index(z));
02075
02076 if (!n_pattern.has_hash()) {
02077 gobj_cat.error()
02078 << "Filename requires two different hash sequences: " << fullpath
02079 << "\n";
02080 return false;
02081 }
02082
02083 Filename file = n_pattern.get_filename_index(n);
02084 Filename alpha_file = alpha_n_pattern.get_filename_index(n);
02085
02086 if ((n_size == 0 && (vfs->exists(file) || n == 0)) ||
02087 (n_size != 0 && n < n_size)) {
02088
02089 } else {
02090
02091 break;
02092 }
02093
02094 while ((z_size == 0 && (vfs->exists(file) || z == 0)) ||
02095 (z_size != 0 && z < z_size)) {
02096 if (!do_read_one(file, alpha_file, z, n, primary_file_num_channels,
02097 alpha_file_channel, options, header_only, record)) {
02098 return false;
02099 }
02100 ++z;
02101
02102 n_pattern = Filename::pattern_filename(fullpath_pattern.get_filename_index(z));
02103 file = n_pattern.get_filename_index(n);
02104 alpha_file = alpha_n_pattern.get_filename_index(n);
02105 }
02106
02107 if (n == 0 && n_size == 0) {
02108
02109
02110
02111 n_size = do_get_expected_num_mipmap_levels();
02112 }
02113 ++n;
02114 }
02115
02116 } else if (read_pages) {
02117
02118 Filename fullpath_pattern = Filename::pattern_filename(fullpath);
02119 Filename alpha_fullpath_pattern = Filename::pattern_filename(alpha_fullpath);
02120 if (!fullpath_pattern.has_hash()) {
02121 gobj_cat.error()
02122 << "Filename requires a hash mark: " << fullpath
02123 << "\n";
02124 return false;
02125 }
02126
02127 do_set_z_size(z_size);
02128 z = 0;
02129 Filename file = fullpath_pattern.get_filename_index(z);
02130 Filename alpha_file = alpha_fullpath_pattern.get_filename_index(z);
02131 while ((z_size == 0 && (vfs->exists(file) || z == 0)) ||
02132 (z_size != 0 && z < z_size)) {
02133 if (!do_read_one(file, alpha_file, z, 0, primary_file_num_channels,
02134 alpha_file_channel, options, header_only, record)) {
02135 return false;
02136 }
02137 ++z;
02138
02139 file = fullpath_pattern.get_filename_index(z);
02140 alpha_file = alpha_fullpath_pattern.get_filename_index(z);
02141 }
02142
02143 } else if (read_mipmaps) {
02144
02145 Filename fullpath_pattern = Filename::pattern_filename(fullpath);
02146 Filename alpha_fullpath_pattern = Filename::pattern_filename(alpha_fullpath);
02147 if (!fullpath_pattern.has_hash()) {
02148 gobj_cat.error()
02149 << "Filename requires a hash mark: " << fullpath
02150 << "\n";
02151 return false;
02152 }
02153
02154 n = 0;
02155 Filename file = fullpath_pattern.get_filename_index(n);
02156 Filename alpha_file = alpha_fullpath_pattern.get_filename_index(n);
02157
02158 while ((n_size == 0 && (vfs->exists(file) || n == 0)) ||
02159 (n_size != 0 && n < n_size)) {
02160 if (!do_read_one(file, alpha_file, z, n,
02161 primary_file_num_channels, alpha_file_channel,
02162 options, header_only, record)) {
02163 return false;
02164 }
02165 ++n;
02166
02167 if (n_size == 0 && n >= do_get_expected_num_mipmap_levels()) {
02168
02169
02170 break;
02171 }
02172
02173 file = fullpath_pattern.get_filename_index(n);
02174 alpha_file = alpha_fullpath_pattern.get_filename_index(n);
02175 }
02176
02177 } else {
02178
02179 if (!do_read_one(fullpath, alpha_fullpath, z, n,
02180 primary_file_num_channels, alpha_file_channel,
02181 options, header_only, record)) {
02182 return false;
02183 }
02184 }
02185
02186 _has_read_pages = read_pages;
02187 _has_read_mipmaps = read_mipmaps;
02188 _num_mipmap_levels_read = _ram_images.size();
02189
02190 if (header_only) {
02191
02192
02193
02194 do_clear_ram_image();
02195 } else {
02196 if ((options.get_texture_flags() & LoaderOptions::TF_preload) != 0) {
02197
02198
02199 bool generate_mipmaps = ((options.get_texture_flags() & LoaderOptions::TF_generate_mipmaps) != 0);
02200 consider_auto_process_ram_image(generate_mipmaps || uses_mipmaps(), true);
02201 }
02202 }
02203
02204 return true;
02205 }
02206
02207
02208
02209
02210
02211
02212
02213
02214 bool Texture::
02215 do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
02216 int z, int n, int primary_file_num_channels, int alpha_file_channel,
02217 const LoaderOptions &options, bool header_only, BamCacheRecord *record) {
02218 if (record != (BamCacheRecord *)NULL) {
02219 nassertr(!header_only, false);
02220 record->add_dependent_file(fullpath);
02221 }
02222
02223 PNMImage image;
02224 if (header_only || textures_header_only) {
02225 if (!image.read_header(fullpath)) {
02226 gobj_cat.error()
02227 << "Texture::read() - couldn't read: " << fullpath << endl;
02228 return false;
02229 }
02230 int x_size = image.get_x_size();
02231 int y_size = image.get_y_size();
02232 if (z == 0 && n == 0) {
02233 _orig_file_x_size = x_size;
02234 _orig_file_y_size = y_size;
02235 }
02236
02237 if (textures_header_only) {
02238
02239
02240 x_size = 1;
02241 y_size = 1;
02242
02243 } else {
02244 consider_rescale(image, fullpath.get_basename());
02245 x_size = image.get_read_x_size();
02246 y_size = image.get_read_y_size();
02247 }
02248
02249 image = PNMImage(x_size, y_size, image.get_num_channels(),
02250 image.get_maxval(), image.get_type());
02251 image.fill(0.2, 0.3, 1.0);
02252 if (image.has_alpha()) {
02253 image.alpha_fill(1.0);
02254 }
02255
02256 } else {
02257 if (!image.read_header(fullpath, NULL, false)) {
02258 gobj_cat.error()
02259 << "Texture::read() - couldn't read: " << fullpath << endl;
02260 return false;
02261 }
02262
02263 if (z == 0 && n == 0) {
02264 _orig_file_x_size = image.get_x_size();
02265 _orig_file_y_size = image.get_y_size();
02266 consider_rescale(image, fullpath.get_basename());
02267 } else {
02268 image.set_read_size(do_get_expected_mipmap_x_size(n),
02269 do_get_expected_mipmap_y_size(n));
02270 }
02271
02272 if (image.get_x_size() != image.get_read_x_size() ||
02273 image.get_y_size() != image.get_read_y_size()) {
02274 gobj_cat.info()
02275 << "Implicitly rescaling " << fullpath.get_basename() << " from "
02276 << image.get_x_size() << " by " << image.get_y_size() << " to "
02277 << image.get_read_x_size() << " by " << image.get_read_y_size()
02278 << "\n";
02279 }
02280
02281 if (!image.read(fullpath, NULL, false)) {
02282 gobj_cat.error()
02283 << "Texture::read() - couldn't read: " << fullpath << endl;
02284 return false;
02285 }
02286 Thread::consider_yield();
02287 }
02288
02289 PNMImage alpha_image;
02290 if (!alpha_fullpath.empty()) {
02291 if (record != (BamCacheRecord *)NULL) {
02292 record->add_dependent_file(alpha_fullpath);
02293 }
02294
02295 if (header_only || textures_header_only) {
02296 if (!alpha_image.read_header(alpha_fullpath)) {
02297 gobj_cat.error()
02298 << "Texture::read() - couldn't read: " << alpha_fullpath << endl;
02299 return false;
02300 }
02301 int x_size = image.get_x_size();
02302 int y_size = image.get_y_size();
02303 alpha_image = PNMImage(x_size, y_size, alpha_image.get_num_channels(),
02304 alpha_image.get_maxval(), alpha_image.get_type());
02305 alpha_image.fill(1.0);
02306 if (alpha_image.has_alpha()) {
02307 alpha_image.alpha_fill(1.0);
02308 }
02309
02310 } else {
02311 if (!alpha_image.read_header(alpha_fullpath, NULL, true)) {
02312 gobj_cat.error()
02313 << "Texture::read() - couldn't read (alpha): " << alpha_fullpath << endl;
02314 return false;
02315 }
02316
02317 if (image.get_x_size() != alpha_image.get_x_size() ||
02318 image.get_y_size() != alpha_image.get_y_size()) {
02319 gobj_cat.info()
02320 << "Implicitly rescaling " << alpha_fullpath.get_basename()
02321 << " from " << alpha_image.get_x_size() << " by "
02322 << alpha_image.get_y_size() << " to " << image.get_x_size()
02323 << " by " << image.get_y_size() << "\n";
02324 alpha_image.set_read_size(image.get_x_size(), image.get_y_size());
02325 }
02326
02327 if (!alpha_image.read(alpha_fullpath, NULL, true)) {
02328 gobj_cat.error()
02329 << "Texture::read() - couldn't read (alpha): " << alpha_fullpath << endl;
02330 return false;
02331 }
02332 Thread::consider_yield();
02333 }
02334 }
02335
02336 if (z == 0 && n == 0) {
02337 if (!has_name()) {
02338 set_name(fullpath.get_basename_wo_extension());
02339 }
02340 if (_filename.empty()) {
02341 _filename = fullpath;
02342 _alpha_filename = alpha_fullpath;
02343
02344
02345
02346
02347 _keep_ram_image = false;
02348 }
02349
02350 _fullpath = fullpath;
02351 _alpha_fullpath = alpha_fullpath;
02352 }
02353
02354 if (!alpha_fullpath.empty()) {
02355
02356
02357
02358 if (image.get_x_size() != alpha_image.get_x_size() ||
02359 image.get_y_size() != alpha_image.get_y_size()) {
02360 gobj_cat.info()
02361 << "Automatically rescaling " << alpha_fullpath.get_basename()
02362 << " from " << alpha_image.get_x_size() << " by "
02363 << alpha_image.get_y_size() << " to " << image.get_x_size()
02364 << " by " << image.get_y_size() << "\n";
02365
02366 PNMImage scaled(image.get_x_size(), image.get_y_size(),
02367 alpha_image.get_num_channels(),
02368 alpha_image.get_maxval(), alpha_image.get_type());
02369 scaled.quick_filter_from(alpha_image);
02370 Thread::consider_yield();
02371 alpha_image = scaled;
02372 }
02373 }
02374
02375 if (n == 0) {
02376 consider_downgrade(image, primary_file_num_channels, get_name());
02377 _primary_file_num_channels = image.get_num_channels();
02378 _alpha_file_channel = 0;
02379 }
02380
02381 if (!alpha_fullpath.empty()) {
02382
02383
02384 image.add_alpha();
02385
02386 if (alpha_file_channel == 4 ||
02387 (alpha_file_channel == 2 && alpha_image.get_num_channels() == 2)) {
02388
02389 for (int x = 0; x < image.get_x_size(); x++) {
02390 for (int y = 0; y < image.get_y_size(); y++) {
02391 image.set_alpha(x, y, alpha_image.get_alpha(x, y));
02392 }
02393 }
02394 _alpha_file_channel = alpha_image.get_num_channels();
02395
02396 } else if (alpha_file_channel >= 1 && alpha_file_channel <= 3 &&
02397 alpha_image.get_num_channels() >= 3) {
02398
02399 for (int x = 0; x < image.get_x_size(); x++) {
02400 for (int y = 0; y < image.get_y_size(); y++) {
02401 image.set_alpha(x, y, alpha_image.get_channel_val(x, y, alpha_file_channel - 1));
02402 }
02403 }
02404 _alpha_file_channel = alpha_file_channel;
02405
02406 } else {
02407
02408 for (int x = 0; x < image.get_x_size(); x++) {
02409 for (int y = 0; y < image.get_y_size(); y++) {
02410 image.set_alpha(x, y, alpha_image.get_gray(x, y));
02411 }
02412 }
02413 _alpha_file_channel = 0;
02414 }
02415 }
02416
02417 return do_load_one(image, fullpath.get_basename(), z, n, options);
02418 }
02419
02420
02421
02422
02423
02424
02425
02426 bool Texture::
02427 do_load_one(const PNMImage &pnmimage, const string &name, int z, int n,
02428 const LoaderOptions &options) {
02429 if (_ram_images.size() <= 1 && n == 0) {
02430
02431
02432
02433 if (!do_reconsider_z_size(z)) {
02434 return false;
02435 }
02436 nassertr(z >= 0 && z < _z_size, false);
02437
02438 if (z == 0) {
02439 ComponentType component_type = T_unsigned_byte;
02440 xelval maxval = pnmimage.get_maxval();
02441 if (maxval > 255) {
02442 component_type = T_unsigned_short;
02443 }
02444
02445 if (!do_reconsider_image_properties(pnmimage.get_x_size(), pnmimage.get_y_size(),
02446 pnmimage.get_num_channels(), component_type,
02447 z, options)) {
02448 return false;
02449 }
02450 }
02451
02452 do_modify_ram_image();
02453 _loaded_from_image = true;
02454 }
02455
02456 do_modify_ram_mipmap_image(n);
02457
02458
02459 int x_size = do_get_expected_mipmap_x_size(n);
02460 int y_size = do_get_expected_mipmap_y_size(n);
02461 if (pnmimage.get_x_size() != x_size ||
02462 pnmimage.get_y_size() != y_size) {
02463 gobj_cat.info()
02464 << "Automatically rescaling " << name;
02465 if (n != 0) {
02466 gobj_cat.info(false)
02467 << " mipmap level " << n;
02468 }
02469 gobj_cat.info(false)
02470 << " from " << pnmimage.get_x_size() << " by "
02471 << pnmimage.get_y_size() << " to " << x_size << " by "
02472 << y_size << "\n";
02473
02474 PNMImage scaled(x_size, y_size, pnmimage.get_num_channels(),
02475 pnmimage.get_maxval(), pnmimage.get_type());
02476 scaled.quick_filter_from(pnmimage);
02477 Thread::consider_yield();
02478
02479 convert_from_pnmimage(_ram_images[n]._image,
02480 do_get_expected_ram_mipmap_page_size(n), z,
02481 scaled, _num_components, _component_width);
02482 } else {
02483
02484
02485 convert_from_pnmimage(_ram_images[n]._image,
02486 do_get_expected_ram_mipmap_page_size(n), z,
02487 pnmimage, _num_components, _component_width);
02488 }
02489 Thread::consider_yield();
02490
02491 return true;
02492 }
02493
02494
02495
02496
02497
02498
02499
02500 bool Texture::
02501 do_read_txo_file(const Filename &fullpath) {
02502 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
02503
02504 Filename filename = Filename::binary_filename(fullpath);
02505 PT(VirtualFile) file = vfs->get_file(filename);
02506 if (file == (VirtualFile *)NULL) {
02507
02508 gobj_cat.error()
02509 << "Could not find " << fullpath << "\n";
02510 return false;
02511 }
02512
02513 if (gobj_cat.is_debug()) {
02514 gobj_cat.debug()
02515 << "Reading texture object " << filename << "\n";
02516 }
02517
02518 istream *in = file->open_read_file(true);
02519 bool success = do_read_txo(*in, fullpath);
02520 vfs->close_read_file(in);
02521
02522 _fullpath = fullpath;
02523 _alpha_fullpath = Filename();
02524 _keep_ram_image = false;
02525
02526 return success;
02527 }
02528
02529
02530
02531
02532
02533
02534 bool Texture::
02535 do_read_txo(istream &in, const string &filename) {
02536 DatagramInputFile din;
02537
02538 if (!din.open(in)) {
02539 gobj_cat.error()
02540 << "Could not read texture object: " << filename << "\n";
02541 return false;
02542 }
02543
02544 string head;
02545 if (!din.read_header(head, _bam_header.size())) {
02546 gobj_cat.error()
02547 << filename << " is not a texture object file.\n";
02548 return false;
02549 }
02550
02551 if (head != _bam_header) {
02552 gobj_cat.error()
02553 << filename << " is not a texture object file.\n";
02554 return false;
02555 }
02556
02557 BamReader reader(&din, filename);
02558 if (!reader.init()) {
02559 return false;
02560 }
02561
02562 TypedWritable *object = reader.read_object();
02563
02564 if (object != (TypedWritable *)NULL &&
02565 object->is_exact_type(BamCacheRecord::get_class_type())) {
02566
02567
02568
02569
02570 object = reader.read_object();
02571 }
02572
02573 if (object == (TypedWritable *)NULL) {
02574 gobj_cat.error()
02575 << "Texture object " << filename << " is empty.\n";
02576 return false;
02577
02578 } else if (!object->is_of_type(Texture::get_class_type())) {
02579 gobj_cat.error()
02580 << "Texture object " << filename << " contains a "
02581 << object->get_type() << ", not a Texture.\n";
02582 return false;
02583 }
02584
02585 PT(Texture) other = DCAST(Texture, object);
02586 if (!reader.resolve()) {
02587 gobj_cat.error()
02588 << "Unable to fully resolve texture object file.\n";
02589 return false;
02590 }
02591
02592 Namable::operator = (*other);
02593 do_assign(*other);
02594 _loaded_from_image = true;
02595 _loaded_from_txo = true;
02596 _has_read_pages = false;
02597 _has_read_mipmaps = false;
02598 _num_mipmap_levels_read = 0;
02599 return true;
02600 }
02601
02602
02603
02604
02605
02606
02607
02608 bool Texture::
02609 do_read_dds_file(const Filename &fullpath, bool header_only) {
02610 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
02611
02612 Filename filename = Filename::binary_filename(fullpath);
02613 PT(VirtualFile) file = vfs->get_file(filename);
02614 if (file == (VirtualFile *)NULL) {
02615
02616 gobj_cat.error()
02617 << "Could not find " << fullpath << "\n";
02618 return false;
02619 }
02620
02621 if (gobj_cat.is_debug()) {
02622 gobj_cat.debug()
02623 << "Reading DDS file " << filename << "\n";
02624 }
02625
02626 istream *in = file->open_read_file(true);
02627 bool success = do_read_dds(*in, fullpath, header_only);
02628 vfs->close_read_file(in);
02629
02630 if (!has_name()) {
02631 set_name(fullpath.get_basename_wo_extension());
02632 }
02633
02634 _fullpath = fullpath;
02635 _alpha_fullpath = Filename();
02636 _keep_ram_image = false;
02637
02638 return success;
02639 }
02640
02641
02642
02643
02644
02645
02646 bool Texture::
02647 do_read_dds(istream &in, const string &filename, bool header_only) {
02648 StreamReader dds(in);
02649
02650
02651 DDSHeader header;
02652 header.dds_magic = dds.get_uint32();
02653 header.dds_size = dds.get_uint32();
02654 header.dds_flags = dds.get_uint32();
02655 header.height = dds.get_uint32();
02656 header.width = dds.get_uint32();
02657 header.pitch = dds.get_uint32();
02658 header.depth = dds.get_uint32();
02659 header.num_levels = dds.get_uint32();
02660 dds.skip_bytes(44);
02661
02662
02663 header.pf.pf_size = dds.get_uint32();
02664 header.pf.pf_flags = dds.get_uint32();
02665 header.pf.four_cc = dds.get_uint32();
02666 header.pf.rgb_bitcount = dds.get_uint32();
02667 header.pf.r_mask = dds.get_uint32();
02668 header.pf.g_mask = dds.get_uint32();
02669 header.pf.b_mask = dds.get_uint32();
02670 header.pf.a_mask = dds.get_uint32();
02671
02672
02673 header.caps.caps1 = dds.get_uint32();
02674 header.caps.caps2 = dds.get_uint32();
02675 header.caps.ddsx = dds.get_uint32();
02676 dds.skip_bytes(4);
02677
02678
02679 dds.skip_bytes(4);
02680
02681 if (header.dds_magic != DDS_MAGIC || (in.fail() || in.eof())) {
02682 gobj_cat.error()
02683 << filename << " is not a DDS file.\n";
02684 return false;
02685 }
02686
02687 if ((header.dds_flags & DDSD_MIPMAPCOUNT) == 0) {
02688
02689 header.num_levels = 1;
02690 }
02691
02692 TextureType texture_type;
02693 if (header.caps.caps2 & DDSCAPS2_CUBEMAP) {
02694 static const unsigned int all_faces =
02695 (DDSCAPS2_CUBEMAP_POSITIVEX |
02696 DDSCAPS2_CUBEMAP_POSITIVEY |
02697 DDSCAPS2_CUBEMAP_POSITIVEZ |
02698 DDSCAPS2_CUBEMAP_NEGATIVEX |
02699 DDSCAPS2_CUBEMAP_NEGATIVEY |
02700 DDSCAPS2_CUBEMAP_NEGATIVEZ);
02701 if ((header.caps.caps2 & all_faces) != all_faces) {
02702 gobj_cat.error()
02703 << filename << " is missing some cube map faces; cannot load.\n";
02704 return false;
02705 }
02706 header.depth = 6;
02707 texture_type = TT_cube_map;
02708
02709 } else if (header.caps.caps2 & DDSCAPS2_VOLUME) {
02710 texture_type = TT_3d_texture;
02711
02712 } else {
02713 texture_type = TT_2d_texture;
02714 header.depth = 1;
02715 }
02716
02717
02718 typedef PTA_uchar (*ReadDDSLevelFunc)(Texture *tex, const DDSHeader &header,
02719 int n, istream &in);
02720 ReadDDSLevelFunc func = NULL;
02721
02722 Format format = F_rgb;
02723
02724 do_clear_ram_image();
02725 CompressionMode compression = CM_off;
02726
02727 if (header.pf.pf_flags & DDPF_FOURCC) {
02728
02729 if (texture_type == TT_3d_texture) {
02730 gobj_cat.error()
02731 << filename << ": unsupported compression on 3-d texture.\n";
02732 return false;
02733 }
02734
02735 if (header.pf.four_cc == 0x31545844) {
02736 compression = CM_dxt1;
02737 func = read_dds_level_dxt1;
02738 } else if (header.pf.four_cc == 0x32545844) {
02739 compression = CM_dxt2;
02740 func = read_dds_level_dxt23;
02741 } else if (header.pf.four_cc == 0x33545844) {
02742 compression = CM_dxt3;
02743 func = read_dds_level_dxt23;
02744 } else if (header.pf.four_cc == 0x34545844) {
02745 compression = CM_dxt4;
02746 func = read_dds_level_dxt45;
02747 } else if (header.pf.four_cc == 0x35545844) {
02748 compression = CM_dxt5;
02749 func = read_dds_level_dxt45;
02750 } else {
02751 gobj_cat.error()
02752 << filename << ": unsupported texture compression.\n";
02753 return false;
02754 }
02755
02756
02757
02758 format = F_rgba;
02759
02760 } else {
02761
02762 func = read_dds_level_generic_uncompressed;
02763
02764 if (header.pf.pf_flags & DDPF_ALPHAPIXELS) {
02765
02766 format = F_rgba;
02767 if (header.pf.rgb_bitcount == 32 &&
02768 header.pf.r_mask == 0x000000ff &&
02769 header.pf.g_mask == 0x0000ff00 &&
02770 header.pf.b_mask == 0x00ff0000 &&
02771 header.pf.a_mask == 0xff000000U) {
02772 func = read_dds_level_abgr8;
02773 } else if (header.pf.rgb_bitcount == 32 &&
02774 header.pf.r_mask == 0x00ff0000 &&
02775 header.pf.g_mask == 0x0000ff00 &&
02776 header.pf.b_mask == 0x000000ff &&
02777 header.pf.a_mask == 0xff000000U) {
02778 func = read_dds_level_rgba8;
02779
02780 } else if (header.pf.r_mask != 0 &&
02781 header.pf.g_mask == 0 &&
02782 header.pf.b_mask == 0) {
02783 func = read_dds_level_luminance_uncompressed;
02784 format = F_luminance_alpha;
02785 }
02786 } else {
02787
02788 if (header.pf.rgb_bitcount == 24 &&
02789 header.pf.r_mask == 0x00ff0000 &&
02790 header.pf.g_mask == 0x0000ff00 &&
02791 header.pf.b_mask == 0x000000ff) {
02792 func = read_dds_level_bgr8;
02793 } else if (header.pf.rgb_bitcount == 24 &&
02794 header.pf.r_mask == 0x000000ff &&
02795 header.pf.g_mask == 0x0000ff00 &&
02796 header.pf.b_mask == 0x00ff0000) {
02797 func = read_dds_level_rgb8;
02798
02799 } else if (header.pf.r_mask != 0 &&
02800 header.pf.g_mask == 0 &&
02801 header.pf.b_mask == 0) {
02802 func = read_dds_level_luminance_uncompressed;
02803 format = F_luminance;
02804 }
02805 }
02806
02807 }
02808
02809 do_setup_texture(texture_type, header.width, header.height, header.depth,
02810 T_unsigned_byte, format);
02811
02812 _orig_file_x_size = _x_size;
02813 _orig_file_y_size = _y_size;
02814 _compression = compression;
02815 _ram_image_compression = compression;
02816
02817 if (!header_only) {
02818 switch (texture_type) {
02819 case TT_3d_texture:
02820 {
02821
02822
02823 for (int n = 0; n < (int)header.num_levels; ++n) {
02824 int z_size = do_get_expected_mipmap_z_size(n);
02825 pvector<PTA_uchar> pages;
02826 size_t page_size = 0;
02827 int z;
02828 for (z = 0; z < z_size; ++z) {
02829 PTA_uchar page = func(this, header, n, in);
02830 if (page.is_null()) {
02831 return false;
02832 }
02833 nassertr(page_size == 0 || page_size == page.size(), false);
02834 page_size = page.size();
02835 pages.push_back(page);
02836 }
02837
02838
02839
02840 PTA_uchar image = PTA_uchar::empty_array(page_size * z_size);
02841 unsigned char *imagep = (unsigned char *)image.p();
02842 for (z = 0; z < z_size; ++z) {
02843 int fz = z_size - 1 - z;
02844 memcpy(imagep + z * page_size, pages[fz].p(), page_size);
02845 }
02846
02847 do_set_ram_mipmap_image(n, image, page_size);
02848 }
02849 }
02850 break;
02851
02852 case TT_cube_map:
02853 {
02854
02855
02856 pvector<pvector<PTA_uchar> > pages;
02857 pages.reserve(6);
02858 int z, n;
02859 for (z = 0; z < 6; ++z) {
02860 pages.push_back(pvector<PTA_uchar>());
02861 pvector<PTA_uchar> &levels = pages.back();
02862 levels.reserve(header.num_levels);
02863
02864 for (n = 0; n < (int)header.num_levels; ++n) {
02865 PTA_uchar image = func(this, header, n, in);
02866 if (image.is_null()) {
02867 return false;
02868 }
02869 levels.push_back(image);
02870 }
02871 }
02872
02873
02874
02875
02876 static const int level_remap[6] = {
02877 0, 1, 5, 4, 2, 3
02878 };
02879 for (n = 0; n < (int)header.num_levels; ++n) {
02880 size_t page_size = pages[0][n].size();
02881 PTA_uchar image = PTA_uchar::empty_array(page_size * 6);
02882 unsigned char *imagep = (unsigned char *)image.p();
02883 for (z = 0; z < 6; ++z) {
02884 int fz = level_remap[z];
02885 nassertr(pages[fz][n].size() == page_size, false);
02886 memcpy(imagep + z * page_size, pages[fz][n].p(), page_size);
02887 }
02888
02889 do_set_ram_mipmap_image(n, image, page_size);
02890 }
02891 }
02892 break;
02893
02894 default:
02895
02896 {
02897 for (int n = 0; n < (int)header.num_levels; ++n) {
02898 PTA_uchar image = func(this, header, n, in);
02899 if (image.is_null()) {
02900 return false;
02901 }
02902 do_set_ram_mipmap_image(n, image, 0);
02903 }
02904 }
02905 }
02906 _has_read_pages = true;
02907 _has_read_mipmaps = true;
02908 _num_mipmap_levels_read = _ram_images.size();
02909 }
02910
02911 if (in.fail() || in.eof()) {
02912 gobj_cat.error()
02913 << filename << ": truncated DDS file.\n";
02914 return false;
02915 }
02916
02917 _loaded_from_image = true;
02918 _loaded_from_txo = true;
02919
02920 return true;
02921 }
02922
02923
02924
02925
02926
02927
02928
02929 bool Texture::
02930 do_write(const Filename &fullpath, int z, int n, bool write_pages, bool write_mipmaps) const {
02931 if (is_txo_filename(fullpath)) {
02932 if (!do_has_ram_image()) {
02933 ((Texture *)this)->do_get_ram_image();
02934 }
02935 nassertr(do_has_ram_image(), false);
02936 return do_write_txo_file(fullpath);
02937 }
02938
02939 if (!do_has_uncompressed_ram_image()) {
02940 ((Texture *)this)->do_get_uncompressed_ram_image();
02941 }
02942
02943 nassertr(do_has_ram_mipmap_image(n), false);
02944 nassertr(_ram_image_compression == CM_off, false);
02945
02946 if (write_pages && write_mipmaps) {
02947
02948 Filename fullpath_pattern = Filename::pattern_filename(fullpath);
02949 int num_levels = _ram_images.size();
02950
02951 for (int n = 0; n < num_levels; ++n) {
02952 int z_size = do_get_expected_mipmap_z_size(n);
02953
02954 for (z = 0; z < z_size; ++z) {
02955 Filename n_pattern = Filename::pattern_filename(fullpath_pattern.get_filename_index(z));
02956
02957 if (!n_pattern.has_hash()) {
02958 gobj_cat.error()
02959 << "Filename requires two different hash sequences: " << fullpath
02960 << "\n";
02961 return false;
02962 }
02963
02964 if (!do_write_one(n_pattern.get_filename_index(n), z, n)) {
02965 return false;
02966 }
02967 }
02968 }
02969
02970 } else if (write_pages) {
02971
02972 Filename fullpath_pattern = Filename::pattern_filename(fullpath);
02973 if (!fullpath_pattern.has_hash()) {
02974 gobj_cat.error()
02975 << "Filename requires a hash mark: " << fullpath
02976 << "\n";
02977 return false;
02978 }
02979
02980 for (z = 0; z < _z_size; ++z) {
02981 if (!do_write_one(fullpath_pattern.get_filename_index(z), z, n)) {
02982 return false;
02983 }
02984 }
02985
02986 } else if (write_mipmaps) {
02987
02988 Filename fullpath_pattern = Filename::pattern_filename(fullpath);
02989 if (!fullpath_pattern.has_hash()) {
02990 gobj_cat.error()
02991 << "Filename requires a hash mark: " << fullpath
02992 << "\n";
02993 return false;
02994 }
02995
02996 int num_levels = _ram_images.size();
02997 for (int n = 0; n < num_levels; ++n) {
02998 if (!do_write_one(fullpath_pattern.get_filename_index(n), z, n)) {
02999 return false;
03000 }
03001 }
03002
03003 } else {
03004
03005 if (!do_write_one(fullpath, z, n)) {
03006 return false;
03007 }
03008 }
03009
03010 return true;
03011 }
03012
03013
03014
03015
03016
03017
03018
03019 bool Texture::
03020 do_write_one(const Filename &fullpath, int z, int n) const {
03021 if (!do_has_ram_mipmap_image(n)) {
03022 return false;
03023 }
03024
03025 nassertr(_ram_image_compression == CM_off, false);
03026
03027 PNMImage pnmimage;
03028 if (!do_store_one(pnmimage, z, n)) {
03029 return false;
03030 }
03031
03032 if (!pnmimage.write(fullpath)) {
03033 gobj_cat.error()
03034 << "Texture::write() - couldn't write: " << fullpath << endl;
03035 return false;
03036 }
03037 return true;
03038 }
03039
03040
03041
03042
03043
03044
03045
03046 bool Texture::
03047 do_store_one(PNMImage &pnmimage, int z, int n) const {
03048
03049 ((Texture *)this)->do_get_uncompressed_ram_image();
03050
03051 nassertr(do_has_ram_mipmap_image(n), false);
03052 nassertr(z >= 0 && z < do_get_expected_mipmap_z_size(n), false);
03053 nassertr(_ram_image_compression == CM_off, false);
03054
03055 return convert_to_pnmimage(pnmimage,
03056 do_get_expected_mipmap_x_size(n),
03057 do_get_expected_mipmap_y_size(n),
03058 _num_components, _component_width,
03059 _ram_images[n]._image,
03060 do_get_ram_mipmap_page_size(n), z);
03061 }
03062
03063
03064
03065
03066
03067
03068
03069 bool Texture::
03070 do_write_txo_file(const Filename &fullpath) const {
03071 Filename filename = Filename::binary_filename(fullpath);
03072 pofstream out;
03073 if (!filename.open_write(out)) {
03074 gobj_cat.error()
03075 << "Unable to open " << filename << "\n";
03076 return false;
03077 }
03078
03079 #ifdef HAVE_ZLIB
03080 if (fullpath.get_extension() == "pz") {
03081 OCompressStream compressor(&out, false);
03082 return do_write_txo(compressor, "stream");
03083 }
03084 #endif // HAVE_ZLIB
03085 return do_write_txo(out, fullpath);
03086 }
03087
03088
03089
03090
03091
03092
03093 bool Texture::
03094 do_write_txo(ostream &out, const string &filename) const {
03095 DatagramOutputFile dout;
03096
03097 if (!dout.open(out)) {
03098 gobj_cat.error()
03099 << "Could not write texture object: " << filename << "\n";
03100 return false;
03101 }
03102
03103 if (!dout.write_header(_bam_header)) {
03104 gobj_cat.error()
03105 << "Unable to write to " << filename << "\n";
03106 return false;
03107 }
03108
03109 BamWriter writer(&dout, filename);
03110 if (!writer.init()) {
03111 return false;
03112 }
03113
03114 writer.set_file_texture_mode(BamWriter::BTM_rawdata);
03115
03116
03117
03118
03119 _lock.release();
03120 if (!writer.write_object(this)) {
03121 _lock.acquire();
03122 return false;
03123 }
03124 _lock.acquire();
03125
03126 if (!do_has_ram_image()) {
03127 gobj_cat.error()
03128 << get_name() << " does not have ram image\n";
03129 return false;
03130 }
03131
03132 return true;
03133 }
03134
03135
03136
03137
03138
03139
03140
03141
03142
03143
03144
03145
03146
03147
03148
03149
03150 void Texture::
03151 do_unlock_and_reload_ram_image(bool allow_compression) {
03152
03153
03154 while (_reloading) {
03155 _cvar.wait();
03156 }
03157
03158
03159 bool has_ram_image = do_has_ram_image();
03160 if (has_ram_image && !allow_compression && get_ram_image_compression() != Texture::CM_off) {
03161
03162
03163 has_ram_image = false;
03164 }
03165 if (_loaded_from_image && !has_ram_image && !_fullpath.empty()) {
03166 nassertv(!_reloading);
03167 _reloading = true;
03168
03169 PT(Texture) tex = do_make_copy();
03170 _lock.release();
03171
03172
03173
03174 tex->do_reload_ram_image(allow_compression);
03175
03176 _lock.acquire();
03177
03178
03179
03180
03181
03182
03183
03184 _orig_file_x_size = tex->_orig_file_x_size;
03185 _orig_file_y_size = tex->_orig_file_y_size;
03186
03187
03188
03189 if (tex->_x_size != _x_size ||
03190 tex->_y_size != _y_size ||
03191 tex->_z_size != _z_size ||
03192 tex->_num_components != _num_components ||
03193 tex->_component_width != _component_width ||
03194 tex->_texture_type != _texture_type ||
03195 tex->_component_type != _component_type) {
03196
03197 _x_size = tex->_x_size;
03198 _y_size = tex->_y_size;
03199 _z_size = tex->_z_size;
03200
03201 _num_components = tex->_num_components;
03202 _component_width = tex->_component_width;
03203 _texture_type = tex->_texture_type;
03204 _format = tex->_format;
03205 _component_type = tex->_component_type;
03206
03207
03208
03209
03210
03211 ++_properties_modified;
03212 ++_image_modified;
03213 }
03214
03215 _keep_ram_image = tex->_keep_ram_image;
03216 _ram_image_compression = tex->_ram_image_compression;
03217 _ram_images = tex->_ram_images;
03218
03219 nassertv(_reloading);
03220 _reloading = false;
03221
03222
03223
03224
03225
03226 _cvar.notify_all();
03227 }
03228 }
03229
03230
03231
03232
03233
03234
03235
03236
03237
03238
03239
03240
03241 void Texture::
03242 do_reload_ram_image(bool allow_compression) {
03243 BamCache *cache = BamCache::get_global_ptr();
03244 PT(BamCacheRecord) record;
03245
03246 if (!do_has_compression()) {
03247 allow_compression = false;
03248 }
03249
03250 if ((cache->get_cache_textures() || (allow_compression && cache->get_cache_compressed_textures())) && !textures_header_only) {
03251
03252
03253
03254 record = cache->lookup(_fullpath, "txo");
03255 if (record != (BamCacheRecord *)NULL &&
03256 record->has_data()) {
03257 PT(Texture) tex = DCAST(Texture, record->get_data());
03258
03259
03260
03261 int x_size = _orig_file_x_size;
03262 int y_size = _orig_file_y_size;
03263 Texture::adjust_size(x_size, y_size, _filename.get_basename());
03264 if (x_size != tex->get_x_size() || y_size != tex->get_y_size()) {
03265 if (gobj_cat.is_debug()) {
03266 gobj_cat.debug()
03267 << "Cached texture " << *this << " has size "
03268 << tex->get_x_size() << " x " << tex->get_y_size()
03269 << " instead of " << x_size << " x " << y_size
03270 << "; ignoring cache.\n";
03271 }
03272 } else {
03273
03274
03275 if (!allow_compression && tex->get_ram_image_compression() != Texture::CM_off) {
03276 if (gobj_cat.is_debug()) {
03277 gobj_cat.debug()
03278 << "Cached texture " << *this
03279 << " is compressed in cache; ignoring cache.\n";
03280 }
03281 } else {
03282 gobj_cat.info()
03283 << "Texture " << get_name() << " reloaded from disk cache\n";
03284
03285
03286
03287
03288 _x_size = tex->get_x_size();
03289 _y_size = tex->get_y_size();
03290 _num_components = tex->get_num_components();
03291 _format = tex->get_format();
03292 _component_type = tex->get_component_type();
03293 _compression = tex->get_compression();
03294 _ram_image_compression = tex->_ram_image_compression;
03295 _ram_images = tex->_ram_images;
03296 _loaded_from_image = true;
03297
03298 bool was_compressed = (_ram_image_compression != CM_off);
03299 if (consider_auto_process_ram_image(uses_mipmaps(), allow_compression)) {
03300 bool is_compressed = (_ram_image_compression != CM_off);
03301 if (!was_compressed && is_compressed &&
03302 cache->get_cache_compressed_textures()) {
03303
03304
03305
03306 record->set_data(this, this);
03307 cache->store(record);
03308 }
03309 }
03310
03311 return;
03312 }
03313 }
03314 }
03315 }
03316
03317 gobj_cat.info()
03318 << "Reloading texture " << get_name() << "\n";
03319
03320 int z = 0;
03321 int n = 0;
03322
03323 if (_has_read_pages) {
03324 z = _z_size;
03325 }
03326 if (_has_read_mipmaps) {
03327 n = _num_mipmap_levels_read;
03328 }
03329
03330 _loaded_from_image = false;
03331 Format orig_format = _format;
03332 int orig_num_components = _num_components;
03333
03334 LoaderOptions options;
03335 options.set_texture_flags(LoaderOptions::TF_preload);
03336 do_read(_fullpath, _alpha_fullpath,
03337 _primary_file_num_channels, _alpha_file_channel,
03338 z, n, _has_read_pages, _has_read_mipmaps, options, NULL);
03339
03340 if (orig_num_components == _num_components) {
03341
03342
03343 _format = orig_format;
03344 }
03345
03346 if (do_has_ram_image() && record != (BamCacheRecord *)NULL) {
03347 if (cache->get_cache_textures() || (_ram_image_compression != CM_off && cache->get_cache_compressed_textures())) {
03348
03349 if (record != (BamCacheRecord *)NULL) {
03350 record->add_dependent_file(_fullpath);
03351 }
03352 record->set_data(this, this);
03353 cache->store(record);
03354 }
03355 }
03356 }
03357
03358
03359
03360
03361
03362
03363
03364 PTA_uchar Texture::
03365 do_modify_ram_image() {
03366 if (_ram_images.empty() || _ram_images[0]._image.empty() ||
03367 _ram_image_compression != CM_off) {
03368 do_make_ram_image();
03369 } else {
03370 do_clear_ram_mipmap_images();
03371 }
03372 return _ram_images[0]._image;
03373 }
03374
03375
03376
03377
03378
03379
03380
03381 PTA_uchar Texture::
03382 do_make_ram_image() {
03383 _ram_images.clear();
03384 _ram_images.push_back(RamImage());
03385 _ram_images[0]._page_size = do_get_expected_ram_page_size();
03386 _ram_images[0]._image = PTA_uchar::empty_array(do_get_expected_ram_image_size(), get_class_type());
03387 _ram_images[0]._pointer_image = NULL;
03388 _ram_image_compression = CM_off;
03389 return _ram_images[0]._image;
03390 }
03391
03392
03393
03394
03395
03396
03397
03398 PTA_uchar Texture::
03399 do_modify_ram_mipmap_image(int n) {
03400 nassertr(_ram_image_compression == CM_off, PTA_uchar());
03401
03402 if (n >= (int)_ram_images.size() ||
03403 _ram_images[n]._image.empty()) {
03404 do_make_ram_mipmap_image(n);
03405 }
03406 return _ram_images[n]._image;
03407 }
03408
03409
03410
03411
03412
03413
03414 PTA_uchar Texture::
03415 do_make_ram_mipmap_image(int n) {
03416 nassertr(_ram_image_compression == CM_off, PTA_uchar(get_class_type()));
03417
03418 while (n >= (int)_ram_images.size()) {
03419 _ram_images.push_back(RamImage());
03420 }
03421
03422 _ram_images[n]._image = PTA_uchar::empty_array(do_get_expected_ram_mipmap_image_size(n), get_class_type());
03423 _ram_images[n]._pointer_image = NULL;
03424 _ram_images[n]._page_size = do_get_expected_ram_mipmap_page_size(n);
03425 return _ram_images[n]._image;
03426 }
03427
03428
03429
03430
03431
03432
03433 void Texture::
03434 do_set_ram_mipmap_image(int n, CPTA_uchar image, size_t page_size) {
03435 nassertv(_ram_image_compression != CM_off || image.size() == do_get_expected_ram_mipmap_image_size(n));
03436
03437 while (n >= (int)_ram_images.size()) {
03438 _ram_images.push_back(RamImage());
03439 }
03440 if (page_size == 0) {
03441 page_size = image.size();
03442 }
03443
03444 if (_ram_images[n]._image != image ||
03445 _ram_images[n]._page_size != page_size) {
03446 _ram_images[n]._image = image.cast_non_const();
03447 _ram_images[n]._pointer_image = NULL;
03448 _ram_images[n]._page_size = page_size;
03449 ++_image_modified;
03450 }
03451 }
03452
03453
03454
03455
03456
03457
03458
03459
03460
03461
03462
03463 bool Texture::
03464 consider_auto_process_ram_image(bool generate_mipmaps, bool allow_compression) {
03465 bool modified = false;
03466
03467 if (generate_mipmaps && !driver_generate_mipmaps &&
03468 _ram_images.size() == 1) {
03469 do_generate_ram_mipmap_images();
03470 modified = true;
03471 }
03472
03473 if (allow_compression && !driver_compress_textures) {
03474 CompressionMode compression = _compression;
03475 if (compression == CM_default && compressed_textures) {
03476 compression = CM_on;
03477 }
03478 if (compression != CM_off && _ram_image_compression == CM_off) {
03479 GraphicsStateGuardianBase *gsg = GraphicsStateGuardianBase::get_default_gsg();
03480 if (do_compress_ram_image(compression, QL_default, gsg)) {
03481 if (gobj_cat.is_debug()) {
03482 gobj_cat.debug()
03483 << "Compressed " << get_name() << " with "
03484 << _ram_image_compression << "\n";
03485 }
03486 modified = true;
03487 }
03488 }
03489 }
03490
03491 return modified;
03492 }
03493
03494
03495
03496
03497
03498
03499 bool Texture::
03500 do_compress_ram_image(Texture::CompressionMode compression,
03501 Texture::QualityLevel quality_level,
03502 GraphicsStateGuardianBase *gsg) {
03503 nassertr(compression != CM_off, false);
03504
03505 if (compression == CM_on) {
03506
03507 switch (_format) {
03508 case Texture::F_rgbm:
03509 case Texture::F_rgb:
03510 case Texture::F_rgb5:
03511 case Texture::F_rgba5:
03512 case Texture::F_rgb8:
03513 case Texture::F_rgb12:
03514 case Texture::F_rgb332:
03515 if (gsg == NULL || gsg->get_supports_compressed_texture_format(CM_dxt1)) {
03516 compression = CM_dxt1;
03517 } else if (gsg == NULL || gsg->get_supports_compressed_texture_format(CM_dxt3)) {
03518 compression = CM_dxt3;
03519 } else if (gsg == NULL || gsg->get_supports_compressed_texture_format(CM_dxt5)) {
03520 compression = CM_dxt5;
03521 }
03522 break;
03523
03524 case Texture::F_rgba4:
03525 if (gsg == NULL || gsg->get_supports_compressed_texture_format(CM_dxt3)) {
03526 compression = CM_dxt3;
03527 } else if (gsg == NULL || gsg->get_supports_compressed_texture_format(CM_dxt5)) {
03528 compression = CM_dxt5;
03529 }
03530 break;
03531
03532 case Texture::F_rgba:
03533 case Texture::F_rgba8:
03534 case Texture::F_rgba12:
03535 case Texture::F_rgba16:
03536 case Texture::F_rgba32:
03537 if (gsg == NULL || gsg->get_supports_compressed_texture_format(CM_dxt5)) {
03538 compression = CM_dxt5;
03539 }
03540 break;
03541
03542 default:
03543 break;
03544 }
03545 }
03546
03547
03548 if (quality_level == Texture::QL_default) {
03549 quality_level = _quality_level;
03550 }
03551 if (quality_level == Texture::QL_default) {
03552 quality_level = texture_quality_level;
03553 }
03554
03555 #ifdef HAVE_SQUISH
03556 if (_texture_type != TT_3d_texture && _component_type == T_unsigned_byte) {
03557 int squish_flags = 0;
03558 switch (compression) {
03559 case CM_dxt1:
03560 squish_flags |= squish::kDxt1;
03561 break;
03562
03563 case CM_dxt3:
03564 squish_flags |= squish::kDxt3;
03565 break;
03566
03567 case CM_dxt5:
03568 squish_flags |= squish::kDxt5;
03569 break;
03570
03571 default:
03572 break;
03573 }
03574
03575 if (squish_flags != 0) {
03576
03577 switch (quality_level) {
03578 case QL_fastest:
03579 squish_flags |= squish::kColourRangeFit;
03580 break;
03581
03582 case QL_normal:
03583
03584 squish_flags |= squish::kColourRangeFit;
03585
03586 break;
03587
03588 case QL_best:
03589 squish_flags |= squish::kColourIterativeClusterFit;
03590 break;
03591
03592 default:
03593 break;
03594 }
03595
03596 if (do_squish(compression, squish_flags)) {
03597 return true;
03598 }
03599 }
03600 }
03601 #endif // HAVE_SQUISH
03602
03603 return false;
03604 }
03605
03606
03607
03608
03609
03610
03611 bool Texture::
03612 do_uncompress_ram_image() {
03613
03614 #ifdef HAVE_SQUISH
03615 if (_texture_type != TT_3d_texture && _component_type == T_unsigned_byte) {
03616 int squish_flags = 0;
03617 switch (_ram_image_compression) {
03618 case CM_dxt1:
03619 squish_flags |= squish::kDxt1;
03620 break;
03621
03622 case CM_dxt3:
03623 squish_flags |= squish::kDxt3;
03624 break;
03625
03626 case CM_dxt5:
03627 squish_flags |= squish::kDxt5;
03628 break;
03629
03630 default:
03631 break;
03632 }
03633
03634 if (squish_flags != 0) {
03635
03636 if (do_unsquish(squish_flags)) {
03637 return true;
03638 }
03639 }
03640 }
03641 #endif // HAVE_SQUISH
03642 return false;
03643 }
03644
03645
03646
03647
03648
03649
03650 bool Texture::
03651 do_has_all_ram_mipmap_images() const {
03652 if (_ram_images.empty() || _ram_images[0]._image.empty()) {
03653
03654 return false;
03655 }
03656 if (!uses_mipmaps()) {
03657
03658
03659 return true;
03660 }
03661
03662
03663
03664 int size = max(_x_size, max(_y_size, _z_size));
03665 int n = 0;
03666 int x = 1;
03667 while (x < size) {
03668 x = (x << 1);
03669 ++n;
03670 if (n >= (int)_ram_images.size() || _ram_images[n]._image.empty()) {
03671 return false;
03672 }
03673 }
03674
03675 return true;
03676 }
03677
03678
03679
03680
03681
03682
03683
03684
03685
03686
03687 bool Texture::
03688 do_reconsider_z_size(int z) {
03689 if (z >= _z_size) {
03690
03691
03692
03693
03694 nassertr(_texture_type == Texture::TT_3d_texture, false);
03695
03696 _z_size = z + 1;
03697
03698
03699 size_t new_size = do_get_expected_ram_image_size();
03700 if (!_ram_images.empty() &&
03701 !_ram_images[0]._image.empty() &&
03702 new_size > _ram_images[0]._image.size()) {
03703 _ram_images[0]._image.insert(_ram_images[0]._image.end(), new_size - _ram_images[0]._image.size(), 0);
03704 nassertr(_ram_images[0]._image.size() == new_size, false);
03705 }
03706 }
03707
03708 return true;
03709 }
03710
03711
03712
03713
03714
03715
03716
03717
03718
03719
03720 bool Texture::
03721 do_reconsider_image_properties(int x_size, int y_size, int num_components,
03722 Texture::ComponentType component_type, int z,
03723 const LoaderOptions &options) {
03724 if (!_loaded_from_image || num_components != _num_components) {
03725
03726
03727
03728
03729 switch (num_components) {
03730 case 1:
03731 _format = F_luminance;
03732 break;
03733
03734 case 2:
03735 _format = F_luminance_alpha;
03736 break;
03737
03738 case 3:
03739 _format = F_rgb;
03740 break;
03741
03742 case 4:
03743 _format = F_rgba;
03744 break;
03745
03746 default:
03747
03748 nassertr(false, false);
03749 _format = F_rgb;
03750 }
03751 }
03752
03753 if (!_loaded_from_image) {
03754 if ((options.get_texture_flags() & LoaderOptions::TF_allow_1d) &&
03755 _texture_type == TT_2d_texture && x_size != 1 && y_size == 1) {
03756
03757 _texture_type = TT_1d_texture;
03758 }
03759
03760 #ifndef NDEBUG
03761 if (_texture_type == TT_1d_texture) {
03762 nassertr(y_size == 1, false);
03763 } else if (_texture_type == TT_cube_map) {
03764 nassertr(x_size == y_size, false);
03765 }
03766 #endif
03767 if ((_x_size != x_size)||(_y_size != y_size)) {
03768 do_set_pad_size(0, 0, 0);
03769 }
03770 _x_size = x_size;
03771 _y_size = y_size;
03772 _num_components = num_components;
03773 do_set_component_type(component_type);
03774
03775 } else {
03776 if (_x_size != x_size ||
03777 _y_size != y_size ||
03778 _num_components != num_components ||
03779 _component_type != component_type) {
03780 gobj_cat.error()
03781 << "Texture properties have changed for texture " << get_name()
03782 << " page " << z << ".\n";
03783 return false;
03784 }
03785 }
03786
03787 return true;
03788 }
03789
03790
03791
03792
03793
03794
03795 PT(Texture) Texture::
03796 do_make_copy() {
03797 PT(Texture) tex = new Texture(get_name());
03798 tex->do_assign(*this);
03799 return tex;
03800 }
03801
03802
03803
03804
03805
03806
03807
03808 void Texture::
03809 do_assign(const Texture ©) {
03810 _filename = copy._filename;
03811 _alpha_filename = copy._alpha_filename;
03812 if (!copy._fullpath.empty()) {
03813
03814
03815 _fullpath = copy._fullpath;
03816 _alpha_fullpath = copy._alpha_fullpath;
03817 }
03818 _primary_file_num_channels = copy._primary_file_num_channels;
03819 _alpha_file_channel = copy._alpha_file_channel;
03820 _x_size = copy._x_size;
03821 _y_size = copy._y_size;
03822 _z_size = copy._z_size;
03823 _pad_x_size = copy._pad_x_size;
03824 _pad_y_size = copy._pad_y_size;
03825 _pad_z_size = copy._pad_z_size;
03826 _orig_file_x_size = copy._orig_file_x_size;
03827 _orig_file_y_size = copy._orig_file_y_size;
03828 _num_components = copy._num_components;
03829 _component_width = copy._component_width;
03830 _texture_type = copy._texture_type;
03831 _format = copy._format;
03832 _component_type = copy._component_type;
03833 _loaded_from_image = copy._loaded_from_image;
03834 _loaded_from_txo = copy._loaded_from_txo;
03835 _wrap_u = copy._wrap_u;
03836 _wrap_v = copy._wrap_v;
03837 _wrap_w = copy._wrap_w;
03838 _minfilter = copy._minfilter;
03839 _magfilter = copy._magfilter;
03840 _anisotropic_degree = copy._anisotropic_degree;
03841 _keep_ram_image = copy._keep_ram_image;
03842 _border_color = copy._border_color;
03843 _compression = copy._compression;
03844 _match_framebuffer_format = copy._match_framebuffer_format;
03845 _quality_level = copy._quality_level;
03846 _ram_image_compression = copy._ram_image_compression;
03847 _ram_images = copy._ram_images;
03848 _simple_x_size = copy._simple_x_size;
03849 _simple_y_size = copy._simple_y_size;
03850 _simple_ram_image = copy._simple_ram_image;
03851 }
03852
03853
03854
03855
03856
03857
03858
03859 void Texture::
03860 do_clear() {
03861 do_assign(Texture());
03862 }
03863
03864
03865
03866
03867
03868
03869 void Texture::
03870 do_setup_texture(Texture::TextureType texture_type, int x_size, int y_size,
03871 int z_size, Texture::ComponentType component_type,
03872 Texture::Format format) {
03873 switch (texture_type) {
03874 case TT_1d_texture:
03875 nassertv(y_size == 1 && z_size == 1);
03876 break;
03877
03878 case TT_2d_texture:
03879 nassertv(z_size == 1);
03880 break;
03881
03882 case TT_3d_texture:
03883 break;
03884
03885 case TT_cube_map:
03886
03887 nassertv(x_size == y_size && z_size == 6);
03888
03889
03890
03891
03892 _wrap_u = WM_clamp;
03893 _wrap_v = WM_clamp;
03894 _wrap_w = WM_clamp;
03895 break;
03896 }
03897
03898 if (texture_type != TT_2d_texture) {
03899 do_clear_simple_ram_image();
03900 }
03901
03902 _texture_type = texture_type;
03903 _x_size = x_size;
03904 _y_size = y_size;
03905 _z_size = z_size;
03906 do_set_component_type(component_type);
03907 do_set_format(format);
03908
03909 do_clear_ram_image();
03910 do_set_pad_size(0, 0, 0);
03911 _orig_file_x_size = 0;
03912 _orig_file_y_size = 0;
03913 _loaded_from_image = false;
03914 _loaded_from_txo = false;
03915 _has_read_pages = false;
03916 _has_read_mipmaps = false;
03917 }
03918
03919
03920
03921
03922
03923
03924 void Texture::
03925 do_set_format(Texture::Format format) {
03926 if (format == _format) {
03927 return;
03928 }
03929 _format = format;
03930 ++_properties_modified;
03931
03932 switch (_format) {
03933 case F_color_index:
03934 case F_depth_stencil:
03935 case F_depth_component:
03936 case F_depth_component16:
03937 case F_depth_component24:
03938 case F_depth_component32:
03939 case F_red:
03940 case F_green:
03941 case F_blue:
03942 case F_alpha:
03943 case F_luminance:
03944 _num_components = 1;
03945 break;
03946
03947 case F_luminance_alpha:
03948 case F_luminance_alphamask:
03949 _num_components = 2;
03950 break;
03951
03952 case F_rgb:
03953 case F_rgb5:
03954 case F_rgb8:
03955 case F_rgb12:
03956 case F_rgb332:
03957 _num_components = 3;
03958 break;
03959
03960 case F_rgba:
03961 case F_rgbm:
03962 case F_rgba4:
03963 case F_rgba5:
03964 case F_rgba8:
03965 case F_rgba12:
03966 case F_rgba16:
03967 case F_rgba32:
03968 _num_components = 4;
03969 break;
03970 }
03971 }
03972
03973
03974
03975
03976
03977
03978 void Texture::
03979 do_set_component_type(Texture::ComponentType component_type) {
03980 _component_type = component_type;
03981
03982 switch (component_type) {
03983 case T_unsigned_byte:
03984 _component_width = 1;
03985 break;
03986
03987 case T_unsigned_short:
03988 _component_width = 2;
03989 break;
03990
03991 case T_float:
03992 _component_width = 4;
03993 break;
03994
03995 case T_unsigned_int_24.:
03996
03997 break;
03998 }
03999 }
04000
04001
04002
04003
04004
04005
04006 void Texture::
04007 do_set_x_size(int x_size) {
04008 if (_x_size != x_size) {
04009 _x_size = x_size;
04010 ++_image_modified;
04011 do_clear_ram_image();
04012 do_set_pad_size(0, 0, 0);
04013 }
04014 }
04015
04016
04017
04018
04019
04020
04021 void Texture::
04022 do_set_y_size(int y_size) {
04023 if (_y_size != y_size) {
04024 nassertv(_texture_type != Texture::TT_1d_texture || y_size == 1);
04025 _y_size = y_size;
04026 ++_image_modified;
04027 do_clear_ram_image();
04028 do_set_pad_size(0, 0, 0);
04029 }
04030 }
04031
04032
04033
04034
04035
04036
04037
04038
04039 void Texture::
04040 do_set_z_size(int z_size) {
04041 if (_z_size != z_size) {
04042 nassertv(_texture_type == Texture::TT_3d_texture ||
04043 (_texture_type == Texture::TT_cube_map && z_size == 6) ||
04044 (z_size == 1));
04045 _z_size = z_size;
04046 ++_image_modified;
04047 do_clear_ram_image();
04048 do_set_pad_size(0, 0, 0);
04049 }
04050 }
04051
04052
04053
04054
04055
04056
04057 void Texture::
04058 do_set_wrap_u(Texture::WrapMode wrap) {
04059 if (_wrap_u != wrap) {
04060 ++_properties_modified;
04061 _wrap_u = wrap;
04062 }
04063 }
04064
04065
04066
04067
04068
04069
04070 void Texture::
04071 do_set_wrap_v(Texture::WrapMode wrap) {
04072 if (_wrap_v != wrap) {
04073 ++_properties_modified;
04074 _wrap_v = wrap;
04075 }
04076 }
04077
04078
04079
04080
04081
04082
04083 void Texture::
04084 do_set_wrap_w(Texture::WrapMode wrap) {
04085 if (_wrap_w != wrap) {
04086 ++_properties_modified;
04087 _wrap_w = wrap;
04088 }
04089 }
04090
04091
04092
04093
04094
04095
04096 void Texture::
04097 do_set_minfilter(Texture::FilterType filter) {
04098 if (_minfilter != filter) {
04099 ++_properties_modified;
04100 _minfilter = filter;
04101 }
04102 }
04103
04104
04105
04106
04107
04108
04109 void Texture::
04110 do_set_magfilter(Texture::FilterType filter) {
04111 if (_magfilter != filter) {
04112 ++_properties_modified;
04113 _magfilter = filter;
04114 }
04115 }
04116
04117
04118
04119
04120
04121
04122 void Texture::
04123 do_set_anisotropic_degree(int anisotropic_degree) {
04124 if (_anisotropic_degree != anisotropic_degree) {
04125 ++_properties_modified;
04126 _anisotropic_degree = anisotropic_degree;
04127 }
04128 }
04129
04130
04131
04132
04133
04134
04135 void Texture::
04136 do_set_border_color(const Colorf &color) {
04137 if (_border_color != color) {
04138 ++_properties_modified;
04139 _border_color = color;
04140 }
04141 }
04142
04143
04144
04145
04146
04147
04148 void Texture::
04149 do_set_compression(Texture::CompressionMode compression) {
04150 if (_compression != compression) {
04151 ++_properties_modified;
04152 _compression = compression;
04153 if (do_has_ram_image()) {
04154 do_reload();
04155 }
04156 }
04157 }
04158
04159
04160
04161
04162
04163
04164 void Texture::
04165 do_set_quality_level(Texture::QualityLevel quality_level) {
04166 if (_quality_level != quality_level) {
04167 ++_properties_modified;
04168 _quality_level = quality_level;
04169 }
04170 }
04171
04172
04173
04174
04175
04176
04177 bool Texture::
04178 do_has_compression() const {
04179 if (_compression == CM_default) {
04180 return compressed_textures;
04181 } else {
04182 return (_compression != CM_off);
04183 }
04184 }
04185
04186
04187
04188
04189
04190
04191
04192 bool Texture::
04193 do_has_ram_image() const {
04194 return !_ram_images.empty() && !_ram_images[0]._image.empty();
04195 }
04196
04197
04198
04199
04200
04201
04202
04203
04204 bool Texture::
04205 do_has_uncompressed_ram_image() const {
04206 return !_ram_images.empty() && !_ram_images[0]._image.empty() && _ram_image_compression == CM_off;
04207 }
04208
04209
04210
04211
04212
04213
04214 CPTA_uchar Texture::
04215 do_get_ram_image() {
04216 if (_loaded_from_image && !do_has_ram_image() && !_fullpath.empty()) {
04217 do_unlock_and_reload_ram_image(true);
04218
04219
04220
04221
04222
04223 ++_image_modified;
04224 ++_properties_modified;
04225 }
04226
04227 if (_ram_images.empty()) {
04228 return CPTA_uchar(get_class_type());
04229 }
04230
04231 return _ram_images[0]._image;
04232 }
04233
04234
04235
04236
04237
04238
04239 CPTA_uchar Texture::
04240 do_get_uncompressed_ram_image() {
04241 if (!_ram_images.empty() && _ram_image_compression != CM_off) {
04242
04243
04244 if (do_uncompress_ram_image()) {
04245 if (gobj_cat.is_debug()) {
04246 gobj_cat.debug()
04247 << "Uncompressed " << get_name() << "\n";
04248 }
04249 return _ram_images[0]._image;
04250 }
04251 }
04252
04253
04254 if (_loaded_from_image && (!do_has_ram_image() || _ram_image_compression != CM_off) && !_fullpath.empty()) {
04255 do_unlock_and_reload_ram_image(false);
04256 }
04257
04258 if (!_ram_images.empty() && _ram_image_compression != CM_off) {
04259
04260 if (do_uncompress_ram_image()) {
04261 gobj_cat.info()
04262 << "Uncompressed " << get_name() << "\n";
04263 return _ram_images[0]._image;
04264 }
04265 }
04266
04267 if (_ram_images.empty() || _ram_image_compression != CM_off) {
04268 return CPTA_uchar(get_class_type());
04269 }
04270
04271 return _ram_images[0]._image;
04272 }
04273
04274
04275
04276
04277
04278
04279
04280
04281
04282
04283
04284
04285
04286
04287
04288
04289
04290
04291
04292
04293
04294
04295
04296
04297
04298
04299
04300
04301
04302 CPTA_uchar Texture::
04303 get_ram_image_as(const string &requested_format) {
04304 MutexHolder holder(_lock);
04305 string format = upcase(requested_format);
04306
04307
04308 CPTA_uchar data = do_get_uncompressed_ram_image();
04309 if (data == NULL) {
04310 gobj_cat.error() << "Couldn't find an uncompressed RAM image!\n";
04311 return CPTA_uchar(get_class_type());
04312 }
04313 int imgsize = _x_size * _y_size;
04314 nassertr(_num_components > 0 && _num_components <= 4, CPTA_uchar(get_class_type()));
04315 nassertr(data.size() == (size_t)(_component_width * _num_components * imgsize), CPTA_uchar(get_class_type()));
04316
04317
04318 if ((_num_components == 1 && format.size() == 1) ||
04319 (_num_components == 2 && format.size() == 2 && format.at(1) == 'A' && format.at(0) != 'A') ||
04320 (_num_components == 3 && format == "BGR") ||
04321 (_num_components == 4 && format == "BGRA")) {
04322
04323 return CPTA_uchar(data);
04324 }
04325
04326
04327 PTA_uchar newdata = PTA_uchar::empty_array(imgsize * format.size() * _component_width, get_class_type());
04328
04329
04330 if (format == "RGBA" && _num_components == 4 && _component_width == 1) {
04331 imgsize *= 4;
04332 for (int p = 0; p < imgsize; p += 4) {
04333 newdata[p ] = data[p + 2];
04334 newdata[p + 1] = data[p + 1];
04335 newdata[p + 2] = data[p ];
04336 newdata[p + 3] = data[p + 3];
04337 }
04338 return newdata;
04339 }
04340 if (format == "RGB" && _num_components == 3 && _component_width == 1) {
04341 imgsize *= 3;
04342 for (int p = 0; p < imgsize; p += 3) {
04343 newdata[p ] = data[p + 2];
04344 newdata[p + 1] = data[p + 1];
04345 newdata[p + 2] = data[p ];
04346 }
04347 return newdata;
04348 }
04349 if (format == "A" && _component_width == 1 && _num_components != 3) {
04350
04351 int component = _num_components - 1;
04352 for (int p = 0; p < imgsize; ++p) {
04353 newdata[p] = data[component];
04354 }
04355 return newdata;
04356 }
04357 if (_component_width == 1) {
04358 for (int p = 0; p < imgsize; ++p) {
04359 for (uchar s = 0; s < format.size(); ++s) {
04360 signed char component = -1;
04361 if (format.at(s) == 'B' || (_num_components <= 2 && format.at(s) != 'A')) {
04362 component = 0;
04363 } else if (format.at(s) == 'G') {
04364 component = 1;
04365 } else if (format.at(s) == 'R') {
04366 component = 2;
04367 } else if (format.at(s) == 'A') {
04368 nassertr(_num_components != 3, CPTA_uchar(get_class_type()));
04369 component = _num_components - 1;
04370 } else if (format.at(s) == '0') {
04371 newdata[p * format.size() + s] = 0x00;
04372 } else if (format.at(s) == '1') {
04373 newdata[p * format.size() + s] = 0xff;
04374 } else {
04375 gobj_cat.error() << "Unexpected component character '"
04376 << format.at(s) << "', expected one of RGBA!\n";
04377 return CPTA_uchar(get_class_type());
04378 }
04379 if (component >= 0) {
04380 newdata[p * format.size() + s] = data[p * _num_components + component];
04381 }
04382 }
04383 }
04384 return newdata;
04385 }
04386 for (int p = 0; p < imgsize; ++p) {
04387 for (uchar s = 0; s < format.size(); ++s) {
04388 signed char component = -1;
04389 if (format.at(s) == 'B' || (_num_components <= 2 && format.at(s) != 'A')) {
04390 component = 0;
04391 } else if (format.at(s) == 'G') {
04392 component = 1;
04393 } else if (format.at(s) == 'R') {
04394 component = 2;
04395 } else if (format.at(s) == 'A') {
04396 nassertr(_num_components != 3, CPTA_uchar(get_class_type()));
04397 component = _num_components - 1;
04398 } else if (format.at(s) == '0') {
04399 memset((void*)(newdata + (p * format.size() + s) * _component_width), 0, _component_width);
04400 } else if (format.at(s) == '1') {
04401 memset((void*)(newdata + (p * format.size() + s) * _component_width), -1, _component_width);
04402 } else {
04403 gobj_cat.error() << "Unexpected component character '"
04404 << format.at(s) << "', expected one of RGBA!\n";
04405 return CPTA_uchar(get_class_type());
04406 }
04407 if (component >= 0) {
04408 memcpy((void*)(newdata + (p * format.size() + s) * _component_width),
04409 (void*)(data + (p * _num_components + component) * _component_width),
04410 _component_width);
04411 }
04412 }
04413 }
04414 return newdata;
04415 }
04416
04417
04418
04419
04420
04421
04422 void Texture::
04423 do_set_simple_ram_image(CPTA_uchar image, int x_size, int y_size) {
04424 nassertv(_texture_type == TT_2d_texture);
04425 size_t expected_page_size = (size_t)(x_size * y_size * 4);
04426 nassertv(image.size() == expected_page_size);
04427
04428 _simple_x_size = x_size;
04429 _simple_y_size = y_size;
04430 _simple_ram_image._image = image.cast_non_const();
04431 _simple_ram_image._page_size = image.size();
04432 _simple_image_date_generated = (PN_int32)time(NULL);
04433 ++_simple_image_modified;
04434 }
04435
04436
04437
04438
04439
04440
04441 int Texture::
04442 do_get_expected_num_mipmap_levels() const {
04443 int size = max(_x_size, max(_y_size, _z_size));
04444 int count = 1;
04445 while (size > 1) {
04446 size >>= 1;
04447 ++count;
04448 }
04449 return count;
04450 }
04451
04452
04453
04454
04455
04456
04457 size_t Texture::
04458 do_get_ram_mipmap_page_size(int n) const {
04459 if (_ram_image_compression != CM_off) {
04460 if (n >= 0 && n < (int)_ram_images.size()) {
04461 return _ram_images[n]._page_size;
04462 }
04463 return 0;
04464 } else {
04465 return do_get_expected_ram_mipmap_page_size(n);
04466 }
04467 }
04468
04469
04470
04471
04472
04473
04474 int Texture::
04475 do_get_expected_mipmap_x_size(int n) const {
04476 int size = max(_x_size, 1);
04477 while (n > 0 && size > 1) {
04478 size >>= 1;
04479 --n;
04480 }
04481 return size;
04482 }
04483
04484
04485
04486
04487
04488
04489 int Texture::
04490 do_get_expected_mipmap_y_size(int n) const {
04491 int size = max(_y_size, 1);
04492 while (n > 0 && size > 1) {
04493 size >>= 1;
04494 --n;
04495 }
04496 return size;
04497 }
04498
04499
04500
04501
04502
04503
04504 int Texture::
04505 do_get_expected_mipmap_z_size(int n) const {
04506
04507
04508
04509 if (_texture_type == Texture::TT_3d_texture) {
04510 int size = max(_z_size, 1);
04511 while (n > 0 && size > 1) {
04512 size >>= 1;
04513 --n;
04514 }
04515 return size;
04516
04517 } else {
04518 return _z_size;
04519 }
04520 }
04521
04522
04523
04524
04525
04526
04527 void Texture::
04528 do_clear_simple_ram_image() {
04529 _simple_x_size = 0;
04530 _simple_y_size = 0;
04531 _simple_ram_image._image.clear();
04532 _simple_ram_image._page_size = 0;
04533 _simple_image_date_generated = 0;
04534
04535
04536
04537
04538 ++_simple_image_modified;
04539 }
04540
04541
04542
04543
04544
04545
04546 void Texture::
04547 do_clear_ram_mipmap_images() {
04548 if (!_ram_images.empty()) {
04549 _ram_images.erase(_ram_images.begin() + 1, _ram_images.end());
04550 }
04551 }
04552
04553
04554
04555
04556
04557
04558 void Texture::
04559 do_generate_ram_mipmap_images() {
04560 nassertv(do_has_ram_image());
04561 nassertv(_component_type != T_float);
04562 if (do_get_expected_num_mipmap_levels() == 1) {
04563
04564 return;
04565 }
04566
04567 RamImage orig_compressed_image;
04568 CompressionMode orig_compression_mode = CM_off;
04569
04570 if (_ram_image_compression != CM_off) {
04571
04572
04573
04574 orig_compressed_image = _ram_images[0];
04575 orig_compression_mode = _ram_image_compression;
04576
04577
04578 do_get_uncompressed_ram_image();
04579
04580 nassertv(_ram_image_compression == CM_off);
04581 }
04582
04583 do_clear_ram_mipmap_images();
04584
04585 if (gobj_cat.is_debug()) {
04586 gobj_cat.debug()
04587 << "Generating mipmap levels for " << *this << "\n";
04588 }
04589
04590 if (_texture_type == Texture::TT_3d_texture && _z_size != 1) {
04591
04592 int x_size = _x_size;
04593 int y_size = _y_size;
04594 int z_size = _z_size;
04595 int n = 0;
04596 while (x_size > 1 || y_size > 1 || z_size > 1) {
04597 _ram_images.push_back(RamImage());
04598 filter_3d_mipmap_level(_ram_images[n + 1], _ram_images[n],
04599 x_size, y_size, z_size);
04600 x_size = max(x_size >> 1, 1);
04601 y_size = max(y_size >> 1, 1);
04602 z_size = max(z_size >> 1, 1);
04603 ++n;
04604 }
04605
04606 } else {
04607
04608 int x_size = _x_size;
04609 int y_size = _y_size;
04610 int n = 0;
04611 while (x_size > 1 || y_size > 1) {
04612 _ram_images.push_back(RamImage());
04613 filter_2d_mipmap_pages(_ram_images[n + 1], _ram_images[n],
04614 x_size, y_size);
04615 x_size = max(x_size >> 1, 1);
04616 y_size = max(y_size >> 1, 1);
04617 ++n;
04618 }
04619 }
04620
04621 if (orig_compression_mode != CM_off) {
04622
04623
04624
04625
04626
04627 nassertv(_ram_images.size() > 1);
04628 int l0_x_size = _x_size;
04629 int l0_y_size = _y_size;
04630 int l0_z_size = _z_size;
04631 _x_size = do_get_expected_mipmap_x_size(1);
04632 _y_size = do_get_expected_mipmap_y_size(1);
04633 _z_size = do_get_expected_mipmap_z_size(1);
04634 RamImage uncompressed_image = _ram_images[0];
04635 _ram_images.erase(_ram_images.begin());
04636
04637 bool success = do_compress_ram_image(orig_compression_mode, QL_default, NULL);
04638
04639 if (success) {
04640 _ram_images.insert(_ram_images.begin(), orig_compressed_image);
04641 } else {
04642 _ram_images.insert(_ram_images.begin(), uncompressed_image);
04643 }
04644 _x_size = l0_x_size;
04645 _y_size = l0_y_size;
04646 _z_size = l0_z_size;
04647 }
04648 }
04649
04650
04651
04652
04653
04654
04655 void Texture::
04656 do_set_pad_size(int x, int y, int z) {
04657 if (x > _x_size) {
04658 x = _x_size;
04659 }
04660 if (y > _y_size) {
04661 y = _y_size;
04662 }
04663 if (z > _z_size) {
04664 z = _z_size;
04665 }
04666
04667 _pad_x_size = x;
04668 _pad_y_size = y;
04669 _pad_z_size = z;
04670 }
04671
04672
04673
04674
04675
04676
04677 bool Texture::
04678 do_reload() {
04679 if (_loaded_from_image && !_fullpath.empty()) {
04680 do_clear_ram_image();
04681 do_unlock_and_reload_ram_image(true);
04682 if (do_has_ram_image()) {
04683
04684 ++_image_modified;
04685 return true;
04686 }
04687 return false;
04688 }
04689
04690
04691 return false;
04692 }
04693
04694
04695
04696
04697
04698
04699
04700 void Texture::
04701 convert_from_pnmimage(PTA_uchar &image, size_t page_size, int z,
04702 const PNMImage &pnmimage,
04703 int num_components, int component_width) {
04704 int x_size = pnmimage.get_x_size();
04705 int y_size = pnmimage.get_y_size();
04706 xelval maxval = pnmimage.get_maxval();
04707
04708 bool is_grayscale = (num_components == 1 || num_components == 2);
04709 bool has_alpha = (num_components == 2 || num_components == 4);
04710 bool img_has_alpha = pnmimage.has_alpha();
04711
04712 int idx = page_size * z;
04713 nassertv(idx + page_size <= image.size());
04714 unsigned char *p = &image[idx];
04715
04716 if (maxval == 255 && component_width == 1) {
04717
04718
04719 for (int j = y_size-1; j >= 0; j--) {
04720 for (int i = 0; i < x_size; i++) {
04721 if (is_grayscale) {
04722 store_unscaled_byte(p, pnmimage.get_gray_val(i, j));
04723 } else {
04724 store_unscaled_byte(p, pnmimage.get_blue_val(i, j));
04725 store_unscaled_byte(p, pnmimage.get_green_val(i, j));
04726 store_unscaled_byte(p, pnmimage.get_red_val(i, j));
04727 }
04728 if (has_alpha) {
04729 if (img_has_alpha) {
04730 store_unscaled_byte(p, pnmimage.get_alpha_val(i, j));
04731 } else {
04732 store_unscaled_byte(p, 255);
04733 }
04734 }
04735 }
04736 }
04737
04738 } else if (maxval == 65535 && component_width == 2) {
04739
04740
04741 for (int j = y_size-1; j >= 0; j--) {
04742 for (int i = 0; i < x_size; i++) {
04743 if (is_grayscale) {
04744 store_unscaled_short(p, pnmimage.get_gray_val(i, j));
04745 } else {
04746 store_unscaled_short(p, pnmimage.get_blue_val(i, j));
04747 store_unscaled_short(p, pnmimage.get_green_val(i, j));
04748 store_unscaled_short(p, pnmimage.get_red_val(i, j));
04749 }
04750 if (has_alpha) {
04751 if (img_has_alpha) {
04752 store_unscaled_short(p, pnmimage.get_alpha_val(i, j));
04753 } else {
04754 store_unscaled_short(p, 65535);
04755 }
04756 }
04757 }
04758 }
04759
04760 } else if (component_width == 1) {
04761
04762
04763
04764 double scale = 255.0 / (double)maxval;
04765
04766 for (int j = y_size-1; j >= 0; j--) {
04767 for (int i = 0; i < x_size; i++) {
04768 if (is_grayscale) {
04769 store_scaled_byte(p, pnmimage.get_gray_val(i, j), scale);
04770 } else {
04771 store_scaled_byte(p, pnmimage.get_blue_val(i, j), scale);
04772 store_scaled_byte(p, pnmimage.get_green_val(i, j), scale);
04773 store_scaled_byte(p, pnmimage.get_red_val(i, j), scale);
04774 }
04775 if (has_alpha) {
04776 if (img_has_alpha) {
04777 store_scaled_byte(p, pnmimage.get_alpha_val(i, j), scale);
04778 } else {
04779 store_unscaled_byte(p, 255);
04780 }
04781 }
04782 }
04783 }
04784
04785 } else {
04786
04787
04788
04789 double scale = 65535.0 / (double)maxval;
04790
04791 for (int j = y_size-1; j >= 0; j--) {
04792 for (int i = 0; i < x_size; i++) {
04793 if (is_grayscale) {
04794 store_scaled_short(p, pnmimage.get_gray_val(i, j), scale);
04795 } else {
04796 store_scaled_short(p, pnmimage.get_blue_val(i, j), scale);
04797 store_scaled_short(p, pnmimage.get_green_val(i, j), scale);
04798 store_scaled_short(p, pnmimage.get_red_val(i, j), scale);
04799 }
04800 if (has_alpha) {
04801 if (img_has_alpha) {
04802 store_scaled_short(p, pnmimage.get_alpha_val(i, j), 1.0);
04803 } else {
04804 store_unscaled_short(p, 65535);
04805 }
04806 }
04807 }
04808 }
04809 }
04810
04811 nassertv(p == &image[idx] + page_size);
04812 }
04813
04814
04815
04816
04817
04818
04819
04820 bool Texture::
04821 convert_to_pnmimage(PNMImage &pnmimage, int x_size, int y_size,
04822 int num_components, int component_width,
04823 CPTA_uchar image, size_t page_size, int z) {
04824 pnmimage.clear(x_size, y_size, num_components);
04825 bool has_alpha = pnmimage.has_alpha();
04826 bool is_grayscale = pnmimage.is_grayscale();
04827
04828 int idx = page_size * z;
04829 nassertr(idx + page_size <= image.size(), false);
04830 const unsigned char *p = &image[idx];
04831
04832 if (component_width == 1) {
04833 for (int j = y_size-1; j >= 0; j--) {
04834 for (int i = 0; i < x_size; i++) {
04835 if (is_grayscale) {
04836 pnmimage.set_gray(i, j, get_unsigned_byte(p));
04837 } else {
04838 pnmimage.set_blue(i, j, get_unsigned_byte(p));
04839 pnmimage.set_green(i, j, get_unsigned_byte(p));
04840 pnmimage.set_red(i, j, get_unsigned_byte(p));
04841 }
04842 if (has_alpha) {
04843 pnmimage.set_alpha(i, j, get_unsigned_byte(p));
04844 }
04845 }
04846 }
04847
04848 } else if (component_width == 2) {
04849 for (int j = y_size-1; j >= 0; j--) {
04850 for (int i = 0; i < x_size; i++) {
04851 if (is_grayscale) {
04852 pnmimage.set_gray(i, j, get_unsigned_short(p));
04853 } else {
04854 pnmimage.set_blue(i, j, get_unsigned_short(p));
04855 pnmimage.set_green(i, j, get_unsigned_short(p));
04856 pnmimage.set_red(i, j, get_unsigned_short(p));
04857 }
04858 if (has_alpha) {
04859 pnmimage.set_alpha(i, j, get_unsigned_short(p));
04860 }
04861 }
04862 }
04863
04864 } else {
04865 return false;
04866 }
04867
04868 nassertr(p == &image[idx] + page_size, false);
04869 return true;
04870 }
04871
04872
04873
04874
04875
04876
04877 PTA_uchar Texture::
04878 read_dds_level_bgr8(Texture *tex, const DDSHeader &header, int n, istream &in) {
04879
04880 int x_size = tex->do_get_expected_mipmap_x_size(n);
04881 int y_size = tex->do_get_expected_mipmap_y_size(n);
04882
04883 size_t size = tex->do_get_expected_ram_mipmap_page_size(n);
04884 size_t row_bytes = x_size * 3;
04885 PTA_uchar image = PTA_uchar::empty_array(size);
04886 for (int y = y_size - 1; y >= 0; --y) {
04887 unsigned char *p = image.p() + y * row_bytes;
04888 nassertr(p + row_bytes <= image.p() + size, PTA_uchar());
04889 in.read((char *)p, row_bytes);
04890 }
04891
04892 return image;
04893 }
04894
04895
04896
04897
04898
04899
04900 PTA_uchar Texture::
04901 read_dds_level_rgb8(Texture *tex, const DDSHeader &header, int n, istream &in) {
04902
04903 int x_size = tex->do_get_expected_mipmap_x_size(n);
04904 int y_size = tex->do_get_expected_mipmap_y_size(n);
04905
04906 size_t size = tex->do_get_expected_ram_mipmap_page_size(n);
04907 size_t row_bytes = x_size * 3;
04908 PTA_uchar image = PTA_uchar::empty_array(size);
04909 for (int y = y_size - 1; y >= 0; --y) {
04910 unsigned char *p = image.p() + y * row_bytes;
04911 nassertr(p + row_bytes <= image.p() + size, PTA_uchar());
04912 in.read((char *)p, row_bytes);
04913
04914
04915 for (int x = 0; x < x_size; ++x) {
04916 unsigned char r = p[0];
04917 p[0] = p[2];
04918 p[2] = r;
04919 p += 3;
04920 }
04921 nassertr(p <= image.p() + size, PTA_uchar());
04922 }
04923
04924 return image;
04925 }
04926
04927
04928
04929
04930
04931
04932 PTA_uchar Texture::
04933 read_dds_level_abgr8(Texture *tex, const DDSHeader &header, int n, istream &in) {
04934
04935 int x_size = tex->do_get_expected_mipmap_x_size(n);
04936 int y_size = tex->do_get_expected_mipmap_y_size(n);
04937
04938 size_t size = tex->do_get_expected_ram_mipmap_page_size(n);
04939 size_t row_bytes = x_size * 4;
04940 PTA_uchar image = PTA_uchar::empty_array(size);
04941 for (int y = y_size - 1; y >= 0; --y) {
04942 unsigned char *p = image.p() + y * row_bytes;
04943 in.read((char *)p, row_bytes);
04944
04945 PN_uint32 *pw = (PN_uint32 *)p;
04946 for (int x = 0; x < x_size; ++x) {
04947 PN_uint32 w = *pw;
04948 #ifdef WORDS_BIGENDIAN
04949
04950 w = ((w & 0xff00) << 16) | ((w & 0xff000000U) >> 16) | (w & 0xff00ff);
04951 #else
04952
04953 w = ((w & 0xff) << 16) | ((w & 0xff0000) >> 16) | (w & 0xff00ff00U);
04954 #endif
04955 *pw = w;
04956 ++pw;
04957 }
04958 nassertr((unsigned char *)pw <= image.p() + size, PTA_uchar());
04959 }
04960
04961 return image;
04962 }
04963
04964
04965
04966
04967
04968
04969 PTA_uchar Texture::
04970 read_dds_level_rgba8(Texture *tex, const DDSHeader &header, int n, istream &in) {
04971
04972 int x_size = tex->do_get_expected_mipmap_x_size(n);
04973 int y_size = tex->do_get_expected_mipmap_y_size(n);
04974
04975 size_t size = tex->do_get_expected_ram_mipmap_page_size(n);
04976 size_t row_bytes = x_size * 4;
04977 PTA_uchar image = PTA_uchar::empty_array(size);
04978 for (int y = y_size - 1; y >= 0; --y) {
04979 unsigned char *p = image.p() + y * row_bytes;
04980 nassertr(p + row_bytes <= image.p() + size, PTA_uchar());
04981 in.read((char *)p, row_bytes);
04982 }
04983
04984 return image;
04985 }
04986
04987
04988
04989
04990
04991
04992
04993 PTA_uchar Texture::
04994 read_dds_level_generic_uncompressed(Texture *tex, const DDSHeader &header,
04995 int n, istream &in) {
04996 int x_size = tex->do_get_expected_mipmap_x_size(n);
04997 int y_size = tex->do_get_expected_mipmap_y_size(n);
04998
04999 int pitch = (x_size * header.pf.rgb_bitcount) / 8;
05000
05001
05002
05003
05004
05005
05006 if (n == 0) {
05007 pitch = ((pitch + 3) / 4) * 4;
05008 if (header.dds_flags & DDSD_PITCH) {
05009 pitch = header.pitch;
05010 }
05011 }
05012
05013 int bpp = header.pf.rgb_bitcount / 8;
05014 int skip_bytes = pitch - (bpp * x_size);
05015 nassertr(skip_bytes >= 0, PTA_uchar());
05016
05017 unsigned int r_mask = header.pf.r_mask;
05018 unsigned int g_mask = header.pf.g_mask;
05019 unsigned int b_mask = header.pf.b_mask;
05020 unsigned int a_mask = header.pf.a_mask;
05021
05022
05023
05024 int r_shift = get_lowest_on_bit(r_mask);
05025 int g_shift = get_lowest_on_bit(g_mask);
05026 int b_shift = get_lowest_on_bit(b_mask);
05027 int a_shift = get_lowest_on_bit(a_mask);
05028
05029
05030
05031 unsigned int r_scale = 0;
05032 if (r_mask != 0) {
05033 r_scale = 0xff000000 / (r_mask >> r_shift);
05034 }
05035 unsigned int g_scale = 0;
05036 if (g_mask != 0) {
05037 g_scale = 0xff000000 / (g_mask >> g_shift);
05038 }
05039 unsigned int b_scale = 0;
05040 if (b_mask != 0) {
05041 b_scale = 0xff000000 / (b_mask >> b_shift);
05042 }
05043 unsigned int a_scale = 0;
05044 if (a_mask != 0) {
05045 a_scale = 0xff000000 / (a_mask >> a_shift);
05046 }
05047
05048 bool add_alpha = has_alpha(tex->_format);
05049
05050 size_t size = tex->do_get_expected_ram_mipmap_page_size(n);
05051 size_t row_bytes = x_size * tex->_num_components;
05052 PTA_uchar image = PTA_uchar::empty_array(size);
05053 for (int y = y_size - 1; y >= 0; --y) {
05054 unsigned char *p = image.p() + y * row_bytes;
05055 for (int x = 0; x < x_size; ++x) {
05056
05057
05058 unsigned int pixel = 0;
05059 int shift = 0;
05060 for (int bi = 0; bi < bpp; ++bi) {
05061 unsigned int ch = (unsigned char)in.get();
05062 pixel |= (ch << shift);
05063 shift += 8;
05064 }
05065
05066
05067
05068 unsigned int r = (((pixel & r_mask) >> r_shift) * r_scale) >> 24;
05069 unsigned int g = (((pixel & g_mask) >> g_shift) * g_scale) >> 24;
05070 unsigned int b = (((pixel & b_mask) >> b_shift) * b_scale) >> 24;
05071
05072
05073 store_unscaled_byte(p, b);
05074 store_unscaled_byte(p, g);
05075 store_unscaled_byte(p, r);
05076 if (add_alpha) {
05077 unsigned int a = (((pixel & a_mask) >> a_shift) * a_scale) >> 24;
05078 store_unscaled_byte(p, a);
05079 }
05080 }
05081 nassertr(p <= image.p() + size, PTA_uchar());
05082 for (int bi = 0; bi < skip_bytes; ++bi) {
05083 in.get();
05084 }
05085 }
05086
05087 return image;
05088 }
05089
05090
05091
05092
05093
05094
05095
05096 PTA_uchar Texture::
05097 read_dds_level_luminance_uncompressed(Texture *tex, const DDSHeader &header,
05098 int n, istream &in) {
05099 int x_size = tex->do_get_expected_mipmap_x_size(n);
05100 int y_size = tex->do_get_expected_mipmap_y_size(n);
05101
05102 int pitch = (x_size * header.pf.rgb_bitcount) / 8;
05103
05104
05105
05106
05107
05108
05109 if (n == 0) {
05110 pitch = ((pitch + 3) / 4) * 4;
05111 if (header.dds_flags & DDSD_PITCH) {
05112 pitch = header.pitch;
05113 }
05114 }
05115
05116 int bpp = header.pf.rgb_bitcount / 8;
05117 int skip_bytes = pitch - (bpp * x_size);
05118 nassertr(skip_bytes >= 0, PTA_uchar());
05119
05120 unsigned int r_mask = header.pf.r_mask;
05121 unsigned int a_mask = header.pf.a_mask;
05122
05123
05124
05125 int r_shift = get_lowest_on_bit(r_mask);
05126 int a_shift = get_lowest_on_bit(a_mask);
05127
05128
05129
05130 unsigned int r_scale = 0;
05131 if (r_mask != 0) {
05132 r_scale = 0xff000000 / (r_mask >> r_shift);
05133 }
05134 unsigned int a_scale = 0;
05135 if (a_mask != 0) {
05136 a_scale = 0xff000000 / (a_mask >> a_shift);
05137 }
05138
05139 bool add_alpha = has_alpha(tex->_format);
05140
05141 size_t size = tex->do_get_expected_ram_mipmap_page_size(n);
05142 size_t row_bytes = x_size * tex->_num_components;
05143 PTA_uchar image = PTA_uchar::empty_array(size);
05144 for (int y = y_size - 1; y >= 0; --y) {
05145 unsigned char *p = image.p() + y * row_bytes;
05146 for (int x = 0; x < x_size; ++x) {
05147
05148
05149 unsigned int pixel = 0;
05150 int shift = 0;
05151 for (int bi = 0; bi < bpp; ++bi) {
05152 unsigned int ch = (unsigned char)in.get();
05153 pixel |= (ch << shift);
05154 shift += 8;
05155 }
05156
05157 unsigned int r = (((pixel & r_mask) >> r_shift) * r_scale) >> 24;
05158
05159
05160 store_unscaled_byte(p, r);
05161 if (add_alpha) {
05162 unsigned int a = (((pixel & a_mask) >> a_shift) * a_scale) >> 24;
05163 store_unscaled_byte(p, a);
05164 }
05165 }
05166 nassertr(p <= image.p() + size, PTA_uchar());
05167 for (int bi = 0; bi < skip_bytes; ++bi) {
05168 in.get();
05169 }
05170 }
05171
05172 return image;
05173 }
05174
05175
05176
05177
05178
05179
05180 PTA_uchar Texture::
05181 read_dds_level_dxt1(Texture *tex, const DDSHeader &header, int n, istream &in) {
05182 int x_size = tex->do_get_expected_mipmap_x_size(n);
05183 int y_size = tex->do_get_expected_mipmap_y_size(n);
05184
05185 static const int div = 4;
05186 static const int block_bytes = 8;
05187
05188
05189
05190 int num_cols = max(div, x_size) / div;
05191 int num_rows = max(div, y_size) / div;
05192 int row_length = num_cols * block_bytes;
05193 int linear_size = row_length * num_rows;
05194
05195 if (n == 0) {
05196 if (header.dds_flags & DDSD_LINEARSIZE) {
05197 nassertr(linear_size == (int)header.pitch, PTA_uchar());
05198 }
05199 }
05200
05201 PTA_uchar image = PTA_uchar::empty_array(linear_size);
05202
05203 if (y_size >= 4) {
05204
05205
05206
05207 for (int ri = num_rows - 1; ri >= 0; --ri) {
05208 unsigned char *p = image.p() + row_length * ri;
05209 in.read((char *)p, row_length);
05210
05211 for (int ci = 0; ci < num_cols; ++ci) {
05212
05213
05214 PN_uint32 *cells = (PN_uint32 *)p;
05215 PN_uint32 w = cells[1];
05216 w = ((w & 0xff) << 24) | ((w & 0xff00) << 8) | ((w & 0xff0000) >> 8) | ((w & 0xff000000U) >> 24);
05217 cells[1] = w;
05218
05219 p += block_bytes;
05220 }
05221 }
05222
05223 } else if (y_size >= 2) {
05224
05225 unsigned char *p = image.p();
05226 in.read((char *)p, row_length);
05227
05228 for (int ci = 0; ci < num_cols; ++ci) {
05229 PN_uint32 *cells = (PN_uint32 *)p;
05230 PN_uint32 w = cells[1];
05231 w = ((w & 0xff) << 8) | ((w & 0xff00) >> 8);
05232 cells[1] = w;
05233
05234 p += block_bytes;
05235 }
05236
05237 } else if (y_size >= 1) {
05238
05239 unsigned char *p = image.p();
05240 in.read((char *)p, row_length);
05241 }
05242
05243 return image;
05244 }
05245
05246
05247
05248
05249
05250
05251 PTA_uchar Texture::
05252 read_dds_level_dxt23(Texture *tex, const DDSHeader &header, int n, istream &in) {
05253 int x_size = tex->do_get_expected_mipmap_x_size(n);
05254 int y_size = tex->do_get_expected_mipmap_y_size(n);
05255
05256 static const int div = 4;
05257 static const int block_bytes = 16;
05258
05259
05260
05261
05262
05263 int num_cols = max(div, x_size) / div;
05264 int num_rows = max(div, y_size) / div;
05265 int row_length = num_cols * block_bytes;
05266 int linear_size = row_length * num_rows;
05267
05268 if (n == 0) {
05269 if (header.dds_flags & DDSD_LINEARSIZE) {
05270 nassertr(linear_size == (int)header.pitch, PTA_uchar());
05271 }
05272 }
05273
05274 PTA_uchar image = PTA_uchar::empty_array(linear_size);
05275
05276 if (y_size >= 4) {
05277
05278
05279
05280 for (int ri = num_rows - 1; ri >= 0; --ri) {
05281 unsigned char *p = image.p() + row_length * ri;
05282 in.read((char *)p, row_length);
05283
05284 for (int ci = 0; ci < num_cols; ++ci) {
05285
05286
05287 PN_uint32 *cells = (PN_uint32 *)p;
05288
05289
05290 PN_uint32 w0 = cells[0];
05291 PN_uint32 w1 = cells[1];
05292 w0 = ((w0 & 0xffff) << 16) | ((w0 & 0xffff0000U) >> 16);
05293 w1 = ((w1 & 0xffff) << 16) | ((w1 & 0xffff0000U) >> 16);
05294 cells[0] = w1;
05295 cells[1] = w0;
05296
05297
05298
05299 PN_uint32 w = cells[3];
05300 w = ((w & 0xff) << 24) | ((w & 0xff00) << 8) | ((w & 0xff0000) >> 8) | ((w & 0xff000000U) >> 24);
05301 cells[3] = w;
05302
05303 p += block_bytes;
05304 }
05305 }
05306
05307 } else if (y_size >= 2) {
05308
05309 unsigned char *p = image.p();
05310 in.read((char *)p, row_length);
05311
05312 for (int ci = 0; ci < num_cols; ++ci) {
05313 PN_uint32 *cells = (PN_uint32 *)p;
05314
05315 PN_uint32 w0 = cells[0];
05316 w0 = ((w0 & 0xffff) << 16) | ((w0 & 0xffff0000U) >> 16);
05317 cells[0] = w0;
05318
05319 PN_uint32 w = cells[3];
05320 w = ((w & 0xff) << 8) | ((w & 0xff00) >> 8);
05321 cells[3] = w;
05322
05323 p += block_bytes;
05324 }
05325
05326 } else if (y_size >= 1) {
05327
05328 unsigned char *p = image.p();
05329 in.read((char *)p, row_length);
05330 }
05331
05332 return image;
05333 }
05334
05335
05336
05337
05338
05339
05340 PTA_uchar Texture::
05341 read_dds_level_dxt45(Texture *tex, const DDSHeader &header, int n, istream &in) {
05342 int x_size = tex->do_get_expected_mipmap_x_size(n);
05343 int y_size = tex->do_get_expected_mipmap_y_size(n);
05344
05345 static const int div = 4;
05346 static const int block_bytes = 16;
05347
05348
05349
05350
05351 int num_cols = max(div, x_size) / div;
05352 int num_rows = max(div, y_size) / div;
05353 int row_length = num_cols * block_bytes;
05354 int linear_size = row_length * num_rows;
05355
05356 if (n == 0) {
05357 if (header.dds_flags & DDSD_LINEARSIZE) {
05358 nassertr(linear_size == (int)header.pitch, PTA_uchar());
05359 }
05360 }
05361
05362 PTA_uchar image = PTA_uchar::empty_array(linear_size);
05363
05364 if (y_size >= 4) {
05365
05366
05367
05368 for (int ri = num_rows - 1; ri >= 0; --ri) {
05369 unsigned char *p = image.p() + row_length * ri;
05370 in.read((char *)p, row_length);
05371
05372 for (int ci = 0; ci < num_cols; ++ci) {
05373
05374
05375 PN_uint32 *cells = (PN_uint32 *)p;
05376
05377
05378
05379
05380 unsigned char p2 = p[2];
05381 unsigned char p3 = p[3];
05382 unsigned char p4 = p[4];
05383 unsigned char p5 = p[5];
05384 unsigned char p6 = p[6];
05385 unsigned char p7 = p[7];
05386
05387 p[2] = ((p7 & 0xf) << 4) | ((p6 & 0xf0) >> 4);
05388 p[3] = ((p5 & 0xf) << 4) | ((p7 & 0xf0) >> 4);
05389 p[4] = ((p6 & 0xf) << 4) | ((p5 & 0xf0) >> 4);
05390 p[5] = ((p4 & 0xf) << 4) | ((p3 & 0xf0) >> 4);
05391 p[6] = ((p2 & 0xf) << 4) | ((p4 & 0xf0) >> 4);
05392 p[7] = ((p3 & 0xf) << 4) | ((p2 & 0xf0) >> 4);
05393
05394
05395
05396 PN_uint32 w = cells[3];
05397 w = ((w & 0xff) << 24) | ((w & 0xff00) << 8) | ((w & 0xff0000) >> 8) | ((w & 0xff000000U) >> 24);
05398 cells[3] = w;
05399
05400 p += block_bytes;
05401 }
05402 }
05403
05404 } else if (y_size >= 2) {
05405
05406 unsigned char *p = image.p();
05407 in.read((char *)p, row_length);
05408
05409 for (int ci = 0; ci < num_cols; ++ci) {
05410 PN_uint32 *cells = (PN_uint32 *)p;
05411
05412 unsigned char p2 = p[2];
05413 unsigned char p3 = p[3];
05414 unsigned char p4 = p[4];
05415
05416 p[2] = ((p4 & 0xf) << 4) | ((p3 & 0xf0) >> 4);
05417 p[3] = ((p2 & 0xf) << 4) | ((p4 & 0xf0) >> 4);
05418 p[4] = ((p3 & 0xf) << 4) | ((p2 & 0xf0) >> 4);
05419
05420 PN_uint32 w0 = cells[0];
05421 w0 = ((w0 & 0xffff) << 16) | ((w0 & 0xffff0000U) >> 16);
05422 cells[0] = w0;
05423
05424 PN_uint32 w = cells[3];
05425 w = ((w & 0xff) << 8) | ((w & 0xff00) >> 8);
05426 cells[3] = w;
05427
05428 p += block_bytes;
05429 }
05430
05431 } else if (y_size >= 1) {
05432
05433 unsigned char *p = image.p();
05434 in.read((char *)p, row_length);
05435 }
05436
05437 return image;
05438 }
05439
05440
05441
05442
05443
05444
05445
05446
05447
05448
05449 void Texture::
05450 clear_prepared(PreparedGraphicsObjects *prepared_objects) {
05451 Contexts::iterator ci;
05452 ci = _contexts.find(prepared_objects);
05453 if (ci != _contexts.end()) {
05454 _contexts.erase(ci);
05455 } else {
05456
05457
05458 nassertv(false);
05459 }
05460 }
05461
05462
05463
05464
05465
05466
05467
05468 void Texture::
05469 consider_downgrade(PNMImage &pnmimage, int num_channels, const string &name) {
05470 if (num_channels != 0 && num_channels < pnmimage.get_num_channels()) {
05471
05472
05473 if (pnmimage.get_num_channels() == 3 && num_channels == 2) {
05474 return;
05475 }
05476
05477 gobj_cat.info()
05478 << "Downgrading " << name << " from "
05479 << pnmimage.get_num_channels() << " components to "
05480 << num_channels << ".\n";
05481 pnmimage.set_num_channels(num_channels);
05482 }
05483 }
05484
05485
05486
05487
05488
05489
05490
05491
05492 bool Texture::
05493 compare_images(const PNMImage &a, const PNMImage &b) {
05494 nassertr(a.get_maxval() == 255 && b.get_maxval() == 255, false);
05495 nassertr(a.get_num_channels() == 4 && b.get_num_channels() == 4, false);
05496 nassertr(a.get_x_size() == b.get_x_size() &&
05497 a.get_y_size() == b.get_y_size(), false);
05498
05499 int delta = 0;
05500 for (int yi = 0; yi < a.get_y_size(); ++yi) {
05501 for (int xi = 0; xi < a.get_x_size(); ++xi) {
05502 delta += abs(a.get_red_val(xi, yi) - b.get_red_val(xi, yi));
05503 delta += abs(a.get_green_val(xi, yi) - b.get_green_val(xi, yi));
05504 delta += abs(a.get_blue_val(xi, yi) - b.get_blue_val(xi, yi));
05505 delta += abs(a.get_alpha_val(xi, yi) - b.get_alpha_val(xi, yi));
05506 }
05507 }
05508
05509 double average_delta = (double)delta / ((double)a.get_x_size() * (double)b.get_y_size() * (double)a.get_maxval());
05510 return (average_delta <= simple_image_threshold);
05511 }
05512
05513
05514
05515
05516
05517
05518
05519
05520
05521
05522
05523
05524
05525
05526 void Texture::
05527 filter_2d_mipmap_pages(Texture::RamImage &to, const Texture::RamImage &from,
05528 int x_size, int y_size) {
05529 size_t pixel_size = _num_components * _component_width;
05530 size_t row_size = (size_t)x_size * pixel_size;
05531
05532 int to_x_size = max(x_size >> 1, 1);
05533 int to_y_size = max(y_size >> 1, 1);
05534
05535 size_t to_row_size = (size_t)to_x_size * pixel_size;
05536 to._page_size = (size_t)to_y_size * to_row_size;
05537 to._image = PTA_uchar::empty_array(to._page_size * _z_size, get_class_type());
05538
05539 Filter2DComponent *filter_component = (_component_type == T_unsigned_byte ? &filter_2d_unsigned_byte : filter_2d_unsigned_short);
05540
05541 for (int z = 0; z < _z_size; ++z) {
05542
05543 unsigned char *p = to._image.p() + z * to._page_size;
05544 const unsigned char *q = from._image.p() + z * from._page_size;
05545 if (y_size != 1) {
05546 int y;
05547 for (y = 0; y < y_size - 1; y += 2) {
05548
05549 nassertv(p == to._image.p() + z * to._page_size + (y / 2) * to_row_size);
05550 nassertv(q == from._image.p() + z * from._page_size + y * row_size);
05551 if (x_size != 1) {
05552 int x;
05553 for (x = 0; x < x_size - 1; x += 2) {
05554
05555 for (int c = 0; c < _num_components; ++c) {
05556
05557 filter_component(p, q, pixel_size, row_size);
05558 }
05559 q += pixel_size;
05560 }
05561 if (x < x_size) {
05562
05563 q += pixel_size;
05564 }
05565 } else {
05566
05567 for (int c = 0; c < _num_components; ++c) {
05568
05569 filter_component(p, q, 0, row_size);
05570 }
05571 }
05572 q += row_size;
05573 Thread::consider_yield();
05574 }
05575 if (y < y_size) {
05576
05577 q += row_size;
05578 }
05579 } else {
05580
05581 if (x_size != 1) {
05582 int x;
05583 for (x = 0; x < x_size - 1; x += 2) {
05584
05585 for (int c = 0; c < _num_components; ++c) {
05586
05587 filter_component(p, q, pixel_size, 0);
05588 }
05589 q += pixel_size;
05590 }
05591 if (x < x_size) {
05592
05593 q += pixel_size;
05594 }
05595 } else {
05596
05597 for (int c = 0; c < _num_components; ++c) {
05598
05599 filter_component(p, q, 0, 0);
05600 }
05601 }
05602 }
05603
05604 nassertv(p == to._image.p() + (z + 1) * to._page_size);
05605 nassertv(q == from._image.p() + (z + 1) * from._page_size);
05606 }
05607 }
05608
05609
05610
05611
05612
05613
05614
05615
05616
05617
05618
05619
05620
05621
05622 void Texture::
05623 filter_3d_mipmap_level(Texture::RamImage &to, const Texture::RamImage &from,
05624 int x_size, int y_size, int z_size) {
05625 size_t pixel_size = _num_components * _component_width;
05626 size_t row_size = (size_t)x_size * pixel_size;
05627 size_t page_size = (size_t)y_size * row_size;
05628
05629 int to_x_size = max(x_size >> 1, 1);
05630 int to_y_size = max(y_size >> 1, 1);
05631 int to_z_size = max(z_size >> 1, 1);
05632
05633 size_t to_row_size = (size_t)to_x_size * pixel_size;
05634 size_t to_page_size = (size_t)to_y_size * to_row_size;
05635 to._page_size = to_page_size;
05636 to._image = PTA_uchar::empty_array(to_page_size * to_z_size, get_class_type());
05637
05638 Filter3DComponent *filter_component = (_component_type == T_unsigned_byte ? &filter_3d_unsigned_byte : filter_3d_unsigned_short);
05639
05640 unsigned char *p = to._image.p();
05641 const unsigned char *q = from._image.p();
05642 if (z_size != 1) {
05643 int z;
05644 for (z = 0; z < z_size - 1; z += 2) {
05645
05646 nassertv(p == to._image.p() + (z / 2) * to_page_size);
05647 nassertv(q == from._image.p() + z * page_size);
05648 if (y_size != 1) {
05649 int y;
05650 for (y = 0; y < y_size - 1; y += 2) {
05651
05652 nassertv(p == to._image.p() + (z / 2) * to_page_size + (y / 2) * to_row_size);
05653 nassertv(q == from._image.p() + z * page_size + y * row_size);
05654 if (x_size != 1) {
05655 int x;
05656 for (x = 0; x < x_size - 1; x += 2) {
05657
05658 for (int c = 0; c < _num_components; ++c) {
05659
05660 filter_component(p, q, pixel_size, row_size, page_size);
05661 }
05662 q += pixel_size;
05663 }
05664 if (x < x_size) {
05665
05666 q += pixel_size;
05667 }
05668 } else {
05669
05670 for (int c = 0; c < _num_components; ++c) {
05671
05672 filter_component(p, q, 0, row_size, page_size);
05673 }
05674 }
05675 q += row_size;
05676 Thread::consider_yield();
05677 }
05678 if (y < y_size) {
05679
05680 q += row_size;
05681 }
05682 } else {
05683
05684 if (x_size != 1) {
05685 int x;
05686 for (x = 0; x < x_size - 1; x += 2) {
05687
05688 for (int c = 0; c < _num_components; ++c) {
05689
05690 filter_component(p, q, pixel_size, 0, page_size);
05691 }
05692 q += pixel_size;
05693 }
05694 if (x < x_size) {
05695
05696 q += pixel_size;
05697 }
05698 } else {
05699
05700 for (int c = 0; c < _num_components; ++c) {
05701
05702 filter_component(p, q, 0, 0, page_size);
05703 }
05704 }
05705 }
05706 q += page_size;
05707 }
05708 if (z < z_size) {
05709
05710 q += page_size;
05711 }
05712 } else {
05713
05714 if (y_size != 1) {
05715 int y;
05716 for (y = 0; y < y_size - 1; y += 2) {
05717
05718 nassertv(p == to._image.p() + (y / 2) * to_row_size);
05719 nassertv(q == from._image.p() + y * row_size);
05720 if (x_size != 1) {
05721 int x;
05722 for (x = 0; x < x_size - 1; x += 2) {
05723
05724 for (int c = 0; c < _num_components; ++c) {
05725
05726 filter_component(p, q, pixel_size, row_size, 0);
05727 }
05728 q += pixel_size;
05729 }
05730 if (x < x_size) {
05731
05732 q += pixel_size;
05733 }
05734 } else {
05735
05736 for (int c = 0; c < _num_components; ++c) {
05737
05738 filter_component(p, q, 0, row_size, 0);
05739 }
05740 }
05741 q += row_size;
05742 Thread::consider_yield();
05743 }
05744 if (y < y_size) {
05745
05746 q += row_size;
05747 }
05748 } else {
05749
05750 if (x_size != 1) {
05751 int x;
05752 for (x = 0; x < x_size - 1; x += 2) {
05753
05754 for (int c = 0; c < _num_components; ++c) {
05755
05756 filter_component(p, q, pixel_size, 0, 0);
05757 }
05758 q += pixel_size;
05759 }
05760 if (x < x_size) {
05761
05762 q += pixel_size;
05763 }
05764 } else {
05765
05766 for (int c = 0; c < _num_components; ++c) {
05767
05768 filter_component(p, q, 0, 0, 0);
05769 }
05770 }
05771 }
05772 }
05773
05774 nassertv(p == to._image.p() + to_z_size * to_page_size);
05775 nassertv(q == from._image.p() + z_size * page_size);
05776 }
05777
05778
05779
05780
05781
05782
05783
05784
05785 void Texture::
05786 filter_2d_unsigned_byte(unsigned char *&p, const unsigned char *&q,
05787 size_t pixel_size, size_t row_size) {
05788 unsigned int result = ((unsigned int)q[0] +
05789 (unsigned int)q[pixel_size] +
05790 (unsigned int)q[row_size] +
05791 (unsigned int)q[pixel_size + row_size]) >> 2;
05792 *p = (unsigned char)result;
05793 ++p;
05794 ++q;
05795 }
05796
05797
05798
05799
05800
05801
05802
05803
05804 void Texture::
05805 filter_2d_unsigned_short(unsigned char *&p, const unsigned char *&q,
05806 size_t pixel_size, size_t row_size) {
05807 unsigned int result = ((unsigned int)*(unsigned short *)&q[0] +
05808 (unsigned int)*(unsigned short *)&q[pixel_size] +
05809 (unsigned int)*(unsigned short *)&q[row_size] +
05810 (unsigned int)*(unsigned short *)&q[pixel_size + row_size]) >> 2;
05811 store_unscaled_short(p, result);
05812 q += 2;
05813 }
05814
05815
05816
05817
05818
05819
05820
05821
05822 void Texture::
05823 filter_3d_unsigned_byte(unsigned char *&p, const unsigned char *&q,
05824 size_t pixel_size, size_t row_size, size_t page_size) {
05825 unsigned int result = ((unsigned int)q[0] +
05826 (unsigned int)q[pixel_size] +
05827 (unsigned int)q[row_size] +
05828 (unsigned int)q[pixel_size + row_size] +
05829 (unsigned int)q[page_size] +
05830 (unsigned int)q[pixel_size + page_size] +
05831 (unsigned int)q[row_size + page_size] +
05832 (unsigned int)q[pixel_size + row_size + page_size]) >> 3;
05833 *p = (unsigned char)result;
05834 ++p;
05835 ++q;
05836 }
05837
05838
05839
05840
05841
05842
05843
05844
05845 void Texture::
05846 filter_3d_unsigned_short(unsigned char *&p, const unsigned char *&q,
05847 size_t pixel_size, size_t row_size,
05848 size_t page_size) {
05849 unsigned int result = ((unsigned int)*(unsigned short *)&q[0] +
05850 (unsigned int)*(unsigned short *)&q[pixel_size] +
05851 (unsigned int)*(unsigned short *)&q[row_size] +
05852 (unsigned int)*(unsigned short *)&q[pixel_size + row_size] +
05853 (unsigned int)*(unsigned short *)&q[page_size] +
05854 (unsigned int)*(unsigned short *)&q[pixel_size + page_size] +
05855 (unsigned int)*(unsigned short *)&q[row_size + page_size] +
05856 (unsigned int)*(unsigned short *)&q[pixel_size + row_size + page_size]) >> 3;
05857 store_unscaled_short(p, result);
05858 q += 2;
05859 }
05860
05861
05862
05863
05864
05865
05866
05867 bool Texture::
05868 do_squish(Texture::CompressionMode compression, int squish_flags) {
05869 #ifdef HAVE_SQUISH
05870 if (_ram_images.empty() || _ram_image_compression != CM_off) {
05871 return false;
05872 }
05873
05874 if (!do_has_all_ram_mipmap_images()) {
05875
05876
05877 do_generate_ram_mipmap_images();
05878 }
05879
05880 RamImages compressed_ram_images;
05881 compressed_ram_images.reserve(_ram_images.size());
05882 for (size_t n = 0; n < _ram_images.size(); ++n) {
05883 RamImage compressed_image;
05884 int x_size = do_get_expected_mipmap_x_size(n);
05885 int y_size = do_get_expected_mipmap_y_size(n);
05886 int z_size = do_get_expected_mipmap_z_size(n);
05887 int page_size = squish::GetStorageRequirements(x_size, y_size, squish_flags);
05888 int cell_size = squish::GetStorageRequirements(4, 4, squish_flags);
05889
05890 compressed_image._page_size = page_size;
05891 compressed_image._image = PTA_uchar::empty_array(page_size * z_size);
05892 for (int z = 0; z < z_size; ++z) {
05893 unsigned char *dest_page = compressed_image._image.p() + z * page_size;
05894 unsigned const char *source_page = _ram_images[n]._image.p() + z * _ram_images[n]._page_size;
05895 unsigned const char *source_page_end = source_page + _ram_images[n]._page_size;
05896
05897 unsigned char *d = dest_page;
05898 for (int y = 0; y < y_size; y += 4) {
05899 for (int x = 0; x < x_size; x += 4) {
05900 unsigned char tb[16 * 4];
05901 int mask = 0;
05902 unsigned char *t = tb;
05903 for (int i = 0; i < 16; ++i) {
05904 int xi = x + i % 4;
05905 int yi = y + i / 4;
05906 unsigned const char *s = source_page + (yi * x_size + xi) * _num_components;
05907 if (s < source_page_end) {
05908 switch (_num_components) {
05909 case 1:
05910 t[0] = s[0];
05911 t[1] = s[0];
05912 t[2] = s[0];
05913 t[3] = 255;
05914 break;
05915
05916 case 2:
05917 t[0] = s[0];
05918 t[1] = s[0];
05919 t[2] = s[0];
05920 t[3] = s[1];
05921 break;
05922
05923 case 3:
05924 t[0] = s[2];
05925 t[1] = s[1];
05926 t[2] = s[0];
05927 t[3] = 255;
05928 break;
05929
05930 case 4:
05931 t[0] = s[2];
05932 t[1] = s[1];
05933 t[2] = s[0];
05934 t[3] = s[3];
05935 break;
05936 }
05937 mask |= (1 << i);
05938 }
05939 t += 4;
05940 }
05941 squish::CompressMasked(tb, mask, d, squish_flags);
05942 d += cell_size;
05943 Thread::consider_yield();
05944 }
05945 }
05946 }
05947 compressed_ram_images.push_back(compressed_image);
05948 }
05949 _ram_images.swap(compressed_ram_images);
05950 _ram_image_compression = compression;
05951 return true;
05952
05953 #else // HAVE_SQUISH
05954 return false;
05955
05956 #endif // HAVE_SQUISH
05957 }
05958
05959
05960
05961
05962
05963
05964
05965 bool Texture::
05966 do_unsquish(int squish_flags) {
05967 #ifdef HAVE_SQUISH
05968 if (_ram_images.empty()) {
05969 return false;
05970 }
05971 RamImages uncompressed_ram_images;
05972 uncompressed_ram_images.reserve(_ram_images.size());
05973 for (size_t n = 0; n < _ram_images.size(); ++n) {
05974 RamImage uncompressed_image;
05975 int x_size = do_get_expected_mipmap_x_size(n);
05976 int y_size = do_get_expected_mipmap_y_size(n);
05977 int z_size = do_get_expected_mipmap_z_size(n);
05978 int page_size = squish::GetStorageRequirements(x_size, y_size, squish_flags);
05979 int cell_size = squish::GetStorageRequirements(4, 4, squish_flags);
05980
05981 uncompressed_image._page_size = do_get_expected_ram_mipmap_page_size(n);
05982 uncompressed_image._image = PTA_uchar::empty_array(uncompressed_image._page_size * z_size);
05983 for (int z = 0; z < z_size; ++z) {
05984 unsigned char *dest_page = uncompressed_image._image.p() + z * uncompressed_image._page_size;
05985 unsigned char *dest_page_end = dest_page + uncompressed_image._page_size;
05986 unsigned const char *source_page = _ram_images[n]._image.p() + z * page_size;
05987
05988 unsigned const char *s = source_page;
05989 for (int y = 0; y < y_size; y += 4) {
05990 for (int x = 0; x < x_size; x += 4) {
05991 unsigned char tb[16 * 4];
05992 squish::Decompress(tb, s, squish_flags);
05993 s += cell_size;
05994
05995 unsigned char *t = tb;
05996 for (int i = 0; i < 16; ++i) {
05997 int xi = x + i % 4;
05998 int yi = y + i / 4;
05999 unsigned char *d = dest_page + (yi * x_size + xi) * _num_components;
06000 if (d < dest_page_end) {
06001 switch (_num_components) {
06002 case 1:
06003 d[0] = t[1];
06004 break;
06005
06006 case 2:
06007 d[0] = t[1];
06008 d[1] = t[3];
06009 break;
06010
06011 case 3:
06012 d[2] = t[0];
06013 d[1] = t[1];
06014 d[0] = t[2];
06015 break;
06016
06017 case 4:
06018 d[2] = t[0];
06019 d[1] = t[1];
06020 d[0] = t[2];
06021 d[3] = t[3];
06022 break;
06023 }
06024 }
06025 t += 4;
06026 }
06027 }
06028 Thread::consider_yield();
06029 }
06030 }
06031 uncompressed_ram_images.push_back(uncompressed_image);
06032 }
06033 _ram_images.swap(uncompressed_ram_images);
06034 _ram_image_compression = CM_off;
06035 return true;
06036
06037 #else // HAVE_SQUISH
06038 return false;
06039
06040 #endif // HAVE_SQUISH
06041 }
06042
06043
06044
06045
06046
06047
06048 void Texture::
06049 register_with_read_factory() {
06050 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
06051 }
06052
06053
06054
06055
06056
06057
06058 TypedWritable *Texture::
06059 make_from_bam(const FactoryParams ¶ms) {
06060
06061
06062
06063
06064
06065 DatagramIterator scan;
06066 BamReader *manager;
06067
06068 parse_params(params, scan, manager);
06069
06070
06071
06072 string name = scan.get_string();
06073 Filename filename = scan.get_string();
06074 Filename alpha_filename = scan.get_string();
06075
06076 int primary_file_num_channels = scan.get_uint8();
06077 int alpha_file_channel = scan.get_uint8();
06078 bool has_rawdata = scan.get_bool();
06079 TextureType texture_type = (TextureType)scan.get_uint8();
06080
06081 Texture *me = NULL;
06082 if (has_rawdata) {
06083
06084
06085 me = new Texture(name);
06086 me->_filename = filename;
06087 me->_alpha_filename = alpha_filename;
06088 me->_primary_file_num_channels = primary_file_num_channels;
06089 me->_alpha_file_channel = alpha_file_channel;
06090 me->_texture_type = texture_type;
06091
06092
06093 me->fillin(scan, manager, has_rawdata);
06094
06095 } else {
06096
06097
06098 PT(Texture) dummy = new Texture("");
06099 dummy->fillin(scan, manager, has_rawdata);
06100
06101 if (filename.empty()) {
06102
06103
06104 gobj_cat.info()
06105 << "Cannot create texture '" << name << "' with no filename.\n";
06106
06107 } else {
06108
06109 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
06110 if (!manager->get_filename().empty()) {
06111
06112
06113 Filename bam_dir = manager->get_filename().get_dirname();
06114 vfs->resolve_filename(filename, bam_dir);
06115 if (!alpha_filename.empty()) {
06116 vfs->resolve_filename(alpha_filename, bam_dir);
06117 }
06118 }
06119
06120 LoaderOptions options = manager->get_loader_options();
06121 if (dummy->uses_mipmaps()) {
06122 options.set_texture_flags(options.get_texture_flags() | LoaderOptions::TF_generate_mipmaps);
06123 }
06124
06125 switch (texture_type) {
06126 case TT_1d_texture:
06127 case TT_2d_texture:
06128 if (alpha_filename.empty()) {
06129 me = TexturePool::load_texture(filename, primary_file_num_channels,
06130 false, options);
06131 } else {
06132 me = TexturePool::load_texture(filename, alpha_filename,
06133 primary_file_num_channels,
06134 alpha_file_channel,
06135 false, options);
06136 }
06137 break;
06138
06139 case TT_3d_texture:
06140 me = TexturePool::load_3d_texture(filename, false, options);
06141 break;
06142
06143 case TT_cube_map:
06144 me = TexturePool::load_cube_map(filename, false, options);
06145 break;
06146 }
06147 }
06148
06149 if (me != (Texture *)NULL) {
06150 me->fillin_from(dummy);
06151 me->set_name(name);
06152 }
06153 }
06154
06155 return me;
06156 }
06157
06158
06159
06160
06161
06162
06163
06164
06165
06166 void Texture::
06167 fillin(DatagramIterator &scan, BamReader *manager, bool has_rawdata) {
06168
06169
06170 _wrap_u = (WrapMode)scan.get_uint8();
06171 _wrap_v = (WrapMode)scan.get_uint8();
06172 _wrap_w = (WrapMode)scan.get_uint8();
06173 _minfilter = (FilterType)scan.get_uint8();
06174 _magfilter = (FilterType)scan.get_uint8();
06175 _anisotropic_degree = scan.get_int16();
06176 _border_color.read_datagram(scan);
06177
06178 if (manager->get_file_minor_ver() >= 1) {
06179 _compression = (CompressionMode)scan.get_uint8();
06180 }
06181 if (manager->get_file_minor_ver() >= 16) {
06182 _quality_level = (QualityLevel)scan.get_uint8();
06183 }
06184
06185 _format = (Format)scan.get_uint8();
06186 _num_components = scan.get_uint8();
06187 ++_properties_modified;
06188
06189 bool has_simple_ram_image = false;
06190 if (manager->get_file_minor_ver() >= 18) {
06191 _orig_file_x_size = scan.get_uint32();
06192 _orig_file_y_size = scan.get_uint32();
06193
06194 has_simple_ram_image = scan.get_bool();
06195 }
06196
06197 if (has_simple_ram_image) {
06198 _simple_x_size = scan.get_uint32();
06199 _simple_y_size = scan.get_uint32();
06200 _simple_image_date_generated = scan.get_int32();
06201
06202 size_t u_size = scan.get_uint32();
06203 PTA_uchar image = PTA_uchar::empty_array(u_size, get_class_type());
06204 for (size_t u_idx = 0; u_idx < u_size; ++u_idx) {
06205 image[(int)u_idx] = scan.get_uint8();
06206 }
06207
06208 _simple_ram_image._image = image;
06209 _simple_ram_image._page_size = u_size;
06210 ++_simple_image_modified;
06211 }
06212
06213 if (has_rawdata) {
06214 _x_size = scan.get_uint32();
06215 _y_size = scan.get_uint32();
06216 _z_size = scan.get_uint32();
06217 _component_type = (ComponentType)scan.get_uint8();
06218 _component_width = scan.get_uint8();
06219 _ram_image_compression = CM_off;
06220 if (manager->get_file_minor_ver() >= 1) {
06221 _ram_image_compression = (CompressionMode)scan.get_uint8();
06222 }
06223
06224 int num_ram_images = 1;
06225 if (manager->get_file_minor_ver() >= 3) {
06226 num_ram_images = scan.get_uint8();
06227 }
06228
06229 _ram_images.clear();
06230 _ram_images.reserve(num_ram_images);
06231 for (int n = 0; n < num_ram_images; ++n) {
06232 _ram_images.push_back(RamImage());
06233 _ram_images[n]._page_size = get_expected_ram_page_size();
06234 if (manager->get_file_minor_ver() >= 1) {
06235 _ram_images[n]._page_size = scan.get_uint32();
06236 }
06237
06238 size_t u_size = scan.get_uint32();
06239
06240
06241 PTA_uchar image = PTA_uchar::empty_array(u_size, get_class_type());
06242 for (size_t u_idx = 0; u_idx < u_size; ++u_idx) {
06243 image[(int)u_idx] = scan.get_uint8();
06244 }
06245 _ram_images[n]._image = image;
06246 }
06247 _loaded_from_image = true;
06248 do_set_pad_size(0, 0, 0);
06249 ++_image_modified;
06250 }
06251 }
06252
06253
06254
06255
06256
06257
06258
06259
06260
06261 void Texture::
06262 fillin_from(Texture *dummy) {
06263 MutexHolder holder(_lock);
06264
06265
06266
06267
06268
06269
06270
06271
06272 do_set_wrap_u(dummy->get_wrap_u());
06273 do_set_wrap_v(dummy->get_wrap_v());
06274 do_set_wrap_w(dummy->get_wrap_w());
06275 do_set_border_color(dummy->get_border_color());
06276
06277 if (dummy->get_minfilter() != FT_default) {
06278 do_set_minfilter(dummy->get_minfilter());
06279 }
06280 if (dummy->get_magfilter() != FT_default) {
06281 do_set_magfilter(dummy->get_magfilter());
06282 }
06283 if (dummy->get_anisotropic_degree() != 0) {
06284 do_set_anisotropic_degree(dummy->get_anisotropic_degree());
06285 }
06286 if (dummy->get_compression() != CM_default) {
06287 do_set_compression(dummy->get_compression());
06288 }
06289 if (dummy->get_quality_level() != QL_default) {
06290 do_set_quality_level(dummy->get_quality_level());
06291 }
06292
06293 Format format = dummy->get_format();
06294 int num_components = dummy->get_num_components();
06295
06296 if (num_components == _num_components) {
06297
06298
06299
06300
06301 do_set_format(format);
06302 }
06303
06304 if (dummy->has_simple_ram_image()) {
06305
06306
06307 if (_simple_ram_image._image.empty() ||
06308 dummy->_simple_image_date_generated > _simple_image_date_generated) {
06309 do_set_simple_ram_image(dummy->get_simple_ram_image(),
06310 dummy->get_simple_x_size(),
06311 dummy->get_simple_y_size());
06312 _simple_image_date_generated = dummy->_simple_image_date_generated;
06313 }
06314 }
06315 }
06316
06317
06318
06319
06320
06321
06322
06323 void Texture::
06324 write_datagram(BamWriter *manager, Datagram &me) {
06325 MutexHolder holder(_lock);
06326
06327
06328
06329
06330
06331
06332
06333
06334
06335 BamWriter::BamTextureMode file_texture_mode = manager->get_file_texture_mode();
06336 bool has_rawdata =
06337 (file_texture_mode == BamWriter::BTM_rawdata || (do_has_ram_image() && _filename.empty()));
06338 if (has_rawdata && !do_has_ram_image()) {
06339 do_get_ram_image();
06340 if (!do_has_ram_image()) {
06341
06342 has_rawdata = false;
06343 }
06344 }
06345
06346 bool has_bam_dir = !manager->get_filename().empty();
06347 Filename bam_dir = manager->get_filename().get_dirname();
06348 Filename filename = _filename;
06349 Filename alpha_filename = _alpha_filename;
06350
06351 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
06352
06353 switch (file_texture_mode) {
06354 case BamWriter::BTM_unchanged:
06355 case BamWriter::BTM_rawdata:
06356 break;
06357
06358 case BamWriter::BTM_fullpath:
06359 filename = _fullpath;
06360 alpha_filename = _alpha_fullpath;
06361 break;
06362
06363 case BamWriter::BTM_relative:
06364 filename = _fullpath;
06365 alpha_filename = _alpha_fullpath;
06366 bam_dir.make_absolute(vfs->get_cwd());
06367 if (!has_bam_dir || !filename.make_relative_to(bam_dir, true)) {
06368 filename.find_on_searchpath(get_model_path());
06369 }
06370 if (gobj_cat.is_debug()) {
06371 gobj_cat.debug()
06372 << "Texture file " << _fullpath
06373 << " found as " << filename << "\n";
06374 }
06375 if (!has_bam_dir || !alpha_filename.make_relative_to(bam_dir, true)) {
06376 alpha_filename.find_on_searchpath(get_model_path());
06377 }
06378 if (gobj_cat.is_debug()) {
06379 gobj_cat.debug()
06380 << "Alpha image " << _alpha_fullpath
06381 << " found as " << alpha_filename << "\n";
06382 }
06383 break;
06384
06385 case BamWriter::BTM_basename:
06386 filename = _fullpath.get_basename();
06387 alpha_filename = _alpha_fullpath.get_basename();
06388 break;
06389
06390 default:
06391 gobj_cat.error()
06392 << "Unsupported bam-texture-mode: " << (int)file_texture_mode << "\n";
06393 }
06394
06395 if (filename.empty() && do_has_ram_image()) {
06396
06397 has_rawdata = true;
06398 }
06399
06400 me.add_string(get_name());
06401 me.add_string(filename);
06402 me.add_string(alpha_filename);
06403 me.add_uint8(_primary_file_num_channels);
06404 me.add_uint8(_alpha_file_channel);
06405 me.add_bool(has_rawdata);
06406 me.add_uint8(_texture_type);
06407
06408
06409 me.add_uint8(_wrap_u);
06410 me.add_uint8(_wrap_v);
06411 me.add_uint8(_wrap_w);
06412 me.add_uint8(_minfilter);
06413 me.add_uint8(_magfilter);
06414 me.add_int16(_anisotropic_degree);
06415 _border_color.write_datagram(me);
06416 me.add_uint8(_compression);
06417 me.add_uint8(_quality_level);
06418
06419 me.add_uint8(_format);
06420 me.add_uint8(_num_components);
06421
06422 me.add_uint32(_orig_file_x_size);
06423 me.add_uint32(_orig_file_y_size);
06424
06425 bool has_simple_ram_image = !_simple_ram_image._image.empty();
06426 me.add_bool(has_simple_ram_image);
06427
06428
06429 if (has_simple_ram_image) {
06430 me.add_uint32(_simple_x_size);
06431 me.add_uint32(_simple_y_size);
06432 me.add_int32(_simple_image_date_generated);
06433 me.add_uint32(_simple_ram_image._image.size());
06434 me.append_data(_simple_ram_image._image, _simple_ram_image._image.size());
06435 }
06436
06437
06438
06439 if (has_rawdata) {
06440 me.add_uint32(_x_size);
06441 me.add_uint32(_y_size);
06442 me.add_uint32(_z_size);
06443 me.add_uint8(_component_type);
06444 me.add_uint8(_component_width);
06445 me.add_uint8(_ram_image_compression);
06446 me.add_uint8(_ram_images.size());
06447 for (size_t n = 0; n < _ram_images.size(); ++n) {
06448 me.add_uint32(_ram_images[n]._page_size);
06449 me.add_uint32(_ram_images[n]._image.size());
06450 me.append_data(_ram_images[n]._image, _ram_images[n]._image.size());
06451 }
06452 }
06453 }
06454
06455
06456
06457
06458
06459 ostream &
06460 operator << (ostream &out, Texture::TextureType tt) {
06461 switch (tt) {
06462 case Texture::TT_1d_texture:
06463 return out << "1d_texture";
06464 case Texture::TT_2d_texture:
06465 return out << "2d_texture";
06466 case Texture::TT_3d_texture:
06467 return out << "3d_texture";
06468 case Texture::TT_cube_map:
06469 return out << "cube_map";
06470 }
06471
06472 return out << "(**invalid Texture::TextureType(" << (int)tt << ")**)";
06473 }
06474
06475
06476
06477
06478
06479 ostream &
06480 operator << (ostream &out, Texture::ComponentType ct) {
06481 switch (ct) {
06482 case Texture::T_unsigned_byte:
06483 return out << "unsigned_byte";
06484 case Texture::T_unsigned_short:
06485 return out << "unsigned_short";
06486 case Texture::T_float:
06487 return out << "float";
06488 case Texture::T_unsigned_int_24.:
06489 return out << "unsigned_int_24.";
06490 }
06491
06492 return out << "(**invalid Texture::ComponentType(" << (int)ct << ")**)";
06493 }
06494
06495
06496
06497
06498
06499 ostream &
06500 operator << (ostream &out, Texture::Format f) {
06501 switch (f) {
06502 case Texture::F_depth_stencil:
06503 return out << "depth_stencil";
06504 case Texture::F_depth_component:
06505 return out << "depth_component";
06506 case Texture::F_depth_component16:
06507 return out << "depth_component16";
06508 case Texture::F_depth_component24:
06509 return out << "depth_component24";
06510 case Texture::F_depth_component32:
06511 return out << "depth_component32";
06512 case Texture::F_color_index:
06513 return out << "color_index";
06514 case Texture::F_red:
06515 return out << "red";
06516 case Texture::F_green:
06517 return out << "green";
06518 case Texture::F_blue:
06519 return out << "blue";
06520 case Texture::F_alpha:
06521 return out << "alpha";
06522 case Texture::F_rgb:
06523 return out << "rgb";
06524 case Texture::F_rgb5:
06525 return out << "rgb5";
06526 case Texture::F_rgb8:
06527 return out << "rgb8";
06528 case Texture::F_rgb12:
06529 return out << "rgb12";
06530 case Texture::F_rgb332:
06531 return out << "rgb332";
06532 case Texture::F_rgba:
06533 return out << "rgba";
06534 case Texture::F_rgbm:
06535 return out << "rgbm";
06536 case Texture::F_rgba4:
06537 return out << "rgba4";
06538 case Texture::F_rgba5:
06539 return out << "rgba5";
06540 case Texture::F_rgba8:
06541 return out << "rgba8";
06542 case Texture::F_rgba12:
06543 return out << "rgba12";
06544 case Texture::F_luminance:
06545 return out << "luminance";
06546 case Texture::F_luminance_alpha:
06547 return out << "luminance_alpha";
06548 case Texture::F_luminance_alphamask:
06549 return out << "luminance_alphamask";
06550 case Texture::F_rgba16:
06551 return out << "rgba16";
06552 case Texture::F_rgba32:
06553 return out << "rgba32";
06554 }
06555
06556 return out << "(**invalid Texture::Format(" << (int)f << ")**)";
06557 }
06558
06559
06560
06561
06562
06563 ostream &
06564 operator << (ostream &out, Texture::FilterType ft) {
06565 switch (ft) {
06566 case Texture::FT_nearest:
06567 return out << "nearest";
06568 case Texture::FT_linear:
06569 return out << "linear";
06570
06571 case Texture::FT_nearest_mipmap_nearest:
06572 return out << "nearest_mipmap_nearest";
06573 case Texture::FT_linear_mipmap_nearest:
06574 return out << "linear_mipmap_nearest";
06575 case Texture::FT_nearest_mipmap_linear:
06576 return out << "nearest_mipmap_linear";
06577 case Texture::FT_linear_mipmap_linear:
06578 return out << "linear_mipmap_linear";
06579
06580 case Texture::FT_shadow:
06581 return out << "shadow";
06582
06583 case Texture::FT_default:
06584 return out << "default";
06585
06586 case Texture::FT_invalid:
06587 return out << "invalid";
06588 }
06589
06590 return out << "(**invalid Texture::FilterType(" << (int)ft << ")**)";
06591 }
06592
06593
06594
06595
06596
06597 istream &
06598 operator >> (istream &in, Texture::FilterType &ft) {
06599 string word;
06600 in >> word;
06601
06602 ft = Texture::string_filter_type(word);
06603 return in;
06604 }
06605
06606
06607
06608
06609
06610 ostream &
06611 operator << (ostream &out, Texture::WrapMode wm) {
06612 switch (wm) {
06613 case Texture::WM_clamp:
06614 return out << "clamp";
06615 case Texture::WM_repeat:
06616 return out << "repeat";
06617 case Texture::WM_mirror:
06618 return out << "mirror";
06619 case Texture::WM_mirror_once:
06620 return out << "mirror_once";
06621 case Texture::WM_border_color:
06622 return out << "border_color";
06623
06624 case Texture::WM_invalid:
06625 return out << "invalid";
06626 }
06627
06628 return out << "(**invalid Texture::WrapMode(" << (int)wm << ")**)";
06629 }
06630
06631
06632
06633
06634
06635 istream &
06636 operator >> (istream &in, Texture::WrapMode &wm) {
06637 string word;
06638 in >> word;
06639
06640 wm = Texture::string_wrap_mode(word);
06641 return in;
06642 }
06643
06644
06645
06646
06647
06648 ostream &
06649 operator << (ostream &out, Texture::CompressionMode cm) {
06650 switch (cm) {
06651 case Texture::CM_default:
06652 return out << "default";
06653 case Texture::CM_off:
06654 return out << "off";
06655 case Texture::CM_on:
06656 return out << "on";
06657 case Texture::CM_fxt1:
06658 return out << "fxt1";
06659 case Texture::CM_dxt1:
06660 return out << "dxt1";
06661 case Texture::CM_dxt2:
06662 return out << "dxt2";
06663 case Texture::CM_dxt3:
06664 return out << "dxt3";
06665 case Texture::CM_dxt4:
06666 return out << "dxt4";
06667 case Texture::CM_dxt5:
06668 return out << "dxt5";
06669 }
06670
06671 return out << "(**invalid Texture::CompressionMode(" << (int)cm << ")**)";
06672 }
06673
06674
06675
06676
06677
06678 ostream &
06679 operator << (ostream &out, Texture::QualityLevel tql) {
06680 switch (tql) {
06681 case Texture::QL_default:
06682 return out << "default";
06683 case Texture::QL_fastest:
06684 return out << "fastest";
06685 case Texture::QL_normal:
06686 return out << "normal";
06687 case Texture::QL_best:
06688 return out << "best";
06689 }
06690
06691 return out << "**invalid Texture::QualityLevel (" << (int)tql << ")**";
06692 }
06693
06694
06695
06696
06697
06698 istream &
06699 operator >> (istream &in, Texture::QualityLevel &tql) {
06700 string word;
06701 in >> word;
06702
06703 if (cmp_nocase(word, "default") == 0) {
06704 tql = Texture::QL_default;
06705
06706 } else if (cmp_nocase(word, "fastest") == 0) {
06707 tql = Texture::QL_fastest;
06708
06709 } else if (cmp_nocase(word, "normal") == 0) {
06710 tql = Texture::QL_normal;
06711
06712 } else if (cmp_nocase(word, "best") == 0) {
06713 tql = Texture::QL_best;
06714
06715 } else {
06716 gobj_cat->error() << "Invalid Texture::QualityLevel value: " << word << "\n";
06717 tql = Texture::QL_default;
06718 }
06719
06720 return in;
06721 }