CU_MDX_Enumeration.zip (63.1 KB, 1,409 hits)
CUnitFramework.zip (101.1 KB, 12,582 hits)
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.
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:
public class AdapterEnum
{
public AdapterDetails AdapterInformation;
public ArrayList DisplayModeList = new ArrayList();
public ArrayList DeviceEnumList = new ArrayList();
public string Description;
}
/// <summary>Represents the capabilities and description of a single device.</summary>
public class DeviceEnum
{
public DeviceType DeviceType;
public Caps Caps;
public ArrayList SettingsList = new ArrayList();
}
/// <summary>Represents the various settings a device can have.</summary>
public class DeviceSettingsEnum
{
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;
}
/// <summary>Represents a Device with single settings configuration.</summary>
public class DeviceSettings : ICloneable
{
public Format AdapterFormat;
public CreateFlags BehaviorFlags;
public Caps Caps;
public DeviceType DeviceType;
public PresentParameters PresentParameters;
/// <summary>Clones the settings</summary>
/// <returns>The cloned settings</returns>
public object Clone()
{
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.
{
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;
/// <summary>Initializes Direct3D.</summary>
/// <param name=”windowed”>True for windowed mode. False for fullscreen mode.</param>
/// <param name=”control”>Render window.</param>
/// <param name=”desiredWidth”>Desired backbuffer width</param>
/// <param name=”desiredHeight”>Desired backbuffer height</param>
public void Initialize( bool windowed, Control control, int desiredWidth, int desiredHeight ) 
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 );
}
/// <summary>Changes the device with new settings.</summary>
public void ChangeDevice( DeviceSettings newSettings ) 
{
m_device = null;
}
try
{
}
catch ( DirectXException )
{
}
}
/// <summary>ReBuilds the PresentParameters class inpreparation for device reset.</summary>
private void ResetPresentParameters() 
{
m_currentSettings.PresentParameters.BackBufferHeight = 0;
}
}
/// <summary>Reset the device</summary>
public void Reset() 
{
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.
public static readonly Format[] AdapterFormats = new Format[]
{
};
public static readonly Format[] BackBufferFormats = new Format[]
{
Format.A8R3G3B2, Format.A4R4G4B4, Format.A1R5G5B5, Format.X4R4G4B4,
Format.X1R5G5B5, Format.R5G6B5, Format.R3G3B2
};
public static readonly DeviceType[] DeviceTypes = new DeviceType[]
{
};
public static readonly MultiSampleType[] MultiSampleTypes = new MultiSampleType[]
{
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[]
{
};
public static readonly PresentInterval[] PresentIntervals = new PresentInterval[]
{
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.
{
/// <summary>Enumerates through all the Adapters in the system.</summary>
private void EnumerateAdapters() 
{
// 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 );
}
}
/// <summary>Enumerates through all supported DisplayModes for an Adapter.</summary>
/// <param name=”a”>Adapter to enumerate.</param>
/// <param name=”currentAdapter”>AdapterEnum that stores the list of DisplayModes.</param>
/// <returns>A List of Adapter Formats used in the supported DisplayModes.</returns>
private ArrayList EnumerateDisplayModes( AdapterDetails a, AdapterEnum currentAdapter ) 
for ( int i = 0; i < AdapterFormats.Length; i++ )
{
{
// Add Adaptor Format used with this DisplayMode
if ( !adapterFormatList.Contains( d.Format ) )
{
}
}
}
DisplayModeSorter sorter = new DisplayModeSorter();
currentAdapter.DisplayModeList.Sort( sorter );
return adapterFormatList;
}
/// <summary>Enumerates through all the Devices an Adapter can make.</summary>
/// <param name=”currentAdapter”></param>
/// <param name=”adapterFormatList”>List of Adapter Formats supported by the Adapter</param>
private void EnumerateDevices( AdapterEnum currentAdapter, ArrayList adapterFormatList ) 
foreach( DeviceType t in DeviceTypes )
{
// Store the DeviceType and Capabilities
currentDevice.DeviceType = t;
try
{
}
catch( DirectXException )
{
}
// 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)
{
}
}
}
/// <summary>Enumerates device combinations for a particular device.</summary>
/// <param name=”currentDevice”>Device to enumerate.</param>
/// <param name=”currentAdapter”></param>
/// <param name=”adapterFormatList”>List of supported Adapter Formats</param>
private void EnumerateDeviceSettings( DeviceEnum currentDevice, AdapterEnum currentAdapter, ArrayList adapterFormatList ) 
foreach ( Format adapterFormat in AdapterFormats )
{
foreach( Format backbufferFormat in BackBufferFormats )
{
for ( int i = 0; i < 2; i++ )
{
// Skip if this is not a supported Device type
if ( !Manager.CheckDeviceType( (int)currentAdapter.AdapterOrdinal, currentDevice.DeviceType,
adapterFormat, backbufferFormat, windowed ) )
{
}
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 );
}
}
}
}
/// <summary>Enumerates through all the Depth Stencil Formats compatible with the Device.</summary>
/// <param name=”deviceSettings”>DeviceEnum with the Device info.</param>
private void EnumerateDepthStencilFormats( DeviceSettingsEnum deviceSettings ) 
foreach ( DepthFormat depthFormat in DepthFormats )
{
if ( Manager.CheckDeviceFormat( (int)deviceSettings.AdapterOrdinal, deviceSettings.DeviceType,
deviceSettings.AdapterFormat, Usage.DepthStencil, ResourceType.Surface, depthFormat ) )
{
if ( Manager.CheckDepthStencilMatch( (int)deviceSettings.AdapterOrdinal, deviceSettings.DeviceType,
deviceSettings.AdapterFormat, deviceSettings.BackBufferFormat, depthFormat ) )
{
deviceSettings.DepthStencilFormatList.Add( depthFormat );
}
}
}
}
/// <summary>Enumerates through all the MultiSampleTypes that are compatible with the Device.</summary>
/// <param name=”deviceSettings”>DeviceEnum with the Device info.</param>
private void EnumerateMultiSampleTypes( DeviceSettingsEnum deviceSettings ) 
foreach ( MultiSampleType t in MultiSampleTypes )
{
// See if it’s supported
if ( Manager.CheckDeviceMultiSampleType( (int)deviceSettings.AdapterOrdinal, deviceSettings.DeviceType,
deviceSettings.BackBufferFormat, deviceSettings.IsWindowed, t, out qualityLevels ) )
{
deviceSettings.MultiSampleQualityList.Add( qualityLevels );
}
}
}
/// <summary>Enumerates through the VertexProcessing Types that are compatible with the Device.</summary>
/// <param name=”deviceSettings”>DeviceEnum with the Device info.</param>
private void EnumerateVertexProcessingTypes( DeviceSettingsEnum deviceSettings ) 
// Check for hardware T&L
if ( deviceSettings.DeviceInformation.Capabilities.DeviceCaps.SupportsHardwareTransformAndLight )
{
if ( deviceSettings.DeviceInformation.Capabilities.DeviceCaps.SupportsPureDevice )
{
}
deviceSettings.VertexProcessingTypeList.Add( CreateFlags.HardwareVertexProcessing );
deviceSettings.VertexProcessingTypeList.Add( CreateFlags.MixedVertexProcessing );
}
// Always supports software
deviceSettings.VertexProcessingTypeList.Add( CreateFlags.SoftwareVertexProcessing );
}
/// <summary>Enumerates through the PresentIntervals that are compatible with the Device.</summary>
/// <param name=”deviceSettings”>DeviceEnum with the Device info.</param>
private void EnumeratePresentIntervals( DeviceSettingsEnum deviceSettings ) 
{
if ( deviceSettings.IsWindowed )
{
(p == PresentInterval.Four) )
{
}
}
if ( p == PresentInterval.Default )
{
deviceSettings.PresentIntervalList.Add( p );
}
// Check if the PresentInterval is supported
if ( (deviceSettings.DeviceInformation.Capabilities.PresentInterval & p) != 0 )
{
}
}
}
// Clip…
}
The enumeration process begins in EnumerateAdapters, and works its way to the bottom of the tree, filling up the ArrayLists along the way.

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
/// </summary>
public class Graphics
{
/// <summary>Finds the best windowed Device settings supported by the system.</summary>
/// <returns>A DeviceSettings class full with the best supported windowed settings.</returns>
private DeviceSettings FindBestWindowedSettings() 
bool foundBest = false;
// Loop through each adapter
foreach ( AdapterEnum a in m_adapters )
{
foreach ( DeviceEnum d in a.DeviceEnumList )
{
foreach ( DeviceSettingsEnum s in d.SettingsList )
{
if ( !s.Windowed || (s.AdapterFormat != m_displayMode.Format) )
{
}
// 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 ( (s.DeviceType == DeviceType.Hardware) && (s.AdapterFormat == s.BackBufferFormat) )
{
}
}
}
}
}
if ( bestSettings == null )
{
}
// 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;
}
/// <summary>Finds the best fullscreen Device settings supported by the system.</summary>
/// <returns>A DeviceSettings class full with the best supported fullscreen settings.</returns>
private DeviceSettings FindBestFullscreenSettings() 
bool foundBest = false;
// Loop through each adapter
foreach ( AdapterEnum a in m_adapters )
{
foreach ( DeviceEnum d in a.DeviceEnumList )
{
foreach ( DeviceSettingsEnum s in d.SettingsList )
{
if ( s.Windowed )
{
}
// 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 ( (s.DeviceType == DeviceType.Hardware) &&
(s.AdapterFormat == m_displayMode.Format) &&
(s.BackBufferFormat == s.AdapterFormat) )
{
}
}
}
}
}
if ( bestSettings == null )
{
}
// 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.
{
public class DeviceOptionsDialog : GameState
{
{
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;
/// <summary>Creates a new VideoOptionsDialog.</summary>
/// <param name=”device”>Direct3D Device</param>
/// <param name=”settings”>Current DeviceSettings</param>
/// <param name=”adapterList”>ArrayList of adapters</param>
public DeviceOptionsDialog( Framework framework ) 
m_graphics = framework.Graphics;
m_newSettings = m_graphics.CurrentSettings;
m_adapterList = m_graphics.Adapters;
OnCreateDevice( m_graphics.Device );
OnResetDevice( m_graphics.Device );
}
/// <summary>Updates the Controls based on the desired settings</summary>
/// <param name=”settings”>Desired settings</param>
private void UpdateControlValues( DeviceSettings settings ) 
( 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 )
{
m_gui.AddListableItem( (int)ControlID.DisplayAdapter, a.Description, a.AdapterOrdinal );
if ( settings.AdapterOrdinal == a.AdapterOrdinal )
{
}
// Everything below depends on AdapterOrdinal
if ( a.AdapterOrdinal != settings.AdapterOrdinal )
{
}
foreach ( DisplayMode d in a.DisplayModeList )
{
if ( !( m_gui[(int)ControlID.RefreshRate] as Gui.ComboBox ).ContainsItem( d.RefreshRate.ToString() + ” Hz” ) )
{
if ( ( d.Width == settings.PresentParameters.BackBufferWidth ) &&
( d.Height == settings.PresentParameters.BackBufferHeight ) &&
( !settings.PresentParameters.IsWindowed ) )
{
if ( ( ( d.RefreshRate == settings.PresentParameters.FullScreenRefreshRateInHz ) &&
( !settings.PresentParameters.IsWindowed ) && settings.PresentParameters.FullScreenRefreshRateInHz != 0 ) ||
( m_gui[(int)ControlID.RefreshRate].Data as ArrayList).Count == 0 )
{
}
}
else if ( settings.PresentParameters.IsWindowed || settings.PresentParameters.FullScreenRefreshRateInHz == 0 )
{
DisplayMode displayMode = Manager.Adapters[(int)a.AdapterOrdinal].CurrentDisplayMode;
if ( !( m_gui[(int)ControlID.RefreshRate] as Gui.ComboBox ).ContainsItem( displayMode.RefreshRate.ToString() + ” Hz” ) )
{
}
( m_gui[(int)ControlID.RefreshRate] as Gui.ComboBox ).SelectItem( displayMode.RefreshRate.ToString() + ” Hz” );
}
}
// Fullscreen Resolution
if ( settings.PresentParameters.IsWindowed )
{
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
{
{
}
string text = string.Format( “{0} by {1}”, d.Width, d.Height );
if ( !( m_gui[(int)ControlID.FullscreenResolution] as Gui.ComboBox ).ContainsItem( text ) )
{
if ( ( d.Width == settings.PresentParameters.BackBufferWidth ) &&
( d.Height == settings.PresentParameters.BackBufferHeight ) )
{
}
}
}
}
foreach ( DeviceEnum d in a.DeviceEnumList )
{
m_gui.AddListableItem( (int)ControlID.RenderDevice, d.DeviceType.ToString(), d.DeviceType );
if ( settings.DeviceType == d.DeviceType )
{
}
// Everything below depends on DeviceType
if ( d.DeviceType != settings.DeviceType )
{
}
foreach ( DeviceSettingsEnum s in d.SettingsList )
{
if ( s.IsWindowed != settings.PresentParameters.IsWindowed )
{
}
// Adapter Formats
if ( !( m_gui[(int)ControlID.AdapterFormat] as Gui.ComboBox ).ContainsItem( s.AdapterFormat.ToString() ) )
{
if ( s.AdapterFormat == settings.AdapterFormat )
{
}
}
// Everything below depends on AdapterFormat
if ( s.AdapterFormat != settings.AdapterFormat )
{
}
// BackBuffer Formats
if ( !( m_gui[(int)ControlID.BackBufferFormat] as Gui.ComboBox ).ContainsItem( s.BackBufferFormat.ToString() ) )
{
if ( s.BackBufferFormat == settings.PresentParameters.BackBufferFormat )
{
}
}
// Depth/Stencil Formats
foreach ( DepthFormat f in s.DepthStencilFormatList )
{
{
if ( f == settings.PresentParameters.AutoDepthStencilFormat )
{
}
}
}
// Everything below depends on BackBufferFormat
if ( s.BackBufferFormat != settings.PresentParameters.BackBufferFormat )
{
}
// Multisample Types
foreach ( MultiSampleType t in s.MultiSampleTypeList )
{
{
if ( t == settings.PresentParameters.MultiSampleType )
{
}
}
}
// Multisample Qualities
int maxQuality = 0;
MultiSampleType currentType = settings.PresentParameters.MultiSampleType;
for ( int i = 0; i < s.MultiSampleTypeList.Count; i++ )
{
if ( msType == currentType )
{
}
}
for ( int i = 0; i < maxQuality; i++ )
{
{
if ( i == settings.PresentParameters.MultiSampleQuality )
{
}
}
}
// VertexProcessing
foreach ( CreateFlags f in s.VertexProcessingTypeList )
{
if ( !( m_gui[(int)ControlID.VertexProcessing] as Gui.ComboBox ).ContainsItem( text ) )
{
{
}
m_gui.AddListableItem( (int)ControlID.VertexProcessing, text, f );
if ( f == settings.BehaviorFlags )
{
}
}
}
// Present interval
foreach ( PresentInterval p in s.PresentIntervalList )
{
{
if ( p == settings.PresentParameters.PresentationInterval )
{
}
}
}
}
}
}
// 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;
}
/// <summary>Call when the device is created</summary>
/// <param name=”device”>D3D Device</param>
public override void OnCreateDevice( Device device ) 
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 )
{
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 )
{
}
UpdateControlValues( m_newSettings );
}
/// <summary>Call when the device is reset</summary>
/// <param name=”device”>D3D device</param>
public override void OnResetDevice( Device device ) 
{
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 ) );
}
}
/// <summary>Call when the device is lost.</summary>
public override void OnLostDevice() 
{
}
}
/// <summary>Call when the device is destroyed.</summary>
public override void OnDestroyDevice() 
{
m_gui = null;
}
}
/// <summary>Update the current frame.</summary>
/// <param name=”device”>D3D Device</param>
/// <param name=”elapsedTime”>Time elapsed since last frame</param>
public override void OnUpdateFrame( Device device, float elapsedTime ) 
{
m_framework.NewSettings = m_newSettings;
}
}
/// <summary>Renders the current frame.</summary>
/// <param name=”device”>D3D Device</param>
/// <param name=”elapsedTime”>Time elapsed since last frame</param>
public override void OnRenderFrame( Device device, float elapsedTime ) 
device.BeginScene();
if ( m_gui != null )
{
}
device.EndScene();
device.Present();
}
/// <summary>Keyboard handler.</summary>
/// <param name=”pressedKeys”>List of pressed keys.</param>
/// <param name=”pressedChar”>Character read from keyboard.</param>
/// <param name=”pressedKey”>Keycode read from keyboard.</param>
/// <param name=”elapsedTime”>Time since last frame</param>
public override void OnKeyboard( List<System.Windows.Forms.Keys> pressedKeys, char pressedChar, int pressedKey, float elapsedTime ) 
}
/// <summary>Mouse handler.</summary>
/// <param name=”position”>Mouse position in client coordinates</param>
/// <param name=”xDelta”>X-axis delta.</param>
/// <param name=”yDelta”>Y-axis delta.</param>
/// <param name=”zDelta”>Wheel delta.</param>
/// <param name=”buttons”>Mouse button state.</param>
/// <param name=”elapsedTime”>Time since last frame</param>
public override void OnMouse( Point position, int xDelta, int yDelta, int zDelta, bool[] buttons, float elapsedTime ) 
{
}
}
/// <summary>Gui Control handler</summary>
/// <param name=”controlID”>Control ID</param>
/// <param name=”data”>Control data</param>
public override void OnControl( int controlID, object data ) 
{
}
switch ( controlID )
{
m_newSettings.AdapterOrdinal = (uint)data;
UpdateControlValues( m_newSettings );
break;
case (int)ControlID.RenderDevice:
if ( m_newSettings.DeviceType == DeviceType.Reference )
{
}
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.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.BackBufferHeight = ( (Size)data ).Height;
UpdateControlValues( m_newSettings );
break;
case (int)ControlID.RefreshRate:
UpdateControlValues( m_newSettings );
break;
case (int)ControlID.BackBufferFormat:
UpdateControlValues( m_newSettings );
break;
case (int)ControlID.DepthStencilFormat:
UpdateControlValues( m_newSettings );
break;
case (int)ControlID.MultiSampleType:
m_newSettings.PresentParameters.MultiSampleType = (MultiSampleType)data;
if ( m_newSettings.PresentParameters.MultiSampleType != MultiSampleType.NonMaskable )
{
}
UpdateControlValues( m_newSettings );
break;
case (int)ControlID.MultiSampleQuality:
UpdateControlValues( m_newSettings );
break;
case (int)ControlID.VertexProcessing:
m_newSettings.BehaviorFlags = (CreateFlags)data;
UpdateControlValues( m_newSettings );
break;
case (int)ControlID.PresentInterval:
UpdateControlValues( m_newSettings );
break;
case (int)ControlID.OK:
m_hasNewSettings = true;
break;
case (int)ControlID.Cancel:
break;
}
}
/// <summary>Tells StateManager when to pop this state off the stack.</summary>
public override bool DoneWithState 
}
}
}
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…