高分急寻directx高手:如何在directdraw图面上直接画点。 (300分)

  • 主题发起人 主题发起人 fbc-gc
  • 开始时间 开始时间
F

fbc-gc

Unregistered / Unconfirmed
GUEST, unregistred user!
如何直接在一个directdraw图面上直接画点。
这儿有一个c语言的例子:
http://gmm.3322.net/docs/myself/drawpixel.htm
请帮忙转化并验证一下!
 
试试下面的方法,在图象的(X,Y)坐标处画一个红色的小点!^_^
很类似你说的那网页中的第一种方法!
Var
H : HDC;
begin
H:=image1.Canvas.Handle;
Windows.SetPixel(H,X,Y,clRed);
end;
 
那样不行,因为太慢。
我想用的是在directx下直接写表面!
谢谢
 
用 DelphiX 控件啊!
 
不想用delphix控件,不如API灵活.
 
没人回答?
唉,只有给jedi-directx的国外高手发邮件了。
 
咦?你贴的那个网址怎么上不了了?想看了以后转换一下都不行了![:(]
像jedi-directx的国外高手发邮件?呵呵!实在是欺我中华无人?那儿的邮件也不一定会有人解答你!
我曾经关于DirectX发过一个帖子,结果E-E、Jedi、GameMake这些顶尖论坛也没人能回答,还是靠自己凑合解决的。
你这个问题并不难啊,起码在DirectX中,不知道你平时又是如何画线的呢?呵呵!画点都成问题!
大富翁上藏龙卧虎,能人异士极多,只是你不识啊!不过不需要他们现身!
就让我这等无名之辈来献丑吧!^_^
那张网页的第二种方法(你想要的就是那种吧!),当时没大仔细看,不过粗粗记得一点!
在DirectX下直接写表面示例如下:
var lpDDSurfaceDesc : DDSurfaceDesc;
lpDDSurfaceDesc.dwSize := SizeOf(lpDDSurfaceDesc);
Hr := backbuf.Lock (rect(0,0,100,50), lpDDSurfaceDesc, DDLOCK_WRITEONLY, 0);
... 这里写下你的 GetPixel() and SetPixel() 代码即可画点 ...
backbuf.Unlock(lpDDSurfaceDesc.lpSurface);
surface.Flip(nil, DDFLIP_WAIT);
 
谢谢YB_unique‘前辈’:)!我可没有小看delphibbs论坛哟,我可是每天10小时在线呀。
下面是我保存下来的网页,您再给转化一下吧。:
thanks!
//////////////////////////
DirectDraw下画点
(CDirectX原创)

连载于《电脑爱好者》的《走进DirectX世界》中曾介绍了DirectDraw的初始化及一些基本操作。朋友们看后一定会发现DirectDraw并未提供画点函数。其实,并非不能有此函数,只是M$偷了个懒,把这些低级函数留给我们去写。

常规方法
LPDIRECTDRAWSURFACE中提供了GetDC函数,我们可以用它取得与DirectDraw兼容的HDC,然后用WinGDI函数画点:

…… //初始化部分请参考《走进DirectX世界》,假设lpDDSurface是一个已初始化的表面
HDC hDC;
lpDDSurface->GetDC(&hDC);//获取兼容DC
COLORREF crCol = ::GetPixel(hDC,200, 200);//取得(200, 200)处的颜色值
::SetPixel(hDC, 100, 100, RGB(128, 128, 128));//在(100,100)画一个灰点
lpDDSurface->ReleaseDC(hDC);//别忘了释放DC
……

这种方法简单易用,而且不容易出错,但是它的缺点也是致命的,那就是速度太慢,效率太低,根本不可能在游戏中用。现在让我们看看第二种方法。

直接写表面
什么,没搞错吧?Win32下也可以这么做?当然,只有想不到,没有做不到。下面介绍两个重要的LPDIRECTDRAWSURFACE的成员函数:

HRESULT Lock(LPRECT lpDestRect,//指向RECT结构的指针,定义了我们要Lock的区域,
//如果为NULL,则Lock整个表面
LPDDSURFACEDDESC lpDesc, //被锁表面的属性
DWORD dwFlags, //一般为DDLOCK_WAIT
HANDLE hEvent //取NULL
);

HRESULT UnLock(LPVOID lpSurfacePointer); //取NULL

当运行Lock后,当前页面被DirectDraw锁定,并且获得指向该页面上相应区域(用户指定的矩形区域)的内存区的地址。将填充一个DDSURFACEDESC结构,描述了你要正确的访问页面内存所需要的所有信息,如lpSurface是指向图像内存的起始位置的指针ddpfPixelFormat则用于描述点的格式。如果页面的像素格式与主页面的不一样,该结构中还包含了关于页面的宽距(pitch)和像素格式的信息。当应用程序结束了对页面内存的访问,可以调用Unlock以解锁页面。

注意:如果在你调用Lock函数的时候,对于该页面的一次Blit操作还在进行之中,函数将立即返回一个错误值。要防止这种情况的发生,可以在调用Lock函数的过程中指定DDLOCK_WAIT标志,以表明该函数将等待,直到成功的获得锁定之后才返回。

现在可以写操作点的函数了

DDSURFACEDDESC Desc;
……
DWORD GetPixel(int x, int y) //取(x, y)点
{
DWORD dwCol; LPBYTE lpBitmap = (LPBYTE)Desc.lpSurface; //lpBitmap中存放的是图像数据
DWORD dw = Desc.ddpfPixelFormat.dwRGBBitCount; //颜色位数
lpBitmap += y * Desc.lPitch + x * (dw >> 3); //到达指定坐标的RAM地址
dwCol = *(DWORD*)lpBitmap;
dwCol &amp;= (1 <<dw) - 1; //(1 << dw)–1相当于一个位屏蔽器,获得需要的位
return dwCol;
}

void PutPixel(int x, int y, DWORD dwCol) //在(x, y)画点dwCol
{
LPBYTE lpBitmap = (LPBYTE)Desc.lpSurface;
DWORD dw = Desc.ddpfPixelFormat.dwRGBBitCount;
lpBitmap += y * Desc.lPitch + x * (dw >> 3);
*(DWORD*)lpBitmap &amp;= ~((1 << dw) - 1); // 把该填色的位清除
*(DWORD*)lpBitmap |= dwCol; // OR填上颜色了
}

注意:dwCol的数据类型是DWORD,不是COLORREF。所以,COLORREF类型必须通过DDColorMatch函数(在DXUTL.cpp中)转化为DWORD类型。

实际上,GetDC函数暗中的调用了Lock锁定页面,并且ReleaseDC函数暗中的调用了Unlock使页面解锁。

有了高效的画点函数,我们就可以构造出画直线,画圆等函数,具体可以参照《您好,游戏世界》。(以上程序在VC++5.0&amp;DirectX SDK 7.0下运行通过)
/////////////////////////////////////////
 
呵呵!不敢当‘前辈’二字! 我好像没那么老啊?^_^
其实和你一样,我加入这个论坛的时间也不是很长!

看来你没有仔细阅读我贴的代码,那段代码的核心算法就和你贴的第二种一样啊!第一种的就和最上面那段一样!
另推荐一个好的游戏开发(包括DirectX、OpenGL)论坛——http://www.gamedev.net/
有什么问题去那先瞧瞧,可能有意想不到的结果喔!
 
谢谢YB_unique.
那GetPixel() and SetPixel()如何转化为object pascal呢?
我对c太不熟悉了.
大一上半学期学pascal,爱不释手,下半学期学c时居然逃课去学校机房用turbo pascal写挖雷。
现在想接受c是很难了。就像母语是汉语,再学英语一样
 
GetPixel() and SetPixel() 都已经在 Delphi的API函数里了!
GetPixel获得象素,SetPixel设置像素颜色。如我的第一次回帖示例!
 
Delphi API中的GetPixel() and SetPixel() 能像directdraw surface写点?
应该不可以吧,正确的方法应该是直接操作内存.
那我自己转化一下下面两个函数吧:
DWORD GetPixel(int x, int y) //取(x, y)点
{
DWORD dwCol; LPBYTE lpBitmap = (LPBYTE)Desc.lpSurface; //lpBitmap中存放的是图像数据
DWORD dw = Desc.ddpfPixelFormat.dwRGBBitCount; //颜色位数
lpBitmap += y * Desc.lPitch + x * (dw >> 3); //到达指定坐标的RAM地址
dwCol = *(DWORD*)lpBitmap;
dwCol &amp;= (1 <<dw) - 1; //(1 << dw)–1相当于一个位屏蔽器,获得需要的位
return dwCol;
}

void PutPixel(int x, int y, DWORD dwCol) //在(x, y)画点dwCol
{
LPBYTE lpBitmap = (LPBYTE)Desc.lpSurface;
DWORD dw = Desc.ddpfPixelFormat.dwRGBBitCount;
lpBitmap += y * Desc.lPitch + x * (dw >> 3);
*(DWORD*)lpBitmap &amp;= ~((1 << dw) - 1); // 把该填色的位清除
*(DWORD*)lpBitmap |= dwCol; // OR填上颜色了
}
 
那样也可以,不过效果效率都很差,自己转换一下那两个函数即可!
 
一个DirectX下的画点函数:
Uses DDraw;

Procedure DrawPixel(X,Y:Integer;C:Byte;Desc:TDDSurfaceDesc);
Type TScreen=Array Of Byte;
Begin
If (X>=0) And (X<=639) And (Y>=0) And (Y<=479) Then Begin
TScreen(Desc.LPSurface)[X+Y*Desc.LPitch]:=C;
End;
End;
 
谢谢YB_unique啦!
用上面你说的那种(TScreen=Array Of Byte)可以画点了。另外我的C真是太差劲了,没转化过来。你能不能把那两个函数转化一下?
 
练习程序写完了: http://go6.163.com/progame/mytest.html
 
接受答案了.
 
后退
顶部