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

OgreD3D9Texture.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 "OgreD3D9Texture.h"
00026 #include "OgreException.h"
00027 #include "OgreLogManager.h"
00028 #include "OgreStringConverter.h"
00029 #include "OgreBitwise.h"
00030 #include "OgreSDDataChunk.h"
00031 
00032 #include "OgreNoMemoryMacros.h"
00033 #include <d3dx9.h>
00034 #include <dxerr9.h>
00035 #include "OgreMemoryMacros.h"
00036 
00037 namespace Ogre 
00038 {
00039     /****************************************************************************************/
00040     D3D9Texture::D3D9Texture( const String& name, TextureType texType, IDirect3DDevice9 *pD3DDevice, TextureUsage usage )
00041     {
00042         // normal constructor
00043         this->_initMembers();
00044         // set the device and caps/formats
00045         this->_setDevice(pD3DDevice);
00046 
00047         mName = name;
00048         mTextureType = texType;
00049         mUsage = usage;
00050         mAutoGenMipMaps = false;
00051 
00052         if (this->getTextureType() == TEX_TYPE_CUBE_MAP)
00053             _constructCubeFaceNames(mName);
00054     }
00055     /****************************************************************************************/
00056     D3D9Texture::D3D9Texture( const String& name, TextureType texType, IDirect3DDevice9 *pD3DDevice, uint width, uint height, uint numMips, PixelFormat format, TextureUsage usage )
00057     {
00058         // this constructor is mainly used for RTT
00059         this->_initMembers();
00060         // set the device and caps/formats
00061         this->_setDevice(pD3DDevice);
00062 
00063         mName = name;
00064         mTextureType = texType;
00065         mUsage = usage;
00066         mNumMipMaps = numMips;
00067         mAutoGenMipMaps = false;
00068 
00069         if (this->getTextureType() == TEX_TYPE_CUBE_MAP)
00070             _constructCubeFaceNames(mName);
00071 
00072         this->_setSrcAttributes(width, height, 1, format);
00073         // if it's a render target we must 
00074         // create it right now, don't know why ???
00075         if (mUsage == TU_RENDERTARGET)
00076         {
00077             this->_createTex();
00078             mIsLoaded = true;
00079         }
00080     }
00081     /****************************************************************************************/
00082     D3D9Texture::~D3D9Texture()
00083     {
00084         if (this->isLoaded())
00085             unload();
00086         SAFE_RELEASE(mpD3D);
00087     }
00088     /****************************************************************************************/
00089     void D3D9Texture::blitImage(const Image& src, const Image::Rect imgRect, const Image::Rect texRect )
00090     {
00091         Except( Exception::UNIMPLEMENTED_FEATURE, "**** Blit image called but not implemented!!! ****", "D3D9Texture::blitImage" );
00092     }
00093     /****************************************************************************************/
00094     void D3D9Texture::blitToTexture( const Image &src, unsigned uStartX, unsigned uStartY )
00095     {
00096         /*
00097         This (as implemented currently) function is a combination of the various functions 
00098         that loadimage would call to apply a bitmap to a texture. But without some of the 
00099         overhead of the other functions. Mostly temp image class and the bitwise class used in
00100         conversion. Now, the elimination of the bitwise stuff makes a difference of 250+ fps.
00101         However, this sacrifises flexibility for speed. Some other things to note: 
00102             I'm not sure if standard windows bitmaps have the r & b inverted... But, the ones 
00103                 used for testing this (mainly ffmpeg stuff) do. SO they are swapped in the loop code.
00104             Also, the uStartX & Y have no effect. But are here because it has use in the OpenGL
00105                 version of this
00106             I think this is pretty straight forward... But if anyone has a better way, I would love
00107                 to see it. :>
00108         */
00109         const unsigned char* pSrc = src.getData();
00110         HRESULT hr;
00111         D3DFORMAT srcFormat = this->_getPF( src.getFormat() );
00112         D3DFORMAT dstFormat = _chooseD3DFormat();
00113         RECT tmpDataRect = {0, 0, src.getWidth(), src.getHeight()}; // the rectangle representing the src. image dim.
00114 
00115         // this surface will hold our temp conversion image
00116         IDirect3DSurface9 *pSrcSurface = NULL;
00117         hr = mpDev->CreateOffscreenPlainSurface( src.getWidth(), src.getHeight(), dstFormat, 
00118                         D3DPOOL_SCRATCH, &pSrcSurface, NULL);
00119         // check result and except if failed
00120         if (FAILED(hr))
00121         {
00122             this->_freeResources();
00123             Except( hr, "Error loading surface from memory", "D3D9Texture::_blitImageToTexture" );
00124         }
00125 
00126         //*** Actual copying code here ***//
00127         D3DSURFACE_DESC desc;
00128         D3DLOCKED_RECT rect;
00129         BYTE *pSurf8;
00130         BYTE *pBuf8 = (BYTE*)pSrc;
00131     
00132         // NOTE - dimensions of surface may differ from buffer
00133         // dimensions (e.g. power of 2 or square adjustments)
00134         // Lock surface
00135         pSrcSurface->GetDesc(&desc);
00136 
00137         // lock our surface to acces raw memory
00138         if( FAILED( hr = pSrcSurface->LockRect(&rect, NULL, D3DLOCK_NOSYSLOCK) ) )
00139         {
00140             Except( hr, "Unable to lock temp texture surface", "D3D9Texture::_copyMemoryToSurface" );
00141             this->_freeResources();
00142             SAFE_RELEASE(pSrcSurface);
00143         }
00144         
00145         // loop through data and do conv.
00146         char r, g, b;
00147         unsigned int iRow, iCol;
00148 
00149         //XXX: This loop is a hack. But - it means the difference between ~20fps and ~300fps
00150         for( iRow = mSrcHeight - 1; iRow > 0; iRow-- )
00151         {
00152             // NOTE: Direct3D used texture coordinates where (0,0) is the TOP LEFT corner of texture
00153             // Everybody else (OpenGL, 3D Studio, etc) uses (0,0) as BOTTOM LEFT corner
00154             // So whilst we load, flip the texture in the Y-axis to compensate
00155             pSurf8 = (BYTE*)rect.pBits + ((mSrcHeight - iRow - 1) * rect.Pitch);
00156             for( iCol = 0; iCol < mSrcWidth; iCol++ )
00157             {
00158                 // Read RGBA values from buffer
00159                 if( mSrcBpp >= 24 )
00160                 {
00161                     r = *pBuf8++;
00162                     g = *pBuf8++;
00163                     b = *pBuf8++;
00164                 }
00165                 //r & b are swapped
00166                 *pSurf8++ = b;
00167                 *pSurf8++ = g;
00168                 *pSurf8++ = r;
00169                 
00170             } // for( iCol...
00171         } // for( iRow...
00172         // unlock the surface
00173         pSrcSurface->UnlockRect();
00174         
00175         //*** Copy to main surface here ***//
00176         IDirect3DSurface9 *pDstSurface; 
00177         hr = mpNormTex->GetSurfaceLevel(0, &pDstSurface);
00178 
00179         // check result and except if failed
00180         if (FAILED(hr))
00181         {
00182             SAFE_RELEASE(pSrcSurface);
00183             this->_freeResources();
00184             Except( hr, "Error getting level 0 surface from dest. texture", "D3D9Texture::_blitImageToTexture" );
00185         }
00186 
00187         // copy surfaces
00188         hr = D3DXLoadSurfaceFromSurface(pDstSurface, NULL, NULL, pSrcSurface, NULL, NULL, D3DX_DEFAULT, 0);
00189         // check result and except if failed
00190         if (FAILED(hr))
00191         {
00192             SAFE_RELEASE(pSrcSurface);
00193             SAFE_RELEASE(pDstSurface);
00194             this->_freeResources();
00195             Except( hr, "Error copying original surface to texture", "D3D9Texture::_blitImageToTexture" );
00196         }
00197 
00198         // Dirty the texture to force update
00199         mpNormTex->AddDirtyRect(NULL);
00200 
00201         // Mipmapping
00202         if (mAutoGenMipMaps)
00203         {
00204             hr = mpTex->SetAutoGenFilterType(_getBestFilterMethod());
00205             if (FAILED(hr))
00206             {
00207                 SAFE_RELEASE(pSrcSurface);
00208                 SAFE_RELEASE(pDstSurface);
00209                 this->_freeResources();
00210                 Except( hr, "Error generating mip maps", "D3D9Texture::_blitImageToNormTex" );
00211             }
00212             mpNormTex->GenerateMipSubLevels();
00213         }
00214         else
00215         {
00216             // Software mipmaps
00217             if( FAILED( hr = D3DXFilterTexture( mpNormTex, NULL, D3DX_DEFAULT, D3DX_DEFAULT ) ) )
00218             {
00219                 this->_freeResources();
00220                 Except( hr, "Failed to filter texture (generate mip maps)", "D3D9Texture::_blitToTexure" );
00221             }
00222         }
00223 
00224         SAFE_RELEASE(pDstSurface);
00225         SAFE_RELEASE(pSrcSurface);
00226     }
00227     /****************************************************************************************/
00228     void D3D9Texture::copyToTexture(Texture *target)
00229     {
00230         // check if this & target are the same format and type
00231         // blitting from or to cube textures is not supported yet
00232         if (target->getUsage() != this->getUsage() ||
00233             target->getTextureType() != this->getTextureType())
00234         {
00235             Except( Exception::ERR_INVALIDPARAMS, 
00236                     "Src. and dest. textures must be of same type and must have the same usage !!!", 
00237                     "D3D9Texture::copyToTexture" );
00238         }
00239 
00240         HRESULT hr;
00241         D3D9Texture *other;
00242         // get the target
00243         other = reinterpret_cast< D3D9Texture * >( target );
00244         // target rectangle (whole surface)
00245         RECT dstRC = {0, 0, other->getWidth(), other->getHeight()};
00246 
00247         // do it plain for normal texture
00248         if (this->getTextureType() == TEX_TYPE_2D)
00249         {
00250             // get our source surface
00251             IDirect3DSurface9 *pSrcSurface;
00252             if( FAILED( hr = mpNormTex->GetSurfaceLevel(0, &pSrcSurface) ) )
00253             {
00254                 String msg = DXGetErrorDescription9(hr);
00255                 Except( hr, "Couldn't blit : " + msg, "D3D9Texture::copyToTexture" );
00256             }
00257 
00258             // get our target surface
00259             IDirect3DSurface9 *pDstSurface;
00260             IDirect3DTexture9 *pOthTex = other->getNormTexture();
00261             if( FAILED( hr = pOthTex->GetSurfaceLevel(0, &pDstSurface) ) )
00262             {
00263                 String msg = DXGetErrorDescription9(hr);
00264                 Except( hr, "Couldn't blit : " + msg, "D3D9Texture::copyToTexture" );
00265                 SAFE_RELEASE(pSrcSurface);
00266             }
00267 
00268             // do the blit, it's called StretchRect in D3D9 :)
00269             if( FAILED( hr = mpDev->StretchRect( pSrcSurface, NULL, pDstSurface, &dstRC, D3DTEXF_NONE) ) )
00270             {
00271                 String msg = DXGetErrorDescription9(hr);
00272                 Except( hr, "Couldn't blit : " + msg, "D3D9Texture::copyToTexture" );
00273                 SAFE_RELEASE(pSrcSurface);
00274                 SAFE_RELEASE(pDstSurface);
00275             }
00276 
00277             // release temp. surfaces
00278             SAFE_RELEASE(pSrcSurface);
00279             SAFE_RELEASE(pDstSurface);
00280         }
00281         else if (this->getTextureType() == TEX_TYPE_CUBE_MAP)
00282         {
00283             // get the target cube texture
00284             IDirect3DCubeTexture9 *pOthTex = other->getCubeTexture();
00285             // blit to 6 cube faces
00286             for (size_t face = 0; face < 6; face++)
00287             {
00288                 // get our source surface
00289                 IDirect3DSurface9 *pSrcSurface;
00290                 if( FAILED( hr = mpCubeTex->GetCubeMapSurface((D3DCUBEMAP_FACES)face, 0, &pSrcSurface) ) )
00291                 {
00292                     String msg = DXGetErrorDescription9(hr);
00293                     Except( hr, "Couldn't blit : " + msg, "D3D9Texture::copyToTexture" );
00294                 }
00295 
00296                 // get our target surface
00297                 IDirect3DSurface9 *pDstSurface;
00298                 if( FAILED( hr = pOthTex->GetCubeMapSurface((D3DCUBEMAP_FACES)face, 0, &pDstSurface) ) )
00299                 {
00300                     String msg = DXGetErrorDescription9(hr);
00301                     Except( hr, "Couldn't blit : " + msg, "D3D9Texture::copyToTexture" );
00302                     SAFE_RELEASE(pSrcSurface);
00303                 }
00304 
00305                 // do the blit, it's called StretchRect in D3D9 :)
00306                 if( FAILED( hr = mpDev->StretchRect( pSrcSurface, NULL, pDstSurface, &dstRC, D3DTEXF_NONE) ) )
00307                 {
00308                     String msg = DXGetErrorDescription9(hr);
00309                     Except( hr, "Couldn't blit : " + msg, "D3D9Texture::copyToTexture" );
00310                     SAFE_RELEASE(pSrcSurface);
00311                     SAFE_RELEASE(pDstSurface);
00312                 }
00313 
00314                 // release temp. surfaces
00315                 SAFE_RELEASE(pSrcSurface);
00316                 SAFE_RELEASE(pDstSurface);
00317             }
00318         }
00319         else
00320         {
00321             Except( Exception::UNIMPLEMENTED_FEATURE, 
00322                     "Copy to texture is implemented only for 2D and cube textures !!!", 
00323                     "D3D9Texture::copyToTexture" );
00324         }
00325     }
00326     /****************************************************************************************/
00327     void D3D9Texture::loadImage( const Image &img )
00328     {
00329         assert(this->getTextureType() == TEX_TYPE_1D || this->getTextureType() == TEX_TYPE_2D);
00330 
00331         Image tImage(img); // our temp image
00332         HRESULT hr = S_OK; // D3D9 methods result
00333 
00334         // we need src image info
00335         this->_setSrcAttributes(tImage.getWidth(), tImage.getHeight(), 1, tImage.getFormat());
00336         // create a blank texture
00337         this->_createNormTex();
00338         // set gamma prior to blitting
00339         Image::applyGamma(tImage.getData(), this->getGamma(), (uint)tImage.getSize(), tImage.getBPP());
00340         this->_blitImageToNormTex(tImage);
00341         mIsLoaded = true;
00342     }
00343     /****************************************************************************************/
00344     void D3D9Texture::load()
00345     {
00346         // unload if loaded
00347         if (this->isLoaded())
00348             unload();
00349         
00350         if (mUsage == TU_RENDERTARGET)
00351         {
00352             this->_createTex();
00353             mIsLoaded = true;
00354             return;
00355         }
00356 
00357         // load based on tex.type
00358         switch (this->getTextureType())
00359         {
00360         case TEX_TYPE_1D:
00361         case TEX_TYPE_2D:
00362             this->_loadNormTex();
00363             break;
00364         case TEX_TYPE_3D:
00365             this->_loadVolumeTex();
00366             break;
00367         case TEX_TYPE_CUBE_MAP:
00368             this->_loadCubeTex();
00369             break;
00370         default:
00371             Except( Exception::ERR_INTERNAL_ERROR, "Unknown texture type", "D3D9Texture::load" );
00372             this->_freeResources();
00373         }
00374 
00375     }
00376     /****************************************************************************************/
00377     void D3D9Texture::unload()
00378     {
00379         // unload if it's loaded
00380         if (this->isLoaded())
00381         {
00382             this->_freeResources();
00383             mIsLoaded = false;
00384         }
00385     }
00386     /****************************************************************************************/
00387     void D3D9Texture::_freeResources()
00388     {
00389         SAFE_RELEASE(mpTex);
00390         SAFE_RELEASE(mpNormTex);
00391         SAFE_RELEASE(mpCubeTex);
00392         SAFE_RELEASE(mpZBuff);
00393     }
00394     /****************************************************************************************/
00395     void D3D9Texture::_loadCubeTex()
00396     {
00397         assert(this->getTextureType() == TEX_TYPE_CUBE_MAP);
00398 
00399         // DDS load?
00400         if (StringUtil::endsWith(getName(), ".dds"))
00401         {
00402             // find & load resource data
00403             SDDataChunk chunk;
00404             TextureManager::getSingleton()._findResourceData(this->getName(), chunk);
00405 
00406             HRESULT hr = D3DXCreateCubeTextureFromFileInMemory(
00407                 mpDev,
00408                 chunk.getPtr(),
00409                 chunk.getSize(),
00410                 &mpCubeTex);
00411 
00412             if (FAILED(hr))
00413             {
00414                 Except( hr, "Can't create cube texture", "D3D9Texture::_loadCubeTex" );
00415                 this->_freeResources();
00416             }
00417 
00418             hr = mpCubeTex->QueryInterface(IID_IDirect3DBaseTexture9, (void **)&mpTex);
00419 
00420             if (FAILED(hr))
00421             {
00422                 Except( hr, "Can't get base texture", "D3D9Texture::_loadCubeTex" );
00423                 this->_freeResources();
00424             }
00425 
00426             D3DSURFACE_DESC texDesc;
00427             mpCubeTex->GetLevelDesc(0, &texDesc);
00428             // set src and dest attributes to the same, we can't know
00429             _setSrcAttributes(texDesc.Width, texDesc.Height, 1, _getPF(texDesc.Format));
00430             _setFinalAttributes(texDesc.Width, texDesc.Height, 1,  _getPF(texDesc.Format));
00431 
00432             
00433         }
00434         else
00435         {
00436 
00437             // Load from 6 separate files
00438             // First create the base surface, for that we need to know the size
00439             Image img;
00440             img.load(this->_getCubeFaceName(0));
00441             _setSrcAttributes(img.getWidth(), img.getHeight(), 1, img.getFormat());
00442             // now create the texture
00443             this->_createCubeTex();
00444 
00445             HRESULT hr; // D3D9 methods result
00446 
00447             // load faces
00448             for (size_t face = 0; face < 6; face++)
00449             {
00450                 SDDataChunk chunk;
00451                 TextureManager::getSingleton()._findResourceData(
00452                     this->_getCubeFaceName(face), chunk);
00453                 
00454                 LPDIRECT3DSURFACE9 pDstSurface;
00455                 hr = mpCubeTex->GetCubeMapSurface((D3DCUBEMAP_FACES)face, 0, &pDstSurface);
00456                 if (FAILED(hr))
00457                 {
00458                     Except(Exception::ERR_INTERNAL_ERROR, "Cannot get cubemap surface", 
00459                         "D3D9Texture::_loadCubeTex");
00460                 }
00461 
00462                 // Load directly using D3DX
00463                 hr = D3DXLoadSurfaceFromFileInMemory(
00464                     pDstSurface,
00465                     NULL,                       // no palette
00466                     NULL,                       // entire surface
00467                     chunk.getPtr(),
00468                     chunk.getSize(),
00469                     NULL,                       // entire source
00470                     D3DX_DEFAULT,               // default filtering
00471                     0,                          // No colour key
00472                     NULL);                      // no src info
00473                         
00474                 if (FAILED(hr))
00475                 {
00476                     Except(Exception::ERR_INTERNAL_ERROR, "Cannot load cubemap surface", 
00477                         "D3D9Texture::_loadCubeTex");
00478                 }
00479 
00480             }
00481 
00482             // Mipmaps
00483             if (mAutoGenMipMaps)
00484             {
00485                 // use best filtering method supported by hardware
00486                 hr = mpTex->SetAutoGenFilterType(_getBestFilterMethod());
00487                 if (FAILED(hr))
00488                 {
00489                     this->_freeResources();
00490                     Except( hr, "Error generating mip maps", "D3D9Texture::_blitImageToCubeTex" );
00491                 }
00492                 mpCubeTex->GenerateMipSubLevels();
00493             }
00494             else
00495             {
00496                 // Software mipmaps
00497                 if( FAILED( hr = D3DXFilterTexture( mpCubeTex, NULL, D3DX_DEFAULT, D3DX_DEFAULT ) ) )
00498                 {
00499                     this->_freeResources();
00500                     Except( hr, "Failed to filter texture (generate mip maps)", "D3D9Texture::_blitImageToCubeTex" );
00501                 }
00502 
00503             }
00504 
00505             // Do final attributes
00506             D3DSURFACE_DESC texDesc;
00507             mpCubeTex->GetLevelDesc(0, &texDesc);
00508             _setFinalAttributes(texDesc.Width, texDesc.Height, 1,  _getPF(texDesc.Format));
00509         }
00510         mIsLoaded = true;
00511     }
00512     /****************************************************************************************/
00513     void D3D9Texture::_loadVolumeTex()
00514     {
00515         assert(this->getTextureType() == TEX_TYPE_3D);
00516 
00517         // find & load resource data
00518         SDDataChunk chunk;
00519         TextureManager::getSingleton()._findResourceData(this->getName(), chunk);
00520 
00521         HRESULT hr = D3DXCreateVolumeTextureFromFileInMemory(
00522             mpDev,
00523             chunk.getPtr(),
00524             chunk.getSize(),
00525             &mpVolumeTex);
00526 
00527         if (FAILED(hr))
00528         {
00529             Except(Exception::ERR_INTERNAL_ERROR, 
00530                 "Unable to load volume texture from " + this->getName(),
00531                 "D3D9Texture::_loadVolumeTex");
00532         }
00533 
00534         hr = mpVolumeTex->QueryInterface(IID_IDirect3DBaseTexture9, (void **)&mpTex);
00535 
00536         if (FAILED(hr))
00537         {
00538             Except( hr, "Can't get base texture", "D3D9Texture::_loadVolumeTex" );
00539             this->_freeResources();
00540         }
00541 
00542         D3DVOLUME_DESC texDesc;
00543         hr = mpVolumeTex->GetLevelDesc(0, &texDesc);
00544 
00545         // set src and dest attributes to the same, we can't know
00546         _setSrcAttributes(texDesc.Width, texDesc.Height, texDesc.Depth, _getPF(texDesc.Format));
00547         _setFinalAttributes(texDesc.Width, texDesc.Height, texDesc.Depth, _getPF(texDesc.Format));
00548         
00549         mIsLoaded = true;
00550     }
00551     /****************************************************************************************/
00552     void D3D9Texture::_loadNormTex()
00553     {
00554         assert(this->getTextureType() == TEX_TYPE_1D || this->getTextureType() == TEX_TYPE_2D);
00555 
00556         // Use D3DX
00557         // find & load resource data
00558         SDDataChunk chunk;
00559         TextureManager::getSingleton()._findResourceData(this->getName(), chunk);
00560 
00561         HRESULT hr = D3DXCreateTextureFromFileInMemory(
00562             mpDev,
00563             chunk.getPtr(),
00564             chunk.getSize(),
00565             &mpNormTex);
00566 
00567         if (FAILED(hr))
00568         {
00569             Except(Exception::ERR_INTERNAL_ERROR, 
00570                 "Unable to load texture from " + this->getName(),
00571                 "D3D9Texture::_loadNormTex");
00572         }
00573 
00574         hr = mpNormTex->QueryInterface(IID_IDirect3DBaseTexture9, (void **)&mpTex);
00575 
00576         if (FAILED(hr))
00577         {
00578             Except( hr, "Can't get base texture", "D3D9Texture::_loadNormTex" );
00579             this->_freeResources();
00580         }
00581 
00582         D3DSURFACE_DESC texDesc;
00583         mpNormTex->GetLevelDesc(0, &texDesc);
00584         // set src and dest attributes to the same, we can't know
00585         _setSrcAttributes(texDesc.Width, texDesc.Height, 1, _getPF(texDesc.Format));
00586         _setFinalAttributes(texDesc.Width, texDesc.Height, 1, _getPF(texDesc.Format));
00587         
00588         mIsLoaded = true;
00589     }
00590     /****************************************************************************************/
00591     void D3D9Texture::_createTex()
00592     {
00593         // if we are there then the source image dim. and format must already be set !!!
00594         assert(mSrcWidth > 0 || mSrcHeight > 0);
00595 
00596         // load based on tex.type
00597         switch (this->getTextureType())
00598         {
00599         case TEX_TYPE_1D:
00600         case TEX_TYPE_2D:
00601             this->_createNormTex();
00602             break;
00603         case TEX_TYPE_CUBE_MAP:
00604             this->_createCubeTex();
00605             break;
00606         default:
00607             Except( Exception::ERR_INTERNAL_ERROR, "Unknown texture type", "D3D9Texture::_createTex" );
00608             this->_freeResources();
00609         }
00610     }
00611     /****************************************************************************************/
00612     void D3D9Texture::_createNormTex()
00613     {
00614         // we must have those defined here
00615         assert(mSrcWidth > 0 || mSrcHeight > 0);
00616 
00617         // determine wich D3D9 pixel format we'll use
00618         HRESULT hr;
00619         D3DFORMAT d3dPF = (mUsage == TU_RENDERTARGET) ? mBBPixelFormat : this->_chooseD3DFormat();
00620 
00621         // Use D3DX to help us create the texture, this way it can adjust any relevant sizes
00622         DWORD usage = (mUsage == TU_RENDERTARGET) ? D3DUSAGE_RENDERTARGET : 0;
00623         UINT numMips = (mNumMipMaps ? mNumMipMaps : 1);
00624         // check if mip maps are supported on hardware
00625         if (mDevCaps.TextureCaps & D3DPTEXTURECAPS_MIPMAP)
00626         {
00627             // use auto.gen. if available
00628             mAutoGenMipMaps = this->_canAutoGenMipMaps(usage, D3DRTYPE_TEXTURE, d3dPF);
00629             if (mAutoGenMipMaps)
00630             {
00631                 usage |= D3DUSAGE_AUTOGENMIPMAP;
00632                 numMips = 0;
00633             }
00634         }
00635         else
00636         {
00637             // device don't support mip maps ???
00638             mNumMipMaps = 0;
00639             numMips = 1;
00640         }
00641 
00642         // create the texture
00643         hr = D3DXCreateTexture( 
00644                 mpDev,                              // device
00645                 mSrcWidth,                          // width
00646                 mSrcHeight,                         // height
00647                 numMips,                            // number of mip map levels
00648                 usage,                              // usage
00649                 d3dPF,                              // pixel format
00650                 (mUsage == TU_RENDERTARGET)?
00651                 D3DPOOL_DEFAULT : D3DPOOL_MANAGED,  // memory pool
00652                 &mpNormTex);                        // data pointer
00653         // check result and except if failed
00654         if (FAILED(hr))
00655         {
00656             Except( hr, "Error creating texture", "D3D9Texture::_createNormTex" );
00657             this->_freeResources();
00658         }
00659 
00660         // set final tex. attributes from tex. description
00661         // they may differ from the source image !!!
00662         D3DSURFACE_DESC desc;
00663         hr = mpNormTex->GetLevelDesc(0, &desc);
00664         if (FAILED(hr))
00665         {
00666             Except( hr, "Can't get texture description", "D3D9Texture::_createNormTex" );
00667             this->_freeResources();
00668         }
00669         this->_setFinalAttributes(desc.Width, desc.Height, 1, this->_getPF(desc.Format));
00670         
00671         // set the base texture we'll use in the render system
00672         hr = mpNormTex->QueryInterface(IID_IDirect3DBaseTexture9, (void **)&mpTex);
00673         if (FAILED(hr))
00674         {
00675             Except( hr, "Can't get base texture", "D3D9Texture::_createNormTex" );
00676             this->_freeResources();
00677         }
00678         
00679         // create a depth stencil if this is a render target
00680         if (mUsage == TU_RENDERTARGET)
00681             this->_createDepthStencil();
00682 
00683     }
00684     /****************************************************************************************/
00685     void D3D9Texture::_createCubeTex()
00686     {
00687         // we must have those defined here
00688         assert(mSrcWidth > 0 || mSrcHeight > 0);
00689 
00690         // determine wich D3D9 pixel format we'll use
00691         HRESULT hr;
00692         D3DFORMAT d3dPF = (mUsage == TU_RENDERTARGET) ? mBBPixelFormat : this->_chooseD3DFormat();
00693 
00694         // Use D3DX to help us create the texture, this way it can adjust any relevant sizes
00695         DWORD usage = (mUsage == TU_RENDERTARGET) ? D3DUSAGE_RENDERTARGET : 0;
00696         UINT numMips = (mNumMipMaps ? mNumMipMaps : 1);
00697         // check if mip map cube textures are supported
00698         if (mDevCaps.TextureCaps & D3DPTEXTURECAPS_MIPCUBEMAP)
00699         {
00700             // use auto.gen. if available
00701             mAutoGenMipMaps = this->_canAutoGenMipMaps(usage, D3DRTYPE_CUBETEXTURE, d3dPF);
00702             if (mAutoGenMipMaps)
00703             {
00704                 usage |= D3DUSAGE_AUTOGENMIPMAP;
00705                 numMips = 0;
00706             }
00707         }
00708         else
00709         {
00710             // no mip map support for this kind of textures :(
00711             mNumMipMaps = 0;
00712             numMips = 1;
00713         }
00714 
00715         // create the texture
00716         hr = D3DXCreateCubeTexture( 
00717                 mpDev,                              // device
00718                 mSrcWidth,                          // dimension
00719                 numMips,                            // number of mip map levels
00720                 usage,                              // usage
00721                 d3dPF,                              // pixel format
00722                 (mUsage == TU_RENDERTARGET)?
00723                 D3DPOOL_DEFAULT : D3DPOOL_MANAGED,  // memory pool
00724                 &mpCubeTex);                        // data pointer
00725         // check result and except if failed
00726         if (FAILED(hr))
00727         {
00728             Except( hr, "Error creating texture", "D3D9Texture::_createCubeTex" );
00729             this->_freeResources();
00730         }
00731 
00732         // set final tex. attributes from tex. description
00733         // they may differ from the source image !!!
00734         D3DSURFACE_DESC desc;
00735         hr = mpCubeTex->GetLevelDesc(0, &desc);
00736         if (FAILED(hr))
00737         {
00738             Except( hr, "Can't get texture description", "D3D9Texture::_createCubeTex" );
00739             this->_freeResources();
00740         }
00741         this->_setFinalAttributes(desc.Width, desc.Height, 1, this->_getPF(desc.Format));
00742 
00743         // set the base texture we'll use in the render system
00744         hr = mpCubeTex->QueryInterface(IID_IDirect3DBaseTexture9, (void **)&mpTex);
00745         if (FAILED(hr))
00746         {
00747             Except( hr, "Can't get base texture", "D3D9Texture::_createCubeTex" );
00748             this->_freeResources();
00749         }
00750         
00751         // create a depth stencil if this is a render target
00752         if (mUsage == TU_RENDERTARGET)
00753             this->_createDepthStencil();
00754 
00755     }
00756     /****************************************************************************************/
00757     void D3D9Texture::_initMembers()
00758     {
00759         mpDev = NULL;
00760         mpD3D = NULL;
00761         mpNormTex = NULL;
00762         mpCubeTex = NULL;
00763         mpZBuff = NULL;
00764         mpTex = NULL;
00765 
00766         for (size_t i = 0; i < 6; ++i)
00767             mCubeFaceNames[i] = "";
00768 
00769         mWidth = mHeight = mSrcWidth = mSrcHeight = 0;
00770         mIsLoaded = false;
00771     }
00772     /****************************************************************************************/
00773     void D3D9Texture::_setDevice(IDirect3DDevice9 *pDev)
00774     { 
00775         assert(pDev);
00776         mpDev = pDev;
00777         HRESULT hr;
00778 
00779         // get device caps
00780         hr = mpDev->GetDeviceCaps(&mDevCaps);
00781         if (FAILED(hr))
00782             Except( Exception::ERR_INTERNAL_ERROR, "Can't get device description", "D3D9Texture::_setDevice" );
00783 
00784         // get D3D pointer
00785         hr = mpDev->GetDirect3D(&mpD3D);
00786         if (FAILED(hr))
00787             Except( hr, "Failed to get D3D9 pointer", "D3D9Texture::_setDevice" );
00788 
00789         // get our device creation parameters
00790         hr = mpDev->GetCreationParameters(&mDevCreParams);
00791         if (FAILED(hr))
00792             Except( hr, "Failed to get D3D9 device creation parameters", "D3D9Texture::_setDevice" );
00793 
00794         // get our back buffer pixel format
00795         IDirect3DSurface9 *pSrf;
00796         D3DSURFACE_DESC srfDesc;
00797         hr = mpDev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pSrf);
00798         if (FAILED(hr))
00799             Except( hr, "Failed to get D3D9 device pixel format", "D3D9Texture::_setDevice" );
00800 
00801         hr = pSrf->GetDesc(&srfDesc);
00802         if (FAILED(hr))
00803         {
00804             Except( hr, "Failed to get D3D9 device pixel format", "D3D9Texture::_setDevice" );
00805             SAFE_RELEASE(pSrf);
00806         }
00807 
00808         mBBPixelFormat = srfDesc.Format;
00809         SAFE_RELEASE(pSrf);
00810     }
00811     /****************************************************************************************/
00812     void D3D9Texture::_constructCubeFaceNames(const String& name)
00813     {
00814         // the suffixes
00815         static const String suffixes[6] = {"_rt", "_lf", "_up", "_dn", "_fr", "_bk"};
00816         size_t pos = -1;
00817 
00818         String ext; // the extension
00819         String baseName; // the base name
00820         String fakeName = name; // the 'fake' name, temp. holder
00821 
00822         // first find the base name
00823         pos = fakeName.find_last_of(".");
00824         if (pos == -1)
00825         {
00826             Except( Exception::ERR_INTERNAL_ERROR, "Invalid cube texture base name", "D3D9Texture::_constructCubeFaceNames" );
00827             this->_freeResources();
00828         }
00829 
00830         baseName = fakeName.substr(0, pos);
00831         ext = fakeName.substr(pos);
00832 
00833         // construct the full 6 faces file names from the baseName, suffixes and extension
00834         for (size_t i = 0; i < 6; ++i)
00835             mCubeFaceNames[i] = baseName + suffixes[i] + ext;
00836     }
00837     /****************************************************************************************/
00838     void D3D9Texture::_setFinalAttributes(unsigned long width, unsigned long height, 
00839         unsigned long depth, PixelFormat format)
00840     { 
00841         // set target texture attributes
00842         mHeight = height; 
00843         mWidth = width; 
00844         mDepth = depth;
00845         mFormat = format; 
00846 
00847         // Update size (the final size, not including temp space)
00848         // this is needed in Resource class
00849         unsigned short bytesPerPixel = mFinalBpp >> 3;
00850         if( !mHasAlpha && mFinalBpp == 32 )
00851             bytesPerPixel--;
00852         mSize = mWidth * mHeight * mDepth * bytesPerPixel 
00853             * (mTextureType == TEX_TYPE_CUBE_MAP)? 6 : 1;
00854 
00855         // say to the world what we are doing
00856         if (mWidth != mSrcWidth ||
00857             mHeight != mSrcHeight)
00858         {
00859             LogManager::getSingleton().logMessage("D3D9 : ***** Dimensions altered by the render system");
00860             LogManager::getSingleton().logMessage("D3D9 : ***** Source image dimensions : " + StringConverter::toString(mSrcWidth) + "x" + StringConverter::toString(mSrcHeight));
00861             LogManager::getSingleton().logMessage("D3D9 : ***** Texture dimensions : " + StringConverter::toString(mWidth) + "x" + StringConverter::toString(mHeight));
00862         }
00863     }
00864     /****************************************************************************************/
00865     void D3D9Texture::_setSrcAttributes(unsigned long width, unsigned long height, 
00866         unsigned long depth, PixelFormat format)
00867     { 
00868         // set source image attributes
00869         mSrcWidth = width; 
00870         mSrcHeight = height; 
00871         mSrcBpp = _getPFBpp(format); 
00872         mHasAlpha = Image::formatHasAlpha(format); 
00873         // say to the world what we are doing
00874         switch (this->getTextureType())
00875         {
00876         case TEX_TYPE_1D:
00877             if (mUsage == TU_RENDERTARGET)
00878                 LogManager::getSingleton().logMessage("D3D9 : Creating 1D RenderTarget, name : '" + this->getName() + "' with " + StringConverter::toString(mNumMipMaps) + " mip map levels");
00879             else
00880                 LogManager::getSingleton().logMessage("D3D9 : Loading 1D Texture, image name : '" + this->getName() + "' with " + StringConverter::toString(mNumMipMaps) + " mip map levels");
00881             break;
00882         case TEX_TYPE_2D:
00883             if (mUsage == TU_RENDERTARGET)
00884                 LogManager::getSingleton().logMessage("D3D9 : Creating 2D RenderTarget, name : '" + this->getName() + "' with " + StringConverter::toString(mNumMipMaps) + " mip map levels");
00885             else
00886                 LogManager::getSingleton().logMessage("D3D9 : Loading 2D Texture, image name : '" + this->getName() + "' with " + StringConverter::toString(mNumMipMaps) + " mip map levels");
00887             break;
00888         case TEX_TYPE_3D:
00889             if (mUsage == TU_RENDERTARGET)
00890                 LogManager::getSingleton().logMessage("D3D9 : Creating 3D RenderTarget, name : '" + this->getName() + "' with " + StringConverter::toString(mNumMipMaps) + " mip map levels");
00891             else
00892                 LogManager::getSingleton().logMessage("D3D9 : Loading 3D Texture, image name : '" + this->getName() + "' with " + StringConverter::toString(mNumMipMaps) + " mip map levels");
00893             break;
00894         case TEX_TYPE_CUBE_MAP:
00895             if (mUsage == TU_RENDERTARGET)
00896                 LogManager::getSingleton().logMessage("D3D9 : Creating Cube map RenderTarget, name : '" + this->getName() + "' with " + StringConverter::toString(mNumMipMaps) + " mip map levels");
00897             else
00898                 LogManager::getSingleton().logMessage("D3D9 : Loading Cube Texture, base image name : '" + this->getName() + "' with " + StringConverter::toString(mNumMipMaps) + " mip map levels");
00899             break;
00900         default:
00901             Except( Exception::ERR_INTERNAL_ERROR, "Unknown texture type", "D3D9Texture::_createTex" );
00902             this->_freeResources();
00903         }
00904     }
00905     /****************************************************************************************/
00906     D3DTEXTUREFILTERTYPE D3D9Texture::_getBestFilterMethod()
00907     {
00908         // those MUST be initialized !!!
00909         assert(mpDev);
00910         assert(mpD3D);
00911         assert(mpTex);
00912 
00913         // TODO : do it really :)
00914         return D3DTEXF_POINT;
00915     }
00916     /****************************************************************************************/
00917     bool D3D9Texture::_canAutoGenMipMaps(DWORD srcUsage, D3DRESOURCETYPE srcType, D3DFORMAT srcFormat)
00918     {
00919         // those MUST be initialized !!!
00920         assert(mpDev);
00921         assert(mpD3D);
00922 
00923         if (mDevCaps.Caps2 & D3DCAPS2_CANAUTOGENMIPMAP)
00924         {
00925             HRESULT hr;
00926             // check for auto gen. mip maps support
00927             hr = mpD3D->CheckDeviceFormat(
00928                     mDevCreParams.AdapterOrdinal, 
00929                     mDevCreParams.DeviceType, 
00930                     mBBPixelFormat, 
00931                     srcUsage | D3DUSAGE_AUTOGENMIPMAP,
00932                     srcType,
00933                     srcFormat);
00934             // this HR could a SUCCES
00935             // but mip maps will not be generated
00936             if (hr == D3D_OK)
00937                 return true;
00938             else
00939                 return false;
00940         }
00941         else
00942             return false;
00943     }
00944     /****************************************************************************************/
00945     void D3D9Texture::_getColorMasks(D3DFORMAT format, DWORD *pdwRed, DWORD *pdwGreen, DWORD *pdwBlue, DWORD *pdwAlpha, DWORD *pdwRGBBitCount)
00946     {
00947         // we choose the format of the D3D texture so check only for our pf types...
00948         switch (format)
00949         {
00950         case D3DFMT_X8R8G8B8:
00951             *pdwRed = 0x00FF0000; *pdwGreen = 0x0000FF00; *pdwBlue = 0x000000FF; *pdwAlpha = 0x00000000;
00952             *pdwRGBBitCount = 32;
00953             break;
00954         case D3DFMT_R8G8B8:
00955             *pdwRed = 0x00FF0000; *pdwGreen = 0x0000FF00; *pdwBlue = 0x000000FF; *pdwAlpha = 0x00000000;
00956             *pdwRGBBitCount = 24;
00957             break;
00958         case D3DFMT_A8R8G8B8:
00959             *pdwRed = 0x00FF0000; *pdwGreen = 0x0000FF00; *pdwBlue = 0x000000FF; *pdwAlpha = 0xFF000000;
00960             *pdwRGBBitCount = 32;
00961             break;
00962         case D3DFMT_X1R5G5B5:
00963             *pdwRed = 0x00007C00; *pdwGreen = 0x000003E0; *pdwBlue = 0x0000001F; *pdwAlpha = 0x00000000;
00964             *pdwRGBBitCount = 16;
00965             break;
00966         case D3DFMT_R5G6B5:
00967             *pdwRed = 0x0000F800; *pdwGreen = 0x000007E0; *pdwBlue = 0x0000001F; *pdwAlpha = 0x00000000;
00968             *pdwRGBBitCount = 16;
00969             break;
00970         case D3DFMT_A4R4G4B4:
00971             *pdwRed = 0x00000F00; *pdwGreen = 0x000000F0; *pdwBlue = 0x0000000F; *pdwAlpha = 0x0000F000;
00972             *pdwRGBBitCount = 16;
00973             break;
00974         default:
00975             Except( Exception::ERR_INTERNAL_ERROR, "Unknown D3D pixel format, this should not happen !!!", "D3D9Texture::_getColorMasks" );
00976         }
00977     }
00978     /****************************************************************************************/
00979     void D3D9Texture::_copyMemoryToSurface(const unsigned char *pBuffer, IDirect3DSurface9 *pSurface)
00980     {
00981         assert(pBuffer);
00982         assert(pSurface);
00983         // Copy the image from the buffer to the temporary surface.
00984         // We have to do our own colour conversion here since we don't 
00985         // have a DC to do it for us
00986         // NOTE - only non-palettised surfaces supported for now
00987         HRESULT hr;
00988         D3DSURFACE_DESC desc;
00989         D3DLOCKED_RECT rect;
00990         BYTE *pSurf8;
00991         BYTE *pBuf8;
00992         DWORD data32;
00993         DWORD out32;
00994         unsigned iRow, iCol;
00995         // NOTE - dimensions of surface may differ from buffer
00996         // dimensions (e.g. power of 2 or square adjustments)
00997         // Lock surface
00998         pSurface->GetDesc(&desc);
00999         DWORD aMask, rMask, gMask, bMask, rgbBitCount;
01000         this->_getColorMasks(desc.Format, &rMask, &gMask, &bMask, &aMask, &rgbBitCount);
01001         // lock our surface to acces raw memory
01002         if( FAILED( hr = pSurface->LockRect(&rect, NULL, D3DLOCK_NOSYSLOCK) ) )
01003         {
01004             Except( hr, "Unable to lock temp texture surface", "D3D9Texture::_copyMemoryToSurface" );
01005             this->_freeResources();
01006             SAFE_RELEASE(pSurface);
01007         }
01008         else
01009             pBuf8 = (BYTE*)pBuffer;
01010         // loop through data and do conv.
01011         for( iRow = 0; iRow < mSrcHeight; iRow++ )
01012         {
01013             pSurf8 = (BYTE*)rect.pBits + (iRow * rect.Pitch);
01014             for( iCol = 0; iCol < mSrcWidth; iCol++ )
01015             {
01016                 // Read RGBA values from buffer
01017                 data32 = 0;
01018                 if( mSrcBpp >= 24 )
01019                 {
01020                     // Data in buffer is in RGB(A) format
01021                     // Read into a 32-bit structure
01022                     // Uses bytes for 24-bit compatibility
01023                     // NOTE: buffer is big-endian
01024                     data32 |= *pBuf8++ << 24;
01025                     data32 |= *pBuf8++ << 16;
01026                     data32 |= *pBuf8++ << 8;
01027                 }
01028                 else if( mSrcBpp == 8 ) // Greyscale, not palettised (palettised NOT supported)
01029                 {
01030                     // Duplicate same greyscale value across R,G,B
01031                     data32 |= *pBuf8 << 24;
01032                     data32 |= *pBuf8 << 16;
01033                     data32 |= *pBuf8++ << 8;
01034                 }
01035                 // check for alpha
01036                 if( mHasAlpha )
01037                     data32 |= *pBuf8++;
01038                 else
01039                     data32 |= 0xFF; // Set opaque
01040                 // Write RGBA values to surface
01041                 // Data in surface can be in varying formats
01042                 // Use bit concersion function
01043                 // NOTE: we use a 32-bit value to manipulate
01044                 // Will be reduced to size later
01045 
01046                 // Red
01047                 out32 = Bitwise::convertBitPattern( (DWORD)data32, (DWORD)0xFF000000, (DWORD)rMask );
01048                 // Green
01049                 out32 |= Bitwise::convertBitPattern( (DWORD)data32, (DWORD)0x00FF0000, (DWORD)gMask );
01050                 // Blue
01051                 out32 |= Bitwise::convertBitPattern( (DWORD)data32, (DWORD)0x0000FF00, (DWORD)bMask );
01052                 // Alpha
01053                 if( aMask > 0 )
01054                 {
01055                     out32 |= Bitwise::convertBitPattern( (DWORD)data32, (DWORD)0x000000FF, (DWORD)aMask );
01056                 }
01057                 // Assign results to surface pixel
01058                 // Write up to 4 bytes
01059                 // Surfaces are little-endian (low byte first)
01060                 if( rgbBitCount >= 8 )
01061                     *pSurf8++ = (BYTE)out32;
01062                 if( rgbBitCount >= 16 )
01063                     *pSurf8++ = (BYTE)(out32 >> 8);
01064                 if( rgbBitCount >= 24 )
01065                     *pSurf8++ = (BYTE)(out32 >> 16);
01066                 if( rgbBitCount >= 32 )
01067                     *pSurf8++ = (BYTE)(out32 >> 24);
01068             } // for( iCol...
01069         } // for( iRow...
01070         // unlock the surface
01071         pSurface->UnlockRect();
01072     }
01073     /****************************************************************************************/
01074     void D3D9Texture::_blitImageToNormTex(const Image &srcImage)
01075     {
01076         HRESULT hr;
01077         D3DFORMAT srcFormat = this->_getPF(srcImage.getFormat());
01078         D3DFORMAT dstFormat = _chooseD3DFormat();
01079         RECT tmpDataRect = {0, 0, srcImage.getWidth(), srcImage.getHeight()}; // the rectangle representing the src. image dim.
01080 
01081         // this surface will hold our temp conversion image
01082         // We need this in all cases because we can't lock 
01083         // the main texture surfaces in all cards
01084         // Also , this cannot be the temp texture because we'd like D3DX to resize it for us
01085         // with the D3DxLoadSurfaceFromSurface
01086         IDirect3DSurface9 *pSrcSurface = NULL;
01087         hr = mpDev->CreateOffscreenPlainSurface( 
01088                         srcImage.getWidth(),
01089                         srcImage.getHeight(),
01090                         dstFormat, 
01091                         D3DPOOL_SCRATCH, 
01092                         &pSrcSurface, 
01093                         NULL);
01094         // check result and except if failed
01095         if (FAILED(hr))
01096         {
01097             this->_freeResources();
01098             Except( hr, "Error loading surface from memory", "D3D9Texture::_blitImageToTexture" );
01099         }
01100         
01101         // copy the buffer to our surface, 
01102         // _copyMemoryToSurface will do color conversion and flipping
01103         this->_copyMemoryToSurface(srcImage.getData(), pSrcSurface);
01104 
01105         // Now we need to copy the source surface (where our image is) to the texture
01106         // This will perform any size conversion (inc stretching)
01107         IDirect3DSurface9 *pDstSurface; 
01108         hr = mpNormTex->GetSurfaceLevel(0, &pDstSurface);
01109 
01110         // check result and except if failed
01111         if (FAILED(hr))
01112         {
01113             SAFE_RELEASE(pSrcSurface);
01114             this->_freeResources();
01115             Except( hr, "Error getting level 0 surface from dest. texture", "D3D9Texture::_blitImageToTexture" );
01116         }
01117 
01118         // copy surfaces
01119         hr = D3DXLoadSurfaceFromSurface(pDstSurface, NULL, NULL, pSrcSurface, NULL, NULL, D3DX_DEFAULT, 0);
01120         // check result and except if failed
01121         if (FAILED(hr))
01122         {
01123             SAFE_RELEASE(pSrcSurface);
01124             SAFE_RELEASE(pDstSurface);
01125             this->_freeResources();
01126             Except( hr, "Error copying original surface to texture", "D3D9Texture::_blitImageToTexture" );
01127         }
01128 
01129         // Generate mipmaps
01130         if (mAutoGenMipMaps)
01131         {
01132             // Hardware mipmapping
01133             // use best filtering method supported by hardware
01134             hr = mpTex->SetAutoGenFilterType(_getBestFilterMethod());
01135             if (FAILED(hr))
01136             {
01137                 SAFE_RELEASE(pSrcSurface);
01138                 SAFE_RELEASE(pDstSurface);
01139                 this->_freeResources();
01140                 Except( hr, "Error generating mip maps", "D3D9Texture::_blitImageToNormTex" );
01141             }
01142             mpNormTex->GenerateMipSubLevels();
01143         }
01144         else
01145         {
01146             // Software mipmaps
01147             if( FAILED( hr = D3DXFilterTexture( mpNormTex, NULL, D3DX_DEFAULT, D3DX_DEFAULT ) ) )
01148             {
01149                 this->_freeResources();
01150                 Except( hr, "Failed to filter texture (generate mip maps)", "D3D9Texture::_blitImageToNormTex" );
01151             }
01152         }
01153 
01154             
01155         SAFE_RELEASE(pDstSurface);
01156         SAFE_RELEASE(pSrcSurface);
01157     }
01158     /****************************************************************************************/
01159     void D3D9Texture::_blitImagesToCubeTex(const Image srcImages[])
01160     {
01161         HRESULT hr;
01162         D3DFORMAT dstFormat = _chooseD3DFormat();
01163 
01164         // we must loop through all 6 cube map faces :(
01165         for (size_t face = 0; face < 6; face++)
01166         {
01167             D3DFORMAT srcFormat = this->_getPF(srcImages[face].getFormat());
01168             RECT tmpDataRect = {0, 0, srcImages[face].getWidth(), srcImages[face].getHeight()}; // the rectangle representing the src. image dim.
01169 
01170             // this surface will hold our temp conversion image
01171             IDirect3DSurface9 *pSrcSurface = NULL;
01172             // We need this in all cases because we can't lock 
01173             // the main texture surfaces in all cards
01174             // Also , this cannot be the temp texture because we'd like D3DX to resize it for us
01175             // with the D3DxLoadSurfaceFromSurface
01176             hr = mpDev->CreateOffscreenPlainSurface( 
01177                             srcImages[face].getWidth(), 
01178                             srcImages[face].getHeight(), 
01179                             dstFormat, 
01180                             D3DPOOL_SCRATCH, 
01181                             &pSrcSurface, 
01182                             NULL);
01183             // check result and except if failed
01184             if (FAILED(hr))
01185             {
01186                 Except( hr, "Error loading surface from memory", "D3D9Texture::_blitImagesToCubeTex" );
01187                 this->_freeResources();
01188             }
01189 
01190             // don't know why but cube textures don't require fliping
01191             // _copyMemoryToSurface flips all around x, so we'll flip the
01192             // src.image first, then 'reflip' it :(, and we need a temp. image for this :(
01193             Image tmpImg(srcImages[face]);
01194             //tmpImg.flipAroundX();
01195             // copy the buffer to our surface, 
01196             // _copyMemoryToSurface will do color conversion and flipping
01197             this->_copyMemoryToSurface(tmpImg.getData(), pSrcSurface);
01198 
01199             // Now we need to copy the source surface (where our image is) to 
01200             // either the the temp. texture level 0 surface (for s/w mipmaps)
01201             // or the final texture (for h/w mipmaps)
01202             IDirect3DSurface9 *pDstSurface; 
01203             hr = mpCubeTex->GetCubeMapSurface((D3DCUBEMAP_FACES)face, 0, &pDstSurface);
01204             // check result and except if failed
01205             if (FAILED(hr))
01206             {
01207                 Except( hr, "Error getting level dest cube map surface", "D3D9Texture::_blitImagesToCubeTex" );
01208                 SAFE_RELEASE(pSrcSurface);
01209                 this->_freeResources();
01210             }
01211 
01212             // load the surface with an in memory buffer
01213             hr = D3DXLoadSurfaceFromSurface(
01214                 pDstSurface, 
01215                 NULL, 
01216                 NULL, 
01217                 pSrcSurface, 
01218                 NULL, 
01219                 NULL, 
01220                 D3DX_DEFAULT, 
01221                 0);
01222             // check result and except if failed
01223             if (FAILED(hr))
01224             {
01225                 Except( hr, "Error loading in temporary surface", "D3D9Texture::_blitImagesToCubeTex" );
01226                 SAFE_RELEASE(pSrcSurface);
01227                 SAFE_RELEASE(pDstSurface);
01228                 this->_freeResources();
01229             }
01230 
01231             SAFE_RELEASE(pDstSurface);
01232             SAFE_RELEASE(pSrcSurface);
01233         }
01234 
01235         // Mipmaps
01236         if (mAutoGenMipMaps)
01237         {
01238             // use best filtering method supported by hardware
01239             hr = mpTex->SetAutoGenFilterType(_getBestFilterMethod());
01240             if (FAILED(hr))
01241             {
01242                 this->_freeResources();
01243                 Except( hr, "Error generating mip maps", "D3D9Texture::_blitImageToCubeTex" );
01244             }
01245             mpCubeTex->GenerateMipSubLevels();
01246         }
01247         else
01248         {
01249             // Software mipmaps
01250             if( FAILED( hr = D3DXFilterTexture( mpCubeTex, NULL, D3DX_DEFAULT, D3DX_DEFAULT ) ) )
01251             {
01252                 this->_freeResources();
01253                 Except( hr, "Failed to filter texture (generate mip maps)", "D3D9Texture::_blitImageToCubeTex" );
01254             }
01255 
01256         }
01257 
01258 
01259     }
01260     /****************************************************************************************/
01261     D3DFORMAT D3D9Texture::_chooseD3DFormat()
01262     {
01263         // choose wise wich D3D format we'll use ;)
01264         if( mFinalBpp > 16 && mHasAlpha )
01265             return D3DFMT_A8R8G8B8;
01266         else if( mFinalBpp > 16 && !mHasAlpha )
01267             return D3DFMT_R8G8B8;
01268         else if( mFinalBpp == 16 && mHasAlpha )
01269             return D3DFMT_A4R4G4B4;
01270         else if( mFinalBpp == 16 && !mHasAlpha )
01271             return D3DFMT_R5G6B5;
01272         else
01273             Except( Exception::ERR_INVALIDPARAMS, "Unknown pixel format", "D3D9Texture::_chooseD3DFormat" );
01274     }
01275     /****************************************************************************************/
01276     void D3D9Texture::_createDepthStencil()
01277     {
01278         IDirect3DSurface9 *pSrf;
01279         D3DSURFACE_DESC srfDesc;
01280         HRESULT hr;
01281 
01282         /* Get the format of the depth stencil surface of our main render target. */
01283         hr = mpDev->GetDepthStencilSurface(&pSrf);
01284         if (FAILED(hr))
01285         {
01286             String msg = DXGetErrorDescription9(hr);
01287             Except( hr, "Error GetDepthStencilSurface : " + msg, "D3D9Texture::_createDepthStencil" );
01288             this->_freeResources();
01289         }
01290         // get it's description
01291         hr = pSrf->GetDesc(&srfDesc);
01292         if (FAILED(hr))
01293         {
01294             String msg = DXGetErrorDescription9(hr);
01295             Except( hr, "Error GetDesc : " + msg, "D3D9Texture::_createDepthStencil" );
01296             SAFE_RELEASE(pSrf);
01297             this->_freeResources();
01298         }
01299         // release the temp. surface
01300         SAFE_RELEASE(pSrf);
01304         hr = mpDev->CreateDepthStencilSurface( 
01305             mSrcWidth, 
01306             mSrcHeight, 
01307             srfDesc.Format, 
01308             srfDesc.MultiSampleType, 
01309             NULL, 
01310             FALSE, 
01311             &mpZBuff, 
01312             NULL);
01313         // cry if failed 
01314         if (FAILED(hr))
01315         {
01316             String msg = DXGetErrorDescription9(hr);
01317             Except( hr, "Error CreateDepthStencilSurface : " + msg, "D3D9Texture::_createDepthStencil" );
01318             this->_freeResources();
01319         }
01320     }
01321     /****************************************************************************************/
01322     PixelFormat D3D9Texture::_getPF(D3DFORMAT d3dPF)
01323     {
01324         switch(d3dPF)
01325         {
01326         case D3DFMT_A8:
01327             return PF_A8;
01328         case D3DFMT_A4L4:
01329             return PF_A4L4;
01330         case D3DFMT_A4R4G4B4:
01331             return PF_A4R4G4B4;
01332         case D3DFMT_A8R8G8B8:
01333             return PF_A8R8G8B8;
01334         case D3DFMT_A2R10G10B10:
01335             return PF_A2R10G10B10;
01336         case D3DFMT_L8:
01337             return PF_L8;
01338         case D3DFMT_X1R5G5B5:
01339         case D3DFMT_R5G6B5:
01340             return PF_R5G6B5;
01341         case D3DFMT_X8R8G8B8:
01342         case D3DFMT_R8G8B8:
01343             return PF_R8G8B8;
01344         default:
01345             return PF_UNKNOWN;
01346         }
01347     }
01348     /****************************************************************************************/
01349     D3DFORMAT D3D9Texture::_getPF(PixelFormat ogrePF)
01350     {
01351         switch(ogrePF)
01352         {
01353         case PF_L8:
01354             return D3DFMT_L8;
01355         case PF_A8:
01356             return D3DFMT_A8;
01357         case PF_B5G6R5:
01358         case PF_R5G6B5:
01359             return D3DFMT_R5G6B5;
01360         case PF_B4G4R4A4:
01361         case PF_A4R4G4B4:
01362             return D3DFMT_A4R4G4B4;
01363         case PF_B8G8R8:
01364         case PF_R8G8B8:
01365             return D3DFMT_R8G8B8;
01366         case PF_B8G8R8A8:
01367         case PF_A8R8G8B8:
01368             return D3DFMT_A8R8G8B8;
01369         case PF_L4A4:
01370         case PF_A4L4:
01371             return D3DFMT_A4L4;
01372         case PF_B10G10R10A2:
01373         case PF_A2R10G10B10:
01374             return D3DFMT_A2R10G10B10;
01375         case PF_UNKNOWN:
01376         default:
01377             return D3DFMT_UNKNOWN;
01378         }
01379     }
01380     /****************************************************************************************/
01381 }

Copyright © 2002-2003 by The OGRE Team
Last modified Sun Nov 28 19:48:22 2004