Panda3D
|
00001 // Filename: texture.cxx 00002 // Created by: mike (09Jan97) 00003 // Updated by: fperazzi, PandaSE(29Apr10) (added TT_2d_texture_array) 00004 // 00005 //////////////////////////////////////////////////////////////////// 00006 // 00007 // PANDA 3D SOFTWARE 00008 // Copyright (c) Carnegie Mellon University. All rights reserved. 00009 // 00010 // All use of this software is subject to the terms of the revised BSD 00011 // license. You should have received a copy of this license along 00012 // with this source code in a file named "LICENSE." 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 // Stuff to read and write DDS files. 00095 00096 // little-endian, of course 00097 #define DDS_MAGIC 0x20534444 00098 00099 00100 // DDS_header.dwFlags 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 // DDS_header.sPixelFormat.dwFlags 00111 #define DDPF_ALPHAPIXELS 0x00000001 00112 #define DDPF_FOURCC 0x00000004 00113 #define DDPF_INDEXED 0x00000020 00114 #define DDPF_RGB 0x00000040 00115 00116 // DDS_header.sCaps.dwCaps1 00117 #define DDSCAPS_COMPLEX 0x00000008 00118 #define DDSCAPS_TEXTURE 0x00001000 00119 #define DDSCAPS_MIPMAP 0x00400000 00120 00121 // DDS_header.sCaps.dwCaps2 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 // Function: Texture::Constructor 00164 // Access: Published 00165 // Description: Constructs an empty texture. The default is to set 00166 // up the texture as an empty 2-d texture; follow up 00167 // with one of the variants of setup_texture() if this 00168 // is not what you want. 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 // Function: Texture::Copy Constructor 00185 // Access: Protected 00186 // Description: Use Texture::make_copy() to make a duplicate copy of 00187 // an existing Texture. 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 // Function: Texture::Copy Assignment Operator 00201 // Access: Protected 00202 // Description: Use Texture::make_copy() to make a duplicate copy of 00203 // an existing Texture. 00204 //////////////////////////////////////////////////////////////////// 00205 void Texture:: 00206 operator = (const Texture ©) { 00207 Namable::operator = (copy); 00208 _cycler = copy._cycler; 00209 } 00210 00211 //////////////////////////////////////////////////////////////////// 00212 // Function: Texture::Destructor 00213 // Access: Published, Virtual 00214 // Description: 00215 //////////////////////////////////////////////////////////////////// 00216 Texture:: 00217 ~Texture() { 00218 release_all(); 00219 nassertv(!_reloading); 00220 } 00221 00222 //////////////////////////////////////////////////////////////////// 00223 // Function: Texture::generate_normalization_cube_map 00224 // Access: Published 00225 // Description: Generates a special cube map image in the texture 00226 // that can be used to apply bump mapping effects: for 00227 // each texel in the cube map that is indexed by the 3-d 00228 // texture coordinates (x, y, z), the resulting value is 00229 // the normalized vector (x, y, z) (compressed from 00230 // -1..1 into 0..1). 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 // Page 0: positive X. 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 // Page 1: negative X. 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 // Page 2: positive Y. 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 // Page 3: negative Y. 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 // Page 4: positive Z. 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 // Page 5: negative Z. 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 // Function: Texture::generate_alpha_scale_map 00330 // Access: Published 00331 // Description: Generates a special 256x1 1-d texture that can be 00332 // used to apply an arbitrary alpha scale to objects by 00333 // judicious use of texture matrix. The texture is a 00334 // gradient, with an alpha of 0 on the left (U = 0), and 00335 // 255 on the right (U = 1). 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 // Function: Texture::read 00360 // Access: Published 00361 // Description: Reads the named filename into the texture. 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 // Function: Texture::read 00375 // Access: Published 00376 // Description: Combine a 3-component image with a grayscale image 00377 // to get a 4-component image. 00378 // 00379 // See the description of the full-parameter read() 00380 // method for the meaning of the 00381 // primary_file_num_channels and alpha_file_channel 00382 // parameters. 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 // Function: Texture::read 00399 // Access: Published 00400 // Description: Reads a single file into a single page or mipmap 00401 // level, or automatically reads a series of files into 00402 // a series of pages and/or mipmap levels. 00403 // 00404 // See the description of the full-parameter read() 00405 // method for the meaning of the various parameters. 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 // Function: Texture::read 00420 // Access: Published 00421 // Description: Reads the texture from the indicated filename. If 00422 // primary_file_num_channels is not 0, it specifies the 00423 // number of components to downgrade the image to if it 00424 // is greater than this number. 00425 // 00426 // If the filename has the extension .txo, this 00427 // implicitly reads a texture object instead of a 00428 // filename (which replaces all of the texture 00429 // properties). In this case, all the rest of the 00430 // parameters are ignored, and the filename should not 00431 // contain any hash marks; just the one named file will 00432 // be read, since a single .txo file can contain all 00433 // pages and mipmaps necessary to define a texture. 00434 // 00435 // If alpha_fullpath is not empty, it specifies the name 00436 // of a file from which to retrieve the alpha. In this 00437 // case, alpha_file_channel represents the numeric 00438 // channel of this image file to use as the resulting 00439 // texture's alpha channel; usually, this is 0 to 00440 // indicate the grayscale combination of r, g, b; or it 00441 // may be a one-based channel number, e.g. 1 for the red 00442 // channel, 2 for the green channel, and so on. 00443 // 00444 // If read pages is false, then z indicates the page 00445 // number into which this image will be assigned. 00446 // Normally this is 0 for the first (or only) page of 00447 // the texture. 3-D textures have one page for each 00448 // level of depth, and cube map textures always have six 00449 // pages. 00450 // 00451 // If read_pages is true, multiple images will be read 00452 // at once, one for each page of a cube map or a 3-D 00453 // texture. In this case, the filename should contain a 00454 // sequence of one or more hash marks ("#") which will 00455 // be filled in with the z value of each page, 00456 // zero-based. In this case, the z parameter indicates 00457 // the maximum z value that will be loaded, or 0 to load 00458 // all filenames that exist. 00459 // 00460 // If read_mipmaps is false, then n indicates the mipmap 00461 // level to which this image will be assigned. Normally 00462 // this is 0 for the base texture image, but it is 00463 // possible to load custom mipmap levels into the later 00464 // images. After the base texture image is loaded (thus 00465 // defining the size of the texture), you can call 00466 // get_expected_num_mipmap_levels() to determine the 00467 // maximum sensible value for n. 00468 // 00469 // If read_mipmaps is true, multiple images will be read 00470 // as above, but this time the images represent the 00471 // different mipmap levels of the texture image. In 00472 // this case, the n parameter indicates the maximum n 00473 // value that will be loaded, or 0 to load all filenames 00474 // that exist (up to the expected number of mipmap 00475 // levels). 00476 // 00477 // If both read_pages and read_mipmaps is true, then 00478 // both sequences will be read; the filename should 00479 // contain two sequences of hash marks, separated by 00480 // some character such as a hyphen, underscore, or dot. 00481 // The first hash mark sequence will be filled in with 00482 // the mipmap level, while the second hash mark sequence 00483 // will be the page index. 00484 // 00485 // This method implicitly sets keep_ram_image to false. 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 // Function: Texture::estimate_texture_memory 00503 // Access: Published 00504 // Description: Estimates the amount of texture memory that will be 00505 // consumed by loading this texture. This returns a 00506 // value that is not specific to any particular graphics 00507 // card or driver; it tries to make a reasonable 00508 // assumption about how a driver will load the texture. 00509 // It does not account for texture compression or 00510 // anything fancy. This is mainly useful for debugging 00511 // and reporting purposes. 00512 // 00513 // Returns a value in bytes. 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 // Function: Texture::set_aux_data 00582 // Access: Published 00583 // Description: Records an arbitrary object in the Texture, 00584 // associated with a specified key. The object may 00585 // later be retrieved by calling get_aux_data() with the 00586 // same key. 00587 // 00588 // These data objects are not recorded to a bam or txo 00589 // file. 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 // Function: Texture::clear_aux_data 00599 // Access: Published 00600 // Description: Removes a record previously recorded via 00601 // set_aux_data(). 00602 //////////////////////////////////////////////////////////////////// 00603 void Texture:: 00604 clear_aux_data(const string &key) { 00605 MutexHolder holder(_lock); 00606 _aux_data.erase(key); 00607 } 00608 00609 //////////////////////////////////////////////////////////////////// 00610 // Function: Texture::get_aux_data 00611 // Access: Published 00612 // Description: Returns a record previously recorded via 00613 // set_aux_data(). Returns NULL if there was no record 00614 // associated with the indicated key. 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 // Function: Texture::read_txo 00629 // Access: Published 00630 // Description: Reads the texture from a Panda texture object. This 00631 // defines the complete Texture specification, including 00632 // the image data as well as all texture properties. 00633 // This only works if the txo file contains a static 00634 // Texture image, as opposed to a subclass of Texture 00635 // such as a movie texture. 00636 // 00637 // Pass a real filename if it is available, or empty 00638 // string if it is not. 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 // Function: Texture::make_from_txo 00650 // Access: Published, Static 00651 // Description: Constructs a new Texture object from the txo file. 00652 // This is similar to Texture::read_txo(), but it 00653 // constructs and returns a new object, which allows it 00654 // to return a subclass of Texture (for instance, a 00655 // movie texture). 00656 // 00657 // Pass a real filename if it is available, or empty 00658 // string if it is not. 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 // Here's a special case: if the first object in the file is a 00693 // BamCacheRecord, it's really a cache data file and not a true 00694 // txo file; but skip over the cache data record and let the user 00695 // treat it like an ordinary txo file. 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 // Function: Texture::write_txo 00723 // Access: Published 00724 // Description: Writes the texture to a Panda texture object. This 00725 // defines the complete Texture specification, including 00726 // the image data as well as all texture properties. 00727 // 00728 // The filename is just for reference. 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 // Function: Texture::read_dds 00738 // Access: Published 00739 // Description: Reads the texture from a DDS file object. This is a 00740 // Microsoft-defined file format; it is similar in 00741 // principle to a txo object, in that it is designed to 00742 // contain the texture image in a form as similar as 00743 // possible to its runtime image, and it can contain 00744 // mipmaps, pre-compressed textures, and so on. 00745 // 00746 // As with read_txo, the filename is just for reference. 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 // Function: Texture::load_related 00758 // Access: Published 00759 // Description: Loads a texture whose filename is derived by 00760 // concatenating a suffix to the filename of this 00761 // texture. May return NULL, for example, if this 00762 // texture doesn't have a filename. 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 // The alpha variant of the filename, with the suffix, exists. 00788 // Use it to load the texture. 00789 res = TexturePool::load_texture(main, alph, 00790 cdata->_primary_file_num_channels, 00791 cdata->_alpha_file_channel, false); 00792 } else { 00793 // If the alpha variant of the filename doesn't exist, just go 00794 // ahead and load the related texture without alpha. 00795 res = TexturePool::load_texture(main); 00796 } 00797 00798 } else { 00799 // No alpha filename--just load the single file. It doesn't 00800 // necessarily have the same number of channels as this one. 00801 res = TexturePool::load_texture(main); 00802 } 00803 00804 // I'm casting away the const-ness of 'this' because this 00805 // field is only a cache. 00806 ((Texture *)this)->_related_textures.insert(RelatedTextures::value_type(suffix, res)); 00807 return res; 00808 } 00809 00810 //////////////////////////////////////////////////////////////////// 00811 // Function: Texture::get_effective_minfilter 00812 // Access: Published 00813 // Description: Returns the filter mode of the texture for 00814 // minification, with special treatment for FT_default. 00815 // This will normally not return FT_default, unless 00816 // there is an error in the config file. 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 // Function: Texture::get_effective_magfilter 00833 // Access: Published 00834 // Description: Returns the filter mode of the texture for 00835 // magnification, with special treatment for FT_default. 00836 // This will normally not return FT_default, unless 00837 // there is an error in the config file. 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 // Function: Texture::set_ram_image_as 00854 // Access: Published 00855 // Description: Replaces the current system-RAM image with the new 00856 // data, converting it first if necessary from the 00857 // indicated component-order format. See 00858 // get_ram_image_as() for specifications about the 00859 // format. This method cannot support compressed image 00860 // data or sub-pages; use set_ram_image() for that. 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 // Make sure we can grab something that's uncompressed. 00869 int imgsize = cdata->_x_size * cdata->_y_size; 00870 nassertv(image.size() == (size_t)(cdata->_component_width * format.size() * imgsize)); 00871 00872 // Check if the format is already what we have internally. 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 // The format string is already our format, so we just need to copy it. 00878 do_set_ram_image(cdata, image); 00879 return; 00880 } 00881 00882 // Create a new empty array that can hold our image. 00883 PTA_uchar newdata = PTA_uchar::empty_array(imgsize * cdata->_num_components * cdata->_component_width, get_class_type()); 00884 00885 // These ifs are for optimization of commonly used image types. 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 // We can generally rely on alpha to be the last component. 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 // Ignore. 00931 } else if (format.at(s) == '1') { 00932 // Ignore. 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 // Ignore. 00960 } else if (format.at(s) == '1') { 00961 // Ignore. 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 // Function: Texture::get_keep_ram_image 00980 // Access: Published, Virtual 00981 // Description: Returns the flag that indicates whether this Texture 00982 // is eligible to have its main RAM copy of the texture 00983 // memory dumped when the texture is prepared for 00984 // rendering. See set_keep_ram_image(). 00985 //////////////////////////////////////////////////////////////////// 00986 bool Texture:: 00987 get_keep_ram_image() const { 00988 CDReader cdata(_cycler); 00989 return cdata->_keep_ram_image; 00990 } 00991 00992 //////////////////////////////////////////////////////////////////// 00993 // Function: Texture::is_cacheable 00994 // Access: Published, Virtual 00995 // Description: Returns true if there is enough information in this 00996 // Texture object to write it to the bam cache 00997 // successfully, false otherwise. For most textures, 00998 // this is the same as has_ram_image(). 00999 //////////////////////////////////////////////////////////////////// 01000 bool Texture:: 01001 is_cacheable() const { 01002 CDReader cdata(_cycler); 01003 return do_has_bam_rawdata(cdata); 01004 } 01005 01006 //////////////////////////////////////////////////////////////////// 01007 // Function: Texture::get_num_loadable_ram_mipmap_images 01008 // Access: Published 01009 // Description: Returns the number of contiguous mipmap levels that 01010 // exist in RAM, up until the first gap in the sequence. 01011 // It is guaranteed that at least mipmap levels [0, 01012 // get_num_ram_mipmap_images()) exist. 01013 // 01014 // The number returned will never exceed the number of 01015 // required mipmap images based on the size of the 01016 // texture and its filter mode. 01017 // 01018 // This method is different from 01019 // get_num_ram_mipmap_images() in that it returns only 01020 // the number of mipmap levels that can actually be 01021 // usefully loaded, regardless of the actual number that 01022 // may be stored. 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 // If we don't even have a base image, the answer is none. 01029 return 0; 01030 } 01031 if (!uses_mipmaps()) { 01032 // If we have a base image and don't require mipmapping, the 01033 // answer is 1. 01034 return 1; 01035 } 01036 01037 // Check that we have enough mipmap levels to meet the size 01038 // requirements. 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 // Function: Texture::get_ram_mipmap_image 01056 // Access: Published 01057 // Description: Returns the system-RAM image data associated with the 01058 // nth mipmap level, if present. Returns NULL if the 01059 // nth mipmap level is not present. 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 // Function: Texture::get_ram_mipmap_pointer 01072 // Access: Published 01073 // Description: Similiar to get_ram_mipmap_image(), however, in this 01074 // case the void pointer for the given ram image is 01075 // returned. This will be NULL unless it has been 01076 // explicitly set. 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 // Function: Texture::set_ram_mipmap_pointer 01089 // Access: Published 01090 // Description: Sets an explicit void pointer as the texture's mipmap 01091 // image for the indicated level. This is a special 01092 // call to direct a texture to reference some external 01093 // image location, for instance from a webcam input. 01094 // 01095 // The texture will henceforth reference this pointer 01096 // directly, instead of its own internal storage; the 01097 // user is responsible for ensuring the data at this 01098 // address remains allocated and valid, and in the 01099 // correct format, during the lifetime of the texture. 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 //_ram_images[n]._image.clear(); wtf is going on?! 01112 cdata->_ram_images[n]._pointer_image = image; 01113 ++(cdata->_image_modified); 01114 } 01115 01116 //////////////////////////////////////////////////////////////////// 01117 // Function: Texture::set_ram_mipmap_pointer_from_int 01118 // Access: Published 01119 // Description: Accepts a raw pointer cast as an int, which is then 01120 // passed to set_ram_mipmap_pointer(); see the 01121 // documentation for that method. 01122 // 01123 // This variant is particularly useful to set an 01124 // external pointer from a language like Python, which 01125 // doesn't support void pointers directly. 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 // Function: Texture::clear_ram_mipmap_image 01134 // Access: Published 01135 // Description: Discards the current system-RAM image for the nth 01136 // mipmap level. 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 // Function: Texture::modify_simple_ram_image 01151 // Access: Published 01152 // Description: Returns a modifiable pointer to the internal "simple" 01153 // texture image. See set_simple_ram_image(). 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 // Function: Texture::new_simple_ram_image 01164 // Access: Published 01165 // Description: Creates an empty array for the simple ram image of 01166 // the indicated size, and returns a modifiable pointer 01167 // to the new array. See set_simple_ram_image(). 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 // Function: Texture::generate_simple_ram_image 01187 // Access: Published 01188 // Description: Computes the "simple" ram image by loading the main 01189 // RAM image, if it is not already available, and 01190 // reducing it to 16x16 or smaller. This may be an 01191 // expensive operation. 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 // Start at the suggested size from the config file. 01208 int x_size = simple_image_size.get_word(0); 01209 int y_size = simple_image_size.get_word(1); 01210 01211 // Limit it to no larger than the source image, and also make it a 01212 // power of two. 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 // Generate a reduced image of that size. 01217 PNMImage scaled(x_size, y_size, pnmimage.get_num_channels()); 01218 scaled.quick_filter_from(pnmimage); 01219 01220 // Make sure the reduced image has 4 components, by convention. 01221 if (!scaled.has_alpha()) { 01222 scaled.add_alpha(); 01223 scaled.alpha_fill(1.0); 01224 } 01225 scaled.set_num_channels(4); 01226 01227 // Now see if we can go even smaller. 01228 bool did_anything; 01229 do { 01230 did_anything = false; 01231 01232 // Try to reduce X. 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 // Try to reduce Y. 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 // Function: Texture::peek 01273 // Access: Published 01274 // Description: Returns a TexturePeeker object that can be used to 01275 // examine the individual texels stored within this 01276 // Texture by (u, v) coordinate. 01277 // 01278 // If the texture has a ram image resident, that image 01279 // is used. If it does not have a full ram image but 01280 // does have a simple_ram_image resident, that image is 01281 // used instead. If neither image is resident the full 01282 // image is reloaded. 01283 // 01284 // Returns NULL if the texture cannot find an image to 01285 // load, or the texture format is incompatible. 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 // Function: Texture::prepare 01301 // Access: Published 01302 // Description: Indicates that the texture should be enqueued to be 01303 // prepared in the indicated prepared_objects at the 01304 // beginning of the next frame. This will ensure the 01305 // texture is already loaded into texture memory if it 01306 // is expected to be rendered soon. 01307 // 01308 // Use this function instead of prepare_now() to preload 01309 // textures from a user interface standpoint. 01310 //////////////////////////////////////////////////////////////////// 01311 void Texture:: 01312 prepare(PreparedGraphicsObjects *prepared_objects) { 01313 prepared_objects->enqueue_texture(this); 01314 } 01315 01316 //////////////////////////////////////////////////////////////////// 01317 // Function: Texture::is_prepared 01318 // Access: Published 01319 // Description: Returns true if the texture has already been prepared 01320 // or enqueued for preparation on the indicated GSG, 01321 // false otherwise. 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 // Function: Texture::was_image_modified 01336 // Access: Published 01337 // Description: Returns true if the texture needs to be re-loaded 01338 // onto the indicated GSG, either because its image data 01339 // is out-of-date, or because it's not fully prepared 01340 // now. 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 // Function: Texture::get_data_size_bytes 01369 // Access: Public 01370 // Description: Returns the number of bytes which the texture is 01371 // reported to consume within graphics memory, for the 01372 // indicated GSG. This may return a nonzero value even 01373 // if the texture is not currently resident; you should 01374 // also check get_resident() if you want to know how 01375 // much space the texture is actually consuming right 01376 // now. 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 // Function: Texture::get_active 01403 // Access: Public 01404 // Description: Returns true if this Texture was rendered in the most 01405 // recent frame within the indicated GSG. 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 // Function: Texture::get_resident 01432 // Access: Public 01433 // Description: Returns true if this Texture is reported to be 01434 // resident within graphics memory for the indicated 01435 // GSG. 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 // Function: Texture::release 01462 // Access: Published 01463 // Description: Frees the texture context only on the indicated object, 01464 // if it exists there. Returns true if it was released, 01465 // false if it had not been prepared. 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 // Maybe it wasn't prepared yet, but it's about to be. 01486 return prepared_objects->dequeue_texture(this); 01487 } 01488 01489 //////////////////////////////////////////////////////////////////// 01490 // Function: Texture::release_all 01491 // Access: Published 01492 // Description: Frees the context allocated on all objects for which 01493 // the texture has been declared. Returns the number of 01494 // contexts which have been freed. 01495 //////////////////////////////////////////////////////////////////// 01496 int Texture:: 01497 release_all() { 01498 MutexHolder holder(_lock); 01499 01500 // We have to traverse a copy of the _prepared_views list, because the 01501 // PreparedGraphicsObjects object will call clear_prepared() in response 01502 // to each release_texture(), and we don't want to be modifying the 01503 // _prepared_views list while we're traversing it. 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 // Function: Texture::write 01527 // Access: Published 01528 // Description: Not to be confused with write(Filename), this method 01529 // simply describes the texture properties. 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 // Stop at the first gap. 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 // Function: Texture::set_size_padded 01746 // Access: Published 01747 // Description: Changes the size of the texture, padding 01748 // if necessary, and setting the pad region 01749 // as well. 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 // Function: Texture::set_orig_file_size 01771 // Access: Published 01772 // Description: Specifies the size of the texture as it exists in its 01773 // original disk file, before any Panda scaling. 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 // Function: Texture::is_mipmap 01786 // Access: Published, Static 01787 // Description: Returns true if the indicated filter type requires 01788 // the use of mipmaps, or false if it does not. 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 // Function: Texture::prepare_now 01806 // Access: Published 01807 // Description: Creates a context for the texture on the particular 01808 // GSG, if it does not already exist. Returns the new 01809 // (or old) TextureContext. This assumes that the 01810 // GraphicsStateGuardian is the currently active 01811 // rendering context and that it is ready to accept new 01812 // textures. If this is not necessarily the case, you 01813 // should use prepare() instead. 01814 // 01815 // Normally, this is not called directly except by the 01816 // GraphicsStateGuardian; a texture does not need to be 01817 // explicitly prepared by the user before it may be 01818 // rendered. 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 // Don't exceed the actual number of views. 01828 view = max(min(view, cdata->_num_views - 1), 0); 01829 01830 // Get the list of PreparedGraphicsObjects for this view. 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 // Function: Texture::up_to_power_2 01846 // Access: Published, Static 01847 // Description: Returns the smallest power of 2 greater than or equal 01848 // to value. 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 // Function: Texture::down_to_power_2 01861 // Access: Published, Static 01862 // Description: Returns the largest power of 2 less than or equal 01863 // to value. 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 // Function: Texture::consider_rescale 01876 // Access: Published 01877 // Description: Asks the PNMImage to change its scale when it reads 01878 // the image, according to the whims of the Config.prc 01879 // file. 01880 // 01881 // This method should be called after 01882 // pnmimage.read_header() has been called, but before 01883 // pnmimage.read(). Also see rescale_texture(). 01884 //////////////////////////////////////////////////////////////////// 01885 void Texture:: 01886 consider_rescale(PNMImage &pnmimage) { 01887 consider_rescale(pnmimage, get_name(), get_auto_texture_scale()); 01888 } 01889 01890 //////////////////////////////////////////////////////////////////// 01891 // Function: Texture::consider_rescale 01892 // Access: Published, Static 01893 // Description: Asks the PNMImage to change its scale when it reads 01894 // the image, according to the whims of the Config.prc 01895 // file. 01896 // 01897 // This method should be called after 01898 // pnmimage.read_header() has been called, but before 01899 // pnmimage.read(). Also see rescale_texture(). 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 // Function: Texture::format_texture_type 01912 // Access: Published, Static 01913 // Description: Returns the indicated TextureType converted to a 01914 // string word. 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 // Function: Texture::string_texture_type 01935 // Access: Published, Static 01936 // Description: Returns the TextureType corresponding to the 01937 // indicated string word. 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 // Function: Texture::format_component_type 01960 // Access: Published, Static 01961 // Description: Returns the indicated ComponentType converted to a 01962 // string word. 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 // Function: Texture::string_component_type 01982 // Access: Published, Static 01983 // Description: Returns the ComponentType corresponding to the 01984 // indicated string word. 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 // Function: Texture::format_format 02005 // Access: Published, Static 02006 // Description: Returns the indicated Format converted to a 02007 // string word. 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 // Function: Texture::string_format 02070 // Access: Published, Static 02071 // Description: Returns the Format corresponding to the 02072 // indicated string word. 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 // Function: Texture::format_filter_type 02137 // Access: Published, Static 02138 // Description: Returns the indicated FilterType converted to a 02139 // string word. 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 // Function: Texture::string_filter_type 02172 // Access: Public 02173 // Description: Returns the FilterType value associated with the given 02174 // string representation, or FT_invalid if the string 02175 // does not match any known FilterType value. 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 // Function: Texture::format_wrap_mode 02204 // Access: Published, Static 02205 // Description: Returns the indicated WrapMode converted to a 02206 // string word. 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 // Function: Texture::string_wrap_mode 02231 // Access: Public 02232 // Description: Returns the WrapMode value associated with the given 02233 // string representation, or WM_invalid if the string 02234 // does not match any known WrapMode value. 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 // Function: Texture::format_compression_mode 02258 // Access: Published, Static 02259 // Description: Returns the indicated CompressionMode converted to a 02260 // string word. 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 // Function: Texture::string_compression_mode 02294 // Access: Public 02295 // Description: Returns the CompressionMode value associated with the 02296 // given string representation. 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 // Function: Texture::format_quality_level 02332 // Access: Published, Static 02333 // Description: Returns the indicated QualityLevel converted to a 02334 // string word. 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 // Function: Texture::string_quality_level 02354 // Access: Public 02355 // Description: Returns the QualityLevel value associated with the 02356 // given string representation. 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 // Function: Texture::texture_uploaded 02377 // Access: Public 02378 // Description: This method is called by the GraphicsEngine at the 02379 // beginning of the frame *after* a texture has been 02380 // successfully uploaded to graphics memory. It is 02381 // intended as a callback so the texture can release its 02382 // RAM image, if _keep_ram_image is false. 02383 // 02384 // This is called indirectly when the GSG calls 02385 // GraphicsEngine::texture_uploaded(). 02386 //////////////////////////////////////////////////////////////////// 02387 void Texture:: 02388 texture_uploaded() { 02389 CDLockedReader cdata(_cycler); 02390 02391 if (!keep_texture_ram && !cdata->_keep_ram_image) { 02392 // Once we have prepared the texture, we can generally safely 02393 // remove the pixels from main RAM. The GSG is now responsible 02394 // for remembering what it looks like. 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 // Function: Texture::has_cull_callback 02407 // Access: Public, Virtual 02408 // Description: Should be overridden by derived classes to return 02409 // true if cull_callback() has been defined. Otherwise, 02410 // returns false to indicate cull_callback() does not 02411 // need to be called for this node during the cull 02412 // traversal. 02413 //////////////////////////////////////////////////////////////////// 02414 bool Texture:: 02415 has_cull_callback() const { 02416 return false; 02417 } 02418 02419 //////////////////////////////////////////////////////////////////// 02420 // Function: Texture::cull_callback 02421 // Access: Public, Virtual 02422 // Description: If has_cull_callback() returns true, this function 02423 // will be called during the cull traversal to perform 02424 // any additional operations that should be performed at 02425 // cull time. 02426 // 02427 // This is called each time the Texture is discovered 02428 // applied to a Geom in the traversal. It should return 02429 // true if the Geom is visible, false if it should be 02430 // omitted. 02431 //////////////////////////////////////////////////////////////////// 02432 bool Texture:: 02433 cull_callback(CullTraverser *, const CullTraverserData &) const { 02434 return true; 02435 } 02436 02437 //////////////////////////////////////////////////////////////////// 02438 // Function: Texture::make_texture 02439 // Access: Public, Static 02440 // Description: A factory function to make a new Texture, used to 02441 // pass to the TexturePool. 02442 //////////////////////////////////////////////////////////////////// 02443 PT(Texture) Texture:: 02444 make_texture() { 02445 return new Texture; 02446 } 02447 02448 //////////////////////////////////////////////////////////////////// 02449 // Function: Texture::is_specific 02450 // Access: Public, Static 02451 // Description: Returns true if the indicated compression mode is one 02452 // of the specific compression types, false otherwise. 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 // Function: Texture::has_alpha 02469 // Access: Public, Static 02470 // Description: Returns true if the indicated format includes alpha, 02471 // false otherwise. 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 // Function: Texture::has_binary_alpha 02496 // Access: Public, Static 02497 // Description: Returns true if the indicated format includes a 02498 // binary alpha only, false otherwise. 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 // Function: Texture::adjust_size 02513 // Access: Public, Static 02514 // Description: Computes the proper size of the texture, based on the 02515 // original size, the filename, and the resizing whims 02516 // of the config file. 02517 // 02518 // x_size and y_size should be loaded with the texture 02519 // image's original size on disk. On return, they will 02520 // be loaded with the texture's in-memory target size. 02521 // The return value is true if the size has been 02522 // adjusted, or false if it is the same. 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 // Don't auto-scale below 4 in either dimension. This causes 02544 // problems for DirectX and texture compression. 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 = textures_power_2; 02552 } 02553 if (!for_padding && ats == ATS_pad) { 02554 // If we're not calculating the padding size--that is, we're 02555 // calculating the initial scaling size instead--then ignore 02556 // ATS_pad, and treat it the same as ATS_none. 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 // Function: Texture::reconsider_dirty 02623 // Access: Protected, Virtual 02624 // Description: Called by TextureContext to give the Texture a chance 02625 // to mark itself dirty before rendering, if necessary. 02626 //////////////////////////////////////////////////////////////////// 02627 void Texture:: 02628 reconsider_dirty() { 02629 } 02630 02631 //////////////////////////////////////////////////////////////////// 02632 // Function: Texture::do_adjust_this_size 02633 // Access: Protected, Virtual 02634 // Description: Works like adjust_size, but also considers the 02635 // texture class. Movie textures, for instance, always 02636 // pad outwards, regardless of textures-power-2. 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 // Function: Texture::do_read 02646 // Access: Protected, Virtual 02647 // Description: The internal implementation of the various read() 02648 // methods. 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 // When we re-read the page 0 of the base image, we clear 02668 // everything and start over. 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 // If read_pages or read_mipmaps is specified, then z and n actually 02687 // indicate z_size and n_size, respectively--the numerical limits on 02688 // which to search for filenames. 02689 int z_size = z; 02690 int n_size = n; 02691 02692 // Certain texture types have an implicit z_size. If z_size is 02693 // omitted, choose an appropriate default based on the texture 02694 // type. 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 // We'll be loading a multiview texture. 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 // Read a sequence of pages * mipmap levels. 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 // For mipmap level 0, the total number of pages might be 02732 // determined by the number of files we find. After mipmap 02733 // level 0, though, the number of pages is predetermined. 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 // Continue through the loop. 02756 } else { 02757 // We've reached the end of the mipmap sequence. 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 // If n_size is not specified, it gets implicitly set after we 02777 // read the base texture image (which determines the size of 02778 // the texture). 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 // Read a sequence of cube map or 3-D texture pages. 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 // Read a sequence of mipmap levels. 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 // Don't try to read more than the requisite number of mipmap 02843 // levels (unless the user insisted on it for some reason). 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 // Just an ordinary read of one file. 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 // If we were only supposed to be checking the image header 02868 // information, don't let the Texture think that it's got the 02869 // image now. 02870 do_clear_ram_image(cdata); 02871 } else { 02872 if ((options.get_texture_flags() & LoaderOptions::TF_preload) != 0) { 02873 // If we intend to keep the ram image around, consider 02874 // compressing it etc. 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 // Function: Texture::do_read_one 02885 // Access: Protected, Virtual 02886 // Description: Called only from do_read(), this method reads a 02887 // single image file, either one page or one mipmap 02888 // level. 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 // In this mode, we never intend to load the actual texture 02915 // image anyway, so we don't even need to make the size right. 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 // The first time we set the filename via a read() operation, we 03021 // clear keep_ram_image. The user can always set it again later 03022 // if he needs to. 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 // The grayscale (alpha channel) image must be the same size as 03032 // the main image. This should really have been already 03033 // guaranteed by the above. 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 // Make the original image a 4-component image by taking the 03059 // grayscale value from the second image. 03060 image.add_alpha(); 03061 03062 if (alpha_file_channel == 4 || 03063 (alpha_file_channel == 2 && alpha_image.get_num_channels() == 2)) { 03064 // Use the alpha channel. 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 // Use the appropriate red, green, or blue channel. 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 // Use the grayscale channel. 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 // Now see if we want to pad the image within a larger power-of-2 03094 // image. 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 // Function: Texture::do_load_one 03120 // Access: Protected, Virtual 03121 // Description: Internal method to load a single page or mipmap 03122 // level. 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 // A special case for mipmap level 0. When we load mipmap level 03129 // 0, unless we already have mipmap levels, it determines the 03130 // image properties like size and number of components. 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 // Ensure the PNMImage is an appropriate size. 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 // Now copy the pixel data from the PNMImage into our internal 03182 // cdata->_image component. 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 // Function: Texture::do_read_txo_file 03194 // Access: Protected 03195 // Description: Called internally when read() detects a txo file. 03196 // Assumes the lock is already held. 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 // No such file. 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 // Function: Texture::do_read_txo 03229 // Access: Protected 03230 // Description: 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 // Function: Texture::do_read_dds_file 03253 // Access: Private 03254 // Description: Called internally when read() detects a DDS file. 03255 // Assumes the lock is already held. 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 // No such file. 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 // Function: Texture::do_read_dds 03292 // Access: Protected 03293 // Description: 03294 //////////////////////////////////////////////////////////////////// 03295 bool Texture:: 03296 do_read_dds(CData *cdata, istream &in, const string &filename, bool header_only) { 03297 StreamReader dds(in); 03298 03299 // DDS header (19 words) 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 // Pixelformat (8 words) 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 // Caps (4 words) 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 // Pad out to 32 words 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 // No bit set means only the base mipmap level. 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 // Determine the function to use to read the DDS image. 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 // Some compressed texture format. 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) { // 'DXT1', little-endian. 03385 compression = CM_dxt1; 03386 func = read_dds_level_dxt1; 03387 } else if (header.pf.four_cc == 0x32545844) { // 'DXT2' 03388 compression = CM_dxt2; 03389 func = read_dds_level_dxt23; 03390 } else if (header.pf.four_cc == 0x33545844) { // 'DXT3' 03391 compression = CM_dxt3; 03392 func = read_dds_level_dxt23; 03393 } else if (header.pf.four_cc == 0x34545844) { // 'DXT4' 03394 compression = CM_dxt4; 03395 func = read_dds_level_dxt45; 03396 } else if (header.pf.four_cc == 0x35545844) { // 'DXT5' 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 // All of the compressed formats support alpha, even DXT1 (to some 03406 // extent, at least). 03407 format = F_rgba; 03408 03409 } else { 03410 // An uncompressed texture format. 03411 func = read_dds_level_generic_uncompressed; 03412 03413 if (header.pf.pf_flags & DDPF_ALPHAPIXELS) { 03414 // An uncompressed format that involves alpha. 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 // An uncompressed format that doesn't involve alpha. 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 // 3-d textures store all the depth slices for mipmap level 0, 03471 // then all the depth slices for mipmap level 1, and so on. 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 // Now reassemble the pages into one big image. Because 03487 // this is a Microsoft format, the images are stacked in 03488 // reverse order; re-reverse them. 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 // Cube maps store all the mipmap levels for face 0, then all 03504 // the mipmap levels for face 1, and so on. 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 // Now, for each level, reassemble the pages into one big 03523 // image. Because this is a Microsoft format, the levels are 03524 // arranged in a rotated order. 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 // Normal 2-d textures simply store the mipmap levels. 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 // Function: Texture::do_write 03574 // Access: Protected 03575 // Description: Internal method to write a series of pages and/or 03576 // mipmap levels to disk files. 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 // Write a sequence of pages * mipmap levels. 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 // Write a sequence of pages. 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 // Write a sequence of mipmap images. 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 // Write a single file. 03656 if (!do_write_one(cdata, fullpath, z, n)) { 03657 return false; 03658 } 03659 } 03660 03661 return true; 03662 } 03663 03664 //////////////////////////////////////////////////////////////////// 03665 // Function: Texture::do_write_one 03666 // Access: Protected 03667 // Description: Internal method to write the indicated page and 03668 // mipmap level to a disk image file. 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 // Function: Texture::do_store_one 03693 // Access: Protected 03694 // Description: Internal method to copy a page and/or mipmap level to 03695 // a PNMImage. 03696 //////////////////////////////////////////////////////////////////// 03697 bool Texture:: 03698 do_store_one(CData *cdata, PNMImage &pnmimage, int z, int n) { 03699 // First, reload the ram image if necessary. 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 // Function: Texture::do_write_txo_file 03719 // Access: Private 03720 // Description: Called internally when write() detects a txo 03721 // filename. 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 // Function: Texture::do_write_txo 03741 // Access: Protected 03742 // Description: 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 // Function: Texture::unlocked_ensure_ram_image 03782 // Access: Protected, Virtual 03783 // Description: If the texture has a ram image already, this acquires 03784 // the CData write lock and returns it. 03785 // 03786 // If the texture lacks a ram image, this performs 03787 // do_reload_ram_image(), but without holding the lock 03788 // on this particular Texture object, to avoid holding 03789 // the lock across what might be a slow operation. 03790 // Instead, the reload is performed in a copy of the 03791 // texture object, and then the lock is acquired and the 03792 // data is copied in. 03793 // 03794 // In any case, the return value is a locked CData 03795 // object, which must be released with an explicit call 03796 // to release_write(). The CData object will have a ram 03797 // image unless for some reason do_reload_ram_image() 03798 // fails. 03799 //////////////////////////////////////////////////////////////////// 03800 Texture::CData *Texture:: 03801 unlocked_ensure_ram_image(bool allow_compression) { 03802 Thread *current_thread = Thread::get_current_thread(); 03803 03804 // First, wait for any other threads that might be simultaneously 03805 // performing the same operation. 03806 MutexHolder holder(_lock); 03807 while (_reloading) { 03808 _cvar.wait(); 03809 } 03810 03811 // Then make sure we still need to reload before continuing. 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 // If we don't want compression, but the ram image we have is 03816 // pre-compressed, we don't consider it. 03817 has_ram_image = false; 03818 } 03819 if (has_ram_image || !do_can_reload(cdata)) { 03820 // We don't need to reload after all, or maybe we can't reload 03821 // anyway. Return, but elevate the lock first, as we promised. 03822 return _cycler.elevate_read_upstream(cdata, false, current_thread); 03823 } 03824 03825 // We need to reload. 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 // Perform the actual reload in a copy of the texture, while our 03834 // own mutex is left unlocked. 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 // Rather than calling do_assign(), which would copy *all* of the 03843 // reloaded texture's properties over, we only copy in the ones 03844 // which are relevant to the ram image. This way, if the 03845 // properties have changed during the reload (for instance, 03846 // because we reloaded a txo), it won't contaminate the original 03847 // texture. 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 // If any of *these* properties have changed, the texture has 03852 // changed in some fundamental way. Update it appropriately. 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 // We don't generally increment the cdata->_image_modified semaphore, 03885 // because this is just a reload, and presumably the image hasn't 03886 // changed (unless we hit the if condition above). 03887 03888 _cvar.notify_all(); 03889 03890 // Return the still-locked cdata. 03891 return cdataw; 03892 } 03893 03894 //////////////////////////////////////////////////////////////////// 03895 // Function: Texture::do_reload_ram_image 03896 // Access: Protected, Virtual 03897 // Description: Called when the Texture image is required but the ram 03898 // image is not available, this will reload it from disk 03899 // or otherwise do whatever is required to make it 03900 // available, if possible. 03901 // 03902 // Assumes the lock is already held. The lock will be 03903 // held during the duration of this operation. 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 // See if the texture can be found in the on-disk cache, if it is 03916 // active. 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 // But don't use the cache record if the config parameters have 03924 // changed, and we want a different-sized texture now. 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 // Also don't keep the cached version if it's compressed but 03938 // we want uncompressed. 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 // We don't want to replace all the texture parameters--for 03949 // instance, we don't want to change the filter type or the 03950 // border color or anything--we just want to get the image and 03951 // necessary associated parameters. 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 // We've re-compressed the image after loading it from the 03971 // cache. To keep the cache current, rewrite it to the 03972 // cache now, in its newly compressed form. 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 // Restore the original format, in case it was needlessly changed 04009 // during the reload operation. 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 // Update the cache. 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 // Function: Texture::do_modify_ram_image 04027 // Access: Protected 04028 // Description: This is called internally to uniquify the ram image 04029 // pointer without updating cdata->_image_modified. 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 // Function: Texture::do_make_ram_image 04044 // Access: Protected 04045 // Description: This is called internally to make a new ram image 04046 // without updating cdata->_image_modified. 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 // Function: Texture::do_set_ram_image 04061 // Access: Protected 04062 // Description: Replaces the current system-RAM image with the new 04063 // data. If compression is not CM_off, it indicates 04064 // that the new data is already pre-compressed in the 04065 // indicated format. 04066 // 04067 // This does *not* affect keep_ram_image. 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 // Function: Texture::do_modify_ram_mipmap_image 04095 // Access: Protected 04096 // Description: This is called internally to uniquify the nth mipmap 04097 // image pointer without updating cdata->_image_modified. 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 // Function: Texture::do_make_ram_mipmap_image 04112 // Access: Protected 04113 // Description: 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 // Function: Texture::do_set_ram_mipmap_image 04131 // Access: Published 04132 // Description: 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 // Function: Texture::consider_auto_process_ram_image 04156 // Access: Protected 04157 // Description: Should be called after a texture has been loaded into 04158 // RAM, this considers generating mipmaps and/or 04159 // compressing the RAM image. 04160 // 04161 // Returns true if the image was modified by this 04162 // operation, false if it wasn't. 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 // Function: Texture::do_consider_auto_process_ram_image 04172 // Access: Protected 04173 // Description: Should be called after a texture has been loaded into 04174 // RAM, this considers generating mipmaps and/or 04175 // compressing the RAM image. 04176 // 04177 // Returns true if the image was modified by this 04178 // operation, false if it wasn't. 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 // Function: Texture::do_compress_ram_image 04214 // Access: Protected 04215 // Description: 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 // Select an appropriate compression mode automatically. 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 // Choose an appropriate quality level. 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 // This compression mode is supported by squish; use it. 04297 switch (quality_level) { 04298 case QL_fastest: 04299 squish_flags |= squish::kColourRangeFit; 04300 break; 04301 04302 case QL_normal: 04303 // ColourClusterFit is just too slow for everyday use. 04304 squish_flags |= squish::kColourRangeFit; 04305 // squish_flags |= squish::kColourClusterFit; 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 // Function: Texture::do_uncompress_ram_image 04328 // Access: Protected 04329 // Description: 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 // This compression mode is supported by squish; use it. 04358 if (do_unsquish(cdata, squish_flags)) { 04359 return true; 04360 } 04361 } 04362 } 04363 #endif // HAVE_SQUISH 04364 return false; 04365 } 04366 04367 //////////////////////////////////////////////////////////////////// 04368 // Function: Texture::do_has_all_ram_mipmap_images 04369 // Access: Protected 04370 // Description: 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 // If we don't even have a base image, the answer is no. 04376 return false; 04377 } 04378 if (!uses_mipmaps()) { 04379 // If we have a base image and don't require mipmapping, the 04380 // answer is yes. 04381 return true; 04382 } 04383 04384 // Check that we have enough mipmap levels to meet the size 04385 // requirements. 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 // Function: Texture::do_reconsider_z_size 04402 // Access: Protected 04403 // Description: Considers whether the z_size (or num_views) should 04404 // automatically be adjusted when the user loads a new 04405 // page. Returns true if the z size is valid, false 04406 // otherwise. 04407 // 04408 // Assumes the lock is already held. 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 // This flag is false if is a multiview texture with a specified 04416 // number of views. It is true if it is not a multiview 04417 // texture, or if it is but the number of views is explicitly 04418 // specified. 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 // If we're loading a page past _z_size, treat it as an implicit 04426 // request to enlarge _z_size. However, this is only legal if 04427 // this is, in fact, a 3-d texture or a 2d texture array (cube maps 04428 // always have z_size 6, and other types have z_size 1). 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 // In the case of a 2-d texture or cube map, or a 3-d texture 04434 // with an unspecified _num_views, assume we're loading views of 04435 // a multiview texture. 04436 cdata->_num_views = (z / cdata->_z_size) + 1; 04437 04438 } else { 04439 // The first image loaded sets an implicit z-size. 04440 cdata->_z_size = 1; 04441 } 04442 04443 // Increase the size of the data buffer to make room for the new 04444 // texture level. 04445 do_allocate_pages(cdata); 04446 } 04447 04448 return true; 04449 } 04450 04451 //////////////////////////////////////////////////////////////////// 04452 // Function: Texture::do_allocate_pages 04453 // Access: Protected, Virtual 04454 // Description: Called internally by do_reconsider_z_size() to 04455 // allocate new memory in _ram_images[0] for the new 04456 // number of pages. 04457 // 04458 // Assumes the lock is already held. 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 // Function: Texture::do_reconsider_image_properties 04473 // Access: Protected 04474 // Description: Resets the internal Texture properties when a new 04475 // image file is loaded. Returns true if the new image 04476 // is valid, false otherwise. 04477 // 04478 // Assumes the lock is already held. 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 // Come up with a default format based on the number of channels. 04486 // But only do this the first time the file is loaded, or if the 04487 // number of channels in the image changes on subsequent loads. 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 // Eh? 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 // If we're loading an Nx1 size texture, infer a 1-d texture type. 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 // Function: Texture::do_rescale_texture 04552 // Access: Private 04553 // Description: 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 // OK, we have to scale the image. 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 // Maybe we should pad the image. 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 // No changes needed. 04622 return false; 04623 } 04624 04625 //////////////////////////////////////////////////////////////////// 04626 // Function: Texture::make_copy_impl 04627 // Access: Protected, Virtual 04628 // Description: 04629 //////////////////////////////////////////////////////////////////// 04630 PT(Texture) Texture:: 04631 make_copy_impl() const { 04632 CDReader cdata(_cycler); 04633 return do_make_copy(cdata); 04634 } 04635 04636 //////////////////////////////////////////////////////////////////// 04637 // Function: Texture::do_make_copy 04638 // Access: Protected 04639 // Description: 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 // Function: Texture::do_assign 04651 // Access: Protected 04652 // Description: The internal implementation of operator =(). Assumes 04653 // the lock is already held on both Textures. 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 // Function: Texture::do_clear 04662 // Access: Protected, Virtual 04663 // Description: The protected implementation of clear(). Assumes the 04664 // lock is already held. 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 // Function: Texture::do_setup_texture 04680 // Access: Protected 04681 // Description: 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 // Cube maps must always consist of six square images. 04704 nassertv(x_size == y_size && z_size == 6); 04705 04706 // In principle the wrap mode shouldn't mean anything to a cube 04707 // map, but some drivers seem to misbehave if it's other than 04708 // WM_clamp. 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 // Function: Texture::do_set_format 04739 // Access: Protected 04740 // Description: 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 // Function: Texture::do_set_component_type 04793 // Access: Protected 04794 // Description: 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 //FIXME: I have no idea... 04815 break; 04816 } 04817 } 04818 04819 //////////////////////////////////////////////////////////////////// 04820 // Function: Texture::do_set_x_size 04821 // Access: Protected 04822 // Description: 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 // Function: Texture::do_set_y_size 04836 // Access: Protected 04837 // Description: 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 // Function: Texture::do_set_z_size 04852 // Access: Protected 04853 // Description: Changes the z size indicated for the texture. This 04854 // also implicitly unloads the texture if it has already 04855 // been loaded. 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 // Function: Texture::do_set_num_views 04872 // Access: Protected 04873 // Description: 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 // Function: Texture::do_set_wrap_u 04888 // Access: Protected 04889 // Description: 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 // Function: Texture::do_set_wrap_v 04901 // Access: Protected 04902 // Description: 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 // Function: Texture::do_set_wrap_w 04914 // Access: Protected 04915 // Description: 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 // Function: Texture::do_set_minfilter 04927 // Access: Protected 04928 // Description: 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 // Function: Texture::do_set_magfilter 04940 // Access: Protected 04941 // Description: 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 // Function: Texture::do_set_anisotropic_degree 04953 // Access: Protected 04954 // Description: 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 // Function: Texture::do_set_border_color 04966 // Access: Protected 04967 // Description: 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 // Function: Texture::do_set_compression 04979 // Access: Protected 04980 // Description: 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 // Reload if we're turning compression on or off, or if we're 04994 // changing the compression mode to a different kind of 04995 // compression. 04996 do_reload(cdata); 04997 } 04998 } 04999 } 05000 } 05001 05002 //////////////////////////////////////////////////////////////////// 05003 // Function: Texture::do_set_quality_level 05004 // Access: Public 05005 // Description: 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 // Function: Texture::do_has_compression 05017 // Access: Protected 05018 // Description: 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 // Function: Texture::do_has_ram_image 05031 // Access: Protected, Virtual 05032 // Description: The protected implementation of has_ram_image(). 05033 // Assumes the lock is already held. 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 // Function: Texture::do_has_uncompressed_ram_image 05042 // Access: Protected, Virtual 05043 // Description: The protected implementation of 05044 // has_uncompressed_ram_image(). Assumes the lock is 05045 // already held. 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 // Function: Texture::do_get_ram_image 05054 // Access: Protected 05055 // Description: 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 // Normally, we don't update the cdata->_modified semaphores in a do_blah 05063 // method, but we'll make an exception in this case, because it's 05064 // easiest to modify these here, and only when we know it's 05065 // needed. 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 // Function: Texture::do_get_uncompressed_ram_image 05079 // Access: Protected 05080 // Description: 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 // We have an image in-ram, but it's compressed. Try to 05086 // uncompress it first. 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 // Couldn't uncompress the existing image. Try to reload it. 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 // Great, now we have an image. 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 // Function: Texture::get_ram_image_as 05119 // Access: Published 05120 // Description: Returns the uncompressed system-RAM image data 05121 // associated with the texture. Rather than 05122 // just returning a pointer to the data, like 05123 // get_uncompressed_ram_image, this function first 05124 // processes the data and reorders the components 05125 // using the specified format string, and places these 05126 // into a new char array. The 'format' argument should 05127 // specify in which order the components of the texture 05128 // must be. For example, valid format strings are 05129 // "RGBA", "GA", "ABRG" or "AAA". A component can 05130 // also be written as "0" or "1", which means an 05131 // empty/black or a full/white channel, respectively. 05132 // This function is particularly useful to 05133 // copy an image in-memory to a different library 05134 // (for example, PIL or wxWidgets) that require 05135 // a different component order than Panda's internal 05136 // format, BGRA. Note, however, that this conversion 05137 // can still be too slow if you want to do it every 05138 // frame, and should thus be avoided for that purpose. 05139 // The only requirement for the reordering is that 05140 // an uncompressed image must be available. If the 05141 // RAM image is compressed, it will attempt to re-load 05142 // the texture from disk, if it doesn't find an 05143 // uncompressed image there, it will return NULL. 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 // Make sure we can grab something that's uncompressed. 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 // Check if the format is already what we have internally. 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 // The format string is already our format, so we just need to copy it. 05166 return CPTA_uchar(data); 05167 } 05168 05169 // Create a new empty array that can hold our image. 05170 PTA_uchar newdata = PTA_uchar::empty_array(imgsize * format.size() * cdata->_component_width, get_class_type()); 05171 05172 // These ifs are for optimization of commonly used image types. 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 // We can generally rely on alpha to be the last component. 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 // Function: Texture::do_set_simple_ram_image 05262 // Access: Protected 05263 // Description: 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 // Function: Texture::do_get_expected_num_mipmap_levels 05281 // Access: Protected 05282 // Description: 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 // Function: Texture::do_get_ram_mipmap_page_size 05297 // Access: Protected 05298 // Description: 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 // Function: Texture::do_get_expected_mipmap_x_size 05314 // Access: Protected 05315 // Description: 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 // Function: Texture::do_get_expected_mipmap_y_size 05329 // Access: Protected 05330 // Description: 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 // Function: Texture::do_get_expected_mipmap_z_size 05344 // Access: Protected 05345 // Description: 05346 //////////////////////////////////////////////////////////////////// 05347 int Texture:: 05348 do_get_expected_mipmap_z_size(const CData *cdata, int n) const { 05349 // 3-D textures have a different number of pages per each mipmap 05350 // level. Other kinds of textures--especially, cube map 05351 // textures--always have the same. 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 // Function: Texture::do_clear_simple_ram_image 05367 // Access: Protected 05368 // Description: 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 // We allow this exception: we update the _simple_image_modified 05379 // here, since no one really cares much about that anyway, and it's 05380 // convenient to do it here. 05381 ++(cdata->_simple_image_modified); 05382 } 05383 05384 //////////////////////////////////////////////////////////////////// 05385 // Function: Texture::do_clear_ram_mipmap_images 05386 // Access: Protected 05387 // Description: 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 // Function: Texture::do_generate_ram_mipmap_images 05398 // Access: Protected 05399 // Description: 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 // Don't bother. 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 // The RAM image is compressed. This means we need to uncompress 05415 // it in order to generate mipmap images. Save the original 05416 // first, to avoid lossy recompression. 05417 orig_compressed_image = cdata->_ram_images[0]; 05418 orig_compression_mode = cdata->_ram_image_compression; 05419 05420 // Now try to get the uncompressed source image. 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 // Eek, a 3-D texture. 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 // A 1-D, 2-D, or cube map texture. 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 // Now attempt to recompress the mipmap images according to the 05466 // original compression mode. We don't need to bother compressing 05467 // the first image (it was already compressed, after all), so 05468 // temporarily remove it from the top of the mipmap stack, and 05469 // compress all of the rest of them instead. 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 // Now restore the toplevel image. 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 // Function: Texture::do_set_pad_size 05495 // Access: Protected 05496 // Description: 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 // Function: Texture::do_can_reload 05517 // Access: Protected, Virtual 05518 // Description: Returns true if we can safely call 05519 // do_reload_ram_image() in order to make the image 05520 // available, or false if we shouldn't do this (because 05521 // we know from a priori knowledge that it wouldn't work 05522 // anyway). 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 // Function: Texture::do_reload 05531 // Access: Protected 05532 // Description: 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 // An explicit call to reload() should increment image_modified. 05541 ++(cdata->_image_modified); 05542 return true; 05543 } 05544 return false; 05545 } 05546 05547 // We don't have a filename to load from. 05548 return false; 05549 } 05550 05551 //////////////////////////////////////////////////////////////////// 05552 // Function: Texture::do_has_bam_rawdata 05553 // Access: Protected, Virtual 05554 // Description: Returns true if there is a rawdata image that we have 05555 // available to write to the bam stream. For a normal 05556 // Texture, this is the same thing as 05557 // do_has_ram_image(), but a movie texture might define 05558 // it differently. 05559 //////////////////////////////////////////////////////////////////// 05560 bool Texture:: 05561 do_has_bam_rawdata(const CData *cdata) const { 05562 return do_has_ram_image(cdata); 05563 } 05564 05565 //////////////////////////////////////////////////////////////////// 05566 // Function: Texture::do_get_bam_rawdata 05567 // Access: Protected, Virtual 05568 // Description: If do_has_bam_rawdata() returned false, this attempts 05569 // to reload the rawdata image if possible. 05570 //////////////////////////////////////////////////////////////////// 05571 void Texture:: 05572 do_get_bam_rawdata(CData *cdata) { 05573 do_get_ram_image(cdata); 05574 } 05575 05576 //////////////////////////////////////////////////////////////////// 05577 // Function: Texture::convert_from_pnmimage 05578 // Access: Private, Static 05579 // Description: Internal method to convert pixel data from the 05580 // indicated PNMImage into the given ram_image. 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 // Most common case: one byte per pixel, and the source image 05600 // shows a maxval of 255. No scaling is necessary. 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 // Another possible case: two bytes per pixel, and the source 05622 // image shows a maxval of 65535. Again, no scaling is necessary. 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 // A less common case: one byte per pixel, but the maxval is 05644 // something other than 255. In this case, we should scale the 05645 // pixel values up to the appropriate amount. 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 { // component_width == 2 05668 // Another uncommon case: two bytes per pixel, and the maxval is 05669 // something other than 65535. Again, we must scale the pixel 05670 // values. 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 // Function: Texture::convert_to_pnmimage 05698 // Access: Private, Static 05699 // Description: Internal method to convert pixel data to the 05700 // indicated PNMImage from the given ram_image. 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 // Function: Texture::read_dds_level_bgr8 05756 // Access: Private, Static 05757 // Description: Called by read_dds for a DDS file in BGR8 format. 05758 //////////////////////////////////////////////////////////////////// 05759 PTA_uchar Texture:: 05760 read_dds_level_bgr8(Texture *tex, CData *cdata, const DDSHeader &header, int n, istream &in) { 05761 // This is in order B, G, R. 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 // Function: Texture::read_dds_level_rgb8 05779 // Access: Private, Static 05780 // Description: Called by read_dds for a DDS file in RGB8 format. 05781 //////////////////////////////////////////////////////////////////// 05782 PTA_uchar Texture:: 05783 read_dds_level_rgb8(Texture *tex, CData *cdata, const DDSHeader &header, int n, istream &in) { 05784 // This is in order R, G, B. 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 // Now reverse the r, g, b triples. 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 // Function: Texture::read_dds_level_abgr8 05811 // Access: Private, Static 05812 // Description: Called by read_dds for a DDS file in ABGR8 format. 05813 //////////////////////////////////////////////////////////////////// 05814 PTA_uchar Texture:: 05815 read_dds_level_abgr8(Texture *tex, CData *cdata, const DDSHeader &header, int n, istream &in) { 05816 // This is laid out in order R, G, B, A. 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 // bigendian: convert R, G, B, A to B, G, R, A. 05832 w = ((w & 0xff00) << 16) | ((w & 0xff000000U) >> 16) | (w & 0xff00ff); 05833 #else 05834 // littendian: convert A, B, G, R to to A, R, G, B. 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 // Function: Texture::read_dds_level_rgba8 05848 // Access: Private, Static 05849 // Description: Called by read_dds for a DDS file in RGBA8 format. 05850 //////////////////////////////////////////////////////////////////// 05851 PTA_uchar Texture:: 05852 read_dds_level_rgba8(Texture *tex, CData *cdata, const DDSHeader &header, int n, istream &in) { 05853 // This is actually laid out in order B, G, R, A. 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 // Function: Texture::read_dds_level_generic_uncompressed 05871 // Access: Private, Static 05872 // Description: Called by read_dds for a DDS file whose format isn't 05873 // one we've specifically optimized. 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 // MS says the pitch can be supplied in the header file and must be 05884 // DWORD aligned, but this appears to apply to level 0 mipmaps only 05885 // (where it almost always will be anyway). Other mipmap levels 05886 // seem to be tightly packed, but there isn't a separate pitch for 05887 // each mipmap level. Weird. 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 // Determine the number of bits to shift each mask to the right so 05905 // that the lowest on bit is at bit 0. 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 // Then determine the scale factor required to raise the highest 05912 // color value to 0xff000000. 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 // Read a little-endian numeric value of bpp bytes. 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 // Then break apart that value into its R, G, B, and maybe A 05949 // components. 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 // Store the components in the Texture's image data. 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 // Function: Texture::read_dds_level_luminance_uncompressed 05974 // Access: Private, Static 05975 // Description: Called by read_dds for a DDS file in uncompressed 05976 // luminance or luminance-alpha format. 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 // MS says the pitch can be supplied in the header file and must be 05987 // DWORD aligned, but this appears to apply to level 0 mipmaps only 05988 // (where it almost always will be anyway). Other mipmap levels 05989 // seem to be tightly packed, but there isn't a separate pitch for 05990 // each mipmap level. Weird. 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 // Determine the number of bits to shift each mask to the right so 06006 // that the lowest on bit is at bit 0. 06007 int r_shift = get_lowest_on_bit(r_mask); 06008 int a_shift = get_lowest_on_bit(a_mask); 06009 06010 // Then determine the scale factor required to raise the highest 06011 // color value to 0xff000000. 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 // Read a little-endian numeric value of bpp bytes. 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 // Store the components in the Texture's image data. 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 // Function: Texture::read_dds_level_dxt1 06059 // Access: Private, Static 06060 // Description: Called by read_dds for DXT1 file format. 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 // The DXT1 image is divided into num_rows x num_cols blocks, where 06071 // each block represents 4x4 pixels. 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 // We have to flip the image as we read it, because of DirectX's 06087 // inverted sense of up. That means we (a) reverse the order of the 06088 // rows of blocks . . . 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 // . . . and (b) within each block, we reverse the 4 individual 06095 // rows of 4 pixels. 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 // To invert a two-pixel high image, we just flip two rows within a cell. 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 // No need to invert a one-pixel-high image. 06121 unsigned char *p = image.p(); 06122 in.read((char *)p, row_length); 06123 } 06124 06125 return image; 06126 } 06127 06128 //////////////////////////////////////////////////////////////////// 06129 // Function: Texture::read_dds_level_dxt23 06130 // Access: Private, Static 06131 // Description: Called by read_dds for DXT2 or DXT3 file format. 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 // The DXT3 image is divided into num_rows x num_cols blocks, where 06142 // each block represents 4x4 pixels. Unlike DXT1, each block 06143 // consists of two 8-byte chunks, representing the alpha and color 06144 // separately. 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 // We have to flip the image as we read it, because of DirectX's 06160 // inverted sense of up. That means we (a) reverse the order of the 06161 // rows of blocks . . . 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 // . . . and (b) within each block, we reverse the 4 individual 06168 // rows of 4 pixels. 06169 PN_uint32 *cells = (PN_uint32 *)p; 06170 06171 // Alpha. The block is four 16-bit words of pixel data. 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 // Color. Only the second 32-bit dword of the color block 06180 // represents the pixel data. 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 // To invert a two-pixel high image, we just flip two rows within a cell. 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 // No need to invert a one-pixel-high image. 06210 unsigned char *p = image.p(); 06211 in.read((char *)p, row_length); 06212 } 06213 06214 return image; 06215 } 06216 06217 //////////////////////////////////////////////////////////////////// 06218 // Function: Texture::read_dds_level_dxt45 06219 // Access: Private, Static 06220 // Description: Called by read_dds for DXT4 or DXT5 file format. 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 // The DXT5 image is similar to DXT3, in that there each 4x4 block 06231 // of pixels consists of an alpha block and a color block, but the 06232 // layout of the alpha block is different. 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 // We have to flip the image as we read it, because of DirectX's 06248 // inverted sense of up. That means we (a) reverse the order of the 06249 // rows of blocks . . . 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 // . . . and (b) within each block, we reverse the 4 individual 06256 // rows of 4 pixels. 06257 PN_uint32 *cells = (PN_uint32 *)p; 06258 06259 // Alpha. The block is one 16-bit word of reference values, 06260 // followed by six words of pixel values, in 12-bit rows. 06261 // Tricky to invert. 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 // Color. Only the second 32-bit dword of the color block 06277 // represents the pixel data. 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 // To invert a two-pixel high image, we just flip two rows within a cell. 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 // No need to invert a one-pixel-high image. 06315 unsigned char *p = image.p(); 06316 in.read((char *)p, row_length); 06317 } 06318 06319 return image; 06320 } 06321 06322 //////////////////////////////////////////////////////////////////// 06323 // Function: Texture::clear_prepared 06324 // Access: Private 06325 // Description: Removes the indicated PreparedGraphicsObjects table 06326 // from the Texture's table, without actually releasing 06327 // the texture. This is intended to be called only from 06328 // PreparedGraphicsObjects::release_texture(); it should 06329 // never be called by user code. 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 // Function: Texture::consider_downgrade 06351 // Access: Private, Static 06352 // Description: Reduces the number of channels in the texture, if 06353 // necessary, according to num_channels. 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 // One special case: we can't reduce from 3 to 2 components, since 06359 // that would require adding an alpha channel. 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 // Function: Texture::compare_images 06374 // Access: Private, Static 06375 // Description: Called by generate_simple_ram_image(), this compares 06376 // the two PNMImages pixel-by-pixel. If they're similar 06377 // enough (within a given threshold), returns true. 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 // Function: Texture::do_filter_2d_mipmap_pages 06402 // Access: Private 06403 // Description: Generates the next mipmap level from the previous 06404 // one. If there are multiple pages (e.g. a cube map), 06405 // generates each page independently. 06406 // 06407 // x_size and y_size are the size of the previous level. 06408 // They need not be a power of 2, or even a multiple of 06409 // 2. 06410 // 06411 // Assumes the lock is already held. 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 // For each level. 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 // For each row. 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 // For each pixel. 06446 for (int c = 0; c < cdata->_num_components; ++c) { 06447 // For each component. 06448 filter_component(p, q, pixel_size, row_size); 06449 } 06450 q += pixel_size; 06451 } 06452 if (x < x_size) { 06453 // Skip the last odd pixel. 06454 q += pixel_size; 06455 } 06456 } else { 06457 // Just one pixel. 06458 for (int c = 0; c < cdata->_num_components; ++c) { 06459 // For each component. 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 // Skip the last odd row. 06468 q += row_size; 06469 } 06470 } else { 06471 // Just one row. 06472 if (x_size != 1) { 06473 int x; 06474 for (x = 0; x < x_size - 1; x += 2) { 06475 // For each pixel. 06476 for (int c = 0; c < cdata->_num_components; ++c) { 06477 // For each component. 06478 filter_component(p, q, pixel_size, 0); 06479 } 06480 q += pixel_size; 06481 } 06482 if (x < x_size) { 06483 // Skip the last odd pixel. 06484 q += pixel_size; 06485 } 06486 } else { 06487 // Just one pixel. 06488 for (int c = 0; c < cdata->_num_components; ++c) { 06489 // For each component. 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 // Function: Texture::do_filter_3d_mipmap_level 06502 // Access: Private 06503 // Description: Generates the next mipmap level from the previous 06504 // one, treating all the pages of the level as a single 06505 // 3-d block of pixels. 06506 // 06507 // x_size, y_size, and z_size are the size of the 06508 // previous level. They need not be a power of 2, or 06509 // even a multiple of 2. 06510 // 06511 // Assumes the lock is already held. 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 // For each level. 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 // For each row. 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 // For each pixel. 06557 for (int c = 0; c < cdata->_num_components; ++c) { 06558 // For each component. 06559 filter_component(p, q, pixel_size, row_size, page_size); 06560 } 06561 q += pixel_size; 06562 } 06563 if (x < x_size) { 06564 // Skip the last odd pixel. 06565 q += pixel_size; 06566 } 06567 } else { 06568 // Just one pixel. 06569 for (int c = 0; c < cdata->_num_components; ++c) { 06570 // For each component. 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 // Skip the last odd row. 06579 q += row_size; 06580 } 06581 } else { 06582 // Just one row. 06583 if (x_size != 1) { 06584 int x; 06585 for (x = 0; x < x_size - 1; x += 2) { 06586 // For each pixel. 06587 for (int c = 0; c < cdata->_num_components; ++c) { 06588 // For each component. 06589 filter_component(p, q, pixel_size, 0, page_size); 06590 } 06591 q += pixel_size; 06592 } 06593 if (x < x_size) { 06594 // Skip the last odd pixel. 06595 q += pixel_size; 06596 } 06597 } else { 06598 // Just one pixel. 06599 for (int c = 0; c < cdata->_num_components; ++c) { 06600 // For each component. 06601 filter_component(p, q, 0, 0, page_size); 06602 } 06603 } 06604 } 06605 q += page_size; 06606 } 06607 if (z < z_size) { 06608 // Skip the last odd page. 06609 q += page_size; 06610 } 06611 } else { 06612 // Just one page. 06613 if (y_size != 1) { 06614 int y; 06615 for (y = 0; y < y_size - 1; y += 2) { 06616 // For each row. 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 // For each pixel. 06623 for (int c = 0; c < cdata->_num_components; ++c) { 06624 // For each component. 06625 filter_component(p, q, pixel_size, row_size, 0); 06626 } 06627 q += pixel_size; 06628 } 06629 if (x < x_size) { 06630 // Skip the last odd pixel. 06631 q += pixel_size; 06632 } 06633 } else { 06634 // Just one pixel. 06635 for (int c = 0; c < cdata->_num_components; ++c) { 06636 // For each component. 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 // Skip the last odd row. 06645 q += row_size; 06646 } 06647 } else { 06648 // Just one row. 06649 if (x_size != 1) { 06650 int x; 06651 for (x = 0; x < x_size - 1; x += 2) { 06652 // For each pixel. 06653 for (int c = 0; c < cdata->_num_components; ++c) { 06654 // For each component. 06655 filter_component(p, q, pixel_size, 0, 0); 06656 } 06657 q += pixel_size; 06658 } 06659 if (x < x_size) { 06660 // Skip the last odd pixel. 06661 q += pixel_size; 06662 } 06663 } else { 06664 // Just one pixel. 06665 for (int c = 0; c < cdata->_num_components; ++c) { 06666 // For each component. 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 // Function: Texture::filter_2d_unsigned_byte 06680 // Access: Public, Static 06681 // Description: Averages a 2x2 block of pixel components into a 06682 // single pixel component, for producing the next mipmap 06683 // level. Increments p and q to the next component. 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 // Function: Texture::filter_2d_unsigned_short 06699 // Access: Public, Static 06700 // Description: Averages a 2x2 block of pixel components into a 06701 // single pixel component, for producing the next mipmap 06702 // level. Increments p and q to the next component. 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 // Function: Texture::filter_3d_unsigned_byte 06717 // Access: Public, Static 06718 // Description: Averages a 2x2x2 block of pixel components into a 06719 // single pixel component, for producing the next mipmap 06720 // level. Increments p and q to the next component. 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 // Function: Texture::filter_3d_unsigned_short 06740 // Access: Public, Static 06741 // Description: Averages a 2x2x2 block of pixel components into a 06742 // single pixel component, for producing the next mipmap 06743 // level. Increments p and q to the next component. 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 // Function: Texture::do_squish 06763 // Access: Private 06764 // Description: Invokes the squish library to compress the RAM 06765 // image(s). 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 // If we're about to compress the RAM image, we should ensure that 06776 // we have all of the mipmap levels first. 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 // Convert one 4 x 4 cell at a time. 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]; // r 06811 t[1] = s[0]; // g 06812 t[2] = s[0]; // b 06813 t[3] = 255; // a 06814 break; 06815 06816 case 2: 06817 t[0] = s[0]; // r 06818 t[1] = s[0]; // g 06819 t[2] = s[0]; // b 06820 t[3] = s[1]; // a 06821 break; 06822 06823 case 3: 06824 t[0] = s[2]; // r 06825 t[1] = s[1]; // g 06826 t[2] = s[0]; // b 06827 t[3] = 255; // a 06828 break; 06829 06830 case 4: 06831 t[0] = s[2]; // r 06832 t[1] = s[1]; // g 06833 t[2] = s[0]; // b 06834 t[3] = s[3]; // a 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 // Function: Texture::do_unsquish 06861 // Access: Private 06862 // Description: Invokes the squish library to uncompress the RAM 06863 // image(s). 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 // Unconvert one 4 x 4 cell at a time. 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]; // g 06904 break; 06905 06906 case 2: 06907 d[0] = t[1]; // g 06908 d[1] = t[3]; // a 06909 break; 06910 06911 case 3: 06912 d[2] = t[0]; // r 06913 d[1] = t[1]; // g 06914 d[0] = t[2]; // b 06915 break; 06916 06917 case 4: 06918 d[2] = t[0]; // r 06919 d[1] = t[1]; // g 06920 d[0] = t[2]; // b 06921 d[3] = t[3]; // a 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 // Function: Texture::register_with_read_factory 06945 // Access: Public, Static 06946 // Description: Factory method to generate a Texture object 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 // Function: Texture::write_datagram 06955 // Access: Public, Virtual 06956 // Description: Function to write the important information in 06957 // the particular object to a Datagram 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 // If we are also including the texture's image data, then stuff it 06968 // in here. 06969 if (has_rawdata) { 06970 do_write_datagram_rawdata(cdata, manager, me); 06971 } 06972 } 06973 06974 //////////////////////////////////////////////////////////////////// 06975 // Function: Texture::finalize 06976 // Access: Public, Virtual 06977 // Description: Called by the BamReader to perform any final actions 06978 // needed for setting up the object after all objects 06979 // have been read and all pointers have been completed. 06980 //////////////////////////////////////////////////////////////////// 06981 void Texture:: 06982 finalize(BamReader *) { 06983 // Unref the pointer that we explicitly reffed in make_from_bam(). 06984 unref(); 06985 06986 // We should never get back to zero after unreffing our own count, 06987 // because we expect to have been stored in a pointer somewhere. If 06988 // we do get to zero, it's a memory leak; the way to avoid this is 06989 // to call unref_delete() above instead of unref(), but this is 06990 // dangerous to do from within a virtual function. 06991 nassertv(get_ref_count() != 0); 06992 } 06993 06994 06995 //////////////////////////////////////////////////////////////////// 06996 // Function: Texture::do_write_datagram_header 06997 // Access: Protected 06998 // Description: Writes the header part of the texture to the 06999 // Datagram. This is the common part that is shared by 07000 // all Texture subclasses, and contains the filename and 07001 // rawdata flags. This method is not virtual because 07002 // all Texture subclasses must write the same data at 07003 // this step. 07004 // 07005 // This part must be read first before calling 07006 // do_fillin_body() to determine whether to load the 07007 // Texture from the TexturePool or directly from the bam 07008 // stream. 07009 // 07010 // After this call, has_rawdata will be filled with 07011 // either true or false, according to whether we expect 07012 // to write the texture rawdata to the bam stream 07013 // following the texture body. 07014 //////////////////////////////////////////////////////////////////// 07015 void Texture:: 07016 do_write_datagram_header(CData *cdata, BamWriter *manager, Datagram &me, bool &has_rawdata) { 07017 // Write out the texture's raw pixel data if (a) the current Bam 07018 // Texture Mode requires that, or (b) there's no filename, so the 07019 // file can't be loaded up from disk, but the raw pixel data is 07020 // currently available in RAM. 07021 07022 // Otherwise, we just write out the filename, and assume whoever 07023 // loads the bam file later will have access to the image file on 07024 // disk. 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 // No image data after all. 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 // If we don't have a filename, we have to store rawdata anyway. 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 // Function: Texture::do_write_datagram_body 07101 // Access: Protected, Virtual 07102 // Description: Writes the body part of the texture to the 07103 // Datagram. This is generally all of the texture 07104 // parameters except for the header and the rawdata. 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 // Write out the simple image too, so it will be available later. 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 // Function: Texture::do_write_datagram_rawdata 07140 // Access: Protected, Virtual 07141 // Description: Writes the rawdata part of the texture to the 07142 // Datagram. 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 // Function: Texture::make_from_bam 07168 // Access: Protected, Static 07169 // Description: Factory method to generate a Texture object 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 // Function: Texture::make_this_from_bam 07179 // Access: Protected, Virtual 07180 // Description: Called by make_from_bam() once the particular 07181 // subclass of Texture is known. This is called on a 07182 // newly-constructed Texture object of the appropriate 07183 // subclass. It will return either the same Texture 07184 // object (e.g. this), or a different Texture object 07185 // loaded via the TexturePool, as appropriate. 07186 //////////////////////////////////////////////////////////////////// 07187 TypedWritable *Texture:: 07188 make_this_from_bam(const FactoryParams ¶ms) { 07189 // The process of making a texture is slightly different than making 07190 // other TypedWritable objects. That is because all creation of 07191 // Textures should be done through calls to TexturePool, which 07192 // ensures that any loads of the same filename refer to the same 07193 // memory. 07194 07195 DatagramIterator scan; 07196 BamReader *manager; 07197 07198 parse_params(params, scan, manager); 07199 07200 // Get the header information--the filenames and texture type--so we 07201 // can look up the file on disk first. 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 // Between Panda3D releases 1.7.2 and 1.8.0 (bam versions 6.24 and 07212 // 6.25), we added TT_2d_texture_array, shifting the definition 07213 // for TT_cube_map. 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 // If the raw image data is included, then just load the texture 07222 // directly from the stream, and return it. In this case we 07223 // return the "this" pointer, since it's a newly-created Texture 07224 // object of the appropriate type. 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 // Read the texture attributes directly from the bam stream. 07235 me->do_fillin_body(cdata_me, scan, manager); 07236 me->do_fillin_rawdata(cdata_me, scan, manager); 07237 07238 // To manage the reference count, explicitly ref it now, then 07239 // unref it in the finalize callback. 07240 me->ref(); 07241 manager->register_finalize(me); 07242 07243 } else { 07244 // The raw image data isn't included, so we'll be loading the 07245 // Texture via the TexturePool. In this case we use the "this" 07246 // pointer as a temporary object to read all of the attributes 07247 // from the bam stream. 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 // This texture has no filename; since we don't have an image to 07258 // load, we can't actually create the texture. 07259 gobj_cat.info() 07260 << "Cannot create texture '" << name << "' with no filename.\n"; 07261 07262 } else { 07263 // This texture does have a filename, so try to load it from disk. 07264 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); 07265 if (!manager->get_filename().empty()) { 07266 // If texture filename was given relative to the bam filename, 07267 // expand it now. 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 // Since in this case me was loaded from the TexturePool, 07315 // there's no need to explicitly manage the reference count. 07316 // TexturePool will hold it safely. 07317 } 07318 } 07319 07320 return me; 07321 } 07322 07323 //////////////////////////////////////////////////////////////////// 07324 // Function: Texture::do_fillin_body 07325 // Access: Protected, Virtual 07326 // Description: Reads in the part of the Texture that was written 07327 // with do_write_datagram_body(). 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 // Function: Texture::do_fillin_rawdata 07383 // Access: Protected, Virtual 07384 // Description: Reads in the part of the Texture that was written 07385 // with do_write_datagram_rawdata(). 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 // fill the cdata->_image buffer with image data 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 // Function: Texture::do_fillin_from 07441 // Access: Protected, Virtual 07442 // Description: Called in make_from_bam(), this method properly 07443 // copies the attributes from the bam stream (as stored 07444 // in dummy) into this texture, updating the modified 07445 // flags appropriately. 07446 //////////////////////////////////////////////////////////////////// 07447 void Texture:: 07448 do_fillin_from(CData *cdata, const Texture *dummy) { 07449 // Use the setters instead of setting these directly, so we can 07450 // correctly avoid incrementing cdata->_properties_modified if none of 07451 // these actually change. (Otherwise, we'd have to reload the 07452 // texture to the GSG every time we loaded a new bam file that 07453 // reference the texture, since each bam file reference passes 07454 // through this function.) 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 // Only reset the format if the number of components hasn't 07484 // changed, since if the number of components has changed our 07485 // texture no longer matches what it was when the bam was 07486 // written. 07487 do_set_format(cdata, format); 07488 } 07489 07490 if (!cdata_dummy->_simple_ram_image._image.empty()) { 07491 // Only replace the simple ram image if it was generated more 07492 // recently than the one we already have. 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 // Function: Texture::CData::Constructor 07506 // Access: Public 07507 // Description: 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 // We will override the format in a moment (in the Texture 07536 // constructor), but set it to something else first to avoid the 07537 // check in do_set_format depending on an uninitialized value. 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 // Function: Texture::CData::Copy Constructor 07560 // Access: Public 07561 // Description: 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 // Function: Texture::CData::make_copy 07576 // Access: Public, Virtual 07577 // Description: 07578 //////////////////////////////////////////////////////////////////// 07579 CycleData *Texture::CData:: 07580 make_copy() const { 07581 return new CData(*this); 07582 } 07583 07584 //////////////////////////////////////////////////////////////////// 07585 // Function: Texture::CData::do_assign 07586 // Access: Public 07587 // Description: 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 // Since the fullpath is often empty on a file loaded directly 07595 // from a txo, we only assign the fullpath if it is not empty. 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 // Function: Texture::CData::write_datagram 07641 // Access: Public, Virtual 07642 // Description: Writes the contents of this object to the datagram 07643 // for shipping out to a Bam file. 07644 //////////////////////////////////////////////////////////////////// 07645 void Texture::CData:: 07646 write_datagram(BamWriter *manager, Datagram &dg) const { 07647 } 07648 07649 //////////////////////////////////////////////////////////////////// 07650 // Function: Texture::CData::complete_pointers 07651 // Access: Public, Virtual 07652 // Description: Receives an array of pointers, one for each time 07653 // manager->read_pointer() was called in fillin(). 07654 // Returns the number of pointers processed. 07655 //////////////////////////////////////////////////////////////////// 07656 int Texture::CData:: 07657 complete_pointers(TypedWritable **p_list, BamReader *manager) { 07658 return 0; 07659 } 07660 07661 //////////////////////////////////////////////////////////////////// 07662 // Function: Texture::CData::fillin 07663 // Access: Public, Virtual 07664 // Description: This internal function is called by make_from_bam to 07665 // read in all of the relevant data from the BamFile for 07666 // the new Geom. 07667 //////////////////////////////////////////////////////////////////// 07668 void Texture::CData:: 07669 fillin(DatagramIterator &scan, BamReader *manager) { 07670 } 07671 07672 //////////////////////////////////////////////////////////////////// 07673 // Function: Texture::TextureType output operator 07674 // Description: 07675 //////////////////////////////////////////////////////////////////// 07676 ostream & 07677 operator << (ostream &out, Texture::TextureType tt) { 07678 return out << Texture::format_texture_type(tt); 07679 } 07680 07681 //////////////////////////////////////////////////////////////////// 07682 // Function: Texture::ComponentType output operator 07683 // Description: 07684 //////////////////////////////////////////////////////////////////// 07685 ostream & 07686 operator << (ostream &out, Texture::ComponentType ct) { 07687 return out << Texture::format_component_type(ct); 07688 } 07689 07690 //////////////////////////////////////////////////////////////////// 07691 // Function: Texture::Format output operator 07692 // Description: 07693 //////////////////////////////////////////////////////////////////// 07694 ostream & 07695 operator << (ostream &out, Texture::Format f) { 07696 return out << Texture::format_format(f); 07697 } 07698 07699 //////////////////////////////////////////////////////////////////// 07700 // Function: Texture::FilterType output operator 07701 // Description: 07702 //////////////////////////////////////////////////////////////////// 07703 ostream & 07704 operator << (ostream &out, Texture::FilterType ft) { 07705 return out << Texture::format_filter_type(ft); 07706 } 07707 07708 //////////////////////////////////////////////////////////////////// 07709 // Function: Texture::FilterType input operator 07710 // Description: 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 // Function: Texture::WrapMode output operator 07723 // Description: 07724 //////////////////////////////////////////////////////////////////// 07725 ostream & 07726 operator << (ostream &out, Texture::WrapMode wm) { 07727 return out << Texture::format_wrap_mode(wm); 07728 } 07729 07730 //////////////////////////////////////////////////////////////////// 07731 // Function: Texture::WrapMode input operator 07732 // Description: 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 // Function: Texture::CompressionMode output operator 07745 // Description: 07746 //////////////////////////////////////////////////////////////////// 07747 ostream & 07748 operator << (ostream &out, Texture::CompressionMode cm) { 07749 return out << Texture::format_compression_mode(cm); 07750 } 07751 07752 //////////////////////////////////////////////////////////////////// 07753 // Function: Texture::QualityLevel output operator 07754 // Description: 07755 //////////////////////////////////////////////////////////////////// 07756 ostream & 07757 operator << (ostream &out, Texture::QualityLevel tql) { 07758 return out << Texture::format_quality_level(tql); 07759 } 07760 07761 //////////////////////////////////////////////////////////////////// 07762 // Function: Texture::QualityLevel input operator 07763 // Description: 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 }