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