• R/O
  • SSH
  • HTTPS

mmdx: Commit


Commit MetaInfo

Revision801 (tree)
Zeit2011-06-05 07:53:15
Autorwilfrem

Log Message

リソース整理

Ändern Zusammenfassung

Diff

--- branches/XNA4/MikuMikuDanceXNADemo1/MikuMikuDanceXNADemo1/GameDebug/FpsCounter.cs (revision 800)
+++ branches/XNA4/MikuMikuDanceXNADemo1/MikuMikuDanceXNADemo1/GameDebug/FpsCounter.cs (nonexistent)
@@ -1,164 +0,0 @@
1-#region Using ステートメント
2-
3-using System;
4-using System.Collections.Generic;
5-using System.Diagnostics;
6-using System.Text;
7-
8-using Microsoft.Xna.Framework;
9-using Microsoft.Xna.Framework.Graphics;
10-
11-#endregion
12-
13-namespace DebugSample
14-{
15- /// <summary>
16- /// FPSの測定と表示用コンポーネント
17- /// </summary>
18- public class FpsCounter : DrawableGameComponent
19- {
20- #region プロパティ
21-
22- /// <summary>
23- /// 現在のFPS値
24- /// </summary>
25- public float Fps { get; private set; }
26-
27- /// <summary>
28- /// FPS測定間隔の所得と設定
29- /// </summary>
30- public TimeSpan SampleSpan { get; set; }
31-
32- #endregion
33-
34- #region フィールド
35-
36- // デバッグマネージャー
37- private DebugManager debugManager;
38-
39- // 測定用のストップウォッチ
40- private Stopwatch stopwatch;
41-
42- // 測定中のフレーム数
43- private int sampleFrames;
44-
45- // FPS表示用の文字バッファ
46- private StringBuilder stringBuilder = new StringBuilder(16);
47-
48- #endregion
49-
50- #region 初期化
51-
52- public FpsCounter(Game game)
53- : base(game)
54- {
55- SampleSpan = TimeSpan.FromSeconds(1);
56- }
57-
58- public override void Initialize()
59- {
60- // デバッグマネージャーをゲームのサービスから取得
61- debugManager =
62- Game.Services.GetService(typeof(DebugManager)) as DebugManager;
63-
64- if (debugManager == null)
65- throw new InvalidOperationException("DebugManaerが登録されていません");
66-
67- // デバッグコマンドがサービスに登録されているなら、FPSコマンドを登録する
68- IDebugCommandHost host =
69- Game.Services.GetService(typeof(IDebugCommandHost))
70- as IDebugCommandHost;
71-
72- if (host != null)
73- {
74- host.RegisterCommand("fps", "FPS Counter", this.CommandExecute);
75- Visible = false;
76- }
77-
78- // パラメーターの初期化
79- Fps = 0;
80- sampleFrames = 0;
81- stopwatch = Stopwatch.StartNew();
82- stringBuilder.Length = 0;
83-
84- base.Initialize();
85- }
86-
87- #endregion
88-
89- /// <summary>
90- /// FPSコマンド処理
91- /// </summary>
92- private void CommandExecute(IDebugCommandHost host,
93- string command, IList<string> arguments)
94- {
95- if (arguments.Count == 0)
96- Visible = !Visible;
97-
98- foreach (string arg in arguments)
99- {
100- switch (arg.ToLower())
101- {
102- case "on":
103- Visible = true;
104- break;
105- case "off":
106- Visible = false;
107- break;
108- }
109- }
110- }
111-
112- #region 更新と描画
113-
114- public override void Update(GameTime gameTime)
115- {
116- if (stopwatch.Elapsed > SampleSpan)
117- {
118- // FPSの更新と次の測定期間の開始
119- Fps = (float)sampleFrames / (float)stopwatch.Elapsed.TotalSeconds;
120-
121- stopwatch.Reset();
122- stopwatch.Start();
123- sampleFrames = 0;
124-
125- // 表示文字列の更新
126- stringBuilder.Length = 0;
127- stringBuilder.Append("FPS: ");
128- stringBuilder.AppendNumber(Fps);
129- }
130- }
131-
132- public override void Draw(GameTime gameTime)
133- {
134- sampleFrames++;
135-
136- SpriteBatch spriteBatch = debugManager.SpriteBatch;
137- SpriteFont font = debugManager.DebugFont;
138-
139- // FPS表示の周りに半透明の黒い矩形のサイズ計算と配置
140- Vector2 size = font.MeasureString("X");
141- Rectangle rc =
142- new Rectangle(0, 0, (int)(size.X * 14f), (int)(size.Y * 1.3f));
143-
144- Layout layout = new Layout(spriteBatch.GraphicsDevice.Viewport);
145- rc = layout.Place(rc, 0.01f, 0.01f, Alignment.TopLeft);
146-
147- // FPS表示を矩形の中で配置
148- size = font.MeasureString(stringBuilder);
149- layout.ClientArea = rc;
150- Vector2 pos = layout.Place(size, 0, 0.1f, Alignment.Center);
151-
152- // 描画
153- spriteBatch.Begin();
154- spriteBatch.Draw(debugManager.WhiteTexture, rc, new Color(0, 0, 0, 128));
155- spriteBatch.DrawString(font, stringBuilder, pos, Color.White);
156- spriteBatch.End();
157-
158- base.Draw(gameTime);
159- }
160-
161- #endregion
162-
163- }
164-}
--- branches/XNA4/MikuMikuDanceXNADemo1/MikuMikuDanceXNADemo1/GameDebug/TimeRuler.cs (revision 800)
+++ branches/XNA4/MikuMikuDanceXNADemo1/MikuMikuDanceXNADemo1/GameDebug/TimeRuler.cs (nonexistent)
@@ -1,834 +0,0 @@
1-#region Using ステートメント
2-
3-using System;
4-using System.Collections.Generic;
5-using System.Diagnostics;
6-using System.Text;
7-using System.Threading;
8-using Microsoft.Xna.Framework;
9-using Microsoft.Xna.Framework.Graphics;
10-
11-#endregion
12-
13-namespace DebugSample
14-{
15- /// <summary>
16- /// CPU処理速度のリアルタイム測定用ツール
17- /// </summary>
18- /// <remarks>
19- /// このツールを使うことでボトルネックの発見と、あとどれだけの処理ができるのかが
20- /// 視覚的に判る。
21- /// また、リアルタイムプロファイラーなのでゲーム中に瞬間的に大量の処理をする場合の
22- /// 様子も把握することができる。
23- ///
24- /// TimeRulerがサポートしている機能は以下の通り:
25- /// * 最大8個(変更可)のバー表示
26- /// * 各マーカーに任意の色をつけることができる
27- /// * マーカーログ表示機能
28- /// * TRACE設定を外すとBeginMark/EndMark等のメソッドの呼び出し自体をしない
29- /// * 最大32個(変更可)のBeginMarkのネスト呼び出しに対応
30- /// * マルチスレッド対応
31- /// * 負荷状態による表示フレーム数の自動変化機能
32- ///
33- /// 基本的な使用方法は、Game.ComponentsにTimeRulerのインスタンスを追加し、
34- /// Game.Updateメソッドの先頭でtimerRuler.StartFrame()メソッドを呼ぶようにする。
35- ///
36- /// 後は測定したい部分の前後でBeginMark,EndMarkを呼び出す。
37- ///
38- /// timeRuler.BeginMark( "Update", Color.Blue );
39- /// // 測定したい処理
40- /// timerRuler.EndMark( "Update" );
41- ///
42- /// また、BeginMarkには測定結果を表示するバーのインデックスを指定できる(規定値は0)
43- ///
44- /// timeRuler.BeginMark( 1, "Update", Color.Blue );
45- ///
46- /// プロファイルに使用するメソッド自体にはConditionalAttributeを指定しているので、
47- /// BeginMark/EndMark等のメソッドはTRACEが設定されていないとメソッド呼び出しのコード
48- /// を生成しないようになっている。実際のリリース時にはビルド設定の
49- /// TRACE定数の定義のチェックボックスをクリアするのを忘れないようにすること。
50- ///
51- /// </remarks>
52- public class TimeRuler : DrawableGameComponent
53- {
54- #region 定数宣言
55-
56- /// <summary>
57- /// 最大バー表示数
58- /// </summary>
59- const int MaxBars = 8;
60-
61- /// <summary>
62- /// バーひとつあたりの最大サンプル数
63- /// </summary>
64- const int MaxSamples = 256;
65-
66- /// <summary>
67- /// バーひとつあたりの最大ネスト数
68- /// </summary>
69- const int MaxNestCall = 32;
70-
71- /// <summary>
72- /// 最多表示フレーム数
73- /// </summary>
74- const int MaxSampleFrames = 4;
75-
76- /// <summary>
77- /// ログのスナップを取る間隔(フレーム数)
78- /// </summary>
79- const int LogSnapDuration = 120;
80-
81- /// <summary>
82- /// バーの高さ(ピクセル)
83- /// </summary>
84- const int BarHeight = 8;
85-
86- /// <summary>
87- /// バーのパディング(ピクセル)
88- /// </summary>
89- const int BarPadding = 2;
90-
91- /// <summary>
92- /// 自動表示フレーム調整に掛かるフレーム数
93- /// </summary>
94- const int AutoAdjustDelay = 30;
95-
96- #endregion
97-
98- #region プロパティ
99-
100- /// <summary>
101- /// ログの表示設定の設定と取得
102- /// </summary>
103- public bool ShowLog { get; set; }
104-
105- /// <summary>
106- /// 目標表示フレーム数の取得と設定
107- /// </summary>
108- public int TargetSampleFrames { get; set; }
109-
110- /// <summary>
111- /// TimeRuler描画位置の取得と設定
112- /// </summary>
113- public Vector2 Position { get { return position; } set { position = value; } }
114-
115- /// <summary>
116- /// TimeRuler描画幅の取得と設定
117- /// </summary>
118- public int Width { get; set; }
119-
120- #endregion
121-
122- #region フィールド
123-
124-#if TRACE
125-
126- /// <summary>
127- /// マーカー構造体
128- /// </summary>
129- private struct Marker
130- {
131- public int MarkerId;
132- public float BeginTime;
133- public float EndTime;
134- public Color Color;
135- }
136-
137- /// <summary>
138- /// マーカーコレクション
139- /// </summary>
140- private class MarkerCollection
141- {
142- // マーカーコレクション
143- public Marker[] Markers = new Marker[MaxSamples];
144- public int MarkCount;
145-
146- // マーカーネスト情報
147- public int[] MarkerNests = new int[MaxNestCall];
148- public int NestCount;
149- }
150-
151- /// <summary>
152- /// フレームのログ
153- /// </summary>
154- private class FrameLog
155- {
156- // バー情報
157- public MarkerCollection[] Bars;
158-
159- public FrameLog()
160- {
161- // マーカーコレクション配列の初期化
162- Bars = new MarkerCollection[MaxBars];
163- for (int i = 0; i < MaxBars; ++i)
164- Bars[i] = new MarkerCollection();
165- }
166- }
167-
168- /// <summary>
169- /// マーカー情報
170- /// </summary>
171- private class MarkerInfo
172- {
173- // マーカー名
174- public string Name;
175-
176- // マーカーログ
177- public MarkerLog[] Logs = new MarkerLog[MaxBars];
178-
179- public MarkerInfo(string name)
180- {
181- Name = name;
182- }
183- }
184-
185- /// <summary>
186- /// マーカーログ情報
187- /// </summary>
188- private struct MarkerLog
189- {
190- public float SnapMin;
191- public float SnapMax;
192- public float SnapAvg;
193-
194- public float Min;
195- public float Max;
196- public float Avg;
197-
198- public int Samples;
199-
200- public Color Color;
201-
202- public bool Initialized;
203- }
204-
205- // デバッグマネージャー
206- DebugManager debugManager;
207-
208- // フレーム毎のログ
209- FrameLog[] logs;
210-
211- // 前フレームのログ
212- FrameLog prevLog;
213-
214- // 測定中のフレームログ
215- FrameLog curLog;
216-
217- // 現在のフレーム数
218- int frameCount;
219-
220- // 計測に使用するストップウォッチ
221- Stopwatch stopwatch = new Stopwatch();
222-
223- // マーカー情報配列
224- List<MarkerInfo> markers = new List<MarkerInfo>();
225-
226- // マーカー名からマーカーIDへの変換マップ
227- Dictionary<string, int> markerNameToIdMap = new Dictionary<string, int>();
228-
229- // サンプルフレーム自動調整用のカウンタ
230- int frameAdjust;
231-
232- // 現在の表示フレーム数
233- int sampleFrames;
234-
235- // マーカーログ表示文字列
236- StringBuilder logString = new StringBuilder(512);
237-
238- // You want to call StartFrame at beginning of Game.Update method.
239- // But Game.Update gets calls multiple time when game runs slow in fixed time step mode.
240- // In this case, we should ignore StartFrame call.
241- // To do this, we just keep tracking of number of StartFrame calls untile Draw gets called.
242- int updateCount;
243-
244-#endif
245- // TimerRulerの表示位置
246- Vector2 position;
247-
248- #endregion
249-
250- #region 初期化
251-
252- public TimeRuler(Game game)
253- : base(game)
254- {
255- // サービスとして登録する
256- // timeLine.BeginMarkを使っているラインはTRACE設定なしの場合でも残ってる
257- // 場合があるので、サービス登録は必要になる
258- Game.Services.AddService(typeof(TimeRuler), this);
259- }
260-
261- public override void Initialize()
262- {
263-#if TRACE
264- debugManager =
265- Game.Services.GetService(typeof(DebugManager)) as DebugManager;
266-
267- if (debugManager == null)
268- throw new InvalidOperationException("DebugManagerが登録されていません");
269-
270- // DebugCommandHostが登録されているのなら、コマンドを登録
271- IDebugCommandHost host =
272- Game.Services.GetService(typeof(IDebugCommandHost))
273- as IDebugCommandHost;
274-
275- if (host != null)
276- {
277- host.RegisterCommand("tr", "TimeRuler", this.CommandExecute);
278- this.Visible = false;
279- this.Enabled = false;
280- }
281-
282- // パラメーターの初期化
283- logs = new FrameLog[2];
284- for (int i = 0; i < logs.Length; ++i)
285- logs[i] = new FrameLog();
286-
287- sampleFrames = TargetSampleFrames = 1;
288-
289- // Time-Ruler's update method doesn't need to get called.
290- this.Enabled = false;
291-#endif
292- base.Initialize();
293- }
294-
295- protected override void LoadContent()
296- {
297- Width = (int)(GraphicsDevice.Viewport.Width * 0.8f);
298-
299- Layout layout = new Layout(GraphicsDevice.Viewport);
300- position = layout.Place(new Vector2(Width, BarHeight),
301- 0, 0.01f, Alignment.BottomCenter);
302-
303- base.LoadContent();
304- }
305-
306-#if TRACE
307- /// <summary>
308- /// TimeRulerコマンド処理
309- /// </summary>
310- void CommandExecute(IDebugCommandHost host, string command,
311- IList<string> arguments)
312- {
313- bool previousVisible = Visible;
314-
315- if (arguments.Count == 0)
316- Visible = !Visible;
317-
318- char[] subArgSeparator = new[] { ':' };
319- foreach (string orgArg in arguments)
320- {
321- string arg = orgArg.ToLower();
322- string[] subargs = arg.Split(subArgSeparator);
323- switch (subargs[0])
324- {
325- case "on":
326- Visible = true;
327- break;
328- case "off":
329- Visible = false;
330- break;
331- case "reset":
332- ResetLog();
333- break;
334- case "log":
335- if (subargs.Length > 1)
336- {
337- if (String.Compare(subargs[1], "on") == 0)
338- ShowLog = true;
339- if (String.Compare(subargs[1], "off") == 0)
340- ShowLog = false;
341- }
342- else
343- {
344- ShowLog = !ShowLog;
345- }
346- break;
347- case "frame":
348- int a = Int32.Parse(subargs[1]);
349- a = Math.Max(a, 1);
350- a = Math.Min(a, MaxSampleFrames);
351- TargetSampleFrames = a;
352- break;
353- case "/?":
354- case "--help":
355- host.Echo("tr [log|on|off|reset|frame]");
356- host.Echo("Options:");
357- host.Echo(" on Display TimeRuler.");
358- host.Echo(" off Hide TimeRuler.");
359- host.Echo(" log Show/Hide marker log.");
360- host.Echo(" reset Reset marker log.");
361- host.Echo(" frame:sampleFrames");
362- host.Echo(" Change target sample frame count");
363- break;
364- default:
365- break;
366- }
367- }
368-
369- // Reset update count when Visible state changed.
370- if (Visible != previousVisible)
371- {
372- Interlocked.Exchange(ref updateCount, 0);
373- }
374- }
375-#endif
376-
377- #endregion
378-
379- #region 測定用メソッド
380-
381- /// <summary>
382- /// 新しいフレームの開始
383- /// </summary>
384- [Conditional("TRACE")]
385- public void StartFrame()
386- {
387-#if TRACE
388- lock (this)
389- {
390- // Game.IsFixedTimeStepがtrueの場合、Game.Updateが複数回呼ばれることがある。
391- // http://blogs.msdn.com/b/ito/archive/2007/03/08/2-update.aspx
392- // このケースに対処する為に、タイムルーラーの描画が呼び出されずにStartFrameが複数回呼ばれた場合は
393- // フレームリセットするのではなく、測定を継続するようになっている。
394- int count = Interlocked.Increment(ref updateCount);
395- if (Visible && (1 < count && count < MaxSampleFrames))
396- return;
397-
398- // 現フレームログの更新
399- prevLog = logs[frameCount++ & 0x1];
400- curLog = logs[frameCount & 0x1];
401-
402- float endFrameTime = (float)stopwatch.Elapsed.TotalMilliseconds;
403-
404- // マーカーの更新とログ生成
405- for (int barIdx = 0; barIdx < prevLog.Bars.Length; ++barIdx)
406- {
407- MarkerCollection prevBar = prevLog.Bars[barIdx];
408- MarkerCollection nextBar = curLog.Bars[barIdx];
409-
410- // 前フレームでEndMarkを呼んでいないマーカーを閉じ、現フレームで
411- // 再度開く。
412- for (int nest = 0; nest < prevBar.NestCount; ++nest)
413- {
414- int markerIdx = prevBar.MarkerNests[nest];
415-
416- prevBar.Markers[markerIdx].EndTime = endFrameTime;
417-
418- nextBar.MarkerNests[nest] = nest;
419- nextBar.Markers[nest].MarkerId =
420- prevBar.Markers[markerIdx].MarkerId;
421- nextBar.Markers[nest].BeginTime = 0;
422- nextBar.Markers[nest].EndTime = -1;
423- nextBar.Markers[nest].Color = prevBar.Markers[markerIdx].Color;
424- }
425-
426- // マーカーログの更新
427- for (int markerIdx = 0; markerIdx < prevBar.MarkCount; ++markerIdx)
428- {
429- float duration = prevBar.Markers[markerIdx].EndTime -
430- prevBar.Markers[markerIdx].BeginTime;
431-
432- int markerId = prevBar.Markers[markerIdx].MarkerId;
433- MarkerInfo m = markers[markerId];
434-
435- m.Logs[barIdx].Color = prevBar.Markers[markerIdx].Color;
436-
437- if (!m.Logs[barIdx].Initialized)
438- {
439- // 最初のフレームの処理
440- m.Logs[barIdx].Min = duration;
441- m.Logs[barIdx].Max = duration;
442- m.Logs[barIdx].Avg = duration;
443-
444- m.Logs[barIdx].Initialized = true;
445- }
446- else
447- {
448- // 2フレーム目以降の処理
449- m.Logs[barIdx].Min = Math.Min(m.Logs[barIdx].Min, duration);
450- m.Logs[barIdx].Max = Math.Min(m.Logs[barIdx].Max, duration);
451- m.Logs[barIdx].Avg += duration;
452- m.Logs[barIdx].Avg *= 0.5f;
453-
454- if (m.Logs[barIdx].Samples++ >= LogSnapDuration)
455- {
456- m.Logs[barIdx].SnapMin = m.Logs[barIdx].Min;
457- m.Logs[barIdx].SnapMax = m.Logs[barIdx].Max;
458- m.Logs[barIdx].SnapAvg = m.Logs[barIdx].Avg;
459- m.Logs[barIdx].Samples = 0;
460- }
461- }
462- }
463-
464- nextBar.MarkCount = prevBar.NestCount;
465- nextBar.NestCount = prevBar.NestCount;
466- }
467-
468- // このフレームの測定開始
469- stopwatch.Reset();
470- stopwatch.Start();
471- }
472-#endif
473- }
474-
475- /// <summary>
476- /// マーカーの開始
477- /// </summary>
478- /// <param name="markerName">マーカー名</param>
479- /// <param name="color">カラー</param>
480- [Conditional("TRACE")]
481- public void BeginMark(string markerName, Color color)
482- {
483-#if TRACE
484- BeginMark(0, markerName, color);
485-#endif
486- }
487-
488- /// <summary>
489- /// マーカーの開始
490- /// </summary>
491- /// <param name="barIndex">バーのインデックス値</param>
492- /// <param name="markerName">マーカー名</param>
493- /// <param name="color">カラー</param>
494- [Conditional("TRACE")]
495- public void BeginMark(int barIndex, string markerName, Color color)
496- {
497-#if TRACE
498- lock (this)
499- {
500- if (barIndex < 0 || barIndex >= MaxBars)
501- throw new ArgumentOutOfRangeException("barIndex");
502-
503- MarkerCollection bar = curLog.Bars[barIndex];
504-
505- if (bar.MarkCount >= MaxSamples)
506- {
507- throw new OverflowException(
508- "サンプル数がMaxSampleを超えました。\n" +
509- "TimeRuler.MaxSmpaleの値を大きくするか、" +
510- "サンプル数を少なくしてください。");
511- }
512-
513- if (bar.NestCount >= MaxNestCall)
514- {
515- throw new OverflowException(
516- "ネスト数がMaxNestCallを超えました。\n" +
517- "TimeRuler.MaxNestCallの値を大きくするか、" +
518- "ネスト呼び出し数を減らしてください。");
519- }
520-
521- // 登録されているマーカーを取得
522- int markerId;
523- if (!markerNameToIdMap.TryGetValue(markerName, out markerId))
524- {
525- // 登録されていなければ新たに登録する
526- markerId = markers.Count;
527- markerNameToIdMap.Add(markerName, markerId);
528- markers.Add(new MarkerInfo(markerName));
529- }
530-
531- // 測定開始
532- bar.MarkerNests[bar.NestCount++] = bar.MarkCount;
533-
534- // マーカーのパラメーターを設定
535- bar.Markers[bar.MarkCount].MarkerId = markerId;
536- bar.Markers[bar.MarkCount].Color = color;
537- bar.Markers[bar.MarkCount].BeginTime =
538- (float)stopwatch.Elapsed.TotalMilliseconds;
539-
540- bar.Markers[bar.MarkCount].EndTime = -1;
541-
542- bar.MarkCount++;
543- }
544-#endif
545- }
546-
547- /// <summary>
548- /// マーカーの終了
549- /// </summary>
550- /// <param name="markerName">マーカー名</param>
551- [Conditional("TRACE")]
552- public void EndMark(string markerName)
553- {
554-#if TRACE
555- EndMark(0, markerName);
556-#endif
557- }
558-
559- /// <summary>
560- /// マーカーの終了
561- /// </summary>
562- /// <param name="barIndex">バーのインデックス値</param>
563- /// <param name="markerName">マーカー名</param>
564- [Conditional("TRACE")]
565- public void EndMark(int barIndex, string markerName)
566- {
567-#if TRACE
568- lock (this)
569- {
570- if (barIndex < 0 || barIndex >= MaxBars)
571- throw new ArgumentOutOfRangeException("barIndex");
572-
573- MarkerCollection bar = curLog.Bars[barIndex];
574-
575- if (bar.NestCount <= 0)
576- {
577- throw new InvalidOperationException(
578- "EndMarkを呼び出す前に、BeginMarkメソッドを呼んでください。");
579- }
580-
581- int markerId;
582- if (!markerNameToIdMap.TryGetValue(markerName, out markerId))
583- {
584- throw new InvalidOperationException(
585- String.Format("マーカー名「{0}」は登録されていません。" +
586- "BeginMarkで使った名前と同じ名前か確認してください。",
587- markerName));
588- }
589-
590- int markerIdx = bar.MarkerNests[--bar.NestCount];
591- if (bar.Markers[markerIdx].MarkerId != markerId)
592- {
593- throw new InvalidOperationException(
594- "BeginMark/EndMarkの呼び出し順序が不正です。" +
595- "BeginMark(A), BeginMark(B), EndMark(B), EndMark(A)の" +
596- "のようには呼べますが、" +
597- "BeginMark(A), BeginMark(B), EndMark(A), EndMark(B)のようには" +
598- "呼べません。");
599- }
600-
601- bar.Markers[markerIdx].EndTime =
602- (float)stopwatch.Elapsed.TotalMilliseconds;
603- }
604-#endif
605- }
606-
607- /// <summary>
608- /// 指定された測定バーインデックスとマーカー名の平均処理時間を返す。
609- /// </summary>
610- /// <param name="barIndex">測定バーのインデックス</param>
611- /// <param name="markerName">マーカー名</param>
612- /// <returns>平均処理時間(ミリ秒)</returns>
613- public float GetAverageTime(int barIndex, string markerName)
614- {
615-#if TRACE
616- if (barIndex < 0 || barIndex >= MaxBars)
617- throw new ArgumentOutOfRangeException("barIndex");
618-
619- float result = 0;
620- int markerId;
621- if (markerNameToIdMap.TryGetValue(markerName, out markerId))
622- result = markers[markerId].Logs[barIndex].Avg;
623-
624- return result;
625-#endif
626- }
627-
628- /// <summary>
629- /// マーカーログのリセット
630- /// </summary>
631- [Conditional("TRACE")]
632- public void ResetLog()
633- {
634-#if TRACE
635- lock (this)
636- {
637- foreach (MarkerInfo markerInfo in markers)
638- {
639- for (int i = 0; i < markerInfo.Logs.Length; ++i)
640- {
641- markerInfo.Logs[i].Initialized = false;
642- markerInfo.Logs[i].SnapMin = 0;
643- markerInfo.Logs[i].SnapMax = 0;
644- markerInfo.Logs[i].SnapAvg = 0;
645-
646- markerInfo.Logs[i].Min = 0;
647- markerInfo.Logs[i].Max = 0;
648- markerInfo.Logs[i].Avg = 0;
649-
650- markerInfo.Logs[i].Samples = 0;
651- }
652- }
653- }
654-#endif
655- }
656-
657- #endregion
658-
659- #region 描画
660-
661- public override void Draw(GameTime gameTime)
662- {
663- Draw(position, Width);
664- base.Draw(gameTime);
665- }
666-
667- [Conditional("TRACE")]
668- public void Draw(Vector2 position, int width)
669- {
670-#if TRACE
671- // 更新カウントをリセットする。
672- Interlocked.Exchange(ref updateCount, 0);
673-
674- // SpriteBatch, SpriteFont, WhiteTextureをDebugManagerから取得する。
675- SpriteBatch spriteBatch = debugManager.SpriteBatch;
676- SpriteFont font = debugManager.DebugFont;
677- Texture2D texture = debugManager.WhiteTexture;
678-
679- // 表示するべきバーの数によって表示サイズと位置を変更する
680- int height = 0;
681- float maxTime = 0;
682- foreach (MarkerCollection bar in prevLog.Bars)
683- {
684- if (bar.MarkCount > 0)
685- {
686- height += BarHeight + BarPadding * 2;
687- maxTime = Math.Max(maxTime,
688- bar.Markers[bar.MarkCount - 1].EndTime);
689- }
690- }
691-
692- // 表示フレーム数の自動調整
693- // 例えば16.6msで処理が間に合わなかった状態が一定時間以上続くと
694- // 自動的に表示する時間間隔を33.3msに調整する
695- const float frameSpan = 1.0f / 60.0f * 1000f;
696- float sampleSpan = (float)sampleFrames * frameSpan;
697-
698- if (maxTime > sampleSpan)
699- frameAdjust = Math.Max(0, frameAdjust) + 1;
700- else
701- frameAdjust = Math.Min(0, frameAdjust) - 1;
702-
703- if (Math.Abs(frameAdjust) > AutoAdjustDelay)
704- {
705- sampleFrames = Math.Min(MaxSampleFrames, sampleFrames);
706- sampleFrames =
707- Math.Max(TargetSampleFrames, (int)(maxTime / frameSpan) + 1);
708-
709- frameAdjust = 0;
710- }
711-
712- // ミリ秒からピクセルに変換する係数を計算
713- float msToPs = (float)width / sampleSpan;
714-
715- // 描画開始位置
716- int startY = (int)position.Y - (height - BarHeight);
717-
718- // 現在のy座標
719- int y = startY;
720-
721- spriteBatch.Begin();
722-
723- // 背景の半透明の矩形を描画
724- Rectangle rc = new Rectangle((int)position.X, y, width, height);
725- spriteBatch.Draw(texture, rc, new Color(0, 0, 0, 128));
726-
727- // 各バーのマーカーを描画
728- rc.Height = BarHeight;
729- foreach (MarkerCollection bar in prevLog.Bars)
730- {
731- rc.Y = y + BarPadding;
732- if (bar.MarkCount > 0)
733- {
734- for (int j = 0; j < bar.MarkCount; ++j)
735- {
736- float bt = bar.Markers[j].BeginTime;
737- float et = bar.Markers[j].EndTime;
738- int sx = (int)(position.X + bt * msToPs);
739- int ex = (int)(position.X + et * msToPs);
740- rc.X = sx;
741- rc.Width = Math.Max(ex - sx, 1);
742-
743- spriteBatch.Draw(texture, rc, bar.Markers[j].Color);
744- }
745- }
746-
747- y += BarHeight + BarPadding;
748- }
749-
750- // グリッドを描画する
751- // ミリ秒単位のグリッド描画
752- rc = new Rectangle((int)position.X, (int)startY, 1, height);
753- for (float t = 1.0f; t < sampleSpan; t += 1.0f)
754- {
755- rc.X = (int)(position.X + t * msToPs);
756- spriteBatch.Draw(texture, rc, Color.Gray);
757- }
758-
759- // フレーム単位のグリッド描画
760- for (int i = 0; i <= sampleFrames; ++i)
761- {
762- rc.X = (int)(position.X + frameSpan * (float)i * msToPs);
763- spriteBatch.Draw(texture, rc, Color.White);
764- }
765-
766- // ログの表示
767- if (ShowLog)
768- {
769- // 表示する文字列をStringBuilderで生成する
770- y = startY - font.LineSpacing;
771- logString.Length = 0;
772- foreach (MarkerInfo markerInfo in markers)
773- {
774- for (int i = 0; i < MaxBars; ++i)
775- {
776- if (markerInfo.Logs[i].Initialized)
777- {
778- if (logString.Length > 0)
779- logString.Append("\n");
780-
781- logString.Append(" Bar ");
782- logString.AppendNumber(i);
783- logString.Append(" ");
784- logString.Append(markerInfo.Name);
785-
786- logString.Append(" Avg.:");
787- logString.AppendNumber(markerInfo.Logs[i].SnapAvg);
788- logString.Append("ms ");
789-
790- y -= font.LineSpacing;
791- }
792- }
793- }
794-
795- // 表示する文字列の背景の矩形サイズの計算と描画
796- Vector2 size = font.MeasureString(logString);
797- rc = new Rectangle((int)position.X, (int)y, (int)size.X + 12, (int)size.Y);
798- spriteBatch.Draw(texture, rc, new Color(0, 0, 0, 128));
799-
800- // ログ文字列の描画
801- spriteBatch.DrawString(font, logString,
802- new Vector2(position.X + 12, y), Color.White);
803-
804- // ログカラーボックスの描画
805- y += (int)((float)font.LineSpacing * 0.3f);
806- rc = new Rectangle((int)position.X + 4, y, 10, 10);
807- Rectangle rc2 = new Rectangle((int)position.X + 5, y + 1, 8, 8);
808- foreach (MarkerInfo markerInfo in markers)
809- {
810- for (int i = 0; i < MaxBars; ++i)
811- {
812- if (markerInfo.Logs[i].Initialized)
813- {
814- rc.Y = y;
815- rc2.Y = y + 1;
816- spriteBatch.Draw(texture, rc, Color.White);
817- spriteBatch.Draw(texture, rc2, markerInfo.Logs[i].Color);
818-
819- y += font.LineSpacing;
820- }
821- }
822- }
823-
824-
825- }
826-
827- spriteBatch.End();
828-#endif
829- }
830-
831- #endregion
832-
833- }
834-}
--- branches/XNA4/MikuMikuDanceXNADemo1/MikuMikuDanceXNADemo1/GameDebug/IDebugCommandHost.cs (revision 800)
+++ branches/XNA4/MikuMikuDanceXNADemo1/MikuMikuDanceXNADemo1/GameDebug/IDebugCommandHost.cs (nonexistent)
@@ -1,120 +0,0 @@
1-#region Using ステートメント
2-
3-using System.Collections.Generic;
4-
5-#endregion
6-
7-namespace DebugSample
8-{
9- /// <summary>
10- /// デバッグコマンドのメッセージタイプ
11- /// </summary>
12- public enum DebugCommandMessage
13- {
14- // 標準出力
15- Standard = 1,
16-
17- // エラー出力
18- Error = 2,
19-
20- // 警告出力
21- Warning = 3
22- }
23-
24- /// <summary>
25- /// デバッグコマンド実行用のデリゲーション
26- /// </summary>
27- /// <param name="host">実行を発行したホスト</param>
28- /// <param name="command">コマンド</param>
29- /// <param name="arguments">コマンドの引数</param>
30- public delegate void DebugCommandExecute(IDebugCommandHost host, string command,
31- IList<string> arguments);
32-
33- /// <summary>
34- /// デバッグコマンド実行者インターフェース
35- /// </summary>
36- public interface IDebugCommandExecutioner
37- {
38- /// <summary>
39- /// コマンドの実行
40- /// </summary>
41- /// <param name="command">実行コマンド</param>
42- void ExecuteCommand(string command);
43- }
44-
45- /// <summary>
46- /// デバッグコマンドメッセージのリスナー用インターフェース
47- /// </summary>
48- public interface IDebugEchoListner
49- {
50- /// <summary>
51- /// メッセージの出力
52- /// </summary>
53- /// <param name="messageType">メッセージの種類</param>
54- /// <param name="text">メッセージ</param>
55- void Echo(DebugCommandMessage messageType, string text);
56- }
57-
58- /// <summary>
59- /// デバッグコマンドホスト用のインターフェース
60- /// </summary>
61- public interface IDebugCommandHost : IDebugEchoListner, IDebugCommandExecutioner
62- {
63- /// <summary>
64- /// コマンドの登録
65- /// </summary>
66- /// <param name="command">コマンド</param>
67- /// <param name="description">コマンドの説明</param>
68- /// <param name="callback">実行時のデリゲーション</param>
69- void RegisterCommand(string command, string description,
70- DebugCommandExecute callback);
71-
72- /// <summary>
73- /// コマンドの登録解除
74- /// </summary>
75- /// <param name="command">コマンド</param>
76- void UnregisterCommand(string command);
77-
78-
79- /// <summary>
80- /// 標準メッセージ出力
81- /// </summary>
82- /// <param name="text"></param>
83- void Echo(string text);
84-
85- /// <summary>
86- /// 警告メッセージ出力
87- /// </summary>
88- /// <param name="text"></param>
89- void EchoWarning(string text);
90-
91- /// <summary>
92- /// エラーメッセージ出力
93- /// </summary>
94- /// <param name="text"></param>
95- void EchoError(string text);
96-
97- /// <summary>
98- /// メッセージ出力リスナーの登録
99- /// </summary>
100- /// <param name="listner"></param>
101- void RegisterEchoListner(IDebugEchoListner listner);
102-
103- /// <summary>
104- /// メッセージ出力リスナーの登録解除
105- /// </summary>
106- /// <param name="listner"></param>
107- void UnregisterEchoListner(IDebugEchoListner listner);
108-
109- /// <summary>
110- /// コマンド実行者の追加
111- /// </summary>
112- void PushExecutioner(IDebugCommandExecutioner executioner);
113-
114- /// <summary>
115- /// コマンド実行者の削除
116- /// </summary>
117- void PopExecutioner();
118- }
119-
120-}
--- branches/XNA4/MikuMikuDanceXNADemo1/MikuMikuDanceXNADemo1/GameDebug/RemoteDebugCommand.cs (revision 800)
+++ branches/XNA4/MikuMikuDanceXNADemo1/MikuMikuDanceXNADemo1/GameDebug/RemoteDebugCommand.cs (nonexistent)
@@ -1,403 +0,0 @@
1-#if XBOX360 || WINDOWS
2-
3-#region Using ステートメント
4-
5-using System;
6-using System.Collections.Generic;
7-using System.Text.RegularExpressions;
8-using Microsoft.Xna.Framework;
9-using Microsoft.Xna.Framework.GamerServices;
10-using Microsoft.Xna.Framework.Net;
11-
12-#endregion
13-
14-namespace DebugSample
15-{
16- /// <summary>
17- /// リモートデバッグコマンドコンポーネント
18- /// </summary>
19- /// <remarks>
20- /// オリジナルのデバッグコマンドはXbox 360にキーボードを接続することで使えたが、
21- /// キーボードが二つない場合や、Xbox 360本体が開発しているPCよりも遠くにある場合に
22- /// 不便なので、NetworkSessionを使ってPCサイドからリモート接続するのが、
23- /// このコンポーネントである。
24- ///
25- /// Xbox 360、Windowsで同じゲームを走らせておいた状態で、"remote"コマンドを
26- /// 使うと、WindowsからXbox 360へと接続する
27- ///
28- /// 接続が完了するとWindows側でタイプされたコマンドはXbox 360側に送られ実行される
29- /// 実行結果はXbox 360、Windowsの両方で表示される
30- ///
31- /// "quit"コマンドでリモート接続を終了する
32- /// </remarks>
33- public class RemoteDebugCommand : GameComponent,
34- IDebugCommandExecutioner, IDebugEchoListner
35- {
36- #region プロパティ
37-
38- /// <summary>
39- /// 接続に使うNetworkSessionの取得と設定
40- /// </summary>
41- public NetworkSession NetworkSession { get; set; }
42-
43- /// <summary>
44- /// このコンポーネントがNetworkSessionのオーナーか?
45- /// </summary>
46- public bool OwnsNetworkSession { get; private set; }
47-
48- #endregion
49-
50- #region 定数宣言
51-
52- const string StartPacketHeader = "RmtStart";
53- const string ExecutePacketHeader = "RmtCmd";
54- const string EchoPacketHeader = "RmtEcho";
55- const string ErrorPacketHeader = "RmtErr";
56- const string WarningPacketHeader = "RmtWrn";
57- const string QuitPacketHeader = "RmtQuit";
58-
59- #endregion
60-
61- #region フィールド
62-
63- IDebugCommandHost commandHost;
64-
65-#if WINDOWS
66- bool IsHost = false;
67-#else
68- bool IsHost = true;
69-#endif
70-
71- Regex packetRe = new Regex(@"\$(?<header>[^$]+)\$:(?<text>.+)");
72-
73- PacketReader packetReader = new PacketReader();
74- PacketWriter packetWriter = new PacketWriter();
75-
76- IAsyncResult asyncResult;
77-
78- enum ConnectionPahse
79- {
80- None,
81- EnsureSignedIn,
82- FindSessions,
83- Joining,
84- }
85-
86- ConnectionPahse phase = ConnectionPahse.None;
87-
88- #endregion
89-
90- #region 初期化
91-
92- public RemoteDebugCommand(Game game)
93- : base(game)
94- {
95- commandHost =
96- game.Services.GetService(typeof(IDebugCommandHost)) as IDebugCommandHost;
97-
98- if (!IsHost)
99- {
100- commandHost.RegisterCommand("remote", "Start remote command",
101- ExecuteRemoteCommand);
102- }
103- }
104-
105- public override void Initialize()
106- {
107- if (IsHost)
108- {
109- commandHost.RegisterEchoListner(this);
110-
111- // Create network session if NetworkSession is not setted.
112- if (NetworkSession == null)
113- {
114- GamerServicesDispatcher.WindowHandle = Game.Window.Handle;
115- GamerServicesDispatcher.Initialize(Game.Services);
116- NetworkSession =
117- NetworkSession.Create(NetworkSessionType.SystemLink, 1, 2);
118-
119- OwnsNetworkSession = true;
120- }
121- }
122-
123- base.Initialize();
124- }
125-
126- #endregion
127-
128- /// <summary>
129- /// パケット文字の処理
130- /// </summary>
131- /// <remarks>ゲーム側でNetworkSessionを保持している場合に受け取ったリモート
132- /// デバッグコマンド用のパケットはこのメソッドで処理する
133- /// </remarks>
134- /// <param name="packetString"></param>
135- /// <returns>指定されたパケット文字が処理されたか?</returns>
136- public bool ProcessRecievedPacket(string packetString)
137- {
138- bool processed = false;
139-
140- Match mc = packetRe.Match(packetString);
141- if (mc.Success)
142- {
143- string packetHeader = mc.Groups["header"].Value;
144- string text = mc.Groups["text"].Value;
145- switch (packetHeader)
146- {
147- case ExecutePacketHeader:
148- commandHost.ExecuteCommand(text);
149- processed = true;
150- break;
151- case EchoPacketHeader:
152- commandHost.Echo(text);
153- processed = true;
154- break;
155- case ErrorPacketHeader:
156- commandHost.EchoError(text);
157- processed = true;
158- break;
159- case WarningPacketHeader:
160- commandHost.EchoWarning(text);
161- processed = true;
162- break;
163- case StartPacketHeader:
164- ConnectedToRemote();
165- commandHost.Echo(text);
166- processed = true;
167- break;
168- case QuitPacketHeader:
169- commandHost.Echo(text);
170- DisconnectedFromRemote();
171- processed = true;
172- break;
173- }
174- }
175-
176- return processed;
177- }
178-
179- #region 実装
180-
181- /// <summary>
182- /// 更新
183- /// </summary>
184- public override void Update(GameTime gameTime)
185- {
186- // 複数のフェーズ処理
187- switch (phase)
188- {
189- case ConnectionPahse.EnsureSignedIn:
190- GamerServicesDispatcher.Update();
191- break;
192-
193- case ConnectionPahse.FindSessions:
194- GamerServicesDispatcher.Update();
195- if (asyncResult.IsCompleted)
196- {
197- AvailableNetworkSessionCollection sessions =
198- NetworkSession.EndFind(asyncResult);
199-
200- if (sessions.Count > 0)
201- {
202- asyncResult = NetworkSession.BeginJoin(sessions[0],
203- null, null);
204- commandHost.EchoError("Connecting to the host...");
205- phase = ConnectionPahse.Joining;
206- }
207- else
208- {
209- commandHost.EchoError("Couldn't find a session.");
210- phase = ConnectionPahse.None;
211- }
212- }
213- break;
214- case ConnectionPahse.Joining:
215- GamerServicesDispatcher.Update();
216- if (asyncResult.IsCompleted)
217- {
218- NetworkSession = NetworkSession.EndJoin(asyncResult);
219- NetworkSession.SessionEnded +=
220- new EventHandler<NetworkSessionEndedEventArgs>(
221- NetworkSession_SessionEnded);
222-
223- OwnsNetworkSession = true;
224- commandHost.EchoError("Connected to the host.");
225- phase = ConnectionPahse.None;
226- asyncResult = null;
227-
228- ConnectedToRemote();
229- }
230- break;
231- }
232-
233- // NetworkSessionの更新
234- if (OwnsNetworkSession)
235- {
236- GamerServicesDispatcher.Update();
237- NetworkSession.Update();
238-
239- if (NetworkSession != null)
240- {
241- // 受け取ったパケットの処理
242- foreach (LocalNetworkGamer gamer in NetworkSession.LocalGamers)
243- {
244- while (gamer.IsDataAvailable)
245- {
246- NetworkGamer sender;
247- gamer.ReceiveData(packetReader, out sender);
248- if (!sender.IsLocal)
249- ProcessRecievedPacket(packetReader.ReadString());
250- }
251- }
252- }
253- }
254-
255- base.Update(gameTime);
256- }
257-
258- /// <summary>
259- /// デバッグコマンドパケットを送信する
260- /// </summary>
261- void SendPacket(string header, string text)
262- {
263- if (NetworkSession != null)
264- {
265- packetWriter.Write("$" + header + "$:" + text);
266- NetworkSession.LocalGamers[0].SendData(packetWriter,
267- SendDataOptions.ReliableInOrder);
268- }
269- }
270-
271- /// <summary>
272- /// リモートデバッグコマンドの開始
273- /// </summary>
274- void ConnectedToRemote()
275- {
276- DebugCommandUI commandUI = commandHost as DebugCommandUI;
277-
278- if (IsHost)
279- {
280- if (commandUI != null)
281- commandUI.Prompt = "[Host]>";
282- }
283- else
284- {
285- if (commandUI != null)
286- commandUI.Prompt = "[Client]>";
287-
288- commandHost.PushExecutioner(this);
289-
290- SendPacket(StartPacketHeader, "Remote Debug Command Started!!");
291- }
292-
293- commandHost.RegisterCommand("quit", "Quit from remote command",
294- ExecuteQuitCommand);
295- }
296-
297- /// <summary>
298- /// リモートデバッグコマンドの終了
299- /// </summary>
300- void DisconnectedFromRemote()
301- {
302- DebugCommandUI commandUI = commandHost as DebugCommandUI;
303- if (commandUI != null)
304- commandUI.Prompt = DebugCommandUI.DefaultPrompt;
305-
306- commandHost.UnregisterCommand("quit");
307-
308- if (!IsHost)
309- {
310- commandHost.PopExecutioner();
311-
312- if (OwnsNetworkSession)
313- {
314- NetworkSession.Dispose();
315- NetworkSession = null;
316- OwnsNetworkSession = false;
317- }
318- }
319- }
320-
321- #region デバッグコマンドの実装
322-
323- private void ExecuteRemoteCommand(IDebugCommandHost host, string command,
324- IList<string> arguments)
325- {
326- if (NetworkSession == null)
327- {
328- try
329- {
330- GamerServicesDispatcher.WindowHandle = Game.Window.Handle;
331- GamerServicesDispatcher.Initialize(Game.Services);
332- }
333- catch { }
334-
335- if (SignedInGamer.SignedInGamers.Count > 0)
336- {
337- commandHost.Echo("Finding available sessions...");
338-
339- asyncResult = NetworkSession.BeginFind(
340- NetworkSessionType.SystemLink, 1, null, null, null);
341-
342- phase = ConnectionPahse.FindSessions;
343- }
344- else
345- {
346- host.Echo("Please signed in.");
347- phase = ConnectionPahse.EnsureSignedIn;
348- }
349- }
350- else
351- {
352- ConnectedToRemote();
353- }
354- }
355-
356- private void ExecuteQuitCommand(IDebugCommandHost host, string command,
357- IList<string> arguments)
358- {
359- SendPacket(QuitPacketHeader, "End Remote Debug Command.");
360- DisconnectedFromRemote();
361- }
362-
363- #endregion
364-
365- #region IDebugCommandExecutionerとIDebugEchoListnerの実装
366-
367- public void ExecuteCommand(string command)
368- {
369- SendPacket(ExecutePacketHeader, command);
370- }
371-
372- public void Echo(DebugCommandMessage messageType, string text)
373- {
374- switch (messageType)
375- {
376- case DebugCommandMessage.Standard:
377- SendPacket(EchoPacketHeader, text);
378- break;
379- case DebugCommandMessage.Warning:
380- SendPacket(WarningPacketHeader, text);
381- break;
382- case DebugCommandMessage.Error:
383- SendPacket(ErrorPacketHeader, text);
384- break;
385- }
386- }
387-
388- #endregion
389-
390- /// <summary>
391- /// ホストが消失したときの処理
392- /// </summary>
393- void NetworkSession_SessionEnded(object sender, NetworkSessionEndedEventArgs e)
394- {
395- DisconnectedFromRemote();
396- commandHost.EchoWarning("Disconnected from the Host.");
397- }
398-
399- #endregion
400- }
401-}
402-
403-#endif
\ No newline at end of file
--- branches/XNA4/MikuMikuDanceXNADemo1/MikuMikuDanceXNADemo1/GameDebug/DebugManager.cs (revision 800)
+++ branches/XNA4/MikuMikuDanceXNADemo1/MikuMikuDanceXNADemo1/GameDebug/DebugManager.cs (nonexistent)
@@ -1,73 +0,0 @@
1-#region Using ステートメント
2-
3-using Microsoft.Xna.Framework;
4-using Microsoft.Xna.Framework.Content;
5-using Microsoft.Xna.Framework.Graphics;
6-
7-#endregion
8-
9-namespace DebugSample
10-{
11- /// <summary>
12- /// デバッグ用のグラフィクスコンテントを格納する為のデバッグ用マネージャー
13- /// </summary>
14- public class DebugManager : DrawableGameComponent
15- {
16- #region プロパティ
17-
18- /// <summary>
19- /// デバッグ用コンテントマネージャーの取得
20- /// </summary>
21- public ContentManager Content { get; private set; }
22-
23- /// <summary>
24- /// デバッグ用SpriteBatchの取得
25- /// </summary>
26- public SpriteBatch SpriteBatch { get; private set; }
27-
28- /// <summary>
29- /// 白テクスチャの取得
30- /// </summary>
31- public Texture2D WhiteTexture { get; private set; }
32-
33- /// <summary>
34- /// デバッグ用フォント
35- /// </summary>
36- public SpriteFont DebugFont { get; private set; }
37-
38- #endregion
39-
40- #region 初期化
41-
42- public DebugManager(Game game)
43- : base(game)
44- {
45- // サービスとして登録する
46- Game.Services.AddService(typeof(DebugManager), this);
47-
48- Content = new ContentManager(game.Services);
49- Content.RootDirectory = "Content/Debug";
50-
51- // このコンポーネント自体はUpdate、Drawが呼ばれる必要はない
52- this.Enabled = false;
53- this.Visible = false;
54- }
55-
56- protected override void LoadContent()
57- {
58- // デバッグ用コンテントの読み込み
59- SpriteBatch = new SpriteBatch(GraphicsDevice);
60-
61- DebugFont = Content.Load<SpriteFont>("DebugFont");
62-
63- // 白テクスチャの生成
64- WhiteTexture = new Texture2D(GraphicsDevice, 1, 1);
65- Color[] whitePixels = new Color[] { Color.White };
66- WhiteTexture.SetData<Color>(whitePixels);
67-
68- base.LoadContent();
69- }
70-
71- #endregion
72- }
73-}
\ No newline at end of file
--- branches/XNA4/MikuMikuDanceXNADemo1/MikuMikuDanceXNADemo1/GameDebug/KeyboardUtils.cs (revision 800)
+++ branches/XNA4/MikuMikuDanceXNADemo1/MikuMikuDanceXNADemo1/GameDebug/KeyboardUtils.cs (nonexistent)
@@ -1,156 +0,0 @@
1-#region Using ステートメント
2-
3-using System;
4-using System.Collections.Generic;
5-using Microsoft.Xna.Framework.Input;
6-
7-#endregion
8-
9-namespace DebugSample
10-{
11- /// <summary>
12- /// キーボード入力関連のユーティリティクラス
13- /// </summary>
14- public static class KeyboardUtils
15- {
16- #region フィールド
17-
18- /// <summary>
19- /// 通常の文字とシフトキーが押下された時の文字を保持する文字ペアクラス
20- /// </summary>
21- class CharPair
22- {
23- public CharPair(char normalChar, Nullable<char> shiftChar)
24- {
25- this.NormalChar = normalChar;
26- this.ShiftChar = shiftChar;
27- }
28-
29- public char NormalChar;
30- public Nullable<char> ShiftChar;
31- }
32-
33- // キー:Keys, 値:CharPair
34- static private Dictionary<Keys, CharPair> keyMap =
35- new Dictionary<Keys, CharPair>();
36-
37- #endregion
38-
39- /// <summary>
40- /// キー情報から文字を取得する
41- /// </summary>
42- /// <param name="key">押下されたキー</param>
43- /// <param name="shitKeyPressed">シフトキーが押されていたか?</param>
44- /// <param name="character">キー入力から変換された文字</param>
45- /// <returns>文字取得が成功した場合trueを返す</returns>
46- public static bool KeyToString(Keys key, bool shitKeyPressed,
47- out char character)
48- {
49- bool result = false;
50- character = ' ';
51- CharPair charPair;
52-
53- if ((Keys.A <= key && key <= Keys.Z) || key == Keys.Space)
54- {
55- // A~Z、スペースキーはそのまま文字コードとして使用する
56- character = (shitKeyPressed) ? (char)key : Char.ToLower((char)key);
57- result = true;
58- }
59- else if (keyMap.TryGetValue(key, out charPair))
60- {
61- // それ以外の場合はKeyMapの情報を元に変換する
62- if (!shitKeyPressed)
63- {
64- character = charPair.NormalChar;
65- result = true;
66- }
67- else if (charPair.ShiftChar.HasValue)
68- {
69- character = charPair.ShiftChar.Value;
70- result = true;
71- }
72- }
73-
74- return result;
75- }
76-
77- #region 初期化
78-
79- static KeyboardUtils()
80- {
81- InitializeKeyMap();
82- }
83-
84- /// <summary>
85- /// 英字以外のキーの文字マップの初期化
86- /// </summary>
87- /// <remarks>ここではUSキーボード用のものを宣言しているので、
88- /// 日本語キーボードでは変更する必要があるかも</remarks>
89- static void InitializeKeyMap()
90- {
91- // 英語キーボードの上から1列目
92- AddKeyMap(Keys.OemTilde, "`~");
93- AddKeyMap(Keys.D1, "1!");
94- AddKeyMap(Keys.D2, "2@");
95- AddKeyMap(Keys.D3, "3#");
96- AddKeyMap(Keys.D4, "4$");
97- AddKeyMap(Keys.D5, "5%");
98- AddKeyMap(Keys.D6, "6^");
99- AddKeyMap(Keys.D7, "7&");
100- AddKeyMap(Keys.D8, "8*");
101- AddKeyMap(Keys.D9, "9(");
102- AddKeyMap(Keys.D0, "0)");
103- AddKeyMap(Keys.OemMinus, "-_");
104- AddKeyMap(Keys.OemPlus, "=+");
105-
106- // 英語キーボードの上から2列目
107- AddKeyMap(Keys.OemOpenBrackets, "[{");
108- AddKeyMap(Keys.OemCloseBrackets, "]}");
109- AddKeyMap(Keys.OemPipe, "\\|");
110-
111- // 英語キーボードの上から3列目
112- AddKeyMap(Keys.OemSemicolon, ";:");
113- AddKeyMap(Keys.OemQuotes, "'\"");
114- AddKeyMap(Keys.OemComma, ",<");
115- AddKeyMap(Keys.OemPeriod, ".>");
116- AddKeyMap(Keys.OemQuestion, "/?");
117-
118- // 英語キーボードのキーパッドのキー
119- AddKeyMap(Keys.NumPad1, "1");
120- AddKeyMap(Keys.NumPad2, "2");
121- AddKeyMap(Keys.NumPad3, "3");
122- AddKeyMap(Keys.NumPad4, "4");
123- AddKeyMap(Keys.NumPad5, "5");
124- AddKeyMap(Keys.NumPad6, "6");
125- AddKeyMap(Keys.NumPad7, "7");
126- AddKeyMap(Keys.NumPad8, "8");
127- AddKeyMap(Keys.NumPad9, "9");
128- AddKeyMap(Keys.NumPad0, "0");
129- AddKeyMap(Keys.Add, "+");
130- AddKeyMap(Keys.Divide, "/");
131- AddKeyMap(Keys.Multiply, "*");
132- AddKeyMap(Keys.Subtract, "-");
133- AddKeyMap(Keys.Decimal, ".");
134- }
135-
136- /// <summary>
137- /// キーボードのキーと文字マップの追加
138- /// </summary>
139- /// <param name="key">キーボードのキー</param>
140- /// <param name="charPair">
141- /// 文字、2文字の場合はシフトキー無し、有り順番に記述する</param>
142- static void AddKeyMap(Keys key, string charPair)
143- {
144- char char1 = charPair[0];
145- Nullable<char> char2 = null;
146- if (charPair.Length > 1)
147- char2 = charPair[1];
148-
149- keyMap.Add(key, new CharPair(char1, char2));
150- }
151-
152- #endregion
153-
154- }
155-
156-}
--- branches/XNA4/MikuMikuDanceXNADemo1/MikuMikuDanceXNADemo1/GameDebug/DebugCommandUI.cs (revision 800)
+++ branches/XNA4/MikuMikuDanceXNADemo1/MikuMikuDanceXNADemo1/GameDebug/DebugCommandUI.cs (nonexistent)
@@ -1,572 +0,0 @@
1-#region Using ステートメント
2-
3-using System;
4-using System.Collections.Generic;
5-using Microsoft.Xna.Framework;
6-using Microsoft.Xna.Framework.Graphics;
7-using Microsoft.Xna.Framework.Input;
8-
9-#endregion
10-
11-namespace DebugSample
12-{
13- /// <summary>
14- /// デバッグ用コマンドウィンドウクラス
15- /// </summary>
16- /// <remarks>
17- /// ゲーム内で動作するデバックコマンドウィンドウUI部分
18- /// キーボード入力によってコマンドを入力、実行することができる。
19- /// Xbox 360でもUSBキーボードを接続することで動作可能。
20- ///
21- /// 使用方法:
22- /// 1)このコンポーネントをゲームに追加。
23- /// 2)RegisterCommandメソッドを使ってコマンドを登録する
24- /// 3)Tabキーでデバッグウィンドウの開閉しコマンド入力
25- /// </remarks>
26- public class DebugCommandUI : DrawableGameComponent, IDebugCommandHost
27- {
28- #region 定数宣言
29-
30- /// <summary>
31- /// 最大行数
32- /// </summary>
33- const int MaxLineCount = 20;
34-
35- /// <summary>
36- /// コマンドヒストリ数
37- /// </summary>
38- const int MaxCommandHistory = 32;
39-
40- /// <summary>
41- /// カーソル文字。ここではUnicodeのBlock Eleemntsからカーソルっぽいものを使用
42- /// http://www.unicode.org/charts/PDF/U2580.pdf
43- /// </summary>
44- const string Cursor = "\u2582";
45-
46- /// <summary>
47- /// デフォルトのコマンドプロンプト文字列
48- /// </summary>
49- public const string DefaultPrompt = "CMD>";
50-
51- #endregion
52-
53- #region プロパティ
54-
55- /// <summary>
56- /// コマンドプロンプト文字列
57- /// </summary>
58- public string Prompt { get; set; }
59-
60- /// <summary>
61- /// キー入力待機状態か
62- /// </summary>
63- public bool Focused { get { return state != State.Closed; } }
64-
65- #endregion
66-
67- #region フィールド
68-
69- // コマンドウィンドウのステート
70- enum State
71- {
72- Closed, // 閉じている
73- Opening, // 開いている途中
74- Opened, // 開いている(コマンド入力待機中)
75- Closing // 閉じている途中
76- }
77-
78- /// <summary>
79- /// コマンド実行用情報格納用のクラス
80- /// </summary>
81- class CommandInfo
82- {
83- public CommandInfo(
84- string command, string description, DebugCommandExecute callback)
85- {
86- this.command = command;
87- this.description = description;
88- this.callback = callback;
89- }
90-
91- // コマンド名
92- public string command;
93-
94- // コマンド詳細
95- public string description;
96-
97- // コマンド実行用のデリゲート
98- public DebugCommandExecute callback;
99- }
100-
101- // デバッグマネージャーへの参照
102- private DebugManager debugManager;
103-
104- // 現在のステート
105- private State state = State.Closed;
106-
107- // ステート移行用のタイマー
108- private float stateTransition;
109-
110- // 登録されているEchoリスナー
111- List<IDebugEchoListner> listenrs = new List<IDebugEchoListner>();
112-
113- // 登録されているコマンド実行者
114- Stack<IDebugCommandExecutioner> executioners = new Stack<IDebugCommandExecutioner>();
115-
116- // 登録されているコマンド
117- private Dictionary<string, CommandInfo> commandTable =
118- new Dictionary<string, CommandInfo>();
119-
120- // 現在入力中のコマンドライン文字列と、カーソル位置
121- private string commandLine = String.Empty;
122- private int cursorIndex = 0;
123-
124- // コマンドライン表示文字列
125- private Queue<string> lines = new Queue<string>();
126-
127- // コマンド履歴用バッファ
128- private List<string> commandHistory = new List<string>();
129-
130- // 現在選択されている履歴インデックス
131- private int commandHistoryIndex;
132-
133- #region キーボード入力処理用の変数群
134-
135- // 前フレームのキーボードステート
136- private KeyboardState prevKeyState;
137-
138- // 最後に押されたキー
139- private Keys pressedKey;
140-
141- // キーリピートタイマー
142- private float keyRepeatTimer;
143-
144- // 最初のキー押下時のリピート時間(秒)
145- private float keyRepeatStartDuration = 0.3f;
146-
147- // 2回目以降のキーリピート時間(秒)
148- private float keyRepeatDuration = 0.03f;
149-
150- #endregion
151-
152- #endregion
153-
154- #region 初期化
155-
156- /// <summary>
157- /// コンストラクタ
158- /// </summary>
159- public DebugCommandUI(Game game)
160- : base(game)
161- {
162- Prompt = DefaultPrompt;
163-
164- // サービスとして追加する
165- Game.Services.AddService(typeof(IDebugCommandHost), this);
166-
167- // 基本コマンドの追加
168-
169- // ヘルプコマンド
170- // 登録されているコマンド情報の表示
171- RegisterCommand("help", "Show Command helps",
172- delegate(IDebugCommandHost host, string command, IList<string> args)
173- {
174- int maxLen = 0;
175- foreach (CommandInfo cmd in commandTable.Values)
176- maxLen = Math.Max(maxLen, cmd.command.Length);
177-
178- string fmt = String.Format("{{0,-{0}}} {{1}}", maxLen);
179-
180- foreach (CommandInfo cmd in commandTable.Values)
181- {
182- Echo(String.Format(fmt, cmd.command, cmd.description));
183- }
184- });
185-
186- // クリアスクリーン
187- // コマンド画面クリア
188- RegisterCommand("cls", "Clear Screen",
189- delegate(IDebugCommandHost host, string command, IList<string> args)
190- {
191- lines.Clear();
192- });
193-
194- // Echoコマンド
195- RegisterCommand("echo", "Display Messages",
196- delegate(IDebugCommandHost host, string command, IList<string> args)
197- {
198- Echo(command.Substring(5));
199- });
200- }
201-
202- /// <summary>
203- /// コンポーネントの初期化
204- /// </summary>
205- public override void Initialize()
206- {
207- debugManager =
208- Game.Services.GetService(typeof(DebugManager)) as DebugManager;
209-
210- if (debugManager == null)
211- throw new InvalidOperationException("DebugManagerが見つかりません。");
212-
213- base.Initialize();
214- }
215-
216- #endregion
217-
218- #region IDebugCommandHostインターフェースの実装
219-
220- public void RegisterCommand(
221- string command, string description, DebugCommandExecute callback)
222- {
223- string lowerCommand = command.ToLower();
224- if (commandTable.ContainsKey(lowerCommand))
225- {
226- throw new InvalidOperationException(
227- String.Format("{0}は既に登録されています", command));
228- }
229-
230- commandTable.Add(
231- lowerCommand, new CommandInfo(command, description, callback));
232- }
233-
234- public void UnregisterCommand(string command)
235- {
236- string lowerCommand = command.ToLower();
237- if (!commandTable.ContainsKey(lowerCommand))
238- {
239- throw new InvalidOperationException(
240- String.Format("{0}は登録されていません", command));
241- }
242-
243- commandTable.Remove(command);
244- }
245-
246- public void ExecuteCommand(string command)
247- {
248- // 他のコマンド実行者が登録されている場合は、最新の登録者にコマンドを
249- // 実行させる。
250- if (executioners.Count != 0)
251- {
252- executioners.Peek().ExecuteCommand(command);
253- return;
254- }
255-
256- // コマンドの実行
257- char[] spaceChars = new char[] { ' ' };
258-
259- Echo(Prompt + command);
260-
261- command = command.TrimStart(spaceChars);
262-
263- List<string> args = new List<string>(command.Split(spaceChars));
264- string cmdText = args[0];
265- args.RemoveAt(0);
266-
267- CommandInfo cmd;
268- if (commandTable.TryGetValue(cmdText.ToLower(), out cmd))
269- {
270- try
271- {
272- // 登録されているコマンドのデリゲートを呼び出す
273- cmd.callback(this, command, args);
274- }
275- catch (Exception e)
276- {
277- // 例外がコマンド実行中に発生
278- EchoError("Unhandled Exception occured");
279-
280- string[] lines = e.Message.Split(new char[] { '\n' });
281- foreach (string line in lines)
282- EchoError(line);
283- }
284- }
285- else
286- {
287- Echo("Unknown Command");
288- }
289-
290- // コマンドヒストリに追加する
291- commandHistory.Add(command);
292- while (commandHistory.Count > MaxCommandHistory)
293- commandHistory.RemoveAt(0);
294-
295- commandHistoryIndex = commandHistory.Count;
296- }
297-
298- public void RegisterEchoListner(IDebugEchoListner listner)
299- {
300- listenrs.Add(listner);
301- }
302-
303- public void UnregisterEchoListner(IDebugEchoListner listner)
304- {
305- listenrs.Remove(listner);
306- }
307-
308- public void Echo(DebugCommandMessage messageType, string text)
309- {
310- lines.Enqueue(text);
311- while (lines.Count >= MaxLineCount)
312- lines.Dequeue();
313-
314- // 登録されているリスナーを呼び出す
315- foreach (IDebugEchoListner listner in listenrs)
316- listner.Echo(messageType, text);
317- }
318-
319- public void Echo(string text)
320- {
321- Echo(DebugCommandMessage.Standard, text);
322- }
323-
324- public void EchoWarning(string text)
325- {
326- Echo(DebugCommandMessage.Warning, text);
327- }
328-
329- public void EchoError(string text)
330- {
331- Echo(DebugCommandMessage.Error, text);
332- }
333-
334- public void PushExecutioner(IDebugCommandExecutioner executioner)
335- {
336- executioners.Push(executioner);
337- }
338-
339- public void PopExecutioner()
340- {
341- executioners.Pop();
342- }
343-
344- #endregion
345-
346- #region 更新と描画
347-
348- /// <summary>
349- /// デバッグコマンドウィンドウを表示する。
350- /// </summary>
351- public void Show()
352- {
353- if (state == State.Closed)
354- {
355- stateTransition = 0.0f;
356- state = State.Opening;
357- }
358- }
359-
360- /// <summary>
361- /// デバッグコマンドウィンドウを非表示にする。
362- /// </summary>
363- public void Hide()
364- {
365- if (state == State.Opened)
366- {
367- stateTransition = 1.0f;
368- state = State.Closing;
369- }
370- }
371-
372- public override void Update(GameTime gameTime)
373- {
374- KeyboardState keyState = Keyboard.GetState();
375-
376- float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;
377- const float OpenSpeed = 8.0f;
378- const float CloseSpeed = 8.0f;
379-
380- switch (state)
381- {
382- case State.Closed:
383- if (keyState.IsKeyDown(Keys.Tab))
384- Show();
385- break;
386- case State.Opening:
387- stateTransition += dt * OpenSpeed;
388- if (stateTransition > 1.0f)
389- {
390- stateTransition = 1.0f;
391- state = State.Opened;
392- }
393- break;
394- case State.Opened:
395- ProcessKeyInputs(dt);
396- break;
397- case State.Closing:
398- stateTransition -= dt * CloseSpeed;
399- if (stateTransition < 0.0f)
400- {
401- stateTransition = 0.0f;
402- state = State.Closed;
403- }
404- break;
405- }
406-
407- prevKeyState = keyState;
408-
409- base.Update(gameTime);
410- }
411-
412- /// <summary>
413- /// キー入力処理
414- /// </summary>
415- /// <param name="dt"></param>
416- public void ProcessKeyInputs(float dt)
417- {
418- KeyboardState keyState = Keyboard.GetState();
419- Keys[] keys = keyState.GetPressedKeys();
420-
421- bool shift = keyState.IsKeyDown(Keys.LeftShift) ||
422- keyState.IsKeyDown(Keys.RightShift);
423-
424- foreach (Keys key in keys)
425- {
426- if (!IsKeyPressed(key, dt)) continue;
427-
428- char ch;
429- if (KeyboardUtils.KeyToString(key, shift, out ch))
430- {
431- // 通常文字の入力
432- commandLine = commandLine.Insert(cursorIndex, new string(ch, 1));
433- cursorIndex++;
434- }
435- else
436- {
437- switch (key)
438- {
439- case Keys.Back:
440- if (cursorIndex > 0)
441- commandLine = commandLine.Remove(--cursorIndex, 1);
442- break;
443- case Keys.Delete:
444- if (cursorIndex < commandLine.Length)
445- commandLine = commandLine.Remove(cursorIndex, 1);
446- break;
447- case Keys.Left:
448- if (cursorIndex > 0)
449- cursorIndex--;
450- break;
451- case Keys.Right:
452- if (cursorIndex < commandLine.Length)
453- cursorIndex++;
454- break;
455- case Keys.Enter:
456- // コマンドの実行
457- ExecuteCommand(commandLine);
458- commandLine = string.Empty;
459- cursorIndex = 0;
460- break;
461- case Keys.Up:
462- // ヒストリ表示
463- if (commandHistory.Count > 0)
464- {
465- commandHistoryIndex =
466- Math.Max(0, commandHistoryIndex - 1);
467-
468- commandLine = commandHistory[commandHistoryIndex];
469- cursorIndex = commandLine.Length;
470- }
471- break;
472- case Keys.Down:
473- // ヒストリ表示
474- if (commandHistory.Count > 0)
475- {
476- commandHistoryIndex = Math.Min(commandHistory.Count - 1,
477- commandHistoryIndex + 1);
478- commandLine = commandHistory[commandHistoryIndex];
479- cursorIndex = commandLine.Length;
480- }
481- break;
482- case Keys.Tab:
483- Hide();
484- break;
485- }
486- }
487- }
488-
489- }
490-
491- /// <summary>
492- /// キーリピート付きキー押下チェック
493- /// </summary>
494- /// <param name="key"></param>
495- /// <returns></returns>
496- bool IsKeyPressed(Keys key, float dt)
497- {
498- // 前フレームでキーが押されていなければ、キーが押されていると判定
499- if (prevKeyState.IsKeyUp(key))
500- {
501- keyRepeatTimer = keyRepeatStartDuration;
502- pressedKey = key;
503- return true;
504- }
505-
506- // 前フレームでキーが押されていた場合はリピート処理
507- if (key == pressedKey)
508- {
509- keyRepeatTimer -= dt;
510- if (keyRepeatTimer <= 0.0f)
511- {
512- keyRepeatTimer += keyRepeatDuration;
513- return true;
514- }
515- }
516-
517- return false;
518- }
519-
520- public override void Draw(GameTime gameTime)
521- {
522- // コマンドウィンドウが完全に閉じている場合は描画処理をしない
523- if (state == State.Closed)
524- return;
525-
526- SpriteFont font = debugManager.DebugFont;
527- SpriteBatch spriteBatch = debugManager.SpriteBatch;
528- Texture2D whiteTexture = debugManager.WhiteTexture;
529-
530- // コマンドウィンドウのサイズ計算と描画
531- float w = GraphicsDevice.Viewport.Width;
532- float h = GraphicsDevice.Viewport.Height;
533- float topMargin = h * 0.1f;
534- float leftMargin = w * 0.1f;
535-
536- Rectangle rect = new Rectangle();
537- rect.X = (int)leftMargin;
538- rect.Y = (int)topMargin;
539- rect.Width = (int)(w * 0.8f);
540- rect.Height = (int)(MaxLineCount * font.LineSpacing);
541-
542- Matrix mtx = Matrix.CreateTranslation(
543- new Vector3(0, -rect.Height * (1.0f - stateTransition), 0));
544-
545- spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, mtx);
546-
547- spriteBatch.Draw(whiteTexture, rect, new Color(0, 0, 0, 200));
548-
549- // 文字列の描画
550- Vector2 pos = new Vector2(leftMargin, topMargin);
551- foreach (string line in lines)
552- {
553- spriteBatch.DrawString(font, line, pos, Color.White);
554- pos.Y += font.LineSpacing;
555- }
556-
557- // プロンプト文字列の描画
558- string leftPart = Prompt + commandLine.Substring(0, cursorIndex);
559- Vector2 cursorPos = pos + font.MeasureString(leftPart);
560- cursorPos.Y = pos.Y;
561-
562- spriteBatch.DrawString(font,
563- String.Format("{0}{1}", Prompt, commandLine), pos, Color.White);
564- spriteBatch.DrawString(font, Cursor, cursorPos, Color.White);
565-
566- spriteBatch.End();
567- }
568-
569- #endregion
570-
571- }
572-}
--- branches/XNA4/MikuMikuDanceXNADemo1/MikuMikuDanceXNADemo1/Utils/StringBuilderExtensions.cs (revision 800)
+++ branches/XNA4/MikuMikuDanceXNADemo1/MikuMikuDanceXNADemo1/Utils/StringBuilderExtensions.cs (nonexistent)
@@ -1,201 +0,0 @@
1-#region Using ステートメント
2-
3-using System;
4-using System.Globalization;
5-using System.Text;
6-
7-#endregion
8-
9-namespace DebugSample
10-{
11- /// <summary>
12- /// StringBuilder拡張メソッド用オプション
13- /// </summary>
14- [Flags]
15- public enum AppendNumberOptions
16- {
17- // 通常フォーマット
18- None = 0,
19-
20- // 正の値の時にも"+"をつける
21- PositiveSign = 1,
22-
23- // 3桁毎に","を表示する
24- NumberGroup = 2,
25- }
26-
27- /// <summary>
28- /// StringBuilder用の拡張メソッド宣言用静的クラス
29- /// </summary>
30- /// <remarks>
31- /// XNA GS 3.0からSpriteFont.DrawStringにはStringBuilderを
32- /// 指定できるようになり、不必要なメモリ確保が少なくなった。
33- ///
34- /// しかし、数字を表示するには2つの問題がある。
35- /// ひとつはStringBuilder.AppendFormatメソッドを使うと
36- /// ボクシングが発生してしまうこと。
37- /// もうひとつは、StringBuilder.Appendで整数値やfloat値を指定すると
38- /// 内部でメモリ確保が発生してしまうこと。
39- ///
40- /// メモリ確保やボクシングが発生させずに数字表示に最低限必要なフォーマット機能を
41- /// このクラスは提供する。
42- ///
43- /// StringBuilderの拡張メソッドとして宣言しているので以下のようにして使用する
44- ///
45- /// stringBuilder.AppendNumber(12345);
46- ///
47- /// </remarks>
48- public static class StringBuilderExtensions
49- {
50- #region フィールド
51-
52- /// <summary>
53- /// NumberFormatクラスのNumberGroupSizesのキッシュ
54- /// </summary>
55- static int[] numberGroupSizes =
56- CultureInfo.CurrentCulture.NumberFormat.NumberGroupSizes;
57-
58- /// <summary>
59- /// 文字列変換用のバッファ
60- /// </summary>
61- static char[] numberString = new char[32];
62-
63- #endregion
64-
65- /// <summary>
66- /// 整数を文字列に変換してStringBuilderに追加する
67- /// </summary>
68- public static void AppendNumber(this StringBuilder builder, int number)
69- {
70- AppendNumbernternal(builder, number, 0, AppendNumberOptions.None);
71- }
72-
73- /// <summary>
74- /// 整数を文字列に変換してStringBuilderに追加する
75- /// </summary>
76- /// <param name="number"></param>
77- /// <param name="options">フォーマット指定オプション</param>
78- public static void AppendNumber(this StringBuilder builder, int number,
79- AppendNumberOptions options)
80- {
81- AppendNumbernternal(builder, number, 0, options);
82- }
83-
84- /// <summary>
85- /// float値を文字列に変換してStringBuilderに追加する
86- /// </summary>
87- /// <param name="number">変換する数字</param>
88- /// <remarks>小数点以下二桁まで表示する</remarks>
89- public static void AppendNumber(this StringBuilder builder, float number)
90- {
91- AppendNumber(builder, number, 2, AppendNumberOptions.None);
92- }
93-
94- /// <summary>
95- /// float値を文字列に変換してStringBuilderに追加する
96- /// </summary>
97- /// <param name="number">変換する数字</param>
98- /// <param name="options">フォーマット指定オプション</param>
99- /// <remarks>小数点以下二桁まで表示する</remarks>
100- public static void AppendNumber(this StringBuilder builder, float number,
101- AppendNumberOptions options)
102- {
103- AppendNumber(builder, number, 2, options);
104- }
105-
106- /// <summary>
107- /// float値を文字列に変換してStringBuilderに追加する
108- /// </summary>
109- /// <param name="number">変換する数字</param>
110- /// <param name="decimalCount">表示する小数点以下の桁数</param>
111- /// <param name="options">フォーマット指定オプション</param>
112- public static void AppendNumber(this StringBuilder builder, float number,
113- int decimalCount, AppendNumberOptions options)
114- {
115- // NaN, Infinity等の数値の特殊ケース判定
116- if (float.IsNaN(number))
117- {
118- builder.Append("NaN");
119- }
120- else if (float.IsNegativeInfinity(number))
121- {
122- builder.Append("-Infinity");
123- }
124- else if (float.IsPositiveInfinity(number))
125- {
126- builder.Append("+Infinity");
127- }
128- else
129- {
130- int intNumber =
131- (int)(number * (float)Math.Pow(10, decimalCount) + 0.5f);
132-
133- AppendNumbernternal(builder, intNumber, decimalCount, options);
134- }
135- }
136-
137-
138- static void AppendNumbernternal(StringBuilder builder, int number,
139- int decimalCount, AppendNumberOptions options)
140- {
141- // 変換に必要な変数の初期化
142- NumberFormatInfo nfi = CultureInfo.CurrentCulture.NumberFormat;
143-
144- int idx = numberString.Length;
145- int decimalPos = idx - decimalCount;
146-
147- if (decimalPos == idx)
148- decimalPos = idx + 1;
149-
150- int numberGroupIdx = 0;
151- int numberGroupCount = numberGroupSizes[numberGroupIdx] + decimalCount;
152-
153- bool showNumberGroup = (options & AppendNumberOptions.NumberGroup) != 0;
154- bool showPositiveSign = (options & AppendNumberOptions.PositiveSign) != 0;
155-
156- bool isNegative = number < 0;
157- number = Math.Abs(number);
158-
159- // 最小桁から各桁を文字に変換する
160- do
161- {
162- // 小数点の区切り文字(日本では".")の追加
163- if (idx == decimalPos)
164- {
165- numberString[--idx] = nfi.NumberDecimalSeparator[0];
166- }
167-
168- // 桁グループ区切り文字(日本では",")の追加
169- if (--numberGroupCount < 0 && showNumberGroup)
170- {
171- numberString[--idx] = nfi.NumberGroupSeparator[0];
172-
173- if (numberGroupIdx < numberGroupSizes.Length - 1)
174- numberGroupIdx++;
175-
176- numberGroupCount = numberGroupSizes[numberGroupIdx] - 1;
177- }
178-
179- // 現在の桁を文字に変換してバッファに追加
180- numberString[--idx] = (char)('0' + (number % 10));
181- number /= 10;
182-
183- } while (number > 0 || decimalPos <= idx);
184-
185-
186- // 符号文字を必要なら追加する
187- if (isNegative)
188- {
189- numberString[--idx] = nfi.NegativeSign[0];
190- }
191- else if (showPositiveSign)
192- {
193- numberString[--idx] = nfi.PositiveSign[0];
194- }
195-
196- // 変換結果をStringBuilderに追加する
197- builder.Append(numberString, idx, numberString.Length - idx);
198- }
199-
200- }
201-}
\ No newline at end of file
--- branches/XNA4/MikuMikuDanceXNADemo1/MikuMikuDanceXNADemo1/Utils/Layout.cs (revision 800)
+++ branches/XNA4/MikuMikuDanceXNADemo1/MikuMikuDanceXNADemo1/Utils/Layout.cs (nonexistent)
@@ -1,235 +0,0 @@
1-#region Using ステートメント
2-
3-using System;
4-
5-using Microsoft.Xna.Framework;
6-using Microsoft.Xna.Framework.Graphics;
7-
8-#endregion
9-
10-namespace DebugSample
11-{
12- /// <summary>
13- /// レイアウトのアライメント位置
14- /// </summary>
15- [Flags]
16- public enum Alignment
17- {
18- // レイアウトなし
19- None = 0,
20-
21- // 水平方向のレイアウト群
22- // 左側
23- Left = 1,
24- // 右側
25- Right = 2,
26- // 水平方向中央
27- HorizontalCenter = 4,
28-
29- // 垂直方向のレイアウト群
30- // 上側
31- Top = 8,
32- // 下側
33- Bottom = 16,
34- // 垂直方向中央
35- VerticalCenter = 32,
36-
37- // 左上
38- TopLeft = Top | Left,
39- // 右上
40- TopRight = Top | Right,
41- // 上側、中央
42- TopCenter = Top | HorizontalCenter,
43-
44- // 左下
45- BottomLeft = Bottom | Left,
46- // 右下
47- BottomRight = Bottom | Right,
48- // 下側、中央
49- BottomCenter = Bottom | HorizontalCenter,
50-
51- // 中央、左側
52- CenterLeft = VerticalCenter | Left,
53- // 中央、右側
54- CenterRight = VerticalCenter | Right,
55- // 中央
56- Center = VerticalCenter | HorizontalCenter
57- }
58-
59- /// <summary>
60- /// セーフエリアに対応したレイアウト構造体
61- /// </summary>
62- /// <remarks>
63- /// Windows、Xbox 360の両プラットフォームで動作するゲームは様々な解像度、
64- /// アスペクト比に対応する必要がある。加えてXbox 360で動作するゲームは
65- /// タイトルセーフエリアにも対応する必要がある。
66- ///
67- /// この構造体では、レイアウト対象領域(クライアントエリア)と、
68- /// セーフエリア領域を保持しAligmentと水平垂直のマージン値から
69- /// 指定した矩形を配置する。
70- /// 配置後の矩形がセーフエリア外にある場合はセーフエリア内に再配置される。
71- ///
72- /// マージンはクライアントエリアの割合で示す。
73- ///
74- /// 使用例:
75- ///
76- /// Place( region, 0.1f, 0.2f, Aligment.TopLeft );
77- ///
78- /// クライアントエリアの左端から10%、上端から20%の部分にregionを配置する
79- ///
80- ///
81- /// Place( region, 0.3f, 0.4f, Aligment.BottomRight );
82- ///
83- /// クライアントエリアの右端から30%、下端から40%の部分にregionを配置する
84- ///
85- ///
86- /// クライアントエリアとセーフエリアを別々に指定できるので、
87- /// 画面分割時にも、セーフエリアにタイトルセーフエリアを指定し、
88- /// クライアントエリアに分割した画面の領域を指定することで、レイアウトは
89- /// 画面分割領域ベースで行いつつも、タイトルセーフエリア内に正しく配置することが
90- /// できる。
91- ///
92- ///
93- /// セーフエリアについては以下のURLを参照
94- /// http://blogs.msdn.com/ito/archive/2008/11/21/safearea-sample.aspx
95- /// /// </remarks>
96- public struct Layout
97- {
98- #region フィールド
99-
100- /// <summary>
101- /// クライアントエリアの取得と設定
102- /// </summary>
103- public Rectangle ClientArea;
104-
105- /// <summary>
106- /// セーフエリアの取得と設定
107- /// </summary>
108- public Rectangle SafeArea;
109-
110- #endregion
111-
112- #region 初期化
113-
114- /// <summary>
115- /// クライアントエリアとセーフエリアを別々に指定して初期化する
116- /// </summary>
117- /// <param name="client">クライアントエリア</param>
118- /// <param name="safeArea">セーフエリア</param>
119- public Layout(Rectangle clientArea, Rectangle safeArea)
120- {
121- ClientArea = clientArea;
122- SafeArea = safeArea;
123- }
124-
125- /// <summary>
126- /// クライアントエリアのみを指定して初期化する
127- /// セーフエリアはクライアントエリアと同じサイズになる
128- /// </summary>
129- /// <param name="client">クライアントエリア</param>
130- public Layout(Rectangle clientArea)
131- : this(clientArea, clientArea)
132- {
133- }
134-
135- /// <summary>
136- /// Viewportを指定して初期化する
137- /// セーフエリアはViewport.TitleSafeAreaになる
138- /// </summary>
139- /// <param name="viewport">ビューポート</param>
140- public Layout(Viewport viewport)
141- {
142- ClientArea = new Rectangle((int)viewport.X, (int)viewport.Y,
143- (int)viewport.Width, (int)viewport.Height);
144- SafeArea = viewport.TitleSafeArea;
145- }
146-
147- #endregion
148-
149- /// <summary>
150- /// 指定したサイズ矩形のレイアウト
151- /// </summary>
152- /// <param name="region">配置する矩形</param>
153- /// <param name="horizontalMargin">垂直方向のマージン</param>
154- /// <param name="verticalMargine">水平方向のマージン</param>
155- /// <param name="alignment">アライメント</param>
156- /// <returns>配置された矩形</returns>
157- public Vector2 Place(Vector2 size, float horizontalMargin,
158- float verticalMargine, Alignment alignment)
159- {
160- Rectangle rc = new Rectangle(0, 0, (int)size.X, (int)size.Y);
161- rc = Place(rc, horizontalMargin, verticalMargine, alignment);
162- return new Vector2(rc.X, rc.Y);
163- }
164-
165- /// <summary>
166- /// 指定した矩形のレイアウト
167- /// </summary>
168- /// <param name="region">配置する矩形</param>
169- /// <param name="horizontalMargin">垂直方向のマージン</param>
170- /// <param name="verticalMargine">水平方向のマージン</param>
171- /// <param name="alignment">アライメント</param>
172- /// <returns>配置された矩形</returns>
173- public Rectangle Place(Rectangle region, float horizontalMargin,
174- float verticalMargine, Alignment alignment)
175- {
176- // 水平方向のレイアウト
177- if ((alignment & Alignment.Left) != 0)
178- {
179- region.X = ClientArea.X + (int)(ClientArea.Width * horizontalMargin);
180- }
181- else if ((alignment & Alignment.Right) != 0)
182- {
183- region.X = ClientArea.X +
184- (int)(ClientArea.Width * (1.0f - horizontalMargin)) -
185- region.Width;
186- }
187- else if ((alignment & Alignment.HorizontalCenter) != 0)
188- {
189- region.X = ClientArea.X + (ClientArea.Width - region.Width) / 2 +
190- (int)(horizontalMargin * ClientArea.Width);
191- }
192- else
193- {
194- // レイアウトなし
195- }
196-
197- // 垂直方向のレイアウト
198- if ((alignment & Alignment.Top) != 0)
199- {
200- region.Y = ClientArea.Y + (int)(ClientArea.Height * verticalMargine);
201- }
202- else if ((alignment & Alignment.Bottom) != 0)
203- {
204- region.Y = ClientArea.Y +
205- (int)(ClientArea.Height * (1.0f - verticalMargine)) -
206- region.Height;
207- }
208- else if ((alignment & Alignment.VerticalCenter) != 0)
209- {
210- region.Y = ClientArea.Y + (ClientArea.Height - region.Height) / 2 +
211- (int)(verticalMargine * ClientArea.Height);
212- }
213- else
214- {
215- // レイアウトなし
216- }
217-
218- // レイアウトした領域をセーフエリア内にあるか確かめる
219- if (region.Left < SafeArea.Left)
220- region.X = SafeArea.Left;
221-
222- if (region.Right > SafeArea.Right)
223- region.X = SafeArea.Right - region.Width;
224-
225- if (region.Top < SafeArea.Top)
226- region.Y = SafeArea.Top;
227-
228- if (region.Bottom > SafeArea.Bottom)
229- region.Y = SafeArea.Bottom - region.Height;
230-
231- return region;
232- }
233-
234- }
235-}
\ No newline at end of file
Show on old repository browser