Panda3D
|
00001 // Filename: dxTextureContext8.cxx 00002 // Created by: georges (02Feb02) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "dxTextureContext8.h" 00016 #include "config_dxgsg8.h" 00017 #include "dxGraphicsStateGuardian8.h" 00018 #include "pStatTimer.h" 00019 #include "dxgsg8base.h" 00020 #include "bamCache.h" 00021 #include "graphicsEngine.h" 00022 00023 #include <assert.h> 00024 #include <time.h> 00025 00026 TypeHandle DXTextureContext8::_type_handle; 00027 00028 static const DWORD g_LowByteMask = 0x000000FF; 00029 00030 //////////////////////////////////////////////////////////////////// 00031 // Function: DXTextureContext8::Constructor 00032 // Access: Public 00033 // Description: 00034 //////////////////////////////////////////////////////////////////// 00035 DXTextureContext8:: 00036 DXTextureContext8(PreparedGraphicsObjects *pgo, Texture *tex, int view) : 00037 TextureContext(pgo, tex, view) { 00038 00039 if (dxgsg8_cat.is_spam()) { 00040 dxgsg8_cat.spam() 00041 << "Creating DX texture [" << tex->get_name() << "], minfilter(" << tex->get_minfilter() << "), magfilter(" << tex->get_magfilter() << "), anisodeg(" << tex->get_anisotropic_degree() << ")\n"; 00042 } 00043 00044 _d3d_texture = NULL; 00045 _d3d_2d_texture = NULL; 00046 _d3d_volume_texture = NULL; 00047 _d3d_cube_texture = NULL; 00048 _has_mipmaps = false; 00049 } 00050 00051 //////////////////////////////////////////////////////////////////// 00052 // Function: DXTextureContext8::Destructor 00053 // Access: Public, Virtual 00054 // Description: 00055 //////////////////////////////////////////////////////////////////// 00056 DXTextureContext8:: 00057 ~DXTextureContext8() { 00058 delete_texture(); 00059 } 00060 00061 //////////////////////////////////////////////////////////////////// 00062 // Function: DXTextureContext8::evict_lru 00063 // Access: Public, Virtual 00064 // Description: Evicts the page from the LRU. Called internally when 00065 // the LRU determines that it is full. May also be 00066 // called externally when necessary to explicitly evict 00067 // the page. 00068 // 00069 // It is legal for this method to either evict the page 00070 // as requested, do nothing (in which case the eviction 00071 // will be requested again at the next epoch), or 00072 // requeue itself on the tail of the queue (in which 00073 // case the eviction will be requested again much 00074 // later). 00075 //////////////////////////////////////////////////////////////////// 00076 void DXTextureContext8:: 00077 evict_lru() { 00078 if (get_texture()->get_render_to_texture()) { 00079 // Don't evict the result of render-to-texture. 00080 mark_used_lru(); 00081 return; 00082 } 00083 00084 dequeue_lru(); 00085 delete_texture(); 00086 update_data_size_bytes(0); 00087 mark_unloaded(); 00088 } 00089 00090 //////////////////////////////////////////////////////////////////// 00091 // Function: DXTextureContext8::create_texture 00092 // Access: Public 00093 // Description: Use panda texture's pixelbuffer to create a texture 00094 // for the specified device. This code gets the 00095 // attributes of the texture from the bitmap, creates 00096 // the texture, and then copies the bitmap into the 00097 // texture. The return value is true if the texture is 00098 // successfully created, false otherwise. 00099 //////////////////////////////////////////////////////////////////// 00100 bool DXTextureContext8:: 00101 create_texture(DXScreenData &scrn) { 00102 HRESULT hr; 00103 int num_alpha_bits; // number of alpha bits in texture pixfmt 00104 D3DFORMAT target_pixel_format = D3DFMT_UNKNOWN; 00105 bool needs_luminance = false; 00106 bool compress_texture = false; 00107 00108 Texture *tex = get_texture(); 00109 nassertr(IS_VALID_PTR(tex), false); 00110 00111 delete_texture(); 00112 00113 #ifdef DO_PSTATS 00114 update_data_size_bytes(tex->estimate_texture_memory()); 00115 #endif // DO_PSTATS 00116 00117 // bpp indicates requested fmt, not texture fmt 00118 DWORD target_bpp = get_bits_per_pixel(tex->get_format(), &num_alpha_bits); 00119 DWORD num_color_channels = tex->get_num_components(); 00120 00121 //PRINT_REFCNT(dxgsg8, scrn._d3d8); 00122 00123 DWORD orig_width = (DWORD)tex->get_x_size(); 00124 DWORD orig_height = (DWORD)tex->get_y_size(); 00125 DWORD orig_depth = (DWORD)tex->get_z_size(); 00126 00127 if ((tex->get_format() == Texture::F_luminance_alpha)|| 00128 (tex->get_format() == Texture::F_luminance_alphamask) || 00129 (tex->get_format() == Texture::F_luminance)) { 00130 needs_luminance = true; 00131 } 00132 00133 if (num_alpha_bits > 0) { 00134 if (num_color_channels == 3) { 00135 dxgsg8_cat.error() 00136 << "texture " << tex->get_name() 00137 << " has no inherent alpha channel, but alpha format is requested!\n"; 00138 } 00139 } 00140 00141 _d3d_format = D3DFMT_UNKNOWN; 00142 00143 // figure out what 'D3DFMT' the Texture is in, so D3DXLoadSurfFromMem knows how to perform copy 00144 00145 switch (num_color_channels) { 00146 case 1: 00147 if (num_alpha_bits > 0) { 00148 _d3d_format = D3DFMT_A8; 00149 } else if (needs_luminance) { 00150 _d3d_format = D3DFMT_L8; 00151 } 00152 break; 00153 case 2: 00154 nassertr(needs_luminance && (num_alpha_bits > 0), false); 00155 _d3d_format = D3DFMT_A8L8; 00156 break; 00157 case 3: 00158 _d3d_format = D3DFMT_R8G8B8; 00159 break; 00160 case 4: 00161 _d3d_format = D3DFMT_A8R8G8B8; 00162 break; 00163 } 00164 00165 // check for texture compression 00166 bool texture_wants_compressed = false; 00167 Texture::CompressionMode compression_mode = tex->get_ram_image_compression(); 00168 bool texture_stored_compressed = compression_mode != Texture::CM_off; 00169 00170 if (texture_stored_compressed) { 00171 texture_wants_compressed = true; 00172 } 00173 else { 00174 if (tex->get_compression() == Texture::CM_off) { 00175 // no compression 00176 } 00177 else { 00178 if (tex->get_compression() == Texture::CM_default) { 00179 // default = use "compressed-textures" config setting 00180 if (compressed_textures) { 00181 texture_wants_compressed = true; 00182 } 00183 } 00184 else { 00185 texture_wants_compressed = true; 00186 } 00187 } 00188 } 00189 00190 switch (tex->get_texture_type()) { 00191 case Texture::TT_1d_texture: 00192 case Texture::TT_2d_texture: 00193 case Texture::TT_cube_map: 00194 // no compression for render target textures, or very small 00195 // textures 00196 if (tex->get_render_to_texture() == false && 00197 orig_width >= 4 && orig_height >= 4) { 00198 if (texture_wants_compressed){ 00199 compress_texture = true; 00200 } 00201 } 00202 break; 00203 case Texture::TT_3d_texture: 00204 // not supported by all video chips 00205 break; 00206 } 00207 00208 // make sure we handled all the possible cases 00209 nassertr(_d3d_format != D3DFMT_UNKNOWN, false); 00210 00211 DWORD target_width = orig_width; 00212 DWORD target_height = orig_height; 00213 DWORD target_depth = orig_depth; 00214 00215 DWORD filter_caps; 00216 00217 switch (tex->get_texture_type()) { 00218 case Texture::TT_1d_texture: 00219 case Texture::TT_2d_texture: 00220 filter_caps = scrn._d3dcaps.TextureFilterCaps; 00221 00222 if (target_width > scrn._d3dcaps.MaxTextureWidth) { 00223 target_width = scrn._d3dcaps.MaxTextureWidth; 00224 } 00225 if (target_height > scrn._d3dcaps.MaxTextureHeight) { 00226 target_height = scrn._d3dcaps.MaxTextureHeight; 00227 } 00228 00229 if (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_POW2) { 00230 if (!ISPOW2(target_width)) { 00231 target_width = down_to_power_2(target_width); 00232 } 00233 if (!ISPOW2(target_height)) { 00234 target_height = down_to_power_2(target_height); 00235 } 00236 } 00237 break; 00238 00239 case Texture::TT_3d_texture: 00240 if ((scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP) == 0) { 00241 dxgsg8_cat.warning() 00242 << "3-d textures are not supported by this graphics driver.\n"; 00243 return false; 00244 } 00245 00246 filter_caps = scrn._d3dcaps.VolumeTextureFilterCaps; 00247 00248 if (target_width > scrn._d3dcaps.MaxVolumeExtent) { 00249 target_width = scrn._d3dcaps.MaxVolumeExtent; 00250 } 00251 if (target_height > scrn._d3dcaps.MaxVolumeExtent) { 00252 target_height = scrn._d3dcaps.MaxVolumeExtent; 00253 } 00254 if (target_depth > scrn._d3dcaps.MaxVolumeExtent) { 00255 target_depth = scrn._d3dcaps.MaxVolumeExtent; 00256 } 00257 00258 if (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP_POW2) { 00259 if (!ISPOW2(target_width)) { 00260 target_width = down_to_power_2(target_width); 00261 } 00262 if (!ISPOW2(target_height)) { 00263 target_height = down_to_power_2(target_height); 00264 } 00265 if (!ISPOW2(target_depth)) { 00266 target_depth = down_to_power_2(target_depth); 00267 } 00268 } 00269 break; 00270 00271 case Texture::TT_cube_map: 00272 if ((scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP) == 0) { 00273 dxgsg8_cat.warning() 00274 << "Cube map textures are not supported by this graphics driver.\n"; 00275 return false; 00276 } 00277 00278 filter_caps = scrn._d3dcaps.CubeTextureFilterCaps; 00279 00280 if (target_width > scrn._d3dcaps.MaxTextureWidth) { 00281 target_width = scrn._d3dcaps.MaxTextureWidth; 00282 } 00283 00284 if (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) { 00285 if (!ISPOW2(target_width)) { 00286 target_width = down_to_power_2(target_width); 00287 } 00288 } 00289 00290 target_height = target_width; 00291 break; 00292 } 00293 00294 // checks for SQUARE reqmt (nvidia riva128 needs this) 00295 if ((target_width != target_height) && 00296 (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY) != 0) { 00297 // assume pow2 textures. sum exponents, divide by 2 rounding down 00298 // to get sq size 00299 int i, width_exp, height_exp; 00300 for (i = target_width, width_exp = 0; i > 1; width_exp++, i >>= 1) { 00301 } 00302 for (i = target_height, height_exp = 0; i > 1; height_exp++, i >>= 1) { 00303 } 00304 target_height = target_width = 1<<((width_exp+height_exp)>>1); 00305 } 00306 00307 bool shrink_original = false; 00308 00309 if (orig_width != target_width || orig_height != target_height || 00310 orig_depth != target_depth) { 00311 if (tex->get_texture_type() == Texture::TT_3d_texture) { 00312 dxgsg8_cat.info() 00313 << "Reducing size of " << tex->get_name() 00314 << " from " << orig_width << "x" << orig_height << "x" << orig_depth 00315 << " to " << target_width << "x" << target_height 00316 << "x" << target_depth << "\n"; 00317 } else { 00318 dxgsg8_cat.info() 00319 << "Reducing size of " << tex->get_name() 00320 << " from " << orig_width << "x" << orig_height 00321 << " to " << target_width << "x" << target_height << "\n"; 00322 } 00323 00324 shrink_original = true; 00325 } 00326 00327 const char *error_message; 00328 00329 error_message = "create_texture failed: couldn't find compatible device Texture Pixel Format for input texture"; 00330 00331 if (dxgsg8_cat.is_spam()) { 00332 dxgsg8_cat.spam() 00333 << "create_texture handling target bitdepth: " << target_bpp 00334 << " alphabits: " << num_alpha_bits << endl; 00335 } 00336 00337 // I could possibly replace some of this logic with 00338 // D3DXCheckTextureRequirements(), but it wouldn't handle all my 00339 // specialized low-memory cases perfectly 00340 00341 #define CHECK_FOR_FMT(FMT) \ 00342 if (scrn._supported_tex_formats_mask & FMT##_FLAG) { \ 00343 target_pixel_format = D3DFMT_##FMT; \ 00344 goto found_matching_format; } 00345 00346 if (texture_stored_compressed && compress_texture) { 00347 // if the texture is already compressed, we need to choose the 00348 // corresponding format, otherwise we might end up 00349 // cross-compressing from e.g. DXT5 to DXT3 00350 switch (compression_mode){ 00351 case Texture::CM_dxt1: 00352 CHECK_FOR_FMT(DXT1); 00353 break; 00354 case Texture::CM_dxt2: 00355 CHECK_FOR_FMT(DXT2); 00356 break; 00357 case Texture::CM_dxt3: 00358 CHECK_FOR_FMT(DXT3); 00359 break; 00360 case Texture::CM_dxt4: 00361 CHECK_FOR_FMT(DXT4); 00362 break; 00363 case Texture::CM_dxt5: 00364 CHECK_FOR_FMT(DXT5); 00365 break; 00366 } 00367 00368 // We don't support the compressed format. Fall through. 00369 } 00370 00371 if (compress_texture) { 00372 if (num_alpha_bits <= 1) { 00373 CHECK_FOR_FMT(DXT1); 00374 } else if (num_alpha_bits <= 4) { 00375 CHECK_FOR_FMT(DXT3); 00376 } else { 00377 CHECK_FOR_FMT(DXT5); 00378 } 00379 } 00380 00381 // We can't compress for some reason, so ensure the uncompressed 00382 // image is ready to load. 00383 if (texture_stored_compressed) { 00384 tex->get_uncompressed_ram_image(); 00385 compression_mode = tex->get_ram_image_compression(); 00386 texture_stored_compressed = compression_mode != Texture::CM_off; 00387 compress_texture = false; 00388 } 00389 00390 // handle each target bitdepth separately. might be less confusing 00391 // to reorg by num_color_channels (input type) 00392 switch (target_bpp) { 00393 00394 // IMPORTANT NOTE: 00395 // target_bpp is REQUESTED bpp, not what exists in the texture 00396 // array (the texture array contains num_color_channels*8bits) 00397 00398 case 32: 00399 if (!((num_color_channels == 3) || (num_color_channels == 4))) 00400 break; //bail 00401 00402 CHECK_FOR_FMT(A8R8G8B8); 00403 00404 if (num_alpha_bits>0) { 00405 nassertr(num_color_channels == 4, false); 00406 00407 // no 32-bit fmt, look for 16 bit w/alpha (1-15) 00408 00409 // 32 bit RGBA was requested, but only 16 bit alpha fmts are 00410 // avail. By default, convert to 4-4-4-4 which has 4-bit alpha 00411 // for blurry edges. If we know tex only needs 1 bit alpha 00412 // (i.e. for a mask), use 1555 instead. 00413 00414 00415 // ConversionType ConvTo1 = Conv32to16_4444, ConvTo2 = Conv32to16_1555; 00416 // DWORD dwAlphaMask1 = 0xF000, dwAlphaMask2 = 0x8000; 00417 00418 // assume ALPHAMASK is x8000 and RGBMASK is x7fff to simplify 00419 // 32->16 conversion. This should be true on most cards. 00420 00421 if (num_alpha_bits == 1) { 00422 CHECK_FOR_FMT(A1R5G5B5); 00423 } 00424 00425 // normally prefer 4444 due to better alpha channel resolution 00426 CHECK_FOR_FMT(A4R4G4B4); 00427 CHECK_FOR_FMT(A1R5G5B5); 00428 00429 // At this point, bail. Don't worry about converting to 00430 // non-alpha formats yet, I think this will be a very rare case. 00431 error_message = "create_texture failed: couldn't find compatible Tex DDPIXELFORMAT! no available 16 or 32-bit alpha formats!"; 00432 } else { 00433 // convert 3 or 4 channel to closest 16bpp color fmt 00434 00435 if (num_color_channels == 3) { 00436 CHECK_FOR_FMT(R5G6B5); 00437 CHECK_FOR_FMT(X1R5G5B5); 00438 } else { 00439 CHECK_FOR_FMT(R5G6B5); 00440 CHECK_FOR_FMT(X1R5G5B5); 00441 } 00442 } 00443 break; 00444 00445 case 24: 00446 nassertr(num_color_channels == 3, false); 00447 00448 CHECK_FOR_FMT(R8G8B8); 00449 00450 // no 24-bit fmt. look for 32 bit fmt (note: this is 00451 // memory-hogging choice instead I could look for 00452 // memory-conserving 16-bit fmt). 00453 00454 CHECK_FOR_FMT(X8R8G8B8); 00455 CHECK_FOR_FMT(A8R8G8B8); 00456 00457 // no 24-bit or 32 fmt. look for 16 bit fmt (higher res 565 1st) 00458 CHECK_FOR_FMT(R5G6B5); 00459 CHECK_FOR_FMT(X1R5G5B5); 00460 CHECK_FOR_FMT(A1R5G5B5); 00461 break; 00462 00463 case 16: 00464 if (needs_luminance) { 00465 nassertr(num_alpha_bits > 0, false); 00466 nassertr(num_color_channels == 2, false); 00467 00468 CHECK_FOR_FMT(A8L8); 00469 CHECK_FOR_FMT(A8R8G8B8); 00470 00471 if (num_alpha_bits == 1) { 00472 CHECK_FOR_FMT(A1R5G5B5); 00473 } 00474 00475 // normally prefer 4444 due to better alpha channel resolution 00476 CHECK_FOR_FMT(A4R4G4B4); 00477 CHECK_FOR_FMT(A1R5G5B5); 00478 } else { 00479 nassertr((num_color_channels == 3)||(num_color_channels == 4), false); 00480 // look for compatible 16bit fmts, if none then give up 00481 // (don't worry about other bitdepths for 16 bit) 00482 switch(num_alpha_bits) { 00483 case 0: 00484 if (num_color_channels == 3) { 00485 CHECK_FOR_FMT(R5G6B5); 00486 CHECK_FOR_FMT(X1R5G5B5); 00487 } else { 00488 nassertr(num_color_channels == 4, false); 00489 // it could be 4 if user asks us to throw away the alpha channel 00490 CHECK_FOR_FMT(R5G6B5); 00491 CHECK_FOR_FMT(X1R5G5B5); 00492 } 00493 break; 00494 case 1: 00495 // app specifically requests 1-5-5-5 F_rgba5 case, where you 00496 // explicitly want 1-5-5-5 fmt, as opposed to F_rgbm, which 00497 // could use 32bpp ARGB. fail if this particular fmt not 00498 // avail. 00499 nassertr(num_color_channels == 4, false); 00500 CHECK_FOR_FMT(X1R5G5B5); 00501 break; 00502 case 4: 00503 // app specifically requests 4-4-4-4 F_rgba4 case, as opposed 00504 // to F_rgba, which could use 32bpp ARGB 00505 nassertr(num_color_channels == 4, false); 00506 CHECK_FOR_FMT(A4R4G4B4); 00507 break; 00508 default: 00509 nassertr(false, false); // problem in get_bits_per_pixel()? 00510 } 00511 } 00512 case 8: 00513 if (needs_luminance) { 00514 // don't bother handling those other 8bit lum fmts like 4-4, 00515 // since 16 8-8 is usually supported too 00516 nassertr(num_color_channels == 1, false); 00517 00518 // look for native lum fmt first 00519 CHECK_FOR_FMT(L8); 00520 CHECK_FOR_FMT(L8); 00521 00522 CHECK_FOR_FMT(R8G8B8); 00523 CHECK_FOR_FMT(X8R8G8B8); 00524 00525 CHECK_FOR_FMT(R5G6B5); 00526 CHECK_FOR_FMT(X1R5G5B5); 00527 00528 } else if (num_alpha_bits == 8) { 00529 // look for 16bpp A8L8, else 32-bit ARGB, else 16-4444. 00530 00531 // skip 8bit alpha only (D3DFMT_A8), because I think only voodoo 00532 // supports it and the voodoo support isn't the kind of blending 00533 // model we need somehow (is it that voodoo assumes color is 00534 // white? isnt that what we do in ConvAlpha8to32 anyway?) 00535 00536 CHECK_FOR_FMT(A8L8); 00537 CHECK_FOR_FMT(A8R8G8B8); 00538 CHECK_FOR_FMT(A4R4G4B4); 00539 } 00540 break; 00541 00542 default: 00543 error_message = "create_texture failed: unhandled pixel bitdepth in DX loader"; 00544 } 00545 00546 // if we've gotten here, haven't found a match 00547 dxgsg8_cat.error() 00548 << error_message << ": " << tex->get_name() << endl 00549 << "NumColorChannels: " << num_color_channels << "; NumAlphaBits: " 00550 << num_alpha_bits << "; targetbpp: " <<target_bpp 00551 << "; _supported_tex_formats_mask: 0x" 00552 << (void*)scrn._supported_tex_formats_mask 00553 << "; NeedLuminance: " << needs_luminance << endl; 00554 goto error_exit; 00555 00556 /////////////////////////////////////////////////////////// 00557 00558 found_matching_format: 00559 // We found a suitable format that matches the texture's format. 00560 00561 if (tex->get_match_framebuffer_format()) { 00562 // Instead of creating a texture with the found format, we will 00563 // need to make one that exactly matches the framebuffer's 00564 // format. Look up what that format is. 00565 IDirect3DSurface8 *render_target; 00566 hr = scrn._d3d_device->GetRenderTarget(&render_target); 00567 if (FAILED(hr)) { 00568 dxgsg8_cat.error() 00569 << "GetRenderTgt failed in create_texture: " << D3DERRORSTRING(hr); 00570 } else { 00571 D3DSURFACE_DESC surface_desc; 00572 hr = render_target->GetDesc(&surface_desc); 00573 if (FAILED(hr)) { 00574 dxgsg8_cat.error() 00575 << "GetDesc failed in create_texture: " << D3DERRORSTRING(hr); 00576 } else { 00577 if (target_pixel_format != surface_desc.Format) { 00578 if (dxgsg8_cat.is_debug()) { 00579 dxgsg8_cat.debug() 00580 << "Chose format " << D3DFormatStr(surface_desc.Format) 00581 << " instead of " << D3DFormatStr(target_pixel_format) 00582 << " for texture to match framebuffer.\n"; 00583 } 00584 target_pixel_format = surface_desc.Format; 00585 } 00586 } 00587 SAFE_RELEASE(render_target); 00588 } 00589 } 00590 00591 // validate magfilter setting 00592 // degrade filtering if no HW support 00593 00594 Texture::FilterType ft; 00595 00596 ft = tex->get_magfilter(); 00597 if ((ft != Texture::FT_linear) && ft != Texture::FT_nearest) { 00598 // mipmap settings make no sense for magfilter 00599 if (ft == Texture::FT_nearest_mipmap_nearest) { 00600 ft = Texture::FT_nearest; 00601 } else { 00602 ft = Texture::FT_linear; 00603 } 00604 } 00605 00606 if (ft == Texture::FT_linear && 00607 (filter_caps & D3DPTFILTERCAPS_MAGFLINEAR) == 0) { 00608 ft = Texture::FT_nearest; 00609 } 00610 tex->set_magfilter(ft); 00611 00612 // figure out if we are mipmapping this texture 00613 ft = tex->get_minfilter(); 00614 _has_mipmaps = false; 00615 00616 if (!dx_ignore_mipmaps) { // set if no HW mipmap capable 00617 switch(ft) { 00618 case Texture::FT_nearest_mipmap_nearest: 00619 case Texture::FT_linear_mipmap_nearest: 00620 case Texture::FT_nearest_mipmap_linear: // pick nearest in each, interpolate linearly b/w them 00621 case Texture::FT_linear_mipmap_linear: 00622 _has_mipmaps = true; 00623 } 00624 00625 if (dx_mipmap_everything) { // debug toggle, ok to leave in since its just a creation cost 00626 _has_mipmaps = true; 00627 if (dxgsg8_cat.is_spam()) { 00628 if (ft != Texture::FT_linear_mipmap_linear) { 00629 dxgsg8_cat.spam() 00630 << "Forcing trilinear mipmapping on DX texture [" 00631 << tex->get_name() << "]\n"; 00632 } 00633 } 00634 ft = Texture::FT_linear_mipmap_linear; 00635 tex->set_minfilter(ft); 00636 } 00637 00638 } else if ((ft == Texture::FT_nearest_mipmap_nearest) || // cvt to no-mipmap filter types 00639 (ft == Texture::FT_nearest_mipmap_linear)) { 00640 ft = Texture::FT_nearest; 00641 00642 } else if ((ft == Texture::FT_linear_mipmap_nearest) || 00643 (ft == Texture::FT_linear_mipmap_linear)) { 00644 ft = Texture::FT_linear; 00645 } 00646 00647 nassertr((filter_caps & D3DPTFILTERCAPS_MINFPOINT) != 0, false); 00648 00649 #define TRILINEAR_MIPMAP_TEXFILTERCAPS (D3DPTFILTERCAPS_MIPFLINEAR | D3DPTFILTERCAPS_MINFLINEAR) 00650 00651 // do any other filter type degradations necessary 00652 switch(ft) { 00653 case Texture::FT_linear_mipmap_linear: 00654 if ((filter_caps & TRILINEAR_MIPMAP_TEXFILTERCAPS) != TRILINEAR_MIPMAP_TEXFILTERCAPS) { 00655 if (filter_caps & D3DPTFILTERCAPS_MINFLINEAR) { 00656 ft = Texture::FT_linear_mipmap_nearest; 00657 } else { 00658 // if you cant do linear in a level, you probably cant do 00659 // linear b/w levels, so just do nearest-all 00660 ft = Texture::FT_nearest_mipmap_nearest; 00661 } 00662 } 00663 break; 00664 00665 case Texture::FT_nearest_mipmap_linear: 00666 // if we don't have bilinear, do nearest_nearest 00667 if (!((filter_caps & D3DPTFILTERCAPS_MIPFPOINT) && 00668 (filter_caps & D3DPTFILTERCAPS_MINFLINEAR))) { 00669 ft = Texture::FT_nearest_mipmap_nearest; 00670 } 00671 break; 00672 00673 case Texture::FT_linear_mipmap_nearest: 00674 // if we don't have mip linear, do nearest_nearest 00675 if (!(filter_caps & D3DPTFILTERCAPS_MIPFLINEAR)) { 00676 ft = Texture::FT_nearest_mipmap_nearest; 00677 } 00678 break; 00679 00680 case Texture::FT_linear: 00681 if (!(filter_caps & D3DPTFILTERCAPS_MINFLINEAR)) { 00682 ft = Texture::FT_nearest; 00683 } 00684 break; 00685 } 00686 00687 tex->set_minfilter(ft); 00688 00689 uint aniso_degree; 00690 00691 aniso_degree = 1; 00692 if (scrn._d3dcaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) { 00693 aniso_degree = tex->get_anisotropic_degree(); 00694 if ((aniso_degree>scrn._d3dcaps.MaxAnisotropy) || 00695 dx_force_anisotropic_filtering) { 00696 aniso_degree = scrn._d3dcaps.MaxAnisotropy; 00697 } 00698 } 00699 tex->set_anisotropic_degree(aniso_degree); 00700 00701 #ifdef _DEBUG 00702 dxgsg8_cat.spam() 00703 << "create_texture: setting aniso degree for " << tex->get_name() 00704 << " to: " << aniso_degree << endl; 00705 #endif 00706 00707 UINT mip_level_count; 00708 00709 if (_has_mipmaps) { 00710 tex->get_ram_image(); 00711 mip_level_count = tex->get_num_loadable_ram_mipmap_images(); 00712 if (mip_level_count < 2) { 00713 // tell CreateTex to alloc space for all mip levels down to 1x1 00714 mip_level_count = 0; 00715 00716 if (dxgsg8_cat.is_debug()) { 00717 dxgsg8_cat.debug() 00718 << "create_texture: generating mipmaps for " << tex->get_name() 00719 << endl; 00720 } 00721 } 00722 } else { 00723 mip_level_count = 1; 00724 } 00725 00726 DWORD usage; 00727 D3DPOOL pool; 00728 00729 usage = 0; 00730 if (tex->get_render_to_texture ()) { 00731 // REQUIRED 00732 pool = D3DPOOL_DEFAULT; 00733 if (support_render_texture && scrn._dxgsg8 -> get_supports_render_texture ( )) { 00734 usage |= D3DUSAGE_RENDERTARGET; 00735 } 00736 } 00737 else { 00738 pool = D3DPOOL_MANAGED; 00739 } 00740 00741 switch (tex->get_texture_type()) { 00742 case Texture::TT_1d_texture: 00743 case Texture::TT_2d_texture: 00744 hr = scrn._d3d_device->CreateTexture 00745 (target_width, target_height, mip_level_count, usage, 00746 target_pixel_format, pool, &_d3d_2d_texture); 00747 _d3d_texture = _d3d_2d_texture; 00748 break; 00749 00750 case Texture::TT_3d_texture: 00751 hr = scrn._d3d_device->CreateVolumeTexture 00752 (target_width, target_height, target_depth, mip_level_count, usage, 00753 target_pixel_format, pool, &_d3d_volume_texture); 00754 _d3d_texture = _d3d_volume_texture; 00755 break; 00756 00757 case Texture::TT_cube_map: 00758 hr = scrn._d3d_device->CreateCubeTexture 00759 (target_width, mip_level_count, usage, 00760 target_pixel_format, pool, &_d3d_cube_texture); 00761 _d3d_texture = _d3d_cube_texture; 00762 break; 00763 } 00764 00765 if (FAILED(hr)) { 00766 dxgsg8_cat.error() 00767 << "D3D create_texture failed!" << D3DERRORSTRING(hr); 00768 goto error_exit; 00769 } 00770 00771 if (dxgsg8_cat.is_debug()) { 00772 dxgsg8_cat.debug() 00773 << "create_texture: " << tex->get_name() 00774 << " converting panda equivalent of " << D3DFormatStr(_d3d_format) 00775 << " => " << D3DFormatStr(target_pixel_format) << endl; 00776 } 00777 00778 hr = fill_d3d_texture_pixels(scrn); 00779 if (FAILED(hr)) { 00780 goto error_exit; 00781 } 00782 00783 if (tex->get_post_load_store_cache()) { 00784 tex->set_post_load_store_cache(false); 00785 // OK, get the RAM image, and save it in a BamCache record. 00786 if (extract_texture_data()) { 00787 if (tex->has_ram_image()) { 00788 BamCache *cache = BamCache::get_global_ptr(); 00789 PT(BamCacheRecord) record = cache->lookup(tex->get_fullpath(), "txo"); 00790 if (record != (BamCacheRecord *)NULL) { 00791 record->set_data(tex, tex); 00792 cache->store(record); 00793 } 00794 } 00795 } 00796 } 00797 00798 scrn._dxgsg8->get_engine()->texture_uploaded(tex); 00799 mark_loaded(); 00800 return true; 00801 00802 error_exit: 00803 00804 RELEASE(_d3d_texture, dxgsg8, "texture", RELEASE_ONCE); 00805 _d3d_2d_texture = NULL; 00806 _d3d_volume_texture = NULL; 00807 _d3d_cube_texture = NULL; 00808 return false; 00809 } 00810 00811 //////////////////////////////////////////////////////////////////// 00812 // Function: DXTextureContext8::create_simple_texture 00813 // Access: Public 00814 // Description: 00815 //////////////////////////////////////////////////////////////////// 00816 bool DXTextureContext8:: 00817 create_simple_texture(DXScreenData &scrn) { 00818 nassertr(IS_VALID_PTR(get_texture()), false); 00819 00820 HRESULT hr; 00821 00822 delete_texture(); 00823 00824 _d3d_format = D3DFMT_A8R8G8B8; 00825 D3DFORMAT target_pixel_format = D3DFMT_A8R8G8B8; 00826 DWORD target_bpp = 32; 00827 DWORD num_color_channels = 4; 00828 00829 DWORD target_width = (DWORD)get_texture()->get_simple_x_size(); 00830 DWORD target_height = (DWORD)get_texture()->get_simple_y_size(); 00831 DWORD mip_level_count = 1; 00832 DWORD usage = 0; 00833 D3DPOOL pool = D3DPOOL_MANAGED; 00834 00835 int data_size = target_width * target_height * 4; 00836 00837 hr = scrn._d3d_device->CreateTexture 00838 (target_width, target_height, mip_level_count, usage, 00839 target_pixel_format, pool, &_d3d_2d_texture); 00840 _d3d_texture = _d3d_2d_texture; 00841 if (FAILED(hr)) { 00842 dxgsg8_cat.error() 00843 << "D3D create_simple_texture failed!" << D3DERRORSTRING(hr); 00844 dxgsg8_cat.error() 00845 << " width = " << target_width << " height = " << target_height << " target_pixel_format = " << target_pixel_format << "\n"; 00846 00847 goto error_exit; 00848 } 00849 00850 if (dxgsg8_cat.is_debug()) { 00851 dxgsg8_cat.debug() 00852 << "create_simple_texture: " << get_texture()->get_name() 00853 << "\n"; 00854 } 00855 00856 { 00857 CPTA_uchar image = get_texture()->get_simple_ram_image(); 00858 00859 hr = -1; 00860 // hr = fill_d3d_texture_pixels(scrn); 00861 00862 IDirect3DSurface8 *surface = NULL; 00863 _d3d_2d_texture->GetSurfaceLevel(0, &surface); 00864 00865 RECT source_size; 00866 source_size.left = source_size.top = 0; 00867 source_size.right = target_width; 00868 source_size.bottom = target_height; 00869 00870 DWORD mip_filter = D3DX_FILTER_LINEAR; 00871 00872 hr = D3DXLoadSurfaceFromMemory 00873 (surface, (PALETTEENTRY*)NULL, (RECT*)NULL, (LPCVOID)image.p(), 00874 target_pixel_format, target_width * 4, (PALETTEENTRY*)NULL, 00875 &source_size, mip_filter, (D3DCOLOR)0x0); 00876 00877 RELEASE(surface, dxgsg8, "create_simple_texture Surface", RELEASE_ONCE); 00878 } 00879 00880 if (FAILED(hr)) { 00881 dxgsg8_cat.debug () 00882 << "*** fill_d3d_texture_pixels failed ***: format " 00883 << target_pixel_format 00884 << "\n"; 00885 00886 goto error_exit; 00887 } 00888 00889 mark_simple_loaded(); 00890 return true; 00891 00892 error_exit: 00893 RELEASE(_d3d_texture, dxgsg8, "texture", RELEASE_ONCE); 00894 _d3d_2d_texture = NULL; 00895 _d3d_volume_texture = NULL; 00896 _d3d_cube_texture = NULL; 00897 return false; 00898 } 00899 00900 //////////////////////////////////////////////////////////////////// 00901 // Function: DXTextureContext8::delete_texture 00902 // Access: Public 00903 // Description: Release the surface used to store the texture 00904 //////////////////////////////////////////////////////////////////// 00905 void DXTextureContext8:: 00906 delete_texture() { 00907 if (_d3d_texture == NULL) { 00908 // don't bother printing the msg below, since we already released it. 00909 return; 00910 } 00911 00912 RELEASE(_d3d_texture, dxgsg8, "texture", RELEASE_ONCE); 00913 _d3d_2d_texture = NULL; 00914 _d3d_volume_texture = NULL; 00915 _d3d_cube_texture = NULL; 00916 } 00917 00918 //////////////////////////////////////////////////////////////////// 00919 // Function: DXTextureContext8::extract_texture_data 00920 // Access: Public 00921 // Description: This method will be called in the draw thread to 00922 // download the texture memory's image into its 00923 // ram_image value. It returns true on success, false 00924 // otherwise. 00925 //////////////////////////////////////////////////////////////////// 00926 bool DXTextureContext8:: 00927 extract_texture_data() { 00928 HRESULT hr; 00929 00930 Texture *tex = get_texture(); 00931 if (tex->get_texture_type() != Texture::TT_2d_texture) { 00932 dxgsg8_cat.error() 00933 << "Not supported: extract_texture_data for " << tex->get_texture_type() 00934 << "\n"; 00935 return false; 00936 } 00937 nassertr(IS_VALID_PTR(_d3d_2d_texture), false); 00938 00939 D3DSURFACE_DESC desc; 00940 hr = _d3d_2d_texture->GetLevelDesc(0, &desc); 00941 if (FAILED(hr)) { 00942 dxgsg8_cat.error() 00943 << "Texture::GetLevelDesc() failed!" << D3DERRORSTRING(hr); 00944 return false; 00945 } 00946 00947 int div = 1; 00948 Texture::Format format = Texture::F_rgba; 00949 Texture::CompressionMode compression = Texture::CM_off; 00950 00951 switch (desc.Format) { 00952 case D3DFMT_R8G8B8: 00953 format = Texture::F_rgb; 00954 break; 00955 00956 case D3DFMT_A8R8G8B8: 00957 case D3DFMT_X8R8G8B8: 00958 break; 00959 00960 case D3DFMT_L8: 00961 format = Texture::F_luminance; 00962 break; 00963 00964 case D3DFMT_A8L8: 00965 format = Texture::F_luminance_alpha; 00966 break; 00967 00968 case D3DFMT_DXT1: 00969 compression = Texture::CM_dxt1; 00970 div = 4; 00971 break; 00972 case D3DFMT_DXT2: 00973 compression = Texture::CM_dxt2; 00974 div = 4; 00975 break; 00976 case D3DFMT_DXT3: 00977 compression = Texture::CM_dxt3; 00978 div = 4; 00979 break; 00980 case D3DFMT_DXT4: 00981 compression = Texture::CM_dxt4; 00982 div = 4; 00983 break; 00984 case D3DFMT_DXT5: 00985 compression = Texture::CM_dxt5; 00986 div = 4; 00987 break; 00988 00989 default: 00990 dxgsg8_cat.error() 00991 << "Cannot extract texture data: unhandled surface format " 00992 << desc.Format << "\n"; 00993 return false; 00994 } 00995 00996 int num_levels = _d3d_2d_texture->GetLevelCount(); 00997 00998 tex->set_x_size(desc.Width); 00999 tex->set_y_size(desc.Height); 01000 tex->set_z_size(1); 01001 tex->set_component_type(Texture::T_unsigned_byte); 01002 tex->set_format(format); 01003 tex->clear_ram_image(); 01004 01005 for (int n = 0; n < num_levels; ++n) { 01006 D3DLOCKED_RECT rect; 01007 hr = _d3d_2d_texture->LockRect(n, &rect, NULL, D3DLOCK_READONLY); 01008 if (FAILED(hr)) { 01009 dxgsg8_cat.error() 01010 << "Texture::LockRect() failed!" << D3DERRORSTRING(hr); 01011 return false; 01012 } 01013 01014 int x_size = tex->get_expected_mipmap_x_size(n); 01015 int y_size = tex->get_expected_mipmap_y_size(n); 01016 PTA_uchar image; 01017 01018 if (compression == Texture::CM_off) { 01019 // Uncompressed, but we have to respect the pitch. 01020 int pitch = x_size * tex->get_num_components() * tex->get_component_width(); 01021 pitch = min(pitch, (int)rect.Pitch); 01022 int size = pitch * y_size; 01023 image = PTA_uchar::empty_array(size); 01024 if (pitch == rect.Pitch) { 01025 // Easy copy. 01026 memcpy(image.p(), rect.pBits, size); 01027 } else { 01028 // Harder copy: we have to de-interleave DirectX's extra bytes 01029 // on the end of each row. 01030 unsigned char *dest = image.p(); 01031 unsigned char *source = (unsigned char *)rect.pBits; 01032 for (int yi = 0; yi < y_size; ++yi) { 01033 memcpy(dest, source, pitch); 01034 dest += pitch; 01035 source += rect.Pitch; 01036 } 01037 } 01038 01039 } else { 01040 // Compressed; just copy the data verbatim. 01041 int size = rect.Pitch * (y_size / div); 01042 image = PTA_uchar::empty_array(size); 01043 memcpy(image.p(), rect.pBits, size); 01044 } 01045 01046 _d3d_2d_texture->UnlockRect(n); 01047 if (n == 0) { 01048 tex->set_ram_image(image, compression); 01049 } else { 01050 tex->set_ram_mipmap_image(n, image); 01051 } 01052 } 01053 01054 return true; 01055 } 01056 01057 //////////////////////////////////////////////////////////////////// 01058 // Function: DXTextureContext8::d3d_surface_to_texture 01059 // Access: Public, Static 01060 // Description: copies source_rect in pD3DSurf to upper left of 01061 // texture 01062 //////////////////////////////////////////////////////////////////// 01063 HRESULT DXTextureContext8:: 01064 d3d_surface_to_texture(RECT &source_rect, IDirect3DSurface8 *d3d_surface, 01065 bool inverted, Texture *result, int z) { 01066 // still need custom conversion since d3d/d3dx has no way to convert 01067 // arbitrary fmt to ARGB in-memory user buffer 01068 01069 HRESULT hr; 01070 DWORD num_components = result->get_num_components(); 01071 01072 nassertr(result->get_component_width() == sizeof(BYTE), E_FAIL); // cant handle anything else now 01073 nassertr(result->get_component_type() == Texture::T_unsigned_byte, E_FAIL); // cant handle anything else now 01074 nassertr((num_components == 3) || (num_components == 4), E_FAIL); // cant handle anything else now 01075 nassertr(IS_VALID_PTR(d3d_surface), E_FAIL); 01076 01077 BYTE *buf = result->modify_ram_image(); 01078 if (z >= 0) { 01079 nassertr(z < result->get_z_size(), E_FAIL); 01080 buf += z * result->get_expected_ram_page_size(); 01081 } 01082 01083 if (IsBadWritePtr(d3d_surface, sizeof(DWORD))) { 01084 dxgsg8_cat.error() 01085 << "d3d_surface_to_texture failed: bad pD3DSurf ptr value (" 01086 << ((void*)d3d_surface) << ")\n"; 01087 exit(1); 01088 } 01089 01090 DWORD x_window_offset, y_window_offset; 01091 DWORD copy_width, copy_height; 01092 01093 D3DLOCKED_RECT locked_rect; 01094 D3DSURFACE_DESC surface_desc; 01095 01096 hr = d3d_surface->GetDesc(&surface_desc); 01097 01098 x_window_offset = source_rect.left, y_window_offset = source_rect.top; 01099 copy_width = RECT_XSIZE(source_rect); 01100 copy_height = RECT_YSIZE(source_rect); 01101 01102 // make sure there's enough space in the texture, its size must 01103 // match (especially xsize) or scanlines will be too long 01104 01105 if (!((copy_width == result->get_x_size()) && (copy_height <= (DWORD)result->get_y_size()))) { 01106 dxgsg8_cat.error() 01107 << "d3d_surface_to_texture, Texture size (" << result->get_x_size() 01108 << ", " << result->get_y_size() 01109 << ") too small to hold display surface (" 01110 << copy_width << ", " << copy_height << ")\n"; 01111 nassertr(false, E_FAIL); 01112 return E_FAIL; 01113 } 01114 01115 hr = d3d_surface->LockRect(&locked_rect, (CONST RECT*)NULL, (D3DLOCK_READONLY | D3DLOCK_NO_DIRTY_UPDATE)); 01116 if (FAILED(hr)) { 01117 dxgsg8_cat.error() 01118 << "d3d_surface_to_texture LockRect() failed!" << D3DERRORSTRING(hr); 01119 return hr; 01120 } 01121 01122 // ones not listed not handled yet 01123 nassertr((surface_desc.Format == D3DFMT_A8R8G8B8) || 01124 (surface_desc.Format == D3DFMT_X8R8G8B8) || 01125 (surface_desc.Format == D3DFMT_R8G8B8) || 01126 (surface_desc.Format == D3DFMT_R5G6B5) || 01127 (surface_desc.Format == D3DFMT_X1R5G5B5) || 01128 (surface_desc.Format == D3DFMT_A1R5G5B5) || 01129 (surface_desc.Format == D3DFMT_A4R4G4B4), E_FAIL); 01130 01131 //buf contains raw ARGB in Texture byteorder 01132 01133 int byte_pitch = locked_rect.Pitch; 01134 BYTE *surface_bytes = (BYTE *)locked_rect.pBits; 01135 01136 if (inverted) { 01137 surface_bytes += byte_pitch * (y_window_offset + copy_height - 1); 01138 byte_pitch = -byte_pitch; 01139 } else { 01140 surface_bytes += byte_pitch * y_window_offset; 01141 } 01142 01143 // writes out last line in DDSurf first in PixelBuf, so Y line order 01144 // precedes inversely 01145 01146 if (dxgsg8_cat.is_debug()) { 01147 dxgsg8_cat.debug() 01148 << "d3d_surface_to_texture converting " 01149 << D3DFormatStr(surface_desc.Format) 01150 << " DDSurf to " << num_components << "-channel panda Texture\n"; 01151 } 01152 01153 DWORD *dest_word = (DWORD *)buf; 01154 BYTE *dest_byte = (BYTE *)buf; 01155 01156 switch(surface_desc.Format) { 01157 case D3DFMT_A8R8G8B8: 01158 case D3DFMT_X8R8G8B8: { 01159 if (num_components == 4) { 01160 DWORD *source_word; 01161 BYTE *dest_line = (BYTE*)dest_word; 01162 01163 for (DWORD y = 0; y < copy_height; y++) { 01164 source_word = ((DWORD*)surface_bytes) + x_window_offset; 01165 memcpy(dest_line, source_word, byte_pitch); 01166 dest_line += byte_pitch; 01167 surface_bytes += byte_pitch; 01168 } 01169 } else { 01170 // 24bpp texture case (numComponents == 3) 01171 DWORD *source_word; 01172 for (DWORD y = 0; y < copy_height; y++) { 01173 source_word = ((DWORD*)surface_bytes) + x_window_offset; 01174 01175 for (DWORD x = 0; x < copy_width; x++) { 01176 BYTE r, g, b; 01177 DWORD pixel = *source_word; 01178 01179 r = (BYTE)((pixel>>16) & g_LowByteMask); 01180 g = (BYTE)((pixel>> 8) & g_LowByteMask); 01181 b = (BYTE)((pixel ) & g_LowByteMask); 01182 01183 *dest_byte++ = b; 01184 *dest_byte++ = g; 01185 *dest_byte++ = r; 01186 source_word++; 01187 } 01188 surface_bytes += byte_pitch; 01189 } 01190 } 01191 break; 01192 } 01193 01194 case D3DFMT_R8G8B8: { 01195 BYTE *source_byte; 01196 01197 if (num_components == 4) { 01198 for (DWORD y = 0; y < copy_height; y++) { 01199 source_byte = surface_bytes + x_window_offset * 3 * sizeof(BYTE); 01200 for (DWORD x = 0; x < copy_width; x++) { 01201 DWORD r, g, b; 01202 01203 b = *source_byte++; 01204 g = *source_byte++; 01205 r = *source_byte++; 01206 01207 *dest_word = 0xFF000000 | (r << 16) | (g << 8) | b; 01208 dest_word++; 01209 } 01210 surface_bytes += byte_pitch; 01211 } 01212 } else { 01213 // 24bpp texture case (numComponents == 3) 01214 for (DWORD y = 0; y < copy_height; y++) { 01215 source_byte = surface_bytes + x_window_offset * 3 * sizeof(BYTE); 01216 memcpy(dest_byte, source_byte, byte_pitch); 01217 dest_byte += byte_pitch; 01218 surface_bytes += byte_pitch; 01219 } 01220 } 01221 break; 01222 } 01223 01224 case D3DFMT_R5G6B5: 01225 case D3DFMT_X1R5G5B5: 01226 case D3DFMT_A1R5G5B5: 01227 case D3DFMT_A4R4G4B4: { 01228 WORD *source_word; 01229 // handle 0555, 1555, 0565, 4444 in same loop 01230 01231 BYTE redshift, greenshift, blueshift; 01232 DWORD redmask, greenmask, bluemask; 01233 01234 if (surface_desc.Format == D3DFMT_R5G6B5) { 01235 redshift = (11-3); 01236 redmask = 0xF800; 01237 greenmask = 0x07E0; 01238 greenshift = (5-2); 01239 bluemask = 0x001F; 01240 blueshift = 3; 01241 } else if (surface_desc.Format == D3DFMT_A4R4G4B4) { 01242 redmask = 0x0F00; 01243 redshift = 4; 01244 greenmask = 0x00F0; 01245 greenshift = 0; 01246 bluemask = 0x000F; 01247 blueshift = 4; 01248 } else { // 1555 or x555 01249 redmask = 0x7C00; 01250 redshift = (10-3); 01251 greenmask = 0x03E0; 01252 greenshift = (5-3); 01253 bluemask = 0x001F; 01254 blueshift = 3; 01255 } 01256 01257 if (num_components == 4) { 01258 // Note: these 16bpp loops ignore input alpha completely (alpha 01259 // is set to fully opaque in texture!) 01260 01261 // if we need to capture alpha, probably need to make separate 01262 // loops for diff 16bpp fmts for best speed 01263 01264 for (DWORD y = 0; y < copy_height; y++) { 01265 source_word = ((WORD*)surface_bytes) + x_window_offset; 01266 for (DWORD x = 0; x < copy_width; x++) { 01267 WORD pixel = *source_word; 01268 BYTE r, g, b; 01269 01270 b = (pixel & bluemask) << blueshift; 01271 g = (pixel & greenmask) >> greenshift; 01272 r = (pixel & redmask) >> redshift; 01273 01274 // alpha is just set to 0xFF 01275 01276 *dest_word = 0xFF000000 | (r << 16) | (g << 8) | b; 01277 source_word++; 01278 dest_word++; 01279 } 01280 surface_bytes += byte_pitch; 01281 } 01282 } else { 01283 // 24bpp texture case (numComponents == 3) 01284 for (DWORD y = 0; y < copy_height; y++) { 01285 source_word = ((WORD*)surface_bytes) + x_window_offset; 01286 for (DWORD x = 0; x < copy_width; x++) { 01287 WORD pixel = *source_word; 01288 BYTE r, g, b; 01289 01290 b = (pixel & bluemask) << blueshift; 01291 g = (pixel & greenmask) >> greenshift; 01292 r = (pixel & redmask) >> redshift; 01293 01294 *dest_byte++ = b; 01295 *dest_byte++ = g; 01296 *dest_byte++ = r; 01297 01298 source_word++; 01299 } 01300 surface_bytes += byte_pitch; 01301 } 01302 } 01303 break; 01304 } 01305 01306 default: 01307 dxgsg8_cat.error() 01308 << "d3d_surface_to_texture: unsupported D3DFORMAT!\n"; 01309 } 01310 01311 d3d_surface->UnlockRect(); 01312 return S_OK; 01313 } 01314 01315 //////////////////////////////////////////////////////////////////// 01316 // Function: calculate_row_byte_length 01317 // Access: Private, hidden 01318 // Description: local helper function, which calculates the 01319 // 'row_byte_length' or 'pitch' needed for calling 01320 // D3DXLoadSurfaceFromMemory. 01321 // Takes compressed formats (DXTn) into account. 01322 //////////////////////////////////////////////////////////////////// 01323 static UINT calculate_row_byte_length (int width, int num_color_channels, D3DFORMAT tex_format) 01324 { 01325 UINT source_row_byte_length = 0; 01326 01327 // check for compressed textures and adjust source_row_byte_length and source_format accordingly 01328 switch (tex_format) { 01329 case D3DFMT_DXT1: 01330 // for dxt1 compressed textures, the row_byte_lenght is "the width of one row of cells, in bytes" 01331 // cells are 4 pixels wide, take up 8 bytes, and at least 1 cell has to be there. 01332 source_row_byte_length = max(1,width / 4)*8; 01333 break; 01334 case D3DFMT_DXT2: 01335 case D3DFMT_DXT3: 01336 case D3DFMT_DXT4: 01337 case D3DFMT_DXT5: 01338 // analogue as above, but cells take up 16 bytes 01339 source_row_byte_length = max(1,width / 4)*16; 01340 break; 01341 default: 01342 // no known compression format.. usual calculation 01343 source_row_byte_length = width*num_color_channels; 01344 break; 01345 } 01346 return source_row_byte_length; 01347 } 01348 01349 //////////////////////////////////////////////////////////////////// 01350 // Function: DXTextureContext8::fill_d3d_texture_mipmap_pixels 01351 // Access: Private 01352 // Description: Called from fill_d3d_texture_pixels, this function 01353 // fills a single mipmap with texture data. 01354 // Takes care of all necessery conversions and error 01355 // handling. 01356 //////////////////////////////////////////////////////////////////// 01357 HRESULT DXTextureContext8::fill_d3d_texture_mipmap_pixels(int mip_level, int depth_index, D3DFORMAT source_format) 01358 { 01359 // This whole function was refactored out of fill_d3d_texture_pixels to make the code 01360 // more readable and to avoid code duplication. 01361 IDirect3DSurface8 *mip_surface = NULL; 01362 bool using_temp_buffer = false; 01363 HRESULT hr = E_FAIL; 01364 CPTA_uchar image = get_texture()->get_ram_mipmap_image(mip_level); 01365 nassertr(!image.is_null(), E_FAIL); 01366 BYTE *pixels = (BYTE*) image.p(); 01367 DWORD width = (DWORD) get_texture()->get_expected_mipmap_x_size(mip_level); 01368 DWORD height = (DWORD) get_texture()->get_expected_mipmap_y_size(mip_level); 01369 int component_width = get_texture()->get_component_width(); 01370 01371 pixels += depth_index * get_texture()->get_expected_ram_mipmap_page_size(mip_level); 01372 01373 if (get_texture()->get_texture_type() == Texture::TT_cube_map) { 01374 nassertr(IS_VALID_PTR(_d3d_cube_texture), E_FAIL); 01375 hr = _d3d_cube_texture->GetCubeMapSurface((D3DCUBEMAP_FACES)depth_index, mip_level, &mip_surface); 01376 } else { 01377 nassertr(IS_VALID_PTR(_d3d_2d_texture), E_FAIL); 01378 hr = _d3d_2d_texture->GetSurfaceLevel(mip_level, &mip_surface); 01379 } 01380 01381 if (FAILED(hr)) { 01382 dxgsg8_cat.error() 01383 << "FillDDTextureMipmapPixels failed for " << get_texture()->get_name() 01384 << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr); 01385 return E_FAIL; 01386 } 01387 01388 RECT source_size; 01389 source_size.left = source_size.top = 0; 01390 source_size.right = width; 01391 source_size.bottom = height; 01392 01393 UINT source_row_byte_length = calculate_row_byte_length(width, get_texture()->get_num_components(), source_format); 01394 01395 DWORD mip_filter; 01396 // need filtering if size changes, (also if bitdepth reduced (need 01397 // dithering)??) 01398 mip_filter = D3DX_FILTER_LINEAR ; //| D3DX_FILTER_DITHER; //dithering looks ugly on i810 for 4444 textures 01399 01400 // D3DXLoadSurfaceFromMemory will load black luminance and we want 01401 // full white, so convert to explicit luminance-alpha format 01402 if (_d3d_format == D3DFMT_A8) { 01403 // alloc buffer for explicit D3DFMT_A8L8 01404 USHORT *temp_buffer = new USHORT[width * height]; 01405 if (!IS_VALID_PTR(temp_buffer)) { 01406 dxgsg8_cat.error() 01407 << "FillDDTextureMipmapPixels couldnt alloc mem for temp pixbuf!\n"; 01408 goto exit_FillMipmapSurf; 01409 } 01410 using_temp_buffer = true; 01411 01412 USHORT *out_pixels = temp_buffer; 01413 BYTE *source_pixels = pixels + component_width - 1; 01414 for (UINT y = 0; y < height; y++) { 01415 for (UINT x = 0; x < width; x++, source_pixels += component_width, out_pixels++) { 01416 // add full white, which is our interpretation of alpha-only 01417 // (similar to default adding full opaque alpha 0xFF to 01418 // RGB-only textures) 01419 *out_pixels = ((*source_pixels) << 8 ) | 0xFF; 01420 } 01421 } 01422 01423 source_format = D3DFMT_A8L8; 01424 source_row_byte_length = width * sizeof(USHORT); 01425 pixels = (BYTE*)temp_buffer; 01426 } 01427 else if (component_width != 1) { 01428 // Convert from 16-bit per channel (or larger) format down to 01429 // 8-bit per channel. This throws away precision in the 01430 // original image, but dx8 doesn't support high-precision images 01431 // anyway. 01432 01433 int num_components = get_texture()->get_num_components(); 01434 int num_pixels = width * height * num_components; 01435 BYTE *temp_buffer = new BYTE[num_pixels]; 01436 if (!IS_VALID_PTR(temp_buffer)) { 01437 dxgsg8_cat.error() << "FillDDTextureMipmapPixels couldnt alloc mem for temp pixbuf!\n"; 01438 goto exit_FillMipmapSurf; 01439 } 01440 using_temp_buffer = true; 01441 01442 BYTE *source_pixels = pixels + component_width - 1; 01443 for (int i = 0; i < num_pixels; i++) { 01444 temp_buffer[i] = *source_pixels; 01445 source_pixels += component_width; 01446 } 01447 pixels = (BYTE*)temp_buffer; 01448 } 01449 01450 // filtering may be done here if texture if targetsize != origsize 01451 #ifdef DO_PSTATS 01452 GraphicsStateGuardian::_data_transferred_pcollector.add_level(source_row_byte_length * height); 01453 #endif 01454 hr = D3DXLoadSurfaceFromMemory 01455 (mip_surface, (PALETTEENTRY*)NULL, (RECT*)NULL, (LPCVOID)pixels, 01456 source_format, source_row_byte_length, (PALETTEENTRY*)NULL, 01457 &source_size, mip_filter, (D3DCOLOR)0x0); 01458 if (FAILED(hr)) { 01459 dxgsg8_cat.error() 01460 << "FillDDTextureMipmapPixels failed for " << get_texture()->get_name() 01461 << ", mip_level " << mip_level 01462 << ", D3DXLoadSurfFromMem failed" << D3DERRORSTRING(hr); 01463 } 01464 01465 exit_FillMipmapSurf: 01466 if (using_temp_buffer) { 01467 SAFE_DELETE_ARRAY(pixels); 01468 } 01469 01470 RELEASE(mip_surface, dxgsg8, "FillDDTextureMipmapPixels MipSurface texture ptr", RELEASE_ONCE); 01471 return hr; 01472 } 01473 01474 //////////////////////////////////////////////////////////////////// 01475 // Function: DXTextureContext8::fill_d3d_texture_pixels 01476 // Access: Private 01477 // Description: 01478 //////////////////////////////////////////////////////////////////// 01479 HRESULT DXTextureContext8:: 01480 fill_d3d_texture_pixels(DXScreenData &scrn) { 01481 Texture *tex = get_texture(); 01482 nassertr(IS_VALID_PTR(tex), E_FAIL); 01483 if (tex->get_texture_type() == Texture::TT_3d_texture) { 01484 return fill_d3d_volume_texture_pixels(scrn); 01485 } 01486 01487 HRESULT hr = E_FAIL; 01488 nassertr(IS_VALID_PTR(tex), E_FAIL); 01489 01490 CPTA_uchar image; 01491 if (scrn._dxgsg8->get_supports_compressed_texture()) { 01492 image = tex->get_ram_image(); 01493 } else { 01494 image = tex->get_uncompressed_ram_image(); 01495 } 01496 01497 Texture::CompressionMode image_compression; 01498 if (image.is_null()) { 01499 image_compression = Texture::CM_off; 01500 } else { 01501 image_compression = tex->get_ram_image_compression(); 01502 } 01503 01504 if (!scrn._dxgsg8->get_supports_compressed_texture_format(image_compression)) { 01505 image = tex->get_uncompressed_ram_image(); 01506 image_compression = Texture::CM_off; 01507 } 01508 if (image.is_null()) { 01509 // The texture doesn't have an image to load. That's ok; it 01510 // might be a texture we've rendered to by frame buffer 01511 // operations or something. 01512 return S_OK; 01513 } 01514 nassertr(IS_VALID_PTR((BYTE*)image.p()), E_FAIL); 01515 nassertr(IS_VALID_PTR(_d3d_texture), E_FAIL); 01516 01517 PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector); 01518 01519 DWORD orig_depth = (DWORD) tex->get_z_size(); 01520 D3DFORMAT source_format = _d3d_format; 01521 01522 // check for compressed textures and adjust source_format accordingly 01523 switch (image_compression) { 01524 case Texture::CM_dxt1: 01525 source_format = D3DFMT_DXT1; 01526 break; 01527 case Texture::CM_dxt2: 01528 source_format = D3DFMT_DXT2; 01529 break; 01530 case Texture::CM_dxt3: 01531 source_format = D3DFMT_DXT3; 01532 break; 01533 case Texture::CM_dxt4: 01534 source_format = D3DFMT_DXT4; 01535 break; 01536 case Texture::CM_dxt5: 01537 source_format = D3DFMT_DXT5; 01538 break; 01539 default: 01540 // no known compression format.. no adjustment 01541 break; 01542 } 01543 01544 for (unsigned int di = 0; di < orig_depth; di++) { 01545 01546 // fill top level mipmap 01547 hr = fill_d3d_texture_mipmap_pixels(0, di, source_format); 01548 if (FAILED(hr)) { 01549 return hr; // error message was already output in fill_d3d_texture_mipmap_pixels 01550 } 01551 01552 if (_has_mipmaps) { 01553 // if we have pre-calculated mipmap levels, use them, otherwise generate on the fly 01554 int miplevel_count = _d3d_2d_texture->GetLevelCount(); // what if it's not a 2d texture? 01555 if (miplevel_count <= tex->get_num_loadable_ram_mipmap_images()) { 01556 dxgsg8_cat.debug() 01557 << "Using pre-calculated mipmap levels for texture " << tex->get_name() << "\n"; 01558 01559 for (int mip_level = 1; mip_level < miplevel_count; ++mip_level) { 01560 hr = fill_d3d_texture_mipmap_pixels(mip_level, di, source_format); 01561 if (FAILED(hr)) { 01562 return hr; // error message was already output in fill_d3d_texture_mipmap_pixels 01563 } 01564 } 01565 } 01566 else { 01567 // mipmaps need to be generated. 01568 01569 DWORD mip_filter_flags; 01570 if (!dx_use_triangle_mipgen_filter) { 01571 mip_filter_flags = D3DX_FILTER_BOX; 01572 } else { 01573 mip_filter_flags = D3DX_FILTER_TRIANGLE; 01574 } 01575 01576 // mip_filter_flags |= D3DX_FILTER_DITHER; 01577 hr = D3DXFilterTexture(_d3d_texture, (PALETTEENTRY*)NULL, 0, 01578 mip_filter_flags); 01579 01580 if (FAILED(hr)) { 01581 dxgsg8_cat.error() 01582 << "FillDDSurfaceTexturePixels failed for " << tex->get_name() 01583 << ", D3DXFilterTex failed" << D3DERRORSTRING(hr); 01584 } 01585 } 01586 } 01587 } 01588 01589 return hr; 01590 } 01591 01592 //////////////////////////////////////////////////////////////////// 01593 // Function: DXTextureContext8::fill_d3d_volume_texture_pixels 01594 // Access: Private 01595 // Description: 01596 //////////////////////////////////////////////////////////////////// 01597 HRESULT DXTextureContext8:: 01598 fill_d3d_volume_texture_pixels(DXScreenData &scrn) { 01599 Texture *tex = get_texture(); 01600 HRESULT hr = E_FAIL; 01601 nassertr(IS_VALID_PTR(tex), E_FAIL); 01602 01603 CPTA_uchar image; 01604 if (scrn._dxgsg8->get_supports_compressed_texture()) { 01605 image = tex->get_ram_image(); 01606 } else { 01607 image = tex->get_uncompressed_ram_image(); 01608 } 01609 01610 Texture::CompressionMode image_compression; 01611 if (image.is_null()) { 01612 image_compression = Texture::CM_off; 01613 } else { 01614 image_compression = tex->get_ram_image_compression(); 01615 } 01616 01617 if (!scrn._dxgsg8->get_supports_compressed_texture_format(image_compression) || 01618 tex->get_x_size() < 4 || tex->get_y_size() < 4) { 01619 // If we don't support this particular compression method, or in 01620 // any case if the texture is too small (DirectX won't accept a 01621 // small compressed texture), then fetch and load the uncompressed 01622 // version instead. 01623 image = tex->get_uncompressed_ram_image(); 01624 image_compression = Texture::CM_off; 01625 } 01626 01627 if (image.is_null()) { 01628 // The texture doesn't have an image to load. That's ok; it 01629 // might be a texture we've rendered to by frame buffer 01630 // operations or something. 01631 return S_OK; 01632 } 01633 01634 PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector); 01635 01636 nassertr(IS_VALID_PTR(_d3d_texture), E_FAIL); 01637 nassertr(tex->get_texture_type() == Texture::TT_3d_texture, E_FAIL); 01638 01639 DWORD orig_width = (DWORD) tex->get_x_size(); 01640 DWORD orig_height = (DWORD) tex->get_y_size(); 01641 DWORD orig_depth = (DWORD) tex->get_z_size(); 01642 DWORD num_color_channels = tex->get_num_components(); 01643 D3DFORMAT source_format = _d3d_format; 01644 BYTE *image_pixels = (BYTE*)image.p(); 01645 int component_width = tex->get_component_width(); 01646 01647 nassertr(IS_VALID_PTR(image_pixels), E_FAIL); 01648 01649 IDirect3DVolume8 *mip_level_0 = NULL; 01650 bool using_temp_buffer = false; 01651 BYTE *pixels = image_pixels; 01652 01653 nassertr(IS_VALID_PTR(_d3d_volume_texture), E_FAIL); 01654 hr = _d3d_volume_texture->GetVolumeLevel(0, &mip_level_0); 01655 01656 if (FAILED(hr)) { 01657 dxgsg8_cat.error() 01658 << "FillDDSurfaceTexturePixels failed for " << tex->get_name() 01659 << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr); 01660 return E_FAIL; 01661 } 01662 01663 D3DBOX source_size; 01664 source_size.Left = source_size.Top = source_size.Front = 0; 01665 source_size.Right = orig_width; 01666 source_size.Bottom = orig_height; 01667 source_size.Back = orig_depth; 01668 01669 UINT source_row_byte_length = orig_width * num_color_channels; 01670 UINT source_page_byte_length = orig_height * source_row_byte_length; 01671 01672 DWORD level_0_filter, mip_filter_flags; 01673 using_temp_buffer = false; 01674 01675 // need filtering if size changes, (also if bitdepth reduced (need 01676 // dithering)??) 01677 level_0_filter = D3DX_FILTER_LINEAR ; //| D3DX_FILTER_DITHER; //dithering looks ugly on i810 for 4444 textures 01678 01679 // D3DXLoadSurfaceFromMemory will load black luminance and we want 01680 // full white, so convert to explicit luminance-alpha format 01681 if (_d3d_format == D3DFMT_A8) { 01682 // alloc buffer for explicit D3DFMT_A8L8 01683 USHORT *temp_buffer = new USHORT[orig_width * orig_height * orig_depth]; 01684 if (!IS_VALID_PTR(temp_buffer)) { 01685 dxgsg8_cat.error() 01686 << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n"; 01687 goto exit_FillDDSurf; 01688 } 01689 using_temp_buffer = true; 01690 01691 USHORT *out_pixels = temp_buffer; 01692 BYTE *source_pixels = pixels + component_width - 1; 01693 for (UINT z = 0; z < orig_depth; z++) { 01694 for (UINT y = 0; y < orig_height; y++) { 01695 for (UINT x = 0; 01696 x < orig_width; 01697 x++, source_pixels += component_width, out_pixels++) { 01698 // add full white, which is our interpretation of alpha-only 01699 // (similar to default adding full opaque alpha 0xFF to 01700 // RGB-only textures) 01701 *out_pixels = ((*source_pixels) << 8 ) | 0xFF; 01702 } 01703 } 01704 } 01705 01706 source_format = D3DFMT_A8L8; 01707 source_row_byte_length = orig_width * sizeof(USHORT); 01708 source_page_byte_length = orig_height * source_row_byte_length; 01709 pixels = (BYTE*)temp_buffer; 01710 01711 } else if (component_width != 1) { 01712 // Convert from 16-bit per channel (or larger) format down to 01713 // 8-bit per channel. This throws away precision in the 01714 // original image, but dx8 doesn't support high-precision images 01715 // anyway. 01716 01717 int num_components = tex->get_num_components(); 01718 int num_pixels = orig_width * orig_height * orig_depth * num_components; 01719 BYTE *temp_buffer = new BYTE[num_pixels]; 01720 if (!IS_VALID_PTR(temp_buffer)) { 01721 dxgsg8_cat.error() << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n"; 01722 goto exit_FillDDSurf; 01723 } 01724 using_temp_buffer = true; 01725 01726 BYTE *source_pixels = pixels + component_width - 1; 01727 for (int i = 0; i < num_pixels; i++) { 01728 temp_buffer[i] = *source_pixels; 01729 source_pixels += component_width; 01730 } 01731 pixels = (BYTE*)temp_buffer; 01732 } 01733 01734 01735 // filtering may be done here if texture if targetsize != origsize 01736 #ifdef DO_PSTATS 01737 GraphicsStateGuardian::_data_transferred_pcollector.add_level(source_page_byte_length * orig_depth); 01738 #endif 01739 hr = D3DXLoadVolumeFromMemory 01740 (mip_level_0, (PALETTEENTRY*)NULL, (D3DBOX*)NULL, (LPCVOID)pixels, 01741 source_format, source_row_byte_length, source_page_byte_length, 01742 (PALETTEENTRY*)NULL, 01743 &source_size, level_0_filter, (D3DCOLOR)0x0); 01744 if (FAILED(hr)) { 01745 dxgsg8_cat.error() 01746 << "FillDDSurfaceTexturePixels failed for " << tex->get_name() 01747 << ", D3DXLoadVolumeFromMem failed" << D3DERRORSTRING(hr); 01748 goto exit_FillDDSurf; 01749 } 01750 01751 if (_has_mipmaps) { 01752 if (!dx_use_triangle_mipgen_filter) { 01753 mip_filter_flags = D3DX_FILTER_BOX; 01754 } else { 01755 mip_filter_flags = D3DX_FILTER_TRIANGLE; 01756 } 01757 01758 // mip_filter_flags| = D3DX_FILTER_DITHER; 01759 01760 hr = D3DXFilterTexture(_d3d_texture, (PALETTEENTRY*)NULL, 0, 01761 mip_filter_flags); 01762 if (FAILED(hr)) { 01763 dxgsg8_cat.error() 01764 << "FillDDSurfaceTexturePixels failed for " << tex->get_name() 01765 << ", D3DXFilterTex failed" << D3DERRORSTRING(hr); 01766 goto exit_FillDDSurf; 01767 } 01768 } 01769 01770 exit_FillDDSurf: 01771 if (using_temp_buffer) { 01772 SAFE_DELETE_ARRAY(pixels); 01773 } 01774 RELEASE(mip_level_0, dxgsg8, "FillDDSurf MipLev0 texture ptr", RELEASE_ONCE); 01775 return hr; 01776 } 01777 01778 01779 //////////////////////////////////////////////////////////////////// 01780 // Function: DXTextureContext8::down_to_power_2 01781 // Access: Private, Static 01782 // Description: Returns the largest power of 2 less than or equal 01783 // to value. 01784 //////////////////////////////////////////////////////////////////// 01785 int DXTextureContext8:: 01786 down_to_power_2(int value) { 01787 int x = 1; 01788 while ((x << 1) <= value) { 01789 x = (x << 1); 01790 } 01791 return x; 01792 } 01793 01794 //////////////////////////////////////////////////////////////////// 01795 // Function: DXTextureContext8::get_bits_per_pixel 01796 // Access: Private 01797 // Description: Maps from the Texture's Format symbols to bpp. 01798 // Returns # of alpha bits. Note: Texture's format 01799 // indicates REQUESTED final format, not the stored 01800 // format, which is indicated by pixelbuffer type 01801 //////////////////////////////////////////////////////////////////// 01802 unsigned int DXTextureContext8:: 01803 get_bits_per_pixel(Texture::Format format, int *alphbits) { 01804 *alphbits = 0; // assume no alpha bits 01805 switch(format) { 01806 case Texture::F_alpha: 01807 *alphbits = 8; 01808 case Texture::F_color_index: 01809 case Texture::F_red: 01810 case Texture::F_green: 01811 case Texture::F_blue: 01812 case Texture::F_rgb332: 01813 return 8; 01814 case Texture::F_luminance_alphamask: 01815 *alphbits = 1; 01816 return 16; 01817 case Texture::F_luminance_alpha: 01818 *alphbits = 8; 01819 return 16; 01820 case Texture::F_luminance: 01821 return 8; 01822 case Texture::F_rgba4: 01823 *alphbits = 4; 01824 return 16; 01825 case Texture::F_rgba5: 01826 *alphbits = 1; 01827 return 16; 01828 case Texture::F_depth_stencil: 01829 return 32; 01830 case Texture::F_rgb5: 01831 return 16; 01832 case Texture::F_rgb8: 01833 case Texture::F_rgb: 01834 return 24; 01835 case Texture::F_rgba8: 01836 case Texture::F_rgba: 01837 *alphbits = 8; 01838 return 32; 01839 case Texture::F_rgbm: 01840 *alphbits = 1; 01841 return 32; 01842 case Texture::F_rgb12: 01843 return 36; 01844 case Texture::F_rgba12: 01845 *alphbits = 12; 01846 return 48; 01847 } 01848 return 8; 01849 }