Capturar janela via DirectX (C++)

Eu estava tentando entender/editar um codigo para capturar uma janela especifica pelo DirectX, como o “Capturar jogo” do OBS Studio faz, porém não consegui entender nenhum exemplo que encontrei na internet.

Eu encontrei esse codigo no github que duplica o Desktop pelo DirectX: https://github.com/arBmind/desktop-duplication-cpp, porém não faço ideia de como fazê-lo capturar uma janela específica ao invés do desktop, é totalmente diferente dos metodos que eu utilizava (PrintWindow\BitBlt).

Outro exemplo que eu encontrei foi esse, porém também não consegui entendê-lo:

void dump_buffer()
{
   IDirect3DSurface9* pRenderTarget=NULL;
   IDirect3DSurface9* pDestTarget=NULL;
     const char file[] = "Pickture.bmp";
   // sanity checks.
   if (Device == NULL)
      return;

   // get the render target surface.
   HRESULT hr = Device->GetRenderTarget(0, &pRenderTarget);
   // get the current adapter display mode.
   //hr = pDirect3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&d3ddisplaymode);

   // create a destination surface.
   hr = Device->CreateOffscreenPlainSurface(DisplayMde.Width,
                         DisplayMde.Height,
                         DisplayMde.Format,
                         D3DPOOL_SYSTEMMEM,
                         &pDestTarget,
                         NULL);
   //copy the render target to the destination surface.
   hr = Device->GetRenderTargetData(pRenderTarget, pDestTarget);
   //save its contents to a bitmap file.
   hr = D3DXSaveSurfaceToFile(file,
                              D3DXIFF_BMP,
                              pDestTarget,
                              NULL,
                              NULL);

   // clean up.
   pRenderTarget->Release();
   pDestTarget->Release();
}

Tentou com GetFrontBufferData() em lugar ou antes de GetRenderTargetData()?

E, acho que se você usar D3D9 não vai conseguir capturar tela de contextos D3D10, ou D3D11.

Obrigado pela resposta Kronal, eu não tentei o GetFrontBufferData() pois não sei como utilizar tal codigo, nunca tive experiencia com DirectX antes, o que eu creio que esteja faltando no código seja criar o “Device”, porém não faço ideia de como fazer isso. E sobre o D3D11, voce teria um exemplo de como eu faria?

Aqui nesse thread tem codigo que parece funcionar (o problema do cara é só com cores 16bits):

Sobre uso de D3D11 eu já vi fazerem captura de tela mas é muito mais complexo, até D3D10 já é bem mais complexo no geral que o 9, e sinceramente ta fora da minha alçada.

O codigo dele está incompleto, foi postado somente a parte da dúvida.

O D3DX foi deprecated desde o DX9.

No lugar, a MS recomenda o uso da biblioteca DirectXTex. Nele existe um módulo chamado ScreenGrab que torna o processo realmente simples.

using namespace DirectX;
using namespace Microsoft::WRL;

ComPtr<ID3D11Texture2D> backBuffer;
HRESULT hr = swapChain->GetBuffer( 0,
__uuidof( ID3D11Texture2D ),
   reinterpret_cast<LPVOID*>( backBuffer.GetAddressOf() ) );
if ( SUCCEEDED(hr) )
{
hr = SaveWICTextureToFile( immContext.Get(), backBuffer.Get(),
            GUID_ContainerFormatJpeg, L"SCREENSHOT.JPG" );
}
DX::ThrowIfFailed(hr);

Aproveite e também instale o DirectXTK que já inclui o ScreenGrab e várias outras funções bastante úteis para lidar com o DirectX. Observe que todos esses módulos são da própria Microsoft.

2 curtidas