Direct3D9 BackBuffer для PixelArray

Я пытаюсь подключить игру DirectX. Я успешно загрузил свой хук, и я могу сохранить изображения / backbuffer на диск, используя:

HRESULT Capture(IDirect3DDevice9* Device, const char* FilePath)
{
IDirect3DSurface9* RenderTarget = nullptr;
HRESULT result = Device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &RenderTarget);
//for some reason result is never S_OK but this still works.
result = D3DXSaveSurfaceToFile(FilePath, D3DXIFF_PNG, RenderTarget, nullptr, nullptr);
SafeRelease(RenderTarget);
return result;
}

Спасает успешно и я рад. Тем не менее, я хочу сохранить в массив пикселей, а не на диск. Я пытался с помощью:

#include <memory>

std::unique_ptr<std::uint8_t[]> mem(new std::uint8_t[100 * 100 * 4]);

HRESULT Direct3DDevice9Proxy::EndScene()
{
IDirect3DSurface9* RenderTarget = nullptr;
HRESULT result = ptr_Direct3DDevice9->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &RenderTarget);

D3DLOCKED_RECT LR;
RenderTarget->LockRect(&LR, nullptr, D3DLOCK_NOSYSLOCK | D3DLOCK_READONLY);
memcpy(mem.get(), LR.pBits, LR.Pitch - 1);
RenderTarget->UnlockRect();

SafeRelease(RenderTarget);
return ptr_Direct3DDevice9->EndScene();
}

Однако он никогда не блокируется и выдает нарушение прав доступа, если я пытаюсь получить доступ к LR.pBits. Я не уверен, почему он не заблокируется. Есть ли другой способ, которым я могу получить пиксели из буфера в байтовый массив? Максимальное окно просмотра игры 1366×768.

РЕДАКТИРОВАТЬ: Я пытался:

void dump_buffer(LPDIRECT3DDEVICE9 Device, std::unique_ptr<std::uint8_t[]> &bits)
{
IDirect3DSurface9* RenderTarget = nullptr;
IDirect3DSurface9* DestTarget = nullptr;
D3DSURFACE_DESC rtDesc = {};

Device->GetRenderTarget(0, &RenderTarget);
RenderTarget->GetDesc(&rtDesc);

Device->CreateOffscreenPlainSurface(rtDesc.Width, rtDesc.Height, rtDesc.Format, D3DPOOL_DEFAULT, &DestTarget, nullptr);
Device->GetRenderTargetData(RenderTarget, DestTarget);

if(DestTarget != nullptr)
{
D3DLOCKED_RECT rect;
DestTarget->LockRect(&rect, 0, D3DLOCK_READONLY);
memcpy(bits.get(), rect.pBits, rtDesc.Width * rtDesc.Height * 4);

std::uint8_t* ptr = &bits[0];
CG::Image(ptr, rtDesc.Width, rtDesc.Height).Save("Foo.bmp");

DestTarget->UnlockRect();
DestTarget->Release();
}

RenderTarget->Release();
}

HRESULT Direct3DDevice9Proxy::EndScene()
{
dump_buffer(ptr_Direct3DDevice9, mem);
return ptr_Direct3DDevice9->EndScene();
}

но мое изображение черное. Есть идеи?

0

Решение

Обратите внимание, что EndScene ставит в очередь сцену для рендеринга — вам не гарантируется, что что-либо было визуализировано до этого (или даже сразу после).

IDirect3DDevice9 :: GetFrontBufferData может быть более полезным для вас. Он «Создает копию переднего буфера устройства и помещает эту копию в системный буфер памяти, предоставленный приложением».

Что вы хотите сделать, это вызвать CreateOffscreenPlainSurface, чтобы создать pSurface в системной памяти, а затем вызвать GetFrontBufferData (0, pSurface).

0

Другие решения

Немного поздно. Но надеюсь, это кому-то поможет.

создание

        if (SUCCEEDED(hr = _device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backBuf)))
{
D3DSURFACE_DESC sd;
backBuf->GetDesc(&sd);

if (SUCCEEDED(hr = _device->CreateOffscreenPlainSurface(sd.Width, sd.Height, sd.Format, D3DPOOL_SYSTEMMEM, &_surface, NULL)))

отлов

    if (SUCCEEDED(hr = _device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backBuf)))
{
if (SUCCEEDED(hr = _device->GetRenderTargetData(backBuf, _surface)))
{
if (SUCCEEDED(hr = D3DXSaveSurfaceToFileInMemory(&buf, D3DXIFF_DIB, _surface, NULL, NULL)))
{
LPVOID imgBuf = buf->GetBufferPointer();
DWORD length = buf->GetBufferSize();

В buf у вас будут необработанные данные изображения.
Не забудьте выпустить все.

1

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector