/// <summary> /// Begins drawing of the world. /// </summary> /// <param name="camera">The camera describing the the current view of the world.</param> /// <returns> /// The <see cref="ISpriteBatch"/> to use to draw the world objects, or null if an unexpected /// error was encountered when preparing the <see cref="ISpriteBatch"/>. When null, all drawing /// should be aborted completely instead of trying to draw with a different <see cref="ISpriteBatch"/> /// or manually recovering the error. /// </returns> /// <exception cref="InvalidOperationException"><see cref="IDrawingManager.State"/> is not equal to /// <see cref="DrawingManagerState.Idle"/>.</exception> public ISpriteBatch BeginDrawWorld(ICamera2D camera) { if (State != DrawingManagerState.Idle) throw new InvalidOperationException("This method cannot be called while already busy drawing."); try { // Ensure the RenderWindow is available if (!IsRenderWindowAvailable()) { if (log.IsInfoEnabled) log.Info("Skipping BeginDrawWorld() call - the RenderWindow is not available."); _state = DrawingManagerState.Idle; return null; } _worldCamera = camera; // No matter what the last draw was, we clear the screen when drawing the world since the world drawing // always comes first or not at all (makes no sense to draw the GUI then the world) _rw.Clear(BackgroundColor); _lastDrawWasToWorld = true; // Ensure the buffer is set up _buffer = _rw.CreateBufferRenderImage(_buffer); _sb.RenderTarget = _buffer; if (_buffer == null) return null; _buffer.Clear(BackgroundColor); // Start up the SpriteBatch _sb.Begin(BlendMode.Alpha, camera); // Change the state _state = DrawingManagerState.DrawingWorld; } catch (AccessViolationException ex) { // More frequent and less concerning exception const string errmsg = "Failed to start drawing world on `{0}`. Device was probably lost. Exception: {1}"; if (log.IsInfoEnabled) log.InfoFormat(errmsg, this, ex); _state = DrawingManagerState.Idle; SafeEndSpriteBatch(_sb); return null; } catch (Exception ex) { // Unexpected exception const string errmsg = "Failed to start drawing world on `{0}` due to unexpected exception. Exception: {1}"; if (log.IsErrorEnabled) log.ErrorFormat(errmsg, this, ex); Debug.Fail(string.Format(errmsg, this, ex)); _state = DrawingManagerState.Idle; SafeEndSpriteBatch(_sb); return null; } return _sb; }
/// <summary> /// Makes sure the internal buffer is ready then returns a <see cref="RenderImage"/> to draw to it. /// </summary> /// <returns>The <see cref="RenderImage"/> to use, or null if the buffer could not be prepared.</returns> RenderImage GetRenderImage() { var oldRI = _ri; _ri = _window.CreateBufferRenderImage(_ri); if (_ri == null) return null; if (!BypassClear || _ri != oldRI) _ri.Clear(BufferClearColor); return _ri; }
/// <summary> /// Begins drawing the graphical user interface, which is not affected by the camera. /// </summary> /// <param name="clearBuffer">When true, the buffer will be cleared before drawing. When false, the contents of the previous /// frame will remain in the buffer, only if the last draw was also to the GUI. When the last draw call was to the /// world, then this will have no affect. Useful for when you want to draw multiple GUI screens on top of one another.</param> /// <returns> /// The <see cref="ISpriteBatch"/> to use to draw the GUI, or null if an unexpected /// error was encountered when preparing the <see cref="ISpriteBatch"/>. When null, all drawing /// should be aborted completely instead of trying to draw with a different <see cref="ISpriteBatch"/> /// or manually recovering the error. /// </returns> /// <exception cref="InvalidOperationException"><see cref="IDrawingManager.State"/> is not equal to /// <see cref="DrawingManagerState.Idle"/>.</exception> public ISpriteBatch BeginDrawGUI(bool clearBuffer = true) { if (State != DrawingManagerState.Idle) throw new InvalidOperationException("This method cannot be called while already busy drawing."); try { // Ensure the RenderWindow is available if (!IsRenderWindowAvailable()) { if (log.IsInfoEnabled) log.Info("Skipping BeginDrawGUI() call - the RenderWindow is not available."); _state = DrawingManagerState.Idle; return null; } if (clearBuffer) { // If the last draw was also to the GUI, clear the screen if (!_lastDrawWasToWorld) _rw.Clear(BackgroundColor); } _lastDrawWasToWorld = false; // Ensure the buffer is set up _buffer = _rw.CreateBufferRenderImage(_buffer); _sb.RenderTarget = _buffer; if (_buffer == null) return null; // Always clear the GUI with alpha = 0 since we will be copying it over the screen _buffer.Clear(_clearGUIBufferColor); // Start up the SpriteBatch _sb.Begin(BlendMode.Alpha); // Change the state _state = DrawingManagerState.DrawingGUI; } catch (AccessViolationException ex) { // More frequent and less concerning exception const string errmsg = "Failed to start drawing GUI on `{0}`. Device was probably lost. Exception: {1}"; if (log.IsInfoEnabled) log.InfoFormat(errmsg, this, ex); _state = DrawingManagerState.Idle; SafeEndSpriteBatch(_sb); return null; } catch (Exception ex) { // Unexpected exception const string errmsg = "Failed to start drawing GUI on `{0}` due to unexpected exception. Exception: {1}"; if (log.IsErrorEnabled) log.ErrorFormat(errmsg, this, ex); Debug.Fail(string.Format(errmsg, this, ex)); _state = DrawingManagerState.Idle; SafeEndSpriteBatch(_sb); return null; } return _sb; }