DirectX游戏编程入门——第一部分(Windows和DirectX游戏编程引言) —— 初识DirectX

本系列文章由 net_assassin 编写,转载请注明出处。

http://blog.csdn.net/net_assassin/article/category/1100363


作者:net_assassin    邮箱: net_assassin@hotmail.com    期待着与志同道合的朋友们相互交流

 

           前面的章节讲到了Windows及相关内容,这一篇我们来唠唠DirectX,以及介绍如何编写初始化DirectX并且创建Direct3D设备的程序。


DirectX是一种图形应用程序接口(API),简单的说它是一个辅助软件,一个提高系统性能的加速软件,由微软创建开发的,微软将定义它为“硬件设备无关性”。Direct是直接的意思,X是很多东西,加在一起就是一组具有共性的东西,从内部原理探讨,也简单说来DirectX 就是一系列的 DLL (动态连接库),通过这些 DLL,开发者可以在无视于设备差异的情况下访问底层的硬件,DirectX 封装了一些 COM(Component Object Model)对象,这些 COM 对象为访问系统硬件提供了一个主要的接口。


一、历代

为游戏而生之DirectX1.0

DirectX出现是在Windows发布后,Windows3.1的声音处理一次只能播放一个音,图形处理的能力也很弱,加之整个Windows3.1的操作系统还很脆弱,这个时候它更不用不上,加上DirectX标准刚刚推出,很多硬件不支持,很多主流游戏也不支持,没有游戏、没有硬件,即使再有好的标准也是没有意义的,DirectX的魅力一直没有的到表现。但是随着Windows 95的发布,稳定的窗口操作系统,出现了划时代的变化,DirectX的命运也由此改变。

2D崛起3D雏形之Directx2.0

终于DirectX升级到了2.0,这个时候标志性的产物诞生了,2.0最大的改善是在Direct Draw,而且这个时代的经典游戏也出现了,很有代表意义的《红色警戒(RedAlert)》和《Diable(恐惧)》,红警的Windows版本和Diable都是在DirectX的标准上开发的。可惜的是,当时很多老显卡由于不能完全支持DirectX2.0,而不能玩Diable。除了2D以外,DirectX2.0的D3D部分的雏形基本完成,由于当时3D游戏较少,很多都是基于DOS开发的。世嘉公司的VR战士的PC版本就是基于DirectX2.0开发完成的,虽然效果粗糙了一些,但Direct 3D魅力还是可以感受到的。

D3D发展壮大之Directx 3.0

1997年微软发布了最后一个版本的Windows95,同年发布了DirectX 3.0,这时候DirectX的魅力被众多软硬件厂商看好,让D3D有了与OpenGL与Glide格斗的勇气。从这个版本开始,很多玩家知道了DirectX存在,也是这个时候开始出现了3D加速卡,如3DFX的Voodoo,Nvidia的Riva128,Intel的I740。这个时候3D游戏越来越多,但是当时的应用程序接口标准却有几个,主要的三个分别是专业的OpenGL接口,微软的D3D接口和3DFX的Glide接口。其中影响力最大的是3DFX的Glide,3DFX如日中天,Glide当然是大树底下好乘凉,游戏程序员使用它可以轻松容易的编出复杂、生动的3D效果,看好3DFX当然看好Glide。可是3DFX的自我封闭,不开放政策,导致它后来的破产被Nvidia收购,没有了3DFX支持Glide的影响力也从此走向衰弱,这是后话了。

D3D日益强大之Directx 5.0

微软似乎没有发布4.0版本的DirectX,DirectX3.0发布后没多久发布了DirectX5.0。尽管5.0与3.0时间间隔不长,但它的意义可不简单。DirectX5.0的D3D效果可以与当时的OpenGL平分秋色。首次引入了雾化的支持,让3D游戏更有空间真实感,更能让玩家体验到真实的三维三维游戏环境;除此以外在游戏系统的兼容性方面作了很大改善。

D3D权威出现之DirectX 6.0

在DirectX5.0发布不久第二代3D加速卡问世了,这一代3D加速卡借助DirectX6.0的技术争得不可开交。主要代表显卡是Nvidia的Riva TNT,并连的VooDoo2,VooDoo3。到了这个时代,市场格局已经很清晰,是NVidia与3DFX的斗争。DirectX 6的3D效果更多了,而且借助硬件的强大性能,可以渲染出高分辨率下的32位色的3D效果,这一点采用PCI总线技术的VOODOO系列败下阵来,它只能支持800x600下的16位色渲染,而Nvidia一开始就使用先进的AGP总线结构,高规格,新技术,每次发布新品都给用户更高性能的享受,每次成功都为他奠定显卡老大的基础。

D3D权威确立之Directx 7.0

DirectX7的发布又一次把显卡市场进行重新整合,DirectX7最大的特色就是支持T&L,中文名称是“坐标转换和光源”。3D游戏中的任何一个物体都有一个坐标,当此物体运动时,它的坐标发生变化,这指的就是坐标转换;3D游戏中除了场景+物体还需要灯光,没有灯光就没有3D物体的表现,无论是实时3D游戏还是3D影像渲染,加上灯光的3D渲染是最消耗资源的。在T&L问世之前,位置转换和灯光都需要CPU来计算,CPU速度越快,游戏表现越流畅。使用了T&L功能后,这两种效果的计算用显示卡的GPU(可以理解为显示卡的CPU)来计算,这样就可以把CPU从繁忙的劳动中解脱出来,让CPU做他该作的事情,比如逻辑运算、数据计算等等。换句话说,拥有T&L显示卡,使用DirectX7,即使没有高速的CPU,同样能能流畅的跑3D游戏。T&L成为当时人们关注的焦点。这时候第一块个支持T&L功能的显示卡是Nvidia的Geforce 256, 随后发布的Geforce 2基本上可以说是Geforce 256的一个提速版本,除了速度快了很多以外,其他没有技术上的提升,同时ATI发布的Radeon7500,一度成为支持T&L功能的效果最好的显示卡。DirectX7的发布却成了VOODOO系列显卡的噩耗,这时候3DFX也走到了尽头,被Nvidia收购,成为了显示卡中的历史,带给后人的是遗憾和叹息。

D3D的疯狂之 DirectX 8.0

2001年微软发布了DirectX8,一场显卡革命开始,它首次引入了“像素渲染”概念,同时具备像素渲染引擎(Vertex Shader)与顶点渲染引擎(Pixel Shader),反映在特效上就是动态光影效果。它发布没多久,Madonion(就是今天的Futuremark)发布了基于DirectX8的3Dmark2001显卡测试软件,它支持DirectX8的全部特效。可是当时华丽的场景,只有极少数显卡才能体验到,绝大部分显卡都不能完成此软件的全部测试,其中的4个场景跑不出来。原因是,DirectX8集成了两大特技 D DVS (Vertex Shader)和PS(Pixel Shader)。通过vs和ps的渲染,可以很容易的宁造出真实的水面动态波纹光影效果。主要代表显卡是NVIDIA的Geforce 3,后期ATI的Radeon8500。DirectX8的发布成了真正的第4代3D加速卡时代来临的标志。

让人耳目一新之Directx 9.0

2002年底,微软发布DirectX9.0,如果从参数上看,DirectX9相比DirectX8仅是提高了PS和VS的版本,目前版本都是2.0版本,似乎没有质的变化,其实不然,下面分别对Pixel Shader和Vertex Shader比较。 
  首先,PS 2.0具备完全可编程的架构,能对纹理效果即时演算、动态纹理贴图,还不占用显存,理论上对材质贴图的分辨率的精度提高无限多;另外PS1.4只能支持28个硬件指令,同时操作6个材质,而PS2.0却可以支持160个硬件指令,同时操作16个材质数量,新的高精度浮点数据规格可以使用多重纹理贴图,可操作的指令数可以任意长,电影级别的显示效果轻而易举的实现。 
  其次,VS 2.0通过增加Vertex程序的灵活性,显著的提高了老版本(DirectX8)的VS性能,新的控制指令,可以用通用的程序代替以前专用的单独着色程序,效率提高许多倍;增加循环操作指令,减少工作时间,提高处理效率;扩展着色指令个数,从128个提升到256个。 
  另外,增加对浮点数据的处理功能,以前只能对整数进行处理,这样提高渲染精度,使最终处理的色彩格式达到电影级别。突破了以前限制PC图形图象质量在数学上的精度障碍,它的每条渲染流水线都升级为128位浮点颜色,让游戏程序设计师们更容易更轻松的创造出更漂亮的效果,让程序员编程更容易。

微软一统3D规格的王牌:DirectX10
DirectX10将完全放弃GPU当中的固定渲染模式,并且支持GPU行为的完全自由化,即GPU不在明确划分像素着色和顶点着色单元,并且支持多种任务,如2D/3D/视频加速等等任务的自由分配。DirectX10将加入Shader4.0技术,并首度实现RayTracing光线追踪,将位移贴图Displacement作为标准之一。


二、家族成员

微软开发了DirectX标准平台,并且根据硬件制造厂商和游戏厂商合作共同更新升级DirectX的标准。硬件制造商按照此标准研发制造更好的产品,游戏开发者根据这套标准开发游戏。也就是说,无论硬件是否支持某种特效,只要DirectX标准中有,游戏开发者就可以把它写到游戏中,当这个游戏在硬件上运行,如果此硬件根据DirectX标准把这个效果做到了此硬件驱动程序中,驱动程序驾驭其硬件算出结果,用户就可以欣赏到此效果。这就是“硬件设备无关性”,是DirectX真正意义所在。 
    通常,Windows对硬件访问的管制非常严格,用通常的办法不易访问,但DirectX通过“硬件抽象层(HAL)”给予了开发人员直接访问硬件的能力,HAL不仅解决了硬件及兼容性问题,而且开发人员可以利用它直接访问计算机的某些硬件设备,例如显示设备的直接显存控制和渲染,键盘、鼠标和游戏杆的控制的直接访问控制,音频设备的直接音频混合与输出能力等等,因此开发人员可以充分利用硬件加速将程序的性能优化到一个新的高度,如果目标机器不支持相应的硬件加速,DirectX还可以仿真加速器以提供强大的多媒体环境。DirectX家族包含的成员有Direct3D、DirectDraw、DirectInput、DirectMusic、DirectPlay、DirectSound和DirectShow。

1、Direct3D、DirectDraw和DirectGraphics

    DirectDraw是DirectX家族中的元老,它为高速的2D渲染提供了良好的支持,由于其具备直接显存访问和位快传送的能力,使得2D图形的绘制速度相对GDI有了一个质的飞跃,其渲染速度甚至有上百倍的差距。在现在回忆当初玩“红色警戒”和“Diablo”的时候,大家可不要忘了DirectDraw的功劳。
    DirectDraw在DirectX3.0时就已经接近极致,但是随着PC图形技术的飞速发展,人们逐渐不再满足于2D的图形效果,而通过2D技术实现伪3D模拟又非常损失效率,这种需求直接导致了Direct3D的诞生,早期的Direct3D技术不甚完善,相对于2D技术还有一定的差距,直到图形加速卡支持硬件3D特效后,Direct3D才逐渐步入正轨,慢慢显示出它的性能优势来。下面让我们来回顾一下历史,看看Direct3D的“成长过程”:

DirectX6中的Direct3D添加了如下新特性:

• 几何形体的灵活顶点格式定义
• 几何形体的顶点缓冲存储
• 支持多纹理渲染
• 自动纹理管理
• 可选深度缓冲(使用Z Buffer或W Buffer)
• 通过凹凸环境贴图(BUMPENVMAP)为反光面和水波特效提供逐像素的渲染和贴图能力DirectX7中的Direct3D添加了以下新特性:
• 硬件坐标转换和灯光(T&L)支持
• 立方体表面的环境贴图
• 几何渲染
• 改进的纹理渲染
• 自动纹理坐标生成、纹理转换、投影纹理和任意面裁剪
• D3DX实用库
• 支持Intel MMX架构、Intel单指令多数据流(SIMD)、SSE®和 AMD® 3DNow®架构。

    版本到了8.0的时候,虽然它依然保持着向前的兼容性,但是它的结构发生了巨大的变化,3D图形处理技术逐渐统一在Vertex Shader和Pixel Shader。Vertex Shader被用来描述和修饰3D物体的几何形状,同时也用来控制光亮和阴影;Pixel Shader则用来操纵物体表面的色彩和外观。Direct3D和DirectDraw合二为一,DirectX家族诞生了一个新的成员-----DirectGraphics。同时也增添了很多令人激动的特性:

• 完全集成DirectDraw与Direct3D 
    简化程序初始化过程并提高数据分配和管理的性能,这将减少内存消耗。同时,集成后的图形应用编程接口(API)允许并行的顶点输入流以达到更加灵活的渲染。 
• 可编程顶点处理语言 
    允许你编写定制的着色器,如变形和渐变动画,矩阵调色板蒙皮,用户定义的光照模型,一般环境映射,可编程几何体或者任何其他开发者定义的算法。 
• 可编程像素处理语言 
    允许你编写定制的硬件着色器,例如通用纹理组合公式,逐像素光照(凹凸贴图),适用于实现照片(真实)级镜面效果的逐像素环境贴图或者任何其他开发者定义的算法。 
• 支持多重采样渲染 
    允许全场景反走样和多重采样效果,例如运动模糊及景深(镜头的聚焦效果)。 
• 点精灵 
    允许高性能的粒子系统渲染,例如火花、爆炸、雨、雪等等。 
• 3-D空间纹理 
    允许范围衰减,实现逐像素级光照及空间大气效果,甚至是更复杂的几何图形应用。 
• 支持高维图元 
    对来自主要的3-D创作工具的3-D内容,增强其外观并简化内容映射。 
• 高级技术 
    包含了用于输出Direct3D蒙皮网格的三维内容创建工具插件,使用了Direct3D多种不同技术,多分辨率层次细节(LOD)几何,还有高维表面数据。 
• 索引顶点混合 
    扩展了几何混合的支持,允许通过指定使用一个矩阵索引把矩阵应用于顶点混合处理。 
• 扩充了Direct3DX实用库 
    包含了大量的新函数。Direct3DX实用库是一个位于Direct3D之上的辅助层,用于简化3-D图形开发者的常规工作。它包括了一个蒙皮库,支持对网格的操作,还有组装顶点与像素着色器的功能。 

    DirectX每一次升级都会有重大的内核结构改变,它会给我们带来巨大的视觉冲击。DirectX7核心的T&L引擎到DirectX9干脆被抛弃了。因此对于图形芯片开发商、游戏开发商以及广大用户而言,DirectX 9的确是一项“绝无仅有的优越图形技术”。DirectX 9“具有多项令人兴奋的全新功能特征”:

Direct3D图形渲染管道

• Vertex Shader 2.0和Pixel Shader 2.0
    在DirectX9中,Vertex Shader和Pixel Shader的版本升级到了2.0,它们都支持64或甚至128位浮点色彩精度。浮点色彩在动态和精度上的增加给图像质量带来质的飞跃,这样在DirectX9中你可以轻易实现电影级别般逼真的效果!
DirectX8和DirectX9的对比参数:


    Vertex Shader 2.0引入了流程控制,增加了条件跳转、循环和子程序。Vertex程序现在最多可以由1024条指令组成(之前只能用128条指令),增加的指令带来更加复杂和强大的表现,新的操作如正弦、余弦及其他强大的函数运算大大简化了代码的编写,并且能够表现更加复杂的效果。
 Vertex Shader 1.0
 VertexShader 2.0

强大的可编程Pixel Shader是实现具有电影质量级别效果的真正精华所在。Pixel Shader 2.0可以支持高级程序语言和汇编语言,开发人员还可以将其汇编代码嵌入较高级的程序语言中。前一版的Pixel Shader语言被限制为只能使用最多6个材质和28条指令,而2.0版则将这一上限提升至最大16材质和160条指令,也新增了很多强化的运算和操作。
 Pixel Shader 1.4
 Pixel Shader 2.0

此外各种Shader工具的大力协助,如nVidia的Cg语言和ATI的RenderMonkey,使得实时图形渲染的质量飞速提高,nVidia和ATI官方的Demo就足以说明这一点。DirectX9中也改进了部分接口定义,Vertex Shader和Pixel Shader分别单独提供了一个接口,而且提供了常见图形的绘制接口,如线段的绘制等,这进一步减轻了开发人员的负担。

• 浮点型色彩和32位帧缓冲格式
    目前大多数色彩表示法(如RGB)用8位整数表示红、绿、蓝色,也许对于显示来说这已经足够了,但在运算中似乎还远不够。由于整数没有小数部分,因此当它们经过Pixel Shader极其复杂的数学运算后,就会产生较大的误差,这可能导致色彩明显失真。而DirectX9支持数种浮点色彩格式,使得其精度有了很大提高。同时DirectX9支持精确到每像素32位的帧缓冲格式,能够表现出4倍于目前亮度等级的数量,这使得图像看上去更加清晰和自然。
    除此以外,DirectX9还提供位移贴图(displacement maps)以及改进的设备模拟等特性的支持,并且毫无意外地,DirectX9 SDK中也进一步扩展了Direct3DX实用库,提高了开发效率。

2、DirectSound、DirectMusic和DirectX Audio

    在DirectX中DirectSound和DirectMusic可以统称DirectX Audio。一个好的游戏是不能没有声音的,DirectX Audio负责了游戏中的音效控制。不仅仅是游戏,很多需要高质量音效的地方都有它们的影子,我们经常在一些播放软件的设置面板中看见是否使用DirectSound支持的选项。
    DirectX Audio做的不仅仅只是简单地对声音的回放。它提供了一个完整的系统,能够利用硬件加速的功能动态地操纵控制音轨和声道(soundtrack)。
    
如果你想在你的程序中使用DirectMusic和DirectSound,你就能够获得以下功能:
• 读入且播放例如MIDI, WAVE, 以及DirectMusic Producer run time等格式的声音文件。
• 同时对多个声音资源进行混音播放。
• 对播放的声轨进行高精度时间控制。
• 可以动态地变更播放节拍与节奏,甚至实时地动态控制一些MIDI事件。
• 使用DLS合成器(DirectX Audio自带的波表合成器),你的程序就可以确保在不同的计算机上听到相同的MIDI声音。你的程序能够播放不受类别限制,各试各样乐器的声音,使用DirectX Audio,你甚至还能够创造出独一无二的乐器声音类别并将它发布。
• 把声音做3D定位,创造出3D的环境声响。
• 可以非常容易地实现例如变调、回响,以及别的声音特效。
• 能使用数量超过16个的MIDI音轨。DirectX Audio突破了从前只能使用16个MIDI音轨的限制,它把同时回放大数量的音轨变成为了可能,而这个数量仅仅只是受到了你的声音硬件合成器能力的限制。
• 播放位于不同的Audiopaths上的声音段(segments),效果就可以各自实现在每一段声音里。
• 实现在不同的端口(port)之间捕捉MIDI数据及流("thru")。
• 从话筒或者别的输入设备中捕捉声音数据。

如果使用DirectMusic Producer或类似程序中的源文件,你还能够做到
• 在声音的回放期间能够做更多的控制,例如动态选择不同的音效变化器(variations)或切换不同的和旋级数。
• 精确地定时重放音乐。
• 利用变化器(variations)播放声音(wave)
• Audiopaths利用Map performance channels可以使相同的声音段在channel的不同部分产生完全不同的播放效果。
• 动态地创造出全新的音乐片段,这不需要专门算法库,仅仅需要你的作曲能力而已。
• 动态地将存在的音乐片段进行组合过渡。
• 在声音回放时端,程序可以获得存在于特殊节拍点的各类声音特效的信息。

这些功能适用于常常只使用主音频流(mainstream)的程序。如果程序只要实现一些基本简单的功能,开发者将DirectX Audio设计得非常易用,很适合初学者。DirectX Audio也是可扩展的。好的程序可以利用虚函数(virtual)继承设计出新的类,例如:
• 支持新的声音格式文件。
• 音轨可以包含各类数据。
• 处理信息的工具 - 比方说,可以截取记录实现变换,或者将要显示的歌词置入声音片段文件。
• 自定义的音序器(sequencer)。
• 自定义的合成器(synthesizer)。
• 效果过滤器。(Effects filters)。

值得一提的是,在DirectX9中加入了DirectMP3和DirectCD两个功能模块,它们使得主流的音频播放也能够通过DirectX与其调用程序更好地结合在一起。

3、DirectInput

    在DirectX这个大家族中,DirectInput掌管着“行为控制权”。与Winodows事件响应相比,DirectInput可以直接访问硬件,直接从输入缓冲区内检索数据,从而获得比响应Windows消息更快的速度。此外DirectInput也对力反馈游戏杆(Force Feedback)提供了良好支持。

4、DirectPlay

    网络底层程序的开发向来是令开发者头痛的一件事,而DirectPlay似乎兼顾了速度与易用性两个方面,在网络游戏这样一类对速度和效率要求较高的软件来说,针对游戏优化设计的DirectPlay显然是一个比较好的选择。DirectPlay提供了一个额外的层,使你的游戏和网络底层相隔。并且,你的游戏可以非常简单地使用DirectPlay API,并使用DirectPlay管理网络通讯。DirectPlay提供的特性,使多人游戏在开发中得到了很多简化。其中包括:
• 创建和管理点对点、客户/服务会话(Session)
• 在一个会话中管理用户(User)和组(Group)
• 管理在不同网络平台上进行会话的成员之间发送的消息
• 使游戏在大厅(Lobby)中互动
• 使用户可以进行语音交互

5、DirectShow

    作为DirectX中的又一重要成员,DirectShow提供了Windows平台下高质量的媒体捕获和回放能力,支持很多格式:ASF、MPG、AVI、MP3和WAV。DirectShow支持使用WDM设备或老式视频设备进行视频捕获。当有硬件支持的环境下,它会在使用视频或音频时自动选择是否使用硬件加速。
    DirectShow简化了媒体回放、格式转换和捕获任务。同时,当应用程序需要自定义底层流媒体解决方案时,它也提供直接流访问控制的功能。
    你可以用DirectShow编写DVD播放器、视频编缉程序、AVI到 ASF转换器、MP3播放器和数字视频捕获程序等等。


让Direct3D转起来:

#include <windows.h>
#include <d3d9.h>
#include <time.h>
#include <iostream>
using namespace std;

#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")

//program settings
const string APPTITLE = "Direct3D_Windowed";
const int SCREENW = 1024;
const int SCREENH = 768;

//Direct3D objects
LPDIRECT3D9 d3d = NULL; 
LPDIRECT3DDEVICE9 d3ddev = NULL; 

bool gameover = false;

//macro to detect key presses
#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)


/**
 ** Game initialization function
 **/
bool Game_Init(HWND window)
{
    MessageBox(window, "Game_Init", "BREAKPOINT", 0);

    //initialize Direct3D
    d3d = Direct3DCreate9(D3D_SDK_VERSION);
    if (d3d == NULL)
    {
        MessageBox(window, "Error initializing Direct3D", "Error", MB_OK);
        return 0;
    }

    //set Direct3D presentation parameters
    D3DPRESENT_PARAMETERS d3dpp; 
    ZeroMemory(&d3dpp, sizeof(d3dpp));
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
    d3dpp.BackBufferCount = 1;
    d3dpp.BackBufferWidth = SCREENW;
    d3dpp.BackBufferHeight = SCREENH;
    d3dpp.hDeviceWindow = window;

    //create Direct3D device
    d3d->CreateDevice(
        D3DADAPTER_DEFAULT, 
        D3DDEVTYPE_HAL, 
        window,
        D3DCREATE_SOFTWARE_VERTEXPROCESSING,
        &d3dpp, 
        &d3ddev);

    if (d3ddev == NULL)
    {
        MessageBox(window, "Error creating Direct3D device", "Error", MB_OK);
        return 0;
    }

    return true;
}

/**
 ** Game update function
 **/
void Game_Run(HWND hwnd)
{
    //make sure the Direct3D device is valid
    if (!d3ddev) return;

    //clear the backbuffer to bright green
    d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,255,0), 1.0f, 0);
    
    //start rendering
    if (d3ddev->BeginScene())
    {
        //do something?
    
        //stop rendering
        d3ddev->EndScene();

        //copy back buffer on the screen
        d3ddev->Present(NULL, NULL, NULL, NULL);
    }

    //check for escape key (to exit program)
    if (KEY_DOWN(VK_ESCAPE))
        PostMessage(hwnd, WM_DESTROY, 0, 0);
}

/**
 ** Game shutdown function
 **/
void Game_End(HWND hwnd)
{
    //display close message
    MessageBox(hwnd, "Program is about to end", "Game_End", MB_OK);

    //free memory
    if (d3ddev) d3ddev->Release();
    if (d3d) d3d->Release();
}


/**
 ** Windows event handling function
 **/
LRESULT WINAPI WinProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    switch( msg )
    {
        case WM_DESTROY:
            gameover = true;
            PostQuitMessage(0);
            return 0;
    }
    return DefWindowProc( hWnd, msg, wParam, lParam );
}

/**
 ** Main Windows entry function
 **/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    //set the new window's properties
    //previously found in the MyRegisterClass function
    WNDCLASSEX wc;
    wc.cbSize = sizeof(WNDCLASSEX); 
    wc.style         = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc   = (WNDPROC)WinProc;
    wc.cbClsExtra     = 0;
    wc.cbWndExtra     = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = NULL;
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = APPTITLE.c_str();
    wc.hIconSm       = NULL;
    RegisterClassEx(&wc);

    //create a new window
    //previously found in the InitInstance function
    HWND window = CreateWindow( APPTITLE.c_str(), APPTITLE.c_str(),
       WS_OVERLAPPEDWINDOW,
       CW_USEDEFAULT, CW_USEDEFAULT,
       SCREENW, SCREENH,
       NULL, NULL, hInstance, NULL);

    //was there an error creating the window?
    if (window == 0) return 0;

    //display the window
    ShowWindow(window, nCmdShow);
    UpdateWindow(window);
    
    //initialize the game
    if (!Game_Init(window)) return 0;


    // main message loop
    MSG message;
    while (!gameover)
    {
        if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) 
        {
            TranslateMessage(&message);
            DispatchMessage(&message);
        }

        Game_Run(window);
    }

    Game_End(window);

    return message.wParam;
}



没有更多推荐了,返回首页