Panda3D
 All Classes Functions Variables Enumerations
dxTextureContext8.cxx
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 }
 All Classes Functions Variables Enumerations