调用IDirectDrawSurface7::GetDC方法的代码行锁定了后台缓冲区以备写入。SetBkColor和SetTextColor函数用于设置背景和文本的颜色。
接下来,phase变量决定了应该写主缓冲区消息,还是写后台缓冲区消息。如果phase等于1,就写主表面消息,并将phase设置为0。如果phase等于0,就写后台缓冲区消息,并将phase设置为1。但是,这两种情况都将消息写入后台缓冲区。
将消息写入后台缓冲区以后,就用IDirectDrawSurface7::ReleaseDC方法将后台缓冲区解锁。
7. 翻转表面
在将表面内存解锁后,就可以用IDirectDrawSurface7::Flip方法将后台缓冲区的内容翻转到主表面,如下列例子所示:
while(1)
{
HRESULT ddrval;
ddrval = lpDDSPrimary->Flip(NULL, 0);
if(ddrval == DD_OK)
{
break;
}
if(ddrval == DDERR_SURFACELOST)
{
ddrval = lpDDSPrimary->Restore();
if(ddrval != DD_OK)
{
break;
}
}
if(ddrval != DDERR_WASSTILLDRAWING)
{
break;
}
}
在上面的例子中,lpDDSPrimary参数表示主表面并与后台缓冲区相关联。在调用IDirectDrawSurface7::Flip时,对前台表面和后台表面进行了交换(只交换了表面的指针,实际上没有移动数据)。如果翻转过程成功并返回DD_OK,应用程序就从while循环中退出。如果翻转过程返回DDERR_SURFACELOST,就调用IDirectDrawSurface7::Restore方法来恢复表面。如果恢复成功,应用程序就向后循环到IDirectDrawSurface7::Flip方法,并再次调用该方法。如果恢复不成功,应用程序就从while循环中退出并返回一个错误。
注意:在调用IDirectDrawSurface7::Flip方法时,翻转操作不会立即完成。实际上会将翻转推迟到系统下一次出现垂直刷新的时候进行。例如,如果前面的翻转没有发生,则IDirectDrawSurface7::Flip方法就返回DDERR_ WASSTILLDRAWING。在上面的例子中,IDirectDrawSurface7::Flip调用继续循环直到该调用返回DD_OK。
8. 释放DirectDraw对象
按下F12键后,DDex1会在退出应用程序之前处理WM_DESTROY消息。该消息调用finiObjects例子函数,在finiObjects例子函数中包括了所有的IUnknown::Release调用,如下列例子所示:
static void finiObjects(void)
{
if(lpDD != NULL)
{
if(lpDDSPrimary != NULL)
{
lpDDSPrimary->Release();
lpDDSPrimary = NULL;
}
lpDD->Release();
lpDD = NULL;
}
} // finiObjects
首先,应用程序检查指向DirectDraw对象(lpDD)和DirectDrawSurface 对象(lpDDSPrimary)的指针是否不等于NULL。DDex1再调用 IDirectDrawSurface7::Release方法将DirectDrawSurface对象的引用计数减1。因为这样会使引用计数变为0,从而清除DirectDrawSurface对象。然后,通过将DirectDrawSurface指针的值设置为NULL来销毁该指针。接着,应用程序调用IDirectDraw7::Release将DirectDraw对象的引用计数减小为0,并释放 DirectDraw对象。最后,通过将DirectDraw指针的值设置为NULL来销毁该指针。
15.1.2 Direct3D
为了能使用Direct3D,首先需要创建一个应用程序窗口,然后创建并初始化与DirectDraw和Direct3D相关的对象。利用这些对象实现的COM接口,可以操纵这些对象和创建绘制场景所需的从属对象。Triangle例子项目通过绘制最简单的场景:一个三角形来说明这些任务。Triangle例子程序用下列步骤来建立Direct3D,绘制场景和最终关闭。Triangle例子程序位于本书配套光盘的Triangle目录下。
1. 创建窗口
执行任何Windows应用程序时必须做的第一件事是创建一个应用程序窗口来显示用户界面。除此之外,当Triangle例子程序在其WinMain函数中开始执行时,使用了下列代码来执行窗口初始化:
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
{
// 注册窗口类
WNDCLASS wndClass = { CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0, hInst,
LoadIcon(hInst, MAKEINTRESOURCE(IDI_MAIN_ICON)),
LoadCursor(NULL, IDC_ARROW),
(HBRUSH)GetStockObject(WHITE_BRUSH), NULL,
TEXT("Render Window") };
RegisterClass( &wndClass );
// 创建主窗口
HWND hWnd = CreateWindow( TEXT("Render Window"),
TEXT("D3D Tutorial: Drawing One Triangle"),
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
CW_USEDEFAULT, 300, 300, 0L, 0L, hInst, 0L );
ShowWindow( hWnd, SW_SHOWNORMAL );
UpdateWindow( hWnd );
上面的代码是标准Windows编程,列在这里主要是为了表达上的完整。例子程序定义并注册一个叫做“Render Window”的窗口类。窗口类被定义成在尺寸改变事件发生时重画窗口,将应用程序提供的图标当做资源存储,背景为白色。在注册窗口类之后,代码创建了一个使用已注册的窗口类的基本顶层窗口,其客户区宽度为300像素,高度为300像素,没有菜单和子窗口。例子程序用 WS_OVERLAPPEDWINDOW窗口风格来创建一个包括所有窗口化程序都具有的最小化、最大化和关闭框的窗口(如果例子程序运行于全屏模式下,则更好的窗口风格是WS_EX_TOPMOST)。一旦创建了窗口,代码就调用标准Win32函数来显示和更新该窗口