2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Diagnostics;
6 using System.Windows.Forms;
7 using Microsoft.VisualBasic.ApplicationServices;
12 /// アプリケーションフォームの基礎クラス。デバイスリソースを持つ。
14 public class ApplicationBase : Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase
21 public bool ウィンドウモードである
23 get { return !this.全画面モードである; }
24 protected set { this.全画面モードである = !value; }
27 public ApplicationBase() : base()
29 this.EnableVisualStyles = true;
30 this.IsSingleInstance = true; // 単一インスタンスである
31 this.MainForm = new Form();
32 this.MainForm.Load += OnLoad;
33 this.MainForm.FormClosing += OnClosing;
34 this.MainForm.ClientSizeChanged += OnClientSizeChanged;
36 public void 全画面モードとウィンドウモードを切り替える()
38 this.スレッド排他領域.ReadLock( () => {
40 if( false == this.スレッド排他領域.アプリを終了せよ )
44 this.スレッド排他領域.デバイスリソース.SwapChain.SetFullscreenState( false, null ); // ウィンドウモードへ。
45 this.ウィンドウモードである = true;
49 this.スレッド排他領域.デバイスリソース.SwapChain.SetFullscreenState( true, null ); // 全画面モードへ。
50 this.全画面モードである = true;
57 protected SharpDX.Size2F 設計画面サイズdpx = SharpDX.Size2F.Empty;
60 /// GUIスレッドと進行描画スレッド(Main) とで排他が必要なデータを集めたクラス。
62 protected class Cスレッド排他領域 : FDK.同期.RWLockAction
66 get { return this.ReadLock( () => this.bs_アプリを終了せよ ); }
67 set { this.WriteLock( () => { this.bs_アプリを終了せよ = value; } ); }
69 public FDK.メディア.デバイスリソース デバイスリソース
71 get { return this.ReadLock( () => this.bs_デバイスリソース ); }
72 set { this.WriteLock( () => { this.bs_デバイスリソース = value; } ); }
74 public FDK.同期.TriStateEvent 進行描画スレッド生存中
76 get { return this.ReadLock( () => this.bs_進行描画スレッド生存中 ); }
77 set { this.WriteLock( () => { this.bs_進行描画スレッド生存中 = value; } ); }
82 protected bool bs_アプリを終了せよ = false;
83 protected FDK.メディア.デバイスリソース bs_デバイスリソース = null;
84 protected FDK.同期.TriStateEvent bs_進行描画スレッド生存中 = new 同期.TriStateEvent( 同期.TriStateEvent.状態種別.OFF );
88 protected Cスレッド排他領域 スレッド排他領域 = new Cスレッド排他領域();
90 protected virtual void 初期化する()
95 Debug.Assert( null == this.スレッド排他領域.デバイスリソース, "デバイスリソースの作成前であること。" );
96 this.設計画面サイズdpx = new SharpDX.Size2F( 640, 480 );
98 protected virtual void 終了する()
103 Debug.Assert( null != this.スレッド排他領域.デバイスリソース, "デバイスリソースが解放される前であること。" );
105 protected virtual void シーンを描画する()
109 // なお、このメソッドはGUIスレッドではなく進行描画スレッドから呼び出されるので注意。
112 this.スレッド排他領域.WriteLock( () => {
123 // 表示する。垂直帰線待ちなどで時間がかかるのでロックしないこと。
124 if( false == this.スレッド排他領域.アプリを終了せよ )
125 this.スレッド排他領域.デバイスリソース.SwapChain.Present( 0, SharpDX.DXGI.PresentFlags.None );
127 protected virtual void デバイス依存リソースを解放する()
129 // デバイスリソースはまだ解放されていない。
131 protected virtual void デバイス依存リソースを再構築する()
133 // デバイスリソースはまだ再構築されていない。
136 /// アプリが二重起動されたときに発生するイベント。
139 /// 後続のインスタンスは起動せず、既存のインスタンスに対してこのイベントが発生する。
140 /// eventArg.CommandLine で、後続のインスタンスのコマンドライン引数を確認することができる。
142 protected override void OnStartupNextInstance( StartupNextInstanceEventArgs eventArgs )
144 base.OnStartupNextInstance( eventArgs );
147 protected System.Threading.Thread 進行描画スレッド = null;
149 private void OnLoad( object sender, EventArgs e )
151 FDK.Log.現在のスレッドに名前をつける( "GUI" );
152 FDK.Log.BeginInfo( $"{FDK.Utilities.現在のメソッド名}" );
156 FDK.Log.BeginInfo( "派生クラスを初期化します。" );
158 Debug.Assert( SharpDX.Size2F.Empty != this.設計画面サイズdpx, "初期化メソッド内で設計画面サイズを設定してあること。" );
159 FDK.Log.Info( $"設計画面サイズ: {this.設計画面サイズdpx}" );
160 FDK.Log.Info( $"物理画面サイズ: {this.MainForm.ClientSize}" );
164 FDK.Log.EndInfo( "派生クラスを初期化しました。" );
169 FDK.Log.BeginInfo( "デバイスリソースを作成します。" );
170 this.スレッド排他領域.WriteLock( () => {
171 this.スレッド排他領域.デバイスリソース = new メディア.デバイスリソース();
172 this.スレッド排他領域.デバイスリソース.設計画面サイズdpx = this.設計画面サイズdpx;
173 this.スレッド排他領域.デバイスリソース.すべてのリソースを作成する( this.MainForm.ClientSize, this.MainForm.Handle );
178 FDK.Log.EndInfo( "デバイスリソースを作成しました。" );
183 FDK.Log.BeginInfo( "進行描画スレッドを開始します。" );
184 this.進行描画スレッド = new System.Threading.Thread( this.進行描画スレッド処理 ) {
186 Priority = System.Threading.ThreadPriority.AboveNormal, // 優先度: やや高
188 this.進行描画スレッド.Start();
189 this.スレッド排他領域.進行描画スレッド生存中.ONになるまでブロックする();
193 FDK.Log.EndInfo( "進行描画スレッドを開始しました。" );
196 FDK.Log.EndInfo( $"{FDK.Utilities.現在のメソッド名}" );
198 private void OnClosing( object sender, FormClosingEventArgs e )
200 FDK.Log.BeginInfo( $"{FDK.Utilities.現在のメソッド名}" );
203 this.スレッド排他領域.アプリを終了せよ = true;
205 // 終了フラグをチェックした進行描画スレッドが終了し、このトライステートに OFF を通知してくるまで待つ。
206 this.スレッド排他領域.進行描画スレッド生存中.OFFになるまでブロックする();
207 FDK.Log.Info( "進行描画スレッドが終了したことを確認しました。" );
213 this.スレッド排他領域.デバイスリソース?.Dispose();
214 this.スレッド排他領域.デバイスリソース = null;
216 FDK.Log.EndInfo( $"{FDK.Utilities.現在のメソッド名}" );
218 private void OnClientSizeChanged( object sender, EventArgs e )
222 FDK.Log.BeginInfo( $"{FDK.Utilities.現在のメソッド名}" );
223 FDK.Log.Info( $"新しいクライアントサイズ = {this.MainForm.ClientSize}" );
225 if( null == this.スレッド排他領域.デバイスリソース )
227 FDK.Log.Info( " まだ初期化されてないので、何もしません。" );
230 if( this.MainForm.WindowState == FormWindowState.Minimized )
232 FDK.Log.Info( "最小化されました。" );
236 this.スレッド排他領域.ReadLock( () => {
238 var dr = this.スレッド排他領域.ReadLock( () => this.スレッド排他領域.デバイスリソース );
239 Debug.Assert( null != dr, "デバイスリソースが作成済みであること。" );
241 // 現在の画面モードを取得しておく。(Alt+TABなど、勝手に全画面を解除されることもあるので。)
242 SharpDX.Mathematics.Interop.RawBool fullscreen;
243 SharpDX.DXGI.Output outputTarget;
244 dr.SwapChain.GetFullscreenState( out fullscreen, out outputTarget );
245 this.全画面モードである = fullscreen;
246 outputTarget?.Dispose();
247 FDK.Log.Info( $"現在、全画面モードである = {this.全画面モードである}" );
250 this.デバイス依存リソースを解放する();
251 dr.サイズに依存するリソースを解放する();
254 dr.物理画面サイズpx = new SharpDX.Size2F( this.MainForm.ClientSize.Width, this.MainForm.ClientSize.Height );
257 dr.サイズに依存するリソースを作成する();
258 this.デバイス依存リソースを再構築する();
264 FDK.Log.EndInfo( $"{FDK.Utilities.現在のメソッド名}" );
267 private void 進行描画スレッド処理()
269 this.スレッド排他領域.進行描画スレッド生存中.状態 = 同期.TriStateEvent.状態種別.ON;
271 FDK.Log.現在のスレッドに名前をつける( "Main" );
272 FDK.Log.Info( "進行描画スレッドを起動しました。" );
277 this.スレッド排他領域.ReadLock( () => {
279 this.スレッド排他領域.デバイスリソース.D3Dデバイスが消失していれば再構築する( out 異常発生 );
281 this.スレッド排他領域.アプリを終了せよ = true;
284 // フラグがセットされていれば、ループを抜けてスレッドを終了する。
285 if( this.スレッド排他領域.アプリを終了せよ )
288 // それ以外なら、シーンを進行・描画する。
292 this.スレッド排他領域.進行描画スレッド生存中.状態 = 同期.TriStateEvent.状態種別.OFF;
294 FDK.Log.Info( "アプリウィンドウをクローズします(非同期)。" );
295 this.MainForm.BeginInvoke( new Action( () => { this.MainForm.Close(); } ) );
297 FDK.Log.Info( "進行描画スレッドを終了します。" );