设定Direct X应用程序中的Direct 3D

更新时间:2023-09-24 11:18:01 阅读量: IT计算机 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

4. 设定Direct X应用程序中的Direct 3D

现在进入有趣的部分!从现在起,我们将开始建立我们程序中的Microsoft Direct3D立即模式。在本章中,我们会先检查在立即模式中有哪些可用的对象和接口。然后我们会带您走过要建立一个立即模式程序框架的相关步骤。在读过 第三章 后,您应该对DirectDraw定义程序代码已经适应了。要记住,Direct3D是一个指向DirectDraw对象的COM接口。因此Microsoft把硬件抽像层(HAL)叫作DirectDraw/Direct3D HAL。此外,Direct3D利用DirectDraw绘图页作为前后缓冲区来显示3D场景和计算3D场景时的z缓冲区。另外,Direct3D贴图是由DirectDraw绘图页所构成的,并且可以引用DirectDraw型态。

Direct3D立即模式对象和接口

Direct3D立即模式是由一些COM对象和连到这些对象的接口所构成的,您可以用这种模式来建构和控制您程序中的3D世界。在本段落中,我们会看到这些对象和他们的接口(以及一些DirectDraw对象和接口)。

DirectDraw物件

和在 第三章 中您看到的一样,您可以用DirectDrawCreateEx函式来建立DirectDraw对象。DirectDrawCreateEx函式开启了DirectX 7最新的DirectDraw和Direct3D接口。您在任何Direct3D应用程序中所建立的第一个对象一定是DirectDraw对象,因为它负责并提供显示装置的存取功能,如此才能实作许多Direct3D的功能。IDirectDraw7是DirectX 7中连到DirectDraw对象的最新版接口,而且它和之前版本有很大的不同。我们也会在本书中使用到它。

DirectDrawSurface物件

在一个Direct3D程序中,可以用DirectDrawSurface ( IDirectDrawSurface7接口)对象来建立前缓冲区、后缓冲区、贴图对映和深度缓冲区。绘图页则表示某块可能存在在您的视讯卡上或您的计算机标准系统内存中的内存。

如果您用DDSCAPS_3DDEVICE特性位建立了一个DirectDrawSurface对象,您可以用IDirect3D7::CreateDevice,并配合绘图页来建立一个Direct3D装置对象,这个对象会用此绘图页作为它的绘制目标,这也是在建立后缓冲区时的一般作法。您也可以利用

IDirectDraw7::CreateSurface方法和DDSCAPS_TEXTURE旗标来建立一个拥有贴图功能的DirectDrawSurface对象。这个对象可以填入您想用在场景中的对象贴图所用到的位图。

Direct3DDevice物件

所谓Direct3Device对象是Direct3D的成像组件。它可以概括和储存立即模式应用程序的「成像状态」和一个可以运用该状态来计算基本形状的方法。所谓成像状态(rendering state)定义了绘制上用到的参数,包括了贴图、上色、色彩和烟雾。DirectX 7中包含了IDirect3DDevice7的接口所提供的装置对象模型。

您可以用IDirect3D7::CreateDevice方法来建立Direct3D装置对象。这个呼叫动作也同时让您取得一个IDirect3DDevice7接口。而这个接口并不会对材质、光源和检视埠使用不同的COM对象,这是和早期版本的DirectX不同之处。在DirectX 7中,这个新的接口包含了可提供这些新特性作为Direct3D装置内部数据结构的一些方法。 在目标系统上可以建立以下几种Direct3D装置: ? HAL装置。

? TnLHAL装置。

? RGB装置。

? 参照扫描成像装置(reference rasterizer device)。

还有其它二种装置在DirectX的之前版本有提供-MMX装置和连冲装置(ramp device),但在DirectX 7中不存在。

HAL装置是一个支持Direct3D的3D绘图器,提供了硬件的扫描成像,但不提供转换和打光功能,(转换、打光和扫描成像会在后面两章有详细说明)。如果列举时有找到HAL装置,应该在您的程序中运用。但是如果您在开发程序时采纳了硬件转换和打光的优点时,TnLHAL会是更好的选择。

TnLHAL(Transform'n'Lighting HAL)装置用硬盘来处理所有转换和打光以及扫描成像模块,而且显然也是最快速的装置类型。它和HAL的差异是在它执行硬件加速的转换和打光动作。因此,它可以减轻CPU的负载,明显加快应用程序的速度。您可以检查

D3DEVCAPS_HWTRANSFORMANDLIGHT装置特性来辨认某个装置有无提供硬件加速的转换和打光。

RGB装置主要是用在不含任何硬件3D加速功能的系统上。RGB装置可用软件仿真3D指令。这意谓着它会比用HAL装置执行速度慢得多,但是它可以利用系统CPU提供的特殊指令。这种扫描成像器会用到支持MMX指令集(某些Intel处理器适用),或者是AMD 3DNow! (某些AMD处理器适用)来加速绘制。MMX指令集是用来加速扫描成像而3DNow!指令集则可加速转换和打光动作。但实时有了这些特殊指令集,RGB装置还是比HAL和TnLHAL慢。

最后一种是参照扫描成像装置,这种绘制器支持所有的Direct3D功能,但是实作上是针对正确性作最佳化而非针对速度。因此,参照扫描成像器相当地慢,您应该只用它来测试您的卡无法支持的Direct3D功能上。

Direct3D的默认值并不会列举扫描成像器。要列举它时,您首先必须使用RegEdit,将HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft \\Direct3D\\Drivers下的记录值EnumReference值设为一个非零的DWORD值。

Direct3DVertexBuffer物件

这种对象是一个内存缓冲区,里面包含要用IDirect3DDevice7接口提供的顶点缓冲区绘制方法计算的顶点。使用IDirect3D7::CreateVertexBuffer方法可以建立顶点缓冲区以及相关的存取接口。下一章会详细说明顶点和顶点缓冲区。

建立一个立即模式应用程序

要让您的程序用到Direct3D时,会包含以下的步骤,其中有一些在第三章就提过了。我会针对前五个步骤深入探讨一些额外的内容,并且描述建立Direct3D装置和深度缓冲区的最终过程。

1. 初始化应用程序。

2. 辨认可用的DirectX版本(如果省略这个动作,本书的程序代码中假设DirectX 7可

用)。

3. 列举存在可用的Direct3D装置。 4. 选择Direct3D装置。

5. 利用DirectDrawCreateEx取得一个IDirectDraw7接口。

6. 利用IDirectDraw7接口的QueryInterface方法来取得IDirect3D7接口,再建立一个

Direct3D装置。

7. 列举深度缓冲区格式,建立一个深度缓冲区用来绘制您的3D世界。

在本章中,您可以看到如何做到以上步骤和建立一个有效的Direct3D装置所需要的相关程序,让您可以绘制您的3D世界。

我们先修改 第三章 提到的CD3DFramework7::CreateEnvironment程序来建立Direct3D、Direct3DDevice和深度缓冲区对象。以下是这个程序修改过的版本:

//-------------------------------------------------------------------

//名称:CreateEnvironment //说明:建立程序框架的内部对象

//-------------------------------------------------------------------

HRESULT CD3DFramework7::CreateEnvironment(GUID*pDriverGUID, GUID*pDeviceGUID, DDSURFACEDESC2*pMode, DWORD dwFlags) {

HRESULT hr;

//依据装置为硬件装置或

//软件装置而定,选择预设的内存型态。

if(IsEqualIID(*pDeviceGUID,IID_IDirect3DHALDevice)) else

m_dwDeviceMemType =DDSCAPS_SYSTEMMEMORY;

//建立DirectDraw对象

hr =CreateDirectDraw(pDriverGUID,dwFlags); if(FAILED(hr))

return hr;

//建立前后缓冲区,并加上裁切。 if(dwFlags &D3DFW_FULLSCREEN)

hr =CreateFullscreenBuffers(pMode,dwFlags); m_dwDeviceMemType =DDSCAPS_VIDEOMEMORY; m_dwDeviceMemType =DDSCAPS_VIDEOMEMORY;

else if(IsEqualIID(*pDeviceGUID,IID_IDirect3DTnLHalDevice))

}

else

hr =CreateWindowedBuffers(pMode,dwFlags); return hr;

if(FAILED(hr))

//建立Direct3D对象和Direct3DDevice对象 hr =CreateDirect3D(pDeviceGUID,dwFlags); if(FAILED(hr))

return hr;

//建立并附加上z-缓冲区 if(dwFlags &D3DFW_ZBUFFER)

hr =CreateZBuffer(pDeviceGUID,dwFlags); if(FAILED(hr))

return hr;

return S_OK;

我们会在本章稍后对这个程序增加其它的呼叫内容。

依照您所建立的不同装置类型(HAL、RGB等),您应该让软件选择您的主绘图页、贴图和顶点缓冲区所需要的内存型态,让您的程序发挥最好的效率。除了标准的视讯内存外,DirectDraw支持加速图型端口(Accelerated Graphics Port, AGP)架构,允许在非本机视讯内存中建立绘图页。AGP架构的作法有二种:执行模型( execute model )和DMA模型。在执行模型下,显示装置同时支持非本机(AGP)和本机(标准)视讯内存绘图页的同样功能。在DMA模型下,如果没有可用的本机视讯内存时,(除非您要求使用本机视讯内存),DirectDraw会针对您建立的任何贴图绘图页使用非本机视讯内存。对其他的绘图页型态而言,绘图页只会建立在本机视讯内存中,除非您的程序需要使用非本机视讯内存。

要辨别某种装置驱动程序是否支持非本机视讯内存绘图页的贴图,您可以看看D3DDEVCAPS_TEXTURENONLOCALVIDMEM旗标值是否有被设定。您可以利用IDirect3DDevice7::GetCaps方法取得3D装置特性清单,再从清单中取得该旗标值。

步骤1:初始化应用程序

要在程序中建立Direct3D内容的第一个步骤是初始化所有相关的变量。这个步骤的主要目的是要清除所有的对象和结构,让您可以在您的3D世界中建立必要的对象和在结构中填入

需要的设定值,例如上色参数和裁切。以下的CD3DFramework7建构元会初始化所有的成员变量,并定义某些项目(如z轴、后缓冲区和装置)。

//-------------------------------------------------------------------

//名称:CD3DFramework7

//说明:用来清除静态变量的建构元

//-------------------------------------------------------------------

CD3DFramework7::CD3DFramework7() { }

m_hWnd m_bIsStereo

=NULL; =FALSE; =FALSE; =0L; =0L; =NULL; =NULL;

m_bIsFullscreen m_dwRenderWidth m_dwRenderHeight m_pddsFrontBuffer m_pddsBackBuffer m_pddsZBuffer m_pd3dDevice m_pDD m_pD3D

m_pddsBackBufferLeft =NULL;

=NULL;

=NULL; =NULL; =NULL; =NULL;

m_dwDeviceMemType

步骤2: 决定DirectX版本

辨别系统上已安装的DirectX版本的整个过程称为版本检查。您需要做到的版本检查程度依照您使用Direct3D的方式而有不同。如果您有兴趣开发自己的系统,那么您大概已经安装了最新且最完整的DirectX,因此不需再作检查。如果您正在撰写一个全新的DirectX 7应用程序,您应该会在产品中附上最新的DirectX执行时期函式库,您的安装程序也会顺便安装(如果系统环境是Windows 95或Windows 98)。如果环境是Microsoft Windows NT4或更早版本,您可以控制程序不要安装或执行。Windows 2000出厂时已附有完整的DirectX支持,所以如果系统环境是Windows 2000时,您的软件可以使用最新的DirectX

特性。大多数公司出厂的3D游戏和其它软件会希望您已安装最新版DirectX-否则会在游戏安装过程中,再从同一片游戏光盘安装DirectX。

然而,如果您打算支持之前版本的DirectX(为了某种理由),您必须作更精准的版本检查。您可能想避免在连结ddraw.lib而不是用LoadLibrary和GetProcAddress时,看到突然出现的标准错误讯息。如果您不想让使用者收到标准的系统错误讯息,请使用

QueryInterface作为需求接口,以一个错误讯息表示失败,并且结束程序。您的最佳作法是建立一个Windows 95或Windows 98的安装程序,能够在安装过程中自动更新系统为最新版的DirectX。然而,请记住,在Windows NT和Windows 2000中,只有系统管理者有权更新操作系统的重要部分(如DirectX),因此您的安装程序无法更新DirectX版本。 如果您希望使用版本检查的作法,好让您的软件能在多个平台上执行,您可以检查不同的DirectX接口的可用性。试着检查从DirectX 2支持的接口到只有DirectX 7才支持的接口,您可以找出目前可用的DirectX版本。一旦找出确实可用的DirectX版本,您可以让程序完全享受到系统平台支持的所有功能的优点。如果系统平台的DirectX版本不及您需求的来得新,您可以让软件本身适当的减少支持效果。比方说,如果您想要DirectX 7,但只有DirectX 3可用,您0可以停用多贴图,因为在DirectX 3中并不支持。依此作法可以让您的应用程序正常执行,只会牺牲一点视觉效果。然而上面也提过,您最好还是在系统平台上安装最新版的DirectX,这样您的软件才能发挥它的实力。

步骤3: 列举现存可用的Direct3D装置

要建立一个稍后可用来绘制的装置,首先您要列举出Direct3D装置。 第三章 提到,这样做意谓着先列举出DirectDraw装置,再列举出附属在每个DirectDraw装置上的所有Direct3D装置。您可以用第三章描述的 D3DEnum_EnumerateDevices 程序来做到这件事。

步骤4: 选择Direct3D装置

要让您的程序能使用Direct3D的下一步骤包含了挑选最适用于程序需求的Direct3D装置,并且去建立该装置。处理这个选择动作和建立装置的原始程序的同时也要能判别是在全屏幕或窗口模式下执行。在第三章的 DeviceEnumCallback 程序中说明了整个动作。

步骤5: 取得一个IDirectDraw7界面

在初始化您的变量及判别DirectX版本后,下一步就是要建立一个DirectDraw对象。 第三章 已详述了如何用CD3DFramework7::CreateDirectDraw成员函式来取得新的IDirectDraw7界面。

步骤6:从IDirectDraw7接口取得IDirect3D7接口并建立一个Direct3D装置

要建立一个Direct3D对象,您要用DirectDraw对象的QueryInterface方法来判定它是否支持DirectX 7所提供的IID_IDirect3D7接口,如果DirectDraw对象支持该接口,QueryInterface会取得一个指到该接口的指针并且呼叫AddRef来累加此参照。 以下的d3dframe.cpp程序说明了如何建立Direct3D对象和Direct3DDevice对象。(我们会在 第五章 中讨论这个程序的最后一段:建立一个检视埠)

//-------------------------------------------------------------------

//名称:CreateDirect3D //说明:建立Direct3D接口

//-------------------------------------------------------------------

HRESULT CD3DFramework7::CreateDirect3D(GUID*pDeviceGUID) {

//建立装置。

if(FAILED(m_pD3D->CreateDevice(*pDeviceGUID,m_pddsBackBuffer, &m_pd3dDevice))) { }

DEBUG_MSG(_T(\return D3DFWERR_NO3DDEVICE;

//查询DirectDraw以存取Direct3D。

if(FAILED(m_pDD->QueryInterface(IID_IDirect3D7, (VOID**)&m_pD3D))) { }

DEBUG_MSG(_T(\return D3DFWERR_NODIRECT3D;

}

//设定新建立的装置的检视端口。

D3DVIEWPORT7 vp ={0,0,m_dwRenderWidth,m_dwRenderHeight, 0.0f,1.0f};

if(FAILED(m_pd3dDevice->SetViewport(&vp))) { }

return S_OK;

DEBUG_MSG(

_T(\

return D3DFWERR_NOVIEWPORT;

device\

一旦这个程序成功地回传,您就拥有了一个有效的Direct3D物件和一个有效的Direct3D装置对象,可以用在应用程序中。

建立Direct3D装置

在本章的前面,您曾经看过可用的Direct3D装置类型。在DirectX 7中,只要呼叫IDirect3D7::CreateDevice方法即可取得IDirect3DDevice7接口,其中即包含了支持材质、光源和视埠的方法,而不是像之前版本的DirectX需要取得不同的Direct3DLight、Direct3DMaterial和Direct3DViewport物件。

我们曾讨论过,您建立的装置必须对应系统平台上的可用功能。Direct3D利用计算机的3D硬件或软件仿真3D特性的方式提供了绘制功能,也就是同时提供硬件存取和软件仿真。 您应该在设计软件时尽可能地使用硬件功能而非软件仿真,因为硬件执行速度较快。记住,软件装置未必支持硬件装置所有支持的特性。因此,您应该查询装置的特性来找出硬件支持的部分,而在缺少硬件加速卡的系统上再使用软件仿真。

HAL和TnLHAL装置皆属于硬件加速,您应该多加利用。Direct3D应用程序利用Direct3D方法和HAL来存取3D硬件。如果系统里有一片Direct3D功能的3D硬件加速卡,您应该将它用在硬件实作的Direct3D功能上。如果没有可用的硬件加速时,RGB装置(它会试着利用MMX)则是次佳的选择。RGB装置是一种软件扫描成像器,所以它会比硬件加速装置来得慢。然而,RGB装置可以运用现有的CPU延伸功能,例如MMX、3DNOW!和Katmai,来尽可能地加快执行速度。

取得各种装置类型的呼叫指令如下:

CreateDevice(IID_IDirect3DTnLHalDevice, lpDirectDrawSurface, lplpDirect3DDevice); CreateDevice(IID_IDirect3DHALDevice, lpDirectDrawSurface, lplpDirect3DDevice); CreateDevice(IID_IDirect3DRGBDevice, lpDirectDrawSurface, lplpDirect3DDevice); CreateDevice(IID_IDirect3DRefDevice, lpDirectDrawSurface, lplpDirect3DDevice);

IDirect3DDevice7界面的成员函式IDirect3DDevice7::GetCaps,会取得所有Direct3D装置的特性。这个方法会将描述这些特性的数据存入D3DDEVICEDESC7结构中。 D3DDEVICEDESC7结构的定义如下:

typedef struct _D3DDeviceDesc7 {

DWORD D3DPRIMCAPS D3DPRIMCAPS DWORD

dwDevCaps;//装置特性 dpcLineCaps; dpcTriCaps;

dwDeviceRenderBitDepth;//DDBB_8,16,等dwDeviceZBufferBitDepth;//DDBD_16,32,dwMinTextureWidth,dwMinTextureHeight; dwMaxTextureWidth,dwMaxTextureHeight; dwMaxTextureRepeat; dwMaxTextureAspectRatio; dwMaxAnisotropy; dvGuardBandLeft; dvGuardBandTop; dvGuardBandRight; dvGuardBandBottom; dvExtentsAdjust;

中的任一种 DWORD 等中的任一种

DWORD DWORD DWORD DWORD DWORD D3DVALUE D3DVALUE D3DVALUE D3DVALUE D3DVALUE

DWORD DWORD DWORD WORD WORD DWORD D3DVALUE GUID WORD WORD DWORD DWORD DWORD DWORD DWORD

dwStencilCaps; dwFVFCaps; dwTextureOpCaps;

wMaxTextureBlendStages; wMaxSimultaneousTextures;

dwMaxActiveLights; dvMaxVertexW;

deviceGUID; wMaxUserClipPlanes; wMaxVertexBlendMatrices;

dwVertexProcessingCaps; dwReserved1; dwReserved2; dwReserved3; dwReserved4;

}D3DDEVICEDESC7,*LPD3DDEVICEDESC7;

这个结构的成员定义如下:

? dwDevCaps 包含了辨认装置特性的旗标。

? dpcLineCaps 和 dpcTriCaps D3DPRIMCAPS结构中定义该装置支持了画线和三

角形基本形状。

? dwDeviceRenderBitDepth 装置的绘制位深度(rendering bit depth)。本成员可能

是一个或多个DirectDraw位深度常数(如DDBD_8、DDBD_16、DDBD_24或DDBD_32)。

? dwDeviceZBufferBitDepth 代表装置的深度-缓冲区位深度,本成员可能是一个或

多个DirectDraw位深度(如DDBD_8、DDBD_16、DDBD_24或DDBD_32)。

? dwMinTextureWidth、dwMinTextureHeight 代表装置的最小贴图宽度和高度。

? dwMaxTextureWidth、dwMaxTextureHeight 代表装置的最大贴图宽度和高度。

? dwMaxTextureRepeat 包含了后正规化贴图索引(postnormalized texture

indices)的整数(非分数)位的全部范围。如果

D3DDEVCAPS_TEXREPEATNOTSCALEDBYSIZE位值被设定,装置会延迟贴图尺寸的缩放,一直套用到贴图地址模式为止。如果未设定时,装置会在内插前先依据贴图尺寸(细部的最大程度)去缩放贴图索引。

? dwMaxTextureAspectRatio 表示硬件支持的最大贴图比例;本值通常是2的幂方。

? dwMaxAnisotropy 代表D3DRENDERSTATE_ANISOTROPY绘图状态的最大有效

值。

? dvGuardBandLeft、dvGuardBandTop、dvGuardBandRight和

dvGuardBandBottom 定义监视guard-band裁切区域的屏幕空间坐标。落在此区块内但不在检视埠区内的坐标会自动被裁切。

? dvExtentsAdjust 要让延伸区向外扩展以容纳柔边核心时所需要调整的像素数目。

? dwStencilCaps 包含了哪些可支持屏蔽缓冲区(stencil-buffer)作业的旗标。

? dwFVFCaps 代表弹性顶点格式特性。

? dwTextureOpCaps 包含了各种旗标值的组合,这些旗标值是用来描述装置所支持

的贴图指令。

? wMaxTextureBlendStages 表示装置支持的最大贴图混合阶层(texture blending

stages)。

? wMaxSimultaneousTextures 表示可同时附加在装置的贴图连缩阶层上的贴图最大

值。

? dwMaxActiveLights 表示可以同时发生作用的最大光源数。

? dvMaxVertexW 表示装置可支持的最大w深度值。

? deviceGUID 表示可辨识该装置的GUID。

? wMaxUserClipPlanes 表示装置支持的使用者定义裁切面的最大值。这个成员的范

围值可以从0到D3DMAXUSERCLIPPLANES。利用

IDirect3DDevice7::GetClipPlane和IDirect3DDevice7::SetClipPlane方法可以控制

使用者定义裁切面。

? wMaxVertexBlendMatrices 表示当执行多矩阵顶点混色(multimatrix vertex

blending)时,装置可以应用的最多矩阵数目。

? dwVertexProcessingCaps 表示装置的顶点处理。

? dwReserved1 到 dwReserved4 保留用途。

您可以看得出来,这里提供了许多的特性。您必须依您的程序需求决定要检查哪些项目。不过,您应该尽可能地多运用他们,以创造出更真实的3D环境。举例来说,本书所提到的RoadRage程序用到了烟雾和α混色来提供尽可能真实的成像和动态3D世界。 您也需要提供使用者管道来挑选其它可用的装置(或模式),这样他/她才能去改变初始的默认值(例如,RGB vs. HAL;全屏幕vs. 窗口模式;一个较低分辨率模式,如800×600 vs. 640×480;等等)。

以下的程序会去处理当使用者从 File 菜单选择「改变装置/模式」的动作。它产生一个对话盒包括了可用的装置和模式,允许使用者挑选想要的装置和模式,并且切换过去。这里是一些需要加入档案d3dapp.cpp中的CD3DApplication::MsgProc成员函式的程序代码,来处理使用者选择菜单的动作:

case IDM_CHANGEDEVICE: }

return 0;

//显示「选择装置」的对话盒 if (m_bActive &&m_bReady) { { }

Pause(FALSE);

if(FAILED(hr =Change3DEnvironment())) return 0;

Pause(TRUE); if

(SUCCEEDED(D3DEnum_UserChangeDevice(&m_pDeviceInfo)))

图4-1表示在选择一个新装置或模式时,程序会产生一个下拉式菜单。

图4-1 选择新装置或模式

图4-2则是当使用者作了选择之后程序所产生的对话盒。使用者可以挑选想要的装置(例如,主要装置或是其它辅助装置)和模式。

图4-2 Change Device对话盒

本章中新增到CD3DApplication::MsgProc成员函式中的新case指令,会去呼叫D3DEnum_UserChangeDevice来产生一个对话盒显示所有系统可用的装置和模式,并且可让使用者挑选一个新的。参考上面的图,对话盒的上方会有一个清单方块列出每一个装置,而对话盒的下方会有一个清单方块列出所有模式。 D3DEnum_UserChangeDevice程序如下:

//-------------------------------------------------------------------

//名称:D3DEnum_UserChangeDevice //说明:跳出一个对话盒让使用者选择 // ---

HRESULT D3DEnum_UserChangeDevice(D3DEnum_DeviceInfo**ppDevice)

新装置

//----------------------------------------------------------------

{ }

这个程序会呼叫Windows DialogBoxParam函式,并从您所指定的对话盒范本资源中 建立一个典型的对话盒。它会用到一个回传函式在lpDialogFunc参数中。除非回传函式呼叫EndDialog函式来终止这个典型的对话盒,否则这个典型的对话盒不会传回控制权。呼叫DialogBoxParam时所指定的ChangeDeviceProc回传会处理在这个装置选择对话盒中的所有Windows讯息。

if(IDOK ==DialogBoxParam((HINSTANCE)GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_CHANGEDEVICE), GetForegroundWindow(),

return S_OK;

ChangeDeviceProc,(LPARAM)ppDevice)) return E_FAIL;

//-------------------------------------------------------------------

//名称:ChangeDeviceProc

//说明:「选择装置」对话盒的Windows讯息处理函式 //

//-------------------------------------------------------------------

static BOOL CALLBACK ChangeDeviceProc(HWND hDlg,UINT uiMsg, WPARAM wParam,LPARAM lParam) {

//取得对列举装置清单的存取权 D3DEnum_DeviceInfo*pDeviceList; DWORD dwNumDevices;

D3DEnum_GetDevices(&pDeviceList,&dwNumDevices); static D3DEnum_DeviceInfo**ppDeviceArg; static D3DEnum_DeviceInfo*pCurrentDevice; static DWORD dwCurrentMode; static BOOL bCurrentWindowed; static BOOL bCurrentStereo;

an }

//处理初始化讯息

if(WM_INITDIALOG ==uiMsg) {

//Get the application 's current device,passed in as //lParam argument.

ppDeviceArg =(D3DEnum_DeviceInfo**)lParam; if(NULL ==ppDeviceArg)

return FALSE;

//设定对话盒的暂时储存指标 pCurrentDevice =(*ppDeviceArg);

dwCurrentMode =pCurrentDevice->dwCurrentMode; bCurrentWindowed =pCurrentDevice->bWindowed; bCurrentStereo =pCurrentDevice->bStereo;

UpdateDialogControls(hDlg,pCurrentDevice,dwCurrentMode, bCurrentWindowed,bCurrentStereo); return TRUE;

else if(WM_COMMAND==uiMsg) {

//取得目前使用者的接口状态。

DWORD dwDevice =ComboBox_GetCurSel(hwndDevice); DWORD dwModeItem =ComboBox_GetCurSel(hwndMode); DWORD dwMode = BOOL bWindowed = BOOL bStereo =

ComboBox_GetItemData(hwndMode,dwModeItem); hwndWindowed ?Button_GetCheck(hwndWindowed):0; hwndStereo ?Button_GetCheck(hwndStereo):0;

D3DEnum_DeviceInfo*pDevice =&pDeviceList [dwDevice]; HWND hwndDevice =GetDlgItem(hDlg,IDC_DEVICE_COMBO); HWND hwndMode =GetDlgItem(hDlg,IDC_MODE_COMBO);

HWND hwndWindowed =GetDlgItem(hDlg,IDC_WINDOWED_CHECKBOX); HWND hwndStereo =GetDlgItem(hDlg,IDC_STEREO_CHECKBOX);

}

if(IDOK ==LOWORD(wParam)) {

//处理当使用者按下Ok时的状况。检查 //使用者是否改变任何选项。 if(pDevice !=pCurrentDevice|| { } else

EndDialog(hDlg,IDCANCEL);

return TRUE;

//传回新选择的装置及 //其新属性。

(*ppDeviceArg)=pDevice; pDevice->bWindowed =bWindowed; pDevice->bStereo =bStereo; pDevice->dwCurrentMode =dwMode; pDevice->ddsdFullscreenMode = pDevice->pddsdModes [dwMode]; EndDialog(hDlg,IDOK); dwMode !=dwCurrentMode|| bWindowed !=bCurrentWindowed|| bStereo !=bCurrentStereo)

else if(IDCANCEL ==LOWORD(wParam)) { }

else if(CBN_SELENDOK ==HIWORD(wParam)) {

if(LOWORD(wParam)==IDC_DEVICE_COMBO) {

//处理当使用者选择「装置组合」时的状况。 //

dwMode =pDeviceList [dwDevice].dwCurrentMode; bWindowed =pDeviceList [dwDevice].bWindowed;

//处理当使用者按下Cancel时的状况。 EndDialog(hDlg,IDCANCEL); return TRUE;

}

}

bStereo =pDeviceList [dwDevice].bStereo;

//将使用接口更新为最新状态

UpdateDialogControls(hDlg,&pDeviceList [dwDevice],dwMode, bWindowed,bStereo); return TRUE; }

一旦建立了对话盒,ChangeDeviceProc回传动作呼叫GetDlgItem函式来取得不同的清单方块控件的处理权。一旦它得到了不同控件的处理权,它会呼叫D3DEnum_GetDevices程序来建立一串装置和模式。在列举动作中建立的g_d3dDevices全域装置数组中执行循环,可以将每个装置加入装置清单方块中。每个装置的相关模式也会自动被加入模式清单方块中。

如果这个装置可以在窗口中成像,即可增加一个窗口模式。然后,会循环检查每个全屏幕模式(这个数目是存在pDevice->dwNumModes全域变量中)。每个储存在pDevice->pddsdModes 数组(它是一种DDSURFACEDESC2结构的数组,包含了每个模式的说明)中的模式都会被加入模式清单方块中。最后清单中被挑选的该项目会被设定成目前的模式。

//-------------------------------------------------------------------

//名称:UpdateDialogControls

//说明:建立装置选择对话盒中组合方块的 // ---

static VOID UpdateDialogControls(HWND hDlg, D3DEnum_DeviceInfo*pCurrentDevice, bWindowed, {

//存取列举装置清单。

D3DEnum_DeviceInfo*pDeviceList; DWORD dwNumDevices;

装置和模式清单

//----------------------------------------------------------------

DWORD dwCurrentMode,BOOL BOOL bStereo)

D3DEnum_GetDevices(&pDeviceList,&dwNumDevices); //存取UI控件

HWND hwndDevice =GetDlgItem(hDlg,IDC_DEVICE_COMBO); HWND hwndMode =GetDlgItem(hDlg,IDC_MODE_COMBO);

HWND hwndWindowed =GetDlgItem(hDlg,IDC_WINDOWED_CHECKBOX); HWND hwndStereo =GetDlgItem(hDlg,IDC_STEREO_CHECKBOX); HWND hwndFullscreenText =GetDlgItem(hDlg,IDC_FULLSCREEN_TEXT); //重设每个组合方块的内容。

ComboBox_ResetContent(hwndDevice); ComboBox_ResetContent(hwndMode); //不要让非GDI装置变成窗口模式

if(FALSE ==pCurrentDevice->bDesktopCompatible) bWindowed //将装置清单加入装置组合方块中。

for(DWORD device =0;device

D3DEnum_DeviceInfo*pDevice =&pDeviceList [device]; //将装置名称加入组合方块中。

DWORD dwItem =ComboBox_AddString(hwndDevice, pDevice->strDesc); //设定目前装置的其余UI状态。 if(pDevice ==pCurrentDevice) { }

//在目前装置上设定组合方块选项。 ComboBox_SetCurSel(hwndDevice,dwItem); //适当的设定/开启全屏幕复选框。 if(hwndWindowed) {

EnableWindow(hwndWindowed, pDevice->bDesktopCompatible);

=FALSE;

Button_SetCheck(hwndWindowed,bWindowed);

//适当的设定/开启立体模式复选框。 if(hwndStereo) {

EnableWindow(hwndStereo, }

//适当的设定/开启全屏幕模式组合方块。 //

EnableWindow(hwndMode,!bWindowed);

EnableWindow(hwndFullscreenText,!bWindowed); //建立全屏幕模式的清单

for(DWORD mode =0;mode dwNumModes;mode++) {

DDSURFACEDESC2*pddsdMode = &pDevice->pddsdModes [mode];

pDevice->bStereoCompatible &&!bWindowed); Button_SetCheck(hwndStereo,bStereo);

//若装置处于立体模式下时,略过 //非立体模式。

if(0 ==(pddsdMode->ddsCaps.dwCaps2 & DDSCAPS2_STEREOSURFACELEFT))

if(bStereo)

continue;

TCHAR strMode [80];

wsprintf(strMode,_T(\

pddsdMode->dwWidth,pddsdMode->dwHeight,pddsdMode-

//将模式描述加入组合方块中。 DWORD dwItem =

ComboBox_AddString(hwndMode,strMode);

//设定可辨别模式的项目数据

\

>ddpfPixelFormat.dwRGBBitCount);

本文来源:https://www.bwwdw.com/article/8g0d.html

Top