00001
00002
00003
00004
00005
00006
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
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
00041 private delegate void DisposeDelegate();
00042
00043
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
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
00055 private FrameworkData State;
00056
00057 private Exception lastDisplayedMessage = null;
00058
00059 private bool isDisposed = false;
00060
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
00076 public void SetCallbackInterface(IFrameworkCallback callback) { State.CallbackInterface = callback; }
00077 public void SetDeviceCreationInterface(IDeviceCreation callback) { State.DeviceCreationInterface = callback; }
00078
00079
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
00126
00127 Device.IsUsingEventHandlers = false;
00128
00129
00130
00131
00132 State.IsShowingMsgBoxOnError = showMessageBoxOnError;
00133 State.IsHandlingDefaultHotkeys = handleDefaultKeys;
00134
00135
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
00146 FrameworkTimer.Reset();
00147 State.IsInited = true;
00148
00149 }
00150
00154 private void ParseCommandLine()
00155 {
00156 string[] args = System.Environment.GetCommandLineArgs();
00157
00158
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;
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
00272 if (!State.IsInited)
00273 {
00274
00275 if (State.WasInitCalled)
00276 {
00277 throw new InvalidOperationException("Initialize was already called and failed.");
00278 }
00279
00280
00281 Initialize(true, true, true);
00282 }
00283
00284
00285 if (State.WindowFocus == null)
00286 {
00287
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
00300 GraphicsWindow renderWindow = new GraphicsWindow(this);
00301
00302 HookEvents(renderWindow);
00303
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
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
00322 renderWindow.ClientSize = windowSize;
00323
00324
00325 State.WindowTitle = windowTitle;
00326 renderWindow.Text = windowTitle;
00327
00328
00329 System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.Default;
00330
00331
00332 renderWindow.Visible = false;
00333 renderWindow.CreateControl();
00334 State.ClientRectangle = renderWindow.ClientRectangle;
00335 State.WindowBoundsRectangle = renderWindow.Bounds;
00336
00337
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
00366
00367
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
00377 HookEvents(windowFocus);
00378 }
00379
00380
00381 if (!State.IsInited)
00382 {
00383
00384 if (State.WasInitCalled)
00385 {
00386 throw new InvalidOperationException("Initialize was already called and failed.");
00387 }
00388
00389
00390 Initialize(true, true, true);
00391 }
00392
00393
00394 State.ClientRectangle = windowDeviceWindowed.ClientRectangle;
00395 State.WindowBoundsRectangle = windowDeviceWindowed.Bounds;
00396
00397
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
00419
00420
00421 if ((windowDeviceFullscreen == null) || (windowDeviceWindowed == null)
00422 || (windowFocus == null))
00423 {
00424 throw new InvalidOperationException("You must pass in valid window handles.");
00425 }
00426
00427
00428 if (!State.IsInited)
00429 {
00430
00431 if (State.WasInitCalled)
00432 {
00433 throw new InvalidOperationException("Initialize was already called and failed.");
00434 }
00435
00436
00437 Initialize(true, true, true);
00438 }
00439
00440
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
00459 SetDeviceCreationInterface(callback);
00460
00461
00462 State.WasDeviceCreateCalled = true;
00463
00464
00465 if (!State.WasWindowCreated)
00466 {
00467
00468 if (State.WasWindowCreateCalled)
00469 {
00470 throw new InvalidOperationException("CreateWindow was already called and failed.");
00471 }
00472
00473
00474 CreateWindow("Direct3D Window", null, null, -1, -1);
00475 }
00476
00477
00478 Enumeration.Enumerate(State.DeviceCreationInterface);
00479
00480
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
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
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
00560
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
00568
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
00602 if (!State.WasWindowCreated)
00603 {
00604
00605 if (State.WasWindowCreateCalled)
00606 {
00607 throw new InvalidOperationException("CreateWindow was already called and failed.");
00608 }
00609
00610
00611 CreateWindow("Direct3D Window", null, null, -1, -1);
00612 }
00613
00614 DeviceSettings deviceSettings = new DeviceSettings();
00615
00616
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
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
00637 ChangeDevice(deviceSettings, device, false);
00638 }
00639
00646 public void CreateDeviceFromSettings(DeviceSettings deviceSettings, bool preserveInput)
00647 {
00648
00649 State.WasDeviceCreateCalled = true;
00650
00651
00652 if (!State.WasWindowCreated)
00653 {
00654
00655 if (State.WasWindowCreateCalled)
00656 {
00657 throw new InvalidOperationException("CreateWindow was already called and failed.");
00658 }
00659
00660
00661 CreateWindow("Direct3D Window", null, null, -1, -1);
00662 }
00663
00664 if (!preserveInput)
00665 {
00666
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
00691 DisplayErrorMessage(e);
00692 throw;
00693 }
00694
00695
00696 ChangeDevice(deviceSettings, null, false);
00697 }
00698 }
00705 public void CreateDeviceFromSettings(DeviceSettings deviceSettings) { CreateDeviceFromSettings(deviceSettings, false); }
00706
00710 public void ToggleFullscreen()
00711 {
00712
00713 Pause(true, true);
00714
00715
00716
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
00782 Pause(false, false);
00783 State.CurrentDeviceSettings = currentSettings;
00784 }
00785 }
00786
00787
00791 public void ToggleReference()
00792 {
00793
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
00826 DisplayErrorMessage(e);
00827 #else
00828 catch
00829 {
00830
00831 #endif
00832 }
00833 finally
00834 {
00835
00836 State.CurrentDeviceSettings = currentSettings;
00837 }
00838 }
00839
00855 private DeviceSettings FindValidDeviceSettings(DeviceSettings settings, MatchOptions match)
00856 {
00857
00858
00859
00860
00861 DeviceSettings optimalSettings = BuildOptimalDeviceSettings(settings, match);
00862 float bestRanking = -1.0f;
00863 EnumDeviceSettingsCombo bestDeviceSettingsCombo = new EnumDeviceSettingsCombo();
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873 DisplayMode adapterDesktopDisplayMode;
00874 for (int iAdapter = 0; iAdapter < Enumeration.AdapterInformationList.Count; iAdapter++)
00875 {
00876 EnumAdapterInformation adapterInfo = Enumeration.AdapterInformationList[iAdapter] as EnumAdapterInformation;
00877
00878
00879 adapterDesktopDisplayMode = Manager.Adapters[(int)adapterInfo.AdapterOrdinal].CurrentDisplayMode;
00880
00881
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
00889
00890 if (deviceSettings.IsWindowed && (deviceSettings.AdapterFormat != adapterDesktopDisplayMode.Format))
00891 continue;
00892
00893
00894 if(!DoesDeviceComboMatchPreserveOptions(deviceSettings, settings, match))
00895 continue;
00896
00897
00898 float curRanking = RankDeviceCombo(deviceSettings, optimalSettings, adapterDesktopDisplayMode);
00899
00900
00901 if (curRanking > bestRanking )
00902 {
00903 bestDeviceSettingsCombo = deviceSettings;
00904 bestRanking = curRanking;
00905 }
00906 }
00907 }
00908 }
00909
00910
00911 if (bestRanking == -1.0f)
00912 {
00913 throw new NoCompatibleDevicesException();
00914 }
00915
00916
00917
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();
00937 optimal.presentParams = new PresentParameters();
00938
00939
00940
00941
00942 if (match.AdapterOrdinal == MatchType.IgnoreInput)
00943 optimal.AdapterOrdinal = 0;
00944 else
00945 optimal.AdapterOrdinal = settings.AdapterOrdinal;
00946
00947
00948
00949
00950 if (match.DeviceType == MatchType.IgnoreInput)
00951 optimal.DeviceType = DeviceType.Hardware;
00952 else
00953 optimal.DeviceType = settings.DeviceType;
00954
00955
00956
00957
00958 if (match.Windowed == MatchType.IgnoreInput)
00959 optimal.presentParams.Windowed = true;
00960 else
00961 optimal.presentParams.Windowed = settings.presentParams.Windowed;
00962
00963
00964
00965
00966 if (match.AdapterFormat == MatchType.IgnoreInput)
00967 {
00968
00969
00970
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
00986
00987 if (match.VertexProcessing == MatchType.IgnoreInput)
00988 optimal.BehaviorFlags = CreateFlags.HardwareVertexProcessing;
00989 else
00990 optimal.BehaviorFlags = settings.BehaviorFlags;
00991
00992
00993
00994
00995 if (match.Resolution == MatchType.IgnoreInput)
00996 {
00997
00998
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
01020
01021 if (match.BackBufferFormat == MatchType.IgnoreInput)
01022 optimal.presentParams.BackBufferFormat = optimal.AdapterFormat;
01023 else
01024 optimal.presentParams.BackBufferFormat = settings.presentParams.BackBufferFormat;
01025
01026
01027
01028
01029 if (match.BackBufferCount == MatchType.IgnoreInput)
01030 optimal.presentParams.BackBufferCount = 2;
01031 else
01032 optimal.presentParams.BackBufferCount = settings.presentParams.BackBufferCount;
01033
01034
01035
01036
01037 if (match.MultiSample == MatchType.IgnoreInput)
01038 optimal.presentParams.MultiSampleQuality = 0;
01039 else
01040 optimal.presentParams.MultiSampleQuality = settings.presentParams.MultiSampleQuality;
01041
01042
01043
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
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
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
01077
01078 if (match.RefreshRate == MatchType.IgnoreInput)
01079 optimal.presentParams.FullScreenRefreshRateInHz = 0;
01080 else
01081 optimal.presentParams.FullScreenRefreshRateInHz = settings.presentParams.FullScreenRefreshRateInHz;
01082
01083
01084
01085
01086 if (match.PresentInterval == MatchType.IgnoreInput)
01087 {
01088
01089
01090
01091
01092
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
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
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
01150 if (deviceCombo.deviceInformation.Caps.DeviceCaps.SupportsHardwareTransformAndLight)
01151 bestBehaviorFlags |= CreateFlags.HardwareVertexProcessing;
01152 else
01153 bestBehaviorFlags |= CreateFlags.SoftwareVertexProcessing;
01154 }
01155 else
01156 {
01157
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
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
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
01199 {
01200 if (deviceCombo.IsWindowed )
01201 {
01202
01203 displayModeIn.Width = DefaultSizeWidth;
01204 displayModeIn.Height = DefaultSizeHeight;
01205 }
01206 else
01207 {
01208
01209 displayModeIn.Width = adapterDesktopDisplayMode.Width;
01210 displayModeIn.Height = adapterDesktopDisplayMode.Height;
01211 }
01212 }
01213
01214
01215 bestDisplayMode = FindValidResolution(deviceCombo, displayModeIn);
01216 }
01217
01218
01219
01220
01221
01222
01223
01224
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
01234 bestBackBufferCount = 2;
01235 }
01236 else
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
01247
01248 MultiSampleType bestMultiSampleType;
01249 uint bestMultiSampleQuality;
01250 if (settings.presentParams.SwapEffect != SwapEffect.Discard)
01251 {
01252
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
01266 bestMultiSampleType = MultiSampleType.None;
01267 bestMultiSampleQuality = 0;
01268 }
01269 else if (match.BackBufferCount == MatchType.ClosestToInput )
01270 {
01271
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
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
01289 {
01290
01291 bestMultiSampleType = MultiSampleType.None;
01292 bestMultiSampleQuality = 0;
01293 }
01294 }
01295
01296
01297
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
01309 {
01310 bestSwapEffect = settings.presentParams.SwapEffect;
01311
01312
01313 if (bestSwapEffect != SwapEffect.Discard &&
01314 bestSwapEffect != SwapEffect.Flip &&
01315 bestSwapEffect != SwapEffect.Copy )
01316 {
01317 bestSwapEffect = SwapEffect.Discard;
01318 }
01319 }
01320
01321
01322
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
01341 if(curDepthBitDepth == inputDepthBitDepth)
01342 ranking = 0;
01343 else
01344 ranking = 10000;
01345 }
01346 else if (match.DepthFormat == MatchType.IgnoreInput )
01347 {
01348
01349 ranking = Math.Abs((int)curDepthBitDepth - (int)(backBufferBitDepth*4));
01350 }
01351 else
01352 {
01353
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
01371 if(curStencilBitDepth == inputStencilBitDepth)
01372 ranking += 0;
01373 else
01374 ranking += 10000;
01375 }
01376 else if (match.StencilFormat == MatchType.IgnoreInput )
01377 {
01378
01379 ranking += (int)curStencilBitDepth;
01380 }
01381 else
01382 {
01383
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
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
01428 {
01429 bestPresentFlag = settings.presentParams.PresentFlag;
01430 if (bestEnableAutoDepthStencil )
01431 bestPresentFlag |= PresentFlag.DiscardDepthStencil;
01432 }
01433
01434
01435
01436
01437 if (deviceCombo.IsWindowed )
01438 {
01439
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
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;
01472
01473
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
01482 if (bestRefreshRanking == 0 )
01483 break;
01484 }
01485 }
01486 }
01487 }
01488 }
01489
01490
01491
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
01503
01504
01505 bestPresentInterval = PresentInterval.Immediate;
01506 }
01507 else
01508 {
01509
01510
01511 bestPresentInterval = PresentInterval.Default;
01512 }
01513 }
01514 else
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
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
01563
01564 if (match.AdapterOrdinal == MatchType.PreserveInput &&
01565 (deviceCombo.AdapterOrdinal != settings.AdapterOrdinal) )
01566 return false;
01567
01568
01569
01570
01571 if (match.DeviceType == MatchType.PreserveInput &&
01572 (deviceCombo.DeviceType != settings.DeviceType) )
01573 return false;
01574
01575
01576
01577
01578 if (match.Windowed == MatchType.PreserveInput &&
01579 (deviceCombo.IsWindowed != settings.presentParams.Windowed) )
01580 return false;
01581
01582
01583
01584
01585 if (match.AdapterFormat == MatchType.PreserveInput &&
01586 (deviceCombo.AdapterFormat != settings.AdapterFormat) )
01587 return false;
01588
01589
01590
01591
01592
01593 if (match.VertexProcessing == MatchType.PreserveInput &&
01594 ((settings.BehaviorFlags & CreateFlags.HardwareVertexProcessing) != 0) &&
01595 (deviceCombo.deviceInformation.Caps.DeviceCaps.SupportsHardwareTransformAndLight) )
01596 return false;
01597
01598
01599
01600
01601
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;
01610
01611 if (displayMode.Width == settings.presentParams.BackBufferWidth &&
01612 displayMode.Height == settings.presentParams.BackBufferHeight )
01613 {
01614 bFound = true;
01615 break;
01616 }
01617 }
01618
01619
01620 if (!bFound )
01621 return false;
01622 }
01623
01624
01625
01626
01627 if (match.BackBufferFormat == MatchType.PreserveInput &&
01628 deviceCombo.BackBufferFormat != settings.presentParams.BackBufferFormat )
01629 return false;
01630
01631
01632
01633
01634
01635
01636
01637
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
01656 if (!bFound )
01657 return false;
01658 }
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668
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
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
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
01715
01716
01717
01718
01719
01720
01721
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
01738 if (!bFound )
01739 return false;
01740 }
01741
01742
01743
01744
01745
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
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
01776
01777 if (deviceCombo.AdapterOrdinal == settings.AdapterOrdinal )
01778 currentRanking += adapterOrdinalWeight;
01779
01780
01781
01782
01783 if (deviceCombo.DeviceType == settings.DeviceType )
01784 currentRanking += deviceTypeWeight;
01785
01786 if (deviceCombo.DeviceType == DeviceType.Hardware )
01787 currentRanking += 0.1f;
01788
01789
01790
01791
01792 if (deviceCombo.IsWindowed == settings.presentParams.Windowed )
01793 currentRanking += windowWeight;
01794
01795
01796
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
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
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
01833 if(deviceCombo.deviceInformation.Caps.DeviceCaps.SupportsHardwareTransformAndLight)
01834 currentRanking += 0.1f;
01835
01836
01837
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
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
01868
01869 bool bAdapterMatchesBB = (deviceCombo.BackBufferFormat == deviceCombo.AdapterFormat);
01870 if (bAdapterMatchesBB )
01871 currentRanking += 0.1f;
01872
01873
01874
01875
01876
01877
01878
01879
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
01899
01900
01901
01902
01903
01904
01905 if (deviceCombo.depthStencilFormatList.Contains( settings.presentParams.AutoDepthStencilFormat ) )
01906 currentRanking += depthStencilWeight;
01907
01908
01909
01910
01911
01912
01913
01914
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
01930
01931
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
01948
01949
01950
01951 EnumAdapterInformation adapterInfo = Enumeration.GetAdapterInformation(deviceCombo.AdapterOrdinal);
01952
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
01959 if (deviceName.IndexOf("\0") > 0)
01960 {
01961 deviceName = deviceName.Substring(0, deviceName.IndexOf("\0"));
01962 }
01963 if (deviceName == adapterName)
01964 {
01965
01966 displayScreen = s;
01967 break;
01968 }
01969 }
01970 System.Diagnostics.Debug.Assert(displayScreen != null, "We should have found the screen by now.");
01971
01972
01973
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
01989 if (storedMode.Format != deviceCombo.AdapterFormat )
01990 continue;
01991
01992
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
02002 if (bestRanking == 0 )
02003 break;
02004 }
02005 }
02006
02007
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
02026 if (isDisposed)
02027 return;
02028
02029
02030 DeviceSettings oldSettings = null;
02031 if (State.CurrentDeviceSettings != null)
02032 oldSettings = State.CurrentDeviceSettings.Clone();
02033
02034
02035 Pause(true, true);
02036
02037
02038
02039
02040 State.AreSizeChangesIgnored = true;
02041
02042
02043
02044 if ( (deviceFromApp == null) && (oldSettings == null) )
02045 {
02046
02047
02048 UpdateDeviceSettingsWithOverrides(ref newDeviceSettings);
02049 }
02050
02051
02052
02053
02054 if (newDeviceSettings.presentParams.Windowed)
02055 {
02056
02057
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
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;
02070 State.WindowBoundsRectangle = WindowFocus.Bounds;;
02071 }
02072 }
02073
02074
02075 State.CurrentDeviceSettings = newDeviceSettings;
02076
02077
02078
02079
02080
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
02091 Reset3DEnvironment();
02092 }
02093 catch
02094 {
02095
02096 Pause (false, false);
02097 State.IsDeviceLost = true;
02098 }
02099 }
02100 else
02101 {
02102
02103 if (oldSettings != null)
02104 {
02105
02106
02107 Cleanup3DEnvironment(false);
02108 }
02109
02110 Device device = deviceFromApp;
02111
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
02123 Pause(false, false);
02124 CreatingDeviceException cde = new CreatingDeviceException(e);
02125 DisplayErrorMessage(cde);
02126 throw;
02127 }
02128 }
02129
02130
02131 device.DeviceLost += new EventHandler(OnDeviceLost);
02132 device.DeviceReset += new EventHandler(OnDeviceReset);
02133 device.Disposing += new EventHandler(OnDeviceDisposing);
02134
02135
02136 State.Device = device;
02137
02138
02139
02140 try
02141 {
02142 Initialize3DEnvironment();
02143 }
02144 catch
02145 {
02146 Pause(false, false);
02147 throw;
02148 }
02149
02150 Enumeration.Enumerate(null);
02151 EnumAdapterInformation adapterInfo = Enumeration.GetAdapterInformation(newDeviceSettings.AdapterOrdinal);
02152 UpdateDeviceStats(newDeviceSettings.DeviceType, newDeviceSettings.BehaviorFlags, adapterInfo.AdapterInformation);
02153 }
02154
02155
02156 State.AdapterMonitor = Manager.GetAdapterMonitor((int)newDeviceSettings.AdapterOrdinal);
02157
02158
02159
02160
02161
02162
02163
02164
02165
02166 if (newDeviceSettings.presentParams.Windowed)
02167 {
02168 if (State.WindowFocus == null)
02169 {
02170 System.Drawing.Rectangle rect = State.WindowBoundsRectangle;
02171
02172
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
02184 NativeMethods.MonitorInformation infoAdapter = new NativeMethods.MonitorInformation();
02185
02186 infoAdapter.Size = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(NativeMethods.MonitorInformation));
02187 NativeMethods.GetMonitorInfo(State.AdapterMonitor, ref infoAdapter);
02188
02189 int monitorWidth = infoAdapter.WorkRectangle.Right - infoAdapter.WorkRectangle.Left;
02190 int monitorHeight = infoAdapter.WorkRectangle.Bottom - infoAdapter.WorkRectangle.Top;
02191
02192
02193 IntPtr monitorHandle = NativeMethods.MonitorFromWindow(Window.Handle, 1);
02194 NativeMethods.MonitorInformation infoWindow = new NativeMethods.MonitorInformation();
02195
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
02208
02209
02210
02211 State.IsWindowCreatedWithDefaultPositions = false;
02212
02213
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
02221 pt.X = infoAdapter.MonitorRectangle.Left + windowOffsetX;
02222 pt.Y = infoAdapter.MonitorRectangle.Top + windowOffsetY;
02223 }
02224
02225 }
02226 else
02227 {
02228
02229 State.FullScreenClientRectangle = new System.Drawing.Rectangle(0,0, newDeviceSettings.presentParams.BackBufferWidth,
02230 newDeviceSettings.presentParams.BackBufferHeight);
02231 }
02232
02233
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;
02246
02247
02248 BehaviorFlags flags = new BehaviorFlags(behaviorFlags);
02249
02250 System.Text.StringBuilder builder = new System.Text.StringBuilder();
02251
02252 builder.Append(deviceType.ToString());
02253
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
02281 builder.Append(": ");
02282 builder.Append(info.Description);
02283
02284
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
02348 if (DeviceLost != null)
02349 DeviceLost(this, EventArgs.Empty);
02350
02351
02352
02353 AdjustWindowStyle(Window, IsWindowed);
02354
02355 try
02356 {
02357
02358
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
02368 if (!(e is DeviceLostException))
02369 {
02370 DisplayErrorMessage(new ResettingDeviceException(e));
02371 }
02372 }
02373
02374
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;
02396
02397 if (State.IsDeviceLost || State.IsRenderingPaused)
02398 {
02399
02400
02401 System.Threading.Thread.Sleep(100);
02402 }
02403
02404 if (!State.IsActive)
02405 {
02406
02407 System.Threading.Thread.Sleep(20);
02408 }
02409
02410 if (State.IsDeviceLost && !State.IsRenderingPaused)
02411 {
02412 int result;
02413
02414 if (!device.CheckCooperativeLevel(out result))
02415 {
02416 if (result == (int)ResultCode.DeviceLost)
02417 {
02418
02419
02420 System.Threading.Thread.Sleep(50);
02421 return;
02422 }
02423
02424
02425
02426
02427 if (IsWindowed)
02428 {
02429 DisplayMode adapterDesktopMode = Manager.Adapters[(int)State.CurrentDeviceSettings.AdapterOrdinal].CurrentDisplayMode;
02430 if (State.CurrentDeviceSettings.AdapterFormat != adapterDesktopMode.Format)
02431 {
02432
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
02456
02457 ChangeDevice(settings, null, false);
02458 }
02459 catch
02460 {
02461 DisplayErrorMessage(new NoCompatibleDevicesException());
02462 Dispose();
02463 }
02464 return;
02465 }
02466 }
02467
02468
02469 try
02470 {
02471 Reset3DEnvironment();
02472 }
02473 catch (DeviceLostException)
02474 {
02475
02476 System.Threading.Thread.Sleep(50);
02477 return;
02478 }
02479 catch
02480 {
02481
02482
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
02501 double time = FrameworkTimer.GetTime();
02502 float elapsedTime = (float)FrameworkTimer.GetElapsedTime();
02503
02504
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
02515 UpdateFrameStats();
02516
02517
02518
02519 if (State.Settings != null && State.IsD3DSettingsDialogShowing)
02520 {
02521 if (!State.IsRenderingPaused)
02522 {
02523
02524 device.Clear(ClearFlags.Target, 0x00003F3F, 1.0f, 0);
02525
02526
02527 device.BeginScene();
02528 State.Settings.OnRender(elapsedTime);
02529 device.EndScene();
02530 }
02531 }
02532 else
02533 {
02534 HandleTimers();
02535
02536
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
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
02561 try
02562 {
02563 device.Present();
02564 }
02565 catch (DeviceLostException)
02566 {
02567
02568 State.IsDeviceLost = true;
02569 }
02570 catch (DriverInternalErrorException)
02571 {
02572
02573
02574
02575
02576
02577
02578
02579
02580
02581
02582
02583
02584
02585
02586 State.IsDeviceLost = true;
02587 }
02588 }
02589
02590
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
02606 Cleanup3DEnvironment(true);
02607
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
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
02634 FrameworkTimer.Stop();
02635 }
02636 else
02637 {
02638
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;
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
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
02734 State.CurrentDeviceSettings = null;
02735 }
02736
02737
02738 State.BackBufferSurfaceDesc = new SurfaceDescription();
02739 State.Caps = new Caps();
02740 State.WasDeviceCreated = false;
02741 }
02742
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
02769
02770 AdjustWindowStyle(Window, IsWindowed);
02771
02772
02773
02774 PrepareDevice(device);
02775
02776 try
02777 {
02778
02779 if (State.Settings != null)
02780 {
02781 State.Settings.OnCreateDevice(device);
02782 State.Settings.OnResetDevice();
02783 }
02784
02785 DialogResourceManager.GetGlobalInstance().OnCreateDevice(device);
02786
02787
02788 ResourceCache.GetGlobalInstance().OnCreateDevice(device);
02789
02790
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
02815 DialogResourceManager.GetGlobalInstance().OnResetDevice(device);
02816
02817
02818 ResourceCache.GetGlobalInstance().OnResetDevice(device);
02819
02820
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
02856 UpdateStaticFrameStats();
02857
02858
02859 using(Surface backBuffer = device.GetBackBuffer(0, 0, BackBufferType.Mono))
02860 {
02861 State.BackBufferSurfaceDesc = backBuffer.Description;
02862 }
02863
02864
02865 State.Caps = device.DeviceCaps;
02866
02867
02868 if (State.IsShowingCursorWhenFullScreen && !IsWindowed)
02869 {
02870
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
02880 if (State.IsCursorClippedWhenFullScreen)
02881 {
02882 if (!IsWindowed)
02883 {
02884
02885 System.Windows.Forms.Cursor.Clip = State.FullScreenClientRectangle;
02886 }
02887 else
02888 {
02889
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)
02902 return;
02903
02904 if (isWindowed)
02905 {
02906
02907
02908 if (State.WindowDeviceWindowed != State.WindowDeviceFullScreen)
02909 {
02910 State.WindowDeviceFullScreen.Hide();
02911 }
02912
02913
02914 window.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Sizable;
02915 }
02916 else
02917 {
02918
02919
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
02932 window.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
02933 }
02934 }
02935
02939 private void UpdateFrameStats()
02940 {
02941 if (State.AreStatsHidden)
02942 return;
02943
02944
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;
02967
02968 State.StaticFrameStats = string.Empty;
02969 DeviceSettings settings = State.CurrentDeviceSettings;
02970 if (settings.presentParams == null)
02971 return;
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;
02979
02980
02981 string formatString = null;
02982 if (settings.AdapterFormat == combo.BackBufferFormat)
02983 {
02984
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
02994 string depthFormat = null;
02995 if (settings.presentParams.EnableAutoDepthStencil)
02996 {
02997 depthFormat = " Format." + settings.presentParams.AutoDepthStencilFormat.ToString();
02998 }
02999
03000
03001 string multiSampleString = null;
03002 switch(settings.presentParams.MultiSample)
03003 {
03004 case MultiSampleType.None:
03005 multiSampleString = null;
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
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
03038 return combo.AdapterFormat;
03039 }
03040 }
03041 }
03042
03043
03044 return backbufferFormat;
03045 }
03046
03047
03051 private void HandlePossibleSizeChange()
03052 {
03053 if ( (!State.WasDeviceCreated) || (State.AreSizeChangesIgnored) )
03054 return;
03055
03056 if (!State.CurrentDeviceSettings.presentParams.Windowed)
03057 return;
03058
03059 if (Window == null)
03060 return;
03061
03062 System.Drawing.Rectangle oldClient = State.ClientRectangle;
03063
03064 State.ClientRectangle = Window.ClientRectangle;
03065
03066
03067 State.WindowBoundsRectangle = Window.Bounds;
03068
03069
03070 if (oldClient.Width != Window.ClientRectangle.Width || oldClient.Height != Window.ClientRectangle.Height)
03071 {
03072
03073
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
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
03106 if (!State.CanAutoChangeAdapter)
03107 return;
03108
03109 IntPtr monitorHandle = NativeMethods.MonitorFromWindow(Window.Handle, 1);
03110 if (monitorHandle != State.AdapterMonitor)
03111 {
03112
03113 Pause(true, true);
03114
03115 uint newOrdinal = GetAdapterOridinalFromMonitor(monitorHandle);
03116
03117
03118
03119 DeviceSettings settings = State.CurrentDeviceSettings.Clone();
03120 settings.AdapterOrdinal = newOrdinal;
03121
03122
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
03143 settings = FindValidDeviceSettings(settings, match);
03144 try
03145 {
03146
03147
03148 ChangeDevice(settings, null, false);
03149 }
03150 catch (Exception e)
03151 {
03152
03153 Dispose();
03154 Pause(false, false);
03155 System.Diagnostics.Debugger.Log(0, string.Empty, e.ToString());
03156 return;
03157 }
03158 }
03159 catch
03160 {
03161
03162
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
03186 System.Reflection.Assembly currentAssembly = System.Reflection.Assembly.GetCallingAssembly();
03187 foreach(string s in currentAssembly.GetManifestResourceNames())
03188 {
03189 try
03190 {
03191
03192 System.IO.Stream resourceStream = currentAssembly.GetManifestResourceStream(s);
03193 return new System.Drawing.Icon(resourceStream);
03194 }
03195 catch
03196 {
03197
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
03212 continue;
03213 }
03214 }
03215 }
03216
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
03284 dialog = new SettingsDialog(this);
03285 State.Settings = dialog;
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
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
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
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
03575 State.Device.Clear(ClearFlags.Target, 0x00003F3F, 1.0f, 0);
03576
03577
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
03591 try
03592 {
03593 State.Device.Present();
03594 }
03595 catch(DeviceLostException)
03596 {
03597
03598 State.IsDeviceLost = true;
03599 }
03600 catch(DriverInternalErrorException)
03601 {
03602
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);
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
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)
03653 {
03654
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:
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
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
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
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
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
03807
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)
03818 {
03819
03820
03821
03822
03823 m.Result = TrueIntPtr;
03824 }
03825 if (m.WParam.ToInt32() == 7)
03826 {
03827
03828
03829
03830
03831
03832
03833
03834 FrameworkTimer.Reset();
03835 State.LastStatsUpdateTime = 0;
03836
03837 m.Result = TrueIntPtr;
03838 }
03839 break;
03840 case NativeMethods.WindowMessage.SystemCommand:
03841
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
03870 if (isDisposed)
03871 return;
03872
03873
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
03881 State.IsInsideMainloop = true;
03882
03883
03884
03885 if (!State.WasDeviceCreated)
03886 {
03887 if (State.WasDeviceCreateCalled)
03888 {
03889
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
03901 State.ApplicationExitCode = 1;
03902 throw;
03903 }
03904 }
03905
03906
03907
03908
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
03918 System.Windows.Forms.Application.Idle += new EventHandler(OnApplicationIdle);
03919
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
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
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
03961 GC.SuppressFinalize(this);
03962
03963 if (!isDisposed)
03964 {
03965
03966 if (Disposing != null)
03967 Disposing(this, EventArgs.Empty);
03968
03969
03970 if (Window != null)
03971 {
03972
03973 Window.BeginInvoke(new DisposeDelegate(this.Shutdown));
03974 }
03975 else
03976 {
03977
03978 Shutdown();
03979 }
03980 }
03981
03982
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
03998 State.IsInsideDeviceCallback = true;
03999
04000
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
04013 if (Disposing != null)
04014 Disposing(this, e);
04015
04016
04017 State.IsInsideDeviceCallback = false;
04018 }
04019
04021 private void OnDeviceLost(object sender, EventArgs e)
04022 {
04023
04024 State.IsInsideDeviceCallback = true;
04025
04026
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
04039 if (DeviceLost != null)
04040 DeviceLost(this, e);
04041
04042
04043 State.IsInsideDeviceCallback = false;
04044 }
04045
04047 private void OnDeviceReset(object sender, EventArgs e)
04048 {
04049
04050 Device device = sender as Device;
04051 System.Diagnostics.Debug.Assert(device != null, "Must have a device here.");
04052
04053
04054 State.IsInsideDeviceCallback = true;
04055
04056
04057
04058 PrepareDevice(device);
04059
04060 if (State.Settings != null)
04061 State.Settings.OnResetDevice();
04062
04063
04064 DialogResourceManager.GetGlobalInstance().OnResetDevice(device);
04065
04066 ResourceCache.GetGlobalInstance().OnResetDevice(device);
04067
04068
04069 if (DeviceReset != null)
04070 DeviceReset(this, new DeviceEventArgs(device, State.BackBufferSurfaceDesc));
04071
04072
04073 State.AreDeviceObjectsReset = true;
04074
04075 State.IsInsideDeviceCallback = false;
04076 }
04077 #endregion
04078
04079 }
04080 }