HRESULT CheckRenderD3D10::ActiveRenderTargetToPPM(ID3D10Device *pDevice, const char *zFileName)
{
	ID3D10RenderTargetView *pRTV = NULL;
	pDevice->OMGetRenderTargets(1,&pRTV,NULL);

	ID3D10Resource *pSourceResource = NULL;
	pRTV->GetResource(&pSourceResource);

	return ResourceToPPM(pDevice,pSourceResource,zFileName);
}
// Detour function that replaces the IDXGISwapChain::Present() API
DllExport HRESULT __stdcall
hook_DXGISwapChainPresent(
		IDXGISwapChain * This,
		UINT SyncInterval,
		UINT Flags
	)
{
	static int frame_interval;
	static LARGE_INTEGER initialTv, captureTv, freq;
	static int capture_initialized = 0;
	//
	int i;
	struct pooldata *data;
	struct vsource_frame *frame;
	//
	DXGI_SWAP_CHAIN_DESC pDESC;
	HRESULT hr = pDXGISwapChainPresent(This, SyncInterval, Flags);	
		
	if(resolution_retrieved == 0) {
		if(DXGI_get_resolution(This) >= 0) {
			resolution_retrieved = 1;
		}
		return hr;
	}
	
	if(vsource_initialized == 0) {
		ga_error("video source not initialized.\n");
		return hr;
	}
	
	This->GetDesc(&pDESC);
	pDXGI_FORMAT = pDESC.BufferDesc.Format;   // extract screen format for sws_scale
	
	if(pDESC.BufferDesc.Width != game_width
	|| pDESC.BufferDesc.Height != game_height) {
		ga_error("game width/height mismatched (%dx%d) != (%dx%d)\n",
			pDESC.BufferDesc.Width, pDESC.BufferDesc.Height,
			game_width, game_height);
		return hr;
	}
	
	//
	if (enable_server_rate_control && ga_hook_video_rate_control() < 0)
		return hr;
	
	if (dx_version == dx_none) {
		//bool check_result = FALSE;
		if (check_dx_device_version(This, IID_ID3D10Device)) {
			dx_version = dx_10;
			ga_error("[DXGISwapChain] DirectX 10\n");
		} else if (check_dx_device_version(This, IID_ID3D10Device1)) {
			dx_version = dx_10_1;
			ga_error("[DXGISwapChain] DirectX 10.1\n");
		} else if (check_dx_device_version(This, IID_ID3D11Device)) {
			dx_version = dx_11;
			ga_error("[DXGISwapChain] DirectX 11\n");
		}
	}
	
	if (capture_initialized == 0) {
		frame_interval = 1000000/video_fps; // in the unif of us
		frame_interval++;
		QueryPerformanceFrequency(&freq);
		QueryPerformanceCounter(&initialTv);
		capture_initialized = 1;
	} else {
		QueryPerformanceCounter(&captureTv);
	}

	hr = 0;

	// d3d10 / d3d10.1
	if (dx_version == dx_10 || dx_version == dx_10_1) {
		
		void *ppDevice;	
		ID3D10Device *pDevice;
		//IUnknown *pDevice;

		if (dx_version == dx_10) {
			This->GetDevice(IID_ID3D10Device, &ppDevice);
			pDevice = (ID3D10Device *)ppDevice;
		} else if (dx_version == dx_10_1) {
			This->GetDevice(IID_ID3D10Device1, &ppDevice);
			pDevice = (ID3D10Device1 *)ppDevice;
		} else {
			OutputDebugString("Invalid DirectX version in IDXGISwapChain::Present");
			return hr;
		}

		ID3D10RenderTargetView *pRTV = NULL;
		ID3D10Resource *pSrcResource = NULL;
		pDevice->OMGetRenderTargets(1, &pRTV, NULL);
		pRTV->GetResource(&pSrcResource);

		ID3D10Texture2D* pSrcBuffer = (ID3D10Texture2D *)pSrcResource;
		ID3D10Texture2D* pDstBuffer = NULL;

		D3D10_TEXTURE2D_DESC desc;
		pSrcBuffer->GetDesc(&desc);
		desc.BindFlags = 0;
		desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ;
		desc.Usage = D3D10_USAGE_STAGING;

		hr = pDevice->CreateTexture2D(&desc, NULL, &pDstBuffer);
		if (FAILED(hr)) {
			OutputDebugString("Failed to create texture2D");
			//assert(exp_state == exp_none);
		}

		pDevice->CopyResource(pDstBuffer, pSrcBuffer);

		D3D10_MAPPED_TEXTURE2D mapped_screen;
		hr = pDstBuffer->Map(0, D3D10_MAP_READ, 0, &mapped_screen);
		if (FAILED(hr)) {
			OutputDebugString("Failed to map from DstBuffer");
			//assert(exp_state == exp_none);
		}

		// copy image 
		do {
			unsigned char *src, *dst;
			data = g_pipe[0]->allocate_data();
			frame = (struct vsource_frame*) data->ptr;
			frame->pixelformat = PIX_FMT_BGRA;
			frame->realwidth = desc.Width;
			frame->realheight = desc.Height;
			frame->realstride = desc.Width<<2;
			frame->realsize = frame->realwidth * frame->realstride;
			frame->linesize[0] = frame->realstride;//frame->stride;
			//
			src = (unsigned char*) mapped_screen.pData;
			dst = (unsigned char*) frame->imgbuf;
			for (i = 0; i < encoder_height; i++) {				
				CopyMemory(dst, src, frame->realstride/*frame->stride*/);
				src += mapped_screen.RowPitch;
				dst += frame->realstride;//frame->stride;
			}
			frame->imgpts = pcdiff_us(captureTv, initialTv, freq)/frame_interval;
		} while(0);
	
		// duplicate from channel 0 to other channels
		for(i = 1; i < SOURCES; i++) {
			int j;
			struct pooldata *dupdata;
			struct vsource_frame *dupframe;
			dupdata = g_pipe[i]->allocate_data();
			dupframe = (struct vsource_frame*) dupdata->ptr;
			//
			vsource_dup_frame(frame, dupframe);
			//
			g_pipe[i]->store_data(dupdata);
			g_pipe[i]->notify_all();
		}
		g_pipe[0]->store_data(data);
		g_pipe[0]->notify_all();
		
		pDstBuffer->Unmap(0);

		pDevice->Release();
		pSrcResource->Release();
		pSrcBuffer->Release();
		pRTV->Release();
		pDstBuffer->Release();

	// d11
	} else if (dx_version == dx_11) {
		void *ppDevice;	
		This->GetDevice(IID_ID3D11Device, &ppDevice);
		ID3D11Device *pDevice = (ID3D11Device*) ppDevice;

		This->GetDevice(IID_ID3D11DeviceContext, &ppDevice);
		ID3D11DeviceContext *pDeviceContext = (ID3D11DeviceContext *) ppDevice;
		
		ID3D11RenderTargetView *pRTV = NULL;
		ID3D11Resource *pSrcResource = NULL;
		pDeviceContext->OMGetRenderTargets(1, &pRTV, NULL);
		pRTV->GetResource(&pSrcResource);
	
		ID3D11Texture2D *pSrcBuffer = (ID3D11Texture2D *)pSrcResource;
		ID3D11Texture2D *pDstBuffer = NULL;
		
		D3D11_TEXTURE2D_DESC desc;
		pSrcBuffer->GetDesc(&desc);
		desc.BindFlags = 0;
		desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
		desc.Usage = D3D11_USAGE_STAGING;

		hr = pDevice->CreateTexture2D(&desc, NULL, &pDstBuffer);
		if (FAILED(hr)) {
			OutputDebugString("Failed to create buffer");
			//assert(exp_state == exp_none);
		}
		pDeviceContext->CopyResource(pDstBuffer, pSrcBuffer);

		D3D11_MAPPED_SUBRESOURCE mapped_screen;
		hr = pDeviceContext->Map(pDstBuffer, 0, D3D11_MAP_READ, 0, &mapped_screen);
		if (FAILED(hr)) {
			OutputDebugString("Failed to map from DeviceContext");
			//assert(exp_state == exp_none);
		}
		
		// copy image 
		do {
			unsigned char *src, *dst;
			data = g_pipe[0]->allocate_data();
			frame = (struct vsource_frame*) data->ptr;
			frame->pixelformat = PIX_FMT_BGRA;
			frame->realwidth = desc.Width;
			frame->realheight = desc.Height;
			frame->realstride = desc.Width<<2;
			frame->realsize = frame->realwidth * frame->realstride;
			frame->linesize[0] = frame->realstride;//frame->stride;
			//
			src = (unsigned char*) mapped_screen.pData;
			dst = (unsigned char*) frame->imgbuf;
			for (i = 0; i < encoder_height; i++) {				
				CopyMemory(dst, src, frame->realstride/*frame->stride*/);
				src += mapped_screen.RowPitch;
				dst += frame->realstride;//frame->stride;
			}
			frame->imgpts = pcdiff_us(captureTv, initialTv, freq)/frame_interval;
		} while(0);
	
		// duplicate from channel 0 to other channels
		for(i = 1; i < SOURCES; i++) {
			int j;
			struct pooldata *dupdata;
			struct vsource_frame *dupframe;
			dupdata = g_pipe[i]->allocate_data();
			dupframe = (struct vsource_frame*) dupdata->ptr;
			//
			vsource_dup_frame(frame, dupframe);
			//
			g_pipe[i]->store_data(dupdata);
			g_pipe[i]->notify_all();
		}
		g_pipe[0]->store_data(data);
		g_pipe[0]->notify_all();

		pDeviceContext->Unmap(pDstBuffer, 0);

		pDevice->Release();
		pDeviceContext->Release();
		pSrcResource->Release();
		pSrcBuffer->Release();
		pRTV->Release();
		pDstBuffer->Release();
	}

	return hr;
}
//--------------------------------------------------------------------------------------
// Render the scene using the D3D10 device
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D10FrameRender( ID3D10Device* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
{
    float ClearColor[4] = { 1.0f, 1.0f, 1.0f, 0.0f }; // R, G, B, A
    ID3D10RenderTargetView* pRTV = DXUTGetD3D10RenderTargetView();
    pd3dDevice->ClearRenderTargetView( pRTV, ClearColor );
    ID3D10DepthStencilView* pDSV = DXUTGetD3D10DepthStencilView();
    pd3dDevice->ClearDepthStencilView( pDSV, D3D10_CLEAR_DEPTH, 1.0, 0 );

    // If the settings dialog is being shown, then render it instead of rendering the app's scene
    if( g_D3DSettingsDlg.IsActive() )
    {
        g_D3DSettingsDlg.OnRender( fElapsedTime );
        return;
    }

    // Set our render target since we can't present multisampled ref
    ID3D10RenderTargetView* pOrigRT;
    ID3D10DepthStencilView* pOrigDS;
    pd3dDevice->OMGetRenderTargets( 1, &pOrigRT, &pOrigDS );
    ID3D10RenderTargetView* aRTViews[ 1 ] = { g_pRTRV };
    pd3dDevice->OMSetRenderTargets( 1, aRTViews, g_pDSRV );

    pd3dDevice->ClearRenderTargetView( g_pRTRV, ClearColor );
    pd3dDevice->ClearDepthStencilView( g_pDSRV, D3D10_CLEAR_DEPTH, 1.0, 0 );

    // Set Matrices
    D3DXMATRIX mWorldViewProj;
    D3DXMATRIX mWorldView;
    D3DXMATRIX mViewProj;
    D3DXMATRIX mWorld;
    D3DXMATRIX mView;
    D3DXMATRIX mProj;

    // Fix the camera motion for now
    D3DXMATRIX mBlurViewProj[MAX_TIME_STEPS];
    for( int i = 0; i < MAX_TIME_STEPS; i++ )
    {
        mView = *g_Camera.GetViewMatrix();
        mProj = *g_Camera.GetProjMatrix();
        mBlurViewProj[i] = mView * mProj;
    }
    g_pmBlurViewProj->SetMatrixArray( ( float* )mBlurViewProj, 0, MAX_TIME_STEPS );

    D3DXMatrixIdentity( &mWorld );
    mView = *g_Camera.GetViewMatrix();
    mProj = *g_Camera.GetProjMatrix();
    mViewProj = mView * mProj;
    mWorldViewProj = mWorld * mViewProj;
    mWorldView = mWorld * mView;

    g_pmWorldViewProj->SetMatrix( ( float* )&mWorldViewProj );
    g_pmViewProj->SetMatrix( ( float* )&mViewProj );
    g_pmWorldView->SetMatrix( ( float* )&mWorldView );

    RenderSceneMesh( pd3dDevice, &g_SceneMesh, false );
    RenderFanMesh( pd3dDevice, &g_FanMesh, fTime, false );
    if( g_bRenderOgre )
        RenderSkinnedMesh( pd3dDevice, &g_AnimMesh, fTime, false );

    for( UINT iMesh = 0; iMesh < g_NumLinkedMeshes; iMesh++ )
        RenderLinkedMesh( pd3dDevice, &g_pLinkedMeshes[iMesh], &g_AnimMesh, g_MeshLinkages[iMesh].iBone, fTime,
                          false );

    if( g_bUseMotionBlur )
    {
        RenderFanMesh( pd3dDevice, &g_FanMesh, fTime, true );
        if( g_bRenderOgre )
            RenderSkinnedMesh( pd3dDevice, &g_AnimMesh, fTime, true );

        for( UINT iMesh = 0; iMesh < g_NumLinkedMeshes; iMesh++ )
            RenderLinkedMesh( pd3dDevice, &g_pLinkedMeshes[iMesh], &g_AnimMesh, g_MeshLinkages[iMesh].iBone, fTime,
                              true );
    }

    //MSAA resolve
    ID3D10Resource* pRT;
    pOrigRT->GetResource( &pRT );
    D3D10_RENDER_TARGET_VIEW_DESC rtDesc;
    pOrigRT->GetDesc( &rtDesc );
    pd3dDevice->ResolveSubresource( pRT, D3D10CalcSubresource( 0, 0, 1 ), g_pRenderTarget, D3D10CalcSubresource( 0, 0,
                                                                                                                 1 ),
                                    rtDesc.Format );
    SAFE_RELEASE( pRT );

    // Use our Old RT again
    aRTViews[0] = pOrigRT;
    pd3dDevice->OMSetRenderTargets( 1, aRTViews, pOrigDS );
    SAFE_RELEASE( pOrigRT );
    SAFE_RELEASE( pOrigDS );

    DXUT_BeginPerfEvent( DXUT_PERFEVENTCOLOR, L"HUD / Stats" );
    RenderText();
    g_HUD.OnRender( fElapsedTime );
    g_SampleUI.OnRender( fElapsedTime );
    DXUT_EndPerfEvent();
}