- Main Page
- Packages
- Classes
- Files

- File List
- File Members

# D:/guillaume/guillara/3D/DXGfx/Backup/DXCommon/dxmut.cs

Go to the documentation of this file.

    00001 //--------------------------------------------------------------------------------------
    00002 // File: DXMUT.cs
    00003 //
    00004 // DirectX SDK Managed Direct3D sample framework
    00005 //
    00006 // Copyright (c) Microsoft Corporation. All rights reserved.
    00007 //--------------------------------------------------------------------------------------
    00008 using System;
    00009 using System.Collections;
    00010 using Microsoft.DirectX;
    00011 using Microsoft.DirectX.Direct3D;
    00012
    00013 namespace Microsoft.Samples.DirectX.UtilityToolkit
    00014 {
    00018     public sealed class Framework : IDisposable
    00019     {
    00020
    00021         #region Class Data
    00022         // Constants for command line arguments
    00023         private const string CmdAdapter = "adapter";
    00024         private const string CmdWindowed = "windowed";
    00025         private const string CmdFullscreen = "fullscreen";
    00026         private const string CmdForceHardware = "forcehal";
    00027         private const string CmdForceRef = "forceref";
    00028         private const string CmdPureHwVp = "forcepurehwvp";
    00029         private const string CmdForceHwVp = "forcehwvp";
    00030         private const string CmdForceSwVp = "forceswvp";
    00031         private const string CmdWidth = "width";
    00032         private const string CmdHeight = "height";
    00033         private const string CmdStartx = "startx";
    00034         private const string CmdStarty = "starty";
    00035         private const string CmdConstantFrame = "constantframetime";
    00036         private const string CmdQuitAfterFrame = "quitafterframe";
    00037         private const string CmdNoErrorBoxes = "noerrormsgboxes";
    00038         private const string CmdNoStats = "nostats";
    00039
    00040         // Delegate used for disposing application
    00041         private delegate void DisposeDelegate();
    00042
    00043         // Constants for minimum window size
    00044         private const int MinimumWindowSizeX = 200;
    00045         private const int MinimumWindowSizeY = 200;
    00046         public const int DefaultSizeWidth = 640;
    00047         public const int DefaultSizeHeight = 480;
    00048         // Default starting size
    00049         private static readonly System.Drawing.Size DefaultStartingSize = new System.Drawing.Size(DefaultSizeWidth, DefaultSizeHeight);
    00050         internal static readonly System.Drawing.Size MinWindowSize = new System.Drawing.Size(MinimumWindowSizeX, MinimumWindowSizeY);
    00051         public static readonly IntPtr TrueIntPtr = new IntPtr(1);
    00052         private const string WindowClassName = "ManagedDirect3DWindowClass";
    00053
    00054         // What about the stored data?
    00055         private FrameworkData State;
    00056         // Last shown error
    00057         private Exception lastDisplayedMessage = null;
    00058         // Has the framework been disposed already
    00059         private bool isDisposed = false;
    00060         // Did the toggle fullscreen happen when maximized?
    00061         private bool toggleMaximized = false;
    00062         #endregion
    00063
    00064         #region Creation
    00068         public Framework()
    00069         {
    00070             State = new FrameworkData();
    00071         }
    00072         #endregion
    00073
    00074         #region Setting up callbacks
    00075         // Interface 'callbacks'
    00076         public void SetCallbackInterface(IFrameworkCallback callback) { State.CallbackInterface = callback; }
    00077         public void SetDeviceCreationInterface(IDeviceCreation callback) { State.DeviceCreationInterface = callback; }
    00078
    00079         // Event 'callbacks'
    00080
    00082         public event EventHandler Disposing;
    00084         public event EventHandler DeviceLost;
    00086         public event DeviceEventHandler DeviceCreated;
    00088         public event DeviceEventHandler DeviceReset;
    00089
    00090         public void SetWndProcCallback(WndProcCallback callback) { State.WndProcFunction = callback; }
    00091         #endregion
    00092
    00121         public void Initialize(bool isParsingCommandLine, bool handleDefaultKeys, bool showMessageBoxOnError)
    00122         {
    00123             State.WasInitCalled = true;
    00124
    00125             // Turn off event handling for the MDX runtime, this will
    00126             // increase performance and remove potential working set issues
    00127             Device.IsUsingEventHandlers = false;
    00128
    00129             // Increase
    00130
    00131             // Store this data
    00132             State.IsShowingMsgBoxOnError = showMessageBoxOnError;
    00133             State.IsHandlingDefaultHotkeys = handleDefaultKeys;
    00134
    00135             // Reset the timer period (ignore any failures)
    00136             try
    00137             { NativeMethods.timeBeginPeriod(1); }
    00138             catch { System.Diagnostics.Debugger.Log(9, string.Empty, "Could not set time period.\r\n" ); }
    00139
    00140             if (isParsingCommandLine)
    00141             {
    00142                 ParseCommandLine();
    00143             }
    00144
    00145             // Reset the timer
    00146             FrameworkTimer.Reset();
    00147             State.IsInited = true;
    00148
    00149         }
    00150
    00154         private void ParseCommandLine()
    00155         {
    00156             string[] args = System.Environment.GetCommandLineArgs(); // Ignore the first one since that's the executable name
    00157
    00158             // Go through each argument, skipping the first one
    00159             for (int i = 1; i < args.Length; i++)
    00160             {
    00161                 string argument = string.Empty;
    00162                 if ((args[i].StartsWith("-")) || (args[i].StartsWith("-")))
    00163                 {
    00164                     argument = args[i].Substring(1, args[i].Length - 1);
    00165                 }
    00166                 else
    00167                     continue;
    00168
    00169                 if (argument.ToLower().StartsWith(CmdAdapter + ":"))
    00170                 {
    00171                     try
    00172                     { State.OverrideAdapterOrdinal = int.Parse(argument.Substring(CmdAdapter.Length + 1, argument.Length - (CmdAdapter.Length + 1))); }
    00173                     catch (FormatException){}
    00174                 }
    00175                 else if (string.Compare(argument, CmdWindowed, true) == 0)
    00176                 {
    00177                     State.IsOverridingWindowed = true;
    00178                 }
    00179                 else if (string.Compare(argument, CmdFullscreen, true) == 0)
    00180                 {
    00181                     State.IsOverridingFullScreen = true;
    00182                 }
    00183                 else if (string.Compare(argument, CmdForceHardware, true) == 0)
    00184                 {
    00185                     State.IsOverridingForceHardware = true;
    00186                 }
    00187                 else if (string.Compare(argument, CmdForceRef, true) == 0)
    00188                 {
    00189                     State.IsOverridingForceReference = true;
    00190                 }
    00191                 else if (string.Compare(argument, CmdPureHwVp, true) == 0)
    00192                 {
    00193                     State.IsOverridingForcePureHardwareVertexProcessing = true;
    00194                 }
    00195                 else if (string.Compare(argument, CmdForceHwVp, true) == 0)
    00196                 {
    00197                     State.IsOverridingForceHardwareVertexProcessing = true;
    00198                 }
    00199                 else if (string.Compare(argument, CmdForceSwVp, true) == 0)
    00200                 {
    00201                     State.IsOverridingForceSoftwareVertexProcessing = true;
    00202                 }
    00203                 else if (argument.ToLower().StartsWith(CmdWidth + ":"))
    00204                 {
    00205                     try
    00206                     { State.OverrideWidth = int.Parse(argument.Substring(CmdWidth.Length + 1, argument.Length - (CmdWidth.Length + 1))); }
    00207                     catch (FormatException){}
    00208                 }
    00209                 else if (argument.ToLower().StartsWith(CmdHeight + ":"))
    00210                 {
    00211                     try
    00212                     { State.OverrideHeight = int.Parse(argument.Substring(CmdHeight.Length + 1, argument.Length - (CmdHeight.Length + 1))); }
    00213                     catch (FormatException){}
    00214                 }
    00215                 else if (argument.ToLower().StartsWith(CmdStartx + ":"))
    00216                 {
    00217                     try
    00218                     { State.OverrideStartX = int.Parse(argument.Substring(CmdStartx.Length + 1, argument.Length - (CmdStartx.Length + 1))); }
    00219                     catch (FormatException){}
    00220                 }
    00221                 else if (argument.ToLower().StartsWith(CmdStarty + ":"))
    00222                 {
    00223                     try
    00224                     { State.OverrideStartY = int.Parse(argument.Substring(CmdStarty.Length + 1, argument.Length - (CmdStarty.Length + 1))); }
    00225                     catch (FormatException){}
    00226                 }
    00227                 else if (argument.ToLower().StartsWith(CmdConstantFrame))
    00228                 {
    00229                     float timePerFrame = 0.033f; // Default to this time
    00230                     try
    00231                     {
    00232                         if ( (argument.Length > CmdConstantFrame.Length) )
    00233                             timePerFrame = float.Parse(argument.Substring(CmdConstantFrame.Length + 1, argument.Length - (CmdConstantFrame.Length + 1)));
    00234                     }
    00235                     catch (FormatException){}
    00236                     State.OverrideConstantTimePerFrame = timePerFrame;
    00237                     State.IsOverridingConstantFrameTime = true;
    00238                     SetConstantFrameTime(true, timePerFrame);
    00239                 }
    00240                 else if (argument.ToLower().StartsWith(CmdQuitAfterFrame + ":"))
    00241                 {
    00242                     try
    00243                     { State.OverrideQuitAfterFrame = int.Parse(argument.Substring(CmdQuitAfterFrame.Length + 1, argument.Length - (CmdQuitAfterFrame.Length + 1))); }
    00244                     catch (FormatException){}
    00245                 }
    00246                 else if (string.Compare(argument, CmdNoErrorBoxes, true) == 0)
    00247                 {
    00248                     State.IsShowingMsgBoxOnError = false;
    00249                 }
    00250                 else if (string.Compare(argument, CmdNoStats, true) == 0)
    00251                 {
    00252                     State.AreStatsHidden = true;
    00253                 }
    00254                 else
    00255                     System.Diagnostics.Debugger.Log(9, string.Empty, string.Format("Unrecognized flag: {0}\r\n", argument));
    00256             }
    00257         }
    00258
    00264         public void CreateWindow(string windowTitle, System.Drawing.Icon icon,
    00265             System.Windows.Forms.MainMenu menu, int x, int y)
    00266         {
    00267             if (State.IsInsideDeviceCallback)
    00268                 throw new InvalidOperationException("You cannot create a window from inside a callback.");
    00269
    00270             State.WasWindowCreateCalled = true;
    00271             // Are we inited?
    00272             if (!State.IsInited)
    00273             {
    00274                 // If Init was already called and failed, fail again
    00275                 if (State.WasInitCalled)
    00276                 {
    00277                     throw new InvalidOperationException("Initialize was already called and failed.");
    00278                 }
    00279
    00280                 // Call initialize with default params
    00281                 Initialize(true, true, true);
    00282             }
    00283
    00284             // Is there already a window created?
    00285             if (State.WindowFocus == null)
    00286             {
    00287                 // Override the window's initial size and position if there were cmd line args
    00288                 if (State.OverrideStartX != -1)
    00289                 {
    00290                     State.DefaultStartingLocation = System.Windows.Forms.FormStartPosition.Manual;
    00291                     x = State.OverrideStartX;
    00292                 }
    00293                 if (State.OverrideStartY != -1)
    00294                 {
    00295                     State.DefaultStartingLocation = System.Windows.Forms.FormStartPosition.Manual;
    00296                     y = State.OverrideStartY;
    00297                 }
    00298
    00299                 // Create the new window
    00300                 GraphicsWindow renderWindow = new GraphicsWindow(this);
    00301                 // Hook the events
    00302                 HookEvents(renderWindow);
    00303                 // Are we in the default start location?
    00304                 if (State.DefaultStartingLocation == System.Windows.Forms.FormStartPosition.WindowsDefaultLocation)
    00305                 {
    00306                     State.IsWindowCreatedWithDefaultPositions = true;
    00307                     renderWindow.StartPosition = System.Windows.Forms.FormStartPosition.WindowsDefaultLocation;
    00308                 }
    00309                 else
    00310                 {
    00311                     State.IsWindowCreatedWithDefaultPositions = false;
    00312                     renderWindow.Location = new System.Drawing.Point(x, y);
    00313                 }
    00314
    00315                 // Calculate the window size
    00316                 System.Drawing.Size windowSize = DefaultStartingSize;
    00317                 if (State.OverrideWidth != 0)
    00318                     windowSize.Width = State.OverrideWidth;
    00319                 if (State.OverrideHeight != 0)
    00320                     windowSize.Height = State.OverrideHeight;
    00321                 // Set the size
    00322                 renderWindow.ClientSize = windowSize;
    00323
    00324                 // Store the window title
    00325                 State.WindowTitle = windowTitle;
    00326                 renderWindow.Text = windowTitle;
    00327
    00328                 // Set current cursor
    00329                 System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.Default;
    00330
    00331                 // Get the window's rectangles
    00332                 renderWindow.Visible = false;
    00333                 renderWindow.CreateControl();
    00334                 State.ClientRectangle = renderWindow.ClientRectangle;
    00335                 State.WindowBoundsRectangle = renderWindow.Bounds;
    00336
    00337                 // Update state
    00338                 State.WasWindowCreated = true;
    00339                 State.WindowFocus = renderWindow;
    00340                 State.WindowDeviceFullScreen = renderWindow;
    00341                 State.WindowDeviceWindowed = renderWindow;
    00342             }
    00343         }
    00344
    00348         public void CreateWindow(string windowTitle)
    00349         {
    00350             CreateWindow(windowTitle, LoadFirstIconFromResource(), null, -1, -1);
    00351         }
    00357         public void SetWindow(System.Windows.Forms.Control windowFocus, System.Windows.Forms.Control windowDeviceFullscreen,
    00358             System.Windows.Forms.Control windowDeviceWindowed, bool handleMessages)
    00359         {
    00360             if (State.IsInsideDeviceCallback)
    00361                 throw new InvalidOperationException("You cannot create a window from inside a callback.");
    00362
    00363             State.WasWindowCreateCalled = true;
    00364
    00365             // To avoid confusion, we do not allow any window handles to be null here.  The
    00366             // caller must pass in valid window handles for all three parameters.  The same
    00367             // window handles may be used for more than one parameter.
    00368             if ((windowDeviceFullscreen == null) || (windowDeviceWindowed == null)
    00369                 || (windowFocus == null))
    00370             {
    00371                 throw new InvalidOperationException("You must pass in valid window handles.");
    00372             }
    00373
    00374             if (handleMessages)
    00375             {
    00376                 // Use the static windows procedure defined here
    00377                 HookEvents(windowFocus);
    00378             }
    00379
    00380             // Are we inited?
    00381             if (!State.IsInited)
    00382             {
    00383                 // If Init was already called and failed, fail again
    00384                 if (State.WasInitCalled)
    00385                 {
    00386                     throw new InvalidOperationException("Initialize was already called and failed.");
    00387                 }
    00388
    00389                 // Call initialize with default params
    00390                 Initialize(true, true, true);
    00391             }
    00392
    00393             // Get the window's rectangles
    00394             State.ClientRectangle = windowDeviceWindowed.ClientRectangle;
    00395             State.WindowBoundsRectangle = windowDeviceWindowed.Bounds;
    00396
    00397             // Update state
    00398             State.WasWindowCreated = true;
    00399             State.WindowFocus = windowFocus;
    00400             State.WindowDeviceFullScreen = windowDeviceFullscreen;
    00401             State.WindowDeviceWindowed = windowDeviceWindowed;
    00402         }
    00403
    00404
    00410         public void SetWinformWindow(System.Windows.Forms.Control windowFocus, System.Windows.Forms.Control windowDeviceFullscreen,
    00411             System.Windows.Forms.Control windowDeviceWindowed)
    00412         {
    00413             if (State.IsInsideDeviceCallback)
    00414                 throw new InvalidOperationException("You cannot create a window from inside a callback.");
    00415
    00416             State.WasWindowCreateCalled = true;
    00417
    00418             // To avoid confusion, we do not allow any controls to be null here.  The
    00419             // caller must pass in valid windows for all three parameters.  The same
    00420             // window may be used for more than one parameter.
    00421             if ((windowDeviceFullscreen == null) || (windowDeviceWindowed == null)
    00422                 || (windowFocus == null))
    00423             {
    00424                 throw new InvalidOperationException("You must pass in valid window handles.");
    00425             }
    00426
    00427             // Are we inited?
    00428             if (!State.IsInited)
    00429             {
    00430                 // If Init was already called and failed, fail again
    00431                 if (State.WasInitCalled)
    00432                 {
    00433                     throw new InvalidOperationException("Initialize was already called and failed.");
    00434                 }
    00435
    00436                 // Call initialize with default params
    00437                 Initialize(true, true, true);
    00438             }
    00439
    00440             // Update state
    00441             State.WasWindowCreated = true;
    00442             State.WindowFocus = windowFocus;
    00443             State.WindowDeviceFullScreen = windowDeviceFullscreen;
    00444             State.WindowDeviceWindowed = windowDeviceWindowed;
    00445         }
    00446
    00452         public void CreateDevice(uint adapterOridinal, bool windowed, int suggestedWidth,
    00453             int suggestedHeight, IDeviceCreation callback)
    00454         {
    00455             if (State.IsInsideDeviceCallback)
    00456                 throw new InvalidOperationException("You cannot create a window from inside a callback.");
    00457
    00458             // Store callbacks in global state
    00459             SetDeviceCreationInterface(callback);
    00460
    00461             // Update device create being called
    00462             State.WasDeviceCreateCalled = true;
    00463
    00464             // Was the window created? If not, create it now
    00465             if (!State.WasWindowCreated)
    00466             {
    00467                 // If CreateWindow or SetWindow was already called and failed, then fail again.
    00468                 if (State.WasWindowCreateCalled)
    00469                 {
    00470                     throw new InvalidOperationException("CreateWindow was already called and failed.");
    00471                 }
    00472
    00473                 // Create a default window
    00474                 CreateWindow("Direct3D Window", null, null, -1, -1);
    00475             }
    00476
    00477             // Force an enumeration with the updated Device Acceptable callback
    00478             Enumeration.Enumerate(State.DeviceCreationInterface);
    00479
    00480             // Set up the match options
    00481             MatchOptions match = new MatchOptions();
    00482             match.AdapterOrdinal = MatchType.PreserveInput;
    00483             match.DeviceType = MatchType.IgnoreInput;
    00484             match.Windowed = MatchType.PreserveInput;
    00485             match.AdapterFormat = MatchType.IgnoreInput;
    00486             match.VertexProcessing = MatchType.IgnoreInput;
    00487             match.Resolution = MatchType.ClosestToInput;
    00488             match.BackBufferFormat = MatchType.IgnoreInput;
    00489             match.BackBufferCount = MatchType.IgnoreInput;
    00490             match.MultiSample = MatchType.IgnoreInput;
    00491             match.SwapEffect = MatchType.IgnoreInput;
    00492             match.DepthFormat = MatchType.IgnoreInput;
    00493             match.StencilFormat = MatchType.IgnoreInput;
    00494             match.PresentFlags = MatchType.IgnoreInput;
    00495             match.RefreshRate = MatchType.IgnoreInput;
    00496             match.PresentInterval = MatchType.IgnoreInput;
    00497
    00498             // Get the device settings
    00499             DeviceSettings settings = new DeviceSettings();
    00500             settings.presentParams = new PresentParameters();
    00501             settings.AdapterOrdinal = adapterOridinal;
    00502             settings.presentParams.Windowed = windowed;
    00503             settings.presentParams.BackBufferWidth = suggestedWidth;
    00504             settings.presentParams.BackBufferHeight = suggestedHeight;
    00505
    00506             // Override with settings for command line
    00507             if (State.OverrideWidth != 0)
    00508                 settings.presentParams.BackBufferWidth = State.OverrideWidth;
    00509             if (State.OverrideHeight != 0)
    00510                 settings.presentParams.BackBufferHeight = State.OverrideHeight;
    00511             if (State.OverrideAdapterOrdinal != -1)
    00512                 settings.AdapterOrdinal = (uint)State.OverrideAdapterOrdinal;
    00513
    00514             if (State.IsOverridingFullScreen)
    00515             {
    00516                 settings.presentParams.Windowed = false;
    00517                 if ((State.OverrideWidth == 0) && (State.OverrideHeight == 0))
    00518                     match.Resolution = MatchType.IgnoreInput;
    00519             }
    00520             if (State.IsOverridingWindowed)
    00521                 settings.presentParams.Windowed = true;
    00522
    00523             if (State.IsOverridingForceHardware)
    00524             {
    00525                 settings.DeviceType = DeviceType.Hardware;
    00526                 match.DeviceType = MatchType.PreserveInput;
    00527             }
    00528             if (State.IsOverridingForceReference)
    00529             {
    00530                 settings.DeviceType = DeviceType.Reference;
    00531                 match.DeviceType = MatchType.PreserveInput;
    00532             }
    00533             if (State.IsOverridingForcePureHardwareVertexProcessing)
    00534             {
    00535                 settings.BehaviorFlags = CreateFlags.HardwareVertexProcessing | CreateFlags.PureDevice;
    00536                 match.VertexProcessing = MatchType.PreserveInput;
    00537             }
    00538             if (State.IsOverridingForceHardwareVertexProcessing)
    00539             {
    00540                 settings.BehaviorFlags = CreateFlags.HardwareVertexProcessing;
    00541                 match.VertexProcessing = MatchType.PreserveInput;
    00542             }
    00543             if (State.IsOverridingForceSoftwareVertexProcessing)
    00544             {
    00545                 settings.BehaviorFlags = CreateFlags.SoftwareVertexProcessing;
    00546                 match.VertexProcessing = MatchType.PreserveInput;
    00547             }
    00548
    00549             try
    00550             {
    00551                 settings = FindValidDeviceSettings(settings, match);
    00552             }
    00553             catch(Exception e)
    00554             {
    00555                 DisplayErrorMessage(e);
    00556                 throw;
    00557             }
    00558
    00559             // If the modify device callback isn't null, call it to
    00560             // let the app change the settings
    00561             if (State.DeviceCreationInterface != null)
    00562             {
    00563                 Caps c = Manager.GetDeviceCaps((int)settings.AdapterOrdinal, settings.DeviceType);
    00564                 State.DeviceCreationInterface.ModifyDeviceSettings(settings, c);
    00565             }
    00566
    00567             // Change to a Direct3D device created from the new device settings
    00568             // If there is an existing device, either reset or recreate
    00569             ChangeDevice(settings, null, false);
    00570         }
    00571
    00572
    00579         public void CreateDevice(int adapterOridinal, bool windowed, int suggestedWidth,
    00580             int suggestedHeight, IDeviceCreation callback)
    00581         {
    00582             CreateDevice((uint)adapterOridinal, windowed, suggestedWidth,
    00583             suggestedHeight, callback);
    00584         }
    00585
    00586
    00593         public void SetDevice(Device device)
    00594         {
    00595             if (device == null)
    00596                 throw new ArgumentNullException("device", "You cannot pass in a null device to SetDevice");
    00597
    00598             if (State.IsInsideDeviceCallback)
    00599                 throw new InvalidOperationException("You cannot set a device from inside a callback.");
    00600
    00601             // Was the window created? If not, create it now
    00602             if (!State.WasWindowCreated)
    00603             {
    00604                 // If CreateWindow or SetWindow was already called and failed, then fail again.
    00605                 if (State.WasWindowCreateCalled)
    00606                 {
    00607                     throw new InvalidOperationException("CreateWindow was already called and failed.");
    00608                 }
    00609
    00610                 // Create a default window
    00611                 CreateWindow("Direct3D Window", null, null, -1, -1);
    00612             }
    00613
    00614             DeviceSettings deviceSettings = new DeviceSettings();
    00615
    00616             // Get the present parameters from the swap chain
    00617             using(Surface backBuffer = device.GetBackBuffer(0, 0, BackBufferType.Mono))
    00618             {
    00619                 using (SwapChain swap = backBuffer.GetContainer(InterfaceGuid.SwapChain) as SwapChain)
    00620                 {
    00621                     deviceSettings.presentParams = swap.PresentParameters;
    00622                     System.Diagnostics.Debug.Assert(deviceSettings.presentParams != null, "You must have valid present parameters here.");
    00623                 }
    00624             }
    00625
    00626             DeviceCreationParameters creationParams = device.CreationParameters;
    00627
    00628             // Fill out the device settings structure now
    00629             deviceSettings.AdapterOrdinal = (uint)creationParams.AdapterOrdinal;
    00630             deviceSettings.DeviceType = creationParams.DeviceType;
    00631             deviceSettings.AdapterFormat = FindAdapterFormat(deviceSettings.AdapterOrdinal,
    00632                 deviceSettings.DeviceType, deviceSettings.presentParams.BackBufferFormat,
    00633                 deviceSettings.presentParams.Windowed);
    00634             deviceSettings.BehaviorFlags = creationParams.Behavior.Value;
    00635
    00636             // Change to the Direct3D device passed in
    00637             ChangeDevice(deviceSettings, device, false);
    00638         }
    00639
    00646         public void CreateDeviceFromSettings(DeviceSettings deviceSettings, bool preserveInput)
    00647         {
    00648             // Set the state since this was called
    00649             State.WasDeviceCreateCalled = true;
    00650
    00651             // Was the window created? If not, create it now
    00652             if (!State.WasWindowCreated)
    00653             {
    00654                 // If CreateWindow or SetWindow was already called and failed, then fail again.
    00655                 if (State.WasWindowCreateCalled)
    00656                 {
    00657                     throw new InvalidOperationException("CreateWindow was already called and failed.");
    00658                 }
    00659
    00660                 // Create a default window
    00661                 CreateWindow("Direct3D Window", null, null, -1, -1);
    00662             }
    00663
    00664             if (!preserveInput)
    00665             {
    00666                 // If not preserving the input, the find the closest valid to it
    00667                 MatchOptions match = new MatchOptions();
    00668                 match.AdapterOrdinal = MatchType.ClosestToInput;
    00669                 match.DeviceType = MatchType.ClosestToInput;
    00670                 match.Windowed = MatchType.ClosestToInput;
    00671                 match.AdapterFormat = MatchType.ClosestToInput;
    00672                 match.VertexProcessing = MatchType.ClosestToInput;
    00673                 match.Resolution = MatchType.ClosestToInput;
    00674                 match.BackBufferFormat = MatchType.ClosestToInput;
    00675                 match.BackBufferCount = MatchType.ClosestToInput;
    00676                 match.MultiSample = MatchType.ClosestToInput;
    00677                 match.SwapEffect = MatchType.ClosestToInput;
    00678                 match.DepthFormat = MatchType.ClosestToInput;
    00679                 match.StencilFormat = MatchType.ClosestToInput;
    00680                 match.PresentFlags = MatchType.ClosestToInput;
    00681                 match.RefreshRate = MatchType.ClosestToInput;
    00682                 match.PresentInterval = MatchType.ClosestToInput;
    00683
    00684                 try
    00685                 {
    00686                     deviceSettings = FindValidDeviceSettings(deviceSettings, match);
    00687                 }
    00688                 catch(Exception e)
    00689                 {
    00690                     // Display any error message
    00691                     DisplayErrorMessage(e);
    00692                     throw;
    00693                 }
    00694                 // Change to a Direct3D device created from the new device settings.
    00695                 // If there is an existing device, then either reset or recreate the scene
    00696                 ChangeDevice(deviceSettings, null, false);
    00697             }
    00698         }
    00705         public void CreateDeviceFromSettings(DeviceSettings deviceSettings) { CreateDeviceFromSettings(deviceSettings, false); }
    00706
    00710         public void ToggleFullscreen()
    00711         {
    00712             // Pause the application
    00713             Pause(true, true);
    00714
    00715             // Get the current device settings and flip the windowed state then
    00716             // find the closest valid device settings with this change
    00717             DeviceSettings currentSettings = State.CurrentDeviceSettings.Clone();
    00718             currentSettings.presentParams.Windowed = !currentSettings.presentParams.Windowed;
    00719
    00720             MatchOptions match = new MatchOptions();
    00721             match.AdapterOrdinal = MatchType.PreserveInput;
    00722             match.DeviceType = MatchType.ClosestToInput;
    00723             match.Windowed = MatchType.PreserveInput;
    00724             match.AdapterFormat = MatchType.IgnoreInput;
    00725             match.VertexProcessing = MatchType.ClosestToInput;
    00726             match.BackBufferFormat = MatchType.IgnoreInput;
    00727             match.BackBufferCount = MatchType.ClosestToInput;
    00728             match.MultiSample = MatchType.ClosestToInput;
    00729             match.SwapEffect = MatchType.ClosestToInput;
    00730             match.DepthFormat = MatchType.ClosestToInput;
    00731             match.StencilFormat = MatchType.ClosestToInput;
    00732             match.PresentFlags = MatchType.ClosestToInput;
    00733             match.RefreshRate = MatchType.IgnoreInput;
    00734             match.PresentInterval = MatchType.IgnoreInput;
    00735
    00736             System.Drawing.Rectangle windowClient;
    00737             if (currentSettings.presentParams.Windowed)
    00738                 windowClient = State.ClientRectangle;
    00739             else
    00740                 windowClient = State.FullScreenClientRectangle;
    00741
    00742             if (windowClient.Width > 0 && windowClient.Height > 0)
    00743             {
    00744                 match.Resolution = MatchType.ClosestToInput;
    00745                 currentSettings.presentParams.BackBufferWidth = windowClient.Width;
    00746                 currentSettings.presentParams.BackBufferHeight = windowClient.Height;
    00747             }
    00748             else
    00749             {
    00750                 match.Resolution = MatchType.IgnoreInput;
    00751             }
    00752
    00753             try
    00754             {
    00755                 if ( (!currentSettings.presentParams.Windowed) && (State.IsMaximized))
    00756                 {
    00757                     if (WindowForm != null)
    00758                     {
    00759                         WindowForm.WindowState = System.Windows.Forms.FormWindowState.Normal;
    00760                     }
    00761                     toggleMaximized = true;
    00762                 }
    00763                 currentSettings = FindValidDeviceSettings(currentSettings, match);
    00764                 ChangeDevice(currentSettings, null, false);
    00765                 Window.Size = State.WindowBoundsRectangle.Size;
    00766                 Window.Location = State.WindowBoundsRectangle.Location;
    00767                 if (currentSettings.presentParams.Windowed)
    00768                 {
    00769                     if (toggleMaximized)
    00770                     {
    00771                         if (WindowForm != null)
    00772                         {
    00773                             WindowForm.WindowState = System.Windows.Forms.FormWindowState.Maximized;
    00774                         }
    00775                     }
    00776                     toggleMaximized = false;
    00777                 }
    00778             }
    00779             finally
    00780             {
    00781                 // Well, unpause no matter what
    00782                 Pause(false, false);
    00783                 State.CurrentDeviceSettings = currentSettings;
    00784             }
    00785         }
    00786
    00787
    00791         public void ToggleReference()
    00792         {
    00793             // Get the current device settings
    00794             DeviceSettings currentSettings = State.CurrentDeviceSettings.Clone();
    00795             if (currentSettings.DeviceType == DeviceType.Hardware)
    00796                 currentSettings.DeviceType = DeviceType.Reference;
    00797             else if (currentSettings.DeviceType == DeviceType.Reference)
    00798                 currentSettings.DeviceType = DeviceType.Hardware;
    00799
    00800             MatchOptions match = new MatchOptions();
    00801             match.AdapterOrdinal = MatchType.PreserveInput;
    00802             match.DeviceType = MatchType.PreserveInput;
    00803             match.Windowed = MatchType.ClosestToInput;
    00804             match.AdapterFormat = MatchType.ClosestToInput;
    00805             match.VertexProcessing = MatchType.ClosestToInput;
    00806             match.Resolution = MatchType.ClosestToInput;
    00807             match.BackBufferFormat = MatchType.ClosestToInput;
    00808             match.BackBufferCount = MatchType.ClosestToInput;
    00809             match.MultiSample = MatchType.ClosestToInput;
    00810             match.SwapEffect = MatchType.ClosestToInput;
    00811             match.DepthFormat = MatchType.ClosestToInput;
    00812             match.StencilFormat = MatchType.ClosestToInput;
    00813             match.PresentFlags = MatchType.ClosestToInput;
    00814             match.RefreshRate = MatchType.ClosestToInput;
    00815             match.PresentInterval = MatchType.ClosestToInput;
    00816
    00817             try
    00818             {
    00819                 currentSettings = FindValidDeviceSettings(currentSettings, match);
    00820                 ChangeDevice(currentSettings, null, false);
    00821             }
    00822 #if(DEBUG)
    00823             catch (Exception e)
    00824             {
    00825                 // In debug mode show this error (maybe - depending on settings)
    00826                 DisplayErrorMessage(e);
    00827 #else
    00828             catch
    00829             {
    00830                 // In release mode fail silently
    00831 #endif
    00832             }
    00833             finally
    00834             {
    00835                 // Update the current settings
    00836                 State.CurrentDeviceSettings = currentSettings;
    00837             }
    00838         }
    00839
    00855         private DeviceSettings FindValidDeviceSettings(DeviceSettings settings, MatchOptions match)
    00856         {
    00857             // Build an optimal device settings structure based upon the match
    00858             // options.  If the match option is set to ignore, then a optimal default value is used.
    00859             // The default value may not exist on the system, but later this will be taken
    00860             // into account.
    00861             DeviceSettings optimalSettings = BuildOptimalDeviceSettings(settings, match);
    00862             float bestRanking = -1.0f;
    00863             EnumDeviceSettingsCombo bestDeviceSettingsCombo = new EnumDeviceSettingsCombo();
    00864
    00865             // Find the best combination of:
    00866             //      Adapter Ordinal
    00867             //      Device Type
    00868             //      Adapter Format
    00869             //      Back Buffer Format
    00870             //      Windowed
    00871             // given what's available on the system and the match options combined with the device settings input.
    00872             // This combination of settings is encapsulated by the EnumDeviceSettingsCombo class.
    00873             DisplayMode adapterDesktopDisplayMode;
    00874             for (int iAdapter = 0; iAdapter < Enumeration.AdapterInformationList.Count; iAdapter++)
    00875             {
    00876                 EnumAdapterInformation adapterInfo = Enumeration.AdapterInformationList[iAdapter] as EnumAdapterInformation;
    00877
    00878                 // Get the desktop display mode of the adapter
    00879                 adapterDesktopDisplayMode = Manager.Adapters[(int)adapterInfo.AdapterOrdinal].CurrentDisplayMode;
    00880
    00881                 // Enum all the device types supported by this adapter to find the best device settings
    00882                 for (int iDeviceInfo = 0; iDeviceInfo < adapterInfo.deviceInfoList.Count; iDeviceInfo++)
    00883                 {
    00884                     EnumDeviceInformation deviceInfo = adapterInfo.deviceInfoList[iDeviceInfo] as EnumDeviceInformation;
    00885                     for (int iDeviceCombo = 0; iDeviceCombo<deviceInfo.deviceSettingsList.Count; iDeviceCombo++)
    00886                     {
    00887                         EnumDeviceSettingsCombo deviceSettings = deviceInfo.deviceSettingsList[iDeviceCombo] as EnumDeviceSettingsCombo;
    00888                         // If windowed mode the adapter format has to be the same as the desktop
    00889                         // display mode format so skip any that don't match
    00890                         if (deviceSettings.IsWindowed && (deviceSettings.AdapterFormat != adapterDesktopDisplayMode.Format))
    00891                             continue;
    00892
    00893                         // Skip any combo that doesn't meet the preserve match options
    00894                         if(!DoesDeviceComboMatchPreserveOptions(deviceSettings, settings, match))
    00895                             continue;
    00896
    00897                         // Get a ranking number that describes how closely this device combo matches the optimal combo
    00898                         float curRanking = RankDeviceCombo(deviceSettings, optimalSettings, adapterDesktopDisplayMode);
    00899
    00900                         // If this combo better matches the input device settings then save it
    00901                         if (curRanking > bestRanking )
    00902                         {
    00903                             bestDeviceSettingsCombo = deviceSettings;
    00904                             bestRanking = curRanking;
    00905                         }
    00906                     }
    00907                 }
    00908             }
    00909
    00910             // If no best device combination was found then fail
    00911             if (bestRanking == -1.0f)
    00912             {
    00913                 throw new NoCompatibleDevicesException();
    00914             }
    00915
    00916             // Using the best device settings combo found, build valid device settings taking heed of
    00917             // the match options and the input device settings
    00918             return BuildValidDeviceSettings(bestDeviceSettingsCombo, settings, match);
    00919         }
    00923         private DeviceSettings FindValidDeviceSettings(DeviceSettings settings)
    00924         {
    00925             return FindValidDeviceSettings(settings, new MatchOptions());
    00926         }
    00927
    00934         private DeviceSettings BuildOptimalDeviceSettings(DeviceSettings settings, MatchOptions match)
    00935         {
    00936             DeviceSettings optimal = new DeviceSettings(); // This will be what we return
    00937             optimal.presentParams = new PresentParameters();
    00938
    00939             //---------------------
    00940             // Adapter ordinal
    00941             //---------------------
    00942             if (match.AdapterOrdinal == MatchType.IgnoreInput)
    00943                 optimal.AdapterOrdinal = 0;
    00944             else
    00945                 optimal.AdapterOrdinal = settings.AdapterOrdinal;
    00946
    00947             //---------------------
    00948             // Device type
    00949             //---------------------
    00950             if (match.DeviceType == MatchType.IgnoreInput)
    00951                 optimal.DeviceType = DeviceType.Hardware;
    00952             else
    00953                 optimal.DeviceType = settings.DeviceType;
    00954
    00955             //---------------------
    00956             // Windowed
    00957             //---------------------
    00958             if (match.Windowed == MatchType.IgnoreInput)
    00959                 optimal.presentParams.Windowed = true;
    00960             else
    00961                 optimal.presentParams.Windowed = settings.presentParams.Windowed;
    00962
    00963             //---------------------
    00964             // Adapter format
    00965             //---------------------
    00966             if (match.AdapterFormat == MatchType.IgnoreInput)
    00967             {
    00968                 // If windowed, default to the desktop display mode
    00969                 // If fullscreen, default to the desktop display mode for quick mode change or
    00970                 // default to Format.X8R8G8B8 if the desktop display mode is < 32bit
    00971                 DisplayMode adapterDesktopMode = Manager.Adapters[(int)optimal.AdapterOrdinal].CurrentDisplayMode;
    00972
    00973                 if (optimal.presentParams.Windowed ||
    00974                     ManagedUtility.GetColorChannelBits(adapterDesktopMode.Format) >= 8 )
    00975                     optimal.AdapterFormat = adapterDesktopMode.Format;
    00976                 else
    00977                     optimal.AdapterFormat = Format.X8R8G8B8;
    00978             }
    00979             else
    00980             {
    00981                 optimal.AdapterFormat = settings.AdapterFormat;
    00982             }
    00983
    00984             //---------------------
    00985             // Vertex processing
    00986             //---------------------
    00987             if (match.VertexProcessing == MatchType.IgnoreInput)
    00988                 optimal.BehaviorFlags = CreateFlags.HardwareVertexProcessing;
    00989             else
    00990                 optimal.BehaviorFlags = settings.BehaviorFlags;
    00991
    00992             //---------------------
    00993             // Resolution
    00994             //---------------------
    00995             if (match.Resolution == MatchType.IgnoreInput)
    00996             {
    00997                 // If windowed, default to 640x480
    00998                 // If fullscreen, default to the desktop res for quick mode change
    00999                 if (optimal.presentParams.Windowed )
    01000                 {
    01001                     optimal.presentParams.BackBufferWidth = DefaultSizeWidth;
    01002                     optimal.presentParams.BackBufferHeight = DefaultSizeHeight;
    01003                 }
    01004                 else
    01005                 {
    01006                     DisplayMode adapterDesktopMode = Manager.Adapters[(int)optimal.AdapterOrdinal].CurrentDisplayMode;
    01007
    01008                     optimal.presentParams.BackBufferWidth = adapterDesktopMode.Width;
    01009                     optimal.presentParams.BackBufferHeight = adapterDesktopMode.Height;
    01010                 }
    01011             }
    01012             else
    01013             {
    01014                 optimal.presentParams.BackBufferWidth = settings.presentParams.BackBufferWidth;
    01015                 optimal.presentParams.BackBufferHeight = settings.presentParams.BackBufferHeight;
    01016             }
    01017
    01018             //---------------------
    01019             // Back buffer format
    01020             //---------------------
    01021             if (match.BackBufferFormat == MatchType.IgnoreInput)
    01022                 optimal.presentParams.BackBufferFormat = optimal.AdapterFormat; // Default to match the adapter format
    01023             else
    01024                 optimal.presentParams.BackBufferFormat = settings.presentParams.BackBufferFormat;
    01025
    01026             //---------------------
    01027             // Back buffer count
    01028             //---------------------
    01029             if (match.BackBufferCount == MatchType.IgnoreInput)
    01030                 optimal.presentParams.BackBufferCount = 2; // Default to triple buffering for perf gain
    01031             else
    01032                 optimal.presentParams.BackBufferCount = settings.presentParams.BackBufferCount;
    01033
    01034             //---------------------
    01035             // Multisample
    01036             //---------------------
    01037             if (match.MultiSample == MatchType.IgnoreInput)
    01038                 optimal.presentParams.MultiSampleQuality = 0; // Default to no multisampling
    01039             else
    01040                 optimal.presentParams.MultiSampleQuality = settings.presentParams.MultiSampleQuality;
    01041
    01042             //---------------------
    01043             // Swap effect
    01044             //---------------------
    01045             if (match.SwapEffect == MatchType.IgnoreInput)
    01046                 optimal.presentParams.SwapEffect = SwapEffect.Discard;
    01047             else
    01048                 optimal.presentParams.SwapEffect = settings.presentParams.SwapEffect;
    01049
    01050             //---------------------
    01051             // Depth stencil
    01052             //---------------------
    01053             if (match.DepthFormat == MatchType.IgnoreInput &&
    01054                 match.StencilFormat == MatchType.IgnoreInput)
    01055             {
    01056                 uint backBufferBits = ManagedUtility.GetColorChannelBits(optimal.presentParams.BackBufferFormat);
    01057                 if (backBufferBits >= 8)
    01058                     optimal.presentParams.AutoDepthStencilFormat = DepthFormat.D32;
    01059                 else
    01060                     optimal.presentParams.AutoDepthStencilFormat = DepthFormat.D16;
    01061             }
    01062             else
    01063             {
    01064                 optimal.presentParams.AutoDepthStencilFormat = settings.presentParams.AutoDepthStencilFormat;
    01065             }
    01066
    01067             //---------------------
    01068             // Present flags
    01069             //---------------------
    01070             if (match.PresentFlags == MatchType.IgnoreInput)
    01071                 optimal.presentParams.PresentFlag = PresentFlag.DiscardDepthStencil;
    01072             else
    01073                 optimal.presentParams.PresentFlag = settings.presentParams.PresentFlag;
    01074
    01075             //---------------------
    01076             // Refresh rate
    01077             //---------------------
    01078             if (match.RefreshRate == MatchType.IgnoreInput)
    01079                 optimal.presentParams.FullScreenRefreshRateInHz = 0;
    01080             else
    01081                 optimal.presentParams.FullScreenRefreshRateInHz = settings.presentParams.FullScreenRefreshRateInHz;
    01082
    01083             //---------------------
    01084             // Present interval
    01085             //---------------------
    01086             if (match.PresentInterval == MatchType.IgnoreInput)
    01087             {
    01088                 // For windowed, default to PresentInterval.Immediate
    01089                 // which will wait not for the vertical retrace period to prevent tearing,
    01090                 // but may introduce tearing.
    01091                 // For full screen, default to PresentInterval.Default
    01092                 // which will wait for the vertical retrace period to prevent tearing.
    01093                 if (optimal.presentParams.Windowed )
    01094                     optimal.presentParams.PresentationInterval = PresentInterval.Immediate;
    01095                 else
    01096                     optimal.presentParams.PresentationInterval = PresentInterval.Default;
    01097             }
    01098             else
    01099             {
    01100                 optimal.presentParams.PresentationInterval = settings.presentParams.PresentationInterval;
    01101             }
    01102
    01103             return optimal;
    01104         }
    01105
    01106
    01111         private DeviceSettings BuildValidDeviceSettings(EnumDeviceSettingsCombo deviceCombo, DeviceSettings settings, MatchOptions match)
    01112         {
    01113             DeviceSettings validSettings = new DeviceSettings();
    01114             DisplayMode adapterDesktopDisplayMode = Manager.Adapters[(int)deviceCombo.AdapterOrdinal].CurrentDisplayMode;
    01115
    01116             // For each setting pick the best, taking into account the match options and
    01117             // what's supported by the device
    01118
    01119             //---------------------
    01120             // Adapter Ordinal
    01121             //---------------------
    01122             // Just using deviceCombo.AdapterOrdinal
    01123
    01124             //---------------------
    01125             // Device Type
    01126             //---------------------
    01127             // Just using deviceCombo.DeviceType
    01128
    01129             //---------------------
    01130             // Windowed
    01131             //---------------------
    01132             // Just using deviceCombo.Windowed
    01133
    01134             //---------------------
    01135             // Adapter Format
    01136             //---------------------
    01137             // Just using deviceCombo.AdapterFormat
    01138
    01139             //---------------------
    01140             // Vertex processing
    01141             //---------------------
    01142             CreateFlags bestBehaviorFlags = 0;
    01143             if (match.VertexProcessing == MatchType.PreserveInput )
    01144             {
    01145                 bestBehaviorFlags = settings.BehaviorFlags;
    01146             }
    01147             else if (match.VertexProcessing == MatchType.IgnoreInput )
    01148             {
    01149                 // The framework defaults to HWVP if available otherwise use SWVP
    01150                 if (deviceCombo.deviceInformation.Caps.DeviceCaps.SupportsHardwareTransformAndLight)
    01151                     bestBehaviorFlags |= CreateFlags.HardwareVertexProcessing;
    01152                 else
    01153                     bestBehaviorFlags |= CreateFlags.SoftwareVertexProcessing;
    01154             }
    01155             else
    01156             {
    01157                 // Default to input, and fallback to SWVP if HWVP not available
    01158                 bestBehaviorFlags = settings.BehaviorFlags;
    01159                 if ((!deviceCombo.deviceInformation.Caps.DeviceCaps.SupportsHardwareTransformAndLight) &&
    01160                     ( (bestBehaviorFlags & CreateFlags.HardwareVertexProcessing ) != 0 ||
    01161                     (bestBehaviorFlags & CreateFlags.MixedVertexProcessing) != 0) )
    01162                 {
    01163                     bestBehaviorFlags &= ~CreateFlags.HardwareVertexProcessing ;
    01164                     bestBehaviorFlags &= ~CreateFlags.MixedVertexProcessing;
    01165                     bestBehaviorFlags |= CreateFlags.SoftwareVertexProcessing;
    01166                 }
    01167
    01168                 // One of these must be selected
    01169                 if ((bestBehaviorFlags & CreateFlags.HardwareVertexProcessing ) == 0 &&
    01170                     (bestBehaviorFlags & CreateFlags.MixedVertexProcessing) == 0 &&
    01171                     (bestBehaviorFlags & CreateFlags.SoftwareVertexProcessing) == 0 )
    01172                 {
    01173                     if (deviceCombo.deviceInformation.Caps.DeviceCaps.SupportsHardwareTransformAndLight)
    01174                         bestBehaviorFlags |= CreateFlags.HardwareVertexProcessing ;
    01175                     else
    01176                         bestBehaviorFlags |= CreateFlags.SoftwareVertexProcessing;
    01177                 }
    01178             }
    01179
    01180             //---------------------
    01181             // Resolution
    01182             //---------------------
    01183             DisplayMode bestDisplayMode = new DisplayMode();
    01184             if (match.Resolution == MatchType.PreserveInput )
    01185             {
    01186                 bestDisplayMode.Width = settings.presentParams.BackBufferWidth;
    01187                 bestDisplayMode.Height = settings.presentParams.BackBufferHeight;
    01188             }
    01189             else
    01190             {
    01191                 DisplayMode displayModeIn = new DisplayMode();
    01192                 if (match.Resolution == MatchType.ClosestToInput &&
    01193                     (settings.presentParams.BackBufferWidth != 0 && settings.presentParams.BackBufferWidth != 0) )
    01194                 {
    01195                     displayModeIn.Width = settings.presentParams.BackBufferWidth;
    01196                     displayModeIn.Height = settings.presentParams.BackBufferHeight;
    01197                 }
    01198                 else // if (match.Resolution == MatchType.IgnoreInput )
    01199                 {
    01200                     if (deviceCombo.IsWindowed )
    01201                     {
    01202                         // The framework defaults to 640x480 for windowed
    01203                         displayModeIn.Width = DefaultSizeWidth;
    01204                         displayModeIn.Height = DefaultSizeHeight;
    01205                     }
    01206                     else
    01207                     {
    01208                         // The framework defaults to desktop resolution for fullscreen to try to avoid slow mode change
    01209                         displayModeIn.Width = adapterDesktopDisplayMode.Width;
    01210                         displayModeIn.Height = adapterDesktopDisplayMode.Height;
    01211                     }
    01212                 }
    01213
    01214                 // Call a helper function to find the closest valid display mode to the optimal
    01215                 bestDisplayMode = FindValidResolution(deviceCombo, displayModeIn);
    01216             }
    01217
    01218             //---------------------
    01219             // Back Buffer Format
    01220             //---------------------
    01221             // Just using deviceCombo.BackBufferFormat
    01222
    01223             //---------------------
    01224             // Back buffer count
    01225             //---------------------
    01226             uint bestBackBufferCount;
    01227             if (match.BackBufferCount == MatchType.PreserveInput )
    01228             {
    01229                 bestBackBufferCount = (uint)settings.presentParams.BackBufferCount;
    01230             }
    01231             else if (match.BackBufferCount == MatchType.IgnoreInput )
    01232             {
    01233                 // The framework defaults to triple buffering
    01234                 bestBackBufferCount = 2;
    01235             }
    01236             else // if (match.BackBufferCount == MatchType.ClosestToInput )
    01237             {
    01238                 bestBackBufferCount = (uint)settings.presentParams.BackBufferCount;
    01239                 if (bestBackBufferCount > 3 )
    01240                     bestBackBufferCount = 3;
    01241                 if (bestBackBufferCount < 1 )
    01242                     bestBackBufferCount = 1;
    01243             }
    01244
    01245             //---------------------
    01246             // Multisample
    01247             //---------------------
    01248             MultiSampleType bestMultiSampleType;
    01249             uint bestMultiSampleQuality;
    01250             if (settings.presentParams.SwapEffect != SwapEffect.Discard)
    01251             {
    01252                 // Swap effect is not set to discard so multisampling has to off
    01253                 bestMultiSampleType = MultiSampleType.None;
    01254                 bestMultiSampleQuality = 0;
    01255             }
    01256             else
    01257             {
    01258                 if (match.BackBufferCount == MatchType.PreserveInput )
    01259                 {
    01260                     bestMultiSampleType    = settings.presentParams.MultiSample;
    01261                     bestMultiSampleQuality = (uint)settings.presentParams.MultiSampleQuality;
    01262                 }
    01263                 else if (match.BackBufferCount == MatchType.IgnoreInput )
    01264                 {
    01265                     // Default to no multisampling (always supported)
    01266                     bestMultiSampleType = MultiSampleType.None;
    01267                     bestMultiSampleQuality = 0;
    01268                 }
    01269                 else if (match.BackBufferCount == MatchType.ClosestToInput )
    01270                 {
    01271                     // Default to no multisampling (always supported)
    01272                     bestMultiSampleType = MultiSampleType.None;
    01273                     bestMultiSampleQuality = 0;
    01274
    01275                     for (int i = 0; i < deviceCombo.multiSampleTypeList.Count; i++)
    01276                     {
    01277                         MultiSampleType tempType = (MultiSampleType)deviceCombo.multiSampleTypeList[i];
    01278                         uint tempQuality = (uint)(int)deviceCombo.multiSampleQualityList[i];
    01279
    01280                         // Check whether supported type is closer to the input than our current best
    01281                         if (Math.Abs((int)tempType -  (int)settings.presentParams.MultiSample) < Math.Abs((int)bestMultiSampleType - (int)settings.presentParams.MultiSample) )
    01282                         {
    01283                             bestMultiSampleType = tempType;
    01284                             bestMultiSampleQuality = (uint)Math.Min(tempQuality-1, settings.presentParams.MultiSampleQuality);
    01285                         }
    01286                     }
    01287                 }
    01288                 else // Error case
    01289                 {
    01290                     // Default to no multisampling (always supported)
    01291                     bestMultiSampleType = MultiSampleType.None;
    01292                     bestMultiSampleQuality = 0;
    01293                 }
    01294             }
    01295
    01296             //---------------------
    01297             // Swap effect
    01298             //---------------------
    01299             SwapEffect bestSwapEffect;
    01300             if (match.SwapEffect == MatchType.PreserveInput )
    01301             {
    01302                 bestSwapEffect = settings.presentParams.SwapEffect;
    01303             }
    01304             else if (match.SwapEffect == MatchType.IgnoreInput )
    01305             {
    01306                 bestSwapEffect = SwapEffect.Discard;
    01307             }
    01308             else // if (match.SwapEffect == MatchType.ClosestToInput )
    01309             {
    01310                 bestSwapEffect = settings.presentParams.SwapEffect;
    01311
    01312                 // Swap effect has to be one of these 3
    01313                 if (bestSwapEffect != SwapEffect.Discard &&
    01314                     bestSwapEffect != SwapEffect.Flip &&
    01315                     bestSwapEffect != SwapEffect.Copy )
    01316                 {
    01317                     bestSwapEffect = SwapEffect.Discard;
    01318                 }
    01319             }
    01320
    01321             //---------------------
    01322             // Depth stencil
    01323             //---------------------
    01324             DepthFormat bestDepthStencilFormat;
    01325             bool bestEnableAutoDepthStencil;
    01326
    01327             int[] depthStencilRanking = new int[deviceCombo.depthStencilFormatList.Count];
    01328
    01329             uint backBufferBitDepth = ManagedUtility.GetColorChannelBits( deviceCombo.BackBufferFormat );
    01330             uint inputDepthBitDepth = ManagedUtility.GetDepthBits( settings.presentParams.AutoDepthStencilFormat );
    01331
    01332             for( int i=0; i<deviceCombo.depthStencilFormatList.Count; i++ )
    01333             {
    01334                 DepthFormat curDepthStencilFmt = (DepthFormat)deviceCombo.depthStencilFormatList[i];
    01335                 uint curDepthBitDepth = ManagedUtility.GetDepthBits( curDepthStencilFmt );
    01336                 int ranking;
    01337
    01338                 if (match.DepthFormat == MatchType.PreserveInput )
    01339                 {
    01340                     // Need to match bit depth of input
    01341                     if(curDepthBitDepth == inputDepthBitDepth)
    01342                         ranking = 0;
    01343                     else
    01344                         ranking = 10000;
    01345                 }
    01346                 else if (match.DepthFormat == MatchType.IgnoreInput )
    01347                 {
    01348                     // Prefer match of backbuffer bit depth
    01349                     ranking = Math.Abs((int)curDepthBitDepth - (int)(backBufferBitDepth*4));
    01350                 }
    01351                 else // if (match.DepthFormat == MatchType.ClosestToInput )
    01352                 {
    01353                     // Prefer match of input depth format bit depth
    01354                     ranking = Math.Abs((int)curDepthBitDepth - (int)inputDepthBitDepth);
    01355                 }
    01356
    01357                 depthStencilRanking[i] = ranking;
    01358             }
    01359
    01360             uint inputStencilBitDepth = ManagedUtility.GetStencilBits( settings.presentParams.AutoDepthStencilFormat );
    01361
    01362             for( int i=0; i<deviceCombo.depthStencilFormatList.Count; i++ )
    01363             {
    01364                 DepthFormat curDepthStencilFmt = (DepthFormat)deviceCombo.depthStencilFormatList[i];
    01365                 int ranking = depthStencilRanking[i];
    01366                 uint curStencilBitDepth = ManagedUtility.GetStencilBits( curDepthStencilFmt );
    01367
    01368                 if (match.StencilFormat == MatchType.PreserveInput )
    01369                 {
    01370                     // Need to match bit depth of input
    01371                     if(curStencilBitDepth == inputStencilBitDepth)
    01372                         ranking += 0;
    01373                     else
    01374                         ranking += 10000;
    01375                 }
    01376                 else if (match.StencilFormat == MatchType.IgnoreInput )
    01377                 {
    01378                     // Prefer 0 stencil bit depth
    01379                     ranking += (int)curStencilBitDepth;
    01380                 }
    01381                 else // if (match.StencilFormat == MatchType.ClosestToInput )
    01382                 {
    01383                     // Prefer match of input stencil format bit depth
    01384                     ranking += Math.Abs((int)curStencilBitDepth - (int)inputStencilBitDepth);
    01385                 }
    01386
    01387                 depthStencilRanking[i] = ranking;
    01388             }
    01389
    01390             int bestRanking = 100000;
    01391             int bestIndex = -1;
    01392             for( int i=0; i<depthStencilRanking.Length; i++ )
    01393             {
    01394                 if (depthStencilRanking[i] < bestRanking )
    01395                 {
    01396                     bestRanking = depthStencilRanking[i];
    01397                     bestIndex = i;
    01398                 }
    01399             }
    01400
    01401             if (bestIndex >= 0 )
    01402             {
    01403                 bestDepthStencilFormat = (DepthFormat)deviceCombo.depthStencilFormatList[bestIndex];
    01404                 bestEnableAutoDepthStencil = true;
    01405             }
    01406             else
    01407             {
    01408                 bestDepthStencilFormat = DepthFormat.Unknown;
    01409                 bestEnableAutoDepthStencil = false;
    01410             }
    01411
    01412
    01413             //---------------------
    01414             // Present flags
    01415             //---------------------
    01416             PresentFlag bestPresentFlag;
    01417             if (match.PresentFlags == MatchType.PreserveInput )
    01418             {
    01419                 bestPresentFlag = settings.presentParams.PresentFlag;
    01420             }
    01421             else if (match.PresentFlags == MatchType.IgnoreInput )
    01422             {
    01423                 bestPresentFlag = 0;
    01424                 if (bestEnableAutoDepthStencil )
    01425                     bestPresentFlag = PresentFlag.DiscardDepthStencil;
    01426             }
    01427             else // if (match.PresentFlags == MatchType.ClosestToInput )
    01428             {
    01429                 bestPresentFlag = settings.presentParams.PresentFlag;
    01430                 if (bestEnableAutoDepthStencil )
    01431                     bestPresentFlag |= PresentFlag.DiscardDepthStencil;
    01432             }
    01433
    01434             //---------------------
    01435             // Refresh rate
    01436             //---------------------
    01437             if (deviceCombo.IsWindowed )
    01438             {
    01439                 // Must be 0 for windowed
    01440                 bestDisplayMode.RefreshRate = 0;
    01441             }
    01442             else
    01443             {
    01444                 if (match.RefreshRate == MatchType.PreserveInput )
    01445                 {
    01446                     bestDisplayMode.RefreshRate = settings.presentParams.FullScreenRefreshRateInHz;
    01447                 }
    01448                 else
    01449                 {
    01450                     uint refreshRateMatch;
    01451                     if (match.RefreshRate == MatchType.ClosestToInput )
    01452                     {
    01453                         refreshRateMatch = (uint)settings.presentParams.FullScreenRefreshRateInHz;
    01454                     }
    01455                     else // if (match.RefreshRate == MatchType.IgnoreInput )
    01456                     {
    01457                         refreshRateMatch = (uint)adapterDesktopDisplayMode.RefreshRate;
    01458                     }
    01459
    01460                     bestDisplayMode.RefreshRate = 0;
    01461
    01462                     if (refreshRateMatch != 0 )
    01463                     {
    01464                         int bestRefreshRanking = 100000;
    01465                         for( int iDisplayMode=0; iDisplayMode<deviceCombo.adapterInformation.displayModeList.Count; iDisplayMode++ )
    01466                         {
    01467                             DisplayMode displayMode = (DisplayMode)deviceCombo.adapterInformation.displayModeList[iDisplayMode];
    01468                             if (displayMode.Format != deviceCombo.AdapterFormat ||
    01469                                 displayMode.Height != bestDisplayMode.Height ||
    01470                                 displayMode.Width != bestDisplayMode.Width )
    01471                                 continue; // Skip display modes that don't match
    01472
    01473                             // Find the delta between the current refresh rate and the optimal refresh rate
    01474                             int currentRefreshRanking = Math.Abs((int)displayMode.RefreshRate - (int)refreshRateMatch);
    01475
    01476                             if (currentRefreshRanking < bestRefreshRanking )
    01477                             {
    01478                                 bestDisplayMode.RefreshRate = displayMode.RefreshRate;
    01479                                 bestRefreshRanking = currentRefreshRanking;
    01480
    01481                                 // Stop if perfect match found
    01482                                 if (bestRefreshRanking == 0 )
    01483                                     break;
    01484                             }
    01485                         }
    01486                     }
    01487                 }
    01488             }
    01489
    01490             //---------------------
    01491             // Present interval
    01492             //---------------------
    01493             PresentInterval bestPresentInterval;
    01494             if (match.PresentInterval == MatchType.PreserveInput )
    01495             {
    01496                 bestPresentInterval = settings.presentParams.PresentationInterval;
    01497             }
    01498             else if (match.PresentInterval == MatchType.IgnoreInput )
    01499             {
    01500                 if (deviceCombo.IsWindowed )
    01501                 {
    01502                     // For windowed, the framework defaults to PresentInterval.Immediate
    01503                     // which will wait not for the vertical retrace period to prevent tearing,
    01504                     // but may introduce tearing
    01505                     bestPresentInterval = PresentInterval.Immediate;
    01506                 }
    01507                 else
    01508                 {
    01509                     // For full screen, the framework defaults to PresentInterval.Default
    01510                     // which will wait for the vertical retrace period to prevent tearing
    01511                     bestPresentInterval = PresentInterval.Default;
    01512                 }
    01513             }
    01514             else // if (match.PresentInterval == MatchType.ClosestToInput )
    01515             {
    01516                 if (deviceCombo.presentIntervalList.Contains( settings.presentParams.PresentationInterval ) )
    01517                 {
    01518                     bestPresentInterval = settings.presentParams.PresentationInterval;
    01519                 }
    01520                 else
    01521                 {
    01522                     if (deviceCombo.IsWindowed )
    01523                         bestPresentInterval = PresentInterval.Immediate;
    01524                     else
    01525                         bestPresentInterval = PresentInterval.Default;
    01526                 }
    01527             }
    01528
    01529             // Fill the device settings struct
    01530             validSettings.AdapterOrdinal = deviceCombo.AdapterOrdinal;
    01531             validSettings.DeviceType = deviceCombo.DeviceType;
    01532             validSettings.AdapterFormat = deviceCombo.AdapterFormat;
    01533             validSettings.BehaviorFlags = bestBehaviorFlags;
    01534             validSettings.presentParams = new PresentParameters();
    01535             validSettings.presentParams.BackBufferWidth = bestDisplayMode.Width;
    01536             validSettings.presentParams.BackBufferHeight = bestDisplayMode.Height;
    01537             validSettings.presentParams.BackBufferFormat = deviceCombo.BackBufferFormat;
    01538             validSettings.presentParams.BackBufferCount = (int)bestBackBufferCount;
    01539             validSettings.presentParams.MultiSample = bestMultiSampleType;
    01540             validSettings.presentParams.MultiSampleQuality = (int)bestMultiSampleQuality;
    01541             validSettings.presentParams.SwapEffect = bestSwapEffect;
    01542             validSettings.presentParams.DeviceWindow = deviceCombo.IsWindowed ? State.WindowDeviceWindowed : State.WindowDeviceFullScreen;
    01543             validSettings.presentParams.Windowed = deviceCombo.IsWindowed;
    01544             validSettings.presentParams.EnableAutoDepthStencil = bestEnableAutoDepthStencil;
    01545             validSettings.presentParams.AutoDepthStencilFormat = bestDepthStencilFormat;
    01546             validSettings.presentParams.PresentFlag = bestPresentFlag;
    01547             validSettings.presentParams.FullScreenRefreshRateInHz  = bestDisplayMode.RefreshRate;
    01548             validSettings.presentParams.PresentationInterval = bestPresentInterval;
    01549             validSettings.presentParams.ForceNoMultiThreadedFlag = true;
    01550
    01551             return validSettings;
    01552         }
    01553
    01554
    01559         private bool DoesDeviceComboMatchPreserveOptions(EnumDeviceSettingsCombo deviceCombo, DeviceSettings settings, MatchOptions match)
    01560         {
    01561             //---------------------
    01562             // Adapter ordinal
    01563             //---------------------
    01564             if (match.AdapterOrdinal == MatchType.PreserveInput &&
    01565                 (deviceCombo.AdapterOrdinal != settings.AdapterOrdinal) )
    01566                 return false;
    01567
    01568             //---------------------
    01569             // Device type
    01570             //---------------------
    01571             if (match.DeviceType == MatchType.PreserveInput &&
    01572                 (deviceCombo.DeviceType != settings.DeviceType) )
    01573                 return false;
    01574
    01575             //---------------------
    01576             // Windowed
    01577             //---------------------
    01578             if (match.Windowed == MatchType.PreserveInput &&
    01579                 (deviceCombo.IsWindowed != settings.presentParams.Windowed) )
    01580                 return false;
    01581
    01582             //---------------------
    01583             // Adapter format
    01584             //---------------------
    01585             if (match.AdapterFormat == MatchType.PreserveInput &&
    01586                 (deviceCombo.AdapterFormat != settings.AdapterFormat) )
    01587                 return false;
    01588
    01589             //---------------------
    01590             // Vertex processing
    01591             //---------------------
    01592             // If keep VP and input has HWVP, then skip if this combo doesn't have HWTL
    01593             if (match.VertexProcessing == MatchType.PreserveInput &&
    01594                 ((settings.BehaviorFlags & CreateFlags.HardwareVertexProcessing) != 0) &&
    01595                 (deviceCombo.deviceInformation.Caps.DeviceCaps.SupportsHardwareTransformAndLight) )
    01596                 return false;
    01597
    01598             //---------------------
    01599             // Resolution
    01600             //---------------------
    01601             // If keep resolution then check that width and height supported by this combo
    01602             if (match.Resolution == MatchType.PreserveInput )
    01603             {
    01604                 bool bFound = false;
    01605                 for( int i=0; i< deviceCombo.adapterInformation.displayModeList.Count; i++ )
    01606                 {
    01607                     DisplayMode displayMode = (DisplayMode)deviceCombo.adapterInformation.displayModeList[i];
    01608                     if (displayMode.Format != deviceCombo.AdapterFormat )
    01609                         continue; // Skip this display mode if it doesn't match the combo's adapter format
    01610
    01611                     if (displayMode.Width == settings.presentParams.BackBufferWidth &&
    01612                         displayMode.Height == settings.presentParams.BackBufferHeight )
    01613                     {
    01614                         bFound = true;
    01615                         break;
    01616                     }
    01617                 }
    01618
    01619                 // If the width and height are not supported by this combo, return false
    01620                 if (!bFound )
    01621                     return false;
    01622             }
    01623
    01624             //---------------------
    01625             // Back buffer format
    01626             //---------------------
    01627             if (match.BackBufferFormat == MatchType.PreserveInput &&
    01628                 deviceCombo.BackBufferFormat != settings.presentParams.BackBufferFormat )
    01629                 return false;
    01630
    01631             //---------------------
    01632             // Back buffer count
    01633             //---------------------
    01634             // No caps for the back buffer count
    01635
    01636             //---------------------
    01637             // Multisample
    01638             //---------------------
    01639             if (match.MultiSample == MatchType.PreserveInput )
    01640             {
    01641                 bool bFound = false;
    01642                 for( int i=0; i<deviceCombo.multiSampleTypeList.Count; i++ )
    01643                 {
    01644                     MultiSampleType msType = (MultiSampleType)deviceCombo.multiSampleTypeList[i];
    01645                     uint msQuality  = (uint)(int)deviceCombo.multiSampleQualityList[i];
    01646
    01647                     if (msType == settings.presentParams.MultiSample &&
    01648                         msQuality >= settings.presentParams.MultiSampleQuality )
    01649                     {
    01650                         bFound = true;
    01651                         break;
    01652                     }
    01653                 }
    01654
    01655                 // If multisample type/quality not supported by this combo, then return false
    01656                 if (!bFound )
    01657                     return false;
    01658             }
    01659
    01660             //---------------------
    01661             // Swap effect
    01662             //---------------------
    01663             // No caps for swap effects
    01664
    01665             //---------------------
    01666             // Depth stencil
    01667             //---------------------
    01668             // If keep depth stencil format then check that the depth stencil format is supported by this combo
    01669             if (match.DepthFormat == MatchType.PreserveInput &&
    01670                 match.StencilFormat == MatchType.PreserveInput )
    01671             {
    01672                 if (settings.presentParams.AutoDepthStencilFormat != (DepthFormat)Format.Unknown &&
    01673                     !deviceCombo.depthStencilFormatList.Contains( settings.presentParams.AutoDepthStencilFormat ) )
    01674                     return false;
    01675             }
    01676
    01677             // If keep depth format then check that the depth format is supported by this combo
    01678             if (match.DepthFormat == MatchType.PreserveInput &&
    01679                 settings.presentParams.AutoDepthStencilFormat != DepthFormat.Unknown )
    01680             {
    01681                 bool bFound = false;
    01682                 uint depthBits = ManagedUtility.GetDepthBits( settings.presentParams.AutoDepthStencilFormat );
    01683                 for( int i=0; i<deviceCombo.depthStencilFormatList.Count; i++ )
    01684                 {
    01685                     DepthFormat depthStencilFmt = (DepthFormat)deviceCombo.depthStencilFormatList[i];
    01686                     uint curDepthBits = ManagedUtility.GetDepthBits(depthStencilFmt);
    01687                     if (curDepthBits - depthBits == 0)
    01688                         bFound = true;
    01689                 }
    01690
    01691                 if (!bFound )
    01692                     return false;
    01693             }
    01694
    01695             // If keep depth format then check that the depth format is supported by this combo
    01696             if (match.StencilFormat == MatchType.PreserveInput &&
    01697                 settings.presentParams.AutoDepthStencilFormat != DepthFormat.Unknown )
    01698             {
    01699                 bool bFound = false;
    01700                 uint stencilBits = ManagedUtility.GetStencilBits( settings.presentParams.AutoDepthStencilFormat );
    01701                 for( int i=0; i<deviceCombo.depthStencilFormatList.Count; i++ )
    01702                 {
    01703                     DepthFormat depthStencilFmt = (DepthFormat)deviceCombo.depthStencilFormatList[i];
    01704                     uint curStencilBits = ManagedUtility.GetStencilBits(depthStencilFmt);
    01705                     if (curStencilBits - stencilBits == 0)
    01706                         bFound = true;
    01707                 }
    01708
    01709                 if (!bFound )
    01710                     return false;
    01711             }
    01712
    01713             //---------------------
    01714             // Present flags
    01715             //---------------------
    01716             // No caps for the present flags
    01717
    01718             //---------------------
    01719             // Refresh rate
    01720             //---------------------
    01721             // If keep refresh rate then check that the resolution is supported by this combo
    01722             if (match.RefreshRate == MatchType.PreserveInput )
    01723             {
    01724                 bool bFound = false;
    01725                 for( int i=0; i<deviceCombo.adapterInformation.displayModeList.Count; i++ )
    01726                 {
    01727                     DisplayMode displayMode = (DisplayMode)deviceCombo.adapterInformation.displayModeList[i];
    01728                     if (displayMode.Format != deviceCombo.AdapterFormat )
    01729                         continue;
    01730                     if (displayMode.RefreshRate == settings.presentParams.FullScreenRefreshRateInHz )
    01731                     {
    01732                         bFound = true;
    01733                         break;
    01734                     }
    01735                 }
    01736
    01737                 // If refresh rate not supported by this combo, then return false
    01738                 if (!bFound )
    01739                     return false;
    01740             }
    01741
    01742             //---------------------
    01743             // Present interval
    01744             //---------------------
    01745             // If keep present interval then check that the present interval is supported by this combo
    01746             if (match.PresentInterval == MatchType.PreserveInput &&
    01747                 !deviceCombo.presentIntervalList.Contains( settings.presentParams.PresentationInterval ) )
    01748                 return false;
    01749
    01750             return true;
    01751         }
    01752
    01756         private float RankDeviceCombo(EnumDeviceSettingsCombo deviceCombo, DeviceSettings settings, DisplayMode adapterMode)
    01757         {
    01758             float currentRanking = 0.0f;
    01759
    01760             // Arbitrary weights.  Gives preference to the ordinal, device type, and windowed
    01761             const float adapterOrdinalWeight = 1000.0f;
    01762             const float deviceTypeWeight = 100.0f;
    01763             const float windowWeight = 10.0f;
    01764             const float adapterFormatWeight = 1.0f;
    01765             const float vertexProcessingWeight = 1.0f;
    01766             const float resolutionWeight = 1.0f;
    01767             const float backBufferFormatWeight = 1.0f;
    01768             const float multiSampleWeight = 1.0f;
    01769             const float depthStencilWeight = 1.0f;
    01770             const float refreshRateWeight = 1.0f;
    01771             const float presentIntervalWeight = 1.0f;
    01772
    01773
    01774             //---------------------
    01775             // Adapter ordinal
    01776             //---------------------
    01777             if (deviceCombo.AdapterOrdinal == settings.AdapterOrdinal )
    01778                 currentRanking += adapterOrdinalWeight;
    01779
    01780             //---------------------
    01781             // Device type
    01782             //---------------------
    01783             if (deviceCombo.DeviceType == settings.DeviceType )
    01784                 currentRanking += deviceTypeWeight;
    01785             // Slightly prefer HAL
    01786             if (deviceCombo.DeviceType == DeviceType.Hardware )
    01787                 currentRanking += 0.1f;
    01788
    01789             //---------------------
    01790             // Windowed
    01791             //---------------------
    01792             if (deviceCombo.IsWindowed == settings.presentParams.Windowed )
    01793                 currentRanking += windowWeight;
    01794
    01795             //---------------------
    01796             // Adapter format
    01797             //---------------------
    01798             if (deviceCombo.AdapterFormat == settings.AdapterFormat )
    01799             {
    01800                 currentRanking += adapterFormatWeight;
    01801             }
    01802             else
    01803             {
    01804                 int bitDepthDelta = Math.Abs((int)ManagedUtility.GetColorChannelBits(deviceCombo.AdapterFormat) -
    01805                     (int)ManagedUtility.GetColorChannelBits(settings.AdapterFormat) );
    01806                 float scale = Math.Max(0.9f - (float)bitDepthDelta*0.2f, 0);
    01807                 currentRanking += scale * adapterFormatWeight;
    01808             }
    01809
    01810             if (!deviceCombo.IsWindowed )
    01811             {
    01812                 // Slightly prefer when it matches the desktop format or is Format.X8R8G8B8
    01813                 bool isAdapterOptimalMatch;
    01814                 if (ManagedUtility.GetColorChannelBits(adapterMode.Format) >= 8 )
    01815                     isAdapterOptimalMatch = (deviceCombo.AdapterFormat == adapterMode.Format);
    01816                 else
    01817                     isAdapterOptimalMatch = (deviceCombo.AdapterFormat == Format.X8R8G8B8);
    01818
    01819                 if (isAdapterOptimalMatch )
    01820                     currentRanking += 0.1f;
    01821             }
    01822
    01823             //---------------------
    01824             // Vertex processing
    01825             //---------------------
    01826             if ((settings.BehaviorFlags & CreateFlags.HardwareVertexProcessing) != 0 ||
    01827                 (settings.BehaviorFlags & CreateFlags.MixedVertexProcessing) != 0 )
    01828             {
    01829                 if(deviceCombo.deviceInformation.Caps.DeviceCaps.SupportsHardwareTransformAndLight)
    01830                     currentRanking += vertexProcessingWeight;
    01831             }
    01832             // Slightly prefer HW T&L
    01833             if(deviceCombo.deviceInformation.Caps.DeviceCaps.SupportsHardwareTransformAndLight)
    01834                 currentRanking += 0.1f;
    01835
    01836             //---------------------
    01837             // Resolution
    01838             //---------------------
    01839             bool bResolutionFound = false;
    01840             for( int idm = 0; idm < deviceCombo.adapterInformation.displayModeList.Count; idm++ )
    01841             {
    01842                 DisplayMode displayMode = (DisplayMode)deviceCombo.adapterInformation.displayModeList[idm];
    01843                 if (displayMode.Format != deviceCombo.AdapterFormat )
    01844                     continue;
    01845                 if (displayMode.Width == settings.presentParams.BackBufferWidth &&
    01846                     displayMode.Height == settings.presentParams.BackBufferHeight )
    01847                     bResolutionFound = true;
    01848             }
    01849             if (bResolutionFound )
    01850                 currentRanking += resolutionWeight;
    01851
    01852             //---------------------
    01853             // Back buffer format
    01854             //---------------------
    01855             if (deviceCombo.BackBufferFormat == settings.presentParams.BackBufferFormat )
    01856             {
    01857                 currentRanking += backBufferFormatWeight;
    01858             }
    01859             else
    01860             {
    01861                 int bitDepthDelta = Math.Abs((int)ManagedUtility.GetColorChannelBits(deviceCombo.BackBufferFormat) -
    01862                     (int)ManagedUtility.GetColorChannelBits(settings.presentParams.BackBufferFormat) );
    01863                 float scale = Math.Max(0.9f - (float)bitDepthDelta*0.2f, 0);
    01864                 currentRanking += scale * backBufferFormatWeight;
    01865             }
    01866
    01867             // Check if this back buffer format is the same as
    01868             // the adapter format since this is preferred.
    01869             bool bAdapterMatchesBB = (deviceCombo.BackBufferFormat == deviceCombo.AdapterFormat);
    01870             if (bAdapterMatchesBB )
    01871                 currentRanking += 0.1f;
    01872
    01873             //---------------------
    01874             // Back buffer count
    01875             //---------------------
    01876             // No caps for the back buffer count
    01877
    01878             //---------------------
    01879             // Multisample
    01880             //---------------------
    01881             bool bMultiSampleFound = false;
    01882             for( int i=0; i<deviceCombo.multiSampleTypeList.Count; i++ )
    01883             {
    01884                 MultiSampleType msType = (MultiSampleType)deviceCombo.multiSampleTypeList[i];
    01885                 uint msQuality  = (uint)(int)deviceCombo.multiSampleQualityList[i];
    01886
    01887                 if (msType == settings.presentParams.MultiSample &&
    01888                     msQuality >= settings.presentParams.MultiSampleQuality )
    01889                 {
    01890                     bMultiSampleFound = true;
    01891                     break;
    01892                 }
    01893             }
    01894             if (bMultiSampleFound )
    01895                 currentRanking += multiSampleWeight;
    01896
    01897             //---------------------
    01898             // Swap effect
    01899             //---------------------
    01900             // No caps for swap effects
    01901
    01902             //---------------------
    01903             // Depth stencil
    01904             //---------------------
    01905             if (deviceCombo.depthStencilFormatList.Contains( settings.presentParams.AutoDepthStencilFormat ) )
    01906                 currentRanking += depthStencilWeight;
    01907
    01908             //---------------------
    01909             // Present flags
    01910             //---------------------
    01911             // No caps for the present flags
    01912
    01913             //---------------------
    01914             // Refresh rate
    01915             //---------------------
    01916             bool bRefreshFound = false;
    01917             for( int idm = 0; idm < deviceCombo.adapterInformation.displayModeList.Count; idm++ )
    01918             {
    01919                 DisplayMode displayMode = (DisplayMode)deviceCombo.adapterInformation.displayModeList[idm];
    01920                 if (displayMode.Format != deviceCombo.AdapterFormat )
    01921                     continue;
    01922                 if (displayMode.RefreshRate == settings.presentParams.FullScreenRefreshRateInHz )
    01923                     bRefreshFound = true;
    01924             }
    01925             if (bRefreshFound )
    01926                 currentRanking += refreshRateWeight;
    01927
    01928             //---------------------
    01929             // Present interval
    01930             //---------------------
    01931             // If keep present interval then check that the present interval is supported by this combo
    01932             if (deviceCombo.presentIntervalList.Contains( settings.presentParams.PresentationInterval ) )
    01933                 currentRanking += presentIntervalWeight;
    01934
    01935             return currentRanking;
    01936         }
    01937
    01941         private DisplayMode FindValidResolution(EnumDeviceSettingsCombo deviceCombo, DisplayMode displayMode)
    01942         {
    01943             DisplayMode bestDisplayMode = displayMode;
    01944
    01945             if (deviceCombo.IsWindowed)
    01946             {
    01947                 // Get the desktop resolution of the current monitor to use to keep the window
    01948                 // in a reasonable size in the desktop's
    01949                 // This isn't the same as the current resolution from GetAdapterDisplayMode
    01950                 // since the device might be fullscreen
    01951                 EnumAdapterInformation adapterInfo = Enumeration.GetAdapterInformation(deviceCombo.AdapterOrdinal);
    01952                 // Find the right screen
    01953                 System.Windows.Forms.Screen displayScreen = null;
    01954                 string adapterName = adapterInfo.AdapterInformation.DeviceName.ToLower();
    01955                 foreach(System.Windows.Forms.Screen s in System.Windows.Forms.Screen.AllScreens)
    01956                 {
    01957                     string deviceName = s.DeviceName.ToLower();
    01958                     // For some reason the device name has null characters in it.  Remove them
    01959                     if (deviceName.IndexOf("\0") > 0)
    01960                     {
    01961                         deviceName = deviceName.Substring(0, deviceName.IndexOf("\0"));
    01962                     }
    01963                     if (deviceName == adapterName)
    01964                     {
    01965                         // Found the correct screen
    01966                         displayScreen = s;
    01967                         break;
    01968                     }
    01969                 }
    01970                 System.Diagnostics.Debug.Assert(displayScreen != null, "We should have found the screen by now.");
    01971
    01972                 // For windowed mode, just keep it something reasonable within the size
    01973                 // of the working area of the desktop
    01974                 if (bestDisplayMode.Width > displayScreen.WorkingArea.Width )
    01975                     bestDisplayMode.Width = displayScreen.WorkingArea.Width;
    01976                 if (bestDisplayMode.Height > displayScreen.WorkingArea.Height )
    01977                     bestDisplayMode.Height = displayScreen.WorkingArea.Height;
    01978
    01979             }
    01980             else
    01981             {
    01982                 int bestRanking = 100000;
    01983                 int currentRanking;
    01984                 for( int iDisplayMode=0; iDisplayMode<deviceCombo.adapterInformation.displayModeList.Count; iDisplayMode++ )
    01985                 {
    01986                     DisplayMode storedMode = (DisplayMode)deviceCombo.adapterInformation.displayModeList[iDisplayMode];
    01987
    01988                     // Skip display modes that don't match the combo's adapter format
    01989                     if (storedMode.Format != deviceCombo.AdapterFormat )
    01990                         continue;
    01991
    01992                     // Find the delta between the current width/height and the optimal width/height
    01993                     currentRanking = Math.Abs((int)storedMode.Width - (int)displayMode.Width) +
    01994                         Math.Abs((int)storedMode.Height- (int)displayMode.Height);
    01995
    01996                     if (currentRanking < bestRanking )
    01997                     {
    01998                         bestDisplayMode = displayMode;
    01999                         bestRanking = currentRanking;
    02000
    02001                         // Stop if perfect match found
    02002                         if (bestRanking == 0 )
    02003                             break;
    02004                     }
    02005                 }
    02006
    02007                 // Were any found?
    02008                 if (bestDisplayMode.Width == 0 )
    02009                 {
    02010                     throw new NoCompatibleDevicesException();
    02011                 }
    02012             }
    02013
    02014             return bestDisplayMode;
    02015         }
    02016
    02023         private void ChangeDevice(DeviceSettings newDeviceSettings, Device deviceFromApp, bool forceRecreate)
    02024         {
    02025             // Nothing to do if the framework is already disposed
    02026             if (isDisposed)
    02027                 return;
    02028
    02029             // First store the current device settings
    02030             DeviceSettings oldSettings = null;
    02031             if (State.CurrentDeviceSettings != null)
    02032                 oldSettings = State.CurrentDeviceSettings.Clone();
    02033
    02034             // Pause the application
    02035             Pause(true, true);
    02036
    02037             // When a size message is received, it calls HandlePossibleSizeChange().
    02038             // A size message might be sent when adjusting the window, so tell
    02039             // HandlePossibleSizeChange() to ignore size changes temporarily
    02040             State.AreSizeChangesIgnored = true;
    02041
    02042             // Only apply the cmd line overrides if this is the first device created
    02043             // and SetDevice() isn't used
    02044             if ( (deviceFromApp == null) && (oldSettings == null) )
    02045             {
    02046                 // Updates the device settings struct based on the cmd line args.
    02047                 // Warning: if the device doesn't support these new settings then CreateDevice() will fail.
    02048                 UpdateDeviceSettingsWithOverrides(ref newDeviceSettings);
    02049             }
    02050
    02051             // If windowed, then update the window client rect and window bounds rect
    02052             // with the new pp.BackBufferWidth & pp.BackBufferHeight
    02053             // The window will be resized after the device is reset/creeted
    02054             if (newDeviceSettings.presentParams.Windowed)
    02055             {
    02056                 // Don't allow smaller than what's used in minimum window size
    02057                 // otherwise the window size will be different than the backbuffer size
    02058                 if (newDeviceSettings.presentParams.BackBufferWidth < MinimumWindowSizeX)
    02059                     newDeviceSettings.presentParams.BackBufferWidth = MinimumWindowSizeX;
    02060                 if (newDeviceSettings.presentParams.BackBufferHeight < MinimumWindowSizeY)
    02061                     newDeviceSettings.presentParams.BackBufferHeight = MinimumWindowSizeY;
    02062
    02063                 if (State.WindowFocus != null)
    02064                 {
    02065                     // Create a new client rectangle of the correct size
    02066                     System.Drawing.Rectangle windowClient = State.ClientRectangle;
    02067                     windowClient.Size = new System.Drawing.Size(newDeviceSettings.presentParams.BackBufferWidth, newDeviceSettings.presentParams.BackBufferHeight);
    02068
    02069                     State.ClientRectangle = windowClient; // Store this for resizing later
    02070                     State.WindowBoundsRectangle = WindowFocus.Bounds;;
    02071                 }
    02072             }
    02073
    02074             // Set the new device settings
    02075             State.CurrentDeviceSettings = newDeviceSettings;
    02076
    02077
    02078             // If AdapterOrdinal and DeviceType are the same, we can just do a Reset().
    02079             // If they've changed, we need to do a complete device tear down/rebuild.
    02080             // Also only allow a reset if deviceFromApp is the same as the current device
    02081             if( !forceRecreate &&
    02082                 (deviceFromApp == null || deviceFromApp == State.Device) &&
    02083                 oldSettings != null &&
    02084                 oldSettings.AdapterOrdinal == newDeviceSettings.AdapterOrdinal &&
    02085                 oldSettings.DeviceType == newDeviceSettings.DeviceType &&
    02086                 oldSettings.BehaviorFlags == newDeviceSettings.BehaviorFlags )
    02087             {
    02088                 try
    02089                 {
    02090                     // Reset the Direct3D device
    02091                     Reset3DEnvironment();
    02092                 }
    02093                 catch
    02094                 {
    02095                     // The reset has failed, the device is lost
    02096                     Pause (false, false);
    02097                     State.IsDeviceLost = true;
    02098                 }
    02099             }
    02100             else
    02101             {
    02102                 // Recreate the device
    02103                 if (oldSettings != null)
    02104                 {
    02105                     // The adapter and device type don't match so
    02106                     // cleanup and create the 3D device again
    02107                     Cleanup3DEnvironment(false);
    02108                 }
    02109
    02110                 Device device = deviceFromApp;
    02111                 // Only create a Direct3D device if one hasn't been supplied by the app
    02112                 if (deviceFromApp == null)
    02113                 {
    02114                     try
    02115                     {
    02116                         device = new Device((int)newDeviceSettings.AdapterOrdinal, newDeviceSettings.DeviceType,
    02117                             State.WindowFocus, newDeviceSettings.BehaviorFlags,
    02118                             newDeviceSettings.presentParams);
    02119                     }
    02120                     catch (Exception e)
    02121                     {
    02122                         // There was an error creating the device
    02123                         Pause(false, false);
    02124                         CreatingDeviceException cde = new CreatingDeviceException(e);
    02125                         DisplayErrorMessage(cde);
    02126                         throw;
    02127                     }
    02128                 }
    02129
    02130                 // Hook the device lost/reset events
    02131                 device.DeviceLost += new EventHandler(OnDeviceLost);
    02132                 device.DeviceReset += new EventHandler(OnDeviceReset);
    02133                 device.Disposing += new EventHandler(OnDeviceDisposing);
    02134
    02135                 // Store the device
    02136                 State.Device = device;
    02137
    02138                 // Now that the device is created, update the window and misc settings and
    02139                 // call the app's DeviceCreated and DeviceReset callbacks.
    02140                 try
    02141                 {
    02142                     Initialize3DEnvironment();
    02143                 }
    02144                 catch
    02145                 {
    02146                     Pause(false, false);
    02147                     throw;
    02148                 }
    02149                 // Update the device stats text
    02150                 Enumeration.Enumerate(null);
    02151                 EnumAdapterInformation adapterInfo = Enumeration.GetAdapterInformation(newDeviceSettings.AdapterOrdinal);
    02152                 UpdateDeviceStats(newDeviceSettings.DeviceType, newDeviceSettings.BehaviorFlags, adapterInfo.AdapterInformation);
    02153             }
    02154
    02155             // Get the adapter monitor
    02156             State.AdapterMonitor = Manager.GetAdapterMonitor((int)newDeviceSettings.AdapterOrdinal);
    02157
    02158             // When moving from full screen to windowed mode, it is important to
    02159             // adjust the window size after resetting the device rather than
    02160             // beforehand to ensure that you get the window size you want.  For
    02161             // example, when switching from 640x480 full screen to windowed with
    02162             // a 1000x600 window on a 1024x768 desktop, it is impossible to set
    02163             // the window size to 1000x600 until after the display mode has
    02164             // changed to 1024x768, because windows cannot be larger than the
    02165             // desktop.
    02166             if (newDeviceSettings.presentParams.Windowed)
    02167             {
    02168                 if (State.WindowFocus == null)
    02169                 {
    02170                     System.Drawing.Rectangle rect = State.WindowBoundsRectangle;
    02171
    02172                     // Resize the window
    02173                     System.Drawing.Point pt = rect.Location;
    02174                     pt = Window.PointToScreen(pt);
    02175
    02176                     if (!State.IsMaximized)
    02177                     {
    02178                         Window.SetBounds(pt.X, pt.Y, rect.Width, rect.Height, System.Windows.Forms.BoundsSpecified.All);
    02179                     }
    02180
    02181
    02182
    02183                     // Check to see if the monitor has changed windows
    02184                     NativeMethods.MonitorInformation infoAdapter = new NativeMethods.MonitorInformation();
    02185                     // Set size
    02186                     infoAdapter.Size = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(NativeMethods.MonitorInformation));
    02187                     NativeMethods.GetMonitorInfo(State.AdapterMonitor, ref infoAdapter);
    02188                     // Calculate width/height, this needs to happen because the unmanaged RECT structure is different than the managed Rectangle
    02189                     int monitorWidth = infoAdapter.WorkRectangle.Right - infoAdapter.WorkRectangle.Left;
    02190                     int monitorHeight = infoAdapter.WorkRectangle.Bottom - infoAdapter.WorkRectangle.Top;
    02191
    02192                     // Get the monitor this app is on
    02193                     IntPtr monitorHandle = NativeMethods.MonitorFromWindow(Window.Handle, 1); // Default to primary
    02194                     NativeMethods.MonitorInformation infoWindow = new NativeMethods.MonitorInformation();
    02195                     // Set size
    02196                     infoWindow.Size = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(NativeMethods.MonitorInformation));
    02197                     NativeMethods.GetMonitorInfo(monitorHandle, ref infoWindow);
    02198
    02199                     rect = State.WindowBoundsRectangle;
    02200                     int windowOffsetX = rect.Left - infoWindow.MonitorRectangle.Left;
    02201                     int windowOffsetY = rect.Top - infoWindow.MonitorRectangle.Top;
    02202                     int windowWidth = rect.Right - rect.Left;
    02203                     int windowHeight = rect.Bottom - rect.Top;
    02204
    02205                     if (State.IsWindowCreatedWithDefaultPositions)
    02206                     {
    02207                         // Since the window was created with a default window position
    02208                         // center it in the work area if its outside the monitor's work area
    02209
    02210                         // Only do this the first time.
    02211                         State.IsWindowCreatedWithDefaultPositions = false;
    02212
    02213                         // Center window if the bottom or right of the window is outside the monitor's work area
    02214                         if (infoAdapter.WorkRectangle.Left + windowOffsetX + windowWidth > infoAdapter.WorkRectangle.Right)
    02215                             windowOffsetX = (monitorWidth - windowWidth) / 2;
    02216                         if (infoAdapter.WorkRectangle.Top + windowOffsetY + windowHeight > infoAdapter.WorkRectangle.Bottom)
    02217                             windowOffsetY = (monitorHeight - windowHeight) / 2;
    02218                     }
    02219
    02220                     // Move & show the window
    02221                     pt.X = infoAdapter.MonitorRectangle.Left + windowOffsetX;
    02222                     pt.Y = infoAdapter.MonitorRectangle.Top + windowOffsetY;
    02223                 }
    02224
    02225             }
    02226             else
    02227             {
    02228                 // Just store the full screen client rectangle
    02229                 State.FullScreenClientRectangle = new System.Drawing.Rectangle(0,0, newDeviceSettings.presentParams.BackBufferWidth,
    02230                     newDeviceSettings.presentParams.BackBufferHeight);
    02231             }
    02232
    02233             // Done creating the device
    02234             State.AreSizeChangesIgnored = false;
    02235             Pause(false, false);
    02236             State.WasDeviceCreated = true;
    02237         }
    02238
    02242         private void UpdateDeviceStats(DeviceType deviceType, CreateFlags behaviorFlags, AdapterDetails info)
    02243         {
    02244             if (State.AreStatsHidden)
    02245                 return; // Do nothing if stats are hidden
    02246
    02247             // Get the behavior flags
    02248             BehaviorFlags flags = new BehaviorFlags(behaviorFlags);
    02249             // Store device information
    02250             System.Text.StringBuilder builder = new System.Text.StringBuilder();
    02251             // Append device type
    02252             builder.Append(deviceType.ToString());
    02253             // Append other types based on flags
    02254             if (flags.HardwareVertexProcessing && flags.PureDevice)
    02255             {
    02256                 if (deviceType == DeviceType.Hardware)
    02257                     builder.Append(" (pure hw vp)");
    02258                 else
    02259                     builder.Append(" (simulated pure hw vp)");
    02260             }
    02261             else if (flags.HardwareVertexProcessing)
    02262             {
    02263                 if (deviceType == DeviceType.Hardware)
    02264                     builder.Append(" (hw vp)");
    02265                 else
    02266                     builder.Append(" (simulated hw vp)");
    02267             }
    02268             else if (flags.MixedVertexProcessing)
    02269             {
    02270                 if (deviceType == DeviceType.Hardware)
    02271                     builder.Append(" (mixed vp)");
    02272                 else
    02273                     builder.Append(" (simulated mixed vp)");
    02274             }
    02275             else if (flags.SoftwareVertexProcessing)
    02276             {
    02277                 builder.Append(" (sw vp)");
    02278             }
    02279
    02280             // now add the description
    02281             builder.Append(": ");
    02282             builder.Append(info.Description);
    02283
    02284             // Store the device stats string
    02285             State.DeviceStats = builder.ToString();
    02286         }
    02287
    02291         private void UpdateDeviceSettingsWithOverrides(ref DeviceSettings settings)
    02292         {
    02293             if (State.OverrideAdapterOrdinal != -1)
    02294                 settings.AdapterOrdinal = (uint)State.OverrideAdapterOrdinal;
    02295
    02296             if (State.IsOverridingFullScreen)
    02297                 settings.presentParams.Windowed = false;
    02298             if (State.IsOverridingWindowed)
    02299                 settings.presentParams.Windowed = true;
    02300
    02301             if (State.IsOverridingForceReference)
    02302                 settings.DeviceType = DeviceType.Reference;
    02303             else if (State.IsOverridingForceHardware)
    02304                 settings.DeviceType = DeviceType.Hardware;
    02305
    02306             if (State.OverrideWidth != 0)
    02307                 settings.presentParams.BackBufferWidth = State.OverrideWidth;
    02308             if (State.OverrideHeight != 0)
    02309                 settings.presentParams.BackBufferHeight = State.OverrideHeight;
    02310
    02311             if (State.IsOverridingForcePureHardwareVertexProcessing)
    02312             {
    02313                 settings.BehaviorFlags &= ~CreateFlags.SoftwareVertexProcessing;
    02314                 settings.BehaviorFlags |= CreateFlags.HardwareVertexProcessing;
    02315                 settings.BehaviorFlags |= CreateFlags.PureDevice;
    02316             }
    02317             else if (State.IsOverridingForceHardwareVertexProcessing)
    02318             {
    02319                 settings.BehaviorFlags &= ~CreateFlags.SoftwareVertexProcessing;
    02320                 settings.BehaviorFlags &= ~CreateFlags.PureDevice;
    02321                 settings.BehaviorFlags |= CreateFlags.HardwareVertexProcessing;
    02322             }
    02323             else if (State.IsOverridingForceSoftwareVertexProcessing)
    02324             {
    02325                 settings.BehaviorFlags &= ~CreateFlags.HardwareVertexProcessing;
    02326                 settings.BehaviorFlags &= ~CreateFlags.PureDevice;
    02327                 settings.BehaviorFlags |= CreateFlags.SoftwareVertexProcessing;
    02328             }
    02329         }
    02330
    02331
    02340         public void Reset3DEnvironment()
    02341         {
    02342             Device device = State.Device;
    02343             System.Diagnostics.Debug.Assert(device != null, "The device should not be null here.");
    02344             if (device == null)
    02345                 throw new InvalidOperationException("The device should not be null.");
    02346
    02347             // Fire the event if required
    02348             if (DeviceLost != null)
    02349                 DeviceLost(this, EventArgs.Empty);
    02350
    02351             // Prepare the window for a possible change between windowed mode
    02352             // and full screen mode by adjusting the window style and its menu.
    02353             AdjustWindowStyle(Window, IsWindowed);
    02354
    02355             try
    02356             {
    02357                 // If the settings dialog exists call its OnResetDevice()
    02358                 // Reset the device
    02359                 device.Reset(State.CurrentDeviceSettings.presentParams);
    02360             }
    02361             catch  (Exception e)
    02362             {
    02363                 if (e is MediaNotFoundException)
    02364                     DisplayErrorMessage(e as MediaNotFoundException);
    02365                 else
    02366                 {
    02367                     // Reset could legitimately fail if the device is lost
    02368                     if (!(e is DeviceLostException))
    02369                     {
    02370                         DisplayErrorMessage(new ResettingDeviceException(e));
    02371                     }
    02372                 }
    02373
    02374                 // We failed, call the lost callback once more
    02375                 OnDeviceLost(null, EventArgs.Empty);
    02376                 if (!(e is DeviceLostException))
    02377                 {
    02378                     throw;
    02379                 }
    02380             }
    02381         }
    02382
    02391         public void Render3DEnvironment()
    02392         {
    02393             Device device = State.Device;
    02394             if (device == null)
    02395                 return; // Nothing to do
    02396
    02397             if (State.IsDeviceLost || State.IsRenderingPaused)
    02398             {
    02399                 // Window is minimized or paused so yield
    02400                 // CPU time to other processes
    02401                 System.Threading.Thread.Sleep(100);
    02402             }
    02403
    02404             if (!State.IsActive)
    02405             {
    02406                 // Window is not in focus so yield some CPU time to other processes
    02407                 System.Threading.Thread.Sleep(20);
    02408             }
    02409
    02410             if (State.IsDeviceLost && !State.IsRenderingPaused)
    02411             {
    02412                 int result;
    02413                 // Check the cooperative level to see if it's ok to render
    02414                 if (!device.CheckCooperativeLevel(out result))
    02415                 {
    02416                     if (result == (int)ResultCode.DeviceLost)
    02417                     {
    02418                         // The device has been lost but cannot be reset at this time.
    02419                         // So wait until it can be reset.
    02420                         System.Threading.Thread.Sleep(50);
    02421                         return;
    02422                     }
    02423
    02424                     // If we are windowed, read the desktop format and
    02425                     // ensure that the Direct3D device is using the same format
    02426                     // since the user could have changed the desktop bitdepth
    02427                     if (IsWindowed)
    02428                     {
    02429                         DisplayMode adapterDesktopMode = Manager.Adapters[(int)State.CurrentDeviceSettings.AdapterOrdinal].CurrentDisplayMode;
    02430                         if (State.CurrentDeviceSettings.AdapterFormat != adapterDesktopMode.Format)
    02431                         {
    02432                             // Set up the match options
    02433                             MatchOptions match = new MatchOptions();
    02434                             match.AdapterOrdinal = MatchType.PreserveInput;
    02435                             match.DeviceType = MatchType.PreserveInput;
    02436                             match.Windowed = MatchType.PreserveInput;
    02437                             match.AdapterFormat = MatchType.PreserveInput;
    02438                             match.VertexProcessing = MatchType.ClosestToInput;
    02439                             match.Resolution = MatchType.ClosestToInput;
    02440                             match.BackBufferFormat = MatchType.ClosestToInput;
    02441                             match.BackBufferCount = MatchType.ClosestToInput;
    02442                             match.MultiSample = MatchType.ClosestToInput;
    02443                             match.SwapEffect = MatchType.ClosestToInput;
    02444                             match.DepthFormat = MatchType.ClosestToInput;
    02445                             match.StencilFormat = MatchType.ClosestToInput;
    02446                             match.PresentFlags = MatchType.ClosestToInput;
    02447                             match.RefreshRate = MatchType.ClosestToInput;
    02448                             match.PresentInterval = MatchType.ClosestToInput;
    02449
    02450                             DeviceSettings settings = State.CurrentDeviceSettings;
    02451                             settings.AdapterFormat = adapterDesktopMode.Format;
    02452                             try
    02453                             {
    02454                                 settings = FindValidDeviceSettings(settings, match);
    02455                                 // Change to a Direct3D device created from the new device settings.
    02456                                 // If there is an existing device, then either reset or recreate the scene
    02457                                 ChangeDevice(settings, null, false);
    02458                             }
    02459                             catch
    02460                             {
    02461                                 DisplayErrorMessage(new NoCompatibleDevicesException());
    02462                                 Dispose();
    02463                             }
    02464                             return;
    02465                         }
    02466                     }
    02467
    02468                     // Try to reset the device
    02469                     try
    02470                     {
    02471                         Reset3DEnvironment();
    02472                     }
    02473                     catch (DeviceLostException)
    02474                     {
    02475                         // The device was lost again, so continue waiting until it can be reset.
    02476                         System.Threading.Thread.Sleep(50);
    02477                         return;
    02478                     }
    02479                     catch
    02480                     {
    02481                         // Reset failed, but the device wasn't lost so something bad happened,
    02482                         // so recreate the device to try to recover
    02483                         DeviceSettings deviceSettings = State.CurrentDeviceSettings;
    02484                         try
    02485                         {
    02486                             ChangeDevice(deviceSettings, null, false);
    02487                         }
    02488                         catch (Exception e)
    02489                         {
    02490                             ResettingDeviceException rde = new ResettingDeviceException(e);
    02491                             DisplayErrorMessage(rde);
    02492                             Dispose();
    02493                             throw;
    02494                         }
    02495                     }
    02496                 }
    02497                 State.IsDeviceLost = false;
    02498             }
    02499
    02500             // Get the app's time, in seconds. Skip rendering if no time elapsed
    02501             double time = FrameworkTimer.GetTime();
    02502             float elapsedTime = (float)FrameworkTimer.GetElapsedTime();
    02503
    02504             // Store the time for the app
    02505             if (State.IsUsingConstantFrameTime)
    02506             {
    02507                 elapsedTime = State.TimePerFrame;
    02508                 time = State.CurrentTime + elapsedTime;
    02509             }
    02510
    02511             State.CurrentTime = time;
    02512             State.ElapsedTime = elapsedTime;
    02513
    02514             // Update the FPS stats
    02515             UpdateFrameStats();
    02516
    02517             // If the settings dialog exists and is being shown, then
    02518             // render it instead of rendering the app's scene
    02519             if (State.Settings != null && State.IsD3DSettingsDialogShowing)
    02520             {
    02521                 if (!State.IsRenderingPaused)
    02522                 {
    02523                     // Clear the render target and the zbuffer
    02524                     device.Clear(ClearFlags.Target, 0x00003F3F, 1.0f, 0);
    02525
    02526                     // Render the scene
    02527                     device.BeginScene();
    02528                     State.Settings.OnRender(elapsedTime);
    02529                     device.EndScene();
    02530                 }
    02531             }
    02532             else
    02533             {
    02534                 HandleTimers();
    02535
    02536                 //Animate the scene by calling the app's frame move callback
    02537                 if (State.CallbackInterface != null)
    02538                 {
    02539                     State.CallbackInterface.OnFrameMove(device, time, elapsedTime);
    02540                     device = State.Device;
    02541                     if (device == null)
    02542                         return;
    02543                 }
    02544
    02545                 if (!State.IsRenderingPaused)
    02546                 {
    02547                     // Render the scene by calling the app's render callback
    02548                     if (State.CallbackInterface != null)
    02549                     {
    02550                         State.CallbackInterface.OnFrameRender(device, time, elapsedTime);
    02551                         device = State.Device;
    02552                         if (device == null)
    02553                             return;
    02554                     }
    02555                 }
    02556             }
    02557
    02558             if (!State.IsRenderingPaused)
    02559             {
    02560                 // Show the frame on the primary surface
    02561                 try
    02562                 {
    02563                     device.Present();
    02564                 }
    02565                 catch (DeviceLostException)
    02566                 {
    02567                     // Whoops, device is lost now
    02568                     State.IsDeviceLost = true;
    02569                 }
    02570                 catch (DriverInternalErrorException)
    02571                 {
    02572                     // When DriverInternalErrorException is thrown from Present(),
    02573                     // the application can do one of the following:
    02574                     //
    02575                     // - End, with the pop-up window saying that the application cannot continue
    02576                     //   because of problems in the display adapter and that the user should
    02577                     //   contact the adapter manufacturer.
    02578                     //
    02579                     // - Attempt to restart by calling Device.Reset, which is essentially the same
    02580                     //   path as recovering from a lost device. If Device.Reset throws the
    02581                     //   DriverInternalErrorException, the application should end immediately with the
    02582                     //   message that the user should contact the adapter manufacturer.
    02583                     //
    02584                     // The framework attempts the path of resetting the device
    02585                     //
    02586                     State.IsDeviceLost = true;
    02587                 }
    02588             }
    02589
    02590             // Update the current frame number
    02591             State.CurrentFrameNumber++;
    02592
    02593             if (State.OverrideQuitAfterFrame != 0)
    02594             {
    02595                 if (State.CurrentFrameNumber > State.OverrideQuitAfterFrame)
    02596                     Dispose();
    02597             }
    02598         }
    02599
    02603         private void Shutdown()
    02604         {
    02605             // Cleanup the environment
    02606             Cleanup3DEnvironment(true);
    02607             // Close the window
    02608             if (Window != null)
    02609             {
    02610                 if (WindowForm != null)
    02611                 {
    02612                     WindowForm.Close();
    02613                 }
    02614             }
    02615         }
    02616
    02620         public void Pause(bool pauseTime, bool pauseRendering)
    02621         {
    02622             // Update counters
    02623             State.PauseTimeCount += pauseTime ? +1 : -1;
    02624             if (State.PauseTimeCount < 0)
    02625                 State.PauseTimeCount = 0;
    02626
    02627             State.PauseRenderingCount += pauseRendering ? +1 : -1;
    02628             if (State.PauseRenderingCount < 0)
    02629                 State.PauseRenderingCount = 0;
    02630
    02631             if (State.PauseTimeCount > 0)
    02632             {
    02633                 // Stop the scene from animating
    02634                 FrameworkTimer.Stop();
    02635             }
    02636             else
    02637             {
    02638                 // Restart the timer
    02639                 FrameworkTimer.Start();
    02640             }
    02641
    02642             State.IsRenderingPaused = (State.PauseRenderingCount > 0);
    02643             State.IsTimePaused = (State.PauseTimeCount > 0);
    02644         }
    02645
    02646
    02650         public void DisplayErrorMessage(Exception e)
    02651         {
    02652             if (e == lastDisplayedMessage)
    02653                 return; //Already displayed this
    02654
    02655             lastDisplayedMessage = e;
    02656
    02657             State.ApplicationExitCode = 1;
    02658             bool found = true;
    02659             if (e is ApplicationException)
    02660             {
    02661                 if (e is NoDirect3DException)
    02662                     State.ApplicationExitCode = 2;
    02663                 else if (e is MediaNotFoundException)
    02664                     State.ApplicationExitCode = 4;
    02665                 else if (e is CreatingDeviceException)
    02666                     State.ApplicationExitCode = 6;
    02667                 else if (e is ResettingDeviceException)
    02668                     State.ApplicationExitCode = 7;
    02669                 else if (e is CreatingDeviceObjectsException)
    02670                     State.ApplicationExitCode = 8;
    02671                 else if (e is ResettingDeviceObjectsException)
    02672                     State.ApplicationExitCode = 9;
    02673                 else if (e is NoCompatibleDevicesException)
    02674                     State.ApplicationExitCode = 3;
    02675                 else
    02676                     found = false;
    02677             }
    02678             else
    02679                 found = false;
    02680
    02681             string errorText = string.Empty;
    02682             if (found && State.IsShowingMsgBoxOnError)
    02683             {
    02684                 errorText = e.Message;
    02685                 if (e.InnerException != null)
    02686                 {
    02687                     errorText += "\r\n\r\n" + e.InnerException.ToString();
    02688                     lastDisplayedMessage = e.InnerException;
    02689                 }
    02690
    02691                 if (State.WindowTitle != null && State.WindowTitle.Length > 0)
    02692                     System.Windows.Forms.MessageBox.Show(errorText, "DirectX Application",
    02693                         System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
    02694                 else
    02695                     System.Windows.Forms.MessageBox.Show(errorText, State.WindowTitle,
    02696                         System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
    02697             }
    02698             else if (!found && State.IsShowingMsgBoxOnError)
    02699             {
    02700                 errorText = e.ToString();
    02701                 // Unknown error, but they still want to see them
    02702                 if (State.WindowTitle != null && State.WindowTitle.Length > 0)
    02703                     System.Windows.Forms.MessageBox.Show(errorText, "DirectX Application",
    02704                         System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
    02705                 else
    02706                     System.Windows.Forms.MessageBox.Show(errorText, State.WindowTitle,
    02707                         System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
    02708             }
    02709         }
    02710
    02717         private void Cleanup3DEnvironment(bool releaseSettings)
    02718         {
    02719             DialogResourceManager.GetGlobalInstance().OnLostDevice();
    02720             DialogResourceManager.GetGlobalInstance().OnDestroyDevice();
    02721             ResourceCache.GetGlobalInstance().OnLostDevice();
    02722             ResourceCache.GetGlobalInstance().OnDestroyDevice();
    02723             if (State.Settings != null)
    02724             {
    02725                 State.Settings.OnLostDevice();
    02726                 State.Settings.OnDestroyDevice( this, EventArgs.Empty);
    02727             }
    02728
    02729             using(Device device = State.Device)
    02730             {
    02731                 if (releaseSettings)
    02732                 {
    02733                     // Get rid of settings
    02734                     State.CurrentDeviceSettings = null;
    02735                 }
    02736
    02737                 // Empty out other structures
    02738                 State.BackBufferSurfaceDesc = new SurfaceDescription();
    02739                 State.Caps = new Caps();
    02740                 State.WasDeviceCreated = false;
    02741             }
    02742             // No more device
    02743             State.Device = null;
    02744         }
    02745
    02755         private void Initialize3DEnvironment()
    02756         {
    02757             Device device = State.Device;
    02758             System.Diagnostics.Debug.Assert(device != null, "The device should not be null here.");
    02759             if (device == null)
    02760                 throw new InvalidOperationException("The device should not be null.");
    02761
    02762             bool success = true;
    02763             try
    02764             {
    02765                 State.AreDeviceObjectsCreated = false;
    02766                 State.AreDeviceObjectsReset = false;
    02767
    02768                 // Prepare the window for a possible change between windowed mode
    02769                 // and full screen mode by adjusting the window style and its menu.
    02770                 AdjustWindowStyle(Window, IsWindowed);
    02771
    02772                 // Prepare the device with cursor info and
    02773                 // store backbuffer desc and caps from the device
    02774                 PrepareDevice(device);
    02775
    02776                 try
    02777                 {
    02778                     // If the settings dialog exists call its OnCreateDevice() and OnResetDevice()
    02779                     if (State.Settings != null)
    02780                     {
    02781                         State.Settings.OnCreateDevice(device);
    02782                         State.Settings.OnResetDevice();
    02783                     }
    02784                     // Call the dialog resource manager create device method
    02785                     DialogResourceManager.GetGlobalInstance().OnCreateDevice(device);
    02786
    02787                     // Call the resource cache created function
    02788                     ResourceCache.GetGlobalInstance().OnCreateDevice(device);
    02789
    02790                     // Call the applications device created callback if it's set
    02791                     State.IsInsideDeviceCallback = true;
    02792                     if (DeviceCreated != null)
    02793                     {
    02794                         DeviceCreated(this, new DeviceEventArgs(device, State.BackBufferSurfaceDesc));
    02795                     }
    02796                     State.IsInsideDeviceCallback = false;
    02797                     State.AreDeviceObjectsCreated = true;
    02798                 }
    02799                 catch (MediaNotFoundException e)
    02800                 {
    02801                     DisplayErrorMessage(e);
    02802                     success = false;
    02803                     throw;
    02804                 }
    02805                 catch (Exception e)
    02806                 {
    02807                     DisplayErrorMessage(new CreatingDeviceException(e));
    02808                     success = false;
    02809                     throw;
    02810                 }
    02811
    02812                 try
    02813                 {
    02814                     // Call the dialog resource manager reset device method
    02815                     DialogResourceManager.GetGlobalInstance().OnResetDevice(device);
    02816
    02817                     // Call the resource cache device reset function
    02818                     ResourceCache.GetGlobalInstance().OnResetDevice(device);
    02819
    02820                     // Call app's reset
    02821                     State.IsInsideDeviceCallback = true;
    02822                     if (DeviceReset != null)
    02823                         DeviceReset(this, new DeviceEventArgs(device, State.BackBufferSurfaceDesc));
    02824
    02825                     State.IsInsideDeviceCallback = false;
    02826                     State.AreDeviceObjectsReset = true;
    02827                 }
    02828                 catch (MediaNotFoundException e)
    02829                 {
    02830                     DisplayErrorMessage(e);
    02831                     success = false;
    02832                     throw;
    02833                 }
    02834                 catch (Exception e)
    02835                 {
    02836                     DisplayErrorMessage(new CreatingDeviceException(e));
    02837                     success = false;
    02838                     throw;
    02839                 }
    02840             }
    02841             finally
    02842             {
    02843                 if (!success)
    02844                     Cleanup3DEnvironment(true);
    02845             }
    02846
    02847         }
    02848
    02853         private void PrepareDevice(Device device)
    02854         {
    02855             // Update the device stats text
    02856             UpdateStaticFrameStats();
    02857
    02858             // Store render target surface desc
    02859             using(Surface backBuffer = device.GetBackBuffer(0, 0, BackBufferType.Mono))
    02860             {
    02861                 State.BackBufferSurfaceDesc = backBuffer.Description;
    02862             }
    02863
    02864             // Update the state's copy of caps
    02865             State.Caps = device.DeviceCaps;
    02866
    02867             // Setup the full screen cursor
    02868             if (State.IsShowingCursorWhenFullScreen && !IsWindowed)
    02869             {
    02870                 // Get a valid cursor
    02871                 System.Windows.Forms.Cursor cursor = System.Windows.Forms.Cursor.Current;
    02872                 if (cursor == null)
    02873                     cursor = System.Windows.Forms.Cursors.Default;
    02874
    02875                 device.SetCursor(cursor, false);
    02876                 device.ShowCursor(true);
    02877             }
    02878
    02879             // Confine cursor to full screen window
    02880             if (State.IsCursorClippedWhenFullScreen)
    02881             {
    02882                 if (!IsWindowed)
    02883                 {
    02884                     // Turn on clipping for the full screen window
    02885                     System.Windows.Forms.Cursor.Clip = State.FullScreenClientRectangle;
    02886                 }
    02887                 else
    02888                 {
    02889                     // Turn off clipping
    02890                     System.Windows.Forms.Cursor.Clip = System.Drawing.Rectangle.Empty;
    02891                 }
    02892             }
    02893         }
    02894
    02898         private void AdjustWindowStyle(System.Windows.Forms.Control control, bool isWindowed)
    02899         {
    02900             System.Windows.Forms.Form window = control as System.Windows.Forms.Form;
    02901             if (window == null) // nothing to do
    02902                 return;
    02903
    02904             if (isWindowed)
    02905             {
    02906                 // If different device windows are used for windowed mode and fullscreen mode,
    02907                 // hide the fullscreen window so that it doesn't obscure the screen.
    02908                 if (State.WindowDeviceWindowed != State.WindowDeviceFullScreen)
    02909                 {
    02910                     State.WindowDeviceFullScreen.Hide();
    02911                 }
    02912
    02913                 // Set the window style mode
    02914                 window.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Sizable;
    02915             }
    02916             else
    02917             {
    02918                 // If different device windows are used for windowed mode and fullscreen mode,
    02919                 // restore and show the fullscreen device window.
    02920                 if (State.WindowDeviceWindowed != State.WindowDeviceFullScreen)
    02921                 {
    02922                     System.Windows.Forms.Form fullscreen = State.WindowDeviceFullScreen as System.Windows.Forms.Form;
    02923                     if (fullscreen != null)
    02924                     {
    02925                         if (fullscreen.WindowState == System.Windows.Forms.FormWindowState.Minimized)
    02926                             fullscreen.WindowState = System.Windows.Forms.FormWindowState.Normal;
    02927
    02928                         State.WindowDeviceFullScreen.Show();
    02929                     }
    02930                 }
    02931                 // Set the full screen style mode
    02932                 window.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
    02933             }
    02934         }
    02935
    02939         private void UpdateFrameStats()
    02940         {
    02941             if (State.AreStatsHidden)
    02942                 return; // Do nothing if stats are hidden
    02943
    02944             // Keep track of frame count
    02945             double time = FrameworkTimer.GetAbsoluteTime();
    02946             State.LastStatsUpdateFrames++;
    02947
    02948             if (time - State.LastStatsUpdateTime > 1.0)
    02949             {
    02950                 float fps = (float)(State.LastStatsUpdateFrames / (time - State.LastStatsUpdateTime));
    02951                 State.CurrentFrameRate = fps;
    02952                 State.LastStatsUpdateFrames = 0;
    02953                 State.LastStatsUpdateTime = time;
    02954
    02955                 State.FrameStats = string.Format(State.StaticFrameStats, fps.ToString("f2",
    02956                     System.Globalization.CultureInfo.CurrentUICulture));
    02957             }
    02958         }
    02959
    02963         private void UpdateStaticFrameStats()
    02964         {
    02965             if (State.AreStatsHidden)
    02966                 return; // Do nothing if stats are hidden
    02967
    02968             State.StaticFrameStats = string.Empty;
    02969             DeviceSettings settings = State.CurrentDeviceSettings;
    02970             if (settings.presentParams == null)
    02971                 return; // Nothing to do
    02972
    02973             EnumDeviceSettingsCombo combo = Enumeration.GetDeviceSettingsCombo(
    02974                 settings.AdapterOrdinal, settings.DeviceType, settings.AdapterFormat,
    02975                 settings.presentParams.BackBufferFormat, settings.presentParams.Windowed);
    02976
    02977             if (combo == null)
    02978                 return; // Still nothing to do
    02979
    02980             // Get adapter/backbuffer format string
    02981             string formatString = null;
    02982             if (settings.AdapterFormat == combo.BackBufferFormat)
    02983             {
    02984                 // Get the format string
    02985                 formatString = "Format." + settings.AdapterFormat.ToString();
    02986             }
    02987             else
    02988             {
    02989                 formatString = string.Format("backbuffer Format.{0}, adapter Format.{1}",
    02990                     combo.BackBufferFormat, settings.AdapterFormat);
    02991             }
    02992
    02993             // Get depth stencil format string
    02994             string depthFormat = null;
    02995             if (settings.presentParams.EnableAutoDepthStencil)
    02996             {
    02997                 depthFormat = " Format." + settings.presentParams.AutoDepthStencilFormat.ToString();
    02998             }
    02999
    03000             // Get any multisampling string
    03001             string multiSampleString = null;
    03002             switch(settings.presentParams.MultiSample)
    03003             {
    03004                 case MultiSampleType.None:
    03005                     multiSampleString = null; // No display
    03006                     break;
    03007                 case MultiSampleType.NonMaskable:
    03008                     multiSampleString = " (Nonmaskable Multisample)";
    03009                     break;
    03010                 default:
    03011                     multiSampleString = string.Format(" ({0} Multisample)", settings.presentParams.MultiSample.ToString());
    03012                     break;
    03013             }
    03014
    03015             // Update static frame stats now
    03016             State.StaticFrameStats = string.Format("{0} fps ({1}x{2}), {3}{4}{5}",
    03017                 "{0}", settings.presentParams.BackBufferWidth, settings.presentParams.BackBufferHeight,
    03018                 formatString, depthFormat, multiSampleString);
    03019         }
    03020
    03025         private Format FindAdapterFormat(uint adapterOrdinal, DeviceType deviceType, Format backbufferFormat,
    03026             bool isWindowed)
    03027         {
    03028             EnumDeviceInformation deviceInfo = Enumeration.GetDeviceInfo(adapterOrdinal, deviceType);
    03029             if (deviceInfo != null)
    03030             {
    03031                 for (int i = 0; i < deviceInfo.deviceSettingsList.Count; i++)
    03032                 {
    03033                     EnumDeviceSettingsCombo combo = deviceInfo.deviceSettingsList[i] as EnumDeviceSettingsCombo;
    03034                     if ( (combo.BackBufferFormat == backbufferFormat) &&
    03035                         (combo.IsWindowed == isWindowed) )
    03036                     {
    03037                         // return first match
    03038                         return combo.AdapterFormat;
    03039                     }
    03040                 }
    03041             }
    03042
    03043             // Couldn't find any adapter format's.. Return back buffer format
    03044             return backbufferFormat;
    03045         }
    03046
    03047
    03051         private void HandlePossibleSizeChange()
    03052         {
    03053             if ( (!State.WasDeviceCreated) || (State.AreSizeChangesIgnored) )
    03054                 return; // Nothing to do here
    03055
    03056             if (!State.CurrentDeviceSettings.presentParams.Windowed)
    03057                 return; // nothing to do here either, can only resize in windowed
    03058
    03059             if (Window == null)
    03060                 return; // still nothing to do, we don't have a window
    03061
    03062             System.Drawing.Rectangle oldClient = State.ClientRectangle;
    03063             // Now store the new client
    03064             State.ClientRectangle = Window.ClientRectangle;
    03065
    03066             // Don't forget the bounds rect
    03067             State.WindowBoundsRectangle = Window.Bounds;
    03068
    03069             // Check if the old client rect has changed
    03070             if (oldClient.Width != Window.ClientRectangle.Width || oldClient.Height != Window.ClientRectangle.Height)
    03071             {
    03072                 // A new window size will require a new backbuffer
    03073                 // size, so the 3D structures must be changed accordingly.
    03074                 Pause(true, true);
    03075
    03076                 DeviceSettings settings = State.CurrentDeviceSettings;
    03077                 settings.presentParams.BackBufferWidth = Window.ClientRectangle.Width;
    03078                 settings.presentParams.BackBufferHeight = Window.ClientRectangle.Height;
    03079
    03080                 // Reset the 3D environment
    03081                 if (State.Device != null)
    03082                 {
    03083                     try
    03084                     {
    03085                         Reset3DEnvironment();
    03086                     }
    03087                     catch
    03088                     {
    03089                         State.IsDeviceLost = true;
    03090                     }
    03091                 }
    03092
    03093                 Pause(false, false);
    03094             }
    03095
    03096             CheckForWindowMonitorChange();
    03097         }
    03098
    03103         private void CheckForWindowMonitorChange()
    03104         {
    03105             // Don't do this if the user doesn't want it
    03106             if (!State.CanAutoChangeAdapter)
    03107                 return;
    03108
    03109             IntPtr monitorHandle = NativeMethods.MonitorFromWindow(Window.Handle, 1); // Primary monitor
    03110             if (monitorHandle != State.AdapterMonitor)
    03111             {
    03112                 // Changing device, pause
    03113                 Pause(true, true);
    03114                 // Get the new ordinal
    03115                 uint newOrdinal = GetAdapterOridinalFromMonitor(monitorHandle);
    03116
    03117                 // Get the current device settings and flip the ordinal then
    03118                 // find the closest valid device settings with this change
    03119                 DeviceSettings settings = State.CurrentDeviceSettings.Clone();
    03120                 settings.AdapterOrdinal = newOrdinal;
    03121
    03122                 // Set up the match options
    03123                 MatchOptions match = new MatchOptions();
    03124                 match.AdapterOrdinal = MatchType.PreserveInput;
    03125                 match.DeviceType = MatchType.ClosestToInput;
    03126                 match.Windowed = MatchType.ClosestToInput;
    03127                 match.AdapterFormat = MatchType.ClosestToInput;
    03128                 match.VertexProcessing = MatchType.ClosestToInput;
    03129                 match.Resolution = MatchType.ClosestToInput;
    03130                 match.BackBufferFormat = MatchType.ClosestToInput;
    03131                 match.BackBufferCount = MatchType.ClosestToInput;
    03132                 match.MultiSample = MatchType.ClosestToInput;
    03133                 match.SwapEffect = MatchType.ClosestToInput;
    03134                 match.DepthFormat = MatchType.ClosestToInput;
    03135                 match.StencilFormat = MatchType.ClosestToInput;
    03136                 match.PresentFlags = MatchType.ClosestToInput;
    03137                 match.RefreshRate = MatchType.ClosestToInput;
    03138                 match.PresentInterval = MatchType.ClosestToInput;
    03139
    03140                 try
    03141                 {
    03142                     // Find some valid settings (if possible)
    03143                     settings = FindValidDeviceSettings(settings, match);
    03144                     try
    03145                     {
    03146                         // Create a Direct3D device using the new device settings.
    03147                         // If there is an existing device, then it will either reset or recreate the scene.
    03148                         ChangeDevice(settings, null, false);
    03149                     }
    03150                     catch (Exception e)
    03151                     {
    03152                         // This is a much worse error.. Shut down and fail
    03153                         Dispose();
    03154                         Pause(false, false);
    03155                         System.Diagnostics.Debugger.Log(0, string.Empty, e.ToString());
    03156                         return;
    03157                     }
    03158                 }
    03159                 catch
    03160                 {
    03161                     // No valid device was found for this monitor, that's bad, but not fatal.
    03162                     // Ignore this error
    03163                 }
    03164
    03165             }
    03166             Pause(false, false);
    03167         }
    03168
    03170         private uint GetAdapterOridinalFromMonitor(IntPtr monitorHandle)
    03171         {
    03172             uint ordinal = 0;
    03173
    03174             foreach(EnumAdapterInformation info in Enumeration.AdapterInformationList)
    03175             {
    03176                 if (Manager.GetAdapterMonitor((int)info.AdapterOrdinal) == monitorHandle)
    03177                     ordinal = info.AdapterOrdinal;
    03178             }
    03179             return ordinal;
    03180         }
    03181
    03183         public System.Drawing.Icon LoadFirstIconFromResource()
    03184         {
    03185             // Get the assembly that is calling this method
    03186             System.Reflection.Assembly currentAssembly = System.Reflection.Assembly.GetCallingAssembly();
    03187             foreach(string s in currentAssembly.GetManifestResourceNames())
    03188             {
    03189                 try
    03190                 {
    03191                     // See if there are any .icos
    03192                     System.IO.Stream resourceStream = currentAssembly.GetManifestResourceStream(s);
    03193                     return new System.Drawing.Icon(resourceStream);
    03194                 }
    03195                 catch
    03196                 {
    03197                     // No icon yet, try reading the resources in a different way
    03198                     try
    03199                     {
    03200                         System.Resources.ResourceReader reader = new System.Resources.ResourceReader(currentAssembly.GetManifestResourceStream(s));
    03201                         IDictionaryEnumerator en = reader.GetEnumerator();
    03202                         while(en.MoveNext())
    03203                         {
    03204                             System.Drawing.Icon test = en.Value as System.Drawing.Icon;
    03205                             if (test != null)
    03206                                 return test;
    03207                         }
    03208                     }
    03209                     catch
    03210                     {
    03211                         // Didn't find an icon yet, continue
    03212                         continue;
    03213                     }
    03214                 }
    03215             }
    03216             // It's no big deal if we can't load the icon, just return null instead
    03217             return null;
    03218         }
    03219
    03221         public void SetCursorSettings(bool showCursorWhenFullscreen, bool clipCursorWhenFullscreen)
    03222         {
    03223             State.IsCursorClippedWhenFullScreen = clipCursorWhenFullscreen;
    03224             State.IsShowingCursorWhenFullScreen = showCursorWhenFullscreen;
    03225         }
    03226
    03228         public bool CanAutomaticallyChangeMonitor
    03229         {
    03230             get { return State.CanAutoChangeAdapter; } set { State.CanAutoChangeAdapter = value; }
    03231         }
    03232
    03234         public void SetConstantFrameTime(bool constantFrameTime, float timePerFrame)
    03235         {
    03236             if (State.IsOverridingConstantFrameTime)
    03237             {
    03238                 constantFrameTime = true;
    03239                 timePerFrame = State.OverrideConstantTimePerFrame;
    03240             }
    03241             State.TimePerFrame = timePerFrame;
    03242             State.IsUsingConstantFrameTime = constantFrameTime;
    03243         }
    03245         public void SetConstantFrameTime(bool constantFrameTime)
    03246         {
    03247             State.OverrideConstantTimePerFrame = 0.0333f;
    03248             State.IsUsingConstantFrameTime = constantFrameTime;
    03249         }
    03250
    03254         public int ExitCode
    03255         {
    03256             get { return State.ApplicationExitCode; }
    03257         }
    03258
    03262         public void ShowSettingsDialog(bool shouldShow)
    03263         {
    03264             State.IsD3DSettingsDialogShowing = shouldShow;
    03265
    03266             if (shouldShow)
    03267             {
    03268                 SettingsDialog dialog = PrepareSettingsDialog();
    03269                 dialog.Refresh();
    03270             }
    03271         }
    03272
    03278         private SettingsDialog PrepareSettingsDialog()
    03279         {
    03280             SettingsDialog dialog = State.Settings;
    03281             if (dialog == null)
    03282             {
    03283                 // Create it
    03284                 dialog = new SettingsDialog(this);
    03285                 State.Settings = dialog; // Store it too
    03286
    03287                 if (State.AreDeviceObjectsCreated)
    03288                 {
    03289                     dialog.OnCreateDevice(State.Device);
    03290                 }
    03291                 if (State.AreDeviceObjectsReset)
    03292                 {
    03293                     dialog.OnResetDevice();
    03294                 }
    03295             }
    03296
    03297             return dialog;
    03298         }
    03299
    03300         #region External state access functions
    03304         public Device Device
    03305         {
    03306             get { return State.Device;}
    03307         }
    03308
    03312         public SurfaceDescription BackBufferSurfaceDescription
    03313         {
    03314             get { return State.BackBufferSurfaceDesc; }
    03315         }
    03316
    03320         public Caps DeviceCaps
    03321         {
    03322             get { return State.Caps; }
    03323         }
    03324
    03328         public System.Windows.Forms.Control Window
    03329         {
    03330             get { return IsWindowed ? State.WindowDeviceWindowed : State.WindowDeviceFullScreen; }
    03331         }
    03332
    03336         public System.Windows.Forms.Form WindowForm
    03337         {
    03338             get { return Window as System.Windows.Forms.Form; }
    03339         }
    03340
    03344         public System.Windows.Forms.Control WindowFocus
    03345         {
    03346             get { return State.WindowFocus; }
    03347         }
    03348
    03352         public System.Windows.Forms.Control WindowDeviceWindowed
    03353         {
    03354             get { return State.WindowDeviceWindowed; }
    03355         }
    03356
    03360         public System.Windows.Forms.Control WindowDeviceFullscreen
    03361         {
    03362             get { return State.WindowDeviceFullScreen; }
    03363         }
    03364
    03368         public System.Drawing.Rectangle WindowClientRectangle
    03369         {
    03370             get { return State.ClientRectangle; }
    03371         }
    03372
    03376         public System.Drawing.Rectangle ClientRectangle
    03377         {
    03378             get { return IsWindowed ? State.ClientRectangle : State.FullScreenClientRectangle; }
    03379         }
    03380
    03384         public bool IsWindowed
    03385         {
    03386             get
    03387             {
    03388                 DeviceSettings settings = State.CurrentDeviceSettings;
    03389                 if ((settings != null) && (settings.presentParams != null))
    03390                     return settings.presentParams.Windowed;
    03391                 else
    03392                     return false;
    03393             }
    03394         }
    03395
    03396
    03400         public string FrameStats
    03401         {
    03402             get { return State.FrameStats; }
    03403         }
    03407         public string DeviceStats
    03408         {
    03409             get { return State.DeviceStats; }
    03410         }
    03411
    03415         public float FPS
    03416         {
    03417             get { return State.CurrentFrameRate; }
    03418         }
    03419
    03423         public bool IsD3DSettingsDialogShowing
    03424         {
    03425             get { return State.IsD3DSettingsDialogShowing; }
    03426         }
    03427
    03431         public bool IsShowingMsgBoxOnError
    03432         {
    03433             get { return State.IsShowingMsgBoxOnError; }
    03434         }
    03435
    03440         public DeviceSettings DeviceSettings
    03441         {
    03442             get
    03443             {
    03444                 if (State.CurrentDeviceSettings != null)
    03445                 {
    03446                     return State.CurrentDeviceSettings;
    03447                 }
    03448                 else
    03449                 {
    03450                     return new DeviceSettings();
    03451                 }
    03452             }
    03453         }
    03458         public PresentParameters PresentParameters
    03459         {
    03460             get
    03461             {
    03462                 if (State.CurrentDeviceSettings != null)
    03463                 {
    03464                     return State.CurrentDeviceSettings.presentParams;
    03465                 }
    03466                 else
    03467                 {
    03468                     return new PresentParameters();
    03469                 }
    03470             }
    03471         }
    03473         public bool IsNotifiedOnMouseMove
    03474         {
    03475             get { return State.IsNotifiedOnMouseMove; } set { State.IsNotifiedOnMouseMove = value;}
    03476         }
    03477
    03479         public bool IsOverridingFullScreen
    03480         {
    03481             get { return State.IsOverridingFullScreen; } set { State.IsOverridingFullScreen = value;}
    03482         }
    03483
    03485         public bool IsIgnoringSizeChanges { get { return State.AreSizeChangesIgnored; } set { State.AreSizeChangesIgnored = value; } }
    03486
    03488         public void ResetState()
    03489         {
    03490             State = new FrameworkData();
    03491         }
    03492         #endregion
    03493
    03494         #region Timer Callbacks
    03497         public int SetTimer(TimerCallback callbackTimer, float timeoutInSeconds)
    03498         {
    03499             if (callbackTimer == null)
    03500                 throw new ArgumentNullException("callbackTimer", "You must pass in a valid timer callback .");
    03501
    03502             TimerData timer = new TimerData();
    03503             timer.callback = callbackTimer;
    03504             timer.Countdown = timeoutInSeconds;
    03505             timer.TimeoutInSecs = timeoutInSeconds;
    03506             timer.IsEnabled = true;
    03507
    03508             State.Timers.Add(timer);
    03509             return State.Timers.Count;
    03510         }
    03511
    03513         public void KillTimer(int id)
    03514         {
    03515             if (id < State.Timers.Count)
    03516             {
    03517                 TimerData timer = (TimerData)State.Timers[id];
    03518                 timer.IsEnabled = false;
    03519                 State.Timers[id] = timer;
    03520             }
    03521             else
    03522             {
    03523                 throw new ArgumentException("An invalid timer ID was passed in", "id");
    03524             }
    03525         }
    03526
    03528         private void HandleTimers()
    03529         {
    03530             float elapsedTime = State.ElapsedTime;
    03531
    03532             // Walk through the list of timers
    03533             for (int i = 0; i < State.Timers.Count; i++)
    03534             {
    03535                 TimerData ft = (TimerData)State.Timers[i];
    03536                 if (ft.IsEnabled)
    03537                 {
    03538                     ft.Countdown -= elapsedTime;
    03539                     // Call the callback if the countdown expired
    03540                     if (ft.Countdown < 0)
    03541                     {
    03542                         ft.callback((uint)i);
    03543                         ft.Countdown = ft.TimeoutInSecs;
    03544                     }
    03545                     State.Timers[i] = ft;
    03546                 }
    03547             }
    03548         }
    03549         #endregion
    03550
    03552         public void CloseWindow()
    03553         {
    03554             if (WindowForm != null)
    03555                 WindowForm.Close();
    03556         }
    03557
    03558         #region Window Message Handling
    03559
    03563         private void OnPaint(object sender, System.Windows.Forms.PaintEventArgs e)
    03564         {
    03565             // Handle paint messages when the app is paused
    03566             if ( (State.Device != null) && (State.AreDeviceObjectsCreated) &&
    03567                 (State.AreDeviceObjectsReset) && (State.IsRenderingPaused) )
    03568             {
    03569                 double time = State.CurrentTime;
    03570                 float elapsedTime = State.ElapsedTime;
    03571
    03572                 if (State.Settings != null && State.IsD3DSettingsDialogShowing)
    03573                 {
    03574                     // Clear the render target and the zbuffer
    03575                     State.Device.Clear(ClearFlags.Target, 0x00003F3F, 1.0f, 0);
    03576
    03577                     // Render the scene
    03578                     State.Device.BeginScene();
    03579                     State.Settings.OnRender(elapsedTime);
    03580                     State.Device.EndScene();
    03581                 }
    03582                 else
    03583                 {
    03584                     if (State.CallbackInterface != null)
    03585                     {
    03586                         State.CallbackInterface.OnFrameRender(State.Device, time, elapsedTime);
    03587                     }
    03588                 }
    03589
    03590                 // Now try to present
    03591                 try
    03592                 {
    03593                     State.Device.Present();
    03594                 }
    03595                 catch(DeviceLostException)
    03596                 {
    03597                     // Device was lost
    03598                     State.IsDeviceLost = true;
    03599                 }
    03600                 catch(DriverInternalErrorException)
    03601                 {
    03602                     // See Render3DEnvironment for information on this exception
    03603                     State.IsDeviceLost = true;
    03604                 }
    03605             }
    03606         }
    03607
    03611         private void OnResize(object sender, EventArgs e)
    03612         {
    03613             System.Windows.Forms.Form form = sender as System.Windows.Forms.Form;
    03614             System.Windows.Forms.Control control = sender as System.Windows.Forms.Control;
    03615
    03616             if (form != null)
    03617             {
    03618                 if (form.WindowState == System.Windows.Forms.FormWindowState.Minimized)
    03619                 {
    03620                     if ((State.IsCursorClippedWhenFullScreen) && !(IsWindowed) )
    03621                         System.Windows.Forms.Cursor.Clip = System.Drawing.Rectangle.Empty;
    03622                     State.IsMinimized = true;
    03623                     State.IsMaximized = false;
    03624                     Pause(true, true); // Pause while minimized
    03625                 }
    03626                 else
    03627                 {
    03628                     if (State.IsMinimized)
    03629                     {
    03630                         Pause(false, false);
    03631                     }
    03632                     State.IsMinimized = false;
    03633                     State.IsMaximized = form.WindowState == System.Windows.Forms.FormWindowState.Maximized;
    03634
    03635                     // Resize
    03636                     HandlePossibleSizeChange();
    03637                 }
    03638             }
    03639
    03640         }
    03641
    03645         private void OnKeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
    03646         {
    03647             if (State.IsHandlingDefaultHotkeys)
    03648             {
    03649                 switch(e.KeyCode)
    03650                 {
    03651                     case System.Windows.Forms.Keys.Enter:
    03652                         if (e.Alt) // Alt was pressed as well
    03653                         {
    03654                             // Toggle the full screen/window mode
    03655                             Pause(true, true);
    03656                             ToggleFullscreen();
    03657                             Pause(false, false);
    03658                             e.Handled = true;
    03659                         }
    03660                         break;
    03661                     case System.Windows.Forms.Keys.F2:
    03662                         ShowSettingsDialog(!State.IsD3DSettingsDialogShowing);
    03663                         break;
    03664                     case System.Windows.Forms.Keys.F3: // Toggle reference
    03665                         Pause(true, true);
    03666                         ToggleReference();
    03667                         Pause(false, false);
    03668                         break;
    03669
    03670                     case System.Windows.Forms.Keys.F8:
    03671                         State.IsInWireframeMode = !State.IsInWireframeMode;
    03672                         if (State.Device != null)
    03673                         {
    03674                             State.Device.RenderState.FillMode = State.IsInWireframeMode ? FillMode.WireFrame : FillMode.Solid;
    03675                         }
    03676                         break;
    03677
    03678                     case System.Windows.Forms.Keys.Escape:
    03679                         // Received key to exit app, check for a form to close
    03680                         if (WindowForm != null)
    03681                         {
    03682                             WindowForm.Close();
    03683                         }
    03684                         break;
    03685
    03686                     case System.Windows.Forms.Keys.Pause:
    03687                         bool isTimePaused = (State.PauseTimeCount > 0);
    03688                         isTimePaused = !isTimePaused;
    03689                         if (isTimePaused)
    03690                             Pause(true, false);
    03691                         else
    03692                             Pause(false, false);
    03693
    03694                         break;
    03695
    03696                 }
    03697             }
    03698         }
    03699
    03703         private void OnCursorChanged(object sender, EventArgs e)
    03704         {
    03705             // Turn off Windows cursor in full screen mode
    03706             if ( (!State.IsRenderingPaused) && (!IsWindowed) )
    03707             {
    03708                 System.Windows.Forms.Cursor.Current = null;
    03709                 if ( (State.Device != null) && State.IsShowingCursorWhenFullScreen)
    03710                     State.Device.ShowCursor(true);
    03711             }
    03712             else
    03713                 System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.Default;
    03714         }
    03715
    03719         private void OnMouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
    03720         {
    03721             if ( (!State.IsRenderingPaused) && (!IsWindowed) )
    03722             {
    03723                 if (State.Device != null)
    03724                 {
    03725                     State.Device.SetCursorPosition(e.X, e.Y, false);
    03726                 }
    03727             }
    03728         }
    03729
    03733         private void OnFormClosed(object sender, EventArgs e)
    03734         {
    03735             // No more windows
    03736             State.WindowFocus = null;
    03737             State.WindowDeviceWindowed = null;
    03738             State.WindowDeviceFullScreen = null;
    03739         }
    03740
    03744         private void OnFormActivated(object sender, EventArgs e)
    03745         {
    03746             State.IsActive = true;
    03747         }
    03748
    03752         private void OnFormDeactivated(object sender, EventArgs e)
    03753         {
    03754             State.IsActive = false;
    03755         }
    03756
    03760         private void OnMenuStart(object sender, EventArgs e)
    03761         {
    03762             Pause(true, true);
    03763         }
    03764
    03768         private void OnMenuEnd(object sender, EventArgs e)
    03769         {
    03770             Pause(false, false);
    03771         }
    03772
    03776         private void HookEvents(System.Windows.Forms.Control c)
    03777         {
    03778             c.Paint += new System.Windows.Forms.PaintEventHandler(OnPaint);
    03779             c.Resize += new EventHandler(OnResize);
    03780             c.KeyDown += new System.Windows.Forms.KeyEventHandler(OnKeyDown);
    03781             c.CursorChanged += new EventHandler(OnCursorChanged);
    03782             c.MouseMove += new System.Windows.Forms.MouseEventHandler(OnMouseMove);
    03783             System.Windows.Forms.Form form = c as System.Windows.Forms.Form;
    03784             if (form != null)
    03785             {
    03786                 // Hook form specific events
    03787                 form.Closed += new EventHandler(OnFormClosed);
    03788                 form.Activated += new EventHandler(OnFormActivated);
    03789                 form.Deactivate += new EventHandler(OnFormDeactivated);
    03790                 form.MenuStart += new EventHandler(OnMenuStart);
    03791                 form.MenuComplete += new EventHandler(OnMenuEnd);
    03792             }
    03793         }
    03795         internal void WindowsProcedure(ref System.Windows.Forms.Message m)
    03796         {
    03797             if (State.Settings != null && State.IsD3DSettingsDialogShowing)
    03798             {
    03799                 State.Settings.HandleMessages(m.HWnd, (NativeMethods.WindowMessage)m.Msg, m.WParam, m.LParam);
    03800             }
    03801             else
    03802             {
    03803                 if (State.WndProcFunction != null)
    03804                 {
    03805                     bool doneProcessing = false;
    03806                     // Pass all messages to the app's MsgProc callback, and don't
    03807                     // process further messages if the apps says not to.
    03808                     IntPtr result = State.WndProcFunction(m.HWnd, (NativeMethods.WindowMessage)m.Msg, m.WParam, m.LParam, ref doneProcessing);
    03809                     if (doneProcessing)
    03810                         m.Result = result;
    03811                 }
    03812             }
    03813
    03814             switch((NativeMethods.WindowMessage)m.Msg)
    03815             {
    03816                 case NativeMethods.WindowMessage.PowerBroadcast:
    03817                     if (m.WParam == IntPtr.Zero) // Query Suspend
    03818                     {
    03819                         // At this point, the app should save any data for open
    03820                         // network connections, files, etc., and prepare to go into
    03821                         // a suspended mode.  The app can use the MsgProc callback
    03822                         // to handle this if desired.
    03823                         m.Result = TrueIntPtr;
    03824                     }
    03825                     if (m.WParam.ToInt32() == 7) // Resume Suspend
    03826                     {
    03827                         // At this point, the app should recover any data, network
    03828                         // connections, files, etc., and resume running from when
    03829                         // the app was suspended. The app can use the MsgProc callback
    03830                         // to handle this if desired.
    03831
    03832                         // QPC may lose consistency when suspending, so reset the timer
    03833                         // upon resume.
    03834                         FrameworkTimer.Reset();
    03835                         State.LastStatsUpdateTime = 0;
    03836
    03837                         m.Result = TrueIntPtr;
    03838                     }
    03839                     break;
    03840                 case NativeMethods.WindowMessage.SystemCommand:
    03841                     // Prevent moving/sizing and power loss in full screen mode
    03842                     const int SystemCommandSize = 0xF000;
    03843                     const int SystemCommandMove = 0xF010;
    03844                     const int SystemCommandMaximize = 0xF030;
    03845                     const int SystemCommandKeyMenu = 0xF100;
    03846                     const int SystemCommandMonitorPower = 0xF170;
    03847                     switch(m.WParam.ToInt32())
    03848                     {
    03849                         case SystemCommandSize:
    03850                         case SystemCommandMove:
    03851                         case SystemCommandMaximize:
    03852                         case SystemCommandKeyMenu:
    03853                         case SystemCommandMonitorPower:
    03854                             if (!IsWindowed)
    03855                                 m.Result = TrueIntPtr;
    03856                             break;
    03857                     }
    03858                     break;
    03859             }
    03860         }
    03861         #endregion
    03862
    03867         public void MainLoop()
    03868         {
    03869             // No need to do anything if the framework is already disposed
    03870             if (isDisposed)
    03871                 return;
    03872
    03873             // Not allowed to call this from inside the device callbacks or reenter
    03874             if (State.IsInsideDeviceCallback || State.IsInsideMainloop)
    03875             {
    03876                 State.ApplicationExitCode = 1;
    03877                 throw new InvalidOperationException("You cannot call this method from a callback, or reenter the method.");
    03878             }
    03879
    03880             // We're inside the loop now
    03881             State.IsInsideMainloop = true;
    03882
    03883             // If CreateDevice*() or SetDevice() has not already been called,
    03884             // then call CreateDevice() with the default parameters.
    03885             if (!State.WasDeviceCreated)
    03886             {
    03887                 if (State.WasDeviceCreateCalled)
    03888                 {
    03889                     // It already called and failed, don't try again
    03890                     State.ApplicationExitCode = 1;
    03891                     throw new InvalidOperationException("The device was never created.");
    03892                 }
    03893
    03894                 try
    03895                 {
    03896                     CreateDevice(0, true, DefaultSizeWidth, DefaultSizeHeight, null);
    03897                 }
    03898                 catch
    03899                 {
    03900                     // Well, can't do anything, just set the exit code and rethrow
    03901                     State.ApplicationExitCode = 1;
    03902                     throw;
    03903                 }
    03904             }
    03905
    03906             // Initialize() must have been called and succeeded for this function to proceed
    03907             // CreateWindow() or SetWindow() must have been called and succeeded for this function to proceed
    03908             // CreateDevice() or CreateDeviceFromSettings() or SetDevice() must have been called and succeeded for this function to proceed
    03909             if ( (!State.IsInited) || (!State.WasWindowCreated) || (!State.WasDeviceCreated) )
    03910             {
    03911                 State.ApplicationExitCode = 1;
    03912                 throw new InvalidOperationException("The framework was not initialized, cannot continue.");
    03913             }
    03914
    03915             using (System.Windows.Forms.Control app = Window)
    03916             {
    03917                 // Hook the application's idle event
    03918                 System.Windows.Forms.Application.Idle += new EventHandler(OnApplicationIdle);
    03919                 // Start the application
    03920                 if (app is System.Windows.Forms.Form)
    03921                 {
    03922                     System.Windows.Forms.Application.Run(app as System.Windows.Forms.Form);
    03923                 }
    03924                 else
    03925                 {
    03926                     // Show the window
    03927                     app.Show();
    03928                     System.Windows.Forms.Application.Run();
    03929                 }
    03930             }
    03931
    03932             State.IsInsideMainloop = false;
    03933         }
    03934
    03935         #region App Idle Events
    03937         private void OnApplicationIdle(object sender, EventArgs e)
    03938         {
    03939             while (AppStillIdle)
    03940             {
    03941                 // Render a frame during idle time (no messages are waiting)
    03942                 Render3DEnvironment();
    03943             }
    03944         }
    03946         private bool AppStillIdle
    03947         {
    03948             get
    03949             {
    03950                 NativeMethods.Message msg;
    03951                 return !NativeMethods.PeekMessage(out msg, IntPtr.Zero, 0, 0, 0);
    03952             }
    03953         }
    03954         #endregion
    03955
    03956         #region IDisposable Members
    03958         public void Dispose()
    03959         {
    03960             // Disable finalization of this object now
    03961             GC.SuppressFinalize(this);
    03962
    03963             if (!isDisposed)
    03964             {
    03965                 // Raise the event if need be
    03966                 if (Disposing != null)
    03967                     Disposing(this, EventArgs.Empty);
    03968
    03969                 // Now shut down the system
    03970                 if (Window != null)
    03971                 {
    03972                     // If we have a window, use BeginInvoke to start shutdown
    03973                     Window.BeginInvoke(new DisposeDelegate(this.Shutdown));
    03974                 }
    03975                 else
    03976                 {
    03977                     // Otherwise, call it directly
    03978                     Shutdown();
    03979                 }
    03980             }
    03981
    03982             // The object has now been disposed
    03983             isDisposed = true;
    03984         }
    03985
    03987         ~Framework()
    03988         {
    03989             Dispose();
    03990         }
    03991         #endregion
    03992
    03993         #region Device event handlers
    03995         private void OnDeviceDisposing(object sender, EventArgs e)
    03996         {
    03997             // Mark as being inside a callback
    03998             State.IsInsideDeviceCallback = true;
    03999
    04000             // Release all vidmem objects
    04001             if (State.AreDeviceObjectsReset)
    04002             {
    04003                 DialogResourceManager.GetGlobalInstance().OnDestroyDevice();
    04004                 ResourceCache.GetGlobalInstance().OnDestroyDevice();
    04005                 if (State.Settings != null)
    04006                 {
    04007                     State.Settings.OnDestroyDevice( this, EventArgs.Empty);
    04008                 }
    04009                 State.AreDeviceObjectsCreated = false;
    04010             }
    04011
    04012             // Pass this event along
    04013             if (Disposing != null)
    04014                 Disposing(this, e);
    04015
    04016             // Now you're not
    04017             State.IsInsideDeviceCallback = false;
    04018         }
    04019
    04021         private void OnDeviceLost(object sender, EventArgs e)
    04022         {
    04023             // Mark as being inside a callback
    04024             State.IsInsideDeviceCallback = true;
    04025
    04026             // Release all vidmem objects
    04027             if (State.AreDeviceObjectsReset)
    04028             {
    04029                 DialogResourceManager.GetGlobalInstance().OnLostDevice();
    04030                 ResourceCache.GetGlobalInstance().OnLostDevice();
    04031                 if (State.Settings != null)
    04032                 {
    04033                     State.Settings.OnLostDevice();
    04034                 }
    04035                 State.AreDeviceObjectsReset = false;
    04036             }
    04037
    04038             // Pass this event along
    04039             if (DeviceLost != null)
    04040                 DeviceLost(this, e);
    04041
    04042             // Now you're not
    04043             State.IsInsideDeviceCallback = false;
    04044         }
    04045
    04047         private void OnDeviceReset(object sender, EventArgs e)
    04048         {
    04049             // Get the device
    04050             Device device = sender as Device;
    04051             System.Diagnostics.Debug.Assert(device != null, "Must have a device here.");
    04052
    04053             // Mark as being inside a callback
    04054             State.IsInsideDeviceCallback = true;
    04055
    04056             // Prepare the device with cursor info and
    04057             // store backbuffer desc and caps from the device
    04058             PrepareDevice(device);
    04059
    04060             if (State.Settings != null)
    04061                 State.Settings.OnResetDevice();
    04062
    04063             // Call the dialog resource manager device reset function
    04064             DialogResourceManager.GetGlobalInstance().OnResetDevice(device);
    04065             // Call the resource cache device reset function
    04066             ResourceCache.GetGlobalInstance().OnResetDevice(device);
    04067
    04068             // Call app's reset callback
    04069             if (DeviceReset != null)
    04070                 DeviceReset(this, new DeviceEventArgs(device, State.BackBufferSurfaceDesc));
    04071
    04072             // Device objects are reset now
    04073             State.AreDeviceObjectsReset = true;
    04074             // Now you're not
    04075             State.IsInsideDeviceCallback = false;
    04076         }
    04077         #endregion
    04078
    04079     }
    04080 }