diff --git a/Blarg.GameFramework/Blarg.GameFramework.csproj b/Blarg.GameFramework/Blarg.GameFramework.csproj
index fbe2608..ebb1f38 100644
--- a/Blarg.GameFramework/Blarg.GameFramework.csproj
+++ b/Blarg.GameFramework/Blarg.GameFramework.csproj
@@ -151,6 +151,12 @@
+
+
+
+
+
+
@@ -168,6 +174,7 @@
+
diff --git a/Blarg.GameFramework/Graphics/ScreenEffects/DimEffect.cs b/Blarg.GameFramework/Graphics/ScreenEffects/DimEffect.cs
new file mode 100644
index 0000000..c7fb5e7
--- /dev/null
+++ b/Blarg.GameFramework/Graphics/ScreenEffects/DimEffect.cs
@@ -0,0 +1,31 @@
+using System;
+
+namespace Blarg.GameFramework.Graphics.ScreenEffects
+{
+ public class DimEffect : ScreenEffect
+ {
+ public static readonly Color DefaultDimColor = Color.Black;
+ public const float DefaultDimAlpha = 0.5f;
+
+ public Color Color;
+ public float Alpha;
+
+ public DimEffect()
+ {
+ Color = DefaultDimColor;
+ Alpha = DefaultDimAlpha;
+ }
+
+ public override void OnRender(float delta)
+ {
+ int width = Platform.GraphicsDevice.ViewContext.ViewportWidth;
+ int height = Platform.GraphicsDevice.ViewContext.ViewportHeight;
+
+ var texture = Platform.GraphicsDevice.GetSolidColorTexture(Color.White);
+ var color = Color;
+ color.A = Alpha;
+
+ //Platform.SpriteBatch.Render(texture, 0, 0, width, height, ref color);
+ }
+ }
+}
diff --git a/Blarg.GameFramework/Graphics/ScreenEffects/EffectInfo.cs b/Blarg.GameFramework/Graphics/ScreenEffects/EffectInfo.cs
new file mode 100644
index 0000000..80bfc2a
--- /dev/null
+++ b/Blarg.GameFramework/Graphics/ScreenEffects/EffectInfo.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Blarg.GameFramework.Graphics.ScreenEffects
+{
+ internal class EffectInfo
+ {
+ public readonly ScreenEffect Effect;
+ public bool IsLocal;
+
+ public EffectInfo(ScreenEffect effect, bool isLocal)
+ {
+ if (effect == null)
+ throw new ArgumentNullException("effect");
+
+ Effect = effect;
+ IsLocal = isLocal;
+ }
+ }
+}
diff --git a/Blarg.GameFramework/Graphics/ScreenEffects/FadeEffect.cs b/Blarg.GameFramework/Graphics/ScreenEffects/FadeEffect.cs
new file mode 100644
index 0000000..eb9494d
--- /dev/null
+++ b/Blarg.GameFramework/Graphics/ScreenEffects/FadeEffect.cs
@@ -0,0 +1,81 @@
+using System;
+
+namespace Blarg.GameFramework.Graphics.ScreenEffects
+{
+ public class FadeEffect : ScreenEffect
+ {
+ public const float DefaultFadeSpeed = 3.0f;
+
+ float _fadeSpeed;
+ bool _isFadingOut;
+ float _alpha;
+ Color _color;
+ float _fadeToAlpha;
+
+ public bool IsDoneFading { get; private set; }
+
+ public FadeEffect()
+ {
+ }
+
+ public void FadeOut(float toAlpha, Color color, float speed = DefaultFadeSpeed)
+ {
+ if (toAlpha < 0.0f || toAlpha > 1.0f)
+ throw new ArgumentOutOfRangeException("toAlpha");
+
+ _color = color;
+ _fadeSpeed = speed;
+ _isFadingOut = true;
+ _alpha = Color.AlphaTransparent;
+ _fadeToAlpha = toAlpha;
+ }
+
+ public void FadeIn(float toAlpha, Color color, float speed = DefaultFadeSpeed)
+ {
+ if (toAlpha < 0.0f || toAlpha > 1.0f)
+ throw new ArgumentOutOfRangeException("toAlpha");
+
+ _color = color;
+ _fadeSpeed = speed;
+ _isFadingOut = false;
+ _alpha = Color.AlphaOpaque;
+ _fadeToAlpha = toAlpha;
+ }
+
+ public override void OnRender(float delta)
+ {
+ int width = Platform.GraphicsDevice.ViewContext.ViewportWidth;
+ int height = Platform.GraphicsDevice.ViewContext.ViewportHeight;
+
+ var texture = Platform.GraphicsDevice.GetSolidColorTexture(Color.White);
+ _color.A = _alpha;
+
+ //Platform.SpriteBatch.Render(texture, 0, 0, width, height, ref _color);
+ }
+
+ public override void OnUpdate(float delta)
+ {
+ if (IsDoneFading)
+ return;
+
+ if (_isFadingOut)
+ {
+ _alpha += (delta + _fadeSpeed);
+ if (_alpha >= _fadeToAlpha)
+ {
+ _alpha = _fadeToAlpha;
+ IsDoneFading = true;
+ }
+ }
+ else
+ {
+ _alpha -= (delta + _fadeSpeed);
+ if (_alpha < _fadeToAlpha)
+ {
+ _alpha = _fadeToAlpha;
+ IsDoneFading = true;
+ }
+ }
+ }
+ }
+}
diff --git a/Blarg.GameFramework/Graphics/ScreenEffects/FlashEffect.cs b/Blarg.GameFramework/Graphics/ScreenEffects/FlashEffect.cs
new file mode 100644
index 0000000..cc6fb9a
--- /dev/null
+++ b/Blarg.GameFramework/Graphics/ScreenEffects/FlashEffect.cs
@@ -0,0 +1,61 @@
+using System;
+
+namespace Blarg.GameFramework.Graphics.ScreenEffects
+{
+ public class FlashEffect : ScreenEffect
+ {
+ public const float DefaultFlashSpeed = 16.0f;
+ public const float DefaultMaxIntensity = 1.0f;
+
+ public float FlashInSpeed;
+ public float FlashOutSpeed;
+ public float MaximumIntensity;
+ public Color Color;
+
+ bool _isFlashingIn;
+ float _alpha;
+
+ public FlashEffect()
+ {
+ _isFlashingIn = true;
+ FlashInSpeed = DefaultFlashSpeed;
+ FlashOutSpeed = DefaultFlashSpeed;
+ MaximumIntensity = DefaultMaxIntensity;
+ Color = Color.White;
+ }
+
+ public override void OnRender(float delta)
+ {
+ int width = Platform.GraphicsDevice.ViewContext.ViewportWidth;
+ int height = Platform.GraphicsDevice.ViewContext.ViewportHeight;
+
+ var texture = Platform.GraphicsDevice.GetSolidColorTexture(Color.White);
+ var color = Color;
+ color.A = _alpha;
+
+ //Platform.SpriteBatch.Render(texture, 0, 0, width, height, ref color);
+ }
+
+ public override void OnUpdate(float delta)
+ {
+ if (_isFlashingIn)
+ {
+ _alpha += (delta * FlashInSpeed);
+ if (_alpha >= MaximumIntensity)
+ {
+ _alpha = MaximumIntensity;
+ _isFlashingIn = false;
+ }
+ }
+ else
+ {
+ _alpha -= (delta * FlashOutSpeed);
+ if (_alpha < 0.0f)
+ _alpha = 0.0f;
+ }
+
+ if (_alpha == 0.0f && _isFlashingIn == false)
+ IsActive = false;
+ }
+ }
+}
diff --git a/Blarg.GameFramework/Graphics/ScreenEffects/ScreenEffect.cs b/Blarg.GameFramework/Graphics/ScreenEffects/ScreenEffect.cs
new file mode 100644
index 0000000..276603e
--- /dev/null
+++ b/Blarg.GameFramework/Graphics/ScreenEffects/ScreenEffect.cs
@@ -0,0 +1,65 @@
+using System;
+
+namespace Blarg.GameFramework.Graphics.ScreenEffects
+{
+ public abstract class ScreenEffect : IDisposable
+ {
+ public bool IsActive;
+
+ public ScreenEffect()
+ {
+ }
+
+ #region Events
+
+ public virtual void OnAdd()
+ {
+ }
+
+ public virtual void OnRemove()
+ {
+ }
+
+ public virtual void OnAppGainFocus()
+ {
+ }
+
+ public virtual void OnAppLostFocus()
+ {
+ }
+
+ public virtual void OnAppPause()
+ {
+ }
+
+ public virtual void OnAppResume()
+ {
+ }
+
+ public virtual void OnLostContext()
+ {
+ }
+
+ public virtual void OnNewContext()
+ {
+ }
+
+ public virtual void OnRender(float delta)
+ {
+ }
+
+ public virtual void OnResize()
+ {
+ }
+
+ public virtual void OnUpdate(float delta)
+ {
+ }
+
+ #endregion
+
+ public virtual void Dispose()
+ {
+ }
+ }
+}
diff --git a/Blarg.GameFramework/Graphics/ScreenEffects/ScreenEffectManager.cs b/Blarg.GameFramework/Graphics/ScreenEffects/ScreenEffectManager.cs
new file mode 100644
index 0000000..74bacc2
--- /dev/null
+++ b/Blarg.GameFramework/Graphics/ScreenEffects/ScreenEffectManager.cs
@@ -0,0 +1,206 @@
+using System;
+using System.Collections.Generic;
+
+namespace Blarg.GameFramework.Graphics.ScreenEffects
+{
+ public class EffectManager : IDisposable
+ {
+ LinkedList _effects;
+ int _numLocalEffects;
+ int _numGlobalEffects;
+
+ public EffectManager()
+ {
+ _effects = new LinkedList();
+ _numLocalEffects = 0;
+ _numGlobalEffects = 0;
+ }
+
+ #region Get / Add / Remove
+
+ public T Get() where T : ScreenEffect
+ {
+ var type = typeof(T);
+ var node = GetNodeFor(type);
+ if (node == null)
+ return null;
+ else
+ return (T)node.Value.Effect;
+ }
+
+ public T Add(bool isLocalEffect = true) where T : ScreenEffect
+ {
+ var type = typeof(T);
+ if (GetNodeFor(type) != null)
+ throw new InvalidOperationException("Cannot add an effect of the same type as an existing effect already being managed.");
+
+ T effect = (T)Activator.CreateInstance(type);
+ var effectInfo = new EffectInfo(effect, isLocalEffect);
+ Add(effectInfo);
+
+ return effect;
+ }
+
+ public void Remove() where T : ScreenEffect
+ {
+ var type = typeof(T);
+ var node = GetNodeFor(type);
+ if (node != null)
+ Remove(node);
+ }
+
+ public void RemoveAll()
+ {
+ while (_effects.Count > 0)
+ Remove(_effects.First);
+ }
+
+ private void Add(EffectInfo effectInfo)
+ {
+ if (effectInfo == null)
+ throw new ArgumentNullException("effectInfo");
+
+ _effects.AddLast(effectInfo);
+ effectInfo.Effect.OnAdd();
+
+ if (effectInfo.IsLocal)
+ ++_numLocalEffects;
+ else
+ ++_numGlobalEffects;
+ }
+
+ private void Remove(LinkedListNode node)
+ {
+ if (node == null)
+ throw new ArgumentNullException("node");
+
+ var effectInfo = node.Value;
+ if (effectInfo.IsLocal)
+ --_numLocalEffects;
+ else
+ --_numGlobalEffects;
+
+ effectInfo.Effect.OnRemove();
+ effectInfo.Effect.Dispose();
+ _effects.Remove(node);
+ }
+
+ #endregion
+
+ #region Events
+
+ public void OnAppGainFocus()
+ {
+ for (var node = _effects.First; node != null; node = node.Next)
+ node.Value.Effect.OnAppGainFocus();
+ }
+
+ public void OnAppLostFocus()
+ {
+ for (var node = _effects.First; node != null; node = node.Next)
+ node.Value.Effect.OnAppLostFocus();
+ }
+
+ public void OnAppPause()
+ {
+ for (var node = _effects.First; node != null; node = node.Next)
+ node.Value.Effect.OnAppPause();
+ }
+
+ public void OnAppResume()
+ {
+ for (var node = _effects.First; node != null; node = node.Next)
+ node.Value.Effect.OnAppResume();
+ }
+
+ public void OnLostContext()
+ {
+ for (var node = _effects.First; node != null; node = node.Next)
+ node.Value.Effect.OnLostContext();
+ }
+
+ public void OnNewContext()
+ {
+ for (var node = _effects.First; node != null; node = node.Next)
+ node.Value.Effect.OnNewContext();
+ }
+
+ public void OnRenderLocal(float delta)
+ {
+ if (_numLocalEffects == 0)
+ return;
+
+ for (var node = _effects.First; node != null; node = node.Next)
+ {
+ if (node.Value.IsLocal)
+ node.Value.Effect.OnRender(delta);
+ }
+ }
+
+ public void OnRenderGlobal(float delta)
+ {
+ if (_numGlobalEffects == 0)
+ return;
+
+ for (var node = _effects.First; node != null; node = node.Next)
+ {
+ if (!node.Value.IsLocal)
+ node.Value.Effect.OnRender(delta);
+ }
+ }
+
+ public void OnResize()
+ {
+ for (var node = _effects.First; node != null; node = node.Next)
+ node.Value.Effect.OnResize();
+ }
+
+ public void OnUpdate(float delta)
+ {
+ var node = _effects.First;
+ while (node != null)
+ {
+ var effect = node.Value.Effect;
+ if (!effect.IsActive)
+ {
+ var next = node.Next;
+ Remove(node);
+ node = next;
+ }
+ else
+ {
+ effect.OnUpdate(delta);
+ node = node.Next;
+ }
+ }
+ }
+
+ #endregion
+
+ #region Misc
+
+ private LinkedListNode GetNodeFor(Type effectType)
+ {
+ if (effectType == null)
+ throw new ArgumentNullException("effectType");
+
+ for (var node = _effects.First; node != null; node = node.Next)
+ {
+ if (node.Value.Effect.GetType() == effectType)
+ return node;
+ }
+ return null;
+ }
+
+ #endregion
+
+ public void Dispose()
+ {
+ if (_effects == null)
+ return;
+
+ RemoveAll();
+ _effects = null;
+ }
+ }
+}