关于对directx中抓图的代码。谁能提供?或者将我此贴的bcb代码转为delphi的(100分)

  • 主题发起人 主题发起人 火龙真人
  • 开始时间 开始时间

火龙真人

Unregistered / Unconfirmed
GUEST, unregistred user!
  该文是关于如何从前台缓冲区中读取数据并在DirectX 8.1中得到屏幕截图。这仅是获得带有反走样屏幕截图的方法的其中一种。此方法非常值得推荐,但在读此文之前,你应该对C++与DirectX 8有很好的理解(但不是必要的)。
  现在,我们以回顾双缓冲区的工作原理作为起点,假如这些东西你已经熟透,大可跳过这个段落。在今天,差不多所有的游戏使用名为双缓冲区的技术将游戏数据发送到屏幕上。绘制当前屏幕的工作都在离屏内存区内完成,例如象大家都知道的后台缓冲区。后台缓冲区的绘制工作完成后,然后切换或交换到可见缓冲区(前台缓冲区)。当切换/交换出现后至帧完成结束。三重缓冲区也是如此,它与双缓冲区之间仅有一个不同之处,三重缓冲区使用两个离屏内存区而不是一个。
  void TakeScreenShot(IDirect3DDevice8* device, char* file_name, int screenx, int screeny)
  {
    IDirect3DSurface8* frontbuf; // this is our pointer to the memory location containing our copy of the
                   // front buffer

    // now we create the image that our screen shot will be copied into
    // NOTE: Surface format of the front buffer is D3DFMT_A8R8G8B8 when it is returned
    device->CreateImageSurface(screenx, screeny, D3DFMT_A8R8G8B8, &frontbuf);

    // now we copy the front buffer into our surface
    HRESULT hr = device->GetFrontBuffer(frontbuf);

    // error checking
    if(hr != D3D_OK)
    {
      // do error handling etc...
      frontbuf->Release(); // release the surface so there is no memory leak
      return;
    }

    // now write our screen shot to a bitmap file
    // the last 2 params are NULL because we want the entire front buffer and no palette
    D3DXSaveSurfaceToFile(file_name, D3DXIFF_BMP, frontbuf, NULL, NULL);

    // release the surface so there is no memory leak
    frontbuf->Release();
  }

  在更进步一点,你可以变化这些方式。你可以在前台缓冲区的拷贝数据写到一个文件之前,在图像中加入你的水印(图像)处理过程(例如将你公司的标识水印粘到图像中)。如果你有任何问题,
或想了解注解,或者发现错误,请您通过电子邮件与我联系
 
还找到一篇可是不是delphi又是bcb
在DirectDraw的非独占模式中,主表面即为当前屏幕。你可以直接Lock住主表面,从而取得主表面图象数据。但如果你要对大量的数据进行直接的操作,最好还是先在SystemRAM中建一个和主表面一样大小的后台表面。用BltFast把主表面Copy一份到后台表面,然后锁住后台表面,再进行操作,这是因为CPU对显示RAM的操作是什分慢的。
实现步骤如下:
1. 初始化DirectDraw
2. 得到图象数据的起始位置指针
3. 图象数据的转换

1. 初始化DirectDraw
你可以响应WM_CREATE消息,并在OnCreate中初始化DirectDraw
void CMainFrame::InitDirectX()
{
//创建DirectDraw
if (FAILED( DirectDrawCreate(NULL,&ddraw1,NULL)))
{
TRACE("Couldn't create DirectDraw object./n");
}
if (FAILED( ddraw1->QueryInterface(IID_IDirectDraw2,(LPVOID *)&ddraw2)))
{
TRACE("Couldn't query the interface./n");
}
if (ddraw2)
{
ddraw2->SetCooperativeLevel(GetSafeHwnd(),DDSCL_NORMAL);
}
if (ddraw1)
{
ddraw1->Release();
ddraw1=NULL;
}
//创建主表面
HRESULT r;

DDSURFACEDESC desc;
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_CAPS;
desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
r=ddraw2->CreateSurface(&desc, &primsurf, 0);
if(r!=DD_OK)
{
AfxMessageBox("Create DirectX Surface failed/n ");
PostMessage(WM_CLOSE);
}
r=ddraw2->CreateClipper(0, &clipper, 0);
if(r!=DD_OK)
{
AfxMessageBox("CreateClipper() fialed/n ");
PostMessage(WM_CLOSE);
}
r=clipper->SetHWnd(0,GetSafeHwnd());
if(r!=DD_OK)
{
AfxMessageBox("SetHWnd() failed/n ");
PostMessage(WM_CLOSE);
}
r=primsurf->SetClipper(clipper);
if(r!=DD_OK)
{
AfxMessageBox("SetClipper() fialed/n ");
PostMessage(WM_CLOSE);
}
//创建后台表面
ZeroMemory(&desc,sizeof(desc));
desc.dwSize=sizeof(desc);
desc.dwFlags=DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS;
desc.dwWidth=::GetSystemMetrics(SM_CXSCREEN);
desc.dwHeight=::GetSystemMetrics(SM_CYSCREEN);
desc.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;

r=ddraw2->CreateSurface(&desc,&backsurf,0);
//收集图象参数
DDSURFACEDESC ddsd;

ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize=sizeof(ddsd);
backsurf->GetSurfaceDesc(&ddsd);
BitCount = ddsd.ddpfPixelFormat.dwRGBBitCount;
lPitch = ddsd.lPitch;
dwWidth = ddsd.dwWidth;
dwHeight = ddsd.dwHeight;
dwRBitMask = ddsd.ddpfPixelFormat.dwRBitMask;
dwGBitMask = ddsd.ddpfPixelFormat.dwGBitMask;
dwBBitMask = ddsd.ddpfPixelFormat.dwBBitMask;
//确定16Bit色时的修正(16Bit色时有两种显示格式565和555)
RMove = 8;//这里先假定为565格式
GMove = 3;
BMove = 3;
if(BitCount==16)
{
if(dwGBitMask==992)
{ //555格式
RMove = 7;
GMove = 2;
}
if(dwGBitMask==1984)//555格式
BMove = 2;
}
}

2. 得到图象数据的起始位置指针
DDSURFACEDESC ddsd;

ZeroMemory(&ddsd,sizeof(ddsd));
ddsd.dwSize=sizeof(ddsd);

if FAILED(backsurf->Lock(NULL, &ddsd, DDLOCK_WAIT , NULL))
TRACE("backsurf->lock failed/n");
// ddsd.lpSurface即为图象数据的指针

3. 图象数据的转换
DirectX是不支持图象格式转换的(DirectX7.0就不知到了,135MB要Download实在太恐怖了),如果你想得到的是24Bit的图象,而现在的显示模式为16Bit色,你就要自己动手了。(看过下面的代码后你可能会发现,经转换后图象是倒置的,这是我为了方便对数进行压缩而进行的,你可以改变其for循环语句把图象换过来。)
void CMainFrame:: Conversion()
{
int x,y;
DDSURFACEDESC ddsd;

ZeroMemory(&ddsd,sizeof(ddsd));
ddsd.dwSize=sizeof(ddsd);

if FAILED(backsurf->Lock(NULL, &ddsd, DDLOCK_WAIT , NULL))
TRACE("backsurf->lock failed/n");

BYTE *scr=new BYTE[3*ddsd.dwHeight*ddsd.dwWidth];
BYTE *scrt=scr;

//Surface to RGB
switch(BitCount)
{
case 8:
{
//TRACE("8 Bit/n");
BYTE *tem=(BYTE *)ddsd.lpSurface;
PALETTEENTRY entry[256];

HDC hScrDC=CreateDC("DISPLAY", NULL, NULL, NULL);
::GetSystemPaletteEntries(hScrDC,0,256, entry);

for(y=(int)dwHeight-1;y>=0;y--)
{
for(x=0;x<(int)dwWidth;x++)
{
*scrt++=entry[tem[x+lPitch*y]].peRed;
*scrt++=entry[tem[x+lPitch*y]].peGreen;
*scrt++=entry[tem[x+lPitch*y]].peBlue;
}
}
break;
}
case 16:
{
//TRACE("16 Bit/n");
WORD *tem=(WORD *)ddsd.lpSurface;
WORD color;
for(y=(int)dwHeight-1;y>=0;y--)
{
for(x=0;x<(int)lPitch/2;x++)
{
color=tem[x+lPitch/2*y];
*scrt++=(BYTE)((color&amp;dwRBitMask)>>RMove);
*scrt++=(BYTE)((color&amp;dwGBitMask)>>GMove);
*scrt++=(BYTE)(((color&amp;dwBBitMask))<<BMove);
}
}
break;
}
case 24:
{
//TRACE("24 Bit/n");
BYTE *tem=(BYTE *)ddsd.lpSurface;
for(y=(int)dwHeight-1;y>=0;y--)
{
for(x=0;x<(int)dwWidth*3;x+=3)
{
*scrt++=tem[x+2+y*lPitch];
*scrt++=tem[x+1+y*lPitch];
*scrt++=tem[x+y*lPitch];
}
}
break;
}
case 32:
{
AfxMessageBox("目前还不支持32Bit色/n请调整为24Bit色或16Bit色");
backsurf->Unlock(NULL);
delete scr;
PostMessage(WM_CLOSE);
break;
}
}
backsurf->Unlock(NULL);
//在里进行你的数据处理

delete scr;//数据处理完毕释放内存
}
请保留以下内容
E-mail: laical@21cn.com
Home page: http://laical.yeah.net or http://www.gz168.com/~laical
1999年10月12日
 
这么多人都看了,竟然就没人说句话。怪不得中国做不出好游戏
大家都去学数据库了吧?
 
用DelphiX解决算么?
procedure GetScreenshot;
var
ADIB:TDIB;
ScreenshotName:String;
begin
ScreenshotName:='screenshot.bmp';
ADIB:=TDIB.Create;
DXDraw.Surface.AssignTo(ADIB);
ADIB.SaveToFile(ScreenshotName);
FreeAndNil(ADIB);
end;
 
算!,好样的,哎,我正想多学点这些知识,可惜
工作原因不得不学数据库类的,现在学这些还不迟
还有个问题,热键问题,我想按一个热键截获游戏里的图形,
就象FPE那样,可是我用了热键。但只对WINDOWS下那种一般窗体的
进程会响应我的热键,可是进入游戏后,我的热键就不管用了啊
我会另提问题多加分的,
 
依旧用DelphiX来一段(最近正在用DelphiX写一个网络SRPG游戏):
用DirectInput,在主换循环中捕捉热键事件就是了。

//设置热键
procedure SetDXInputKeys;
const
KsButton1:TKeyAssign = (VK_F4,VK_F4,VK_F4); //热键为F4
begin
DXInput1.Keyboard.KeyAssigns[isButton1]:=KsButton1;
end;
//主循环中加入热键事件
procedure DXTimerTimer(Sender: TObject; LagCount: Integer);
begin
...
DXInput.Update;
if (isButton1 in DXInput.States) then
DoSomething;//比如截屏 GetScreenshot;
...
end;
 
最近忙着写游戏,不然我按原样给你转化为pascal 代码[:)]
以后有机会吧
 
呵呵太好了,哈哈,最后再问一下,有DELPHIX for delphi6 的么
呵呵,等此问题圆满解决,每位200分。
 
问题还是没有得到解决,照eguan说的那么做
只能在自己做的程序里检查得到按键,切换
到游戏里就不行
 
火龙真人用这个控件:
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1129967
有问题向xdzhan问
 
给你个网址:
http://turbo.gamedev.net/delphix.asp
另外最好用UnDelphiX Patch一下,这样就可以使用Jedi的DirectX头了。
东东在这里:
http://turbo.gamedev.net/undelphix.asp
 
我现在最想知道如何在其他游戏里也能让用自己定义的热件得到响应
 
热键与截图都不行.截别人游戏里就出现这问题
canvas dose not allow drawing

 
没办法啊没办法啊,怎么办啊 怎么办啊
 
呵呵,中国的delphier没有高手,别费心了!
 
to eguan
你的那段截屏代码怎么不对呀!我试了试截出来的图是黑屏的,我用的是delphix for d6
你给个完整的吧! hlzee@163.com
 
是啊,那是自己截自己定义的DDRAW的,怎么行啊,还有DELPHIX FOR 6好象没有吧
是从5那里改的是不是,我也改过,不过出好多问题哦
 
关注,谁有代码?smhp@163.net 谢谢!
 
D3DXSaveSurfaceToFile 这个函数好象不是 8 中的,不知道是不是附加的工具函数。
第一篇代码是 bcb ? 不会吧。
代码中,主表面应该是屏幕吧,但没有声明合作级别,使用的函数也怪怪的....
好象不是 DDraw 而是 Direct3D 模式吧。兄弟搞清楚说话啊。
第二篇是 DDraw 没错,不过主表面什么也没有。另外,在图象转换代码里,不看我还
知道要怎么写,看完了我倒晕了,越看越复杂,其实就是将字节位转为RGB输出吧。
以上内容,各位看得懂的部分,都是我写的,看不懂的或者有错误的,肯定不是我写的,
我也不知道是谁写的。
 
正在做,做出来了一点点,没试过截游戏的图行不行,用的是第二种方法,火兄如果做出来
了可否给点好的算法和代码
 
后退
顶部