Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

OgreD3D7Texture.cpp

Go to the documentation of this file.
00001 /*
00002 -----------------------------------------------------------------------------
00003 This source file is part of OGRE
00004     (Object-oriented Graphics Rendering Engine)
00005 For the latest info, see http://www.ogre3d.org/
00006 
00007 Copyright © 2000-2002 The OGRE Team
00008 Also see acknowledgements in Readme.html
00009 
00010 This program is free software; you can redistribute it and/or modify it under
00011 the terms of the GNU Lesser General Public License as published by the Free Software
00012 Foundation; either version 2 of the License, or (at your option) any later
00013 version.
00014 
00015 This program is distributed in the hope that it will be useful, but WITHOUT
00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
00018 
00019 You should have received a copy of the GNU Lesser General Public License along with
00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
00022 http://www.gnu.org/copyleft/lesser.txt.
00023 -----------------------------------------------------------------------------
00024 */
00025 #include "OgreD3D7Texture.h"
00026 #include "OgreException.h"
00027 #include "OgreImage.h"
00028 #include "OgreLogManager.h"
00029 
00030 #include "OgreRoot.h"
00031 
00032 namespace Ogre {
00033 
00034     static bool OgreFormatRequiresEndianFlipping( PixelFormat format )
00035     {
00036         switch( format )
00037         {
00038         case PF_L4A4:
00039         case PF_B5G6R5:
00040         case PF_B4G4R4A4:
00041         case PF_B8G8R8:
00042         case PF_B8G8R8A8:
00043         case PF_B10G10R10A2:
00044             return true;
00045 
00046         case PF_L8:
00047         case PF_A8:
00048         case PF_R5G6B5:
00049         case PF_A4R4G4B4:
00050         case PF_R8G8B8:
00051         case PF_A8R8G8B8:
00052         case PF_A2R10G10B10:
00053         case PF_A4L4:
00054         case PF_UNKNOWN:
00055         default:
00056             return false;
00057         }
00058     }
00059     static D3DX_SURFACEFORMAT OgreFormat_to_D3DXFormat( PixelFormat format )
00060     {
00061         switch( format )
00062         {
00063         case PF_L8:
00064             return D3DX_SF_L8;
00065         case PF_A8:
00066             return D3DX_SF_A8;
00067         case PF_R5G6B5:
00068         case PF_B5G6R5:
00069             return D3DX_SF_R5G6B5;
00070         case PF_A4R4G4B4:
00071         case PF_B4G4R4A4:
00072             return D3DX_SF_A4R4G4B4;
00073         case PF_R8G8B8:
00074         case PF_B8G8R8:
00075             return D3DX_SF_R8G8B8;
00076         case PF_A8R8G8B8:
00077         case PF_B8G8R8A8:
00078             return D3DX_SF_A8R8G8B8;
00079         case PF_UNKNOWN:
00080         case PF_A4L4:
00081         case PF_L4A4:
00082         case PF_A2R10G10B10:
00083         case PF_B10G10R10A2:
00084         default:
00085             return D3DX_SF_UNKNOWN;
00086         }
00087     }
00088 
00089     static void OgreFormat_to_DDPixelFormat( PixelFormat format, DDPIXELFORMAT & out )
00090     {
00091         memset( &out, 0, sizeof( DDPIXELFORMAT ) );
00092         out.dwSize = sizeof( DDPIXELFORMAT );
00093 
00094         switch( format )
00095         {
00096         case PF_A8:
00097             out.dwFlags = DDPF_ALPHA;
00098             out.dwAlphaBitDepth = 8;
00099             
00100             break;
00101 
00102         case PF_L8:
00103             out.dwFlags = DDPF_LUMINANCE ;
00104             out.dwLuminanceBitCount = 8;
00105 
00106             break;
00107 
00108         case PF_A4L4:
00109         case PF_L4A4:
00110             out.dwFlags = DDPF_LUMINANCE | DDPF_ALPHAPIXELS;
00111             out.dwLuminanceBitCount = 4;
00112 
00113             if( format == PF_A4L4 )
00114             {
00115                 out.dwLuminanceAlphaBitMask = 0xf0;
00116                 out.dwLuminanceBitMask = 0x0f;
00117             }
00118             else
00119             {
00120                 out.dwLuminanceAlphaBitMask = 0x0f;
00121                 out.dwLuminanceBitMask = 0xf0;
00122             }
00123 
00124             break;
00125 
00126         case PF_R5G6B5:
00127         case PF_B5G6R5:
00128             out.dwFlags = DDPF_RGB;
00129             out.dwRGBBitCount = 16;
00130 
00131             if( format == PF_R5G6B5 )
00132             {
00133                 out.dwRBitMask = 0xf800;
00134                 out.dwGBitMask = 0x07e0;
00135                 out.dwBBitMask = 0x001f;
00136             }
00137             else
00138             {
00139                 out.dwRBitMask = 0x001f;
00140                 out.dwGBitMask = 0x07e0;
00141                 out.dwBBitMask = 0xf800;
00142             }
00143 
00144             break;
00145 
00146         case PF_A4R4G4B4:
00147         case PF_B4G4R4A4:
00148             out.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
00149             out.dwRGBBitCount = 12;
00150 
00151             if( format == PF_A4R4G4B4 )
00152             {
00153                 out.dwRGBAlphaBitMask = 0xf000;
00154                 out.dwRBitMask        = 0x0f00;
00155                 out.dwGBitMask        = 0x00f0;
00156                 out.dwBBitMask        = 0x000f;
00157             }
00158             else
00159             {
00160                 out.dwRGBAlphaBitMask = 0x000f;
00161                 out.dwRBitMask          = 0x00f0;
00162                 out.dwGBitMask          = 0x0f00;
00163                 out.dwBBitMask          = 0xf000;
00164             }
00165 
00166             break;
00167 
00168         case PF_R8G8B8:
00169         case PF_B8G8R8:
00170             out.dwFlags = DDPF_RGB;
00171             out.dwRGBBitCount = 24;
00172 
00173             if( format == PF_R8G8B8 )
00174             {
00175                 out.dwRBitMask = 0xff0000;
00176                 out.dwGBitMask = 0x00ff00;
00177                 out.dwBBitMask = 0x0000ff;
00178             }
00179             else
00180             {
00181                 out.dwRBitMask = 0x0000ff;
00182                 out.dwGBitMask = 0x00ff00;
00183                 out.dwBBitMask = 0xff0000;
00184             }
00185 
00186             break;
00187 
00188         case PF_A8R8G8B8:
00189         case PF_B8G8R8A8:
00190             out.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
00191             out.dwRGBBitCount = 24;
00192 
00193             if( format == PF_A8R8G8B8 )
00194             {
00195                 out.dwRGBAlphaBitMask = 0xff000000;
00196                 out.dwRBitMask        = 0x00ff0000;
00197                 out.dwGBitMask        = 0x0000ff00;
00198                 out.dwBBitMask        = 0x000000ff;
00199             }
00200             else
00201             {
00202                 out.dwRGBAlphaBitMask = 0x000000ff;
00203                 out.dwRBitMask        = 0x0000ff00;
00204                 out.dwGBitMask        = 0x00ff0000;
00205                 out.dwBBitMask        = 0xff000000;
00206             }
00207 
00208             break;
00209         }
00210     }
00211 
00212     //---------------------------------------------------------------------------------------------
00213     D3DTexture::D3DTexture(const String& name, TextureType texType, LPDIRECT3DDEVICE7 lpDirect3dDevice, TextureUsage usage )
00214     {
00215         mD3DDevice = lpDirect3dDevice; mD3DDevice->AddRef();
00216 
00217         mName = name;
00218         mTextureType = texType;
00219         mUsage = usage;
00220         mDepth = 1; // D3D7 does not support volume textures
00221 
00222         // Default to 16-bit texture
00223         enable32Bit( false );
00224     }
00225     //---------------------------------------------------------------------------------------------
00226     D3DTexture::D3DTexture( 
00227         const String& name, 
00228         TextureType texType, 
00229         IDirect3DDevice7 * lpDirect3dDevice, 
00230         uint width, 
00231         uint height, 
00232         uint num_mips,
00233         PixelFormat format,
00234         TextureUsage usage )
00235     {
00236         mD3DDevice = lpDirect3dDevice; mD3DDevice->AddRef();
00237 
00238         mName = name;
00239         mTextureType = texType;
00240         mSrcWidth = width;
00241         mSrcHeight = height;
00242         mNumMipMaps = num_mips;
00243 
00244         mUsage = usage;
00245         mFormat = format;
00246         mSrcBpp = mFinalBpp = Image::getNumElemBits( mFormat );
00247         mHasAlpha = Image::formatHasAlpha(mFormat);
00248 
00249         createSurface();
00250         mIsLoaded = true;
00251     }
00252     //---------------------------------------------------------------------------------------------
00253     D3DTexture::~D3DTexture()
00254     {
00255         if( mIsLoaded )
00256             unload();
00257 
00258         __safeRelease( &mD3DDevice );
00259     }
00260     /****************************************************************************************/
00261     void D3DTexture::blitToTexture( 
00262         const Image &src, unsigned uStartX, unsigned uStartY )
00263     {
00264         blitImage( src, Image::Rect( uStartX, uStartY, src.getWidth(), src.getHeight() ),
00265             Image::Rect( 0, 0, Texture::getWidth(), Texture::getHeight() ) );
00266     }
00267 
00268     //---------------------------------------------------------------------------------------------
00269     void D3DTexture::blitImage( const Image& src, 
00270             const Image::Rect imgRect, const Image::Rect texRect )
00271     {
00272         OgreGuard( "D3DTexture::blitImage" );
00273 
00274         /* We need a temporary surface in which to load the image data. */
00275         LPDIRECTDRAWSURFACE7 pddsTempSurface;
00276         HRESULT hr;
00277         D3DX_SURFACEFORMAT surfFmt, texFmt;
00278 
00279         /* Compute the pixel format for the image. */
00280         if( src.getBPP() == 16 )
00281         {
00282             if( src.getHasAlpha() )
00283                 surfFmt = D3DX_SF_A4R4G4B4;
00284             else
00285                 surfFmt = D3DX_SF_R5G6B5;
00286         }
00287         else
00288         {
00289             if( src.getHasAlpha() )
00290                 surfFmt = D3DX_SF_A8R8G8B8;
00291             else
00292                 surfFmt = D3DX_SF_R8G8B8;
00293         }
00294 
00295         /* Compute the current pixel format of the texture. */
00296         if( mFinalBpp == 16 )
00297         {
00298             if( mHasAlpha )
00299                 texFmt = D3DX_SF_A4R4G4B4;
00300             else
00301                 texFmt = D3DX_SF_R5G6B5;
00302         }
00303         else
00304         {
00305             if( mHasAlpha )
00306                 texFmt = D3DX_SF_A8R8G8B8;
00307             else
00308                 texFmt = D3DX_SF_R8G8B8;
00309         }
00310 
00311         /* Oh, you, endianness! How thy beauty never ceases to amaze me. NOT! 
00312            In other words we need to create a temporary image in which we can
00313            convert the data (and also apply gamma transformation). */
00314         Image tempImg( src );
00315         Image::applyGamma( tempImg.getData(), mGamma, static_cast< uint >( tempImg.getSize() ), tempImg.getBPP() );
00316         {
00317             /* Scoping in order to get rid of the local vars. */
00318             uchar *c = tempImg.getData();
00319             for( uint i = 0; i < src.getSize(); i+= src.getBPP() >> 3, c += src.getBPP() >> 3 )
00320             {
00321                 uchar tmp;
00322 
00323                 if( src.getBPP() == 16 )
00324                 {
00325                     tmp = c[0]; c[0] = c[1]; c[1] = tmp;
00326                 }
00327                 else
00328                 {
00329                     tmp = c[0]; c[0] = c[2]; c[2] = tmp;
00330                 }
00331             }
00332         }
00333 
00334         /* We generate the mip-maps by hand. */
00335         DWORD mipFlag, numMips;
00336         mipFlag = D3DX_TEXTURE_NOMIPMAP;
00337 
00338         /* Set the width and height. */
00339         DWORD dwWidth = src.getWidth(), dwHeight = src.getHeight();
00340 
00341         /* Create the temporary surface. */
00342         if( FAILED( hr = D3DXCreateTexture(
00343             mD3DDevice,
00344             NULL,
00345             &dwWidth,
00346             &dwHeight,
00347             &texFmt,
00348             NULL,
00349             &pddsTempSurface,
00350             &numMips ) ) )
00351         {
00352             Except( hr, "Error during blit operation.", "D3DTexture::blitImage" );
00353         }
00354 
00355         /* Load the image into the temporary surface. */
00356         if( FAILED( hr = D3DXLoadTextureFromMemory(
00357             mD3DDevice,
00358             pddsTempSurface,
00359             D3DX_DEFAULT,
00360             tempImg.getData(),
00361             NULL,
00362             surfFmt,
00363             D3DX_DEFAULT,
00364             NULL,
00365             D3DX_FT_LINEAR ) ) )
00366         {
00367             pddsTempSurface->Release();
00368             Except( hr, "Error during blit operation.", "D3DTexture::blitImage" );
00369         }
00370 
00371         /* We have to make sure that the source image wasn't stretched during the loading. */
00372         Image::Rect finalRect;
00373 
00374         Real fHeightFactor = Real( dwHeight ) / Real( src.getHeight() );
00375         Real fWidthFactor = Real( dwWidth ) / Real( src.getWidth() );
00376 
00377         finalRect.bottom = Real( imgRect.bottom ) * fHeightFactor;
00378         finalRect.top    = Real( imgRect.top )    * fHeightFactor;
00379         finalRect.left   = Real( imgRect.left )   * fWidthFactor;
00380         finalRect.right  = Real( imgRect.right )  * fWidthFactor;
00381 
00382         if( FAILED( hr = mSurface->Blt(
00383             (RECT*)&texRect,
00384             pddsTempSurface, 
00385             (RECT*)&finalRect,
00386             DDBLT_WAIT,
00387             NULL ) ) )
00388         {
00389             pddsTempSurface->Release();
00390             Except( hr, "Error during blit operation.", "D3DTexture::blitImage" );
00391         }
00392 
00393         /* Load the image in all the mip-maps (if there are any, that is). */
00394         LPDIRECTDRAWSURFACE7 ddsMipLevel, ddsNextLevel;
00395         DDSCAPS2 ddsCaps;
00396         HRESULT mipRes = DD_OK;
00397         uint mipLevel = 1;
00398 
00399         ZeroMemory(&ddsCaps, sizeof(DDSCAPS2));
00400         ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_MIPMAP;
00401 
00402         /* Get the base level and increae the reference count. */
00403         ddsMipLevel = mSurface;
00404         ddsMipLevel->AddRef();
00405 
00406         /* While we can get a next level in the mip-map chain. */
00407         while( ddsMipLevel->GetAttachedSurface( &ddsCaps, &ddsNextLevel ) == DD_OK )
00408         {
00409             /* Calculate the destination rect. */
00410             RECT mipRect = { 
00411                 texRect.left >> mipLevel,
00412                 texRect.top  >> mipLevel,
00413                 texRect.right >> mipLevel,
00414                 texRect.bottom >> mipLevel
00415             };
00416 
00417             /* Blit using D3DX in order to use bilinear filtering. */
00418             D3DXLoadTextureFromSurface(
00419                 mD3DDevice,
00420                 ddsNextLevel,
00421                 0,
00422                 mSurface,
00423                 (RECT*)&texRect,
00424                 (RECT*)&mipRect,
00425                 D3DX_FT_LINEAR );
00426 
00427             /* Release the current level and get the next one, incrementing the mip depth. */
00428             ddsMipLevel->Release();
00429             ddsMipLevel = ddsNextLevel;
00430             mipLevel++;
00431         }
00432 
00433         /* Release the last mip-map level surface. */
00434         ddsMipLevel->Release();
00435 
00436         /* Release the temporary surface. */
00437         pddsTempSurface->Release();
00438 
00439         OgreUnguard();
00440     }
00441     //---------------------------------------------------------------------------------------------
00442 HRESULT WINAPI testEnumAtt( 
00443   LPDIRECTDRAWSURFACE7 lpDDSurface,  
00444   LPDDSURFACEDESC2 desc,  
00445   LPVOID lpContext                  
00446 )
00447 {
00448     if (desc->dwWidth == 512)
00449     {
00450         int i = 0;
00451         i = 1;
00452     }
00453     return DDENUMRET_OK;
00454 
00455 }
00456 
00457     void D3DTexture::blitImage3D( const Image src[], 
00458             const Image::Rect imgRect, const Image::Rect texRect )
00459     {
00460         OgreGuard( "D3DTexture::blitImage3D" );
00461 
00462         HRESULT hr;
00463 
00464         //mSurface->EnumAttachedSurfaces(NULL, testEnumAtt);
00465 
00466 
00467         for (size_t face = 0; face < 6; ++face)
00468         {
00469             /* We need a temporary surface in which to load the image data. */
00470             LPDIRECTDRAWSURFACE7 pddsTempSurface;
00471             D3DX_SURFACEFORMAT surfFmt, texFmt;
00472             /* Compute the pixel format for the image. */
00473             if( src[face].getBPP() == 16 )
00474             {
00475                 if( src[face].getHasAlpha() )
00476                     surfFmt = D3DX_SF_A4R4G4B4;
00477                 else
00478                     surfFmt = D3DX_SF_R5G6B5;
00479             }
00480             else
00481             {
00482                 if( src[face].getHasAlpha() )
00483                     surfFmt = D3DX_SF_A8R8G8B8;
00484                 else
00485                     surfFmt = D3DX_SF_R8G8B8;
00486             }
00487 
00488             /* Compute the current pixel format of the texture. */
00489             if( mFinalBpp == 16 )
00490             {
00491                 if( mHasAlpha )
00492                     texFmt = D3DX_SF_A4R4G4B4;
00493                 else
00494                     texFmt = D3DX_SF_R5G6B5;
00495             }
00496             else
00497             {
00498                 if( mHasAlpha )
00499                     texFmt = D3DX_SF_A8R8G8B8;
00500                 else
00501                     texFmt = D3DX_SF_R8G8B8;
00502             }
00503 
00504             /* Oh, you, endianness! How thy beauty never ceases to amaze me. NOT! 
00505             In other words we need to create a temporary image in which we can
00506             convert the data (and also apply gamma transformation). */
00507             Image tempImg( src[face] );
00508             Image::applyGamma( tempImg.getData(), mGamma, static_cast< uint >( tempImg.getSize() ), tempImg.getBPP() );
00509             {
00510                 /* Scoping in order to get rid of the local vars. */
00511                 uchar *c = tempImg.getData();
00512                 for( uint i = 0; i < src[face].getSize(); i+= src[face].getBPP() >> 3, c += src[face].getBPP() >> 3 )
00513                 {
00514                     uchar tmp;
00515 
00516                     if( src[face].getBPP() == 16 )
00517                     {
00518                         tmp = c[0]; c[0] = c[1]; c[1] = tmp;
00519                     }
00520                     else
00521                     {
00522                         tmp = c[0]; c[0] = c[2]; c[2] = tmp;
00523                     }
00524                 }
00525             }
00526 
00527             /* We generate the mip-maps by hand. */
00528             DWORD mipFlag, numMips;
00529             mipFlag = D3DX_TEXTURE_NOMIPMAP;
00530 
00531             /* Set the width and height. */
00532             DWORD dwWidth = src[face].getWidth(), dwHeight = src[face].getHeight();
00533 
00534             /* Create the temporary surface. */
00535             if( FAILED( hr = D3DXCreateTexture(
00536                 mD3DDevice,
00537                 NULL,
00538                 &dwWidth,
00539                 &dwHeight,
00540                 &texFmt,
00541                 NULL,
00542                 &pddsTempSurface,
00543                 &numMips ) ) )
00544             {
00545                 Except( hr, "Error during blit operation.", "D3DTexture::blitImage" );
00546             }
00547 
00548             /* Load the image into the temporary surface. */
00549             if( FAILED( hr = D3DXLoadTextureFromMemory(
00550                 mD3DDevice,
00551                 pddsTempSurface,
00552                 D3DX_DEFAULT,
00553                 tempImg.getData(),
00554                 NULL,
00555                 surfFmt,
00556                 D3DX_DEFAULT,
00557                 NULL,
00558                 D3DX_FT_LINEAR ) ) )
00559             {
00560                 pddsTempSurface->Release();
00561                 Except( hr, "Error during blit operation.", "D3DTexture::blitImage" );
00562             }
00563 
00564             /* We have to make sure that the source image wasn't stretched during the loading. */
00565             Image::Rect finalRect;
00566 
00567             Real fHeightFactor = Real( dwHeight ) / Real( src[face].getHeight() );
00568             Real fWidthFactor = Real( dwWidth ) / Real( src[face].getWidth() );
00569 
00570             finalRect.bottom = Real( imgRect.bottom ) * fHeightFactor;
00571             finalRect.top    = Real( imgRect.top )    * fHeightFactor;
00572             finalRect.left   = Real( imgRect.left )   * fWidthFactor;
00573             finalRect.right  = Real( imgRect.right )  * fWidthFactor;
00574 
00575             // Get cube map face to blit to
00576             LPDIRECTDRAWSURFACE7 pCubeFace;
00577             DDSCAPS2 cubeCaps;
00578             ZeroMemory(&cubeCaps, sizeof(DDSCAPS2));
00579             switch (face)
00580             {
00581             case 0:
00582                 // left
00583 
00584                 // WTF???
00585                 // If we try to retrieve DDSCAPS2_CUBEMAP_POSITIVEX we actually get
00586                 // the FIRST MIPMAP of the +X cubemap surface and we fail on exit
00587                 // the size is wrong
00588                 // IS THIS A D3D7 BUG??
00589                 // The below hack to get around it for now but leaves surface blank
00590                 //continue;
00591                 //
00592                 cubeCaps.dwCaps2 = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX;
00593                 break;
00594             case 1:
00595                 // right
00596                 cubeCaps.dwCaps2 = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEX;
00597                 break;
00598             case 2:
00599                 // up
00600                 cubeCaps.dwCaps2 = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEY;
00601                 break;
00602             case 3:
00603                 // down
00604                 cubeCaps.dwCaps2 = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEY;
00605                 break;
00606             case 4:
00607                 // front - NB DirectX is backwards
00608                 cubeCaps.dwCaps2 = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEZ;
00609                 break;
00610             case 5:
00611                 // back - NB DirectX is backwards
00612                 cubeCaps.dwCaps2 = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEZ;
00613                 break;
00614             }
00615 
00616             if (FAILED(hr = mSurface->GetAttachedSurface( &cubeCaps, &pCubeFace)))
00617             {
00618                 pddsTempSurface->Release();
00619                 Except( hr, "Error getting cube face surface.", "D3DTexture::blitImage" );
00620             }
00621 
00622             if( FAILED( hr = pCubeFace->Blt(
00623                 NULL,
00624                 pddsTempSurface, 
00625                 NULL,
00626                 DDBLT_WAIT,
00627                 NULL ) ) )
00628             {
00629                 pddsTempSurface->Release();
00630                 char msg[256];
00631                 D3DXGetErrorString(hr, 256, msg);
00632                 Except( hr, String("Error during blit operation: ") + msg, "D3DTexture::blitImage" );
00633             }
00634 
00636             
00637             LPDIRECTDRAWSURFACE7 ddsMipLevel, ddsNextLevel;
00638             DDSCAPS2 ddsCaps;
00639             HRESULT mipRes = DD_OK;
00640             uint mipLevel = 1;
00641 
00642             ZeroMemory(&ddsCaps, sizeof(DDSCAPS2));
00643             ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_MIPMAP;
00644 
00645             // Get the base level and increae the reference count. 
00646             ddsMipLevel = pCubeFace;
00647             ddsMipLevel->AddRef();
00648 
00650             while( ddsMipLevel->GetAttachedSurface( &ddsCaps, &ddsNextLevel ) == DD_OK )
00651             {
00652                 // Calculate the destination rect. 
00653                 RECT mipRect = { 
00654                     texRect.left >> mipLevel,
00655                     texRect.top  >> mipLevel,
00656                     texRect.right >> mipLevel,
00657                     texRect.bottom >> mipLevel
00658                 };
00659 
00660                 // Blit using D3DX in order to use bilinear filtering. 
00661                 D3DXLoadTextureFromSurface(
00662                     mD3DDevice,
00663                     ddsNextLevel,
00664                     0,
00665                     pCubeFace,
00666                     (RECT*)&texRect,
00667                     (RECT*)&mipRect,
00668                     D3DX_FT_LINEAR );
00669 
00670                 // Release the current level and get the next one, incrementing the mip depth. 
00671                 ddsMipLevel->Release();
00672                 ddsMipLevel = ddsNextLevel;
00673                 mipLevel++;
00674             }
00675 
00676             // Release the last mip-map level surface. 
00677             ddsMipLevel->Release();
00678             
00679         }
00680         OgreUnguard();
00681     }
00682 
00683     //---------------------------------------------------------------------------------------------
00684     void D3DTexture::copyToTexture( Texture * target )
00685     {
00686         HRESULT hr;
00687         D3DTexture * other;
00688 
00689         if( target->getUsage() != mUsage )
00690             return;
00691 
00692         other = reinterpret_cast< D3DTexture * >( target );
00693 
00694         //if( FAILED( hr = other->getDDSurface()->BltFast( 0, 0, mSurface, NULL, DDBLTFAST_WAIT ) ) )
00695         if( FAILED( hr = other->getDDSurface()->Blt( NULL, mSurface, NULL, DDBLT_WAIT, NULL ) ) )
00696         {
00697             Except( Exception::ERR_RENDERINGAPI_ERROR, "Couldn't blit!", "" );
00698         }
00699     }
00700 
00701     //---------------------------------------------------------------------------------------------
00702     void D3DTexture::loadImage( const Image & img )
00703     {
00704         OgreGuard( "D3DTexture::loadImage" );
00705 
00706         if( mIsLoaded )
00707             unload();
00708 
00709         LogManager::getSingleton().logMessage( 
00710             LML_TRIVIAL,
00711             "D3DTexture: Loading %s with %d mipmaps from Image.", 
00712             Texture::mName.c_str(), mNumMipMaps );
00713 
00714         /* Get parameters from the Image */
00715         mHasAlpha = img.getHasAlpha();
00716         mSrcWidth = img.getWidth();
00717         mSrcHeight = img.getHeight();
00718         mSrcBpp = img.getBPP();
00719         mFormat = img.getFormat();
00720 
00721         /* Now that we have the image's parameters, create the D3D surface based on them. */
00722         createSurface();
00723 
00724         /* Blit to the image. This also creates the mip-maps and applies gamma. */
00725         blitImage( 
00726             img, 
00727             Image::Rect( 0, 0, mSrcWidth, mSrcHeight ),
00728             Image::Rect( 0, 0, Texture::mWidth, Texture::mHeight ) );
00729         
00730         unsigned short bytesPerPixel = mFinalBpp >> 3;
00731         if( !mHasAlpha && mFinalBpp == 32 )
00732         {
00733             bytesPerPixel--;
00734         }
00735         mSize = Texture::mWidth * Texture::mHeight * bytesPerPixel;
00736 
00737         mIsLoaded = true;
00738 
00739         OgreUnguard();
00740     }
00741     //---------------------------------------------------------------------------------------------
00742     void D3DTexture::loadImage3D( const Image imgs[] )
00743     {
00744         OgreGuard( "D3DTexture::loadImage" );
00745 
00746         if( mIsLoaded )
00747             unload();
00748 
00749         LogManager::getSingleton().logMessage( 
00750             LML_TRIVIAL,
00751             "D3DTexture: Loading cubemap %s with %d mipmaps from Image.", 
00752             Texture::mName.c_str(), mNumMipMaps );
00753 
00754         /* Get parameters from Image[0] (they are all the same) */
00755         mHasAlpha = imgs[0].getHasAlpha();
00756         mSrcWidth = imgs[0].getWidth();
00757         mSrcHeight = imgs[0].getHeight();
00758         mSrcBpp = imgs[0].getBPP();
00759         mFormat = imgs[0].getFormat();
00760 
00761         /* Now that we have the image's parameters, create the D3D surface based on them. */
00762         createSurface();
00763 
00764         /* Blit to the image. This also creates the mip-maps and applies gamma. */
00765         blitImage3D( 
00766             imgs, 
00767             Image::Rect( 0, 0, mSrcWidth, mSrcHeight ),
00768             Image::Rect( 0, 0, Texture::mWidth, Texture::mHeight ) );
00769         
00770         unsigned short bytesPerPixel = mFinalBpp >> 3;
00771         if( !mHasAlpha && mFinalBpp == 32 )
00772         {
00773             bytesPerPixel--;
00774         }
00775         mSize = Texture::mWidth * Texture::mHeight * bytesPerPixel;
00776 
00777         mIsLoaded = true;
00778 
00779         OgreUnguard();
00780     }
00781     //---------------------------------------------------------------------------------------------
00782     void D3DTexture::load(void)
00783     {
00784         if( mIsLoaded )
00785             return;
00786 
00787         if( mUsage == TU_DEFAULT )
00788         {
00789             if (mTextureType == TEX_TYPE_CUBE_MAP)
00790             {
00791                 _constructCubeFaceNames(mName);
00792                 Image imgs[6];
00793                 for (int face = 0; face < 6; ++face)
00794                 {
00795                     imgs[face].load(mCubeFaceNames[face]);
00796                 }
00797                 loadImage3D(imgs);
00798 
00799             }
00800             else
00801             {
00802                 Image img;
00803                 img.load( Texture::mName );
00804                 
00805                 loadImage( img );
00806             }
00807         }
00808         else if( mUsage == TU_RENDERTARGET )
00809         {
00810             mSrcWidth = mSrcHeight = 512;
00811             mSrcBpp = mFinalBpp;
00812             createSurface();
00813         }
00814 
00815         mIsLoaded = true;
00816     }
00817 
00818     //---------------------------------------------------------------------------------------------
00819     void D3DTexture::unload()
00820     {
00821         if( mIsLoaded )
00822         {
00823             __safeRelease( &mSurface );
00824             mIsLoaded = false;
00825         }
00826     }
00827     //---------------------------------------------------------------------------------------------
00828     void D3DTexture::_chooseD3DFormat(DDPIXELFORMAT &ddpf)
00829     {
00830         /* The pixel format is always RGB */
00831         ddpf.dwFlags = DDPF_RGB;
00832         ddpf.dwRGBBitCount = mFinalBpp;
00833         
00834         if( mHasAlpha )
00835         {
00836             ddpf.dwFlags |= DDPF_ALPHAPIXELS;
00837         }
00838 
00839         /* Compute the bit masks */
00840         if( mFinalBpp == 16 )
00841         {
00842             if( mHasAlpha )
00843             {
00844                 /* 4-4-4-4 ARGB */
00845                 ddpf.dwRGBAlphaBitMask = 0xf000;
00846                 ddpf.dwRBitMask        = 0x0f00;
00847                 ddpf.dwGBitMask        = 0x00f0;
00848                 ddpf.dwBBitMask        = 0x000f;
00849             }
00850             else
00851             {
00852                 /* 5-6-5 RGB */
00853                 ddpf.dwRBitMask = 0xf800;
00854                 ddpf.dwGBitMask = 0x07e0;
00855                 ddpf.dwBBitMask = 0x001f;
00856             }
00857         }
00858         else
00859         {
00860             if( mHasAlpha )
00861             {
00862                 /* 8-8-8-8 ARGB */
00863                 ddpf.dwRGBAlphaBitMask = 0xff000000;
00864                 ddpf.dwRBitMask        = 0x00ff0000;
00865                 ddpf.dwGBitMask        = 0x0000ff00;
00866                 ddpf.dwBBitMask        = 0x000000ff;
00867             }
00868             else
00869             {
00870                 /* 8-8-8 RGB */
00871                 ddpf.dwRBitMask        = 0xff0000;
00872                 ddpf.dwGBitMask        = 0x00ff00;
00873                 ddpf.dwBBitMask        = 0x0000ff;
00874             }
00875         }
00876     }
00877     //---------------------------------------------------------------------------------------------
00878     void D3DTexture::createSurface(void)
00879     {
00880 
00881         if (mTextureType == TEX_TYPE_CUBE_MAP)
00882         {
00883             createSurface3D();
00884         }
00885         else
00886         {
00887             createSurface2D();
00888         }
00889     }
00890     //---------------------------------------------------------------------------------------------
00891     void D3DTexture::createSurface2D(void)
00892     {
00893         D3DDEVICEDESC7 ddDesc;
00894         ZeroMemory( &ddDesc, sizeof(D3DDEVICEDESC7) );
00895 
00896         if( FAILED( mD3DDevice->GetCaps( &ddDesc ) ) )
00897             Except( Exception::ERR_RENDERINGAPI_ERROR, 
00898                     "Could not retrieve Direct3D Device caps.",
00899                     "D3DTexture::createSurfaces" );
00900 
00901         // Create a surface descriptor.
00902         DDSURFACEDESC2 ddsd;
00903         D3DUtil_InitSurfaceDesc( ddsd );
00904 
00905         ddsd.dwSize          = sizeof(DDSURFACEDESC2);
00906         ddsd.dwFlags         = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
00907         ddsd.ddsCaps.dwCaps  = DDSCAPS_TEXTURE;
00908         ddsd.ddsCaps.dwCaps2 = 0;
00909         ddsd.dwWidth         = mSrcWidth;
00910         ddsd.dwHeight        = mSrcHeight;
00911 
00912         /* If the texture is a render target, set the corresponding flags */
00913         if( mUsage == TU_RENDERTARGET )
00914         {
00915             ddsd.ddsCaps.dwCaps |= DDSCAPS_3DDEVICE | DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY;
00916             ddsd.ddsCaps.dwCaps2 = 0;
00917             mNumMipMaps = 0;
00918         }
00919         else
00920         {
00921             ddsd.ddsCaps.dwCaps2 = DDSCAPS2_D3DTEXTUREMANAGE;
00922         }
00923         
00924         /* If we want to have mip-maps, set the flags. Note that if the
00925            texture is the render target type mip-maps are automatically 
00926            disabled. */
00927         if( mNumMipMaps )
00928         {
00929             ddsd.dwFlags |= DDSD_MIPMAPCOUNT;
00930             ddsd.dwMipMapCount = mNumMipMaps;
00931 
00932             ddsd.ddsCaps.dwCaps |= DDSCAPS_MIPMAP | DDSCAPS_COMPLEX;            
00933         }
00934 
00935         _chooseD3DFormat(ddsd.ddpfPixelFormat);
00936 
00937         /* Change texture size so that it is a power of 2, if needed. */
00938         if( ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2 )
00939         {
00940             for( ddsd.dwWidth = 1; mSrcWidth > ddsd.dwWidth; ddsd.dwWidth <<= 1 );
00941             for( ddsd.dwHeight = 1; mSrcHeight > ddsd.dwHeight; ddsd.dwHeight <<= 1 );
00942         }
00943 
00944         /* Change texture size so that it is square, if needed. Note that we made it a
00945            power of 2 in the above test, so here we just have to find the bigger dimension
00946            and make it the side length. */
00947         if( ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY )
00948         {
00949             if( ddsd.dwWidth > ddsd.dwHeight ) 
00950                 ddsd.dwHeight = ddsd.dwWidth;
00951             else                               
00952                 ddsd.dwWidth  = ddsd.dwHeight;
00953         }
00954 
00955         /* Register the possibly modified dimensions. */
00956         mWidth = ddsd.dwWidth;
00957         mHeight = ddsd.dwHeight;
00958         mIsLoaded = true;
00959 
00960         LPDIRECTDRAWSURFACE7 pddsRender;
00961         LPDIRECTDRAW7        pDD;
00962 
00963         /* Get a DirectDraw interface. */
00964         mD3DDevice->GetRenderTarget( &pddsRender );
00965         pddsRender->GetDDInterface( (VOID**)&pDD );
00966         pddsRender->Release();
00967 
00968         if( mUsage == TU_RENDERTARGET )
00969         {
00970             /* Get the pixel format of the primary surface - we need it because
00971                render target surfaces need to have the same pixel format. */
00972             IDirectDrawSurface7 * pddsPrimarySurface;
00973             pDD->GetGDISurface( &pddsPrimarySurface );
00974             pddsPrimarySurface->GetPixelFormat( &( ddsd.ddpfPixelFormat ) );
00975             pddsPrimarySurface->Release();
00976         }
00977 
00978         HRESULT hr;
00979 
00980         /* Now create the surface. */
00981         if( FAILED( hr = pDD->CreateSurface( &ddsd, &mSurface, NULL ) ) )
00982         {
00983             pDD->Release();
00984             Except( hr,
00985                 "Could not create DirectDraw surface.",
00986                 "D3DTexture::createSurfaces" );
00987         }
00988 
00989         if( mUsage == TU_RENDERTARGET )
00990         {
00991             LPDIRECTDRAWSURFACE7 pddsZBuffer, pddsBackBuffer, pddsTexZBuffer;
00992 
00993             DDSCAPS2 ZBuffDDSCaps;
00994             DDSURFACEDESC2 ZBuffDDSD;
00995 
00996             ZBuffDDSCaps.dwCaps = DDSCAPS_ZBUFFER;
00997             ZBuffDDSCaps.dwCaps2 = ZBuffDDSCaps.dwCaps3 = ZBuffDDSCaps.dwCaps4 = 0;
00998 
00999             memset( &ZBuffDDSD, 0, sizeof( DDSURFACEDESC2 ) );
01000             ZBuffDDSD.dwSize = sizeof( DDSURFACEDESC2 );
01001 
01002             /* If the primary surface has an attached z-buffer, we need one for our texture
01003                too. Here, we get the primary surface's z-buffer format and we create a new
01004                Z-buffer that we attach to the our texture. */
01005             if( SUCCEEDED( mD3DDevice->GetRenderTarget( &pddsBackBuffer ) ) )
01006             {
01007                 if( SUCCEEDED( pddsBackBuffer->GetAttachedSurface( &ZBuffDDSCaps, &pddsZBuffer ) ) )
01008                 {
01009                     pddsZBuffer->GetSurfaceDesc( &ZBuffDDSD );
01010 
01011                     /* Our new Z-buffer should have the size of the new render target. */
01012                     ZBuffDDSD.dwWidth = ddsd.dwWidth;
01013                     ZBuffDDSD.dwHeight = ddsd.dwHeight;
01014 
01015                     hr = pDD->CreateSurface( &ZBuffDDSD, &pddsTexZBuffer, NULL );
01016                     hr = mSurface->AddAttachedSurface( pddsTexZBuffer );
01017 
01018                     pddsBackBuffer->Release();
01019                     pddsZBuffer->Release();
01020                     pddsTexZBuffer->Release();
01021                 }
01022             }
01023         }
01024 
01025         /* Release the DirectDraw interface used in the surface creation */
01026         pDD->Release();
01027     }
01028     //---------------------------------------------------------------------------------------------
01029     void D3DTexture::createSurface3D(void)
01030     {
01031         D3DDEVICEDESC7 ddDesc;
01032         ZeroMemory( &ddDesc, sizeof(D3DDEVICEDESC7) );
01033 
01034         if( FAILED( mD3DDevice->GetCaps( &ddDesc ) ) )
01035             Except( Exception::ERR_RENDERINGAPI_ERROR, 
01036                     "Could not retrieve Direct3D Device caps.",
01037                     "D3DTexture::createSurfaces" );
01038 
01039         // Create a surface descriptor.
01040         DDSURFACEDESC2 ddsd;
01041         D3DUtil_InitSurfaceDesc( ddsd );
01042 
01043         ddsd.dwSize          = sizeof(DDSURFACEDESC2);
01044         ddsd.dwFlags         = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
01045         ddsd.ddsCaps.dwCaps  = DDSCAPS_COMPLEX | DDSCAPS_TEXTURE;
01046         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP|DDSCAPS2_CUBEMAP_ALLFACES;
01047         ddsd.dwWidth         = mSrcWidth;
01048         ddsd.dwHeight        = mSrcHeight;
01049 
01050         /* If the texture is a render target, set the corresponding flags */
01051         if( mUsage == TU_RENDERTARGET )
01052         {
01053             ddsd.ddsCaps.dwCaps |= DDSCAPS_3DDEVICE | DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY;
01054             mNumMipMaps = 0;
01055         }
01056         else
01057         {
01058             ddsd.ddsCaps.dwCaps2 |= DDSCAPS2_D3DTEXTUREMANAGE;
01059         }
01060         
01061         /* If we want to have mip-maps, set the flags. Note that if the
01062            texture is the render target type mip-maps are automatically 
01063            disabled. */
01064         if( mNumMipMaps )
01065         {
01066             ddsd.dwFlags |= DDSD_MIPMAPCOUNT;
01067             ddsd.dwMipMapCount = mNumMipMaps;
01068 
01069             ddsd.ddsCaps.dwCaps |= DDSCAPS_MIPMAP;            
01070         }
01071 
01072         _chooseD3DFormat(ddsd.ddpfPixelFormat);
01073 
01074         /* Change texture size so that it is a power of 2, if needed. */
01075         if( ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2 )
01076         {
01077             for( ddsd.dwWidth = 1; mSrcWidth > ddsd.dwWidth; ddsd.dwWidth <<= 1 );
01078             for( ddsd.dwHeight = 1; mSrcHeight > ddsd.dwHeight; ddsd.dwHeight <<= 1 );
01079         }
01080 
01081         /* Change texture size so that it is square, if needed. Note that we made it a
01082            power of 2 in the above test, so here we just have to find the bigger dimension
01083            and make it the side length. */
01084         if( ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY )
01085         {
01086             if( ddsd.dwWidth > ddsd.dwHeight ) 
01087                 ddsd.dwHeight = ddsd.dwWidth;
01088             else                               
01089                 ddsd.dwWidth  = ddsd.dwHeight;
01090         }
01091 
01092         /* Register the possibly modified dimensions. */
01093         mWidth = ddsd.dwWidth;
01094         mHeight = ddsd.dwHeight;
01095         mIsLoaded = true;
01096 
01097 
01098         LPDIRECTDRAWSURFACE7 pddsRender;
01099         LPDIRECTDRAW7        pDD;
01100 
01101         /* Get a DirectDraw interface. */
01102         mD3DDevice->GetRenderTarget( &pddsRender );
01103         pddsRender->GetDDInterface( (VOID**)&pDD );
01104         pddsRender->Release();
01105 
01106         if( mUsage == TU_RENDERTARGET )
01107         {
01108             /* Get the pixel format of the primary surface - we need it because
01109                render target surfaces need to have the same pixel format. */
01110             IDirectDrawSurface7 * pddsPrimarySurface;
01111             pDD->GetGDISurface( &pddsPrimarySurface );
01112             pddsPrimarySurface->GetPixelFormat( &( ddsd.ddpfPixelFormat ) );
01113             pddsPrimarySurface->Release();
01114         }
01115 
01116         HRESULT hr;
01117 
01118         /* Now create the surface. */
01119         if( FAILED( hr = pDD->CreateSurface( &ddsd, &mSurface, NULL ) ) )
01120         {
01121             pDD->Release();
01122             Except( hr,
01123                 "Could not create DirectDraw surface.",
01124                 "D3DTexture::createSurfaces" );
01125         }
01126 
01127 
01128         if( mUsage == TU_RENDERTARGET )
01129         {
01130             LPDIRECTDRAWSURFACE7 pddsZBuffer, pddsBackBuffer, pddsTexZBuffer;
01131 
01132             DDSCAPS2 ZBuffDDSCaps;
01133             DDSURFACEDESC2 ZBuffDDSD;
01134 
01135             ZBuffDDSCaps.dwCaps = DDSCAPS_ZBUFFER;
01136             ZBuffDDSCaps.dwCaps2 = ZBuffDDSCaps.dwCaps3 = ZBuffDDSCaps.dwCaps4 = 0;
01137 
01138             memset( &ZBuffDDSD, 0, sizeof( DDSURFACEDESC2 ) );
01139             ZBuffDDSD.dwSize = sizeof( DDSURFACEDESC2 );
01140 
01141             /* If the primary surface has an attached z-buffer, we need one for our texture
01142                too. Here, we get the primary surface's z-buffer format and we create a new
01143                Z-buffer that we attach to the our texture. */
01144             if( SUCCEEDED( mD3DDevice->GetRenderTarget( &pddsBackBuffer ) ) )
01145             {
01146                 if( SUCCEEDED( pddsBackBuffer->GetAttachedSurface( &ZBuffDDSCaps, &pddsZBuffer ) ) )
01147                 {
01148                     pddsZBuffer->GetSurfaceDesc( &ZBuffDDSD );
01149 
01150                     /* Our new Z-buffer should have the size of the new render target. */
01151                     ZBuffDDSD.dwWidth = ddsd.dwWidth;
01152                     ZBuffDDSD.dwHeight = ddsd.dwHeight;
01153 
01154                     hr = pDD->CreateSurface( &ZBuffDDSD, &pddsTexZBuffer, NULL );
01155                     hr = mSurface->AddAttachedSurface( pddsTexZBuffer );
01156 
01157                     pddsBackBuffer->Release();
01158                     pddsZBuffer->Release();
01159                     pddsTexZBuffer->Release();
01160                 }
01161             }
01162         }
01163 
01164         /* Release the DirectDraw interface used in the surface creation */
01165         pDD->Release();
01166     }
01167     //---------------------------------------------------------------------------------------------
01168     LPDIRECTDRAWSURFACE7 D3DTexture::getDDSurface(void)
01169     {
01170         return mSurface;
01171     }
01172     void D3DTexture::_constructCubeFaceNames(const String name)
01173     {
01174         // the suffixes
01175         String suffixes[6] = {"_rt", "_lf", "_up", "_dn", "_fr", "_bk"};
01176         size_t pos = -1;
01177 
01178         String ext; // the extension
01179         String baseName; // the base name
01180         String fakeName = name; // the 'fake' name, temp. holder
01181 
01182         // first find the base name
01183         pos = fakeName.find_last_of(".");
01184         if (pos == -1)
01185         {
01186             Except( Exception::ERR_INTERNAL_ERROR, "Invalid cube texture base name", "D3D9Texture::_constructCubeFaceNames" );
01187         }
01188 
01189         baseName = fakeName.substr(0, pos);
01190         ext = fakeName.substr(pos);
01191 
01192         // construct the full 6 faces file names from the baseName, suffixes and extension
01193         for (size_t i = 0; i < 6; ++i)
01194             mCubeFaceNames[i] = baseName + suffixes[i] + ext;
01195     }
01196 
01197 
01198 }
01199 

Copyright © 2002-2003 by The OGRE Team
Last modified Wed Jan 21 00:10:07 2004