编程初学者:游戏编程起源(初学者)Ⅷ



☆ 设置协作等级和显示模式
我不需要说太多Windows编程设置协作级别你只需要IDirectDraw7::SetCooperativeLevel;设置显示模式你就IDirectDraw7::SetDisplayMode就这么简单!先来看看协作级别这就是原形:

HRESULT SetCooperativeLevel(
HWND hWnd,
DWORD dwFlags
);

返回类型是HRESULT你应该已经熟悉它了对于所有DirectX你都可以用SUCCEEDED和FAILED宏检测结果以下是SetCooperativeLevel()参数:
HWND hWnd:很熟悉吧!传递主窗口句柄给它使Windows知道谁将使用它资源
DWORD dwFlags:这个也很眼熟吧!每次我们看到dwFlags参数几乎都有个大标志常量列表供我们选择并且可以用“|”组合这次也不会让你失望哦!
◎ DDSCL_ALLOWMODEX:启用Mode X 显示模式(如320×200320×240或者320×400)该标志只能用于DDSCL_EXCLUSIVE和DDSCL_FULLSCREEN模式
◎ DDSCL_ALLOWREBOOT:在独占模式中启用Ctrl+Alt+Del组合键功能
◎ DDSCL_EXCLUSIVE:请求独占模式必须和DDSCL_FULLSCREEN同时使用
◎ DDSCL_FULLSCREEN:独占模式拥有者负责整个主表面GDI被忽略必须和DDSCL_EXCLUSIVE同时使用
◎ DDSCL_NORMAL:表示常规Windows应用不能和DDSCL_ALLOWMODEX、DDSCL_EXCLUSEIVE或DDSCL_FULLSCREEN标志同时使用在该模式下运行应用不能进行页交换或者更改主调色板
◎ DDSCL_NOWINDOWCHANGES:防止DirectDraw最小化或恢复应用窗口
还有几个标志常量我们暂时用不到就不说了由于我们要建立个全屏640×480×16显示模式所以我们得这样设置:

lpdd7->SetCooperativeLevel(hwnd, DDSCL_ALLOWREBOOT | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);

现在协作级别已经设置好了让我们再看看改变显示模式:

HRESULT SetDisplayMode(
DWORD dwWidth,
DWORD dwHeight,
DWORD dwBPP,
DWORD dwRefreshRate,
DWORD dwFlags
);

别忘了用宏去检测成功或失败!大多数参数同你料想差不多:
DWORD dwWidthdwHeight:以象素为单位新显示模式尺寸
DWORD dwBPP:新显示模式色彩深度就是每个象素有多少位字节可以设置为81624或32警告:很多显示卡不支持24-bits
DWORD dwRefreshRate:屏幕刷新频率但你最好设置为0使用默认刷新频率
DWORD dwFlags:对不起这次没有列表了^_^选择是DDSDM_STANDARDVGAMODE它把显示模式设置为0x13(DOS好朋友)取代了Mode X320×200×8模式如果你还想使用其它模式(你可能经常需要)没有问题把它设置为0好了
这些就是显示模式设置事先最好了解你显示卡支持显示模式它们通常都支持640×480800×6001024×768等等这些都是标准模式但是如果你非得设置成542×366模式你可能就会得到反馈科技在发展吗什么都是可能让我们继续吧!

☆ 创建表面
我们需要比点点东东创建表面不是很难实际上也是由个单独完成但是首先你要填充个描述你所要创建表面结构给你看这个结构的前我只想告诉你你不必填满所有成员^_^这就是它DDSURFACEDESC2:

typedef struct _DDSURFACEDESC2 {
DWORD dwSize;
DWORD dwFlags;
DWORD dwHeight;
DWORD dwWidth;

union
{
LONG lPitch;
DWORD dwLinearSize;
} DUMMYUNIONNAMEN(1);

DWORD dwBackBufferCount;

union
{
DWORD dwMipMapCount;
DWORD dwRefreshRate;
} DUMMYUNIONNAMEN(2);

DWORD dwAlphaBitDepth;
DWORD dwReserved;
LPVOID lpSurface;
DDCOLORKEY ddckCKDestOverlay;
DDCOLORKEY ddckCKDestBlt;
DDCOLORKEY ddckCKSrcOverlay;
DDCOLORKEY ddckCKSrcBlt;
DDPIXELFORMAT ddpfPixelFormat;
DDSCAPS2 ddsCaps;
DWORD dwTextureStage;
} DDSURFACEDESC2, FAR *LPDDSURFACEDESC2;

坦率编写DirectDraw应用其实并不难但是事情往往是这样80%工作只需要我们花费20%时间就可以完成而剩下20%工作却需要我们花费80%时间来完成DirectDraw编程比这还要严重就笔者看法至少90%工作只需要我们不到10%时间来完成而剩下不到10%工作却至少需要我们90%时间!结构DDSURFACEDESC就是10%部分它较为复杂它嵌套了其它结构让我们看看这个怪物到底做了什么我只说说重点部分:
DWORD dwSize:任何DirectX结构都有dwSize这个成员表示结构大小有了它接收到指向这些结构指针时就可以测定结构大小了
DWORD dwFlags:太好了又有大堆标志常量了^_^ !这些标志告诉接收哪些数据成员是有效要想使需要数据成员有效就必须传递相对应标志常量给dwFlags你当然可以用“|”组合它们以下是列表:
◎ DDSD_ALL:所有数据成员都有效
◎ DDSD_ALPHABITDEPTH:表示数据成员dwAlphaBitDepth有效
◎ DDSD_BACKBUFFERCOUNT:表示数据成员dwBackBufferCount有效
◎ DDSD_CAPS:表示数据成员ddsCaps有效
◎ DDSD_CKDESTBLT:表示数据成员ddckCKDestBlt有效
◎ DDSD_CKDESTOVERLAY:表示数据成员ddckCKDestOverlay有效
◎ DDSD_CKSRCBLT:表示数据成员ddckCKSrcBlt有效
◎ DDSD_CKSRCOVERLAY:表示数据成员ddckCKSrcOverlay有效
◎ DDSD_HEIGHT:表示数据成员dwHeight有效
◎ DDSD_LINEARSIZE:表示数据成员dwLinearSize有效
◎ DDSD_LPSURFACE:表示数据成员lpSurface有效
◎ DDSD_MIPMAPCOUNT:表示数据成员dwMipMapCount有效
◎ DDSD_PITCH:表示数据成员lPitch有效
◎ DDSD_PIXELFORMAT:表示数据成员ddpfPixelFormat有效
◎ DDSD_REFRESHRATE:表示数据成员dwRefreshRate有效
◎ DDSD_TEXTURESTAGE:表示数据成员dwTextureStage有效
◎ DDSD_WIDTH:表示数据成员dwWidth有效
DWORD dwheightdwWidth:表示要创建表面尺寸以象素为单位
LONG lPitch:这个需要好好解释lPitch表示从画面行行首数据到下行行首数据距离以字节为单位例如640×480×16行有640个象素每个象素需要两个字节装颜色信息所以pitch应该是1280个字节对不对?可能有些显示卡要多于1280这每行多于内存没有装置任何图形数据但是防备有些显示卡不能在线性内存模式显示图形你还是把多于地放在那吧这种情况很少发生但你最好还是考虑在内
LPVOID lpSurface:指向表面内存开始地址指针不管你使用什么显示模式你都可以用DirectDraw创建线性地址模式操作表面象素要想这样你必须锁住表面但这已经超出我们现在所学
DWORD dwBackBufferCount:后缓冲区数目以后我们会在提到它
DWORD ddckCKDestBltddckCKSrcBlt:前者为描述位转换操作目标颜色值后者是源颜色值我们将在以后文章中具体介绍
DDPIXELFORMAT ddpfPixelFormat:这个结构包含了描述显示模式象素格式标识符以后会具体介绍现在就不多说了
DDSCAPS2 ddsCaps:这是最后个重要结构它是个充满控制标志结构感谢菩萨这是个小结构结构成员中只有个很重要让我们看看:



typedef struct _DDSCAPS2{
DWORD dwCaps;
DWORD dwCaps2;
DWORD dwCaps3;
DWORD dwCaps4;
} DDSCAPS2, FAR* LPDDSCAPS2;

最重要就是dwCaps了第 3个和第 4个成员从来没有用过是为将来准备总的dwCaps可以使用如下当然可以用“|”组合以下是最为常用其它你若有兴趣自己查好了^_^
※ DDSCAPS_BACKBUFFER:指出这个表面是需要表面切换结构后缓冲区
※ DDSCAPS_COMPLEX:是个复杂表面由主表面个或多个粘贴表面组成通常是为了页面切换
※ DDSCAPS_FLIP:指出这个表面是表面切换结构部分前缓冲区紧跟着个或多个建立好后缓冲区
※ DDSCAPS_FRONTBUFFER:是有关表面切换结构前缓冲区
※ DDSCAPS_LOCALVIDMEM:指出在true、local video memory【不知如何翻译】中建立表面如果使用该标志必须也同时使用DDSCAPS_VIDEOMEMORY标志但不能同DDSCAPS_NONLOCALVIDMEM标志同时使用
※ DDSCAPS_MODEX:指出这个表面是Mode X模式(320×200或320×240)表面
※ DDSCAPS_NONLOCALVIDMEM:指出表面建立在non-local video memory【不知如何翻译】中如果定义该标志必须也同时使用DDSCAPS_VIDEOMEMORY标志但是不能同DDSCAPS_LOCALVIDMEM同时使用
※ DSCAPS_OFFSCREENPLAIN:这是个简单离屏表面
※ DDSCAPS_OWNDC:这个表面将具有长周期设备上下文
※ DDSCAPS_PRIMARYSURFACE:主表面
※ DDSCAPS_STANDARDVGAMODE:是标准VGA模式表面不能同DDSCAPS_MODEX同用
※ DDSCAPS_SYSTEMMEMORY:建立在系统内存里表面
※ DDSCAPS_VIDEOMEMORY:这个表面建立在显示内存里
天啊终于介绍完了这个结构现在我们准备建立表面吧步当然是填充DDSURFACEDESC2结构Microsoft推荐大家当你使用个结构的前你应该把它先化为0有鉴于此我经常使用这样个宏:

# INIT_DXSTRUCT(dxs) { ZeroMemory(&dxs, (dxs)); dds.dwSize = (dxs); }

它可以用于任何个DirectX结构它们都有dwSize成员所以这是很方便如果你以前从来没有看过ZeroMemory这个它只是由mem扩充来在Windows头文件中用#定义好了所以你不需要用#indlude添加任何东西就可以用它
化了结构的后你得根据实际情况设置表面了对于主表面你需要ddsCaps和dwBackBufferCount对于离屏缓冲区你也需要dwHeight和dwWidth但不需要dwBackBufferCount对于些表面你可能还需要颜色值但我们不把它弄得太复杂了填充完结构后你需要IDirectDraw7::CreateSurface原形是这样:

HRESULT CreateSurface(
LPDDSURFACEDESC2 lpDDSurfaceDesc,
LPDIRECTDRAWSURFACE7 FAR *lplpDDSurface,
IUnknown FAR *pUnkOuter
);

这些参数意义可能你也能猜出个大概了毕竟我们已经习惯了这些疯狂DirectX素材:
LPDDSURFACEDESC2 lpDDSurfaceDesc:表示要创建表面描述结构当然是个指针了
LPDIRECTDRAWSURFACE7 FAR *lplpDDSurface:为指向表面指针指针此参数在此成功后填充为什么要使用指向指针指针呢?这是我们任务就是分配片表面内存区域这样只能使用指针(表面指针)作为操作该表面内存区域标志返回值应该是该指针值而不是该指针所表示内容(具体表面)当我们使用参数传递该值时又只能使用指针(即指针指针)修改表面指针内容而不是表面指针所代表表面内存区域(理论复杂使用简单不明白不要太在意)
IUnknown FAR *pUnkOuter:看过这个模式吧无论何时pUnkOuter都是有关COM应用我们不想在这儿浪费时间设置为NULL好了
来个例子吧你会明白希望在例子里我们要个主表面和个紧随主表面后缓冲区还有个离屏缓冲区用来放置位图假设我们已经得到了IDirectDraw7接口指针代码如下:

DDSURFACEDESC2 ddsd; // surface description structure
LPDIRECTDRAWSURFACE7 lpddsPrimary = NULL; // primary surface

// up primary drawing surface
INIT_DXSTRUCT(ddsd); // initialize ddsd
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; // valid flags
ddsd.dwBackBufferCount = 1; // _disibledevent=>DDSCAPS_COMPLEX | // back buffer is chained
DDSCAPS_FLIP | // allow page flipping
DDSCAPS_VIDEOMEMORY; // create in video memory

// create primary surface
(FAILED(lpdd7->CreateSurface(&ddsd, &lpddsPrimary, NULL)))
{
// error-handling code here
}

你当然还可以用CreateSurface创建复杂表面只是使用DDSCAPS_COMPLEX标志罢了由于刚才我们创建了个后缓冲区所以我们还得必须得到指向它指针那就得IDirectDrawSurface7::GetAttachedSurface了:

HRESULT GetAttachedSurface(
LPDDSCAPS2 lpDDSCaps,
LPDIRECTDRAWSURFACE7 FAR *lplpDDAttachedSurface
);

参数很简单啦:
LPDDSCAPS2 lpDDSCaps:指向创建后缓冲区表面DDSCAPS2结构你就可以使用DDSCAPS2结构中相应成员了
LPDIRECTDRAWSURFACE7 FAR *lplpDDAttachedSurface:后缓冲区表面指针地址简单理解为声明个指针然后把指针地址传递给该参数
看看下面代码就明白了:

LPDIRECTDRAWSURFACE7 lpddsBack = NULL; // back buffer

// get the attached surface
ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
(FAILED(lpddsPrimary->GetAttachedSurface(&ddsd.ddsCaps, &lpddsBack)))
{


// error-handling code here
}

感觉有点儿入门了吗?如果你很难记住以上步骤那么你是个正常人反复运用就会熟悉了没有人能记住所有庞大结构成员和标志常量这就是我们手边总是准备员参考手册或者拥有MSDN Library CD原因了^_^ !OK最后步是建立离屏缓冲区假设它宽400高300(单位是象素)代码如下:

LPDIRECTDRAWSURFACE7 lpddsOffscreen = NULL; // offscreen buffer

// up offscreen surface
INIT_DXSTRUCT(ddsd); // initialize ddsd
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; // valid flags
ddsd.dwWidth = 400; // width
ddsd.dwHeight = 300; // height
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | // offscreen buffer
DDSCAPS_VIDEOMEMORY; // video memory

// create offscreen buffer
(FAILED(lpdd7->CreateSurface(&ddsd, &lpddsOffscreen, NULL)))
{
// error-handling code here
}

表面这些学问就介绍到这儿还有好多东西要介绍可是唯问题是文章太长了我们先暂停吧你现在可以建立个最基本但是什么也不显示表面
千万记住了你使用个DirectDraw接口和所有表面用完后定要释放(Release)它们啊!切记、切记!!!!!!!

☆ 整理总结
很抱歉在这里中断了尤其是你还没有看到显示图形但有关图形有太多内容了不是 3言两语就能说清除所以放到下两章章讨论DirectDraw中调色板和象素再下下章讨论DirectDraw中位图精彩在后面哦!请耐心期待
待续

Tags:  网络游戏的起源 网络游戏起源 游戏的起源 编程初学者

延伸阅读

最新评论

发表评论