2014-09-25 4 views
0

Хорошо, так что для тех, кто использовал его много - это должен быть легкий вопрос SUPER.с использованием GetFrontBufferData(), и скриншот места в отдельном устройстве backbuffer

Я просто искал в Интернете способ использовать DirectX/Direct3D для более быстрого скриншота, и все говорили о GetFrontBufferData() и о том, как это было замечательно.

Я немного набросился на него, но я начинаю думать, что они неправильно используют термин «скриншот» ... Мой звонок преуспевает, но я никогда не получаю «скриншот».

Так вопрос является, вы можете на самом деле использовать GetFrontBufferData(), чтобы сделать реальный скриншот всего рабочего стола, или это просто способ чтения пикселей из переднего буфера в пределах вашего d3d- область рисования устройства?

(После успеха я бы ожидал увидеть область чертежа в моем окне, чтобы сделать это старое телевидение в телевизоре в телевизоре в телевизионном эффекте. черный)

Edit:.

Итак, я был в состоянии получить снимок экрана, чтобы работать, но не могу поставить мое изображение в буфер для моего окна приложения.

Сначала я думал, что это были разные устройства, но я попытался создать вторую поверхность на правильном устройстве и затем вручную скопировать содержимое. (Хотя я могу скопировать его неправильно ((не важно сейчас)), вызов на растяжку по-прежнему не подходит для правильного устройства.

Любая идея, почему это не позволит мне применить эту поверхность к моему backbuffer ???

D3DDISPLAYMODE   d3dDisplayMode; 
D3DPRESENT_PARAMETERS d3dPresentationParameters; 

if((d3d=Direct3DCreate9(D3D_SDK_VERSION))==NULL) 
    exit(1); 
D3DCAPS9 d3dcps; 
d3d->GetDeviceCaps(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,&d3dcps); 
DWORD targets = d3dcps.NumSimultaneousRTs; 
// TODO:^make a way for user to select one from this and put it into i 
DWORD i=D3DADAPTER_DEFAULT; 

if(d3d->GetAdapterDisplayMode(i,&d3dDisplayMode)==D3DERR_INVALIDCALL) 
    exit(1); 

ZeroMemory(&d3dPresentationParameters,sizeof(D3DPRESENT_PARAMETERS));//Fills a block of memory with zeros. 
d3dPresentationParameters.Windowed = TRUE; 
d3dPresentationParameters.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; 
d3dPresentationParameters.BackBufferFormat = d3dDisplayMode.Format;//d3dDisplayMode.Format;//D3DFMT_A8R8G8B8; 
d3dPresentationParameters.BackBufferCount = 1; 
d3dPresentationParameters.BackBufferHeight = d3dDisplayMode.Height; 
d3dPresentationParameters.BackBufferWidth = d3dDisplayMode.Width; 
d3dPresentationParameters.MultiSampleType = D3DMULTISAMPLE_NONE; 
d3dPresentationParameters.MultiSampleQuality = 0; 
d3dPresentationParameters.SwapEffect = D3DSWAPEFFECT_DISCARD; 
d3dPresentationParameters.hDeviceWindow = hwDesktop; 
d3dPresentationParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; 
d3dPresentationParameters.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; 

if(d3d->CreateDevice(i,D3DDEVTYPE_HAL,hwDesktop,D3DCREATE_SOFTWARE_VERTEXPROCESSING,&d3dPresentationParameters,&d3dcdev) != D3D_OK) 
    exit(1); 

if(d3dcdev->CreateOffscreenPlainSurface(d3dDisplayMode.Width,d3dDisplayMode.Height,D3DFMT_A8R8G8B8,D3DPOOL_SYSTEMMEM,&sfScrn, NULL) != D3D_OK) 
    exit(1); 

if(d3dcdev->GetFrontBufferData(0,sfScrn) != D3D_OK) 
    exit(1); 

// we now have a screenshot in sfScrn. 
// let's render it to a separate device in our app window! 
d3dPresentationParameters.hDeviceWindow = hwDrawArea; 
if(d3d->CreateDevice(i,D3DDEVTYPE_HAL,hwDrawArea,D3DCREATE_SOFTWARE_VERTEXPROCESSING,&d3dPresentationParameters,&d3drdev) != D3D_OK) 
    exit(1); 
d3drdev->GetBackBuffer(0,0,D3DBACKBUFFER_TYPE_MONO,&sfBackBuffer); 
if(d3drdev->CreateOffscreenPlainSurface(d3dDisplayMode.Width,d3dDisplayMode.Height,D3DFMT_A8R8G8B8,D3DPOOL_SYSTEMMEM,&sfTransfer, NULL) != D3D_OK) 
    exit(1); 

D3DLOCKED_RECT lockedRectScrn, lockedRectTransfer; 
ZeroMemory(&lockedRectScrn, sizeof(D3DLOCKED_RECT)); 
ZeroMemory(&lockedRectTransfer, sizeof(D3DLOCKED_RECT)); 
if(sfScrn->LockRect(&lockedRectScrn,NULL,D3DLOCK_READONLY) != D3D_OK 
    || sfTransfer->LockRect(&lockedRectTransfer,NULL,0) != D3D_OK) 
    exit(1); 
memcpy((BYTE*)lockedRectTransfer.pBits,(BYTE*)lockedRectScrn.pBits,lockedRectScrn.Pitch*d3dDisplayMode.Height); 
sfScrn->UnlockRect(); 
sfTransfer->UnlockRect(); 

while(true) 
{ 
    if(d3drdev != NULL) 
    { 
     d3drdev->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(75,0,0),1.0f,0); 
     if(D3D_OK!=d3drdev->StretchRect(sfTransfer,NULL,sfBackBuffer,NULL,D3DTEXF_NONE)) 
     { 
      MessageBox(NULL,"failed to use stretchrect","",0); 
      exit(1); 
     } 
     if(d3drdev->BeginScene()) 
     { 
      d3drdev->EndScene(); 
     } 
     d3drdev->Present(NULL,NULL,NULL,NULL); 
    } 
} 

Edit2:..

о Таким образом, очевидно, вы не можете использовать StretchRect() на поверхностях, находящихся в D3DPOOL_SYSTEMMEM, но вы должны использовать GetFronBufferData() на D3DPOOL_SYSTEMMEM

ответ

2

Да, вы можете захватите рабочий стол Windows, используя GetFrontBufferData. Я могу предложить это recent question, где плакат работал, за исключением случаев, когда рабочий стол использовал 16-битный цвет. Это может дать вам некоторое представление о том, как правильно использовать его.

Но нет, это не «истинная цель» GetFrontBufferData. Реальная цель - позволить Direct3D-играм снимать скриншоты самой игры независимо от того, была ли игра оконной или полноэкранной, и что самое главное, независимо от того, использует ли игра мультисэмплинг или нет.

GetFrontBufferData не предназначен, чтобы быть лучшим способом сделать скриншоты рабочего стола Windows. Возможно, это быстрее, чем другие методы, но это не значит, что он существует.

+0

Эй, спасибо! Я понял, что моя способность получить скриншот в моем другом бэкбуфере - моя главная проблема. Заставляет меня задаться вопросом, сколько успешных попыток у меня было на скриншоте раньше, не осознавая этого. – user980058