using System; using System.Drawing; using System.Windows.Forms; using Microsoft.Xna.Framework.Graphics; using Color = System.Drawing.Color; using Rectangle = Microsoft.Xna.Framework.Rectangle; using System.ComponentModel.Design; using Microsoft.Xna.Framework.Content; namespace InnovationEditor { // Control that draws to a windows form abstract public class GraphicsDeviceControl : Control { GraphicsDeviceService graphicsDeviceService; // Gets a GraphicsDevice that can be used to draw onto this control. public GraphicsDevice GraphicsDevice { get { return graphicsDeviceService.GraphicsDevice; } } public IGraphicsDeviceService GraphicsServices { get { return graphicsDeviceService; } } // Gets an IServiceProvider containing our IGraphicsDeviceService public ServiceContainer Services { get { return services; } } ServiceContainer services = new ServiceContainer(); protected abstract void Initialize(); protected abstract void Draw(); 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(typeof(IGraphicsDeviceService), graphicsDeviceService); // Give derived classes a chance to initialize themselves. Initialize(); } base.OnCreateControl(); } protected override void Dispose(bool disposing) { if (graphicsDeviceService != null) { graphicsDeviceService.Release(disposing); graphicsDeviceService = null; } base.Dispose(disposing); } // Redraws the control in response to a WinForms paint message. 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); } // 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. 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. 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; } // Ends drawing the control 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 } } // 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 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; } // If we do not have a valid graphics device display a status message. 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); } } } // Ignores WinForms paint-background messages. The default implementation // would cause flickering protected override void OnPaintBackground(PaintEventArgs pevent) { } } }