-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathGraphicsDeviceControl.cs
304 lines (236 loc) · 9.72 KB
/
GraphicsDeviceControl.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
#region File Description
//-----------------------------------------------------------------------------
// GraphicsDeviceControl.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion
#region Using Statements
using System;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.Xna.Framework.Graphics;
#endregion
namespace PasiveRadar
{
// System.Drawing and the XNA Framework both define Color and Rectangle
// types. To avoid conflicts, we specify exactly which ones to use.
using Color = System.Drawing.Color;
using Rectangle = Microsoft.Xna.Framework.Rectangle;
/// <summary>
/// Custom control uses the XNA Framework GraphicsDevice to render onto
/// a Windows Form. Derived classes can override the Initialize and Draw
/// methods to add their own drawing code.
/// </summary>
abstract public class GraphicsDeviceControl : Control
{
#region Fields
// However many GraphicsDeviceControl instances you have, they all share
// the same underlying GraphicsDevice, managed by this helper service.
GraphicsDeviceService graphicsDeviceService;
#endregion
#region Properties
/// <summary>
/// Gets a GraphicsDevice that can be used to draw onto this control.
/// </summary>
public GraphicsDevice GraphicsDevice
{
get { return graphicsDeviceService.GraphicsDevice; }
}
/// <summary>
/// Gets an IServiceProvider containing our IGraphicsDeviceService.
/// This can be used with components such as the ContentManager,
/// which use this service to look up the GraphicsDevice.
/// </summary>
public ServiceContainer Services
{
get { return services; }
}
ServiceContainer services = new ServiceContainer();
#endregion
#region Initialization
/// <summary>
/// Initializes the control.
/// </summary>
protected override void OnCreateControl()
{
// Don't initialize the graphics device if we are running in the designer.
if (!DesignMode)
{
graphicsDeviceService = GraphicsDeviceService.AddRef(Handle,
ClientSize.Width,
ClientSize.Height);
// Register the service, so components like ContentManager can find it.
services.AddService<IGraphicsDeviceService>(graphicsDeviceService);
// Give derived classes a chance to initialize themselves.
Initialize();
}
base.OnCreateControl();
}
/// <summary>
/// Disposes the control.
/// </summary>
protected override void Dispose(bool disposing)
{
if (graphicsDeviceService != null)
{
graphicsDeviceService.Release(disposing);
graphicsDeviceService = null;
}
base.Dispose(disposing);
}
#endregion
#region Paint
/// <summary>
/// Redraws the control in response to a WinForms paint message.
/// </summary>
protected override void OnPaint(PaintEventArgs e)
{
string beginDrawError = BeginDraw();
if (string.IsNullOrEmpty(beginDrawError))
{
// Draw the control using the GraphicsDevice.
Draw();
EndDraw();
}
else
{
// If BeginDraw failed, show an error message using System.Drawing.
PaintUsingSystemDrawing(e.Graphics, beginDrawError);
}
}
/// <summary>
/// Attempts to begin drawing the control. Returns an error message string
/// if this was not possible, which can happen if the graphics device is
/// lost, or if we are running inside the Form designer.
/// </summary>
string BeginDraw()
{
// If we have no graphics device, we must be running in the designer.
if (graphicsDeviceService == null)
{
return Text + "\n\n" + GetType();
}
// Make sure the graphics device is big enough, and is not lost.
string deviceResetError = HandleDeviceReset();
if (!string.IsNullOrEmpty(deviceResetError))
{
return deviceResetError;
}
// Many GraphicsDeviceControl instances can be sharing the same
// GraphicsDevice. The device backbuffer will be resized to fit the
// largest of these controls. But what if we are currently drawing
// a smaller control? To avoid unwanted stretching, we set the
// viewport to only use the top left portion of the full backbuffer.
Viewport viewport = new Viewport();
viewport.X = 0;
viewport.Y = 0;
viewport.Width = ClientSize.Width;
viewport.Height = ClientSize.Height;
viewport.MinDepth = 0;
viewport.MaxDepth = 1;
GraphicsDevice.Viewport = viewport;
return null;
}
/// <summary>
/// Ends drawing the control. This is called after derived classes
/// have finished their Draw method, and is responsible for presenting
/// the finished image onto the screen, using the appropriate WinForms
/// control handle to make sure it shows up in the right place.
/// </summary>
void EndDraw()
{
try
{
Rectangle sourceRectangle = new Rectangle(0, 0, ClientSize.Width,
ClientSize.Height);
// GraphicsDevice.Present(sourceRectangle, null, this.Handle);
}
catch
{
// Present might throw if the device became lost while we were
// drawing. The lost device will be handled by the next BeginDraw,
// so we just swallow the exception.
}
}
/// <summary>
/// Helper used by BeginDraw. This checks the graphics device status,
/// making sure it is big enough for drawing the current control, and
/// that the device is not lost. Returns an error string if the device
/// could not be reset.
/// </summary>
string HandleDeviceReset()
{
bool deviceNeedsReset = false;
switch (GraphicsDevice.GraphicsDeviceStatus)
{
case GraphicsDeviceStatus.Lost:
// If the graphics device is lost, we cannot use it at all.
return "Graphics device lost";
case GraphicsDeviceStatus.NotReset:
// If device is in the not-reset state, we should try to reset it.
deviceNeedsReset = true;
break;
default:
// If the device state is ok, check whether it is big enough.
PresentationParameters pp = GraphicsDevice.PresentationParameters;
deviceNeedsReset = (ClientSize.Width > pp.BackBufferWidth) ||
(ClientSize.Height > pp.BackBufferHeight);
break;
}
// Do we need to reset the device?
if (deviceNeedsReset)
{
try
{
graphicsDeviceService.ResetDevice(ClientSize.Width,
ClientSize.Height);
}
catch (Exception e)
{
return "Graphics device reset failed\n\n" + e;
}
}
return null;
}
/// <summary>
/// If we do not have a valid graphics device (for instance if the device
/// is lost, or if we are running inside the Form designer), we must use
/// regular System.Drawing method to display a status message.
/// </summary>
protected virtual void PaintUsingSystemDrawing(Graphics graphics, string text)
{
graphics.Clear(Color.CornflowerBlue);
using (Brush brush = new SolidBrush(Color.Black))
{
using (StringFormat format = new StringFormat())
{
format.Alignment = StringAlignment.Center;
format.LineAlignment = StringAlignment.Center;
graphics.DrawString(text, Font, brush, ClientRectangle, format);
}
}
}
/// <summary>
/// Ignores WinForms paint-background messages. The default implementation
/// would clear the control to the current background color, causing
/// flickering when our OnPaint implementation then immediately draws some
/// other color over the top using the XNA Framework GraphicsDevice.
/// </summary>
protected override void OnPaintBackground(PaintEventArgs pevent)
{
}
#endregion
#region Abstract Methods
/// <summary>
/// Derived classes override this to initialize their drawing code.
/// </summary>
protected abstract void Initialize();
/// <summary>
/// Derived classes override this to draw themselves using the GraphicsDevice.
/// </summary>
protected abstract void Draw();
#endregion
}
}