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