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