我想快速访问使用directX9或10的游戏像素。因此我使用了D3D9库。当它是DirectX10游戏时,我是否必须使用D3D10库?如果这是真的,那么下一部分就无关紧要了。
以下代码有效,但我只在qDebug("%.2f, %.2f, %.2f, %.2f", pixel[0].r, pixel[0].g, pixel[0].b, pixel[0].a);
中得到零,尽管它应该有另一种颜色,我不知道为什么。交换数据时是否有错误?
初始化:
IDirect3D9 *m_d3d;
IDirect3DDevice9 *m_d3ddev;
D3DDISPLAYMODE *m_d3ddm;
HRESULT hr;
m_d3d = Direct3DCreate9(D3D_SDK_VERSION);
if (m_d3d == NULL)
{
qFatal("Cannot create Direct3D!");
}
m_d3ddm = (D3DDISPLAYMODE *)calloc(1, sizeof(D3DDISPLAYMODE));
hr = m_d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, m_d3ddm);
if (hr != D3D_OK)
{
m_d3d->Release();
qFatal("Cannot get DisplayMode!");
}
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = m_target;
d3dpp.BackBufferWidth = m_d3ddm->Width;
d3dpp.BackBufferHeight = m_d3ddm->Height;
d3dpp.BackBufferFormat = m_d3ddm->Format;
hr = m_d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_target, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &m_d3ddev);
if (FAILED(hr))
{
m_d3d->Release();
qFatal("Failed CreateDevice!");
}
else
{
qDebug("Created Device with %i * %i", m_d3ddm->Width, m_d3ddm->Height);
}
捕获
IDirect3DSurface9 *renderTarget= NULL;
IDirect3DSurface9 *destTarget = NULL;
hr = m_d3ddev->GetRenderTarget(0, &renderTarget);
if (FAILED(hr))
{
qFatal("Failed GetRenderTarget!");
}
hr = m_d3ddev->CreateOffscreenPlainSurface(m_d3ddm->Width, m_d3ddm->Height, m_d3ddm->Format, D3DPOOL_SYSTEMMEM, &destTarget, NULL);
if (FAILED(hr))
{
qFatal("Failed CreateOffscreenPlainSurface!");
}
hr = m_d3ddev->GetRenderTargetData(renderTarget, destTarget);
if (FAILED(hr))
{
qFatal("Failed GetRenderTargetData!");
}
D3DLOCKED_RECT lr;
ZeroMemory(&lr, sizeof(D3DLOCKED_RECT));
hr = destTarget->LockRect(&lr, 0, D3DLOCK_READONLY);
if (FAILED(hr))
{
qFatal("Cannot lock rect!");
}
ARGB *pixel = (ARGB *)lr.pBits;
if (!pixel)
{
qFatal("No data!");
}
qDebug("%.2f, %.2f, %.2f, %.2f", pixel[0].r, pixel[0].g, pixel[0].b, pixel[0].a);
hr = destTarget->UnlockRect();
if (FAILED(hr))
{
qFatal("Cannot unlock rect!");
}
renderTarget->Release();
destTarget->Release();
清洁
m_d3ddev->Release();
m_d3d->Release();
delete m_d3ddm;
delete m_d3d;
delete m_d3ddev;
答案 0 :(得分:3)
此代码模拟了您应该拥有的内容。它显示后备缓冲区实际上正在被捕获。我以与您完全相同的方式创建了设备。我以同样的方式捕获后缓冲区..
为了测试是否实际捕获了后缓冲区,我将窗口背景设置为海军蓝色。然后当我调用捕获函数时,我将缓冲区中的所有颜色与原始背景颜色进行比较..这让我知道单个像素是否与背景不同..
如果不同,我们可能"无法捕捉背景。否则,我们很好..
我已经测试了下面的内容,它确实捕获了后备缓冲区。我甚至将后备缓冲区保存到位图中,看它是否捕获了它并且它确实...
总而言之,您的代码没有任何问题,但我不能保证您正确使用它。换句话说,您还没有告诉我您在哪里调用后缓冲区捕获代码..它可以被调用很多地方,但最好的地方要么是在EndScene的钩子中,要么是对Present的钩子。如果您在自己的应用程序中使用它,请在onDraw / onUpdate函数中调用它。
#include <tchar.h>
#include <windows.h>
#include <d3d9.h>
#include <d3dx9.h>
#include <iostream>
HRESULT capture(IDirect3DDevice9* m_d3ddev, void* buffer, int& width, int& height, D3DFORMAT format);
void onUpdate(HWND hwnd, IDirect3D9* d3d9, IDirect3DDevice9* d3ddev9, D3DFORMAT format)
{
d3ddev9->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 40, 100), 1.0f, 0);
d3ddev9->BeginScene();
//All drawing goes here..
d3ddev9->EndScene();
d3ddev9->Present(NULL, NULL, NULL, NULL); //Swaps the back and front buffers. Displays all drawing on the screen..
RECT rect;
GetClientRect(hwnd, &rect);
int width = rect.right - rect.left, height = rect.bottom - rect.top;
unsigned char* buffer = new unsigned char[width * height * 4];
capture(d3ddev9, buffer, width, height, format);
unsigned char* px = buffer;
for(int i = 0; i < height; ++i)
{
for(int j = 0; j < width; ++j)
{
unsigned char B = *px++;
unsigned char G = *px++;
unsigned char R = *px++;
unsigned char A = *px++;
if(D3DCOLOR_XRGB(R, G, B) != D3DCOLOR_XRGB(0, 40, 100))
{
MessageBox(NULL, "FAILED.. Colour differs from original background..", NULL, 0);
}
}
}
delete[] buffer;
}
int onDisplay(HWND hwnd)
{
IDirect3D9* d3d9 = NULL;
IDirect3DDevice9* d3ddev9 = NULL;
D3DPRESENT_PARAMETERS Parameters = {0};
d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
D3DDISPLAYMODE* dispMode = new D3DDISPLAYMODE();
d3d9->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, dispMode);
Parameters.Windowed = true;
Parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
Parameters.hDeviceWindow = hwnd;
Parameters.BackBufferFormat = dispMode->Format;
d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &Parameters, &d3ddev9);
delete dispMode;
MSG messages;
ShowWindow(hwnd, SW_SHOW);
while(true)
{
if(PeekMessage(&messages, NULL, 0, 0, PM_REMOVE) > 0)
{
if(messages.message != WM_QUIT)
{
TranslateMessage(&messages);
DispatchMessageW(&messages);
continue;
}
break;
}
else
{
onUpdate(hwnd, d3d9, d3ddev9, Parameters.BackBufferFormat);
}
}
if(d3ddev9) d3ddev9->Release();
if(d3d9) d3d9->Release();
return messages.wParam;
}
LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
{
WNDCLASSEX wincl;
wincl.hInstance = hThisInstance;
wincl.lpszClassName = "D3DWindow";
wincl.lpfnWndProc = WindowProcedure;
wincl.style = CS_DBLCLKS;
wincl.cbSize = sizeof(WNDCLASSEX);
wincl.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor(NULL, IDC_ARROW);
wincl.lpszMenuName = NULL;
wincl.cbClsExtra = 0;
wincl.cbWndExtra = 0;
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
if(!RegisterClassEx(&wincl)) return 0;
HWND hwnd = CreateWindowEx(0, "D3DWindow", "D3D9: Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 544, 375, HWND_DESKTOP, NULL, hThisInstance, NULL);
return onDisplay(hwnd);
}
HRESULT capture(IDirect3DDevice9* m_d3ddev, void* buffer, int& width, int& height, D3DFORMAT format)
{
IDirect3DSurface9 *renderTarget= NULL;
IDirect3DSurface9 *destTarget = NULL;
HRESULT hr = m_d3ddev->GetRenderTarget(0, &renderTarget);
hr = m_d3ddev->CreateOffscreenPlainSurface(width, height, format, D3DPOOL_SYSTEMMEM, &destTarget, NULL);
if(FAILED(hr))
{
printf("Failed CreateOffscreenPlainSurface!");
}
hr = m_d3ddev->GetRenderTargetData(renderTarget, destTarget);
if(FAILED(hr))
{
printf("Failed GetRenderTargetData!");
}
D3DLOCKED_RECT lr;
ZeroMemory(&lr, sizeof(D3DLOCKED_RECT));
hr = destTarget->LockRect(&lr, 0, D3DLOCK_READONLY);
if(FAILED(hr))
{
printf("Cannot lock rect!");
}
if(lr.pBits)
{
memcpy(buffer, lr.pBits, width * height * 4);
}
hr = destTarget->UnlockRect();
if(FAILED(hr))
{
printf("Cannot unlock rect!");
}
renderTarget->Release();
destTarget->Release();
return hr;
}