上面,g_pd3dDevice
是一个初始化好的IDirect3DDevice 对象,这个例子直接把捕捉到的图像保存到文件。然而,有时候我们想访问直接这个图像中的各个位,我们可以使用 IDirect3DSurface8:ockRect() ,它给我们一个执行 surface 内存的指针,也就是捕捉到的图像的数据。我们复制这些数据到程序定义的内存中就可以操作它了。看下面的代码:
extern void* pBits; extern IDirect3DDevice8* g_pd3dDevice; IDirect3DSurface8 * pSurface; g_pd3dDeviceàCreateImageSurface(ScreenWidth,ScreenHeight, D3DFMT_A8R8G8B8,&pSurface); g_pd3dDevice->GetFrontBuffer(pSurface); D3DLOCKED_RECT lockedRect; pSurfaceàLockRect(&lockedRect,NULL, D3DLOCK_NO_DIRTY_UPDATE|D3DLOCK_NOSYSLOCK| D3DLOCK_READONLY))); for( int i=0 ; i < ScreenHeight ; i++) { memcpy( (BYTE*) pBits + i * ScreenWidth * BITSPERPIXEL / 8 , (BYTE*) lockedRect.pBits + i* lockedRect.Pitch , ScreenWidth * BITSPERPIXEL / 8); } g_pSurface->UnlockRect(); pSurface->Release();
上面的pBits是一个void*,请保证为先为它分配组足够的内存空间。BITSPERPIXEL一般用32位色即可,它也取决于你的显示器当前配置。一个需要注意的是,surface的宽度和被捕捉的屏幕宽度不一样。由于内存对齐的原因(按WORD对齐的内存通常在访问时效率较高),surface在每行结尾处可能会有多余的bits以使它对齐到word边界上。lockedRect.Pitch 给我们提供了两个连续行的开端之间的字节数。也就是说我们在读取一行时要向后移动指针 Pitch 字节而不是 Width 字节。你可以用下面的代码反序复制 surface :
for( int i=0 ; i < ScreenHeight ; i++) { memcpy((BYTE*) pBits +( ScreenHeight - i - 1) * ScreenWidth * BITSPERPIXEL/8 , (BYTE*) lockedRect.pBits + i* lockedRect.Pitch , ScreenWidth* BITSPERPIXEL/8); } 这对于从top-down位图到bottom-up位图很有用。
我们还可以使用IDirect3DSurface9 的
GetDC() 方法取得 DirectX surface 的 GDI 兼容 DC ,然后复制它的内容到我们的兼容 DC 。如果你用的是 DirectX9 ,试试吧。
|