//----------------------------------------------------------------------------- // PostScreenMenu.cs // // Microsoft XNA Community Game Platform // Copyright (C) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using System; using System.Collections; using System.IO; using System.Text; using RacingGame.GameLogic; using RacingGame.Graphics; using RacingGame.Helpers; using Texture = RacingGame.Graphics.Texture; namespace RacingGame.Shaders { /// /// Post screen glow shader based on PostScreenMenu.fx /// /// Shader effect public class PostScreenMenu : ShaderEffect { /// /// The shader effect filename for this shader. /// private const string Filename = "PostScreenMenu.fx"; /// /// Effect handles for window size and scene map. /// protected EffectParameter windowSize, sceneMap, downsampleMap, blurMap1, blurMap2, noiseMap, timer; /// /// Links to the passTextures, easier to write code this way. /// This are just reference copies. Static to load them only once /// (used for both PostScreenMenu and PostScreenGlow). /// //dunno why, but RenderToTexture crashes if we do this: protected static RenderToTexture sceneMapTexture, // Instead load twice: //protected RenderToTexture sceneMapTexture = null, downsampleMapTexture, blurMap1Texture, blurMap2Texture; /// /// Helper texture for the noise and film effects. /// private Texture noiseMapTexture = null; /// /// Is this post screen shader started? /// Else don't execute Show if it is called. /// protected static bool started = false; /// /// Started /// /// Bool public static bool Started { get { return started; } } /// /// Create post screen menu. Also used for the constructor of /// PostScreenGlow (same RenderToTextures used there). /// protected PostScreenMenu(string shaderFilename) : base(shaderFilename) { // Scene map texture if (sceneMapTexture == null) sceneMapTexture = new RenderToTexture( RenderToTexture.SizeType.FullScreen); // Downsample map texture (to 1/4 of the screen) if (downsampleMapTexture == null) downsampleMapTexture = new RenderToTexture( RenderToTexture.SizeType.QuarterScreen); // Blur map texture if (blurMap1Texture == null) blurMap1Texture = new RenderToTexture( RenderToTexture.SizeType.QuarterScreen); // Blur map texture if (blurMap2Texture == null) blurMap2Texture = new RenderToTexture( RenderToTexture.SizeType.QuarterScreen); } /// /// Create post screen menu /// public PostScreenMenu() : this(Filename) { } /// /// Reload /// protected override void GetParameters() { // Can't get parameters if loading failed! if (effect == null) return; windowSize = effect.Parameters["windowSize"]; sceneMap = effect.Parameters["sceneMap"]; // We need both windowSize and sceneMap. if (windowSize == null || sceneMap == null) throw new NotSupportedException("windowSize and sceneMap must be " + "valid in PostScreenShader=" + Filename); // Init additional stuff downsampleMap = effect.Parameters["downsampleMap"]; blurMap1 = effect.Parameters["blurMap1"]; blurMap2 = effect.Parameters["blurMap2"]; timer = effect.Parameters["Timer"]; // Load noise texture for stripes effect noiseMap = effect.Parameters["noiseMap"]; noiseMapTexture = new Texture("Noise128x128"); // Set texture noiseMap.SetValue(noiseMapTexture.XnaTexture); } /// /// Start this post screen shader, will just call SetRenderTarget. /// All render calls will now be drawn on the sceneMapTexture. /// Make sure you don't reset the RenderTarget until you call Show()! /// public void Start() { // Only apply post screen shader if texture is valid and effect is valid if (sceneMapTexture == null || effect == null || started == true || // Also skip if we don't use post screen shaders at all! BaseGame.UsePostScreenShaders == false) return; BaseGame.SetRenderTarget(sceneMapTexture.RenderTarget, true); started = true; } /// /// Execute shaders and show result on screen, Start(..) must have been /// called before and the scene should be rendered to sceneMapTexture. /// public virtual void Show() { // Only apply post screen glow if texture is valid and effect is valid if (sceneMapTexture == null || Valid == false || started == false) return; started = false; // Resolve sceneMapTexture render target for Xbox360 support sceneMapTexture.Resolve(); // Don't use or write to the z buffer BaseGame.Device.DepthStencilState = DepthStencilState.None; // Also don't use any kind of blending. BaseGame.Device.BlendState = BlendState.Opaque; if (windowSize != null) windowSize.SetValue( new Vector2(sceneMapTexture.Width, sceneMapTexture.Height)); if (sceneMap != null) sceneMap.SetValue(sceneMapTexture.XnaTexture); if (timer != null) // Add a little offset to prevent first effect. timer.SetValue(BaseGame.TotalTime + 0.75f); effect.CurrentTechnique = effect.Techniques["ScreenGlow20"]; // We must have exactly 4 passes! if (effect.CurrentTechnique.Passes.Count != 4) throw new InvalidOperationException( "This shader should have exactly 4 passes!"); try { for (int pass = 0; pass < effect.CurrentTechnique.Passes.Count; pass++) { if (pass == 0) downsampleMapTexture.SetRenderTarget(); else if (pass == 1) blurMap1Texture.SetRenderTarget(); else if (pass == 2) blurMap2Texture.SetRenderTarget(); else { BaseGame.ResetRenderTarget(true); } EffectPass effectPass = effect.CurrentTechnique.Passes[pass]; effectPass.Apply(); VBScreenHelper.Render(); if (pass == 0) { downsampleMapTexture.Resolve(); if (downsampleMap != null) downsampleMap.SetValue(downsampleMapTexture.XnaTexture); effectPass.Apply(); } else if (pass == 1) { blurMap1Texture.Resolve(); if (blurMap1 != null) blurMap1.SetValue(blurMap1Texture.XnaTexture); effectPass.Apply(); } else if (pass == 2) { blurMap2Texture.Resolve(); if (blurMap2 != null) blurMap2.SetValue(blurMap2Texture.XnaTexture); effectPass.Apply(); } } } finally { // Restore z buffer state BaseGame.Device.DepthStencilState = DepthStencilState.Default; } } } }