Game Accessibility Library logo SourceForge.net Logo
Game Accessibility Suite: CAT/CATOverlayDirect3D9.cpp Source File

CATOverlayDirect3D9.cpp

Go to the documentation of this file.
00001 /// \file  CATOverlayDirect3D9.cpp
00002 /// \brief Direct3D function interception
00003 /// \ingroup CAT
00004 ///
00005 /// Copyright (c) 2007-2008 by Michael Ellison.
00006 /// See COPYING.txt for the \ref gaslicense License (MIT License).
00007 ///
00008 // $Author: mikeellison $
00009 // $Date: 2008-01-31 21:20:49 -0600 (Thu, 31 Jan 2008) $
00010 // $Revision:   $
00011 // $NoKeywords: $
00012 
00013 #include "CATOverlayDirect3D9.h"
00014 #include "CATString.h"
00015 
00016 #ifdef CAT_CONFIG_WIN32
00017 #include <d3d9.h>
00018 
00019 /// This table contains all of the functions we wish to intercept
00020 /// from IDirect3DDevice9 and the targets for those functions.
00021 CATINTERCEPT_COM_TABLE_ENTRY CATOverlayDirect3D9::kDirect3DDeviceInterceptTable9[] =
00022 {
00023     // VTableIndex  HookFunction                                 StubLength
00024     {  16,          CATOverlayDirect3D9::OnReset9,            5},  
00025     {  17,          CATOverlayDirect3D9::OnPresent9,          5},  
00026     {  42,          CATOverlayDirect3D9::OnEndScene,          5},  
00027     // End marker
00028     {(CATUInt32)-1,0,-1}
00029 };
00030 CATOverlayDirect3D9::CATOverlayDirect3D9()
00031 {
00032     fDeviceLost  = true;
00033     fTexture     = 0;
00034     fBackTexture = 0;
00035     fTexScaleX   = 1.0f;
00036     fTexScaleY   = 1.0f;
00037     fD3d9DLL     = ::LoadLibrary(L"d3d9.dll");
00038 }
00039 
00040 CATOverlayDirect3D9::~CATOverlayDirect3D9()
00041 {
00042     RestoreAll();
00043     if (fD3d9DLL)
00044         FreeLibrary(fD3d9DLL);
00045     fD3d9DLL = 0;
00046 }
00047 
00048 void CATOverlayDirect3D9::DrawToScene(IDirect3DDevice9* device)
00049 {
00050     fLock.Wait();
00051     
00052     if (fDeviceLost)
00053     {
00054         fLock.Release();
00055         return;
00056     }
00057 
00058     // If the overlay is dirty, regen the texture
00059     if (fOverlayDirty)
00060     {
00061         //::OutputDebugString(L"DX9: Refreshing overlay.");
00062         if (fTexture)
00063             fTexture->Release();
00064         if (fBackTexture)
00065             fBackTexture->Release();
00066         
00067         fTexture     = 0;
00068         fBackTexture = 0;
00069         
00070         if (fOverlay == 0)
00071         {
00072             fLock.Release();
00073             return;
00074         }
00075 
00076         CATInt32 tw = 2;
00077         while (tw < fOverlay->Width())
00078             tw*= 2;
00079         CATInt32 th = 2;
00080         while (th < fOverlay->Height())
00081             th*=2;
00082 
00083         RECT textureRect;
00084         textureRect.left   = textureRect.top = 0;
00085         textureRect.right  = tw;
00086         textureRect.bottom = th;
00087 
00088         HRESULT hr =  device->CreateTexture(tw,th,1,0,D3DFMT_A8R8G8B8,D3DPOOL_DEFAULT,&fBackTexture,0);
00089         hr |= device->CreateTexture(tw,th,1,0,D3DFMT_A8R8G8B8,D3DPOOL_SYSTEMMEM,&fTexture,0);
00090         
00091         if (FAILED(hr))
00092         {
00093             ::OutputDebugString(L"Failed creating texture");
00094             fLock.Release();
00095             return;
00096         }
00097         
00098         D3DSURFACE_DESC surfaceDesc,sd2;        
00099         fTexture->GetLevelDesc(0,&surfaceDesc);
00100         fBackTexture->GetLevelDesc(0,&sd2);
00101         if ((surfaceDesc.Format != D3DFMT_A8R8G8B8) || (sd2.Format != D3DFMT_A8R8G8B8))
00102         {
00103             CATString dbg;
00104             dbg.Format(L"Surface format mismatch. %d",surfaceDesc.Format);
00105             ::OutputDebugString(dbg);
00106             fTexture->Release();
00107             fTexture = 0;
00108             fBackTexture->Release();
00109             fBackTexture = 0;
00110             fLock.Release();
00111             return;
00112         }            
00113         
00114         D3DLOCKED_RECT lockedRect;                       
00115         if (!FAILED(fTexture->LockRect(0,&lockedRect,&textureRect,0)))
00116         {
00117             // Create a buffer to copy image into that's a power of 2 for texture happiness.
00118             CATUInt8* buffer = (CATUInt8*)lockedRect.pBits;
00119             CATUInt8* srcBuf = fOverlay->GetRawDataPtr();
00120             CATUInt32 imgWidth = fOverlay->Width();
00121             
00122             
00123             // Yuck. our current format is swapped from what DX likes to give me.
00124             int uh = fOverlay->Height();
00125             int uw = fOverlay->Width();
00126             
00127             memset(buffer,0,tw*th*4);
00128 
00129             int dstLinePad = (tw - uw)*4;
00130             for (int y = 0; y < uh; y++)
00131             {
00132                 for (int x = 0; x < uw; x++)
00133                 {
00134                     *buffer = srcBuf[2];
00135                     buffer[2] = *srcBuf;
00136                     buffer[1] = srcBuf[1];
00137                     buffer[3] = srcBuf[3];
00138                     buffer += 4;
00139                     srcBuf += 4;
00140                 }
00141                 buffer += dstLinePad;
00142             }
00143             fTexture->UnlockRect(0);
00144 
00145             // Preserve image/texture scale for drawing
00146             fTexScaleX = (CATFloat32)fOverlay->Width() /  (CATFloat32)tw;
00147             fTexScaleY = (CATFloat32)fOverlay->Height() / (CATFloat32)th;
00148     
00149             RECT textureRect;
00150             textureRect.left = textureRect.top = 0;
00151             textureRect.right = tw;
00152             textureRect.bottom = th;
00153 
00154             device->UpdateTexture(fTexture, fBackTexture);
00155 
00156             fOverlayDirty = false;
00157         }
00158         else
00159         {
00160             ::OutputDebugString(L"Failed to lock texture.");
00161         }
00162     }
00163 
00164     // Whew... texture regen'd if needed. Now draw it.
00165     if (fBackTexture)
00166     {       
00167         IDirect3DSurface9* surface = 0;
00168         //device->GetRenderTarget(0,&surface);
00169         device->GetBackBuffer(0,0,D3DBACKBUFFER_TYPE_MONO,&surface);
00170         if (surface)
00171         {
00172             IDirect3DSurface9* textSurface = 0;
00173             fBackTexture->GetSurfaceLevel(0,&textSurface);
00174             if (textSurface)
00175             {
00176                 RECT srcRect;
00177                 srcRect.left = srcRect.top = 0;
00178                 srcRect.bottom = fOverlay->Height();
00179                 
00180                 srcRect.right  = fOverlay->Width();
00181 
00182                 D3DSURFACE_DESC desc;
00183                 surface->GetDesc(&desc);
00184 
00185                 POINT topLeft = {0.0};
00186                 RECT destRect;
00187                 fRect.right = desc.Width;
00188                 fRect.bottom = desc.Height;
00189 
00190                 CATFloat32 scaleX = (CATFloat32)desc.Width / (CATFloat32)fRefScreenWidth;
00191                 CATFloat32 scaleY = (CATFloat32)desc.Height / (CATFloat32)fRefScreenHeight;
00192                 if (fKeepAspect)
00193                 {
00194                     scaleY = scaleX = CATMin(scaleX,scaleY);
00195                 }
00196 
00197                 destRect.left   = fOverlayRect.left*scaleX;
00198                 destRect.top    = fOverlayRect.top*scaleY;
00199                 destRect.right  = fOverlayRect.right*scaleX;
00200                 destRect.bottom = fOverlayRect.bottom*scaleY;
00201                 
00202                 HRESULT hr = device->StretchRect(textSurface,&srcRect,surface,&destRect,D3DTEXF_NONE);
00203                 if (FAILED(hr))
00204                 {
00205                     CATString dbg;
00206                     
00207                     surface->GetDesc(&desc);
00208                     dbg.Format(L"Stretch failed: %08x Surface format: %d src %d,%d,%d,%d dst %d,%d,%d,%d",hr,desc.Format,
00209                         srcRect.left, srcRect.top, srcRect.right, srcRect.bottom, destRect.left, destRect.top,destRect.right,destRect.bottom);
00210                     ::OutputDebugString(dbg);
00211                     dbg.Format(L"Target: %dx%d pool %d type %d Multi: %d MQ: %d",
00212                         desc.Width, desc.Height, desc.Pool,desc.Type,desc.MultiSampleType, desc.MultiSampleQuality);
00213                     ::OutputDebugString(dbg);
00214                 }
00215                 textSurface->Release();                
00216             }
00217             else
00218             {
00219                 ::OutputDebugString(L"didn't get texture surface..");
00220             }
00221 
00222             surface->Release();
00223         }
00224     }
00225 
00226     fLock.Release();
00227 }
00228 
00229 void CATOverlayDirect3D9::Reset(      IDirect3DDevice9*             device,
00230                                       _D3DPRESENT_PARAMETERS_*    presParams)
00231 {
00232     fLock.Wait();
00233     ::OutputDebugString(L"DX9: Reset");
00234     
00235     // Flag the texture for recreation.
00236     fDeviceLost   = true;
00237     
00238     if (fTexture)        
00239         fTexture->Release();
00240     fTexture = 0;
00241     if (fBackTexture)
00242         fBackTexture->Release();
00243     fBackTexture = 0;
00244 
00245     fLock.Release();
00246 }
00247 
00248 void CATOverlayDirect3D9::DeviceLost(     CATHOOK*             hookInst,
00249                                           IDirect3DDevice9*    device)
00250 {
00251 
00252     CATOverlayDirect3D9* overlay = (CATOverlayDirect3D9*)hookInst->InterceptObj;
00253     overlay->fLock.Wait();
00254     ::OutputDebugString(L"DX9: Device Lost");
00255     
00256     overlay->fDeviceLost = true;    
00257     
00258     if (overlay->fTexture)
00259         overlay->fTexture->Release();
00260     overlay->fTexture = 0;
00261     if (overlay->fBackTexture)
00262         overlay->fBackTexture->Release();
00263     overlay->fBackTexture = 0;
00264 
00265     overlay->fLock.Release();
00266 }
00267 
00268 void CATOverlayDirect3D9::DeviceOk(     CATHOOK*             hookInst,
00269                                         IDirect3DDevice9*    device)
00270 {
00271     
00272 
00273     CATOverlayDirect3D9* overlay = (CATOverlayDirect3D9*)hookInst->InterceptObj;
00274     overlay->fLock.Wait();
00275 
00276     if (overlay->fDeviceLost)
00277     {
00278         ::OutputDebugString(L"DX9: Device OK");
00279         overlay->fDeviceLost   = false;    
00280         overlay->fOverlayDirty = true;
00281     }
00282 
00283     overlay->fLock.Release();
00284 }
00285 
00286 CATResult CATOverlayDirect3D9::HookFunctions()
00287 {
00288     HWND procWnd = ::GetDesktopWindow();
00289 
00290     HRESULT           hr            = 0;
00291     
00292     CATResult result = CAT_SUCCESS;
00293 
00294     D3DDISPLAYMODE    displayMode;    
00295     IDirect3D9*       d3d9          = 0;
00296     IDirect3DDevice9* device9       = 0;
00297 
00298     // First, try loading values from registry if available.
00299     result = this->LoadAndHook(L"Direct3DDevice9",kDirect3DDeviceInterceptTable9,this);
00300     if (CATSUCCEEDED(result))
00301     {
00302         return CAT_SUCCESS;
00303     }
00304     {
00305         typedef IDirect3D9* (STDMETHODCALLTYPE *DIRECT3DCREATE9FUNC)(UINT);
00306         DIRECT3DCREATE9FUNC d3dCreate9 = (DIRECT3DCREATE9FUNC)::GetProcAddress(fD3d9DLL,"Direct3DCreate9");
00307         if (d3dCreate9 == 0)
00308         {
00309             ::OutputDebugStringW(L"Failed to retrieve Direct3dCreate9 func.");
00310             return CATRESULT(CAT_ERR_INTERCEPT_NO_DSOUND);
00311         }
00312 
00313         d3d9 = d3dCreate9(D3D_SDK_VERSION);    // 32 is d3d9 version
00314         if (d3d9 == 0)
00315         {
00316             ::OutputDebugStringW(L"Failed to create Direct3d9 object.");
00317             return CATRESULT(CAT_ERR_INTERCEPT_NO_DSOUND);
00318         }
00319                
00320         hr = d3d9->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &displayMode );
00321         if (FAILED(hr))
00322         {
00323             ::OutputDebugStringW(L"Failed retrieving display mode.");
00324             return CATRESULT(CAT_ERR_INTERCEPT_NO_DSOUND);
00325         }
00326 
00327         D3DPRESENT_PARAMETERS presentParams; 
00328         memset(&presentParams, 0, sizeof(presentParams));
00329         presentParams.Windowed          = true;
00330         presentParams.SwapEffect        = D3DSWAPEFFECT_DISCARD;
00331         presentParams.BackBufferFormat  = displayMode.Format;
00332 
00333         
00334         hr = d3d9->CreateDevice( D3DADAPTER_DEFAULT, 
00335                                 D3DDEVTYPE_HAL, 
00336                                 procWnd,
00337                                 D3DCREATE_HARDWARE_VERTEXPROCESSING,//D3DCREATE_SOFTWARE_VERTEXPROCESSING,
00338                                 &presentParams, 
00339                                 &device9);
00340 
00341         result = this->InterceptCOMObject(device9,kDirect3DDeviceInterceptTable9,this);
00342         
00343         // On success, try to save out data so we don't have to do it next time.
00344         if (CATSUCCEEDED(result))
00345         {
00346             SaveInterceptData(L"Direct3DDevice9",device9,kDirect3DDeviceInterceptTable9,this);
00347         }
00348 
00349         if (device9)
00350             device9->Release();
00351         
00352         if (d3d9)
00353             d3d9->Release();    
00354     }
00355     return result;
00356 }
00357 
00358 
00359 CATHOOKFUNC void CATOverlayDirect3D9::OnReset9(     CATHOOK*                hookInst,
00360                                                     IDirect3DDevice9*       device,
00361                                                     D3DPRESENT_PARAMETERS*  presParams)
00362 {
00363     CATHOOK_PROLOGUE(2);    
00364     CATHOOK_CALLORIGINAL_WINAPI(hookInst, 2);
00365     ((CATOverlayDirect3D9*)(hookInst->InterceptObj))->Reset(device,presParams);
00366     CATHOOK_EPILOGUE_WINAPI(2);
00367 }
00368 
00369 CATHOOKFUNC void CATOverlayDirect3D9::OnPresent9(    CATHOOK*             hookInst,
00370                                                       IDirect3DDevice9*    device,
00371                                                       const RECT*          sourceRect,
00372                                                       const RECT*          destRect,
00373                                                       HWND                 destWindow,
00374                                                       const RGNDATA*       pDirtyRgn)
00375 {
00376     CATHOOK_PROLOGUE(5);
00377     CATHOOK_CALLORIGINAL_WINAPI(hookInst, 5);   
00378     
00379     _asm 
00380     {
00381         mov eax, [ebp-4]
00382         or  eax, 0x80000000         // Check for lost device
00383         jnz presentOk
00384         push device
00385         push hookInst
00386         call DeviceLost             // Got one, notify our overlay!
00387         add  esp,8
00388         jmp  presentDone
00389 presentOk:
00390         push device
00391         push hookInst
00392         call DeviceOk
00393         add  esp,8
00394 presentDone:
00395     }
00396 
00397     CATHOOK_EPILOGUE_WINAPI(5);
00398 }
00399 
00400 CATHOOKFUNC void CATOverlayDirect3D9::OnEndScene(    CATHOOK*             hookInst,
00401                                                      IDirect3DDevice9*    device)
00402 {
00403     CATHOOK_PROLOGUE(1);    
00404     ((CATOverlayDirect3D9*)(hookInst->InterceptObj))->DrawToScene(device);
00405     CATHOOK_CALLORIGINAL_WINAPI(hookInst, 1);       
00406     CATHOOK_EPILOGUE_WINAPI(1);
00407 }
00408 
00409 #endif // CAT_CONFIG_WIN32

Generated on Mon Feb 11 04:09:45 2008 for Game Accessibility Suite by doxygen 1.5.4