PageRenderTime 53ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/Open Model Implementation/ColladaViewer/GraphicsDeviceControl.cs

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