Chinaunix首页 | 论坛 | 博客
  • 博客访问: 588399
  • 博文数量: 208
  • 博客积分: 3286
  • 博客等级: 中校
  • 技术积分: 1780
  • 用 户 组: 普通用户
  • 注册时间: 2007-09-24 20:38
文章分类

全部博文(208)

文章存档

2012年(7)

2011年(28)

2010年(21)

2009年(76)

2008年(65)

2007年(11)

我的朋友

分类: C/C++

2008-02-20 13:03:28

作者:clayman

转载请注明作者,商业使用请联系我^_^

理解框架

 

         首先创建工程,添加对DirectX程序集的引用。接下来,把sample framework添加到工程中。我们把这些文件放到一个单独的文件夹中,在解决方案管理器中点击右键---添加---新建文件夹,并把它命名为framework。右键点击新创建的文件夹,选择添加现有项,导航到SDK\Samples\Managed\Common目录下,把每一个文件添加到项目中。

 

         好了,现在回到我们刚才创建的Form1.cs文件中来,可以看到大部分自动生成的代码都是用来创建Windows Form应用程序的。因此删除所有代码,并添加如下代码:

 

using System;

 

using System.Configuration;

 

using Microsoft.DirectX;

 

using Microsoft.DirectX.Direct3D;

 

using Microsoft.Samples.DirectX.UtilityToolkit;

 

 

public class GameEngine : IDeviceCreation

 

{

 

    static intMain()

 

    {

 

        using(Framework sampleFramework = new Framework())

 

        {

 

            return sampleFramework.ExitCode;

 

        }

 

    }

 

}

 

这里有三个需要注意的地方 。首先,我们只留下了一个修改过的main方法。由于其他代码都是窗体设计器为Windows Form程序生成的,所以完全可以删除它们。其次,代码现在还不能通过编译,应为GameEngine类还有两个接口没有实现。第三,这段代码实际上什么也没做。

 

首先我们来实现IDeviceCreation接口,你将通过他来控制枚举和创建device。在这里,枚举的含义包括检查目标机器上有几块显卡、几个显示器、可以支持多少种显示模式、控制刷新率等等。

 

public bool IsDeviceAcceptable(Caps caps, Format adapterFormat,Format backBufferFormat, bool windowed)

 

{

 

         if (!Manager.CheckDeviceFormat(caps.AdapterOrdinal, caps.DeviceType,adapterFormat, Usage.QueryPostPixelShaderBlending,

 

                   ResourceType.Textures, backBufferFormat))

 

                   return false;

 

         if (caps.MaxActiveLights == 0)

 

                   return false;

 

return true;

 

}

 

 

public void ModifyDeviceSettings(DeviceSettings settings, Caps caps)

 

{

 

         if ( (caps.DeviceCaps.SupportsPureDevice) && ((settings.BehaviorFlags & CreateFlags.HardwareVertexProcessing) != 0 ) )

 

                   settings.BehaviorFlags |= CreateFlags.PureDevice;

 

}

 

第一个方法将在device初始化时调用,用来检查device最低能支持什么特性(capability)。当sample framework在系统上枚举设备时,他会对所找到的每一种可能组合调用这个方法。注意看这个方法是如何决定返回值的。他的第一个参数包含了大量关于制定设备的信息,可以帮你决定它是否是你希望创建的device类型。接下来的参数一个是关于后备缓冲的,另一个则是关于设备格式。最后一个参数则是检查是否支持窗口模式。虽然大多数游戏都是运行在全屏模式,但在窗口模式之下调试程序会方便一些。这个方法默认情况下将返回true,但他还做了两个特别的检查。首先,检查它是否支持alpha混合(创建游戏的用户界面将用到他)。其次,检查是否支持动态灯光----没有灯光物体看起来会很单调而且不真实,所以至少使用一个灯光。

 

再来看第二个方法:在创建device之前调用它,来修改创建设备的参数。Setting参数包含了框架为device所制定的设置,你可以自由的修改这些设置。需要特别注意的是sample framework不会验证这些设置的有效性,因此,你需要自己来验证。

 

在继续之前,还有一件事情要做。由于sample framework包含一些unsafe的代码块,因此,必须允许工程中包含不安全代码:

 

现在,可以使用框架来枚举设备了。首先,为GameEngine类添加一个构造函数,把从main方法中创建的sample framework实例作为参数:

 

private Framework sampleFramework = null;

 

public GameEngine(Framework f)

 

{

 

         // Store framework

 

sampleFramework = f;

 

}

 

在调用了sample framework之后,他所做的第一件事就是枚举系统设备。在工程中,打开之前添加的dxmutenum.cs文件。这个文件包含了枚举设备的所有代码。由于知道如何以及为什么枚举设备是很重要的,我们来仔细看一下这些代码。

 

首先注意到Enumeration是不能被实例化的,塔顶每一个方法和成员也都是静态的。因为就目前来说,你的硬件图形设备在运行时不太可以改变,所以枚举的过程在程序一开始运行一次就可以了。

 

大多数的枚举过程都是在创建device之前,通过sample framework调用Enumerate方法开始的。这个方法所接受的唯一参数,就是我们至今为止在GameEngine类中实现的接口。在枚举设备状态组合的时候,需要调用IsDeviceAcceptable方法来判断这个设备状态是否应该添加到正确的设备列表中。那么到底是如何来枚举设备的呢?实际上大多数功能都是通过Manager类来完成的。如果你熟悉普通的DirectX API,那么这个类实际上就是COM接口Idirect3D9的映射。(注:枚举设备的过程这里不再讲解,请看我以前翻译过的文章)

 

把所有符合框架要求的显示模式都保存到一个列表中,最后,通过实现Icomparer接口对他们进行排序。

 

public class DisplayModeSorter : IComparer

 

{

 

        public int Compare(object x, object y)

 

        {

 

            DisplayMode d1 = (DisplayMode)x;

 

            DisplayMode d2 = (DisplayMode)y;

 

            if (d1.Width > d2.Width)

 

                return +1;

 

            if (d1.Width < d2.Width)

 

                return -1;

 

            if (d1.Height > d2.Height)

 

                return +1;

 

            if (d1.Height < d2.Height)

 

                return -1;

 

            if (d1.Format > d2.Format)

 

                return +1;

 

            if (d1.Format < d2.Format)

 

                return -1;

 

            if (d1.RefreshRate > d2.RefreshRate)

 

                return +1;

 

            if (d1.RefreshRate < d2.RefreshRate)

 

                return -1;

 

            return 0;

 

        }

 

}

 

这里的算法很简单,大家自己看吧。保存了可用的显示模式之后,调用EnumerateDevices方法。

 

private static void EnumerateDevices(EnumAdapterInformation adapterInfo,

 

    ArrayList adapterFormatList)

 

{

 

    // Ignore any exceptions while looking for these device types

 

    DirectXException.IgnoreExceptions();

 

    // Enumerate each Direct3D device type

 

    for(uint i = 0; i < deviceTypeArray.Length; i++)

 

    {

 

        // Create a new device information object

 

        EnumDeviceInformation deviceInfo = new EnumDeviceInformation();

 

        // Store the type

 

        deviceInfo.DeviceType = deviceTypeArray[i];

 

        // Try to get the capabilities

 

        deviceInfo.Caps = Manager.GetDeviceCaps((int)adapterInfo.AdapterOrdinal, deviceInfo.DeviceType);

 

        // Get information about each device combination on this device

 

        EnumerateDeviceCombos( adapterInfo, deviceInfo, adapterFormatList);

 

        // Do we have any device combinations?

 

        if (deviceInfo.deviceSettingsList.Count > 0)

 

        {

 

            // Yes, add it

 

            adapterInfo.deviceInfoList.Add(deviceInfo);

 

        }

 

    }

 

    // Turn exception handling back on

 

    DirectXException.EnableExceptions();

 

}

 

观察一下这段代码,你应该注意到并且记住两件事。猜猜是什么?如果答案是DirectXException类方法调用,那么恭喜,答对了。DirectXException.IgnoreExceptions();方法关闭了Managed DirectX程序集中所有异常抛出。你可能会问这样做有什么好处,答案是性能的提升。捕捉和抛出异常是系统花费很大的操作,而这段代码有可能导致多个异常的抛出。你只希望快速的完成枚举,因此,暂时忽略所有异常,在这段代码结束的时候,再打开异常机制。虽然这里的代码很简单,但你可能会问问什么会导致异常。

 

很高兴你问到了这个问题,那么我们就来仔细讨论一下吧。最常见的问题就是你的设备不支持DirectX 9。有可能你没有更新驱动程序,或者当前的驱动程序没有正确安装。也有可能是你的显卡太老了无法使用DirectX 9。通常PCI接口的显卡都不能很好的支持DirectX 9了。

 

这段代码尝试获得关于显卡能力的信息,并为适配器枚举合适的组合。可用的设备类型有以下几种:Hardware, Reference, software

 

假设枚举时找到了合适的设备设置组合,就把他保存到一个列表中。Enumeration类为之后创建device保存了一些列表,观察EnumerateDeviceCombos方法。注意,如果IsDeviceAcceptable方法返回false,那么就忽略这种设备组合类型。

阅读(938) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~