OSDN Git Service

#35680 Direct3D、DirectSound、DirectInputのフレームワークをSharpDX 4.0.1に変更(DTXManiaからの輸入。またこの影響...
[dtxmaniaxg-verk/dtxmaniaxg-verk-git.git] / FDK17プロジェクト / コード / 01.フレームワーク / Core / Game.cs
1 /*
2 * Copyright (c) 2007-2009 SlimDX Group
3
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22 using System;
23 using System.ComponentModel;
24 using System.Threading;
25 using System.Windows.Forms;
26 using SharpDX;
27 using SharpDX.Direct3D9;
28 using System.Collections.ObjectModel;
29
30 namespace SampleFramework
31 {
32     /// <summary>
33     /// Presents an easy to use wrapper for making games and samples.
34     /// </summary>
35     public abstract class Game : IDisposable
36     {
37         GameClock clock = new GameClock();
38         GameTime gameTime = new GameTime();
39         TimeSpan maximumElapsedTime = TimeSpan.FromMilliseconds(500.0);
40         TimeSpan totalGameTime;
41         TimeSpan accumulatedElapsedGameTime;
42         TimeSpan lastFrameElapsedGameTime;
43         TimeSpan lastFrameElapsedRealTime;
44         TimeSpan targetElapsedTime = TimeSpan.FromTicks(166667);
45         TimeSpan inactiveSleepTime = TimeSpan.FromMilliseconds(20.0);
46         int updatesSinceRunningSlowly1 = int.MaxValue;
47         int updatesSinceRunningSlowly2 = int.MaxValue;
48         bool forceElapsedTimeToZero;
49         bool drawRunningSlowly;
50         long lastUpdateFrame;
51         float lastUpdateTime;
52
53         /// <summary>
54         /// Occurs when the game is disposed.
55         /// </summary>
56         public event EventHandler Disposed;
57
58         /// <summary>
59         /// Occurs when the game is activated.
60         /// </summary>
61         public event EventHandler Activated;
62
63         /// <summary>
64         /// Occurs when the game is deactivated.
65         /// </summary>
66         public event EventHandler Deactivated;
67
68         /// <summary>
69         /// Occurs when the game is exiting.
70         /// </summary>
71         public event EventHandler Exiting;
72
73         /// <summary>
74         /// Occurs when a drawing frame is about to start.
75         /// </summary>
76         public event CancelEventHandler FrameStart;
77
78         /// <summary>
79         /// Occurs when a drawing frame ends.
80         /// </summary>
81         public event EventHandler FrameEnd;
82
83         /// <summary>
84         /// Gets or sets the inactive sleep time.
85         /// </summary>
86         /// <value>The inactive sleep time.</value>
87         public TimeSpan InactiveSleepTime
88         {
89             get { return inactiveSleepTime; }
90             set
91             {
92                 // error checking
93                 if (value < TimeSpan.Zero)
94                     throw new ArgumentOutOfRangeException("value", "Inactive sleep time cannot be less than zero.");
95                 inactiveSleepTime = value;
96             }
97         }
98
99         /// <summary>
100         /// Gets or sets the target elapsed time.
101         /// </summary>
102         /// <value>The target elapsed time.</value>
103         public TimeSpan TargetElapsedTime
104         {
105             get { return targetElapsedTime; }
106             set
107             {
108                 // error checking
109                 if (value <= TimeSpan.Zero)
110                     throw new ArgumentOutOfRangeException("value", "Target elapsed time must be greater than zero.");
111                 targetElapsedTime = value;
112             }
113         }
114
115         /// <summary>
116         /// Gets or sets a value indicating whether the game is using a fixed time step.
117         /// </summary>
118         /// <value>
119         /// <c>true</c> if the game is using a fixed time step; otherwise, <c>false</c>.
120         /// </value>
121         public bool IsFixedTimeStep
122         {
123             get;
124             set;
125         }
126
127         /// <summary>
128         /// Gets a value indicating whether this <see cref="Game"/> is exiting.
129         /// </summary>
130         /// <value><c>true</c> if exiting; otherwise, <c>false</c>.</value>
131         public bool IsExiting
132         {
133             get;
134             private set;
135         }
136
137         /// <summary>
138         /// Gets or sets a value indicating whether this instance is running.
139         /// </summary>
140         /// <value>
141         /// <c>true</c> if this instance is running; otherwise, <c>false</c>.
142         /// </value>
143         public bool IsRunning
144         {
145             get;
146             private set;
147         }
148
149         /// <summary>
150         /// Gets the game window.
151         /// </summary>
152         /// <value>The game window.</value>
153         public GameWindow Window
154         {
155             get;
156             private set;
157         }
158
159         /// <summary>
160         /// Gets the graphics device manager.
161         /// </summary>
162         /// <value>The graphics device manager.</value>
163         public GraphicsDeviceManager GraphicsDeviceManager
164         {
165             get;
166             private set;
167         }
168
169         /// <summary>
170         /// Gets or sets a value indicating whether this <see cref="Game"/> is active.
171         /// </summary>
172         /// <value><c>true</c> if active; otherwise, <c>false</c>.</value>
173         public bool IsActive
174         {
175             get;
176             private set;
177         }
178
179         /// <summary>
180         /// Initializes the <see cref="Game"/> class.
181         /// </summary>
182         static Game()
183         {
184             // configure SlimDX
185             //Configuration.ThrowOnError = true;
186             //Configuration.AddResultWatch(ResultCode.DeviceLost, ResultWatchFlags.AlwaysIgnore);
187             //Configuration.AddResultWatch(ResultCode.WasStillDrawing, ResultWatchFlags.AlwaysIgnore);
188
189 #if DEBUG
190             //Configuration.DetectDoubleDispose = true;
191             Configuration.EnableObjectTracking = true;
192                         //Configuration.EnableTrackingReleaseOnFinalizer = true;
193                         //Configuration.EnableReleaseOnFinalizer = true;
194 #else
195             //Configuration.DetectDoubleDispose = false;
196             Configuration.EnableObjectTracking = false;
197 #endif
198
199             // setup the application
200             Application.EnableVisualStyles();
201             Application.SetCompatibleTextRenderingDefault(false);
202         }
203
204         /// <summary>
205         /// Initializes a new instance of the <see cref="Game"/> class.
206         /// </summary>
207         protected Game()
208         {
209             IsFixedTimeStep = true;
210
211             Window = new GameWindow();
212             Window.ApplicationActivated += Window_ApplicationActivated;
213             Window.ApplicationDeactivated += Window_ApplicationDeactivated;
214             Window.Suspend += Window_Suspend;
215             Window.Resume += Window_Resume;
216             Window.Paint += Window_Paint;
217
218             GraphicsDeviceManager = new GraphicsDeviceManager(this);
219         }
220
221         /// <summary>
222         /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
223         /// </summary>
224         public void Dispose()
225         {
226             // GraphicsDeviceManager.Dispose will come around and call the Dispose(bool)
227             // overload, so we don't need to do it here. It's convoluted, but it works well.
228             if (GraphicsDeviceManager != null)
229                 GraphicsDeviceManager.Dispose();
230             GraphicsDeviceManager = null;
231
232             if (Disposed != null)
233                 Disposed(this, EventArgs.Empty);
234
235             GC.SuppressFinalize(this);
236         }
237
238         /// <summary>
239         /// Exits the game.
240         /// </summary>
241         public void Exit()
242         {
243             // request the game to terminate
244             IsExiting = true;
245         }
246
247         /// <summary>
248         /// Runs the game.
249         /// </summary>
250         public void Run()
251         {
252             IsRunning = true;
253
254             try
255             {
256                 gameTime.ElapsedGameTime = 0;
257                 gameTime.ElapsedRealTime = 0;
258                 gameTime.TotalGameTime = (float)totalGameTime.TotalSeconds;
259                 gameTime.TotalRealTime = (float)clock.CurrentTime.TotalSeconds;
260                 gameTime.IsRunningSlowly = false;
261
262                 Update(gameTime);
263
264                 Application.Idle += Application_Idle;
265                 Application.Run(Window);
266             }
267             finally
268             {
269                 Application.Idle -= Application_Idle;
270                 IsRunning = false;
271                 OnExiting(EventArgs.Empty);
272             }
273         }
274
275         /// <summary>
276         /// Performs one complete frame for the game.
277         /// </summary>
278         public void Tick()
279         {
280             // if we are exiting, do nothing
281             if (IsExiting)
282                 return;
283
284             // if we are inactive, sleep for a bit
285             //if (!IsActive)
286             //    Thread.Sleep((int)InactiveSleepTime.TotalMilliseconds);
287
288             clock.Step();
289
290             gameTime.TotalRealTime = (float)clock.CurrentTime.TotalSeconds;
291             gameTime.ElapsedRealTime = (float)clock.ElapsedTime.TotalSeconds;
292             lastFrameElapsedRealTime += clock.ElapsedTime;
293             TimeSpan elapsedAdjustedTime = clock.ElapsedAdjustedTime;
294             if (elapsedAdjustedTime < TimeSpan.Zero)
295                 elapsedAdjustedTime = TimeSpan.Zero;
296
297             if (forceElapsedTimeToZero)
298             {
299                 gameTime.ElapsedRealTime = 0;
300                 lastFrameElapsedRealTime = elapsedAdjustedTime = TimeSpan.Zero;
301                 forceElapsedTimeToZero = false;
302             }
303
304             // cap the adjusted time
305             if (elapsedAdjustedTime > maximumElapsedTime)
306                 elapsedAdjustedTime = maximumElapsedTime;
307
308             // check if we are using a fixed or variable time step
309             if (IsFixedTimeStep)
310             {
311                 accumulatedElapsedGameTime += elapsedAdjustedTime;
312                 long ratio = accumulatedElapsedGameTime.Ticks / TargetElapsedTime.Ticks;
313                 accumulatedElapsedGameTime = TimeSpan.FromTicks(accumulatedElapsedGameTime.Ticks % TargetElapsedTime.Ticks);
314                 lastFrameElapsedGameTime = TimeSpan.Zero;
315                 if (ratio == 0)
316                     return;
317                 TimeSpan targetElapsedTime = TargetElapsedTime;
318
319                 if (ratio > 1)
320                 {
321                     updatesSinceRunningSlowly2 = updatesSinceRunningSlowly1;
322                     updatesSinceRunningSlowly1 = 0;
323                 }
324                 else
325                 {
326                     if (updatesSinceRunningSlowly1 < int.MaxValue)
327                         updatesSinceRunningSlowly1++;
328                     if (updatesSinceRunningSlowly2 < int.MaxValue)
329                         updatesSinceRunningSlowly2++;
330                 }
331
332                 drawRunningSlowly = updatesSinceRunningSlowly2 < 20;
333
334                 // update until it's time to draw the next frame
335                 while (ratio > 0 && !IsExiting)
336                 {
337                     ratio -= 1;
338
339                     try
340                     {
341                         gameTime.ElapsedGameTime = (float)targetElapsedTime.TotalSeconds;
342                         gameTime.TotalGameTime = (float)totalGameTime.TotalSeconds;
343                         gameTime.IsRunningSlowly = drawRunningSlowly;
344
345                         Update(gameTime);
346                     }
347                     finally
348                     {
349                         lastFrameElapsedGameTime += targetElapsedTime;
350                         totalGameTime += targetElapsedTime;
351                     }
352                 }
353             }
354             else
355             {
356                 drawRunningSlowly = false;
357                 updatesSinceRunningSlowly1 = int.MaxValue;
358                 updatesSinceRunningSlowly2 = int.MaxValue;
359
360                 // make sure we shouldn't be exiting
361                 if (!IsExiting)
362                 {
363                     try
364                     {
365                         gameTime.ElapsedGameTime = 0;
366                         lastFrameElapsedGameTime = elapsedAdjustedTime;
367                         gameTime.TotalGameTime = (float)totalGameTime.TotalSeconds;
368                         gameTime.IsRunningSlowly = false;
369
370                         Update(gameTime);
371                     }
372                     finally
373                     {
374                         totalGameTime += elapsedAdjustedTime;
375                     }
376                 }
377             }
378
379             DrawFrame();
380
381             // refresh the FPS counter once per second
382             lastUpdateFrame++;
383             if ((float)clock.CurrentTime.TotalSeconds - lastUpdateTime > 1.0f)
384             {
385                 gameTime.FramesPerSecond = (float)lastUpdateFrame / (float)(clock.CurrentTime.TotalSeconds - lastUpdateTime);
386                 lastUpdateTime = (float)clock.CurrentTime.TotalSeconds;
387                 lastUpdateFrame = 0;
388             }
389         }
390
391         /// <summary>
392         /// Resets the elapsed time.
393         /// </summary>
394         public void ResetElapsedTime()
395         {
396             forceElapsedTimeToZero = true;
397             updatesSinceRunningSlowly1 = int.MaxValue;
398             updatesSinceRunningSlowly2 = int.MaxValue;
399         }
400
401         /// <summary>
402         /// Allows the game to perform logic processing.
403         /// </summary>
404         /// <param name="gameTime">The time passed since the last update.</param>
405         protected virtual void Update(GameTime gameTime)
406         {
407         }
408
409         /// <summary>
410         /// Called when a frame is ready to be drawn.
411         /// </summary>
412         /// <param name="gameTime">The time passed since the last frame.</param>
413         protected virtual void Draw(GameTime gameTime)
414         {
415         }
416
417         /// <summary>
418         /// Initializes the game.
419         /// </summary>
420         protected internal virtual void Initialize()
421         {
422         }
423
424         /// <summary>
425         /// Loads graphical resources.
426         /// </summary>
427         protected internal virtual void LoadContent()
428         {
429         }
430
431         /// <summary>
432         /// Unloads graphical resources.
433         /// </summary>
434         protected internal virtual void UnloadContent()
435         {
436         }
437
438         /// <summary>
439         /// Releases unmanaged and - optionally - managed resources
440         /// </summary>
441         /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
442         protected internal virtual void Dispose(bool disposing)
443         {
444         }
445
446         /// <summary>
447         /// Raises the <see cref="E:Activated"/> event.
448         /// </summary>
449         /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
450         protected virtual void OnActivated(EventArgs e)
451         {
452             if (Activated != null)
453                 Activated(this, e);
454         }
455
456         /// <summary>
457         /// Raises the <see cref="E:Deactivated"/> event.
458         /// </summary>
459         /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
460         protected virtual void OnDeactivated(EventArgs e)
461         {
462             if (Deactivated != null)
463                 Deactivated(this, e);
464         }
465
466         /// <summary>
467         /// Raises the <see cref="E:Exiting"/> event.
468         /// </summary>
469         /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
470         protected virtual void OnExiting(EventArgs e)
471         {
472             if (Exiting != null)
473                 Exiting(this, e);
474         }
475
476         /// <summary>
477         /// Raises the <see cref="E:FrameStart"/> event.
478         /// </summary>
479         /// <param name="e">The <see cref="System.ComponentModel.CancelEventArgs"/> instance containing the event data.</param>
480         protected virtual void OnFrameStart(CancelEventArgs e)
481         {
482             if (FrameStart != null)
483                 FrameStart(this, e);
484         }
485
486         /// <summary>
487         /// Raises the <see cref="E:FrameEnd"/> event.
488         /// </summary>
489         /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
490         protected virtual void OnFrameEnd(EventArgs e)
491         {
492             if (FrameEnd != null)
493                 FrameEnd(this, e);
494         }
495
496         void DrawFrame()
497         {
498             try
499             {
500                                 if ( !IsExiting /* && !Window.IsMinimized */ )          // #28230 2012.5.1 yyagi
501                                 {
502                     CancelEventArgs e = new CancelEventArgs(false);
503                     OnFrameStart(e);
504                     if (!e.Cancel)
505                     {
506                         gameTime.TotalRealTime = (float)clock.CurrentTime.TotalSeconds;
507                         gameTime.ElapsedRealTime = (float)lastFrameElapsedRealTime.TotalSeconds;
508                         gameTime.TotalGameTime = (float)totalGameTime.TotalSeconds;
509                         gameTime.ElapsedGameTime = (float)lastFrameElapsedGameTime.TotalSeconds;
510                         gameTime.IsRunningSlowly = drawRunningSlowly;
511
512                         Draw(gameTime);
513
514                         OnFrameEnd(EventArgs.Empty);
515                     }
516                 }
517             }
518             finally
519             {
520                 lastFrameElapsedGameTime = TimeSpan.Zero;
521                 lastFrameElapsedRealTime = TimeSpan.Zero;
522             }
523         }
524
525         void Application_Idle(object sender, EventArgs e)
526         {
527             NativeMessage message;
528             while (!NativeMethods.PeekMessage(out message, IntPtr.Zero, 0, 0, 0))
529             {
530                 if (IsExiting)
531                     Window.Close();
532                 else
533                     Tick();
534             }
535         }
536
537         void Window_ApplicationDeactivated(object sender, EventArgs e)
538         {
539             if (IsActive)
540             {
541                 IsActive = false;
542                 OnDeactivated(EventArgs.Empty);
543             }
544         }
545
546         void Window_ApplicationActivated(object sender, EventArgs e)
547         {
548             if (!IsActive)
549             {
550                 IsActive = true;
551                 OnActivated(EventArgs.Empty);
552             }
553         }
554
555         void Window_Paint(object sender, PaintEventArgs e)
556         {
557             DrawFrame();
558         }
559
560         void Window_Resume(object sender, EventArgs e)
561         {
562             clock.Resume();
563         }
564
565         void Window_Suspend(object sender, EventArgs e)
566         {
567             clock.Suspend();
568         }
569     }
570 }