/// <summary> /// This is called when the game should draw itself. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> /// <param name="graphics">The <see cref="Microsoft.Xna.Framework.Graphics.GraphicsDeviceManager"> /// Microsoft.Xna.Framework.Graphics.GraphicsDeviceManager</see> used to draw the frame.</param> /// <param name="spriteBatch">The <see cref="Microsoft.Xna.Framework.Graphics.SpriteBatch"> /// Microsoft.Xna.Framework.Graphics.SpriteBatch</see> used to draw the frame.</param> public static Texture2D Draw(bool textureOut) { if (Frozen || GraphicsDevice == null || DeviceManager == null || SpriteBatch == null || Effects == null) { return(lastFrame); } if (!viewportsMap.ContainsKey(Viewport.Default)) { viewportsMap.Add(Viewport.Default, GraphicsDevice.Viewport); } RenderTarget2D target = null, oldTarget = null; if (textureOut) { RenderTargetBinding[] rts = GraphicsDevice.GetRenderTargets(); target = rts.Length == 0 ? null : (RenderTarget2D)rts[0].RenderTarget; oldTarget = target; PresentationParameters pp = GraphicsDevice.PresentationParameters; target = new RenderTarget2D(GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, false, SurfaceFormat.Rg32, DepthFormat.Depth24); GraphicsDevice.SetRenderTarget(target); } GraphicsDevice.Clear(Microsoft.Xna.Framework.Color.Black); Microsoft.Xna.Framework.Color color; Texture2D texture; int totalAlpha; SpriteEffects sEffects = SpriteEffects.None; BlendState blendState = BlendState.AlphaBlend, lastBlendState = BlendState.AlphaBlend; SpriteBatch.Begin(SpriteSortMode.Immediate, blendState); int t = 0; Viewports.Sort(); foreach (Viewport viewport in Viewports) { if (viewport == null || viewport.Disposed || !viewport.Visible) { continue; } viewport.Sprites.Sort(); GraphicsDevice.Viewport = GetViewport(viewport); List <Sprite> remove = new List <Sprite>(); foreach (Sprite sprite in viewport.Sprites) { t++; if (sprite == null || sprite.Disposed || sprite.Bitmap == null) { remove.Add(sprite); continue; } if (!sprite.Visible) { continue; } totalAlpha = sprite.Color.Alpha + sprite.Viewport.Color.Alpha; if (totalAlpha == 0) { color = new Microsoft.Xna.Framework.Color(255, 255, 255, sprite.Opacity); } else { color = new Microsoft.Xna.Framework.Color( (byte)((sprite.Color.Red * sprite.Color.Alpha + viewport.Color.Red * viewport.Color.Alpha) / totalAlpha), (byte)((sprite.Color.Green * sprite.Color.Alpha + viewport.Color.Green * viewport.Color.Alpha) / totalAlpha), (byte)((sprite.Color.Blue * sprite.Color.Alpha + viewport.Color.Blue * viewport.Color.Alpha) / totalAlpha)); } color.R += (byte)(sprite.Tone.Red + viewport.Tone.Red); color.G += (byte)(sprite.Tone.Green + viewport.Tone.Green); color.B += (byte)(sprite.Tone.Blue + viewport.Tone.Blue); if (sprite.Opacity < 255) { color *= sprite.Opacity / 255f; } Rect rect = sprite.Rect; rect.X -= viewport.OX; rect.Y -= viewport.OY; switch (sprite.FlipMode) { case FlipModes.None: { sEffects = SpriteEffects.None; break; } case FlipModes.Horizontally: { sEffects = SpriteEffects.FlipHorizontally; break; } case FlipModes.Vertically: { sEffects = SpriteEffects.FlipVertically; break; } } //still need to do a better job of negative blending blendState = sprite.BlendType == 1 ? BlendState.Additive : BlendState.AlphaBlend; if (sprite.Bitmap.NeedRefresh) { sprite.Bitmap.Texture = CreateTextureFromBitmap(sprite.Bitmap.SystemBitmap); sprite.Bitmap.NeedRefresh = false; } texture = sprite.Bitmap.Texture; //There's still a problem with a lot of consecutive sprites using effect //Which I'll need to fix once I have a good laggy test case EffectGray = (sprite.Tone.Gray + viewport.Tone.Gray) / 255.0f; EffectColor = color; EffectBlendType = sprite.BlendType; bool useEffect = (sprite.Tone.Gray + viewport.Tone.Gray > 0) || // (color != Colors.White.ToXNAColor()) || (sprite.BlendType == 2); //DeviceManager.GraphicsDevice.Textures[1] = texture; //Effects.Parameters["width"].SetValue(sprite.Width); //Effects.Parameters["height"].SetValue(sprite.Height); //Effects.Parameters["bushDepth"].SetValue(sprite.BushDepth); //Effects.Parameters["blur"].SetValue(sprite.Blur); //Effects.Parameters["bubbleX"].SetValue(sprite.Bubble.X); //Effects.Parameters["bubbleY"].SetValue(sprite.Bubble.Y); //Effects.Parameters["bubbleRad"].SetValue((sprite.BubbleRadius)); if (blendState != lastBlendState) { if (!useEffect) { SpriteBatch.End(); SpriteBatch.Begin(SpriteSortMode.Immediate, blendState); } lastBlendState = blendState; } if (useEffect) { SpriteBatch.End(); SpriteBatch.Begin(SpriteSortMode.Immediate, blendState); // TODO: The Effects shader is still messed up, at least for rotation/scaling // so we can't use it right now //Effects.CurrentTechnique.Passes[0].Apply(); } try { SpriteBatch.Draw( texture, rect.ToXNARect(), sprite.BmpSourceRect.ToXNARect(), color, (float)(sprite.Rotation * 2 * Math.PI), new Vector2(sprite.OX, sprite.OY), sEffects, 0); } catch { MsgBox.Show("Graphics Error!"); throw new Exception("Graphics Error!"); } if (useEffect) { SpriteBatch.End(); SpriteBatch.Begin(SpriteSortMode.Immediate, blendState); } } foreach (Sprite sprite in remove) { viewport.Sprites.Remove(sprite); } } SpriteBatch.End(); //Console.WriteLine(t); if (Math.Abs(fading) > 0) { GraphicsDevice.Textures[1] = transitionTexture; TransEffect.Parameters["opacity"].SetValue((float)faded); SpriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend); if (!blankTransition) { TransEffect.CurrentTechnique.Passes[0].Apply(); } color = new Microsoft.Xna.Framework.Color((byte)255, (byte)255, (byte)255, (byte)(255.0 * faded)); SpriteBatch.Draw( lastFrame, ScreenRect.ToXNARect(), color); SpriteBatch.End(); faded += fading; if (faded <= 0) { faded = 0; fading = 0; } else if (faded >= 1) { faded = 1; fading = 0; } } if (textureOut) { GraphicsDevice.SetRenderTarget(oldTarget); return((Texture2D)target); } else { return(null); } }