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

Copyright © 2002-2003 by The OGRE Team
Last modified Fri May 14 23:22:05 2004