From a056127f7c5f8dc95d99754aa0c038d5aaef3c58 Mon Sep 17 00:00:00 2001 From: Simon Holmberg Date: Sat, 29 Sep 2012 22:04:29 +0200 Subject: [PATCH] Krypton lighting engine http://krypton.codeplex.com/ --- DepthsBelow.sln | 15 +- Krypton v2.0/Krypton.sln | 38 ++ Krypton v2.0/Krypton/Common/BoundingRect.cs | 278 ++++++++++ Krypton v2.0/Krypton/Krypton.csproj | 98 ++++ Krypton v2.0/Krypton/KryptonEngine.cs | 423 ++++++++++++++++ Krypton v2.0/Krypton/KryptonRenderHelper.cs | 476 +++++++++++++++++ Krypton v2.0/Krypton/LightTextureBuilder.cs | 89 ++++ Krypton v2.0/Krypton/Lights/ILight2D.cs | 17 + Krypton v2.0/Krypton/Lights/Light2D.cs | 192 +++++++ .../Krypton/Properties/AssemblyInfo.cs | 34 ++ Krypton v2.0/Krypton/ShadowHull.cs | 241 +++++++++ Krypton v2.0/Krypton/ShadowHullPoint.cs | 36 ++ Krypton v2.0/Krypton/ShadowHullVertex.cs | 60 +++ .../KryptonTestbed/KryptonTestbed/Game.ico | Bin 0 -> 4286 bytes .../KryptonTestbed/GameKryptonDemo.cs | 245 +++++++++ .../KryptonTestbed/GameThumbnail.png | Bin 0 -> 5734 bytes .../KryptonTestbed/KryptonTestbed.csproj | 153 ++++++ .../KryptonTestbed/KryptonTestbed/Program.cs | 21 + .../KryptonTestbed/Properties/AssemblyInfo.cs | 34 ++ .../KryptonTestbedContent/KryptonEffect.fx | 478 ++++++++++++++++++ .../KryptonTestbedContent.contentproj | 50 ++ 21 files changed, 2977 insertions(+), 1 deletion(-) create mode 100755 Krypton v2.0/Krypton.sln create mode 100755 Krypton v2.0/Krypton/Common/BoundingRect.cs create mode 100755 Krypton v2.0/Krypton/Krypton.csproj create mode 100755 Krypton v2.0/Krypton/KryptonEngine.cs create mode 100755 Krypton v2.0/Krypton/KryptonRenderHelper.cs create mode 100755 Krypton v2.0/Krypton/LightTextureBuilder.cs create mode 100755 Krypton v2.0/Krypton/Lights/ILight2D.cs create mode 100755 Krypton v2.0/Krypton/Lights/Light2D.cs create mode 100755 Krypton v2.0/Krypton/Properties/AssemblyInfo.cs create mode 100755 Krypton v2.0/Krypton/ShadowHull.cs create mode 100755 Krypton v2.0/Krypton/ShadowHullPoint.cs create mode 100755 Krypton v2.0/Krypton/ShadowHullVertex.cs create mode 100755 Krypton v2.0/KryptonTestbed/KryptonTestbed/Game.ico create mode 100755 Krypton v2.0/KryptonTestbed/KryptonTestbed/GameKryptonDemo.cs create mode 100755 Krypton v2.0/KryptonTestbed/KryptonTestbed/GameThumbnail.png create mode 100755 Krypton v2.0/KryptonTestbed/KryptonTestbed/KryptonTestbed.csproj create mode 100755 Krypton v2.0/KryptonTestbed/KryptonTestbed/Program.cs create mode 100755 Krypton v2.0/KryptonTestbed/KryptonTestbed/Properties/AssemblyInfo.cs create mode 100755 Krypton v2.0/KryptonTestbed/KryptonTestbedContent/KryptonEffect.fx create mode 100755 Krypton v2.0/KryptonTestbed/KryptonTestbedContent/KryptonTestbedContent.contentproj diff --git a/DepthsBelow.sln b/DepthsBelow.sln index 73818fa..176dd07 100644 --- a/DepthsBelow.sln +++ b/DepthsBelow.sln @@ -13,6 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AStar", "AStar\AStar.csproj EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libraries", "Libraries", "{FF7D4CEE-291C-4F85-9630-977446A466D3}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Krypton", "Krypton v2.0\Krypton\Krypton.csproj", "{B1BFCB2A-C001-4DAC-BA7D-B68BF28757F3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -69,12 +71,23 @@ Global {CD3F949D-54AA-4D38-99DB-92905A375D84}.Release|Mixed Platforms.Build.0 = Release|x86 {CD3F949D-54AA-4D38-99DB-92905A375D84}.Release|x86.ActiveCfg = Release|x86 {CD3F949D-54AA-4D38-99DB-92905A375D84}.Release|x86.Build.0 = Release|x86 + {B1BFCB2A-C001-4DAC-BA7D-B68BF28757F3}.Debug|Any CPU.ActiveCfg = Debug|x86 + {B1BFCB2A-C001-4DAC-BA7D-B68BF28757F3}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {B1BFCB2A-C001-4DAC-BA7D-B68BF28757F3}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {B1BFCB2A-C001-4DAC-BA7D-B68BF28757F3}.Debug|x86.ActiveCfg = Debug|x86 + {B1BFCB2A-C001-4DAC-BA7D-B68BF28757F3}.Debug|x86.Build.0 = Debug|x86 + {B1BFCB2A-C001-4DAC-BA7D-B68BF28757F3}.Release|Any CPU.ActiveCfg = Release|x86 + {B1BFCB2A-C001-4DAC-BA7D-B68BF28757F3}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {B1BFCB2A-C001-4DAC-BA7D-B68BF28757F3}.Release|Mixed Platforms.Build.0 = Release|x86 + {B1BFCB2A-C001-4DAC-BA7D-B68BF28757F3}.Release|x86.ActiveCfg = Release|x86 + {B1BFCB2A-C001-4DAC-BA7D-B68BF28757F3}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {EC3F6988-459C-4783-89E9-F34C0CC731C7} = {FF7D4CEE-291C-4F85-9630-977446A466D3} {CD3F949D-54AA-4D38-99DB-92905A375D84} = {FF7D4CEE-291C-4F85-9630-977446A466D3} + {EC3F6988-459C-4783-89E9-F34C0CC731C7} = {FF7D4CEE-291C-4F85-9630-977446A466D3} + {B1BFCB2A-C001-4DAC-BA7D-B68BF28757F3} = {FF7D4CEE-291C-4F85-9630-977446A466D3} EndGlobalSection EndGlobal diff --git a/Krypton v2.0/Krypton.sln b/Krypton v2.0/Krypton.sln new file mode 100755 index 0000000..db89da7 --- /dev/null +++ b/Krypton v2.0/Krypton.sln @@ -0,0 +1,38 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Krypton", "Krypton\Krypton.csproj", "{B1BFCB2A-C001-4DAC-BA7D-B68BF28757F3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KryptonTestbed", "KryptonTestbed\KryptonTestbed\KryptonTestbed.csproj", "{E9787BEE-7290-4C74-B919-79DC70AABE87}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KryptonTestbedContent", "KryptonTestbed\KryptonTestbedContent\KryptonTestbedContent.contentproj", "{EA878F1A-4714-4377-8E6A-4947ACFF386A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B1BFCB2A-C001-4DAC-BA7D-B68BF28757F3}.Debug|Any CPU.ActiveCfg = Debug|x86 + {B1BFCB2A-C001-4DAC-BA7D-B68BF28757F3}.Debug|x86.ActiveCfg = Debug|x86 + {B1BFCB2A-C001-4DAC-BA7D-B68BF28757F3}.Debug|x86.Build.0 = Debug|x86 + {B1BFCB2A-C001-4DAC-BA7D-B68BF28757F3}.Release|Any CPU.ActiveCfg = Release|x86 + {B1BFCB2A-C001-4DAC-BA7D-B68BF28757F3}.Release|x86.ActiveCfg = Release|x86 + {B1BFCB2A-C001-4DAC-BA7D-B68BF28757F3}.Release|x86.Build.0 = Release|x86 + {E9787BEE-7290-4C74-B919-79DC70AABE87}.Debug|Any CPU.ActiveCfg = Debug|x86 + {E9787BEE-7290-4C74-B919-79DC70AABE87}.Debug|x86.ActiveCfg = Debug|x86 + {E9787BEE-7290-4C74-B919-79DC70AABE87}.Debug|x86.Build.0 = Debug|x86 + {E9787BEE-7290-4C74-B919-79DC70AABE87}.Release|Any CPU.ActiveCfg = Release|x86 + {E9787BEE-7290-4C74-B919-79DC70AABE87}.Release|x86.ActiveCfg = Release|x86 + {E9787BEE-7290-4C74-B919-79DC70AABE87}.Release|x86.Build.0 = Release|x86 + {EA878F1A-4714-4377-8E6A-4947ACFF386A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EA878F1A-4714-4377-8E6A-4947ACFF386A}.Debug|x86.ActiveCfg = Debug|Any CPU + {EA878F1A-4714-4377-8E6A-4947ACFF386A}.Release|Any CPU.ActiveCfg = Debug|Any CPU + {EA878F1A-4714-4377-8E6A-4947ACFF386A}.Release|x86.ActiveCfg = Debug|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Krypton v2.0/Krypton/Common/BoundingRect.cs b/Krypton v2.0/Krypton/Common/BoundingRect.cs new file mode 100755 index 0000000..6443c7f --- /dev/null +++ b/Krypton v2.0/Krypton/Common/BoundingRect.cs @@ -0,0 +1,278 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using Microsoft.Xna.Framework; +using System.Globalization; +using System.Runtime.InteropServices; + +namespace Krypton.Common +{ + /// + /// Much like Rectangle, but stored as two Vector2s + /// + public struct BoundingRect + { + public Vector2 Min; + public Vector2 Max; + + public float Left { get { return this.Min.X; } } + public float Right { get { return this.Max.X; } } + public float Top { get { return this.Max.Y; } } + public float Bottom { get { return this.Min.Y; } } + + public float Width { get { return this.Max.X - this.Min.X; } } + public float Height { get { return this.Max.Y - this.Min.Y; } } + + private static BoundingRect mEmpty; + private static BoundingRect mMinMax; + + static BoundingRect() + { + BoundingRect.mEmpty = new BoundingRect(); + BoundingRect.mMinMax = new BoundingRect(Vector2.One * float.MinValue, Vector2.One * float.MaxValue); + } + + public Vector2 Center + { + get { return (this.Min + this.Max) / 2; } + } + + public static BoundingRect Empty + { + get { return BoundingRect.mEmpty; } + } + + + public static BoundingRect MinMax + { + get { return BoundingRect.mMinMax; } + } + + public bool IsZero + { + get + { + return + (this.Min.X == 0) && + (this.Min.Y == 0) && + (this.Max.X == 0) && + (this.Max.Y == 0); + } + } + + public BoundingRect(float x, float y, float width, float height) + { + this.Min.X = x; + this.Min.Y = y; + this.Max.X = x + width; + this.Max.Y = y + height; + } + + public BoundingRect(Vector2 min, Vector2 max) + { + this.Min = min; + this.Max = max; + } + + public bool Contains(float x, float y) + { + return + (this.Min.X <= x) && + (this.Min.Y <= y) && + (this.Max.X >= x) && + (this.Max.Y >= y); + } + + public bool Contains(Vector2 vector) + { + return + (this.Min.X <= vector.X) && + (this.Min.Y <= vector.Y) && + (this.Max.X >= vector.X) && + (this.Max.Y >= vector.Y); + } + + public void Contains(ref Vector2 rect, out bool result) + { + result = + (this.Min.X <= rect.X) && + (this.Min.Y <= rect.Y) && + (this.Max.X >= rect.X) && + (this.Max.Y >= rect.Y); + } + + public bool Contains(BoundingRect rect) + { + return + (this.Min.X <= rect.Min.X) && + (this.Min.Y <= rect.Min.Y) && + (this.Max.X >= rect.Max.X) && + (this.Max.Y >= rect.Max.Y); + } + + public void Contains(ref BoundingRect rect, out bool result) + { + result = + (this.Min.X <= rect.Min.X) && + (this.Min.Y <= rect.Min.Y) && + (this.Max.X >= rect.Max.X) && + (this.Max.Y >= rect.Max.Y) ; + } + + public bool Intersects(BoundingRect rect) + { + return + (this.Min.X < rect.Max.X) && + (this.Min.Y < rect.Max.Y) && + (this.Max.X > rect.Min.X) && + (this.Max.Y > rect.Min.Y); + } + + public void Intersects(ref BoundingRect rect, out bool result) + { + result = + (this.Min.X < rect.Max.X) && + (this.Min.Y < rect.Max.Y) && + (this.Max.X > rect.Min.X) && + (this.Max.Y > rect.Min.Y); + } + + public static BoundingRect Intersect(BoundingRect rect1, BoundingRect rect2) + { + BoundingRect result; + + float num8 = rect1.Max.X; + float num7 = rect2.Max.X; + float num6 = rect1.Max.Y; + float num5 = rect2.Max.Y; + float num2 = (rect1.Min.X > rect2.Min.X) ? rect1.Min.X : rect2.Min.X; + float num = (rect1.Min.Y > rect2.Min.Y) ? rect1.Min.Y : rect2.Min.Y; + float num4 = (num8 < num7) ? num8 : num7; + float num3 = (num6 < num5) ? num6 : num5; + + if ((num4 > num2) && (num3 > num)) + { + result.Min.X = num2; + result.Min.Y = num; + result.Max.X = num4; + result.Max.Y = num3; + + return result; + } + + result.Min.X = 0; + result.Min.Y = 0; + result.Max.X = 0; + result.Max.Y = 0; + + return result; + } + + public static void Intersect(ref BoundingRect rect1, ref BoundingRect rect2, out BoundingRect result) + { + float num8 = rect1.Max.X; + float num7 = rect2.Max.X; + float num6 = rect1.Max.Y; + float num5 = rect2.Max.Y; + float num2 = (rect1.Min.X > rect2.Min.X) ? rect1.Min.X : rect2.Min.X; + float num = (rect1.Min.Y > rect2.Min.Y) ? rect1.Min.Y : rect2.Min.Y; + float num4 = (num8 < num7) ? num8 : num7; + float num3 = (num6 < num5) ? num6 : num5; + + if ((num4 > num2) && (num3 > num)) + { + result.Min.X = num2; + result.Min.Y = num; + result.Max.X = num4; + result.Max.Y = num3; + } + + result.Min.X = 0; + result.Min.Y = 0; + result.Max.X = 0; + result.Max.Y = 0; + } + + public static BoundingRect Union(BoundingRect rect1, BoundingRect rect2) + { + BoundingRect result; + + float num6 = rect1.Max.X; + float num5 = rect2.Max.X; + float num4 = rect1.Max.Y; + float num3 = rect2.Max.Y; + float num2 = (rect1.Min.X < rect2.Min.X) ? rect1.Min.X : rect2.Min.X; + float num = (rect1.Min.Y < rect2.Min.Y) ? rect1.Min.Y : rect2.Min.Y; + float num8 = (num6 > num5) ? num6 : num5; + float num7 = (num4 > num3) ? num4 : num3; + + result.Min.X = num2; + result.Min.Y = num; + result.Max.X = num8; + result.Max.Y = num7; + + return result; + } + + public static void Union(ref BoundingRect rect1, ref BoundingRect rect2, out BoundingRect result) + { + float num6 = rect1.Max.X; + float num5 = rect2.Max.X; + float num4 = rect1.Max.Y; + float num3 = rect2.Max.Y; + float num2 = (rect1.Min.X < rect2.Min.X) ? rect1.Min.X : rect2.Min.X; + float num = (rect1.Min.Y < rect2.Min.Y) ? rect1.Min.Y : rect2.Min.Y; + float num8 = (num6 > num5) ? num6 : num5; + float num7 = (num4 > num3) ? num4 : num3; + + result.Min.X = num2; + result.Min.Y = num; + result.Max.X = num8; + result.Max.Y = num7; + } + + public bool Equals(BoundingRect other) + { + return + (this.Min.X == other.Min.X) && + (this.Min.Y == other.Min.Y) && + (this.Max.X == other.Max.X) && + (this.Max.Y == other.Max.Y); + } + + public override int GetHashCode() + { + return this.Min.GetHashCode() + this.Max.GetHashCode(); + } + + public static bool operator ==(BoundingRect a, BoundingRect b) + { + return + (a.Min.X == b.Min.X) && + (a.Min.Y == b.Min.Y) && + (a.Max.X == b.Max.X) && + (a.Max.Y == b.Max.Y); + } + + public static bool operator !=(BoundingRect a, BoundingRect b) + { + return + (a.Min.X != b.Min.X) || + (a.Min.Y != b.Min.Y) || + (a.Max.X != b.Max.X) || + (a.Max.Y != b.Max.Y); + } + + public override bool Equals(object obj) + { + if (obj is BoundingRect) + { + return this == (BoundingRect)obj; + } + + return false; + } + } +} diff --git a/Krypton v2.0/Krypton/Krypton.csproj b/Krypton v2.0/Krypton/Krypton.csproj new file mode 100755 index 0000000..0e1209d --- /dev/null +++ b/Krypton v2.0/Krypton/Krypton.csproj @@ -0,0 +1,98 @@ + + + + {B1BFCB2A-C001-4DAC-BA7D-B68BF28757F3} + {6D335F3A-9D43-41b4-9D22-F6F17C4BE596};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Debug + x86 + Library + Properties + Krypton + Krypton + v4.0 + Client + v4.0 + Windows + HiDef + f22a3b67-7b26-4bcf-9fa4-831713f618f0 + Library + + + + + + + + + + + true + full + false + bin\x86\Debug + DEBUG;TRACE;WINDOWS + prompt + 4 + true + false + x86 + false + + + pdbonly + true + bin\x86\Release + TRACE;WINDOWS + prompt + 4 + true + false + x86 + true + + + + + + + False + + + False + + + False + + + 4.0 + False + + + 4.0 + False + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Krypton v2.0/Krypton/KryptonEngine.cs b/Krypton v2.0/Krypton/KryptonEngine.cs new file mode 100755 index 0000000..1bc77bc --- /dev/null +++ b/Krypton v2.0/Krypton/KryptonEngine.cs @@ -0,0 +1,423 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Audio; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.GamerServices; +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework.Input; +using Microsoft.Xna.Framework.Media; + +using Krypton.Lights; +using Krypton.Common; + + +namespace Krypton +{ + public enum LightMapSize + { + Full = 1, + Fourth = 2, + Eighth = 4, + } + + /// + /// A GPU-based 2D lighting engine + /// + public class KryptonEngine : DrawableGameComponent + { + // The Krypton Effect + private string mEffectAssetName; + private Effect mEffect; + private CullMode mCullMode = CullMode.CullCounterClockwiseFace; + + // The goods + private List mHulls = new List(); + private List mLights = new List(); + + // World View Projection matrix, and it's min and max view bounds + private Matrix mWVP = Matrix.Identity; + private bool mSpriteBatchCompatabilityEnabled = false; + private BoundingRect mBounds = BoundingRect.MinMax; + + // Blur + private float mBluriness = 0.25f; + private RenderTarget2D mMapBlur; + + // Light maps + private RenderTarget2D mMap; + private Color mAmbientColor = new Color(35,35,35); + private LightMapSize mLightMapSize = LightMapSize.Full; + + /// + /// Krypton's render helper. It helps render. It also needs to be re-written. + /// + public KryptonRenderHelper RenderHelper { get; private set; } + + /// + /// Gets or sets a value indicating how Krypton should cull geometry. The default value is CullMode.CounterClockwise + /// + public CullMode CullMode + { + get { return this.mCullMode; } + set { this.mCullMode = value; } + } + + /// + /// The collection of lights krypton uses to render shadows + /// + public List Lights { get { return this.mLights; } } + + /// + /// The collection of hulls krypton uses to render shadows + /// + public List Hulls { get { return this.mHulls; } } + + /// + /// Gets or sets the matrix used to draw the light map. This should match your scene's matrix. + /// + public Matrix Matrix + { + get { return this.mWVP; } + set + { + if (this.mWVP != value) + { + this.mWVP = value; + + // This is totally ghetto, but it works for now. :) + // Compute the world-space bounds of the given matrix + var inverse = Matrix.Invert(value); + + var v1 = Vector2.Transform(new Vector2(1, 1), inverse); + var v2 = Vector2.Transform(new Vector2(1, -1), inverse); + var v3 = Vector2.Transform(new Vector2(-1, -1), inverse); + var v4 = Vector2.Transform(new Vector2(-1, 1), inverse); + + this.mBounds.Min = v1; + this.mBounds.Min = Vector2.Min(this.mBounds.Min, v2); + this.mBounds.Min = Vector2.Min(this.mBounds.Min, v3); + this.mBounds.Min = Vector2.Min(this.mBounds.Min, v4); + + this.mBounds.Max = v1; + this.mBounds.Max = Vector2.Max(this.mBounds.Max, v2); + this.mBounds.Max = Vector2.Max(this.mBounds.Max, v3); + this.mBounds.Max = Vector2.Max(this.mBounds.Max, v4); + + this.mBounds = BoundingRect.MinMax; + } + } + } + + /// + /// Gets or sets a value indicating weither or not to use SpriteBatch's matrix when drawing lightmaps + /// + public bool SpriteBatchCompatablityEnabled + { + get { return this.mSpriteBatchCompatabilityEnabled; } + set { this.mSpriteBatchCompatabilityEnabled = value; } + } + + /// + /// Ambient color of the light map. Lights + AmbientColor = Final + /// + public Color AmbientColor + { + get { return this.mAmbientColor; } + set { this.mAmbientColor = value; } + } + + /// + /// Gets or sets the value used to determine light map size + /// + public LightMapSize LightMapSize + { + get { return this.mLightMapSize; } + set + { + if (this.mLightMapSize != value) + { + this.mLightMapSize = value; + this.DisposeRenderTargets(); + this.CreateRenderTargets(); + } + } + } + + /// + /// Gets or sets a value indicating how much to blur the final light map. If the value is zero, the lightmap will not be blurred + /// + public float Bluriness + { + get { return this.mBluriness; } + set { this.mBluriness = Math.Max(0, value); } + } + + /// + /// Constructs a new instance of krypton + /// + /// Your game object + /// The asset name of Krypton's effect file, which must be included in your content project + public KryptonEngine(Game game, string effectAssetName) + : base(game) + { + this.mEffectAssetName = effectAssetName; + } + + /// + /// Initializes Krpyton, and hooks itself to the graphics device + /// + public override void Initialize() + { + base.Initialize(); + + this.GraphicsDevice.DeviceReset += new EventHandler(GraphicsDevice_DeviceReset); + } + + /// + /// Resets kryptons graphics device resources + /// + private void GraphicsDevice_DeviceReset(object sender, EventArgs e) + { + this.DisposeRenderTargets(); + this.CreateRenderTargets(); + } + + /// + /// Load's the graphics related content required to draw light maps + /// + protected override void LoadContent() + { + // This needs to better handle content loading... + // if the window is resized, Krypton needs to notice. + this.mEffect = this.Game.Content.Load(this.mEffectAssetName); + this.RenderHelper = new KryptonRenderHelper(this.GraphicsDevice, this.mEffect); + + this.CreateRenderTargets(); + } + + /// + /// Unload's the graphics content required to draw light maps + /// + protected override void UnloadContent() + { + this.DisposeRenderTargets(); + } + + /// + /// Creates render targets + /// + private void CreateRenderTargets() + { + var targetWidth = GraphicsDevice.Viewport.Width / (int)(this.mLightMapSize); + var targetHeight = GraphicsDevice.Viewport.Height / (int)(this.mLightMapSize); + + this.mMap = new RenderTarget2D(GraphicsDevice, targetWidth, targetHeight, false, SurfaceFormat.Color, DepthFormat.Depth24Stencil8, 0, RenderTargetUsage.PlatformContents); + this.mMapBlur = new RenderTarget2D(GraphicsDevice, targetWidth, targetHeight, false, SurfaceFormat.Color, DepthFormat.Depth24Stencil8, 0, RenderTargetUsage.PlatformContents); + } + + /// + /// Disposes of render targets + /// + private void DisposeRenderTargets() + { + KryptonEngine.TryDispose(this.mMap); + KryptonEngine.TryDispose(this.mMapBlur); + } + + /// + /// Attempts to dispose of disposable objects, and assigns them a null value afterward + /// + /// + private static void TryDispose(IDisposable obj) + { + if (obj != null) + { + obj.Dispose(); + obj = null; + } + } + + /// + /// Draws the light map to the current render target + /// + /// N/A - Required + public override void Draw(GameTime gameTime) + { + this.LightMapPresent(); + } + + /// + /// Prepares the light map to be drawn (pre-render) + /// + public void LightMapPrepare() + { + // Prepare and set the matrix + var viewWidth = this.GraphicsDevice.ScissorRectangle.Width; + var viewHeight = this.GraphicsDevice.ScissorRectangle.Height; + + // Prepare the matrix with optional settings and assign it to an effect parameter + Matrix lightMapMatrix = this.LightmapMatrixGet(); + this.mEffect.Parameters["Matrix"].SetValue(lightMapMatrix); + + // Obtain the original rendering states + var originalRenderTargets = this.GraphicsDevice.GetRenderTargets(); + + // Set and clear the target + this.GraphicsDevice.SetRenderTarget(this.mMap); + this.GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.Stencil, this.mAmbientColor, 0, 1); + + // Make sure we're culling the right way! + this.GraphicsDevice.RasterizerState = KryptonEngine.RasterizerStateGetFromCullMode(this.mCullMode); + + // put the render target's size into a more friendly format + var targetSize = new Vector2(this.mMap.Width, this.mMap.Height); + + // Render Light Maps + foreach (var light in this.mLights) + { + // Loop through each light within the view frustum + if (light.Bounds.Intersects(this.mBounds)) + { + // Clear the stencil and set the scissor rect (because we're stretching geometry past the light's reach) + this.GraphicsDevice.Clear(ClearOptions.Stencil, Color.Black, 0, 1); + this.GraphicsDevice.ScissorRectangle = KryptonEngine.ScissorRectCreateForLight(light, lightMapMatrix, targetSize); + + // Draw the light! + light.Draw(this.RenderHelper, this.mHulls); + } + } + + if (this.mBluriness > 0) + { + // Blur the shadow map horizontally to the blur target + this.GraphicsDevice.SetRenderTarget(this.mMapBlur); + this.RenderHelper.BlurTextureToTarget(this.mMap, LightMapSize.Full, BlurTechnique.Horizontal, this.mBluriness); + + // Blur the shadow map vertically back to the final map + this.GraphicsDevice.SetRenderTarget(this.mMap); + this.RenderHelper.BlurTextureToTarget(this.mMapBlur, LightMapSize.Full, BlurTechnique.Vertical, this.mBluriness); + } + + // Reset to the original rendering states + this.GraphicsDevice.SetRenderTargets(originalRenderTargets); + } + + /// + /// Returns the final, modified matrix used to render the lightmap. + /// + /// + private Matrix LightmapMatrixGet() + { + if (this.mSpriteBatchCompatabilityEnabled) + { + float xScale = (this.GraphicsDevice.Viewport.Width > 0) ? (1f / this.GraphicsDevice.Viewport.Width) : 0f; + float yScale = (this.GraphicsDevice.Viewport.Height > 0) ? (-1f / this.GraphicsDevice.Viewport.Height) : 0f; + + // This is the default matrix used to render sprites via spritebatch + var matrixSpriteBatch = new Matrix() + { + M11 = xScale * 2f, + M22 = yScale * 2f, + M33 = 1f, + M44 = 1f, + M41 = -1f - xScale, + M42 = 1f - yScale, + }; + + // Return krypton's matrix, compensated for use with SpriteBatch + return this.mWVP * matrixSpriteBatch; + } + else + { + // Return krypton's matrix + return this.mWVP; + } + } + + /// + /// Gets a pixel-space rectangle which contains the light passed in + /// + /// The light used to create the rectangle + /// the WorldViewProjection matrix being used to render + /// The rendertarget's size + /// + private static Rectangle ScissorRectCreateForLight(ILight2D light, Microsoft.Xna.Framework.Matrix matrix, Vector2 targetSize) + { + // This needs refining, but it works as is (I believe) + var lightBounds = light.Bounds; + + var min = KryptonEngine.VectorToPixel(lightBounds.Min, matrix, targetSize); + var max = KryptonEngine.VectorToPixel(lightBounds.Max, matrix, targetSize); + + var min2 = Vector2.Min(min, max); + var max2 = Vector2.Max(min, max); + + min = Vector2.Clamp(min2, Vector2.Zero, targetSize); + max = Vector2.Clamp(max2, Vector2.Zero, targetSize); + + return new Rectangle((int)(min.X), (int)(min.Y), (int)(max.X - min.X), (int)(max.Y - min.Y)); + } + + /// + /// Takes a screen-space vector and puts it in to pixel space + /// + /// + /// + /// + /// + private static Vector2 VectorToPixel(Vector2 v, Matrix matrix, Vector2 targetSize) + { + Vector2.Transform(ref v, ref matrix, out v); + + v.X = (1 + v.X) * (targetSize.X / 2f); + v.Y = (1 - v.Y) * (targetSize.Y / 2f); + + return v; + } + + /// + /// Takes a screen-space size vector and converts it to a pixel-space size vector + /// + /// + /// + /// + /// + private static Vector2 ScaleToPixel(Vector2 v, Matrix matrix, Vector2 targetSize) + { + v.X *= matrix.M11 * (targetSize.X / 2f); + v.Y *= matrix.M22 * (targetSize.Y / 2f); + + return v; + } + + /// + /// Retrieves a rasterize state by using the cull mode as a lookup + /// + /// The cullmode used to lookup the rasterize state + /// + private static RasterizerState RasterizerStateGetFromCullMode(CullMode cullMode) + { + switch (cullMode) + { + case (CullMode.CullCounterClockwiseFace): + return RasterizerState.CullCounterClockwise; + + case (CullMode.CullClockwiseFace): + return RasterizerState.CullClockwise; + + default: + return RasterizerState.CullNone; + } + } + + /// + /// Presents the light map to the current render target + /// + private void LightMapPresent() + { + RenderHelper.DrawTextureToTarget(this.mMap, this.mLightMapSize, BlendTechnique.Multiply); + } + } +} diff --git a/Krypton v2.0/Krypton/KryptonRenderHelper.cs b/Krypton v2.0/Krypton/KryptonRenderHelper.cs new file mode 100755 index 0000000..ff8dcf9 --- /dev/null +++ b/Krypton v2.0/Krypton/KryptonRenderHelper.cs @@ -0,0 +1,476 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +using Krypton.Lights; + +namespace Krypton +{ + public enum BlendTechnique + { + Add = 1, + Multiply = 2, + }; + + public enum BlurTechnique + { + Horizontal = 1, + Vertical = 2, + }; + + public class KryptonRenderHelper + { + #region Static Unit Quad + + private static VertexPositionTexture[] UnitQuad = new VertexPositionTexture[] + { + new VertexPositionTexture() + { + Position = new Vector3(-1, 1, 0), + TextureCoordinate = new Vector2(0, 0), + }, + new VertexPositionTexture() + { + Position = new Vector3(1, 1, 0), + TextureCoordinate = new Vector2(1, 0), + }, + new VertexPositionTexture() + { + Position = new Vector3(-1, -1, 0), + TextureCoordinate = new Vector2(0, 1), + }, + new VertexPositionTexture() + { + Position = new Vector3(1, -1, 0), + TextureCoordinate = new Vector2(1, 1), + }, + }; + + #endregion Static Unit Quad + + private GraphicsDevice mGraphicsDevice; + private Effect mEffect; + private List mShadowHullVertices = new List(); + private List mShadowHullIndicies = new List(); + + public GraphicsDevice GraphicsDevice + { + get { return this.mGraphicsDevice; } + } + public Effect Effect + { + get { return this.mEffect; } + } + + public List ShadowHullVertices + { + get { return this.mShadowHullVertices; } + } + public List ShadowHullIndicies + { + get { return this.mShadowHullIndicies; } + } + + public KryptonRenderHelper(GraphicsDevice graphicsDevice, Effect effect) + { + this.mGraphicsDevice = graphicsDevice; + this.mEffect = effect; + } + + public void BufferAddShadowHull(ShadowHull hull) + { + // Why do we need all of these again? (hint: we don't) + + Matrix vertexMatrix = Matrix.Identity; + Matrix normalMatrix = Matrix.Identity; + + float cos, sin; + + ShadowHullPoint point; + ShadowHullVertex hullVertex; + + // Create the matrices (3X speed boost versus prior version) + cos = (float)Math.Cos(hull.Angle); + sin = (float)Math.Sin(hull.Angle); + + // vertexMatrix = scale * rotation * translation; + vertexMatrix.M11 = hull.Scale.X * cos; + vertexMatrix.M12 = hull.Scale.X * sin; + vertexMatrix.M21 = hull.Scale.Y * -sin; + vertexMatrix.M22 = hull.Scale.Y * cos; + vertexMatrix.M41 = hull.Position.X; + vertexMatrix.M42 = hull.Position.Y; + + // normalMatrix = scaleInv * rotation; + normalMatrix.M11 = (1f / hull.Scale.X) * cos; + normalMatrix.M12 = (1f / hull.Scale.X) * sin; + normalMatrix.M21 = (1f / hull.Scale.Y) * -sin; + normalMatrix.M22 = (1f / hull.Scale.Y) * cos; + + // Where are we in the buffer? + var vertexCount = this.mShadowHullVertices.Count; + + // Add the vertices to the buffer + for (int i = 0; i < hull.NumPoints; i++) + { + + // Transform the vertices to screen coordinates + point = hull.Points[i]; + Vector2.Transform(ref point.Position, ref vertexMatrix, out hullVertex.Position); + Vector2.TransformNormal(ref point.Normal, ref normalMatrix, out hullVertex.Normal); + + hullVertex.Color = Color.Black; + + this.mShadowHullVertices.Add(hullVertex); // could this be sped up... ? + } + + //// Add the indicies to the buffer + foreach (int index in hull.Indicies) + { + mShadowHullIndicies.Add(vertexCount + index); // what about this? Add range? + } + } + + public void DrawSquareQuad(Vector2 position, float rotation, float size, Color color) + { + size /= 2; + + size = (float)Math.Sqrt(Math.Pow(size, 2) + Math.Pow(size, 2)); + + rotation += (float)Math.PI / 4; + + var cos = (float)Math.Cos(rotation) * size; + var sin = (float)Math.Sin(rotation) * size; + + var v1 = new Vector3(+cos, +sin, 0) + new Vector3(position, 0); + var v2 = new Vector3(-sin, +cos, 0) + new Vector3(position, 0); + var v3 = new Vector3(-cos, -sin, 0) + new Vector3(position, 0); + var v4 = new Vector3(+sin, -cos, 0) + new Vector3(position, 0); + + var quad = new VertexPositionColorTexture[] + { + new VertexPositionColorTexture() + { + Position = v2, + Color = color, + TextureCoordinate = new Vector2(0,0), + }, + new VertexPositionColorTexture() + { + Position = v1, + Color = color, + TextureCoordinate = new Vector2(1,0), + }, + new VertexPositionColorTexture() + { + Position = v3, + Color = color, + TextureCoordinate = new Vector2(0,1), + }, + new VertexPositionColorTexture() + { + Position = v4, + Color = color, + TextureCoordinate = new Vector2(1,1), + }, + }; + + this.mGraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, quad, 0, 2); + } + + public void DrawClippedFov(Vector2 position, float rotation, float size, Color color, float fov) + { + fov = MathHelper.Clamp(fov, 0, MathHelper.TwoPi); + + if (fov == 0) + { + return; + } + else if (fov == MathHelper.TwoPi) + { + this.DrawSquareQuad(position, rotation, size, color); + return; + } + else + { + var ccw = ClampToBox(fov / 2); + var cw = ClampToBox(-fov / 2); + + var ccwTex = new Vector2(ccw.X + 1, -ccw.Y + 1) / 2f; + var cwTex = new Vector2(cw.X + 1, -cw.Y + 1) / 2f; + + VertexPositionColorTexture[] vertices; + + #region Vertices + vertices = new VertexPositionColorTexture[] + { + new VertexPositionColorTexture() + { + Position = Vector3.Zero, + Color = color, + TextureCoordinate = new Vector2(0.5f, 0.5f), + }, + new VertexPositionColorTexture() + { + Position = new Vector3(ccw,0), + Color = color, + TextureCoordinate = ccwTex + }, + new VertexPositionColorTexture() + { + Position = new Vector3(-1, 1, 0), + Color = color, + TextureCoordinate = new Vector2(0, 0), + }, + new VertexPositionColorTexture() + { + Position = new Vector3(1, 1, 0), + Color = color, + TextureCoordinate = new Vector2(1, 0), + }, + new VertexPositionColorTexture() + { + Position = new Vector3(1, -1, 0), + Color = color, + TextureCoordinate = new Vector2(1, 1), + }, + new VertexPositionColorTexture() + { + Position = new Vector3(-1, -1, 0), + Color = color, + TextureCoordinate = new Vector2(0, 1), + }, + new VertexPositionColorTexture() + { + Position = new Vector3(cw, 0), + Color = color, + TextureCoordinate = cwTex, + }, + }; + + var r = Matrix.CreateRotationZ(rotation) * Matrix.CreateScale(size / 2) * Matrix.CreateTranslation(new Vector3(position, 0)); + + for (int i = 0; i < vertices.Length; i++) + { + var vertex = vertices[i]; + + Vector3.Transform(ref vertex.Position, ref r, out vertex.Position); + + vertices[i] = vertex; + } + + #endregion Vertices + + Int32[] indicies; + + #region Indicies + + if (fov <= MathHelper.Pi / 2) + { + indicies = new Int32[] + { + 0, 1, 6, + }; + } + else if (fov <= 3 * MathHelper.Pi / 2) + { + indicies = new Int32[] + { + 0, 1, 3, + 0, 3, 4, + 0, 4, 6, + }; + } + else + { + indicies = new Int32[] + { + 0, 1, 2, + 0, 2, 3, + 0, 3, 4, + 0, 4, 5, + 0, 5, 6, + }; + } + #endregion Indicies + + this.mGraphicsDevice.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, vertices, 0, vertices.Length, indicies, 0, indicies.Length / 3); + } + } + + public static Vector2 ClampToBox(float angle) + { + var x = Math.Cos(angle); + var y = Math.Sin(angle); + var absMax = Math.Max(Math.Abs(x), Math.Abs(y)); + + return new Vector2((float)(x / absMax), (float)(y / absMax)); + } + + public void BufferDraw() + { + if (this.mShadowHullIndicies.Count >= 3) + { + this.mGraphicsDevice.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, this.mShadowHullVertices.ToArray(), 0, this.mShadowHullVertices.Count, this.mShadowHullIndicies.ToArray(), 0, this.mShadowHullIndicies.Count / 3); + } + } + + public void DrawFullscreenQuad() + { + // Obtain the original rendering states + var originalRasterizerState = this.mGraphicsDevice.RasterizerState; + + // Draw the quad + this.mEffect.CurrentTechnique = this.mEffect.Techniques["ScreenCopy"]; + //this.mGraphicsDevice.RasterizerState = RasterizerState.CullNone; + + this.mEffect.Parameters["TexelBias"].SetValue(new Vector2(0.5f / this.mGraphicsDevice.Viewport.Width, 0.5f / this.mGraphicsDevice.Viewport.Height)); + + foreach (var effectPass in this.mEffect.CurrentTechnique.Passes) + { + effectPass.Apply(); + this.mGraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, KryptonRenderHelper.UnitQuad, 0, 2); + } + + // Reset to the original rendering states + //this.mGraphicsDevice.RasterizerState = originalRasterizerState; + } + + public void BlurTextureToTarget(Texture2D texture, LightMapSize mapSize, BlurTechnique blurTechnique, float bluriness) + { + // Get the pass to use + string passName = ""; + + switch (blurTechnique) + { + case (BlurTechnique.Horizontal): + this.mEffect.Parameters["BlurFactorU"].SetValue(1f / this.GraphicsDevice.PresentationParameters.BackBufferWidth); + passName = "HorizontalBlur"; + break; + + case (BlurTechnique.Vertical): + this.mEffect.Parameters["BlurFactorV"].SetValue(1f / this.mGraphicsDevice.PresentationParameters.BackBufferHeight); + passName = "VerticalBlur"; + break; + } + + var biasFactor = KryptonRenderHelper.BiasFactorFromLightMapSize(mapSize); + + // Calculate the texel bias + Vector2 texelBias = new Vector2() + { + X = biasFactor / this.mGraphicsDevice.Viewport.Width, + Y = biasFactor / this.mGraphicsDevice.Viewport.Height, + }; + + + this.mEffect.Parameters["Texture0"].SetValue(texture); + this.mEffect.Parameters["TexelBias"].SetValue(texelBias); + this.mEffect.Parameters["Bluriness"].SetValue(bluriness); + this.mEffect.CurrentTechnique = this.mEffect.Techniques["Blur"]; + + mEffect.CurrentTechnique.Passes[passName].Apply(); + this.mGraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, KryptonRenderHelper.UnitQuad, 0, 2); + } + + public void DrawTextureToTarget(Texture2D texture, LightMapSize mapSize, BlendTechnique blend) + { + // Get the technique to use + string techniqueName = ""; + + switch (blend) + { + case(BlendTechnique.Add): + techniqueName = "TextureToTarget_Add"; + break; + + case(BlendTechnique.Multiply): + techniqueName = "TextureToTarget_Multiply"; + break; + } + + var biasFactor = KryptonRenderHelper.BiasFactorFromLightMapSize(mapSize); + + // Calculate the texel bias + Vector2 texelBias = new Vector2() + { + X = biasFactor / this.mGraphicsDevice.ScissorRectangle.Width, + Y = biasFactor / this.mGraphicsDevice.ScissorRectangle.Height, + }; + + this.mEffect.Parameters["Texture0"].SetValue(texture); + this.mEffect.Parameters["TexelBias"].SetValue(texelBias); + this.mEffect.CurrentTechnique = this.mEffect.Techniques[techniqueName]; + + // Draw the quad + foreach (var effectPass in this.mEffect.CurrentTechnique.Passes) + { + effectPass.Apply(); + this.mGraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, KryptonRenderHelper.UnitQuad, 0, 2); + } + } + + private static float BiasFactorFromLightMapSize(LightMapSize mapSize) + { + switch (mapSize) + { + case (LightMapSize.Full): + return 0.5f; + + case (LightMapSize.Fourth): + return 0.6f; + + case (LightMapSize.Eighth): + return 0.7f; + + default: + return 0.0f; + } + } + + public void BufferAddBoundOutline(Common.BoundingRect boundingRect) + { + var vertexCount = this.mShadowHullVertices.Count; + + this.mShadowHullVertices.Add(new ShadowHullVertex() + { + Color = Color.Black, + Normal = Vector2.Zero, + Position = new Vector2(boundingRect.Left, boundingRect.Top) + }); + + this.mShadowHullVertices.Add(new ShadowHullVertex() + { + Color = Color.Black, + Normal = Vector2.Zero, + Position = new Vector2(boundingRect.Right, boundingRect.Top) + }); + + this.mShadowHullVertices.Add(new ShadowHullVertex() + { + Color = Color.Black, + Normal = Vector2.Zero, + Position = new Vector2(boundingRect.Right, boundingRect.Bottom) + }); + + this.mShadowHullVertices.Add(new ShadowHullVertex() + { + Color = Color.Black, + Normal = Vector2.Zero, + Position = new Vector2(boundingRect.Left, boundingRect.Bottom) + }); + + this.mShadowHullIndicies.Add(vertexCount + 0); + this.mShadowHullIndicies.Add(vertexCount + 1); + this.mShadowHullIndicies.Add(vertexCount + 2); + + this.mShadowHullIndicies.Add(vertexCount + 0); + this.mShadowHullIndicies.Add(vertexCount + 2); + this.mShadowHullIndicies.Add(vertexCount + 3); + } + } +} diff --git a/Krypton v2.0/Krypton/LightTextureBuilder.cs b/Krypton v2.0/Krypton/LightTextureBuilder.cs new file mode 100755 index 0000000..dae80a9 --- /dev/null +++ b/Krypton v2.0/Krypton/LightTextureBuilder.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace Krypton +{ + public static class LightTextureBuilder + { + /// + /// Create a Point Light based on a size. + /// + /// Your game's GraphicsDevice + /// Maximum Size + /// Light Texture + public static Texture2D CreatePointLight(GraphicsDevice device, int size) + { + return CreateConicLight(device, size, MathHelper.TwoPi, 0); + } + + /// + /// Create a Conic Light based on the size, and field of view. + /// + /// Your game's GraphicsDevice + /// Maximum Size + /// Maximum Field of View + /// Light Texture + public static Texture2D CreateConicLight(GraphicsDevice device, int size, float FOV) + { + return CreateConicLight(device, size, FOV, 0); + } + + /// + /// Create a Conic Light based on the size, field of view, and near plane distance. + /// + /// Your game's GraphicsDevice + /// Maximum size + /// Maximum Field of View + /// Prevents texture from being drawn at this plane distance, originating from the center of light + /// Light Texture + public static Texture2D CreateConicLight(GraphicsDevice device, int size, float FOV, float nearPlaneDistance) + { + /*if (!IsPowerOfTwo(size)) + throw new Exception("The size must be a power of 2");*/ + float[,] Data = new float[size, size]; + + float center = size / 2; + + FOV = FOV / 2; + + for (int x = 0; x < size; x++) + for (int y = 0; y < size; y++) + { + float Distance = Vector2.Distance(new Vector2(x, y), new Vector2(center)); + + Vector2 Difference = new Vector2(x, y) - new Vector2(center); + float Angle = (float)Math.Atan2(Difference.Y, Difference.X); + + if (Distance <= center && Distance >= nearPlaneDistance && Math.Abs(Angle) <= FOV) + Data[x, y] = (center - Distance) / center; + else + Data[x, y] = 0; + } + + Texture2D tex = new Texture2D(device, size, size); + + Color[] Data1D = new Color[size * size]; + for (int x = 0; x < size; x++) + for (int y = 0; y < size; y++) + Data1D[x + y * size] = new Color(new Vector3(Data[x, y])); + + tex.SetData(Data1D); + + return tex; + } + + /// + /// Math helper to determine if integer is a power of two + /// + /// Integer value + private static bool IsPowerOfTwo(int x) + { + return (x & (x - 1)) == 0; + } + } +} diff --git a/Krypton v2.0/Krypton/Lights/ILight2D.cs b/Krypton v2.0/Krypton/Lights/ILight2D.cs new file mode 100755 index 0000000..4e67e34 --- /dev/null +++ b/Krypton v2.0/Krypton/Lights/ILight2D.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.Xna.Framework; + +using Krypton.Common; + +namespace Krypton.Lights +{ + public interface ILight2D + { + BoundingRect Bounds { get; } + + void Draw(KryptonRenderHelper renderHelper, List hulls); + } +} diff --git a/Krypton v2.0/Krypton/Lights/Light2D.cs b/Krypton v2.0/Krypton/Lights/Light2D.cs new file mode 100755 index 0000000..b0bcdb1 --- /dev/null +++ b/Krypton v2.0/Krypton/Lights/Light2D.cs @@ -0,0 +1,192 @@ +using System; +using System.Collections.Generic; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +using Microsoft.Xna.Framework.Input; + +using Krypton.Common; + +namespace Krypton.Lights +{ + public class Light2D : ILight2D + { + private bool mIsOn = true; + private Vector2 mPosition = Vector2.Zero; + private float mAngle = 0; + private Texture2D mTexture = null; + private Color mColor = Color.White; + private float mRange = 1; + private float mFov = MathHelper.TwoPi; + private float mIntensity = 1; + + #region Parameters + + /// + /// The light's position + /// + public Vector2 Position + { + get { return this.mPosition; } + set { this.mPosition = value; } + } + + /// + /// The X coordinate of the light's position + /// + public float X + { + get { return this.mPosition.X; } + set { this.mPosition.X = value; } + } + + /// + /// The Y coordinate of the light's position + /// + public float Y + { + get { return this.mPosition.Y; } + set { this.mPosition.Y = value; } + } + + /// + /// The light's angle + /// + public float Angle + { + get { return this.mAngle; } + set { this.mAngle = value; } + } + + /// + /// The texture used as the base light map, from which shadows will be subtracted + /// + public Texture2D Texture + { + get { return this.mTexture; } + set { this.mTexture = value; } + } + + /// + /// The color used to tint the light's texture + /// + public Color Color + { + get { return this.mColor; } + set { this.mColor = value; } + } + + /// + /// The light's maximum radius (or "half width", if you will) + /// + public float Range + { + get { return this.mRange; } + set { this.mRange = value; } + } + + /// + /// Gets or sets the light's field of view. This value determines the angles at which the light will cease to draw + /// + public float Fov + { + get { return this.mFov; } + set + { + this.mFov = MathHelper.Clamp(value, 0, MathHelper.TwoPi); + } + } + + /// + /// Gets or sets the light's intensity. Think pixel = (tex * color) ^ (1 / intensity) + /// + public float Intensity + { + get { return this.mIntensity; } + set { this.mIntensity = MathHelper.Clamp(value, 0.01f, 3f); } + } + + #endregion Parameters + + /// + /// Gets or sets a value indicating weither or not to draw the light + /// + public bool IsOn + { + get { return this.mIsOn; } + set { this.mIsOn = value; } + } + + /// + /// Draws shadows from the light's position outward + /// + /// A render helper for drawing shadows + /// The shadow hulls used to draw shadows + public void Draw(KryptonRenderHelper helper, List hulls) + { + // Draw the light only if it's on + if (!this.mIsOn) + return; + + // Make sure we only render the following hulls + helper.ShadowHullVertices.Clear(); + helper.ShadowHullIndicies.Clear(); + + // Loop through each hull + foreach (ShadowHull hull in hulls) + { + //if(hull.Bounds.Intersects(this.Bounds)) + // Add the hulls to the buffer only if they are within the light's range + if (hull.Visible && Light2D.IsInRange(hull.Position - this.Position, hull.MaxRadius * Math.Max(hull.Scale.X, hull.Scale.Y) + this.Range)) + { + helper.BufferAddShadowHull(hull); + } + } + + var shadowEffect = helper.Effect.Techniques["PointLight_Shadow_Fast"]; + helper.Effect.CurrentTechnique = shadowEffect; + // Set the effect parameters + helper.Effect.Parameters["LightPosition"].SetValue(this.mPosition); + helper.Effect.Parameters["Texture0"].SetValue(this.mTexture); + helper.Effect.Parameters["LightIntensityFactor"].SetValue(1 / (this.mIntensity * this.mIntensity)); + + shadowEffect.Passes["ShadowStencil"].Apply(); + helper.BufferDraw(); + + shadowEffect.Passes["Light"].Apply(); + helper.DrawClippedFov(this.mPosition, this.mAngle, this.mRange * 2, this.mColor, this.mFov); + } + + /// + /// Determines if a vector's length is less than a specified value + /// + /// Offset + /// Distance + /// + private static bool IsInRange(Vector2 offset, float dist) + { + if (offset.X * offset.X + offset.Y * offset.Y < dist * dist) + return true; + + return false; + } + + /// + /// Gets the world-space bounds which contain the light + /// + public BoundingRect Bounds + { + get + { + BoundingRect rect; + + rect.Min.X = this.mPosition.X - this.mRange; + rect.Min.Y = this.mPosition.Y - this.mRange; + rect.Max.X = this.mPosition.X + this.mRange; + rect.Max.Y = this.mPosition.Y + this.mRange; + + return rect; + } + } + } +} diff --git a/Krypton v2.0/Krypton/Properties/AssemblyInfo.cs b/Krypton v2.0/Krypton/Properties/AssemblyInfo.cs new file mode 100755 index 0000000..bfb5383 --- /dev/null +++ b/Krypton v2.0/Krypton/Properties/AssemblyInfo.cs @@ -0,0 +1,34 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Krypton")] +[assembly: AssemblyProduct("Krypton")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. Only Windows +// assemblies support COM. +[assembly: ComVisible(false)] + +// On Windows, the following GUID is for the ID of the typelib if this +// project is exposed to COM. On other platforms, it unique identifies the +// title storage container when deploying this assembly to the device. +[assembly: Guid("0ce98116-fee5-4948-bdc1-edab3ed0d43e")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] diff --git a/Krypton v2.0/Krypton/ShadowHull.cs b/Krypton v2.0/Krypton/ShadowHull.cs new file mode 100755 index 0000000..bb78128 --- /dev/null +++ b/Krypton v2.0/Krypton/ShadowHull.cs @@ -0,0 +1,241 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using Krypton.Common; + +namespace Krypton +{ + /// + /// A hull used for casting shadows from a light source + /// + public class ShadowHull + { + #region Orientation + + /// + /// The position of the shadow hull + /// + public Vector2 Position; + + /// + /// The angle of the shadow hull + /// + public float Angle; + + #endregion + + #region Shape + + /// + /// The maximum radius in which all of the shadow hull's vertices are contained, originating from the hull's position + /// + public float MaxRadius; + + /// + /// The vertices comprising the shadow hull + /// + public ShadowHullPoint[] Points; + + /// + /// The number of vertices comprising the shadow hull + /// + public int NumPoints; + + /// + /// The indicies used to render the shadow hull + /// + public Int32[] Indicies; + + /// + /// The number of indicies used to render the shadow hull + /// + public int NumIndicies; + + /// + /// A value indicating if the hull should cast a shadow + /// + public bool Visible = true; + + /// + /// A value indicating how much to stretch the hull + /// + public Vector2 Scale = Vector2.One; + + #endregion + + private ShadowHull(){} + + #region Factory Methods + + /// + /// Creates a rectangular shadow hull + /// + /// The dimensions of the rectangle + /// A rectangular shadow hull + public static ShadowHull CreateRectangle(Vector2 size) + { + ShadowHull hull = new ShadowHull(); + + size *= 0.5f; + + hull.MaxRadius = (float)Math.Sqrt(size.X * size.X + size.Y * size.Y); + + hull.NumPoints = 4 * 2; + var numTris = hull.NumPoints - 2; + hull.NumIndicies = numTris * 3; + + hull.Points = new ShadowHullPoint[hull.NumPoints]; + hull.Indicies = new Int32[hull.NumIndicies]; + + // Vertex position + var posTR = new Vector2(+size.X, +size.Y); + var posBR = new Vector2(+size.X, -size.Y); + var posBL = new Vector2(-size.X, -size.Y); + var posTL = new Vector2(-size.X, +size.Y); + + // Right + hull.Points[0] = new ShadowHullPoint(posTR, Vector2.UnitX); + hull.Points[1] = new ShadowHullPoint(posBR, Vector2.UnitX); + + // Bottom + hull.Points[2] = new ShadowHullPoint(posBR, -Vector2.UnitY); + hull.Points[3] = new ShadowHullPoint(posBL, -Vector2.UnitY); + + // Left + hull.Points[4] = new ShadowHullPoint(posBL, -Vector2.UnitX); + hull.Points[5] = new ShadowHullPoint(posTL, -Vector2.UnitX); + + // Top + hull.Points[6] = new ShadowHullPoint(posTL, Vector2.UnitY); + hull.Points[7] = new ShadowHullPoint(posTR, Vector2.UnitY); + + // Create tris + for (int i = 0; i < numTris; i++) + { + hull.Indicies[i * 3 + 0] = 0; + hull.Indicies[i * 3 + 1] = i + 1; + hull.Indicies[i * 3 + 2] = i + 2; + } + + return hull; + } + + /// + /// Creates a circular shadow hull + /// + /// radius of the circle + /// number of sides the circle will be comprised of + /// A circular shadow hull + public static ShadowHull CreateCircle(float radius, int sides) + { + // Validate input + if (sides < 3) { throw new ArgumentException("Shadow hull must have at least 3 sides."); } + + ShadowHull hull = new ShadowHull(); + + hull.MaxRadius = radius; + + // Calculate number of sides + hull.NumPoints = sides * 2; + var numTris = hull.NumPoints - 2; + hull.NumIndicies = numTris * 3; + + hull.Points = new ShadowHullPoint[hull.NumPoints]; + hull.Indicies = new Int32[hull.NumIndicies]; + + var angle = (float)(-Math.PI * 2) / sides; // XNA Renders Clockwise + var angleOffset = angle / 2; + + for (int i = 0; i < sides; i++) + { + // Create vertices + var v1 = new ShadowHullPoint(); + var v2 = new ShadowHullPoint(); + + // Vertex Position + v1.Position.X = (float)Math.Cos(angle * i) * radius; + v1.Position.Y = (float)Math.Sin(angle * i) * radius; + + v2.Position.X = (float)Math.Cos(angle * (i + 1)) * radius; + v2.Position.Y = (float)Math.Sin(angle * (i + 1)) * radius; + + // Vertex Normal + v1.Normal.X = (float)Math.Cos(angle * i + angleOffset); + v1.Normal.Y = (float)Math.Sin(angle * i + angleOffset); + + v2.Normal.X = (float)Math.Cos(angle * i + angleOffset); + v2.Normal.Y = (float)Math.Sin(angle * i + angleOffset); + + // Copy vertices + hull.Points[i * 2 + 0] = v1; + hull.Points[i * 2 + 1] = v2; + } + + for (int i = 0; i < numTris; i++) + { + hull.Indicies[i * 3 + 0] = 0; + hull.Indicies[i * 3 + 1] = (Int32)(i + 1); + hull.Indicies[i * 3 + 2] = (Int32)(i + 2); + } + + return hull; + } + + /// + /// Creates a custom shadow hull based on a series of vertices + /// + /// The points which the shadow hull will be comprised of + /// A custom shadow hulll + public static ShadowHull CreateConvex(ref Vector2[] points) + { + // Validate input + if (points == null) { throw new ArgumentNullException("Points cannot be null."); } + if (points.Length < 3) { throw new ArgumentException("Need at least 3 points to create shadow hull."); } + + var numPoints = points.Length; + + ShadowHull hull = new ShadowHull(); + + hull.NumPoints = numPoints * 2; + var numTris = hull.NumPoints - 2; + hull.NumIndicies = numTris * 3; + + hull.Points = new ShadowHullPoint[hull.NumPoints]; + hull.Indicies = new Int32[hull.NumIndicies]; + + Vector2 pointMin = points[0]; + Vector2 pointMax = points[0]; + + for (int i = 0; i < numPoints; i++) + { + var p1 = points[(i + 0) % numPoints]; + var p2 = points[(i + 1) % numPoints]; + + hull.MaxRadius = Math.Max(hull.MaxRadius, p1.Length()); + + var line = p2 - p1; + + var normal = new Vector2(-line.Y, +line.X); + + normal.Normalize(); + + hull.Points[i * 2 + 0] = new ShadowHullPoint(p1, normal); + hull.Points[i * 2 + 1] = new ShadowHullPoint(p2, normal); + } + + for (Int32 i = 0; i < numTris; i++) + { + hull.Indicies[i * 3 + 0] = 0; + hull.Indicies[i * 3 + 1] = (Int32)(i + 1); + hull.Indicies[i * 3 + 2] = (Int32)(i + 2); + } + + return hull; + } + + #endregion + } +} diff --git a/Krypton v2.0/Krypton/ShadowHullPoint.cs b/Krypton v2.0/Krypton/ShadowHullPoint.cs new file mode 100755 index 0000000..14e959f --- /dev/null +++ b/Krypton v2.0/Krypton/ShadowHullPoint.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using Microsoft.Xna.Framework; + +namespace Krypton +{ + /// + /// A two dimensional point with normal + /// + public struct ShadowHullPoint + { + /// + /// Creates a new Shadow Hull Point + /// + /// The position of the point + /// The normal of the side which the point helps represent + public ShadowHullPoint(Vector2 position, Vector2 normal) + { + this.Position = position; + this.Normal = normal; + } + + /// + /// The position of the point + /// + public Vector2 Position; + + /// + /// The normal of the side of the shadow hull of which the point helps represent + /// + public Vector2 Normal; + } +} diff --git a/Krypton v2.0/Krypton/ShadowHullVertex.cs b/Krypton v2.0/Krypton/ShadowHullVertex.cs new file mode 100755 index 0000000..85978fa --- /dev/null +++ b/Krypton v2.0/Krypton/ShadowHullVertex.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace Krypton +{ + public struct ShadowHullVertex : IVertexType + { + /// + /// The position of the vertex + /// + public Vector2 Position; + + /// + /// The normal of the vertex + /// + public Vector2 Normal; + + /// + /// The color of vertex + /// + public Color Color; + + private static readonly VertexDeclaration mVertexDeclaration; + + /// + /// + /// + public VertexDeclaration VertexDeclaration { get { return ShadowHullVertex.mVertexDeclaration; } } + + static ShadowHullVertex() + { + VertexElement[] elements = new VertexElement[] + { + new VertexElement(0, VertexElementFormat.Vector2, VertexElementUsage.Position, 0), + new VertexElement(8, VertexElementFormat.Vector2, VertexElementUsage.Normal,0), + new VertexElement(16, VertexElementFormat.Color, VertexElementUsage.Color,0), + }; + + mVertexDeclaration = new VertexDeclaration(elements); + } + + /// + /// + /// + /// + /// + /// + public ShadowHullVertex(Vector2 position, Vector2 normal, Color color) + { + this.Position = position; + this.Normal = normal; + this.Color = color; + } + } +} diff --git a/Krypton v2.0/KryptonTestbed/KryptonTestbed/Game.ico b/Krypton v2.0/KryptonTestbed/KryptonTestbed/Game.ico new file mode 100755 index 0000000000000000000000000000000000000000..8cff41eab28dc99e31a693a39d399f9eb05f1cce GIT binary patch literal 4286 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 literal 0 HcmV?d00001 diff --git a/Krypton v2.0/KryptonTestbed/KryptonTestbed/GameKryptonDemo.cs b/Krypton v2.0/KryptonTestbed/KryptonTestbed/GameKryptonDemo.cs new file mode 100755 index 0000000..257489f --- /dev/null +++ b/Krypton v2.0/KryptonTestbed/KryptonTestbed/GameKryptonDemo.cs @@ -0,0 +1,245 @@ +using System; +using System.Collections.Generic; +//using System.Linq; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Audio; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.GamerServices; +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework.Input; +using Microsoft.Xna.Framework.Media; + +using Krypton; +using Krypton.Lights; + +namespace KryptonTestbed +{ + /// + /// This is the main type for your game + /// + public class KryptonDemoGame : Microsoft.Xna.Framework.Game + { + GraphicsDeviceManager graphics; + + KryptonEngine krypton; + + private Texture2D mLightTexture; + private int mNumLights = 50; + private int mNumHorzontalHulls = 15; + private int mNumVerticalHulls = 15; + + private float mVerticalUnits = 50; + + Random mRandom = new Random(); + + public KryptonDemoGame() + { + // Setup the graphics device manager with some default settings + this.graphics = new GraphicsDeviceManager(this); + this.graphics.PreferredBackBufferWidth = 1280; + this.graphics.PreferredBackBufferHeight = 720; + + // Allow the window to be resized (to demonstrate render target recreation) + this.Window.AllowUserResizing = true; + + // Setup the content manager with some default settings + this.Content.RootDirectory = "Content"; + + // Create Krypton + this.krypton = new KryptonEngine(this, "KryptonEffect"); + + // As a side note, you may want Krypton to be used as a GameComponent. + // To do this, you would simply add the following line of code and remove the Initialize and Draw function of krypton below: + // this.Components.Add(this.krypton); + } + + protected override void Initialize() + { + // Make sure to initialize krpyton, unless it has been added to the Game's list of Components + this.krypton.Initialize(); + + base.Initialize(); + } + + protected override void LoadContent() + { + // Create a new simple point light texture to use for the lights + this.mLightTexture = LightTextureBuilder.CreatePointLight(this.GraphicsDevice, 512); + + // Create some lights and hulls + this.CreateLights(mLightTexture, this.mNumLights); + this.CreateHulls(this.mNumHorzontalHulls, this.mNumVerticalHulls); + } + + private void CreateLights(Texture2D texture, int count) + { + // Make some random lights! + for (int i = 0; i < count; i++) + { + byte r = (byte)(this.mRandom.Next(255 - 64) + 64); + byte g = (byte)(this.mRandom.Next(255 - 64) + 64); + byte b = (byte)(this.mRandom.Next(255 - 64) + 64); + + Light2D light = new Light2D() + { + Texture = texture, + Range = (float)(this.mRandom.NextDouble() * 5 + 1), + Color = new Color(r,g,b), + //Intensity = (float)(this.mRandom.NextDouble() * 0.25 + 0.75), + Intensity = 1f, + Angle = MathHelper.TwoPi * (float)this.mRandom.NextDouble(), + X = (float)(this.mRandom.NextDouble() * 50 - 25), + Y = (float)(this.mRandom.NextDouble() * 50 - 25), + }; + + // Here we set the light's field of view + if (i % 2 == 0) + { + light.Fov = MathHelper.PiOver2 * (float)(this.mRandom.NextDouble() * 0.75 + 0.25); + } + + this.krypton.Lights.Add(light); + } + } + + private void CreateHulls(int x, int y) + { + float w = 50; + float h = 50; + + // Make lines of lines of hulls! + for (int j = 0; j < y; j++) + { + // Make lines of hulls! + for (int i = 0; i < x; i++) + { + var posX = ((i * w) / x) - w / 2 + (j % 2 == 0 ? w / x / 2 : 0); + var posY = ((j * h) / y) - h / 2 + (i % 2 == 0 ? h / y / 4 : 0); + + var hull = ShadowHull.CreateRectangle(Vector2.One); + hull.Position.X = posX; + hull.Position.Y = posY; + hull.Scale.X = (float)(this.mRandom.NextDouble() * 0.75f + 0.25f); + hull.Scale.Y = (float)(this.mRandom.NextDouble() * 0.75f + 0.25f); + + krypton.Hulls.Add(hull); + } + } + } + + protected override void UnloadContent() + { + // Not sure if anything actually NEEDS to go here, as the game exits immediately upon unloading content. Please advise if you think this is bad :) + } + + protected override void Update(GameTime gameTime) + { + // Make sure the user doesn't want to quit (but why would they?) + if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Escape)) + this.Exit(); + + // make it much simpler to deal with the time :) + var t = (float)gameTime.ElapsedGameTime.TotalSeconds; + + var speed = 5; + + // Allow for randomization of lights and hulls, to demonstrait that each hull and light is individually rendered + if (Keyboard.GetState().IsKeyDown(Keys.R)) + { + // randomize lights + foreach (Light2D light in this.krypton.Lights) + { + light.Position += Vector2.UnitY * (float)(this.mRandom.NextDouble() * 2 - 1) * t * speed; + light.Position += Vector2.UnitX * (float)(this.mRandom.NextDouble() * 2 - 1) * t * speed; + light.Angle -= MathHelper.TwoPi * (float)(this.mRandom.NextDouble() * 2 - 1) * t * speed; + } + + // randomize hulls + foreach (var hull in this.krypton.Hulls) + { + hull.Position += Vector2.UnitY * (float)(this.mRandom.NextDouble() * 2 - 1) * t * speed; + hull.Position += Vector2.UnitX * (float)(this.mRandom.NextDouble() * 2 - 1) * t * speed; + hull.Angle -= MathHelper.TwoPi * (float)(this.mRandom.NextDouble() * 2 - 1) * t * speed; + } + } + + base.Update(gameTime); + } + + protected override void Draw(GameTime gameTime) + { + // Create a world view projection matrix to use with krypton + Matrix world = Matrix.Identity; + Matrix view = Matrix.CreateTranslation(new Vector3(0, 0, 0) * -1f); + Matrix projection = Matrix.CreateOrthographic(this.mVerticalUnits * this.GraphicsDevice.Viewport.AspectRatio, this.mVerticalUnits, 0, 1); + + // Assign the matrix and pre-render the lightmap. + // Make sure not to change the position of any lights or shadow hulls after this call, as it won't take effect till the next frame! + this.krypton.Matrix = world * view * projection; + this.krypton.Bluriness = 3; + this.krypton.LightMapPrepare(); + + // Make sure we clear the backbuffer *after* Krypton is done pre-rendering + this.GraphicsDevice.Clear(Color.White); + + // ----- DRAW STUFF HERE ----- // + // By drawing here, you ensure that your scene is properly lit by krypton. + // Drawing after KryptonEngine.Draw will cause you objects to be drawn on top of the lightmap (can be useful, fyi) + // ----- DRAW STUFF HERE ----- // + + // Draw krypton (This can be omited if krypton is in the Component list. It will simply draw krypton when base.Draw is called + this.krypton.Draw(gameTime); + + // Draw the shadow hulls as-is (no shadow stretching) in pure white on top of the shadows + // You can omit this line if you want to see what the light-map looks like :) + this.DebugDraw(); + + base.Draw(gameTime); + } + + private void DebugDraw() + { + this.krypton.RenderHelper.Effect.CurrentTechnique = this.krypton.RenderHelper.Effect.Techniques["DebugDraw"]; + this.GraphicsDevice.RasterizerState = new RasterizerState() + { + CullMode = CullMode.None, + FillMode = FillMode.WireFrame, + }; + if (Keyboard.GetState().IsKeyDown(Keys.H)) + { + // Clear the helpers vertices + this.krypton.RenderHelper.ShadowHullVertices.Clear(); + this.krypton.RenderHelper.ShadowHullIndicies.Clear(); + + foreach (var hull in krypton.Hulls) + { + this.krypton.RenderHelper.BufferAddShadowHull(hull); + } + + + foreach (var effectPass in krypton.RenderHelper.Effect.CurrentTechnique.Passes) + { + effectPass.Apply(); + this.krypton.RenderHelper.BufferDraw(); + } + } + + if (Keyboard.GetState().IsKeyDown(Keys.L)) + { + this.krypton.RenderHelper.ShadowHullVertices.Clear(); + this.krypton.RenderHelper.ShadowHullIndicies.Clear(); + + foreach (Light2D light in krypton.Lights) + { + this.krypton.RenderHelper.BufferAddBoundOutline(light.Bounds); + } + + foreach (var effectPass in krypton.RenderHelper.Effect.CurrentTechnique.Passes) + { + effectPass.Apply(); + this.krypton.RenderHelper.BufferDraw(); + } + } + } + } +} diff --git a/Krypton v2.0/KryptonTestbed/KryptonTestbed/GameThumbnail.png b/Krypton v2.0/KryptonTestbed/KryptonTestbed/GameThumbnail.png new file mode 100755 index 0000000000000000000000000000000000000000..462311aba2cd09de3992129ca43564755249ef09 GIT binary patch literal 5734 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 Y0L3g3-xp*i%>V!Z07*qoM6N<$f>>Wb>;M1& literal 0 HcmV?d00001 diff --git a/Krypton v2.0/KryptonTestbed/KryptonTestbed/KryptonTestbed.csproj b/Krypton v2.0/KryptonTestbed/KryptonTestbed/KryptonTestbed.csproj new file mode 100755 index 0000000..78f58f8 --- /dev/null +++ b/Krypton v2.0/KryptonTestbed/KryptonTestbed/KryptonTestbed.csproj @@ -0,0 +1,153 @@ + + + + {E9787BEE-7290-4C74-B919-79DC70AABE87} + {6D335F3A-9D43-41b4-9D22-F6F17C4BE596};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Debug + x86 + WinExe + Properties + KryptonTestbed + KryptonTestbed + v4.0 + Client + v4.0 + Windows + HiDef + 04e8736f-6d19-442f-95e4-08f9b783d054 + Game + Game.ico + GameThumbnail.png + + + + + + + + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + bin\x86\Debug + DEBUG;TRACE;WINDOWS + prompt + 4 + true + false + x86 + false + + + pdbonly + true + bin\x86\Release + TRACE;WINDOWS + prompt + 4 + true + false + x86 + true + + + + + + + + + + + + + + False + + + False + + + False + + + False + + + False + + + + + + + + + + + + + + {B1BFCB2A-C001-4DAC-BA7D-B68BF28757F3} + Krypton + + + KryptonTestbedContent + Content + + + + + False + Microsoft .NET Framework 4 Client Profile %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + false + + + False + Windows Installer 3.1 + true + + + False + Microsoft XNA Framework Redistributable 4.0 + true + + + + + + \ No newline at end of file diff --git a/Krypton v2.0/KryptonTestbed/KryptonTestbed/Program.cs b/Krypton v2.0/KryptonTestbed/KryptonTestbed/Program.cs new file mode 100755 index 0000000..bbc294f --- /dev/null +++ b/Krypton v2.0/KryptonTestbed/KryptonTestbed/Program.cs @@ -0,0 +1,21 @@ +using System; + +namespace KryptonTestbed +{ +#if WINDOWS || XBOX + static class Program + { + /// + /// The main entry point for the application. + /// + static void Main(string[] args) + { + using (KryptonDemoGame game = new KryptonDemoGame()) + { + game.Run(); + } + } + } +#endif +} + diff --git a/Krypton v2.0/KryptonTestbed/KryptonTestbed/Properties/AssemblyInfo.cs b/Krypton v2.0/KryptonTestbed/KryptonTestbed/Properties/AssemblyInfo.cs new file mode 100755 index 0000000..a9780bc --- /dev/null +++ b/Krypton v2.0/KryptonTestbed/KryptonTestbed/Properties/AssemblyInfo.cs @@ -0,0 +1,34 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("KryptonTestbed")] +[assembly: AssemblyProduct("KryptonTestbed")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. Only Windows +// assemblies support COM. +[assembly: ComVisible(false)] + +// On Windows, the following GUID is for the ID of the typelib if this +// project is exposed to COM. On other platforms, it unique identifies the +// title storage container when deploying this assembly to the device. +[assembly: Guid("44537967-0d21-441c-bf8b-9c788e77ff51")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] diff --git a/Krypton v2.0/KryptonTestbed/KryptonTestbedContent/KryptonEffect.fx b/Krypton v2.0/KryptonTestbed/KryptonTestbedContent/KryptonEffect.fx new file mode 100755 index 0000000..59abc92 --- /dev/null +++ b/Krypton v2.0/KryptonTestbed/KryptonTestbedContent/KryptonEffect.fx @@ -0,0 +1,478 @@ +// ------------------------------------------------------------------------------------------------ // +// ----- Copyright 2011 Christopher Harris --------------------- http://krypton.codeplex.com/ ----- // +// ----------------------------------------------------------------- mailto:xixonia@gmail.com ----- // +// ------------------------------------------------------------------------------------------------ // + +// ------------------------------------------------------------------------------------------------ // +// ----- Parameters ------------------------------------------------------------------------------- // + +float4x4 Matrix; + +texture Texture0; +texture Texture1; +float2 LightPosition; +float LightIntensityFactor = 1; + +float ShadowStrech = 1000000; + +float2 TexelBias; + +float4 AmbientColor; + +float Bluriness = 0.5f; +float BlurFactorU = 0; +float BlurFactorV = 0; + +// ------------------------------------------------------------------------------------------------ // +// ----- Samplers --------------------------------------------------------------------------------- // + +sampler2D tex0 = sampler_state +{ + Texture = ; + AddressU = Clamp; + AddressV = Clamp; +}; + +sampler2D tex1 = sampler_state +{ + Texture = ; + AddressU = Clamp; + AddressV = Clamp; +}; + +// ------------------------------------------------------------------------------------------------ // +// ----- Structures ------------------------------------------------------------------------------- // + +struct ShadowHullVertex +{ + float4 Position : POSITION0; + float2 Normal : NORMAL0; + float4 Color : COLOR0; +}; + +struct VertexPositionColor +{ + float4 Position : POSITION0; + float4 Color : COLOR0; +}; + +struct VertexPositionNormalTexture +{ + float4 Position : POSITION0; + float4 Normal : NORMAL0; + float2 TexCoord : TEXCOORD0; +}; + +struct VertexPositionColorTexture +{ + float4 Position : POSITION0; + float4 Color : COLOR0; + float2 TexCoord : TEXCOORD0; +}; + +struct VertexPositionTexture +{ + float4 Position : POSITION0; + float2 TexCoord : TEXCOORD0; +}; + +// ------------------------------------------------------------------------------------------------ // +// ----- Techniques ------------------------------------------------------------------------------- // + +// ------------------------------------------------------------------------------------------------ +// ----- Technique: TextureToTarget --------------------------------------------------------------- + +VertexPositionTexture VS_ScreenCopy(VertexPositionTexture input) +{ + VertexPositionTexture output; + + output.Position = input.Position; + output.TexCoord = input.TexCoord; + + return input; +}; + +float4 PS_ScreenCopy(VertexPositionTexture input) : COLOR0 +{ + return tex2D(tex0, input.TexCoord + TexelBias); +}; + +technique TextureToTarget_Add +{ + pass Pass1 + { + StencilEnable = False; + + BlendOp = Add; + SrcBlend = One; + DestBlend = One; + + AlphaBlendEnable = True; + + CullMode = CCW; + + VertexShader = compile vs_2_0 VS_ScreenCopy(); + PixelShader = compile ps_2_0 PS_ScreenCopy(); + } +}; + +technique TextureToTarget_Multiply +{ + pass Pass1 + { + StencilEnable = False; + + BlendOp = Add; + SrcBlend = Zero; + DestBlend = SrcColor; + + AlphaBlendEnable = True; + + CullMode = CCW; + + VertexShader = compile vs_2_0 VS_ScreenCopy(); + PixelShader = compile ps_2_0 PS_ScreenCopy(); + } +}; + +float4 PS_ClearTarget() : COLOR0 +{ + return float4(0, 0, 0, 1); +} + +// ------------------------------------------------------------------------------------------------ +// ----- Technique: SimpleTexture ----------------------------------------------------------------- + +VertexPositionColorTexture VS_SimpleTexture(VertexPositionColorTexture input) +{ + VertexPositionColorTexture output; + + output.Position = mul(input.Position, Matrix); + output.Color = input.Color; + output.TexCoord = input.TexCoord; + + return output; +}; + +float4 PS_SimpleTexture(VertexPositionColorTexture input) : COLOR0 +{ + return tex2D(tex0, input.TexCoord) * input.Color; +}; + +float4 PS_LightTexture(VertexPositionColorTexture input) : COLOR0 +{ + return pow(tex2D(tex0, input.TexCoord) * input.Color, LightIntensityFactor); +}; + +technique SimpleTexture +{ + pass Pass1 + { + StencilEnable = False; + + VertexShader = compile vs_2_0 VS_SimpleTexture(); + PixelShader = compile ps_2_0 PS_SimpleTexture(); + } +}; + +technique LightTexture +{ + pass Pass1 + { + StencilEnable = False; + + BlendOp = Add; + DestBlend = Zero; + SrcBlend = SrcAlpha; + + AlphaBlendEnable = True; + + VertexShader = compile vs_2_0 VS_SimpleTexture(); + PixelShader = compile ps_2_0 PS_LightTexture(); + } +}; + +// ------------------------------------------------------------------------------------------------ +// ----- Technique: PointLight_Shadow ------------------------------------------------------------- + +VertexPositionColor VS_PointLight_Shadow(ShadowHullVertex input) +{ + float2 direction = normalize(LightPosition.xy - input.Position.xy); + + if(dot(input.Normal.xy, direction) < 0) + { + // Stretch backfacing vertices + input.Position.xy -= direction * ShadowStrech; + } + + VertexPositionColor output; + + output.Position = mul(input.Position, Matrix); + output.Color = input.Color; + + return output; +}; + +float4 PS_PointLight_Shadow(float4 input : COLOR0) : COLOR0 +{ + return input; +}; + +VertexPositionColor VS_Shadow_HullIllumination(ShadowHullVertex input) +{ + VertexPositionColor output; + + output.Position = mul(input.Position, Matrix); + output.Color = input.Color; + + return output; +}; + +float4 PS_Shadow_HullIllumination() : COLOR0 +{ + return float4(1, 1, 1, 1); +}; + +technique PointLight_Shadow +{ + pass Shadow + { + StencilEnable = False; + + AlphaBlendEnable = True; + + BlendOp = RevSubtract; + SrcBlend = One; + DestBlend = One; + + VertexShader = compile vs_2_0 VS_PointLight_Shadow(); + PixelShader = compile ps_2_0 PS_PointLight_Shadow(); + } +}; + +// ------------------------------------------------------------------------------------------------ +// ----- Technique: PointLight_ShadowWithIllumination --------------------------------------------- + +technique PointLight_ShadowWithIllumination +{ + pass Shadow_Illumination + { + // This outlines where our hulls are currently, so we don't draw shadows there + StencilEnable = True; + StencilFunc = Never; + StencilFail = Incr; + + AlphaBlendEnable = False; + + VertexShader = compile vs_2_0 VS_Shadow_HullIllumination(); + PixelShader = compile ps_2_0 PS_Shadow_HullIllumination(); + } + + pass Shadow + { + // Only draw where the Stencil hasn't touched + StencilEnable = True; + StencilFunc = Equal; + StencilRef = 0; + StencilFail = Incr; + + AlphaBlendEnable = True; + + BlendOp = RevSubtract; + SrcBlend = One; + DestBlend = One; + + VertexShader = compile vs_2_0 VS_PointLight_Shadow(); + PixelShader = compile ps_2_0 PS_PointLight_Shadow(); + } + +}; + +// ------------------------------------------------------------------------------------------------ +// ----- Technique: PointLight_ShadowWithOcclusion ------------------------------------------------ + +technique PointLight_ShadowWithOcclusion +{ + pass Shadow_HullStencil + { + // This outlines where our hulls are currently, so we don't draw shadows there, unless the hull is occluded + StencilEnable = True; + StencilFunc = Never; + StencilFail = Incr; + + VertexShader = compile vs_2_0 VS_Shadow_HullIllumination(); + PixelShader = compile ps_2_0 PS_Shadow_HullIllumination(); + } + + pass Shadow + { + // This allows us to draw shadows on hulls behind other hulls + StencilEnable = True; + StencilFunc = NotEqual; + StencilRef = 1; + StencilPass = Keep; + StencilFail = Incr; + + AlphaBlendEnable = True; + + BlendOp = RevSubtract; + SrcBlend = One; + DestBlend = One; + + VertexShader = compile vs_2_0 VS_PointLight_Shadow(); + PixelShader = compile ps_2_0 PS_PointLight_Shadow(); + } +}; + +// ------------------------------------------------------------------------------------------------ +// ----- Technique: DebugDraw --------------------------------------------------------------------- + +technique DebugDraw +{ + pass Solid + { + StencilEnable = False; + AlphaBlendEnable = False; + + VertexShader = compile vs_2_0 VS_Shadow_HullIllumination(); + PixelShader = compile ps_2_0 PS_Shadow_HullIllumination(); + } +}; + +// ------------------------------------------------------------------------------------------------ +// ----- Technique: Blur -------------------------------------------------------------------------- + +float4 PS_BlurH(in float2 texCoord : TEXCOORD0) : COLOR0 +{ + float blurFactor = Bluriness * BlurFactorU / 4.0f; + + return + tex2D(tex0, float2(texCoord.x - blurFactor * 4, texCoord.y) + TexelBias) * 0.05f + + tex2D(tex0, float2(texCoord.x - blurFactor * 3, texCoord.y) + TexelBias) * 0.09f + + tex2D(tex0, float2(texCoord.x - blurFactor * 2, texCoord.y) + TexelBias) * 0.12f + + tex2D(tex0, float2(texCoord.x - blurFactor, texCoord.y) + TexelBias) * 0.15f + + tex2D(tex0, float2(texCoord.x, texCoord.y) + TexelBias) * 0.18f + + tex2D(tex0, float2(texCoord.x + blurFactor, texCoord.y) + TexelBias) * 0.15f + + tex2D(tex0, float2(texCoord.x + blurFactor * 2, texCoord.y) + TexelBias) * 0.12f + + tex2D(tex0, float2(texCoord.x + blurFactor * 3, texCoord.y) + TexelBias) * 0.09f + + tex2D(tex0, float2(texCoord.x + blurFactor * 4, texCoord.y) + TexelBias) * 0.05f; +} + +float4 PS_BlurV(in float2 texCoord : TEXCOORD0) : COLOR0 +{ + float blurFactor = Bluriness * BlurFactorV / 4.0f; + + return + tex2D(tex0, float2(texCoord.x, texCoord.y - blurFactor * 4) + TexelBias) * 0.05f + + tex2D(tex0, float2(texCoord.x, texCoord.y - blurFactor * 3) + TexelBias) * 0.09f + + tex2D(tex0, float2(texCoord.x, texCoord.y - blurFactor * 2) + TexelBias) * 0.12f + + tex2D(tex0, float2(texCoord.x, texCoord.y - blurFactor) + TexelBias) * 0.15f + + tex2D(tex0, float2(texCoord.x, texCoord.y) + TexelBias) * 0.18f + + tex2D(tex0, float2(texCoord.x, texCoord.y + blurFactor) + TexelBias) * 0.15f + + tex2D(tex0, float2(texCoord.x, texCoord.y + blurFactor * 2) + TexelBias) * 0.12f + + tex2D(tex0, float2(texCoord.x, texCoord.y + blurFactor * 3) + TexelBias) * 0.09f + + tex2D(tex0, float2(texCoord.x, texCoord.y + blurFactor * 4) + TexelBias) * 0.05f; +} + +technique Blur +{ + pass HorizontalBlur + { + ScissorTestEnable = False; + StencilEnable = False; + AlphaBlendEnable = False; + + CullMode = CCW; + + VertexShader = compile vs_2_0 VS_ScreenCopy(); + PixelShader = compile ps_2_0 PS_BlurH(); + } + + pass VerticalBlur + { + ScissorTestEnable = False; + StencilEnable = False; + AlphaBlendEnable = False; + + CullMode = CCW; + + VertexShader = compile vs_2_0 VS_ScreenCopy(); + PixelShader = compile ps_2_0 PS_BlurV(); + } +} + + +technique PointLight_Shadow_Fast +{ + pass ShadowStencil + { + StencilEnable = True; + StencilFunc = Always; + StencilPass = Incr; + + ScissorTestEnable = True; + + AlphaBlendEnable = True; + BlendOp = Add; + SrcBlend = DestAlpha; + DestBlend = Zero; + + ColorWriteEnable = Alpha; + + VertexShader = compile vs_2_0 VS_PointLight_Shadow(); + PixelShader = compile ps_2_0 PS_PointLight_Shadow(); + } + + pass Light + { + StencilEnable = True; + StencilFunc = Equal; + StencilRef = 1; + StencilPass = Keep; + + ScissorTestEnable = True; + + AlphaBlendEnable = True; + BlendOp = Add; + SrcBlend = One; + DestBlend = One; + + ColorWriteEnable = Red | Green | Blue; + + VertexShader = compile vs_2_0 VS_SimpleTexture(); + PixelShader = compile ps_2_0 PS_LightTexture(); + } + + pass LightAlpha + { + StencilEnable = True; + StencilFunc = NotEqual; + StencilRef = 1; + StencilPass = Keep; + + ScissorTestEnable = True; + + AlphaBlendEnable = True; + BlendOp = Add; + SrcBlend = DestAlpha; + DestBlend = One; + + VertexShader = compile vs_2_0 VS_SimpleTexture(); + PixelShader = compile ps_2_0 PS_LightTexture(); + } + + pass ClearAlpha + { + StencilEnable = False; + + AlphaBlendEnable = False; + + CullMode = CCW; + + ColorWriteEnable = Alpha; + + VertexShader = compile vs_2_0 VS_ScreenCopy(); + PixelShader = compile ps_2_0 PS_ClearTarget(); + } + +}; \ No newline at end of file diff --git a/Krypton v2.0/KryptonTestbed/KryptonTestbedContent/KryptonTestbedContent.contentproj b/Krypton v2.0/KryptonTestbed/KryptonTestbedContent/KryptonTestbedContent.contentproj new file mode 100755 index 0000000..b218d9d --- /dev/null +++ b/Krypton v2.0/KryptonTestbed/KryptonTestbedContent/KryptonTestbedContent.contentproj @@ -0,0 +1,50 @@ + + + + {EA878F1A-4714-4377-8E6A-4947ACFF386A} + {96E2B04D-8817-42c6-938A-82C39BA4D311};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Debug + x86 + Library + Properties + v4.0 + v4.0 + bin\$(Platform)\$(Configuration) + Content + + + + + + + + + + + KryptonTestbedContent + + + + KryptonEffect + EffectImporter + EffectProcessor + + + + + + + + + + + + + + \ No newline at end of file