OSDN Git Service

DPX→PX変換に失敗していたミスを修正。
[strokestylet/CsWin10Desktop3.git] / FDK24 / メディア / 文字列画像.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Diagnostics;
4
5 namespace FDK.メディア
6 {
7         /// <summary>
8         /// DirectWrite を使った Direct2D1ビットマップ。
9         /// </summary>
10         /// <remarks>
11         /// 「表示文字列」メンバを設定/更新すれば、次回の描画時にビットマップが生成される。
12         /// </remarks>
13         public class 文字列画像 : FDK.Activity
14         {
15                 /// <summary>
16                 /// このメンバを set すれば、次回の進行描画時に画像が更新される。
17                 /// </summary>
18                 public string 表示文字列 { get; set; } = null;
19                 public string フォント名 { get; set; } = "メイリオ";
20                 public float フォントサイズpt { get; set; } = 20.0f;
21                 public SharpDX.Direct2D1.InterpolationMode 補正モード { get; set; } = SharpDX.Direct2D1.InterpolationMode.Linear;
22                 public SharpDX.RectangleF? 転送元矩形dpx { get; set; } = null;
23                 public bool 加算合成 { get; set; } = false;
24                 public SharpDX.Size2F レイアウトサイズdpx { get; set; } = new SharpDX.Size2F( -1f, -1f );
25                 public bool 下詰め { get; set; } = false;
26
27                 public 文字列画像()
28                 {
29                 }
30                 public 文字列画像( string 文字列, float フォントサイズpt = 20.0f, string フォント名 = "メイリオ" )
31                 {
32                         this.表示文字列 = 文字列;
33                         this.フォント名 = フォント名;
34                         this.フォントサイズpt = フォントサイズpt;
35                 }
36                 protected override void Onデバイス依存リソースの作成( デバイスリソース dr )
37                 {
38                         this.前回の表示文字列 = null;
39
40                         if( this.表示文字列.Nullでも空でもない() )
41                         {
42                                 this.ビットマップを生成する( dr );
43                                 this.前回の表示文字列 = this.表示文字列; // 最初の構築完了。
44                         }
45                 }
46                 protected override void Onデバイス依存リソースの解放( デバイスリソース dr )
47                 {
48                         FDK.Utilities.解放する( ref this.黒ブラシ );
49                         FDK.Utilities.解放する( ref this.白ブラシ );
50                         FDK.Utilities.解放する( ref this.ビットマップレンダーターゲット );
51                         FDK.Utilities.解放する( ref this.テキストレイアウト );
52                         FDK.Utilities.解放する( ref this.テキストフォーマット );
53                 }
54                 public void 進行描画する(
55                         デバイスリソース dr,
56                         float 左位置dpx,
57                         float 上位置dpx,
58                         float 不透明度0to1 = 1.0f,
59                         float X方向拡大率 = 1.0f,
60                         float Y方向拡大率 = 1.0f,
61                         SharpDX.Matrix? 変換行列3Dpx = null )
62                 {
63                         var 変換行列2Dpx =
64                                 dr.拡大行列DPXtoPX  // スケーリング(1) DPX → PX
65                                 * SharpDX.Matrix3x2.Scaling( X方向拡大率, Y方向拡大率 )   // スケーリング(2)
66                                 * SharpDX.Matrix3x2.Translation( 左位置dpx * dr.拡大率DPXtoPX横方法, 上位置dpx * dr.拡大率DPXtoPX縦方向 );  // 平行移動(物理単位)。
67
68                         this.進行描画する( dr, 変換行列2Dpx, 変換行列3Dpx, 不透明度0to1 );
69                 }
70
71                 public void 進行描画する(
72                         デバイスリソース dr,
73                         SharpDX.Matrix3x2? 変換行列2Dpx = null,
74                         SharpDX.Matrix? 変換行列3Dpx = null,
75                         float 不透明度0to1 = 1.0f )
76                 {
77                         Debug.Assert( this.活性化している );
78
79                         if( this.表示文字列.Nullまたは空である() )
80                                 return;
81
82                         // 表示文字列が変更されているなら、ここで表示ビットマップの再構築を行う。
83                         if( false == string.Equals( this.表示文字列, this.前回の表示文字列 ) )
84                                 this.ビットマップを生成する( dr );
85
86                         if( null == this.ビットマップレンダーターゲット )
87                                 return;
88
89                         Utilities.D2DBatchDraw( dr.D2DContext1, () => {
90
91                                 dr.D2DContextの設定をリセットする( dr.D2DContext1 );
92
93                                 // 変換行列とブレンドモードをD2Dレンダーターゲットに設定する。
94                                 dr.D2DContext1.Transform = 変換行列2Dpx ?? SharpDX.Matrix3x2.Identity;
95                                 dr.D2DContext1.PrimitiveBlend = ( 加算合成 ) ? SharpDX.Direct2D1.PrimitiveBlend.Add : SharpDX.Direct2D1.PrimitiveBlend.SourceOver;
96
97                                 // D2Dレンダーターゲットに this.Bitmap を描画する。
98                                 using( var bmp = this.ビットマップレンダーターゲット.Bitmap )
99                                 {
100                                         dr.D2DContext1.DrawBitmap(
101                                                 bitmap: bmp,
102                                                 destinationRectangle: null,
103                                                 opacity: 不透明度0to1,
104                                                 interpolationMode: this.補正モード,
105                                                 sourceRectangle: this.転送元矩形dpx,
106                                                 erspectiveTransformRef: 変換行列3Dpx );
107                                 }
108                         } );
109                 }
110
111                 protected string 前回の表示文字列 = null;
112                 protected SharpDX.Direct2D1.BitmapRenderTarget ビットマップレンダーターゲット = null;
113                 protected SharpDX.DirectWrite.TextFormat テキストフォーマット = null;
114                 protected SharpDX.DirectWrite.TextLayout テキストレイアウト = null;
115                 protected SharpDX.Direct2D1.SolidColorBrush 白ブラシ = null;
116                 protected SharpDX.Direct2D1.SolidColorBrush 黒ブラシ = null;
117
118                 protected void ビットマップを生成する( デバイスリソース dr )
119                 {
120                         this.前回の表示文字列 = this.表示文字列;
121
122                         // テキストフォーマット/レイアウトを作成し、表示ビットマップのサイズを計算する。
123                         if( null == this.テキストフォーマット )
124                         {
125                                 this.テキストフォーマット = new SharpDX.DirectWrite.TextFormat( dr.DWriteFactory, this.フォント名, this.フォントサイズpt ) {
126                                         TextAlignment = SharpDX.DirectWrite.TextAlignment.Leading,
127                                 };
128                         }
129
130                         if( ( 0.0f >= this.レイアウトサイズdpx.Width ) || ( 0.0f >= this.レイアウトサイズdpx.Height ) )
131                                 this.レイアウトサイズdpx = dr.設計画面サイズdpx;
132
133                         this.テキストレイアウト?.Dispose();
134                         this.テキストレイアウト = new SharpDX.DirectWrite.TextLayout(
135                                 dr.DWriteFactory,
136                                 this.表示文字列,
137                                 this.テキストフォーマット,
138                                 this.レイアウトサイズdpx.Width,
139                                 this.レイアウトサイズdpx.Height );
140
141                         var 表示ビットマップのサイズdpx = new SharpDX.Size2F();
142                         var 上マージン = 0.0f;
143                         if( this.下詰め )
144                         {
145                                 表示ビットマップのサイズdpx = new SharpDX.Size2F(
146                                         this.テキストレイアウト.Metrics.WidthIncludingTrailingWhitespace,
147                                         this.レイアウトサイズdpx.Height );       // レイアウトの最大高
148
149                                 上マージン = this.レイアウトサイズdpx.Height - this.テキストレイアウト.Metrics.Height;
150                         }
151                         else
152                         {
153                                 表示ビットマップのサイズdpx = new SharpDX.Size2F(
154                                         this.テキストレイアウト.Metrics.WidthIncludingTrailingWhitespace,
155                                         this.テキストレイアウト.Metrics.Height );
156                         }
157
158                         // ビットマップレンダーターゲットを生成する。
159                         using( var target = dr.D2DContext1.Target )     // Target を get すると COM参照カウンタが増えるので注意。
160                         {
161                                 // D2DContext1.Target が設定済みであること。さもなきゃ例外も出さずに落ちる。
162                                 Debug.Assert( null != target );
163                         }
164                         this.ビットマップレンダーターゲット?.Dispose();
165                         this.ビットマップレンダーターゲット = new SharpDX.Direct2D1.BitmapRenderTarget(
166                                 dr.D2DContext1,
167                                 SharpDX.Direct2D1.CompatibleRenderTargetOptions.None,
168                                 表示ビットマップのサイズdpx );
169
170                         // ブラシの作成がまだなら行う。
171                         if( null == this.白ブラシ )
172                                 this.白ブラシ = new SharpDX.Direct2D1.SolidColorBrush( this.ビットマップレンダーターゲット, SharpDX.Color.LightGray );
173                         if( null == this.黒ブラシ )
174                                 this.黒ブラシ = new SharpDX.Direct2D1.SolidColorBrush( this.ビットマップレンダーターゲット, SharpDX.Color.Black );
175
176                         // ビットマップレンダーターゲットにテキストを描画する。
177                         Utilities.D2DBatchDraw( this.ビットマップレンダーターゲット, () => {
178
179                                 this.ビットマップレンダーターゲット.Clear( SharpDX.Color.Transparent );
180
181                                 this.ビットマップレンダーターゲット.DrawTextLayout(    // ドロップシャドウ
182                                         new SharpDX.Vector2( 1.0f, 上マージン + 1.0f ),
183                                         this.テキストレイアウト,
184                                         this.黒ブラシ,
185                                         SharpDX.Direct2D1.DrawTextOptions.Clip );
186
187                                 this.ビットマップレンダーターゲット.DrawTextLayout(    // 本体
188                                         new SharpDX.Vector2( 0.0f, 上マージン ),
189                                         this.テキストレイアウト,
190                                         this.白ブラシ,
191                                         SharpDX.Direct2D1.DrawTextOptions.Clip );
192                         } );
193                 }
194         }
195 }