OSDN Git Service

f8c57f04e869c0d72a8d7d878d668c255c39d201
[fooeditengine/FooEditEngine.git] / WPF / FooEditEngine / Direct2D / D2DRender.cs
1 /*
2  * Copyright (C) 2013 FooProject
3  * * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
5
6  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 
7  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
8
9 You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
10  */
11 using System;
12 using System.Collections.Generic;
13 using System.Linq;
14 using System.Text;
15 using System.Windows;
16 using System.Windows.Controls;
17 using System.Windows.Media;
18 using System.Windows.Interop;
19 using FooEditEngine;
20 using DotNetTextStore;
21 using DotNetTextStore.UnmanagedAPI.TSF;
22 using DotNetTextStore.UnmanagedAPI.WinDef;
23 using SharpDX;
24 using D2D = SharpDX.Direct2D1;
25 using DW = SharpDX.DirectWrite;
26 using D3D10 = SharpDX.Direct3D10;
27 using D3D9 = SharpDX.Direct3D9;
28 using DXGI = SharpDX.DXGI;
29
30 namespace FooEditEngine.WPF
31 {
32     sealed class D2DRender : D2DRenderCommon, IEditorRender
33     {
34         DotNetTextStore.TextStore store;
35         D3D10.Texture2D texture;
36         DXGI.Surface surface;
37         D3D10.Device device;
38         D3D9.Device device9;
39         D3D9.Surface surface9;
40         D2D.RenderTarget render;
41         double fontSize;
42         FontFamily fontFamily;
43         FontWeight fontWeigth;
44         FontStyle fontStyle;
45         D3DImage imageSource;
46
47         public D2DRender(FooTextBox textbox, double width, double height,Image image)
48         {
49             this.fontFamily = textbox.FontFamily;
50             this.fontSize = textbox.FontSize;
51             this.fontWeigth = textbox.FontWeight;
52             this.fontStyle = textbox.FontStyle;
53             this.Foreground = ToColor4(textbox.Foreground);
54             this.Background = ToColor4(textbox.Background);
55             this.ControlChar = ToColor4(textbox.ControlChar);
56             this.Hilight = ToColor4(textbox.Hilight);
57             this.Comment = ToColor4(textbox.Comment);
58             this.Url = ToColor4(textbox.URL);
59             this.Keyword1 = ToColor4(textbox.Keyword1);
60             this.Keyword2 = ToColor4(textbox.Keyword2);
61             this.Literal = ToColor4(textbox.Literal);
62             this.InsertCaret = ToColor4(textbox.InsertCaret);
63             this.OverwriteCaret = ToColor4(textbox.OverwriteCaret);
64             this.LineMarker = ToColor4(textbox.LineMarker);
65             this.UpdateArea = ToColor4(textbox.UpdateArea);
66             this.LineNumber = ToColor4(textbox.LineNumber);
67             this.store = textbox.TextStore;
68
69             this.CreateDevice();
70
71             this.ConstructDeviceResource(width, height);
72             this.InitTextFormat(this.fontFamily.Source, (float)this.fontSize, this.GetDWFontWeigth(this.fontWeigth), this.GetDWFontStyle(this.fontStyle));
73
74             this.imageSource = new D3DImage();
75             this.imageSource.Lock();
76             this.imageSource.SetBackBuffer(D3DResourceType.IDirect3DSurface9, this.surface9.NativePointer);  //設定しないとロード時に例外が発生する
77             this.imageSource.Unlock();
78
79             image.Source = this.imageSource;
80         }
81
82         public FontFamily FontFamily
83         {
84             get { return this.fontFamily; }
85             set
86             {
87                 this.fontFamily = value;
88                 this.InitTextFormat(this.fontFamily.Source, (float)this.fontSize, this.GetDWFontWeigth(this.fontWeigth), this.GetDWFontStyle(this.fontStyle));
89                 this.TabWidthChar = this.TabWidthChar;
90             }
91         }
92
93         public double FontSize
94         {
95             get { return this.fontSize; }
96             set
97             {
98                 this.fontSize = value;
99                 this.InitTextFormat(this.fontFamily.Source, (float)value, this.GetDWFontWeigth(this.fontWeigth), this.GetDWFontStyle(this.fontStyle));
100                 this.TabWidthChar = this.TabWidthChar;
101             }
102         }
103
104         public FontWeight FontWeigth
105         {
106             get
107             {
108                 return this.fontWeigth;
109             }
110             set
111             {
112                 this.fontWeigth = value;
113                 this.InitTextFormat(this.fontFamily.Source, (float)this.fontSize, this.GetDWFontWeigth(value),this.GetDWFontStyle(this.fontStyle));
114             }
115         }
116
117         public FontStyle FontStyle
118         {
119             get
120             {
121                 return this.fontStyle;
122             }
123             set
124             {
125                 this.fontStyle = value;
126                 this.InitTextFormat(this.fontFamily.Source, (float)this.fontSize, this.GetDWFontWeigth(this.fontWeigth), this.GetDWFontStyle(this.fontStyle));
127             }
128         }
129
130         public static Color4 ToColor4(System.Windows.Media.Color color)
131         {
132             return new Color4(color.R / 255.0f, color.G / 255.0f, color.B / 255.0f, color.A / 255.0f);
133         }
134
135         public bool Resize(double width, double height)
136         {
137             if (Math.Floor(width) != Math.Floor(this.imageSource.Width) || Math.Floor(height) != Math.Floor(this.imageSource.Height))
138             {
139                 this.ReConstructDeviceResource(width, height);
140                 this.imageSource.Lock();
141                 this.imageSource.SetBackBuffer(D3DResourceType.IDirect3DSurface9, this.surface9.NativePointer);
142                 this.imageSource.Unlock();
143                 return true;
144             }
145             return false;
146         }
147
148         public override void BegineDraw()
149         {
150             base.BegineDraw();
151         }
152
153         public override void EndDraw()
154         {
155             base.EndDraw();
156             this.device.Flush();
157
158             if (this.imageSource.IsFrontBufferAvailable)
159             {
160                 this.imageSource.Lock();
161                 this.imageSource.SetBackBuffer(D3DResourceType.IDirect3DSurface9, this.surface9.NativePointer);
162                 this.imageSource.AddDirtyRect(new Int32Rect(0, 0, (int)this.imageSource.Width, (int)this.imageSource.Height));
163                 this.imageSource.Unlock();
164             }
165         }
166
167         public void DrawOneLine(LineToIndexTable lti, int row, double x, double y, IEnumerable<Selection> SelectRanges)
168         {
169             PreDrawOneLineHandler PreDrawOneLine = (layout) => {
170                 using (Unlocker locker = this.store.LockDocument(false))
171                 {
172                     int lineIndex = lti.GetIndexFromLineNumber(row);
173                     int lineLength = lti.GetLengthFromLineNumber(row);
174                     foreach (TextDisplayAttribute attr in this.store.EnumAttributes(lineIndex,lineIndex + lineLength))
175                     {
176                         if (attr.startIndex == attr.endIndex)
177                             continue;
178                         int length = attr.endIndex - attr.startIndex;
179                         int start = attr.startIndex - lineIndex;
180
181                         HilightType type = HilightType.None;
182                         Color4? color = null;
183                         switch (attr.attribute.lsStyle)
184                         {
185                             case TF_DA_LINESTYLE.TF_LS_DOT:
186                                 type = HilightType.Dot;
187                                 color = this.GetColor4(attr.attribute.crLine);
188                                 break;
189                             case TF_DA_LINESTYLE.TF_LS_SOLID:
190                                 type = HilightType.Sold;
191                                 color = this.GetColor4(attr.attribute.crLine);
192                                 break;
193                             case TF_DA_LINESTYLE.TF_LS_DASH:
194                                 type = HilightType.Dash;
195                                 color = this.GetColor4(attr.attribute.crLine);
196                                 break;
197                             case TF_DA_LINESTYLE.TF_LS_SQUIGGLE:
198                                 type = HilightType.Squiggle;
199                                 color = this.GetColor4(attr.attribute.crLine);
200                                 break;
201                         }
202
203                         if (attr.attribute.crBk.type != TF_DA_COLORTYPE.TF_CT_NONE)
204                         {
205                             type = HilightType.Select;
206                             color = this.GetColor4(attr.attribute.crBk);
207                         }
208
209                         this.DrawMarkerEffect(layout, type, start, length,x,y,attr.attribute.fBoldLine,color);
210
211                         color = this.GetColor4(attr.attribute.crText);
212                         if (color != null)
213                         {
214                             this.SetTextColor(layout, start, length, color);
215                             layout.Invaild = true;
216                         }
217                     }
218                 }
219             };
220             base.DrawOneLine(lti,
221                 row,
222                 x,
223                 y,
224                 SelectRanges,
225                 PreDrawOneLine);
226         }
227
228         private Color4? GetColor4(TF_DA_COLOR cr)
229         {
230             COLORREF colorref;
231             switch(cr.type)
232             {
233                 case TF_DA_COLORTYPE.TF_CT_SYSCOLOR:
234                     colorref = new COLORREF(NativeMethods.GetSysColor((int)cr.indexOrColorRef));
235                     break;
236                 case TF_DA_COLORTYPE.TF_CT_COLORREF:
237                     colorref = new COLORREF(cr.indexOrColorRef);
238                     break;
239                 default:
240                     return null;
241             }
242             return new Color4(colorref.R / 255.0f, colorref.G / 255.0f, colorref.B / 255.0f, 1);
243         }
244
245         public override void Dispose()
246         {
247             base.Dispose();
248             this.DestructDevice();
249         }
250
251         DW.FontStyle GetDWFontStyle(FontStyle style)
252         {
253             return (DW.FontStyle)Enum.Parse(typeof(DW.FontStyle), style.ToString());
254         }
255
256         DW.FontWeight GetDWFontWeigth(FontWeight weigth)
257         {
258             return (DW.FontWeight)Enum.Parse(typeof(DW.FontWeight), weigth.ToString());
259         }
260
261         public override void DrawCachedBitmap(Rectangle rect)
262         {
263             if (this.render == null || this.render.IsDisposed)
264                 return;
265             render.DrawBitmap(this.cachedBitMap, rect, 1.0f, D2D.BitmapInterpolationMode.Linear, rect);
266         }
267
268         public override void CacheContent()
269         {
270             if (this.render == null || this.cachedBitMap == null || this.cachedBitMap.IsDisposed || this.render.IsDisposed)
271                 return;
272             //render.Flush();
273             this.cachedBitMap.CopyFromRenderTarget(this.render, new SharpDX.Point(), new SharpDX.Rectangle(0, 0, (int)this.renderSize.Width, (int)this.renderSize.Height));
274             this.hasCache = true;
275         }
276
277         void CreateDevice()
278         {
279             D3D10.FeatureLevel[] levels = new D3D10.FeatureLevel[]{D3D10.FeatureLevel.Level_10_1,
280                 D3D10.FeatureLevel.Level_10_0,
281                 D3D10.FeatureLevel.Level_9_3,
282                 D3D10.FeatureLevel.Level_9_2,
283                 D3D10.FeatureLevel.Level_9_1};
284             foreach (D3D10.FeatureLevel level in levels)
285             {
286                 try
287                 {
288                     this.device = new D3D10.Device1(D3D10.DriverType.Hardware, D3D10.DeviceCreationFlags.BgraSupport,level);
289                     break;
290                 }
291                 catch
292                 {
293                     continue;
294                 }
295             }
296             if (this.device == null)
297                 throw new PlatformNotSupportedException("DirectX10デバイスの作成に失敗しました");
298
299             IntPtr DesktopWnd = NativeMethods.GetDesktopWindow();
300             D3D9.Direct3DEx d3dex = new D3D9.Direct3DEx();
301
302             D3D9.PresentParameters param = new D3D9.PresentParameters();
303             param.Windowed = true;
304             param.SwapEffect = D3D9.SwapEffect.Discard;
305             param.DeviceWindowHandle = DesktopWnd;
306             param.PresentationInterval = D3D9.PresentInterval.Default;
307
308             try
309             {
310                 this.device9 = new D3D9.DeviceEx(
311                     d3dex,
312                     0,
313                     D3D9.DeviceType.Hardware,
314                     DesktopWnd,
315                     D3D9.CreateFlags.HardwareVertexProcessing | D3D9.CreateFlags.Multithreaded | D3D9.CreateFlags.FpuPreserve,
316                     param);
317             }
318             catch
319             {
320                 try
321                 {
322                     this.device9 = new D3D9.DeviceEx(
323                         d3dex,
324                         0,
325                         D3D9.DeviceType.Hardware,
326                         DesktopWnd,
327                         D3D9.CreateFlags.SoftwareVertexProcessing | D3D9.CreateFlags.Multithreaded | D3D9.CreateFlags.FpuPreserve,
328                         param);
329                 }
330                 catch
331                 {
332                     throw new PlatformNotSupportedException("DirectX9デバイスの作成に失敗しました");
333                 }
334             }
335             finally
336             {
337                 d3dex.Dispose();
338             }
339         }
340
341         void DestructDevice()
342         {
343             if (this.device != null)
344             {
345                 this.device.Dispose();
346                 this.device = null;
347             }
348             if (this.device9 != null)
349             {
350                 this.device9.Dispose();
351                 this.device9 = null;
352             }
353         }
354
355         protected override void ReCreateTarget()
356         {
357             System.Diagnostics.Debug.WriteLine("ReCreatedDevice");
358             this.DestructDevice();
359             this.CreateDevice();
360             this.ReConstructDeviceResource();
361         }
362
363         protected override D2D.RenderTarget ConstructRender(D2D.Factory factory, D2D.RenderTargetProperties prop, double width, double height)
364         {
365             D3D10.Texture2DDescription desc = new D3D10.Texture2DDescription();
366             desc.Width = (int)width;
367             desc.Height = (int)height;
368             desc.MipLevels = 1;
369             desc.ArraySize = 1;
370             desc.Format = DXGI.Format.B8G8R8A8_UNorm;
371             desc.SampleDescription = new DXGI.SampleDescription(1, 0);
372             desc.Usage = D3D10.ResourceUsage.Default;
373             desc.BindFlags = D3D10.BindFlags.RenderTarget | D3D10.BindFlags.ShaderResource;
374             desc.CpuAccessFlags = D3D10.CpuAccessFlags.None;
375             desc.OptionFlags = D3D10.ResourceOptionFlags.Shared;
376             this.texture = new D3D10.Texture2D(this.device, desc);
377
378             this.surface = this.texture.QueryInterface<DXGI.Surface>();
379
380             DXGI.Resource resource = this.texture.QueryInterface<DXGI.Resource>();
381             IntPtr handel = resource.SharedHandle;
382             D3D9.Texture texture = new D3D9.Texture(
383                 this.device9,
384                 this.texture.Description.Width,
385                 this.texture.Description.Height,
386                 1,
387                 D3D9.Usage.RenderTarget,
388                 D3D9.Format.A8R8G8B8,
389                 D3D9.Pool.Default,
390                 ref handel);
391             this.surface9 = texture.GetSurfaceLevel(0);
392             resource.Dispose();
393             texture.Dispose();
394
395             this.render = new D2D.RenderTarget(factory, this.surface, prop);
396             return this.render;
397         }
398
399         protected override void ConstrctedResource()
400         {
401         }
402
403         public double GetScale()
404         {
405             float dpi;
406             this.GetDpi(out dpi, out dpi);
407             return dpi / 96.0;
408         }
409
410         public override void GetDpi(out float dpix, out float dpiy)
411         {
412             IntPtr hDc = NativeMethods.GetDC(IntPtr.Zero);
413             dpix = NativeMethods.GetDeviceCaps(hDc, NativeMethods.LOGPIXELSX);
414             dpiy = NativeMethods.GetDeviceCaps(hDc, NativeMethods.LOGPIXELSY);
415             NativeMethods.ReleaseDC(IntPtr.Zero, hDc);
416         }
417
418         protected override void DestructRender()
419         {
420             if (this.texture != null)
421                 this.texture.Dispose();
422             if (this.surface != null)
423                 this.surface.Dispose();
424             if (this.surface9 != null)
425                 this.surface9.Dispose();
426             if (this.render != null)
427                 this.render.Dispose();
428         }
429     }
430 }