📄 directdraw
字号:
DirectDraw 游戏编程基础(2)
游戏使计算机的发展超越了晶体管时代
微软公司供稿
例程1(DDEX1):DirectDraw 的基本知识
在使用 DirextDraw时,需要首先创建一个对象DirectDraw 的实体,该对象实体代表了微机显示适配器。然后,使用接口所提供的方法来操作该对象实体,使之完成有关命令和任务。接着,你还需要创建一个或多个 DirectDraw-surface对象的实体,以便能在图形表面(Surface)上展示你的游戏画面。
下面,在例程 DDEX1 中展示如何使用Directx 3 SDK来 DirectDraw对象实体,如何创建一个带有后台缓冲区的基本表面(Surface),以及如何弹出表面(Surface)。
注意:所有的例程都是用C++写成的,如果你的编辑器是C,你需要在文件中作出某些改动(至少,你要加入 Vtable 和指向各种接口方法的 this 指针)。
DirectDraw 初始化:
DirectDraw 初始化代码写在例程 DDEX1 的 doInit 函数中。
/*
* Create the main DirectDraw object.
*/
ddrval = DirectDrawCreate(NULL,&lpDD,NULL);
if(ddrval==DD_OK)
{
//Get exclusive mode.
Ddrval=lpdd->SetCooperativeLevel(hwnd,
DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN);
if(ddrval==DD_OK)
{
//Create the primary surface with 1 back buffer.
Ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS \ DSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
DDSCAPS_FLIP |
DDSCAPS_COMPLEX;
ddsd.dwBackBufferCount = 1;
ddrval = lpDD->CreateSurfae(&ddsd, &lpDDSPrimary,
NULL);
if(ddrval == DD_OK)
{
//Cet a pointer to the back buffer.
Ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
ddrval = lpDDSPrimary->GetAttachedSurface(&ddscaps,
&lpDDSBack);
if( ddrval == DD_OK)
{ // Draw some text.
If(lpDDSPrimary->GetDC(&hdc) == DD_OK)
{
SetBkColor(hdc, RGB(0,0,255));
SetTextColor( hdc,RGB(255,255,0 ) );
TextOut( hdc, 0, 0, sxFrontMsg, lstrlen(szFrontMsg ));
lpDDSPrimary->ReleaseDC(hdc);
}
if(lpDDSBack->GetDC(&hdc) == DD_OK)
{
SetBkColor( hdc, RGB(0, 0, 255 ) );
SetTextColor( hdc, RGB( 255,255, 0 ) ):
TexOut( hdc, 0, 0, szBackMsg, lstrlen( szBackMsg ) );
lpDDSBack->ReleaseDC(hdc);
}
// Create a timer to flop the pages.
If(SetTimer( hwnd, TIMER_ID, TIMER_RATE, NULL))
{
return TRUE;
}
}
}
}
}
}
wsprintf(buf,"Direct Draw Init Failed (%08lx)\n",ddrval);
.
.
.
以下针对初始化 DirectDraw 对象和准备表面(Surface)集的各个步骤分别进行讨论:
创建一个 DirectDraw 对象
为了创建一个 DirecDraw 对象实体,你应该在程序中使用DirectDrawCreate API 函数(注意:这里我所说的是应该,而不是必须), 这是因为使用 OLE 中的 CoCreatelnstance 函数也能创建一个 DirectDraw 对象实体,但这不在我们的讨论范围之中)。DirectDrawCreate 采用全球统一的标准,它代表显示设备,这些显示设备在大多数情况下被定为 NULL (即:系统使用缺省的显示设备)。 当DirectDraw对象实体创建好后,就会有一个指针指向该对象实体。而且,在调色板中有三分之一的指针指向 NULL (这样做的目的是为了今后的扩展)。
接下来的例子说明如何创建一个DirectDraw 对象,并判别该对象是否创建成功:
ddrval = directDrawCreat( NULL, &lpDD, NULL );
if( ddrval == DD_OK )
{
//lpDD is a valid DirectDraw object.
}
else
{
//DirectDraw object could not be created.
}
使用 IDirectDraw2 和 IDirectDrawSurface2 接口
在你读本文的其他部分时,你会注意到所有的例程都使用的是 IDirectDraw和 IDirectDrawSurface 的老版本接口。这是因为 DirectX 3 SDK 所给出的例程还没有来及使用 IDirectDraw 和 IDirectDrawSurface 更新后的接口。你可以通过调用 IDirectDraw::QueryInterface 方法来得到 IDirectDraw2 和IDirectDrawSurface2 接口。
下面的代码给出如何得到 IDirectDraw2 接口:
// Create an IDirectDraw2 interface.
LPDIRECTDRAW lpDD;
ddrval = DirectDrawCreate( NULL, &lpDD, NULL);
if(ddrval != DD_OK)
return;
ddrval = lpDD->SetCooperativeLevel(hwnd, DDSCL_NORMAL);
if(ddrval != DD_OK)
return;
ddrval = lpDD->QueryInterfave(IID_IDirectDraw2, (lPVOID *)&lpDD2);
if(ddrval !=DD_OK)
return;
下面的代码给出如何得到 IDirectDrawSurface2 接口:
LPDIRECTDRAWSURFACE lpSurf;
LPDIRECTDRAWSURFACE lpSurf2;
// Create surfaces.
Memset( &ddsd, 0, sizeof(ddsd ));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS |DDSD_WIDTH |DDSD_HEIGHT;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN |
DDSCAPS_SYSTEMMEMORY;
ddsd.dwWidth = 10;
ddsd.dwHeight = 10;
ddrval = lpDD2->CreateSurface( &ddsd, &lpSurf, NULL);
if(ddrval != DD_OK)
return;
ddrval = lpSurf->QueryInterface(
IID_IDirectDrawSurface2, ( LPVOID *(&lpSurf2);
if(ddrval !=DD_OK)
return;
设置显示模式
安装DirectDraw 的下一步是设置显示模式。在DirectDraw应用程序中设置显示模式关键有两个步骤:第一,调用Idirectdraw::SetCooperativelevel方法设置底层参数。设置好底层参数后,再调用 IDirectDraw::SetdisplayMode方法来设置显示方式。
确定应用程序的运行特征:
如果你想改变你的显示方式 , 你必须先在调色板的 dwFlags 中设置 DDSCL_ EXCLUSIVE 和 DDSCL_FULLSCREEN 标志。其中,调色板的dwFlags包含在IDirectDraw::SetCooperativelLevel 方法中。这样一来,你的应用程序就可以单独占用显示设备,而使其它进程不能共享显示设备。 另外 , 标志DDSCL_FULLSCREEN 把显示设备置为全屏幕方式。正如在运行DDWX1时见到的那样,当同时按下ALT键和TAB键后,最初的表面(Surface)(尽管仍然有效)会被你的表面(Surface)所覆盖,且只有你的表面(Surface)能够进行写屏操作。
下面的例子说明如何使用 IDirectDraw::SetCooperativeLevel:
HRESULT ddrval;
LPDIRECTDRAW lpDD; // already created by DirectDrawCreate
ddrval = lpDD->SetCooperativeLevel(hwnd, DDSCL_EXCLUSIVE |
DDSCL_FULLSCREEN);
if(ddrval == DD_OK)
{
// exclusive mode was successful
}
else
{
// not successful
// however, the application can still run
}
如果 IDirectDraw::SetCooperativeLevel 不返回 DD_OK,你的应用程序仍能继续执行,但是我不主张这样做。因为这样会使你的程序无法工作在全屏幕模式下,而且可能不按照你预先的要求工作。如果你确实想使你的应用程序继续运行下去,你应该显示一个错误信息,以便使终端用户知道 IDirectDraw ::SetCooperativeLevel 没有返回DD_OK,然后由用户自己去决定是否继续执行该程序。
使用IDirectDraw::SetCooperativeLevel 时,有一个要求:给每一个窗口赋一个句柄。这样当你的应用程序被异常中止时,Windows 能够知道。例如:
当发生GP错误时,GDI被推入缓冲区,终端用户就再也不能返回到Windows界面。为防止这种情况的发生,DirectDraw 能够在关键时刻执行一个后台过程向前台弹出一定的信息,利用这些信息可以确定应用程序是何时被中止的。这就给应用程序强加了一个限制。首先,你必须给每个窗口赋一个特殊的句柄。通过这些句柄,可以知道应用程序的运行信息。也就是说,要创建一个窗口,你必须设置一个处于活动状态的句柄。否则,无法很好执行许多功能。诸如:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -