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