Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
GamePlatform.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 //
4 // Copyright (c) 2010-2013 SharpDX - Alexandre Mutel
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to deal
8 // in the Software without restriction, including without limitation the rights
9 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 // copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 // THE SOFTWARE.
23 
24 using System;
25 using System.Collections.Generic;
26 using System.Linq;
27 using SiliconStudio.Paradox.Graphics;
28 using SiliconStudio.Core;
29 
30 namespace SiliconStudio.Paradox.Games
31 {
32  internal abstract class GamePlatform : ReferenceBase, IGraphicsDeviceFactory, IGamePlatform
33  {
34  private bool hasExitRan = false;
35 
36  protected readonly GameBase game;
37 
38  protected readonly IServiceRegistry Services;
39 
40  protected GameWindow gameWindow;
41 
42  protected GamePlatform(GameBase game)
43  {
44  this.game = game;
45  Services = game.Services;
46  Services.AddService(typeof(IGraphicsDeviceFactory), this);
47  }
48 
49  public static GamePlatform Create(GameBase game)
50  {
51 #if SILICONSTUDIO_PLATFORM_WINDOWS_RUNTIME
52  return new GamePlatformWindowsRuntime(game);
53 #elif SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP && SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGL
54  return new GamePlatformOpenTK(game);
55 #elif SILICONSTUDIO_PLATFORM_ANDROID
56  return new GamePlatformAndroid(game);
57 #elif SILICONSTUDIO_PLATFORM_IOS
58  return new GamePlatformiOS(game);
59 #else
60  return new GamePlatformDesktop(game);
61 #endif
62  }
63 
64  public abstract string DefaultAppDirectory { get; }
65 
66  public object WindowContext { get; set; }
67 
68  public event EventHandler<EventArgs> Activated;
69 
70  public event EventHandler<EventArgs> Deactivated;
71 
72  public event EventHandler<EventArgs> Exiting;
73 
74  public event EventHandler<EventArgs> Idle;
75 
76  public event EventHandler<EventArgs> Resume;
77 
78  public event EventHandler<EventArgs> Suspend;
79 
80  public event EventHandler<EventArgs> WindowCreated;
81 
82  public GameWindow MainWindow
83  {
84  get
85  {
86  return gameWindow;
87  }
88  }
89 
90  internal abstract GameWindow[] GetSupportedGameWindows();
91 
92  public virtual GameWindow CreateWindow(GameContext gameContext)
93  {
94  gameContext = gameContext ?? new GameContext();
95 
96  var windows = GetSupportedGameWindows();
97 
98  foreach (var gameWindowToTest in windows)
99  {
100  if (gameWindowToTest.CanHandle(gameContext))
101  {
102  gameWindowToTest.Services = Services;
103  gameWindowToTest.Initialize(gameContext);
104  return gameWindowToTest;
105  }
106  }
107 
108  throw new ArgumentException("Game Window context not supported on this platform");
109  }
110 
111  public bool IsBlockingRun { get; protected set; }
112 
113  public void Run(GameContext gameContext)
114  {
115  gameWindow = CreateWindow(gameContext);
116 
117  // Register on Activated
118  gameWindow.GameContext = gameContext;
119  gameWindow.Activated += OnActivated;
120  gameWindow.Deactivated += OnDeactivated;
121  gameWindow.InitCallback = OnInitCallback;
122  gameWindow.RunCallback = OnRunCallback;
123 
124  var windowCreated = WindowCreated;
125  if (windowCreated != null)
126  {
127  windowCreated(this, EventArgs.Empty);
128  }
129 
130  gameWindow.Run();
131  }
132 
133  private void OnRunCallback()
134  {
135  // If/else outside of try-catch to separate user-unhandled exceptions properly
136  var unhandledException = game.UnhandledExceptionInternal;
137  if (unhandledException != null)
138  {
139  // Catch exceptions and transmit them to UnhandledException event
140  try
141  {
142  Tick();
143  }
144  catch (Exception e)
145  {
146  // Some system was listening for exceptions
147  unhandledException(this, new GameUnhandledExceptionEventArgs(e, false));
148  game.Exit();
149  }
150  }
151  else
152  {
153  Tick();
154  }
155  }
156 
157  private void OnInitCallback()
158  {
159  // If/else outside of try-catch to separate user-unhandled exceptions properly
160  var unhandledException = game.UnhandledExceptionInternal;
161  if (unhandledException != null)
162  {
163  // Catch exceptions and transmit them to UnhandledException event
164  try
165  {
166  game.InitializeBeforeRun();
167  }
168  catch (Exception e)
169  {
170  // Some system was listening for exceptions
171  unhandledException(this, new GameUnhandledExceptionEventArgs(e, false));
172  game.Exit();
173  }
174  }
175  else
176  {
177  game.InitializeBeforeRun();
178  }
179  }
180 
181  private void Tick()
182  {
183  game.Tick();
184 
185  if (!IsBlockingRun && game.IsExiting() && !hasExitRan)
186  {
187  hasExitRan = true;
188  OnExiting(this, EventArgs.Empty);
189  }
190  }
191 
192  public virtual void Exit()
193  {
194  // Notifies that the GameWindow should exit.
195  gameWindow.Exiting = true;
196  }
197 
198  protected void OnActivated(object source, EventArgs e)
199  {
200  EventHandler<EventArgs> handler = Activated;
201  if (handler != null) handler(this, e);
202  }
203 
204  protected void OnDeactivated(object source, EventArgs e)
205  {
206  EventHandler<EventArgs> handler = Deactivated;
207  if (handler != null) handler(this, e);
208  }
209 
210  protected void OnExiting(object source, EventArgs e)
211  {
212  EventHandler<EventArgs> handler = Exiting;
213  if (handler != null) handler(this, e);
214  }
215 
216  protected void OnIdle(object source, EventArgs e)
217  {
218  EventHandler<EventArgs> handler = Idle;
219  if (handler != null) handler(this, e);
220  }
221 
222  protected void OnResume(object source, EventArgs e)
223  {
224  EventHandler<EventArgs> handler = Resume;
225  if (handler != null) handler(this, e);
226  }
227 
228  protected void OnSuspend(object source, EventArgs e)
229  {
230  EventHandler<EventArgs> handler = Suspend;
231  if (handler != null) handler(this, e);
232  }
233 
234  protected void AddDevice(DisplayMode mode, GraphicsDeviceInformation deviceBaseInfo, GameGraphicsParameters preferredParameters, List<GraphicsDeviceInformation> graphicsDeviceInfos)
235  {
236  // TODO: Temporary woraround
237  if (mode == null)
238  mode = new DisplayMode(PixelFormat.R8G8B8A8_UNorm, 800, 480, new Rational(60, 1));
239 
240  var deviceInfo = deviceBaseInfo.Clone();
241 
242  deviceInfo.PresentationParameters.RefreshRate = mode.RefreshRate;
243 
244  if (preferredParameters.IsFullScreen)
245  {
246  deviceInfo.PresentationParameters.BackBufferFormat = mode.Format;
247  deviceInfo.PresentationParameters.BackBufferWidth = mode.Width;
248  deviceInfo.PresentationParameters.BackBufferHeight = mode.Height;
249  }
250  else
251  {
252  deviceInfo.PresentationParameters.BackBufferFormat = preferredParameters.PreferredBackBufferFormat;
253  deviceInfo.PresentationParameters.BackBufferWidth = preferredParameters.PreferredBackBufferWidth;
254  deviceInfo.PresentationParameters.BackBufferHeight = preferredParameters.PreferredBackBufferHeight;
255  }
256 
257  // TODO: Handle multisampling
258  deviceInfo.PresentationParameters.DepthStencilFormat = preferredParameters.PreferredDepthStencilFormat;
259  deviceInfo.PresentationParameters.MultiSampleCount = MSAALevel.None;
260 
261  if (!graphicsDeviceInfos.Contains(deviceInfo))
262  {
263  graphicsDeviceInfos.Add(deviceInfo);
264  }
265  }
266 
267  public virtual List<GraphicsDeviceInformation> FindBestDevices(GameGraphicsParameters preferredParameters)
268  {
269  var graphicsDeviceInfos = new List<GraphicsDeviceInformation>();
270 
271  // Iterate on each adapter
272  foreach (var graphicsAdapter in GraphicsAdapterFactory.Adapters)
273  {
274  // Skip adapeters that don't have graphics output
275  if (graphicsAdapter.Outputs.Length == 0)
276  {
277  continue;
278  }
279 
280  var preferredGraphicsProfiles = preferredParameters.PreferredGraphicsProfile;
281 
282  // INTEL workaround: it seems Intel driver doesn't support properly feature level 9.x. Fallback to 10.
283  if (graphicsAdapter.VendorId == 0x8086)
284  preferredGraphicsProfiles = preferredGraphicsProfiles.Select(x => x < GraphicsProfile.Level_10_0 ? GraphicsProfile.Level_10_0 : x).ToArray();
285 
286  // Iterate on each preferred graphics profile
287  foreach (var featureLevel in preferredGraphicsProfiles)
288  {
289  // Check if this profile is supported.
290  if (graphicsAdapter.IsProfileSupported(featureLevel))
291  {
292  var deviceInfo = new GraphicsDeviceInformation
293  {
294  Adapter = graphicsAdapter,
295  GraphicsProfile = featureLevel,
297  {
298  MultiSampleCount = MSAALevel.None,
299  IsFullScreen = preferredParameters.IsFullScreen,
300  PreferredFullScreenOutputIndex = preferredParameters.PreferredFullScreenOutputIndex,
301  PresentationInterval = preferredParameters.SynchronizeWithVerticalRetrace ? PresentInterval.One : PresentInterval.Immediate,
302  DeviceWindowHandle = MainWindow.NativeWindow,
303  }
304  };
305 
306  var preferredMode = new DisplayMode(preferredParameters.PreferredBackBufferFormat,
307  preferredParameters.PreferredBackBufferWidth,
308  preferredParameters.PreferredBackBufferHeight,
309  preferredParameters.PreferredRefreshRate);
310 
311  // if we want to switch to fullscreen, try to find only needed output, otherwise check them all
312  if (preferredParameters.IsFullScreen)
313  {
314  if (preferredParameters.PreferredFullScreenOutputIndex < graphicsAdapter.Outputs.Length)
315  {
316  var output = graphicsAdapter.Outputs[preferredParameters.PreferredFullScreenOutputIndex];
317  var displayMode = output.FindClosestMatchingDisplayMode(preferredGraphicsProfiles, preferredMode);
318  AddDevice(displayMode, deviceInfo, preferredParameters, graphicsDeviceInfos);
319  }
320  }
321  else
322  {
323  AddDevice(preferredMode, deviceInfo, preferredParameters, graphicsDeviceInfos);
324  }
325 
326  // If the profile is supported, we are just using the first best one
327  break;
328  }
329  }
330  }
331 
332  return graphicsDeviceInfos;
333  }
334 
335  public virtual GraphicsDevice CreateDevice(GraphicsDeviceInformation deviceInformation)
336  {
337  var graphicsDevice = GraphicsDevice.New(deviceInformation.Adapter, deviceInformation.DeviceCreationFlags, gameWindow.NativeWindow, deviceInformation.GraphicsProfile);
338  graphicsDevice.Presenter = new SwapChainGraphicsPresenter(graphicsDevice, deviceInformation.PresentationParameters);
339 
340  return graphicsDevice;
341  }
342 
343  public virtual void RecreateDevice(GraphicsDevice currentDevice, GraphicsDeviceInformation deviceInformation)
344  {
345  currentDevice.Recreate(deviceInformation.Adapter ?? GraphicsAdapterFactory.Default, new[] { deviceInformation.GraphicsProfile }, deviceInformation.DeviceCreationFlags, gameWindow.NativeWindow);
346  }
347 
348  public virtual void DeviceChanged(GraphicsDevice currentDevice, GraphicsDeviceInformation deviceInformation)
349  {
350  // Force to resize the gameWindow
351  gameWindow.Resize(deviceInformation.PresentationParameters.BackBufferWidth, deviceInformation.PresentationParameters.BackBufferHeight);
352  }
353 
354  public virtual GraphicsDevice ChangeOrCreateDevice(GraphicsDevice currentDevice, GraphicsDeviceInformation deviceInformation)
355  {
356  if (currentDevice == null)
357  {
358  currentDevice = CreateDevice(deviceInformation);
359  }
360  else
361  {
362  RecreateDevice(currentDevice, deviceInformation);
363  }
364 
365  DeviceChanged(currentDevice, deviceInformation);
366 
367  return currentDevice;
368  }
369 
370  protected override void Destroy()
371  {
372  if (gameWindow != null)
373  {
374  gameWindow.Dispose();
375  gameWindow = null;
376  }
377 
378  Activated = null;
379  Deactivated = null;
380  Exiting = null;
381  Idle = null;
382  Resume = null;
383  Suspend = null;
384  }
385  }
386 }
ComponentBase.Destroy() event.
static GraphicsAdapter[] Adapters
Collection of available adapters on the system.
A service registry is a IServiceProvider that provides methods to register and unregister services...
Describes the display mode.
Definition: DisplayMode.cs:10
Performs primitive-based rendering, creates resources, handles system-level variables, adjusts gamma ramp levels, and creates shaders. See The+GraphicsDevice+class to learn more about the class.
Base class for a IReferencable class.
Creates a new file, always. If a file exists, the function overwrites the file, clears the existing a...
GraphicsProfile
Identifies the set of supported devices for the demo based on device capabilities.
PixelFormat
Defines various types of pixel formats.
Definition: PixelFormat.cs:32
Describess how data will be displayed to the screen.