// DirectDrawHook.cpp : Implementation of CDirectDrawHook
#include "stdafx.h"
#include "Inject.h"
#include "DirectDrawHook.h"

#include "MaterialHook.h"
#include "DirectDrawSurfaceHook.h"

#include "Manager.h"
//#include <fstream>
/////////////////////////////////////////////////////////////////////////////
// CDirectDrawHook

void CDirectDrawHook::setObject( IDirectDraw *pDD )
{
   m_pDD = pDD;
   m_pDD->QueryInterface( IID_IDirectDraw2, reinterpret_cast< void ** >( &m_pDD2 ) );
   m_pDD->QueryInterface( IID_IDirectDraw4, reinterpret_cast< void ** >( &m_pDD4 ) );

   m_pDD->QueryInterface( IID_IDirect3D, reinterpret_cast< void ** >( &m_pD3D ) );
   m_pDD->QueryInterface( IID_IDirect3D2, reinterpret_cast< void ** >( &m_pD3D2 ) );
   m_pDD->QueryInterface( IID_IDirect3D3, reinterpret_cast< void ** >( &m_pD3D3 ) );

   cManager::_p->setDirectDraw( m_pDD4, m_pD3D3, NULL);
}

STDMETHODIMP CDirectDrawHook::SetCooperativeLevel(HWND p1, DWORD p2)
{
   cManager::_p->setWindow( p1 );
   return m_pDD->SetCooperativeLevel( p1, p2 );
}

STDMETHODIMP CDirectDrawHook::SetDisplayMode(DWORD p1, DWORD p2, DWORD p3)
{
   return m_pDD->SetDisplayMode( p1, p2, p3 );
}

HRESULT (__stdcall *pfnOldUnlock)(IDirectDrawSurface4 *pDDS, LPRECT rc);

HRESULT __stdcall myUnlock ( IDirectDrawSurface4 *pDDS, LPRECT rc)
{
	HRESULT hRes = pfnOldUnlock(pDDS, rc);	
	if(rc==NULL)
		cManager::_p->draw2D();
		//MessageBox(0, _bstr_t(" left: ") + _bstr_t((long)rc->left) + _bstr_t(" top: ") + _bstr_t((long)rc->top) + _bstr_t(" right: ") + _bstr_t((long)rc->right) + _bstr_t(" bottom: ") + _bstr_t((long)rc->bottom), "Asd", 0);

	 return hRes;
}


STDMETHODIMP CDirectDrawHook::CreateSurface(LPDDSURFACEDESC2 p1, LPDIRECTDRAWSURFACE4 FAR *ppDDS, IUnknown FAR *p3)
{
	static bool bGotPrimary=false;
static sc=0;

	//static std::ofstream ass("c:\\acl.txt", std::ios::binary);
	
	//ass << "Flags: " << p1->dwFlags << " dwCaps: " << p1->ddsCaps.dwCaps << " Width: " << p1->dwWidth << " Height: " << p1->dwHeight << "\r\n";

	if((cManager::_p->getSoftwareMode()))// && (!bGotPrimary))
	{
	   /*CComPtr< IDirectDrawSurface4 > pDDS;

	   HRESULT hRes = m_pDD4->CreateSurface( p1, &pDDS, p3 );
	   if( FAILED( hRes ) )
		  return hRes;

	   if(!(p1->ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE)))// | DDSCAPS_COMPLEX)))
	   {
		   pDDS->QueryInterface(IID_IDirectDrawSurface4, reinterpret_cast< void ** >(ppDDS));
		   return hRes;
	   }

	   m_nSurfaceCount++;

	   if(m_nSurfaceCount==1)//!=4)
				cManager::_p->setDirectDraw(m_pDD4, NULL, pDDS);
	   
	   CComObject< CDirectDrawSurfaceHook > *pHook;
	   CComObject< CDirectDrawSurfaceHook >::CreateInstance( &pHook );
	   pHook->setObject( pDDS );
	   pHook->setSurfaceNum( m_nSurfaceCount );

	   pHook->QueryInterface( IID_IDirectDrawSurface4, reinterpret_cast< void ** >( ppDDS ) );
*/

		CComPtr< IDirectDrawSurface4 > pDDS;

		HRESULT hRes = m_pDD4->CreateSurface( p1, &pDDS, p3 );
		   if( FAILED( hRes ) )
			   return hRes;

   // Get the configured width from the registry
	 /*  DWORD dwConfiguredWidth;

	   {
		  RECT rc;
		  ::GetClientRect( cManager::_p->m_hMain, &rc );
		  dwConfiguredWidth = rc.right - rc.left;
	   }*/

	   /*if( p1->dwWidth < ( dwConfiguredWidth - 330 ) )
	   {
		
	   }
	   else*/


		   if(p1->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)// && (p1->dwHeight==362) && (p1->dwWidth==300))//(p1->ddsCaps.dwCaps & DDSCAPS_OFFSCREENPLAIN)
		   {
			  //MessageBox(0, _bstr_t("Width: ") + _bstr_t((long)p1->dwWidth) + _bstr_t(" Height: ") + _bstr_t((long)p1->dwHeight), "asd", 0);
			sc++;
			 if((!bGotPrimary) && (sc==2))
			{
				 sc=0;
			   HRESULT (__stdcall *&pfnUnlock)(IDirectDrawSurface4 *pDDS, LPRECT rc) = reinterpret_cast< HRESULT (__stdcall**)(IDirectDrawSurface4 *pDDS, LPRECT rc) > ( *reinterpret_cast< DWORD * > ( pDDS.p ) )[ 32 ];

					pfnOldUnlock = *pfnUnlock;

					pfnUnlock = myUnlock;


		   	//if((p1->dwHeight>=362) && (p1->dwWidth>=300))
			//{
			//	cManager::_p->SurfaceList.push_back(pDDS);
				//MessageBox(0, _bstr_t(CSC), "asd", 0);
				//557 or 333
			//}	

		   //if(CSC==1)
		   //{
			   
			 /*  CComObject< CDirectDrawSurfaceHook > *pHook;
			   CComObject< CDirectDrawSurfaceHook >::CreateInstance( &pHook );
			   pHook->setObject( pDDS );*/

			   bGotPrimary=true;
	   //if(!bGotPrimary)
	   //{
			   cManager::_p->setDirectDraw(m_pDD4, NULL, pDDS);
			   cManager::_p->setSurface(NULL);
	   //}
			}
			   
		   }
			   //pHook->QueryInterface( IID_IDirectDrawSurface4, reinterpret_cast< void ** >( ppDDS ) );
			//	return hRes;	
		   //}

		/*		pHook->QueryInterface(IID_IDirectDrawSurface4, reinterpret_cast< void ** >(ppDDS));
		   }
		   else*/
			   pDDS->QueryInterface(IID_IDirectDrawSurface4, reinterpret_cast< void ** >(ppDDS));
			   m_pPrimary = pDDS.p;

		   return hRes;
	}
	else
		return m_pDD4->CreateSurface(p1, ppDDS, p3);
}

STDMETHODIMP CDirectDrawHook::SetDisplayMode(DWORD p1, DWORD p2, DWORD p3, DWORD p4, DWORD p5)
{
   return m_pDD2->SetDisplayMode( p1, p2, p3, p4, p5 );
}

STDMETHODIMP CDirectDrawHook::CreateMaterial(LPDIRECT3DMATERIAL *p1,IUnknown *p2)
{
   CComPtr< IDirect3DMaterial > pMat;
   HRESULT hRes = m_pD3D->CreateMaterial( &pMat, p2 );

   if( FAILED( hRes ) )
      return hRes;

   CComObject< CMaterialHook > *pHook;
   CComObject< CMaterialHook >::CreateInstance( &pHook );
   pHook->setObject( pMat, m_pDevice2, m_pDevice3 );
   pHook->QueryInterface( IID_IDirect3DMaterial, reinterpret_cast< void ** >( p1 ) );

   return hRes;
}

STDMETHODIMP CDirectDrawHook::CreateMaterial(LPDIRECT3DMATERIAL2*p1,IUnknown*p2)
{
   CComPtr< IDirect3DMaterial2 > pMat;
   HRESULT hRes = m_pD3D2->CreateMaterial( &pMat, p2 );

   if( FAILED( hRes ) )
      return hRes;

   CComObject< CMaterialHook > *pHook;
   CComObject< CMaterialHook >::CreateInstance( &pHook );
   pHook->setObject( pMat, m_pDevice2, m_pDevice3 );
   pHook->QueryInterface( IID_IDirect3DMaterial2, reinterpret_cast< void ** >( p1 ) );

   return hRes;
}

STDMETHODIMP CDirectDrawHook::CreateMaterial(LPDIRECT3DMATERIAL3*p1,LPUNKNOWN p2)
{
   CComPtr< IDirect3DMaterial3 > pMat;
   HRESULT hRes = m_pD3D3->CreateMaterial( &pMat, p2 );

   if( FAILED( hRes ) )
      return hRes;

   CComObject< CMaterialHook > *pHook;
   CComObject< CMaterialHook >::CreateInstance( &pHook );
   pHook->setObject( pMat, m_pDevice2, m_pDevice3 );
   pHook->QueryInterface( IID_IDirect3DMaterial3, reinterpret_cast< void ** >( p1 ) );

   return hRes;
}

STDMETHODIMP CDirectDrawHook::CreateDevice( REFCLSID cls,LPDIRECTDRAWSURFACE pDDS,LPDIRECT3DDEVICE2 *ppD3D )
{
   CComPtr< IDirect3DDevice2 > pD3D;

   HRESULT hRes = m_pD3D2->CreateDevice( cls, pDDS, &pD3D );

   if( FAILED( hRes ) )
   {
	   ::MessageBox (NULL, "2COULDN'T CreateDevice IN D3D HOOK", "ERROR", MB_OK);

      return hRes;
	  }

   CComObject< CDirect3DHook > *pHook;
   CComObject< CDirect3DHook >::CreateInstance( &pHook );
   pHook->setObject( pD3D );

   pHook->QueryInterface( IID_IDirect3DDevice2, reinterpret_cast< void ** >( ppD3D ) );

   m_pDevice2 = *ppD3D;

   return hRes;
}

STDMETHODIMP CDirectDrawHook::CreateDevice(REFCLSID cls,LPDIRECTDRAWSURFACE4 pDDS,LPDIRECT3DDEVICE3* ppD3D,LPUNKNOWN pUnk)
{
   CComPtr< IDirect3DDevice3 > pD3D;

   HRESULT hRes = m_pD3D3->CreateDevice( cls, pDDS, &pD3D, pUnk );

   if( FAILED( hRes ) )
   {
	   ::MessageBox (NULL, "3COULDN'T CreateDevice IN D3D HOOK", "ERROR", MB_OK);
      return hRes;
	}

   // Ok, figure out if this is the "primary" 3d device
   DDSURFACEDESC2 ddsd;
   ddsd.dwSize = sizeof( DDSURFACEDESC2 );
   pDDS->GetSurfaceDesc( &ddsd );

   // Get the configured width from the registry
   DWORD dwConfiguredWidth;

   {
      RECT rc;
      ::GetClientRect( cManager::_p->m_hMain, &rc );
      dwConfiguredWidth = rc.right - rc.left;
   }

   if( ddsd.dwWidth < ( dwConfiguredWidth - 330 ) )
   {
	   // This is a secondary 3ddevice - do not hook it
      return pD3D->QueryInterface( IID_IDirect3DDevice3, reinterpret_cast< void ** >( ppD3D ) );
   }
   // Ok, we're past the wrong device, get to the right device
   cManager::_p->setSurface( pD3D );

   CComObject< CDirect3DHook > *pHook;
   CComObject< CDirect3DHook >::CreateInstance( &pHook );
   pHook->setObject( pD3D );

   pHook->QueryInterface( IID_IDirect3DDevice3, reinterpret_cast< void ** >( ppD3D ) );

   m_pDevice3 = *ppD3D;

   return hRes;
}
