Device Options and Enumeration

  CU_MDX_Enumeration.zip (63.1 KiB, 2,859 hits)


  CUnitFramework.zip (101.1 KiB, 20,406 hits)

Extract the C-Unit Framework
inside the project (not solution) directory.

In just about all commercial games available today, users have the ability to customize their display options to suit their machine’s capabilities. In this tutorial, we will create_ a video options dialog that will allow users to select from such settings as display resolutions, color formats, refresh rates, depth formats, presentation intervals, and pretty much everything that is found in the PresentParameters class.

Dialog

Note that this dialog uses the C-Unit GUI system. Since we haven’t learned about that yet, just think of it as a black box for now. We’ll learn about it in detail in a later tutorial.

In order to create_ this options dialog, we first have to enumerate all the different Device configurations that the client system supports. These configurations can be represented in a tree-like structure. At the top of the tree are the display adapters, or video cards. Each display adapter in a system is assigned an adapter ordinal. Usually, the adapter ordinal will be 0. The ordinal increments with each new adapter added to the system. Each display adapter also has its own set of DisplayModes that it can support and a set of Devices that it can create. The DisplayMode set specifies which screen resolution/color format/refresh rate combinations the adapter supports. The Device set is usually comprised of two Device types: a hardware device and a reference device. We pretty much always want the hardware device as a reference device is dreadfully slow and is used only to test features that are not currently implemented by the hardware.

Moving down the tree, we land on the Devices found in the list of Devices that the display adapter can make. As stated above, each Device has a unique DeviceType. Each Device also has its own Capabilities structure and list of settings that the Device supports. Each of these settings represents a unique combination of a backbuffer format, an adapter format, and either windowed or fullscreen mode. This brings us down another step of the tree.

Each Device has a list of Device settings. As stated previously, each of these settings represents a unique combination of a backbuffer format, an adapter format, and either windowed or fullscreen mode. Along with this unique combination are a bunch of lists of more settings that can be used with this combination. These additional settings include depth/stencil formats, multisample types, multisample qualities, presentation intervals, and vertex processing options. This node of the tree basically represents all the different combinations of PresentParameters that can be made given an adapter format, backbuffer format, and windowed or fullscreen flag.

The Device that we actually create_ will use a unique set of settings from the “Device Settings” node of the tree. And since we all know how nice pictures are, below is a picture of all that I just talked about:

Enumeration
/// Represents a system adaptor.
public class AdapterEnum
{

public uint AdapterOrdinal;

public AdapterDetails AdapterInformation;
public ArrayList DisplayModeList = new ArrayList();
public ArrayList DeviceEnumList = new ArrayList();

public string Description;

}

///

Represents the capabilities and description of a single device.
public class DeviceEnum

{

public uint AdapterOrdinal;
public DeviceType DeviceType;
public Caps Caps;
public ArrayList SettingsList = new ArrayList();

}

///

Represents the various settings a device can have.
public class DeviceSettingsEnum
{

public uint AdapterOrdinal;

public DeviceType DeviceType;
public Format AdapterFormat;
public Format BackBufferFormat;
public bool Windowed;

// Array lists
public ArrayList DepthStencilFormatList = new ArrayList();
public ArrayList MultiSampleTypeList = new ArrayList();

public ArrayList MultiSampleQualityList = new ArrayList();
public ArrayList PresentIntervalList = new ArrayList();
public ArrayList VertexProcessingTypeList = new ArrayList();

public AdapterEnum AdapterInformation = null;
public DeviceEnum DeviceInformation = null;

}

///

Represents a Device with single settings configuration.
public class DeviceSettings : ICloneable
{

public uint AdapterOrdinal;

public Format AdapterFormat;
public CreateFlags BehaviorFlags;
public Caps Caps;
public DeviceType DeviceType;
public PresentParameters PresentParameters;

///

Clones the settings
/// The cloned settings
public object Clone()

{

DeviceSettings settings = new DeviceSettings();
settings.AdapterOrdinal = AdapterOrdinal;
settings.AdapterFormat = AdapterFormat;
settings.BehaviorFlags = BehaviorFlags;
settings.Caps = Caps;
settings.DeviceType = DeviceType;
settings.PresentParameters = (PresentParameters)PresentParameters.Clone();

return settings;

}

}

These classes form the nodes of the tree that I described earlier. There’s a class for an adapter, a class for a DeviceType, and class for all the settings for each DeviceType. There’s also a class, DeviceSettings, that represents a unique set of all the settings put together. When we create_ or reset the Device, we’ll use the settings found in DeviceSettings to specify how to create_ or reset the Device.

public class Graphics

{

private ArrayList m_adapters = new ArrayList();
private DeviceSettings m_windowedSettings = null;
private DeviceSettings m_fullscreenSettings = null;

private DeviceSettings m_currentSettings = null;

private Device m_device = null;
private Control m_renderWindow = null;

private DisplayMode m_displayMode;
private bool m_windowed;

///

Initializes Direct3D.

/// True for windowed mode. False for fullscreen mode.
/// Render window.
/// Desired backbuffer width

/// Desired backbuffer height
public void Initialize( bool windowed, Control control, int desiredWidth, int desiredHeight ) Toggle

{

m_windowed = windowed;

m_renderWindow = control;
m_displayMode = Manager.Adapters[0].CurrentDisplayMode;
EnumerateAdapters();

// Create the device settings
m_windowedSettings = FindBestWindowedSettings();
m_fullscreenSettings = FindBestFullscreenSettings();
m_currentSettings = (windowed) ? m_windowedSettings : m_fullscreenSettings;

ChangeDevice( m_currentSettings );

}

///

Changes the device with new settings.
public void ChangeDevice( DeviceSettings newSettings ) Toggle

{

if ( m_device != null )

{

m_device.Dispose();
m_device = null;

}
try
{

m_device = new Device( (int)newSettings.AdapterOrdinal, newSettings.DeviceType, m_renderWindow.Handle, newSettings.BehaviorFlags, newSettings.PresentParameters );

}
catch ( DirectXException )
{

throw new DirectXException( “Unable to create_ the Direct3D device.” );

}

}

///

ReBuilds the PresentParameters class inpreparation for device reset.
private void ResetPresentParameters() Toggle

{

if ( m_windowed )

{

m_currentSettings.PresentParameters.BackBufferWidth = 0;
m_currentSettings.PresentParameters.BackBufferHeight = 0;

}

}

///

Reset the device

public void Reset() Toggle

{

if ( m_device != null )
{

ResetPresentParameters();
m_device.Reset( m_currentSettings.PresentParameters );

}

}

// Clip…

}

To implement all this enumeration mumbo jumbo, the C-Unit Framework has a Graphics class that finds all the supported Device configurations and allows us to create_ a Device with one of these configurations. To do this, the Graphics class will store three different DeviceSettings instances: one for fullscreen mode, one for windowed mode, and one that we’ll use as the current settings, which will switch between the fullscreen and windowed settings. Before we can set the DeviceSettings instances, we have to enumerate through all the possible Device configurations that the system supports. To do this however, we’ll first create_ a few arrays that specify the possible values that the settings can take.

// Default arrays
public static readonly Format[] AdapterFormats = new Format[]
{

Format.X8R8G8B8, Format.X1R5G5B5, Format.R5G6B5, Format.A2R10G10B10

};
public static readonly Format[] BackBufferFormats = new Format[]
{

Format.A8R8G8B8, Format.X8R8G8B8, Format.R8G8B8, Format.A2R10G10B10,
Format.A8R3G3B2, Format.A4R4G4B4, Format.A1R5G5B5, Format.X4R4G4B4,

Format.X1R5G5B5, Format.R5G6B5, Format.R3G3B2

};
public static readonly DeviceType[] DeviceTypes = new DeviceType[]
{

DeviceType.Hardware, DeviceType.Software, DeviceType.Reference

};
public static readonly MultiSampleType[] MultiSampleTypes = new MultiSampleType[]
{

MultiSampleType.None, MultiSampleType.NonMaskable, MultiSampleType.TwoSamples,
MultiSampleType.ThreeSamples, MultiSampleType.FourSamples, MultiSampleType.FiveSamples,

MultiSampleType.SixSamples, MultiSampleType.SevenSamples, MultiSampleType.EightSamples,
MultiSampleType.NineSamples, MultiSampleType.TenSamples, MultiSampleType.ElevenSamples,
MultiSampleType.ThirteenSamples, MultiSampleType.TwelveSamples, MultiSampleType.FourteenSamples,
MultiSampleType.FifteenSamples, MultiSampleType.SixteenSamples

};
public static readonly DepthFormat[] DepthFormats = new DepthFormat[]

{

DepthFormat.D32, DepthFormat.D24X4S4, DepthFormat.D24X8, DepthFormat.D24S8, DepthFormat.D16, DepthFormat.D15S1

};
public static readonly PresentInterval[] PresentIntervals = new PresentInterval[]
{

PresentInterval.Immediate, PresentInterval.Default, PresentInterval.One,

PresentInterval.Two, PresentInterval.Three, PresentInterval.Four

};

These arrays form all the different possible values that we will test support for. The contents of each array are specified in preference order. When we create_ the initial DeviceSettings instance, we’ll use the values found at the beginning of each array. If you don’t know what all these values are used for, head over to MSDN’s Direct3D page and practice your lookup skills 🙂 Once these arrays are specified, we can begin the enumeration process.

public class Graphics

{

// Clip…

///

Enumerates through all the Adapters in the system.
private void EnumerateAdapters() Toggle

{

foreach ( AdapterDetails a in Manager.Adapters )

{

AdapterEnum currentAdapter = new AdapterEnum();

// Store Adapter Ordinal and Information
currentAdapter.AdapterOrdinal = (uint)a.Adapter;
currentAdapter.AdapterInformation = a.Information;
currentAdapter.Description = a.Information.Description;

// Get all the DisplayModes the Adapter supports
ArrayList adapterFormatList = EnumerateDisplayModes( a, currentAdapter );
// Get all the Devices the Adapter can make
EnumerateDevices( currentAdapter, adapterFormatList );

// Add the Adaptor to the list
m_adapters.Add( currentAdapter );

}

}

///

Enumerates through all supported DisplayModes for an Adapter.
/// Adapter to enumerate.

/// AdapterEnum that stores the list of DisplayModes.
/// A List of Adapter Formats used in the supported DisplayModes.
private ArrayList EnumerateDisplayModes( AdapterDetails a, AdapterEnum currentAdapter ) Toggle

{

ArrayList adapterFormatList = new ArrayList();

for ( int i = 0; i < AdapterFormats.Length; i++ )
{

foreach ( DisplayMode d in a.SupportedDisplayModes[AdapterFormats[i]] )

{

currentAdapter.DisplayModeList.Add( d );

// Add Adaptor Format used with this DisplayMode
if ( !adapterFormatList.Contains( d.Format ) )
{

adapterFormatList.Add( d.Format );

}

}

}
DisplayModeSorter sorter = new DisplayModeSorter();
currentAdapter.DisplayModeList.Sort( sorter );
return adapterFormatList;

}

///

Enumerates through all the Devices an Adapter can make.
///
/// List of Adapter Formats supported by the Adapter

private void EnumerateDevices( AdapterEnum currentAdapter, ArrayList adapterFormatList ) Toggle

{

// Get all the Devices this Adapter can make
foreach( DeviceType t in DeviceTypes )
{

DeviceEnum currentDevice = new DeviceEnum();

// Store the DeviceType and Capabilities
currentDevice.DeviceType = t;
try
{

currentDevice.Capabilities = Manager.GetDeviceCapabilities( (int)currentAdapter.AdapterOrdinal, currentDevice.DeviceType );

}
catch( DirectXException )

{

// DeviceType.Software throws an exception. Can ignore

}

// Find the supported settings for this device
EnumerateDeviceSettings( currentDevice, currentAdapter, adapterFormatList );

// Add the Device to the list if it has any valid settings
if ( currentDevice.SettingsList.Count > 0)

{

currentAdapter.DeviceEnumList.Add( currentDevice );

}

}

}

///

Enumerates device combinations for a particular device.

/// Device to enumerate.
///
/// List of supported Adapter Formats

private void EnumerateDeviceSettings( DeviceEnum currentDevice, AdapterEnum currentAdapter, ArrayList adapterFormatList ) Toggle

{

// Go through each Adapter Format
foreach ( Format adapterFormat in AdapterFormats )
{

// Go through each BackBuffer Format

foreach( Format backbufferFormat in BackBufferFormats )
{

// Check both windowed and fullscreen modes
for ( int i = 0; i < 2; i++ )

{

bool windowed = (i == 1);

// Skip if this is not a supported Device type
if ( !Manager.CheckDeviceType( (int)currentAdapter.AdapterOrdinal, currentDevice.DeviceType,

adapterFormat, backbufferFormat, windowed ) )
{

continue;

}

DeviceSettingsEnum deviceSettings = new DeviceSettingsEnum();

// Store the information
deviceSettings.AdapterInformation = currentAdapter;
deviceSettings.DeviceInformation = currentDevice;
deviceSettings.AdapterOrdinal = currentAdapter.AdapterOrdinal;
deviceSettings.DeviceType = currentDevice.DeviceType;
deviceSettings.AdapterFormat = adapterFormat;
deviceSettings.BackBufferFormat = backbufferFormat;
deviceSettings.IsWindowed = windowed;

// Create the settings Arrays
EnumerateDepthStencilFormats( deviceSettings );
EnumerateMultiSampleTypes( deviceSettings );
EnumerateVertexProcessingTypes( deviceSettings );
EnumeratePresentIntervals( deviceSettings);

// Add the settings to the Device’s settings list
currentDevice.SettingsList.Add( deviceSettings );

}

}

}

}

///

Enumerates through all the Depth Stencil Formats compatible with the Device.
/// DeviceEnum with the Device info.

private void EnumerateDepthStencilFormats( DeviceSettingsEnum deviceSettings ) Toggle

{

// Check each DepthFormat
foreach ( DepthFormat depthFormat in DepthFormats )
{

// Check if the DepthFormat is a valid surface format

if ( Manager.CheckDeviceFormat( (int)deviceSettings.AdapterOrdinal, deviceSettings.DeviceType,
deviceSettings.AdapterFormat, Usage.DepthStencil, ResourceType.Surface, depthFormat ) )
{

// Check if the DepthFormat is compatible with the BackBufferFormat
if ( Manager.CheckDepthStencilMatch( (int)deviceSettings.AdapterOrdinal, deviceSettings.DeviceType,

deviceSettings.AdapterFormat, deviceSettings.BackBufferFormat, depthFormat ) )
{

// Add it to the list
deviceSettings.DepthStencilFormatList.Add( depthFormat );

}

}

}

}

///

Enumerates through all the MultiSampleTypes that are compatible with the Device.
/// DeviceEnum with the Device info.
private void EnumerateMultiSampleTypes( DeviceSettingsEnum deviceSettings ) Toggle

{

// Check each MultiSampleType

foreach ( MultiSampleType t in MultiSampleTypes )
{

int qualityLevels;
// See if it’s supported
if ( Manager.CheckDeviceMultiSampleType( (int)deviceSettings.AdapterOrdinal, deviceSettings.DeviceType,

deviceSettings.BackBufferFormat, deviceSettings.IsWindowed, t, out qualityLevels ) )
{

deviceSettings.MultiSampleTypeList.Add( t );
deviceSettings.MultiSampleQualityList.Add( qualityLevels );

}

}

}

///

Enumerates through the VertexProcessing Types that are compatible with the Device.
/// DeviceEnum with the Device info.
private void EnumerateVertexProcessingTypes( DeviceSettingsEnum deviceSettings ) Toggle

{

// Best option is stored first

// Check for hardware T&L
if ( deviceSettings.DeviceInformation.Capabilities.DeviceCaps.SupportsHardwareTransformAndLight )
{

// Check for pure device
if ( deviceSettings.DeviceInformation.Capabilities.DeviceCaps.SupportsPureDevice )
{

deviceSettings.VertexProcessingTypeList.Add( CreateFlags.PureDevice | CreateFlags.HardwareVertexProcessing );

}
deviceSettings.VertexProcessingTypeList.Add( CreateFlags.HardwareVertexProcessing );
deviceSettings.VertexProcessingTypeList.Add( CreateFlags.MixedVertexProcessing );

}

// Always supports software
deviceSettings.VertexProcessingTypeList.Add( CreateFlags.SoftwareVertexProcessing );

}

///

Enumerates through the PresentIntervals that are compatible with the Device.
/// DeviceEnum with the Device info.
private void EnumeratePresentIntervals( DeviceSettingsEnum deviceSettings ) Toggle

{

foreach ( PresentInterval p in PresentIntervals )

{

// If the device is windowed, skip all the intervals above one
if ( deviceSettings.IsWindowed )
{

if ( (p == PresentInterval.Two) || (p == PresentInterval.Three) ||
(p == PresentInterval.Four) )
{

continue;

}

}

if ( p == PresentInterval.Default )
{

// Default interval is always available
deviceSettings.PresentIntervalList.Add( p );

}

// Check if the PresentInterval is supported
if ( (deviceSettings.DeviceInformation.Capabilities.PresentInterval & p) != 0 )
{

deviceSettings.PresentIntervalList.Add( p );

}

}

}

// Clip…

}

The enumeration process begins in EnumerateAdapters, and works its way to the bottom of the tree, filling up the ArrayLists along the way.

Flow

We start by getting each of the adapters connected to the computer by looking through each of the AdapterInformation‘s found in the Manager.Adapters property. After storing some adapter information, we move on to enumerate all the adapter’s supported DisplayModes in EnumerateDisplayModes.

All of an adapter’s supported DisplayModes are found in the aptly named property, AdapterInformation.SupportedDisplayModes. While we’re storing the DisplayModes, we’ll also keep a separate copy of the Format of each DisplayMode, which we will use to help define the rest of the settings.

After the DisplayModes have been enumerated, we enumerate the Devices with EnumerateDevices. In EnumerateDevices, we create_ a new DeviceEnum instance for each DeviceType. We’ll store the Capabilities of the Device with the help of the Manager.GetDeviceCaps method. Note that a DeviceType.Software device will throw an exception, which is not big deal so we’ll just catch it and do nothing. After we have the Capabilities, we move on to EnumerateDeviceSettings. If any settings are enumerated, we add the DeviceEnum to our list of Devices.

EnumerateDeviceSettings begins by creating a new DeviceSettingsEnum instance. However, we will only create_ an instance if the current settings so far are supported by the display adapter. We can check for support by using the Manager.CheckDeviceType method. After filling out the members of the DeviceSettingsEnum that we already know, we move on to enumerate the rest of the Device settings.

The last four enumerate methods, EnumerateDepthStencilFormats, EnumerateMultiSampleTypes, EnumerateVertexProcessingTypes, and EnumeratePresentIntervals all fill up their respective ArrayLists of the current DeviceSettingsEnum instance. The Depth/Stencil Format list is filled up with the help of the Manager.CheckDeviceFormat and Manager.CheckDepthStencilMatch methods. The MultiSample type and quality lists are filled up with the help of the Manager.CheckDeviceMultiSampleType method. Finally, the VertexProcessing and PresentInterval lists are filled up by checking the values in the Capabilities structure. After all the foreach loops finish, we’ll have all the possible Device configurations stored neatly away in our AdapterEnum ArrayList.

///

/// Device wrapper
///


public class Graphics
{

// Clip…

///

Finds the best windowed Device settings supported by the system.
/// A DeviceSettings class full with the best supported windowed settings.
private DeviceSettings FindBestWindowedSettings() Toggle

{

DeviceSettingsEnum bestSettings = null;

bool foundBest = false;
// Loop through each adapter
foreach ( AdapterEnum a in m_adapters )
{

// Loop through each device

foreach ( DeviceEnum d in a.DeviceEnumList )
{

// Loop through each device settings configuration
foreach ( DeviceSettingsEnum s in d.SettingsList )

{

// Must be windowed mode and the AdapterFormat must match current DisplayMode Format
if ( !s.Windowed || (s.AdapterFormat != m_displayMode.Format) )
{

continue;

}

// The best DeviceSettingsEnum is a DeviceType.Hardware Device

// where its BackBufferFormat is the same as the AdapterFormat
if ( (bestSettings == null) ||
((s.DeviceType == DeviceType.Hardware) && (s.AdapterFormat == s.BackBufferFormat)) ||
((bestSettings.DeviceType != DeviceType.Hardware) && (s.DeviceType == DeviceType.Hardware)) )
{

if ( !foundBest )

{

bestSettings = s;

}

if ( (s.DeviceType == DeviceType.Hardware) && (s.AdapterFormat == s.BackBufferFormat) )
{

foundBest = true;

}

}

}

}

}
if ( bestSettings == null )

{

throw new DirectXException( “Unable to find any supported window mode settings.” );

}
// Store the best settings
DeviceSettings windowedSettings = new DeviceSettings();

windowedSettings.AdapterFormat = bestSettings.AdapterFormat;
windowedSettings.AdapterOrdinal = bestSettings.AdapterOrdinal;
windowedSettings.BehaviorFlags = (CreateFlags)bestSettings.VertexProcessingTypeList[0];
windowedSettings.Caps = bestSettings.DeviceInformation.Caps;
windowedSettings.DeviceType = bestSettings.DeviceType;

windowedSettings.PresentParameters = new PresentParameters();

windowedSettings.PresentParameters.AutoDepthStencilFormat = (DepthFormat)bestSettings.DepthStencilFormatList[0];
windowedSettings.PresentParameters.BackBufferCount = 1;
windowedSettings.PresentParameters.BackBufferFormat = bestSettings.AdapterFormat;
windowedSettings.PresentParameters.BackBufferHeight = 0;
windowedSettings.PresentParameters.BackBufferWidth = 0;

windowedSettings.PresentParameters.DeviceWindow = m_renderWindow;
windowedSettings.PresentParameters.EnableAutoDepthStencil = true;
windowedSettings.PresentParameters.FullScreenRefreshRateInHz = 0;
windowedSettings.PresentParameters.MultiSample = (MultiSampleType)bestSettings.MultiSampleTypeList[0];
windowedSettings.PresentParameters.MultiSampleQuality = 0;

windowedSettings.PresentParameters.PresentationInterval = (PresentInterval)bestSettings.PresentIntervalList[0];
windowedSettings.PresentParameters.PresentFlag = PresentFlag.DiscardDepthStencil;
windowedSettings.PresentParameters.SwapEffect = SwapEffect.Discard;
windowedSettings.PresentParameters.Windowed = true;

return windowedSettings;

}

///

Finds the best fullscreen Device settings supported by the system.
/// A DeviceSettings class full with the best supported fullscreen settings.

private DeviceSettings FindBestFullscreenSettings() Toggle

{

DeviceSettingsEnum bestSettings = null;
bool foundBest = false;

// Loop through each adapter
foreach ( AdapterEnum a in m_adapters )
{

// Loop through each device
foreach ( DeviceEnum d in a.DeviceEnumList )

{

// Loop through each device settings configuration
foreach ( DeviceSettingsEnum s in d.SettingsList )
{

// Must be fullscreen mode
if ( s.Windowed )

{

continue;

}

// To make things easier, we’ll say the best DeviceSettingsEnum
// is a DeviceType.Hardware Device whose AdapterFormat is the same as the
// current DisplayMode Format and whose BackBufferFormat matches the
// AdapterFormat
if ( (bestSettings == null) ||

((s.DeviceType == DeviceType.Hardware) && (s.AdapterFormat == m_displayMode.Format)) ||
((bestSettings.DeviceType != DeviceType.Hardware) && (s.DeviceType == DeviceType.Hardware)) )
{

if ( !foundBest )
{

bestSettings = s;

}

if ( (s.DeviceType == DeviceType.Hardware) &&
(s.AdapterFormat == m_displayMode.Format) &&
(s.BackBufferFormat == s.AdapterFormat) )
{

foundBest = true;

}

}

}

}

}
if ( bestSettings == null )

{

throw new DirectXException( “Unable to find any supported fullscreen mode settings.” );

}

// Store the best settings
DeviceSettings fullscreenSettings = new DeviceSettings();

fullscreenSettings.AdapterFormat = bestSettings.AdapterFormat;
fullscreenSettings.AdapterOrdinal = bestSettings.AdapterOrdinal;
fullscreenSettings.BehaviorFlags = (CreateFlags)bestSettings.VertexProcessingTypeList[0];
fullscreenSettings.Caps = bestSettings.DeviceInformation.Caps;
fullscreenSettings.DeviceType = bestSettings.DeviceType;

fullscreenSettings.PresentParameters = new PresentParameters();

fullscreenSettings.PresentParameters.AutoDepthStencilFormat = (DepthFormat)bestSettings.DepthStencilFormatList[0];
fullscreenSettings.PresentParameters.BackBufferCount = 1;
fullscreenSettings.PresentParameters.BackBufferFormat = bestSettings.AdapterFormat;
fullscreenSettings.PresentParameters.BackBufferHeight = m_displayMode.Height;
fullscreenSettings.PresentParameters.BackBufferWidth = m_displayMode.Width;
fullscreenSettings.PresentParameters.DeviceWindow = m_renderWindow;
fullscreenSettings.PresentParameters.EnableAutoDepthStencil = true;

fullscreenSettings.PresentParameters.FullScreenRefreshRateInHz = m_displayMode.RefreshRate;
fullscreenSettings.PresentParameters.MultiSample = (MultiSampleType)bestSettings.MultiSampleTypeList[0];
fullscreenSettings.PresentParameters.MultiSampleQuality = 0;
fullscreenSettings.PresentParameters.PresentationInterval = (PresentInterval)bestSettings.PresentIntervalList[0];
fullscreenSettings.PresentParameters.PresentFlag = PresentFlag.DiscardDepthStencil;
fullscreenSettings.PresentParameters.SwapEffect = SwapEffect.Discard;

fullscreenSettings.PresentParameters.Windowed = false;

return fullscreenSettings;

}

// Clip…

}

Once we have enumerated all the Device configurations, we’ll use the above methods to create_ our initial DeviceSettings instances. As stated earlier, the Graphics class will have one DeviceSettings instance for windowed mode and one for fullscreen mode. To initialize these instances, we’ll look through all the supported Device configurations that we enumerated and pick out the best configuration for windowed mode and best for fullscreen mode. While the “best” configuration can change from person to person, I simply chose the best windowed configuration as the one which uses a hardware device and where the adapter format is the same as the backbuffer format. For the fullscreen configuration, I chose one which uses a hardware device and where the adapter format is the same as both the backbuffer format and the current DisplayMode format.

At this point we have enumerated all possible Device configurations that our system can support and we have chosen a couple of initial configurations to get us up and running. Now we need to be able to choose from among the slew of Device configurations. That is where DeviceOptionsDialog comes in.

namespace CUnit
{

/// Used to adjust Device options

public class DeviceOptionsDialog : GameState
{

public enum ControlID
{

Panel = 1, DisplayAdapter, DisplayAdapterText, RenderDevice, RenderDeviceText,

RadioWindow, RadioFullscreen, AdapterFormat, AdapterFormatText, FullscreenResolution, FullscreenResolutionText,
RefreshRate, RefreshRateText, BackBufferFormat, BackBufferFormatText, DepthStencilFormat,
DepthStencilFormatText, MultiSampleType, MultiSampleTypeText, MultiSampleQuality, MultiSampleQualityText,
VertexProcessing, VertexProcessingText, PresentInterval, PresentIntervalText, OK, Cancel

}
private Gui.GuiManager m_gui = null;
private Graphics m_graphics;

private Framework m_framework;
private DeviceSettings m_newSettings = null;
private ArrayList m_adapterList;
private bool m_doneSetting;

private bool m_hasNewSettings;
private const float Width = 360f;
private const float Height = 400f;

///

Creates a new VideoOptionsDialog.
/// Direct3D Device
/// Current DeviceSettings

/// ArrayList of adapters
public DeviceOptionsDialog( Framework framework ) Toggle

{

m_framework = framework;
m_graphics = framework.Graphics;
m_newSettings = m_graphics.CurrentSettings;
m_adapterList = m_graphics.Adapters;

OnCreateDevice( m_graphics.Device );
OnResetDevice( m_graphics.Device );

}

///

Updates the Controls based on the desired settings
/// Desired settings

private void UpdateControlValues( DeviceSettings settings ) Toggle

{

// Clear everything
( m_gui[(int)ControlID.DisplayAdapter] as Gui.ComboBox ).Clear();
( m_gui[(int)ControlID.RenderDevice] as Gui.ComboBox ).Clear();

( m_gui[(int)ControlID.AdapterFormat] as Gui.ComboBox ).Clear();
( m_gui[(int)ControlID.FullscreenResolution] as Gui.ComboBox ).Clear();
( m_gui[(int)ControlID.RefreshRate] as Gui.ComboBox ).Clear();

( m_gui[(int)ControlID.BackBufferFormat] as Gui.ComboBox ).Clear();
( m_gui[(int)ControlID.DepthStencilFormat] as Gui.ComboBox ).Clear();
( m_gui[(int)ControlID.MultiSampleType] as Gui.ComboBox ).Clear();

( m_gui[(int)ControlID.MultiSampleQuality] as Gui.ComboBox ).Clear();
( m_gui[(int)ControlID.VertexProcessing] as Gui.ComboBox ).Clear();
( m_gui[(int)ControlID.PresentInterval] as Gui.ComboBox ).Clear();

// Fill it all back up based on the passed in settings
foreach ( AdapterEnum a in m_adapterList )
{

// Display Adapters
m_gui.AddListableItem( (int)ControlID.DisplayAdapter, a.Description, a.AdapterOrdinal );

if ( settings.AdapterOrdinal == a.AdapterOrdinal )
{

( m_gui[(int)ControlID.DisplayAdapter] as Gui.ComboBox ).SelectItem( a.Description );

}

// Everything below depends on AdapterOrdinal

if ( a.AdapterOrdinal != settings.AdapterOrdinal )
{

continue;

}
foreach ( DisplayMode d in a.DisplayModeList )

{

// Refresh Rate
if ( !( m_gui[(int)ControlID.RefreshRate] as Gui.ComboBox ).ContainsItem( d.RefreshRate.ToString() + ” Hz” ) )
{

// Available refresh rates depend on resolution

if ( ( d.Width == settings.PresentParameters.BackBufferWidth ) &&
( d.Height == settings.PresentParameters.BackBufferHeight ) &&
( !settings.PresentParameters.IsWindowed ) )
{

m_gui.AddListableItem( (int)ControlID.RefreshRate, d.RefreshRate.ToString() + ” Hz”, d.RefreshRate );

if ( ( ( d.RefreshRate == settings.PresentParameters.FullScreenRefreshRateInHz ) &&
( !settings.PresentParameters.IsWindowed ) && settings.PresentParameters.FullScreenRefreshRateInHz != 0 ) ||
( m_gui[(int)ControlID.RefreshRate].Data as ArrayList).Count == 0 )

{

( m_gui[(int)ControlID.RefreshRate] as Gui.ComboBox ).SelectItem( d.RefreshRate.ToString() + ” Hz” );

}

}
else if ( settings.PresentParameters.IsWindowed || settings.PresentParameters.FullScreenRefreshRateInHz == 0 )

{

// Select current refresh rate if in windowed mode
DisplayMode displayMode = Manager.Adapters[(int)a.AdapterOrdinal].CurrentDisplayMode;
if ( !( m_gui[(int)ControlID.RefreshRate] as Gui.ComboBox ).ContainsItem( displayMode.RefreshRate.ToString() + ” Hz” ) )

{

m_gui.AddListableItem( (int)ControlID.RefreshRate, displayMode.RefreshRate.ToString() + ” Hz”, d.RefreshRate );

}
( m_gui[(int)ControlID.RefreshRate] as Gui.ComboBox ).SelectItem( displayMode.RefreshRate.ToString() + ” Hz” );

}

}

// Fullscreen Resolution
if ( settings.PresentParameters.IsWindowed )
{

// Select current resolution if in windowed mode
DisplayMode displayMode = Manager.Adapters[(int)a.AdapterOrdinal].CurrentDisplayMode;

string text = string.Format( “{0} by {1}”, displayMode.Width, displayMode.Height );
m_gui.AddListableItem( (int)ControlID.FullscreenResolution, text, new Size( displayMode.Width, displayMode.Height ) );

( m_gui[(int)ControlID.FullscreenResolution] as Gui.ComboBox ).SelectItem( text );

}
else
{

if ( d.Format != settings.AdapterFormat )

{

continue;

}
string text = string.Format( “{0} by {1}”, d.Width, d.Height );

if ( !( m_gui[(int)ControlID.FullscreenResolution] as Gui.ComboBox ).ContainsItem( text ) )
{

m_gui.AddListableItem( (int)ControlID.FullscreenResolution, text, new Size( d.Width, d.Height ) );

if ( ( d.Width == settings.PresentParameters.BackBufferWidth ) &&
( d.Height == settings.PresentParameters.BackBufferHeight ) )
{

( m_gui[(int)ControlID.FullscreenResolution] as Gui.ComboBox ).SelectItem( text );

}

}

}

}

foreach ( DeviceEnum d in a.DeviceEnumList )
{

// Render Devices

m_gui.AddListableItem( (int)ControlID.RenderDevice, d.DeviceType.ToString(), d.DeviceType );
if ( settings.DeviceType == d.DeviceType )
{

( m_gui[(int)ControlID.RenderDevice] as Gui.ComboBox ).SelectItem( d.DeviceType.ToString() );

}

// Everything below depends on DeviceType
if ( d.DeviceType != settings.DeviceType )
{

continue;

}
foreach ( DeviceSettingsEnum s in d.SettingsList )

{

// Everything below depends on windowed
if ( s.IsWindowed != settings.PresentParameters.IsWindowed )
{

continue;

}
// Adapter Formats
if ( !( m_gui[(int)ControlID.AdapterFormat] as Gui.ComboBox ).ContainsItem( s.AdapterFormat.ToString() ) )

{

m_gui.AddListableItem( (int)ControlID.AdapterFormat, s.AdapterFormat.ToString(), s.AdapterFormat );
if ( s.AdapterFormat == settings.AdapterFormat )
{

( m_gui[(int)ControlID.AdapterFormat] as Gui.ComboBox ).SelectItem( s.AdapterFormat.ToString() );

}

}

// Everything below depends on AdapterFormat
if ( s.AdapterFormat != settings.AdapterFormat )
{

continue;

}

// BackBuffer Formats
if ( !( m_gui[(int)ControlID.BackBufferFormat] as Gui.ComboBox ).ContainsItem( s.BackBufferFormat.ToString() ) )
{

( m_gui[(int)ControlID.BackBufferFormat] as Gui.ComboBox ).AddItem( s.BackBufferFormat.ToString(), s.BackBufferFormat );

if ( s.BackBufferFormat == settings.PresentParameters.BackBufferFormat )
{

( m_gui[(int)ControlID.BackBufferFormat] as Gui.ComboBox ).SelectItem( s.BackBufferFormat.ToString() );

}

}

// Depth/Stencil Formats
foreach ( DepthFormat f in s.DepthStencilFormatList )
{

if ( !( m_gui[(int)ControlID.DepthStencilFormat] as Gui.ComboBox ).ContainsItem( f.ToString() ) )

{

( m_gui[(int)ControlID.DepthStencilFormat] as Gui.ComboBox ).AddItem( f.ToString(), f );
if ( f == settings.PresentParameters.AutoDepthStencilFormat )
{

( m_gui[(int)ControlID.DepthStencilFormat] as Gui.ComboBox ).SelectItem( f.ToString() );

}

}

}

// Everything below depends on BackBufferFormat
if ( s.BackBufferFormat != settings.PresentParameters.BackBufferFormat )
{

continue;

}

// Multisample Types
foreach ( MultiSampleType t in s.MultiSampleTypeList )
{

if ( !( m_gui[(int)ControlID.MultiSampleType] as Gui.ComboBox ).ContainsItem( t.ToString() ) )

{

m_gui.AddListableItem( (int)ControlID.MultiSampleType, t.ToString(), t );
if ( t == settings.PresentParameters.MultiSampleType )
{

( m_gui[(int)ControlID.MultiSampleType] as Gui.ComboBox ).SelectItem( t.ToString() );

}

}

}

// Multisample Qualities
int maxQuality = 0;
MultiSampleType currentType = settings.PresentParameters.MultiSampleType;

for ( int i = 0; i < s.MultiSampleTypeList.Count; i++ )
{

MultiSampleType msType = (MultiSampleType)s.MultiSampleTypeList[i];
if ( msType == currentType )

{

maxQuality = (int)s.MultiSampleQualityList[i];

}

}
for ( int i = 0; i < maxQuality; i++ )

{

if ( !( m_gui[(int)ControlID.MultiSampleQuality] as Gui.ComboBox ).ContainsItem( i.ToString() ) )
{

m_gui.AddListableItem( (int)ControlID.MultiSampleQuality, i.ToString(), i );
if ( i == settings.PresentParameters.MultiSampleQuality )

{

( m_gui[(int)ControlID.MultiSampleQuality] as Gui.ComboBox ).SelectItem( i.ToString() );

}

}

}

// VertexProcessing

foreach ( CreateFlags f in s.VertexProcessingTypeList )
{

string text = f.ToString();
if ( !( m_gui[(int)ControlID.VertexProcessing] as Gui.ComboBox ).ContainsItem( text ) )

{

if ( f == ( CreateFlags.PureDevice | CreateFlags.HardwareVertexProcessing ) )
{

text = “PureDevice”;

}
m_gui.AddListableItem( (int)ControlID.VertexProcessing, text, f );
if ( f == settings.BehaviorFlags )

{

( m_gui[(int)ControlID.VertexProcessing] as Gui.ComboBox ).SelectItem( text );

}

}

}

// Present interval

foreach ( PresentInterval p in s.PresentIntervalList )
{

if ( !( m_gui[(int)ControlID.PresentInterval] as Gui.ComboBox ).ContainsItem( p.ToString() ) )

{

m_gui.AddListableItem( (int)ControlID.PresentInterval, p.ToString(), p );
if ( p == settings.PresentParameters.PresentationInterval )
{

( m_gui[(int)ControlID.PresentInterval] as Gui.ComboBox ).SelectItem( p.ToString() );

}

}

}

}

}

}

// Window/Fullscreen mode
( m_gui[(int)ControlID.RadioWindow] as Gui.RadioButton ).Checked = settings.PresentParameters.IsWindowed;

( m_gui[(int)ControlID.RadioFullscreen] as Gui.RadioButton ).Checked = !settings.PresentParameters.IsWindowed;

m_gui.DirtyBuffer = true;

}

///

Call when the device is created
/// D3D Device
public override void OnCreateDevice( Device device ) Toggle

{

float x = ( (float)m_graphics.CurrentSettings.PresentParameters.BackBufferWidth / 2f ) – ( Width / 2f );

float y = ( (float)m_graphics.CurrentSettings.PresentParameters.BackBufferHeight / 2f ) – ( Height / 2f );
m_gui = new Gui.GuiManager( “CUnit.xml”, new Gui.GuiManager.ControlDelegate( OnControl ) );

m_gui.CreatePanel( (int)ControlID.Panel, new PointF( x, y ), new SizeF( Width, Height ) );
( m_gui[(int)ControlID.Panel] as Gui.Panel ).Locked = true;

int panel = (int)ControlID.Panel;
float dropSize = 155f;
float fontSize = 14f;

x = 140f;
y = 15f;
// Add Controls
m_gui.CreateComboBox( (int)ControlID.DisplayAdapter, panel, new PointF( x, y ), new SizeF( 200.0f, 20.0f ), 80f, fontSize, new ColorValue( 0.0f, 0.0f, 0.0f ) );

m_gui.CreateLabel( (int)ControlID.DisplayAdapterText, panel, new PointF( 0f, y ), new SizeF( x – 5f, 20.0f ), “Display Adapter”, fontSize, new ColorValue( 0.0f, 0.0f, 0.0f ), BitmapFont.Align.Right );

m_gui.CreateComboBox( (int)ControlID.RenderDevice, panel, new PointF( x, y + 25f ), new SizeF( 200.0f, 20.0f ), 80f, fontSize, new ColorValue( 0.0f, 0.0f, 0.0f ) );

m_gui.CreateLabel( (int)ControlID.RenderDeviceText, panel, new PointF( 0f, y + 25f ), new SizeF( x – 5f, 20.0f ), “Render Device”, fontSize, new ColorValue( 0.0f, 0.0f, 0.0f ), BitmapFont.Align.Right );

m_gui.CreateRadioButton( (int)ControlID.RadioWindow, panel, 0, new PointF( x, y + 50f ), new SizeF( 20.0f, 20.0f ), “Windowed”, fontSize, new ColorValue( 0.0f, 0.0f, 0.0f ), CUnit.Gui.Control.TextAlign.Right, true );

m_gui.CreateRadioButton( (int)ControlID.RadioFullscreen, panel, 0, new PointF( 243f, y + 50f ), new SizeF( 20.0f, 20.0f ), “Fullscreen”, fontSize, new ColorValue( 0.0f, 0.0f, 0.0f ), CUnit.Gui.Control.TextAlign.Right, false );

m_gui.CreateComboBox( (int)ControlID.AdapterFormat, panel, new PointF( x, y + 75f ), new SizeF( 200.0f, 20.0f ), dropSize, fontSize, new ColorValue( 0.0f, 0.0f, 0.0f ) );

m_gui.CreateLabel( (int)ControlID.AdapterFormatText, panel, new PointF( 0f, y + 75f ), new SizeF( x – 5f, 20.0f ), “Adapter Format”, fontSize, new ColorValue( 0.0f, 0.0f, 0.0f ), BitmapFont.Align.Right );

m_gui.CreateComboBox( (int)ControlID.FullscreenResolution, panel, new PointF( x, y + 100f ), new SizeF( 200.0f, 20.0f ), dropSize, fontSize, new ColorValue( 0.0f, 0.0f, 0.0f ) );

m_gui.CreateLabel( (int)ControlID.FullscreenResolutionText, panel, new PointF( 0f, y + 100f ), new SizeF( x – 5f, 20.0f ), “Screen Resolution”, fontSize, new ColorValue( 0.0f, 0.0f, 0.0f ), BitmapFont.Align.Right );

m_gui.CreateComboBox( (int)ControlID.RefreshRate, panel, new PointF( x, y + 125f ), new SizeF( 200.0f, 20.0f ), dropSize, fontSize, new ColorValue( 0.0f, 0.0f, 0.0f ) );

m_gui.CreateLabel( (int)ControlID.RefreshRateText, panel, new PointF( 0f, y + 125f ), new SizeF( x – 5f, 20.0f ), “Refresh Rate”, fontSize, new ColorValue( 0.0f, 0.0f, 0.0f ), BitmapFont.Align.Right );

m_gui.CreateComboBox( (int)ControlID.BackBufferFormat, panel, new PointF( x, y + 150f ), new SizeF( 200.0f, 20.0f ), dropSize, fontSize, new ColorValue( 0.0f, 0.0f, 0.0f ) );

m_gui.CreateLabel( (int)ControlID.BackBufferFormatText, panel, new PointF( 0f, y + 150f ), new SizeF( x – 5f, 20.0f ), “Backbuffer Format”, fontSize, new ColorValue( 0.0f, 0.0f, 0.0f ), BitmapFont.Align.Right );

m_gui.CreateComboBox( (int)ControlID.DepthStencilFormat, panel, new PointF( x, y + 175f ), new SizeF( 200.0f, 20.0f ), dropSize, fontSize, new ColorValue( 0.0f, 0.0f, 0.0f ) );

m_gui.CreateLabel( (int)ControlID.DepthStencilFormatText, panel, new PointF( 0f, y + 175f ), new SizeF( x – 5f, 20.0f ), “Depth/Stencil Format”, fontSize, new ColorValue( 0.0f, 0.0f, 0.0f ), BitmapFont.Align.Right );

m_gui.CreateComboBox( (int)ControlID.MultiSampleType, panel, new PointF( x, y + 200f ), new SizeF( 200.0f, 20.0f ), dropSize, fontSize, new ColorValue( 0.0f, 0.0f, 0.0f ) );

m_gui.CreateLabel( (int)ControlID.MultiSampleTypeText, panel, new PointF( 0f, y + 200f ), new SizeF( x – 5f, 20.0f ), “Multisample Type”, fontSize, new ColorValue( 0.0f, 0.0f, 0.0f ), BitmapFont.Align.Right );

m_gui.CreateComboBox( (int)ControlID.MultiSampleQuality, panel, new PointF( x, y + 225f ), new SizeF( 200.0f, 20.0f ), dropSize, fontSize, new ColorValue( 0.0f, 0.0f, 0.0f ) );

m_gui.CreateLabel( (int)ControlID.MultiSampleQualityText, panel, new PointF( 0f, y + 225f ), new SizeF( x – 5f, 20.0f ), “Multisample Quality”, fontSize, new ColorValue( 0.0f, 0.0f, 0.0f ), BitmapFont.Align.Right );

m_gui.CreateComboBox( (int)ControlID.VertexProcessing, panel, new PointF( x, y + 250f ), new SizeF( 200.0f, 20.0f ), dropSize, fontSize, new ColorValue( 0.0f, 0.0f, 0.0f ) );

m_gui.CreateLabel( (int)ControlID.VertexProcessingText, panel, new PointF( 0f, y + 250f ), new SizeF( x – 5f, 20.0f ), “Vertex Processing”, fontSize, new ColorValue( 0.0f, 0.0f, 0.0f ), BitmapFont.Align.Right );

m_gui.CreateComboBox( (int)ControlID.PresentInterval, panel, new PointF( x, y + 275f ), new SizeF( 200.0f, 20.0f ), dropSize, fontSize, new ColorValue( 0.0f, 0.0f, 0.0f ) );

m_gui.CreateLabel( (int)ControlID.PresentIntervalText, panel, new PointF( 0f, y + 275f ), new SizeF( x – 5f, 20.0f ), “Present Interval”, fontSize, new ColorValue( 0.0f, 0.0f, 0.0f ), BitmapFont.Align.Right );

m_gui.CreateButton( (int)ControlID.OK, panel, new PointF( x, y + 300f ), new SizeF( 75f, 20f ), “OK”, fontSize, new ColorValue( 0.0f, 0.0f, 0.0f ) );

m_gui.CreateButton( (int)ControlID.Cancel, panel, new PointF( 275, y + 300f ), new SizeF( 75f, 20f ), “Cancel”, fontSize, new ColorValue( 0.0f, 0.0f, 0.0f ) );

if ( m_newSettings.PresentParameters.IsWindowed )
{

// Disable Controls only meant for fullscreen
m_gui[(int)ControlID.AdapterFormat].Disabled = true;
m_gui[(int)ControlID.FullscreenResolution].Disabled = true;

m_gui[(int)ControlID.RefreshRate].Disabled = true;

}
if ( m_gui != null )
{

m_gui.OnCreateDevice( device );

}
UpdateControlValues( m_newSettings );

}

///

Call when the device is reset
/// D3D device

public override void OnResetDevice( Device device ) Toggle

{

if ( m_gui != null )
{

// Center the Panel

m_gui.OnResetDevice( device );
float x = ( (float)m_graphics.CurrentSettings.PresentParameters.BackBufferWidth / 2f ) – ( Width / 2f );
float y = ( (float)m_graphics.CurrentSettings.PresentParameters.BackBufferHeight / 2f ) – ( Height / 2f );

m_gui.SetPosition( (int)ControlID.Panel, new PointF( x, y ) );

}

}

///

Call when the device is lost.

public override void OnLostDevice() Toggle

{

if ( m_gui != null )
{

m_gui.OnLostDevice();

}

}

///

Call when the device is destroyed.
public override void OnDestroyDevice() Toggle

{

if ( m_gui != null )

{

m_gui.OnDestroyDevice();
m_gui = null;

}

}

///

Update the current frame.

/// D3D Device
/// Time elapsed since last frame
public override void OnUpdateFrame( Device device, float elapsedTime ) Toggle

{

if ( m_hasNewSettings )

{

// Flag framework to change the device
m_framework.NewSettings = m_newSettings;

}

}

///

Renders the current frame.

/// D3D Device
/// Time elapsed since last frame
public override void OnRenderFrame( Device device, float elapsedTime ) Toggle

{

device.Clear( ClearFlags.Target | ClearFlags.ZBuffer, Color.Black, 1f, 0 );

device.BeginScene();
if ( m_gui != null )
{

m_gui.Render( device );

}
device.EndScene();
device.Present();

}

///

Keyboard handler.
/// List of pressed keys.

/// Character read from keyboard.
/// Keycode read from keyboard.
/// Time since last frame

public override void OnKeyboard( List pressedKeys, char pressedChar, int pressedKey, float elapsedTime ) Toggle

{

// Empty

}

///

Mouse handler.
/// Mouse position in client coordinates

/// X-axis delta.
/// Y-axis delta.
/// Wheel delta.

/// Mouse button state.
/// Time since last frame
public override void OnMouse( Point position, int xDelta, int yDelta, int zDelta, bool[] buttons, float elapsedTime ) Toggle

{

if ( m_gui != null )

{

m_gui.MouseHandler( position, buttons, zDelta );

}

}

///

Gui Control handler
/// Control ID

/// Control data
public override void OnControl( int controlID, object data ) Toggle

{

if ( m_gui[controlID] is Gui.ComboBox )

{

data = ( (ArrayList)data )[0];

}
switch ( controlID )
{

case (int)ControlID.DisplayAdapter:

m_newSettings.AdapterOrdinal = (uint)data;
UpdateControlValues( m_newSettings );
break;

case (int)ControlID.RenderDevice:

m_newSettings.DeviceType = (DeviceType)data;

if ( m_newSettings.DeviceType == DeviceType.Reference )
{

m_newSettings.PresentParameters.PresentationInterval = PresentInterval.Default;

}
UpdateControlValues( m_newSettings );
break;

case (int)ControlID.RadioFullscreen:

m_gui[(int)ControlID.RefreshRate].Disabled = false;
m_gui[(int)ControlID.FullscreenResolution].Disabled = false;
m_gui[(int)ControlID.AdapterFormat].Disabled = false;

m_newSettings.PresentParameters.IsWindowed = false;
m_newSettings.PresentParameters.BackBufferFormat = m_newSettings.AdapterFormat;
// Reset displaymode
DisplayMode mode = Manager.Adapters[(int)m_newSettings.AdapterOrdinal].CurrentDisplayMode;
m_newSettings.PresentParameters.BackBufferWidth = mode.Width;
m_newSettings.PresentParameters.BackBufferHeight = mode.Height;
m_newSettings.PresentParameters.FullScreenRefreshRateInHz = mode.RefreshRate;

UpdateControlValues( m_newSettings );
break;

case (int)ControlID.RadioWindow:

m_gui[(int)ControlID.RefreshRate].Disabled = true;

m_gui[(int)ControlID.FullscreenResolution].Disabled = true;
m_gui[(int)ControlID.AdapterFormat].Disabled = true;
m_newSettings.PresentParameters.IsWindowed = true;
m_newSettings.PresentParameters.BackBufferWidth = 0;

m_newSettings.PresentParameters.BackBufferHeight = 0;
m_newSettings.PresentParameters.FullScreenRefreshRateInHz = 0;
UpdateControlValues( m_newSettings );
break;

case (int)ControlID.AdapterFormat:

m_newSettings.AdapterFormat = (Format)data;
m_newSettings.PresentParameters.BackBufferFormat = (Format)data;
UpdateControlValues( m_newSettings );
break;

case (int)ControlID.FullscreenResolution:

m_newSettings.PresentParameters.BackBufferWidth = ( (Size)data ).Width;

m_newSettings.PresentParameters.BackBufferHeight = ( (Size)data ).Height;
UpdateControlValues( m_newSettings );
break;

case (int)ControlID.RefreshRate:

m_newSettings.PresentParameters.FullScreenRefreshRateInHz = (int)data;

UpdateControlValues( m_newSettings );
break;

case (int)ControlID.BackBufferFormat:

m_newSettings.PresentParameters.BackBufferFormat = (Format)data;
UpdateControlValues( m_newSettings );
break;

case (int)ControlID.DepthStencilFormat:

m_newSettings.PresentParameters.AutoDepthStencilFormat = (DepthFormat)data;
UpdateControlValues( m_newSettings );
break;

case (int)ControlID.MultiSampleType:

m_newSettings.PresentParameters.MultiSampleType = (MultiSampleType)data;
if ( m_newSettings.PresentParameters.MultiSampleType != MultiSampleType.NonMaskable )
{

m_newSettings.PresentParameters.MultiSampleQuality = 0;

}
UpdateControlValues( m_newSettings );
break;

case (int)ControlID.MultiSampleQuality:

m_newSettings.PresentParameters.MultiSampleQuality = (int)data;
UpdateControlValues( m_newSettings );
break;

case (int)ControlID.VertexProcessing:

m_newSettings.BehaviorFlags = (CreateFlags)data;
UpdateControlValues( m_newSettings );
break;

case (int)ControlID.PresentInterval:

m_newSettings.PresentParameters.PresentationInterval = (PresentInterval)data;
UpdateControlValues( m_newSettings );

break;

case (int)ControlID.OK:

m_doneSetting = true;
m_hasNewSettings = true;

break;

case (int)ControlID.Cancel:

m_doneSetting = true;
break;

}

}

///

Tells StateManager when to pop this state off the stack.
public override bool DoneWithState Toggle

{

get { return m_doneSetting; }

}

}

}

The DeviceOptionsDialog class inherits from GameState so we can add it to the Framework’s state stack. When the user toggle the dialog, it is added to the stack and when the user hits the OK or Cancel button, it is removed from the stack.

DeviceOptionsDialog manipulates a DeviceSettings object through a series of C-Unit GUI ComboBoxes. Again, since we haven’t learned about the GUI yet, ignore all that code and focus on the UpdateControlValues method.

The main workhorse method of DeviceOptionsDialog is the UpdateControlValues method. The UpdateControlValues method will take in a DeviceSettings instance, and set all the values of the ComboBoxes based on the values of the DeviceSettings parameter. This includes leaving out incompatible values and only displaying values that are valid with the currently selected values. For example, some refresh rates are only available with certain screen resolutions. So the only selectable refresh rates will be those that are valid with the currently selected resolution.

Whenever a new value is selected, the OnControl method is called where the new value is stored in the m_newSettings instance. After we store the new value, the Controls are all updated to account for the new value by calling the UpdateControlValues method.

Notice that when some values are changed, other values are selected automatically. For example, when we toggle the Fullscreen Mode Radio button (in OnControl: case (int)ControlID.RadioFullscreen), the backbuffer format is automatically changed to the same format as the adapter. We do this because values currently selected in some fields may not be compatible with new values that we select, so we need to adjust the values accordingly. Once a new set of values is created, it’s just a matter of handing them off to the Framework so it can update_ the Device. DeviceOptionsDialog tells the Framework about the new settings in OnUpdateFrame.

We know know enough about the C-Unit Framework that we can start rendering interesting geometry…like triangles…