//-----------------------------------------------------------------------------
// PostScreenGlow.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
using System;
using System.Collections;
using System.Text;
using System.IO;
using RacingGame.GameLogic;
using RacingGame.Graphics;
using RacingGame.Helpers;
using Microsoft.Xna.Framework.Graphics;
using Texture = RacingGame.Graphics.Texture;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework;
namespace RacingGame.Shaders
{
///
/// Post screen glow shader based on PostScreenGlow.fx.
/// Derive from PostScreenMenu, this way we can save duplicating
/// the effect parameters and use the same RenderToTextures.
///
public class PostScreenGlow : PostScreenMenu
{
static readonly BlendState BlendStateAlphaWrite = new BlendState() {
ColorSourceBlend = Blend.One,
AlphaSourceBlend = Blend.Zero,
ColorDestinationBlend = Blend.Zero,
AlphaDestinationBlend = Blend.One
};
///
/// The shader effect filename for this shader.
///
private const string Filename = "PostScreenGlow.fx";
///
/// Effect handles for window size and scene map.
///
private EffectParameter radialSceneMap,
radialBlurScaleFactor,
screenBorderFadeoutMap;
///
/// Links to the passTextures, easier to write code this way.
/// This are just reference copies.
///
private RenderToTexture radialSceneMapTexture;
///
/// Helper texture for the screen border (darken the borders).
///
private Texture screenBorderFadeoutMapTexture = null;
///
/// Last used radial blur scale factor
///
private float lastUsedRadialBlurScaleFactor = 0;
///
/// Radial blur scale factor
///
public float RadialBlurScaleFactor
{
get
{
return lastUsedRadialBlurScaleFactor;
}
set
{
if (radialBlurScaleFactor != null &&
lastUsedRadialBlurScaleFactor != value)
{
lastUsedRadialBlurScaleFactor = value;
radialBlurScaleFactor.SetValue(value);
}
}
}
///
/// Create post screen glow
///
public PostScreenGlow()
: base(Filename)
{
// Final map for glow, used to perform radial blur next step
radialSceneMapTexture = new RenderToTexture(
RenderToTexture.SizeType.FullScreen);
}
///
/// 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"];
radialSceneMap = effect.Parameters["radialSceneMap"];
// Load screen border texture
screenBorderFadeoutMap = effect.Parameters["screenBorderFadeoutMap"];
screenBorderFadeoutMapTexture = new Texture("ScreenBorderFadeout");
// Set texture
screenBorderFadeoutMap.SetValue(
screenBorderFadeoutMapTexture.XnaTexture);
radialBlurScaleFactor = effect.Parameters["radialBlurScaleFactor"];
}
///
/// Execute shaders and show result on screen, Start(..) must have been
/// called before and the scene should be rendered to sceneMapTexture.
///
public override void Show()
{
// Only apply post screen glow if texture is valid and effect is valid
if (sceneMapTexture == null ||
effect == null ||
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.
//Update: allow writing to alpha!
BaseGame.Device.BlendState = BlendStateAlphaWrite;
if (windowSize != null)
windowSize.SetValue(
new Vector2(sceneMapTexture.Width, sceneMapTexture.Height));
if (sceneMap != null)
sceneMap.SetValue(sceneMapTexture.XnaTexture);
RadialBlurScaleFactor =
// Warning: To big values will make the motion blur look to
// stepy (we see each step and thats not good). -0.02 should be max.
-(0.0025f + RacingGameManager.Player.Speed * 0.005f /
Player.DefaultMaxSpeed);
effect.CurrentTechnique = effect.Techniques["ScreenGlow20"];
// We must have exactly 5 passes!
if (effect.CurrentTechnique.Passes.Count != 5)
throw new InvalidOperationException(
"This shader should have exactly 5 passes!");
try
{
for (int pass = 0; pass < effect.CurrentTechnique.Passes.Count;
pass++)
{
if (pass == 0)
radialSceneMapTexture.SetRenderTarget();
else if (pass == 1)
downsampleMapTexture.SetRenderTarget();
else if (pass == 2)
blurMap1Texture.SetRenderTarget();
else if (pass == 3)
blurMap2Texture.SetRenderTarget();
else
{
BaseGame.ResetRenderTarget(true);
}
EffectPass effectPass = effect.CurrentTechnique.Passes[pass];
effectPass.Apply();
// For first effect we use radial blur, draw it with a grid
// to get cooler results (more blur at borders than in middle).
if (pass == 0)
VBScreenHelper.Render10x10Grid();
else
VBScreenHelper.Render();
if (pass == 0)
{
radialSceneMapTexture.Resolve();
if (radialSceneMap != null)
radialSceneMap.SetValue(radialSceneMapTexture.XnaTexture);
effectPass.Apply();
}
else if (pass == 1)
{
downsampleMapTexture.Resolve();
if (downsampleMap != null)
downsampleMap.SetValue(downsampleMapTexture.XnaTexture);
effectPass.Apply();
}
else if (pass == 2)
{
blurMap1Texture.Resolve();
if (blurMap1 != null)
blurMap1.SetValue(blurMap1Texture.XnaTexture);
effectPass.Apply();
}
else if (pass == 3)
{
blurMap2Texture.Resolve();
if (blurMap2 != null)
blurMap2.SetValue(blurMap2Texture.XnaTexture);
effectPass.Apply();
}
}
}
finally
{
// Restore z buffer state
BaseGame.Device.DepthStencilState = DepthStencilState.Default;
}
}
}
}