diff --git a/DepthsBelow.sln b/DepthsBelow.sln index 176dd07..8f63927 100644 --- a/DepthsBelow.sln +++ b/DepthsBelow.sln @@ -13,7 +13,7 @@ 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}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Krypton", "Krypton\Krypton\Krypton.csproj", "{B1BFCB2A-C001-4DAC-BA7D-B68BF28757F3}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/DepthsBelow/DepthsBelow/Core.cs b/DepthsBelow/DepthsBelow/Core.cs index b924bd5..778e2c5 100755 --- a/DepthsBelow/DepthsBelow/Core.cs +++ b/DepthsBelow/DepthsBelow/Core.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Krypton.Lights; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; @@ -84,16 +85,31 @@ namespace DepthsBelow var light = new Krypton.Lights.Light2D() { Texture = Krypton.LightTextureBuilder.CreatePointLight(this.GraphicsDevice, 512), - Range = (float)(200), + Range = (float)(500), Color = Color.White, Intensity = 1f, Angle = MathHelper.TwoPi, X = 17 * Grid.TileSize, Y = 7 * Grid.TileSize, - Fov = MathHelper.TwoPi, - IsOn = true + Fov = MathHelper.TwoPi / 15, + IsOn = true, + ShadowType = ShadowType.Illuminated }; this.KryptonEngine.Lights.Add(light); + light = new Krypton.Lights.Light2D() + { + Texture = Krypton.LightTextureBuilder.CreatePointLight(this.GraphicsDevice, 512), + Range = (float)(100), + Color = Color.White, + Intensity = 1f, + Angle = MathHelper.TwoPi, + X = 17 * Grid.TileSize, + Y = 7 * Grid.TileSize, + Fov = MathHelper.TwoPi, + IsOn = true, + ShadowType = ShadowType.Illuminated + }; + this.KryptonEngine.Lights.Add(light); // TODO: use this.Content to load your game content here Soldier.LoadContent(this); @@ -147,11 +163,12 @@ namespace DepthsBelow this.KryptonEngine.LightMapPrepare(); GraphicsDevice.Clear(Color.Black); - + /* * Draw game world */ - spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null, null, Camera.Transform); + //GraphicsDevice.BlendState = BlendState.AlphaBlend; + spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.PointClamp, null, null, null, Camera.Transform); // Draw the level Map.Draw(spriteBatch); diff --git a/DepthsBelow/DepthsBelow/DepthsBelow.csproj b/DepthsBelow/DepthsBelow/DepthsBelow.csproj index a6a7b0d..121db3f 100644 --- a/DepthsBelow/DepthsBelow/DepthsBelow.csproj +++ b/DepthsBelow/DepthsBelow/DepthsBelow.csproj @@ -146,7 +146,7 @@ {CD3F949D-54AA-4D38-99DB-92905A375D84} AStar - + {B1BFCB2A-C001-4DAC-BA7D-B68BF28757F3} Krypton diff --git a/DepthsBelow/DepthsBelow/Map.cs b/DepthsBelow/DepthsBelow/Map.cs index b2de6e3..f31cabf 100755 --- a/DepthsBelow/DepthsBelow/Map.cs +++ b/DepthsBelow/DepthsBelow/Map.cs @@ -66,7 +66,22 @@ namespace DepthsBelow var objectLayer = layer as MapObjectLayer; if (objectLayer != null) { - // Parse objects + // Parse lighting engine hulls + /*if (objectLayer.Name == "Opaque") + { + foreach (var hullObject in objectLayer.Objects) + { + Console.WriteLine("Width: " + hullObject.Bounds.Width); + Console.WriteLine("Height: " + hullObject.Bounds.Height); + Console.WriteLine(hullObject.Bounds.X + ", " + hullObject.Bounds.Y); + Krypton.ShadowHull hull = Krypton.ShadowHull.CreateRectangle(new Vector2(hullObject.Bounds.Width, hullObject.Bounds.Height)); + hull.Position.X = hullObject.Bounds.X + hullObject.Bounds.Width / 2; + hull.Position.Y = hullObject.Bounds.Y + hullObject.Bounds.Height / 2; + kryptonEngine.Hulls.Add(hull); + } + }*/ + + // Parse general objects foreach (var mapObject in objectLayer.Objects) { if (mapObject.Type == "SquadStart") @@ -104,6 +119,8 @@ namespace DepthsBelow } } } + + } } } diff --git a/DepthsBelow/DepthsBelowContent/KryptonEffect.fx b/DepthsBelow/DepthsBelowContent/KryptonEffect.fx index 59abc92..0f26190 100755 --- a/DepthsBelow/DepthsBelowContent/KryptonEffect.fx +++ b/DepthsBelow/DepthsBelowContent/KryptonEffect.fx @@ -56,13 +56,6 @@ struct VertexPositionColor float4 Color : COLOR0; }; -struct VertexPositionNormalTexture -{ - float4 Position : POSITION0; - float4 Normal : NORMAL0; - float2 TexCoord : TEXCOORD0; -}; - struct VertexPositionColorTexture { float4 Position : POSITION0; @@ -76,126 +69,38 @@ struct VertexPositionTexture float2 TexCoord : TEXCOORD0; }; -// ------------------------------------------------------------------------------------------------ // -// ----- Techniques ------------------------------------------------------------------------------- // - -// ------------------------------------------------------------------------------------------------ -// ----- Technique: TextureToTarget --------------------------------------------------------------- - -VertexPositionTexture VS_ScreenCopy(VertexPositionTexture input) +struct Color2 +{ + float4 Color0 : COLOR0; + float4 Color1 : COLOR1; +}; + +// ------------------------------------------------------------------------------------------------ // +// ----- Vertex Shaders --------------------------------------------------------------------------- // + +VertexPositionTexture VS_TextureNoTransform(VertexPositionTexture input) { - VertexPositionTexture output; - - output.Position = input.Position; - output.TexCoord = input.TexCoord; - return input; }; -float4 PS_ScreenCopy(VertexPositionTexture input) : COLOR0 +VertexPositionColorTexture VS_ColorTexture(VertexPositionColorTexture input) { - return tex2D(tex0, input.TexCoord + TexelBias); + input.Position = mul(input.Position, Matrix); + + return input; }; -technique TextureToTarget_Add +VertexPositionColor VS_Hull(ShadowHullVertex input) { - 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; + VertexPositionColor 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) +VertexPositionColor VS_Hull_RadialStretch(ShadowHullVertex input) { float2 direction = normalize(LightPosition.xy - input.Position.xy); @@ -213,135 +118,47 @@ VertexPositionColor VS_PointLight_Shadow(ShadowHullVertex input) return output; }; -float4 PS_PointLight_Shadow(float4 input : COLOR0) : COLOR0 +// ------------------------------------------------------------------------------------------------ // +// ----- Pixel Shaders ---------------------------------------------------------------------------- // + +// ------------------------------------------------------------------------------------------------ // +// ----- Techniques ------------------------------------------------------------------------------- // + +float4 PS_Texture(in float2 texCoord : TEXCOORD0) : COLOR0 { - return input; + return tex2D(tex0, texCoord + TexelBias); }; -VertexPositionColor VS_Shadow_HullIllumination(ShadowHullVertex input) +float4 PS_ColorTexture(in float4 color : COLOR0, in float2 texCoord : TEXCOORD0) : COLOR0 { - VertexPositionColor output; - - output.Position = mul(input.Position, Matrix); - output.Color = input.Color; - - return output; + return tex2D(tex0, texCoord) * color; }; -float4 PS_Shadow_HullIllumination() : COLOR0 +float4 PS_LightTexture(VertexPositionColorTexture input) : COLOR0 +{ + return pow(abs(tex2D(tex0, input.TexCoord)) * input.Color, LightIntensityFactor); +}; + +float4 PS_Color(in float4 color : COLOR0) : COLOR0 +{ + return color; +}; + +float4 PS_White() : COLOR0 { return float4(1, 1, 1, 1); }; -technique PointLight_Shadow +float4 PS_Black() : COLOR0 { - 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(); - } + return float4(0, 0, 0, 1); }; -// ------------------------------------------------------------------------------------------------ -// ----- Technique: PointLight_ShadowWithIllumination --------------------------------------------- - -technique PointLight_ShadowWithIllumination +float4 PS_Debug() : COLOR0 { - 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(); - } - + return float4(1, 0, 0, 1); }; -// ------------------------------------------------------------------------------------------------ -// ----- 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; @@ -374,41 +191,92 @@ float4 PS_BlurV(in float2 texCoord : TEXCOORD0) : COLOR0 tex2D(tex0, float2(texCoord.x, texCoord.y + blurFactor * 4) + TexelBias) * 0.05f; } -technique Blur +// ------------------------------------------------------------------------------------------------ +// ----- Technique: TextureToTarget --------------------------------------------------------------- + +technique TextureToTarget_Add { - 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 + pass Pass1 { - StencilEnable = True; - StencilFunc = Always; - StencilPass = Incr; + StencilEnable = False; + + BlendOp = Add; + SrcBlend = One; + DestBlend = One; + + AlphaBlendEnable = True; + + CullMode = CCW; + + VertexShader = compile vs_2_0 VS_TextureNoTransform(); + PixelShader = compile ps_2_0 PS_Texture(); + } +}; + +technique TextureToTarget_Multiply +{ + pass Pass1 + { + StencilEnable = False; + + BlendOp = Add; + SrcBlend = Zero; + DestBlend = SrcColor; + + AlphaBlendEnable = True; + + CullMode = CCW; + + VertexShader = compile vs_2_0 VS_TextureNoTransform(); + PixelShader = compile ps_2_0 PS_Texture(); + } +}; + +technique LightTexture +{ + pass Pass1 + { + StencilEnable = False; + + BlendOp = Add; + DestBlend = Zero; + SrcBlend = SrcAlpha; + + AlphaBlendEnable = True; + + VertexShader = compile vs_2_0 VS_ColorTexture(); + PixelShader = compile ps_2_0 PS_LightTexture(); + } +}; + +// ------------------------------------------------------------------------------------------------ +// ----- Technique: PointLight_Shadow ------------------------------------------------------------- + +technique PointLight_Shadow_Solid +{ + pass Shadow + { + StencilEnable = False; + + ScissorTestEnable = True; + + AlphaBlendEnable = True; + BlendOp = Add; + SrcBlend = DestColor; + DestBlend = Zero; + + ColorWriteEnable = Alpha; + + VertexShader = compile vs_2_0 VS_Hull_RadialStretch(); + PixelShader = compile ps_2_0 PS_Color(); + } +}; + +technique PointLight_Shadow_Illuminated +{ + pass Shadow + { + StencilEnable = False; ScissorTestEnable = True; @@ -419,11 +287,51 @@ technique PointLight_Shadow_Fast ColorWriteEnable = Alpha; - VertexShader = compile vs_2_0 VS_PointLight_Shadow(); - PixelShader = compile ps_2_0 PS_PointLight_Shadow(); + VertexShader = compile vs_2_0 VS_Hull_RadialStretch(); + PixelShader = compile ps_2_0 PS_Color(); } - pass Light + pass Hull + { + StencilEnable = False; + + ScissorTestEnable = True; + + AlphaBlendEnable = True; + BlendOp = Add; + SrcBlend = One; + DestBlend = Zero; + + ColorWriteEnable = Alpha; + + VertexShader = compile vs_2_0 VS_Hull(); + PixelShader = compile ps_2_0 PS_White(); + } +}; + +technique PointLight_Shadow_Occluded +{ + pass Shadow + { + StencilEnable = True; + StencilFunc = Always; + StencilPass = IncrSat; + StencilFail = Keep; + + ScissorTestEnable = True; + + AlphaBlendEnable = True; + BlendOp = Add; + SrcBlend = DestAlpha; + DestBlend = Zero; + + ColorWriteEnable = Alpha; + + VertexShader = compile vs_2_0 VS_Hull_RadialStretch(); + PixelShader = compile ps_2_0 PS_Color(); + } + + pass Hull { StencilEnable = True; StencilFunc = Equal; @@ -435,44 +343,96 @@ technique PointLight_Shadow_Fast AlphaBlendEnable = True; BlendOp = Add; SrcBlend = One; - DestBlend = One; - - ColorWriteEnable = Red | Green | Blue; + DestBlend = Zero; - VertexShader = compile vs_2_0 VS_SimpleTexture(); - PixelShader = compile ps_2_0 PS_LightTexture(); + ColorWriteEnable = Alpha; + + VertexShader = compile vs_2_0 VS_Hull(); + PixelShader = compile ps_2_0 PS_White(); } +}; - pass LightAlpha +technique PointLight_Light +{ + pass Light { - StencilEnable = True; - StencilFunc = NotEqual; - StencilRef = 1; - StencilPass = Keep; + StencilEnable = False; - ScissorTestEnable = True; + ScissorTestEnable = False; AlphaBlendEnable = True; BlendOp = Add; SrcBlend = DestAlpha; DestBlend = One; + + ColorWriteEnable = Red | Green | Blue; - VertexShader = compile vs_2_0 VS_SimpleTexture(); + VertexShader = compile vs_2_0 VS_ColorTexture(); PixelShader = compile ps_2_0 PS_LightTexture(); } +}; - pass ClearAlpha +technique ClearTarget_Alpha +{ + pass Pass1 { StencilEnable = False; + AlphaBlendEnable = True; + BlendOp = Add; + SrcBlend = One; + DestBlend = One; + + ScissorTestEnable = True; + + ColorWriteEnable = Red | Green | Blue | Alpha; + + VertexShader = compile vs_2_0 VS_TextureNoTransform(); + PixelShader = compile ps_2_0 PS_Black(); + } +}; + +// ------------------------------------------------------------------------------------------------ +// ----- Technique: Blur -------------------------------------------------------------------------- + +technique Blur +{ + pass HorizontalBlur + { + ScissorTestEnable = False; + StencilEnable = False; AlphaBlendEnable = False; CullMode = CCW; - - ColorWriteEnable = Alpha; - VertexShader = compile vs_2_0 VS_ScreenCopy(); - PixelShader = compile ps_2_0 PS_ClearTarget(); + VertexShader = compile vs_2_0 VS_TextureNoTransform(); + PixelShader = compile ps_2_0 PS_BlurH(); + } + + pass VerticalBlur + { + ScissorTestEnable = False; + StencilEnable = False; + AlphaBlendEnable = False; + + CullMode = CCW; + + VertexShader = compile vs_2_0 VS_TextureNoTransform(); + PixelShader = compile ps_2_0 PS_BlurV(); + } +} + +// ------------------------------------------------------------------------------------------------ +// ----- Technique: DebugDraw --------------------------------------------------------------------- + +technique DebugDraw +{ + pass Solid + { + StencilEnable = False; + AlphaBlendEnable = False; + + VertexShader = compile vs_2_0 VS_Hull(); + PixelShader = compile ps_2_0 PS_Debug(); } - }; \ No newline at end of file diff --git a/Krypton/Krypton.sln b/Krypton/Krypton.sln new file mode 100755 index 0000000..d0f1d0f --- /dev/null +++ b/Krypton/Krypton.sln @@ -0,0 +1,75 @@ + +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("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3A5C565D-761D-484C-B0BB-57BA2AC2A909}" + ProjectSection(SolutionItems) = preProject + Krypton.vsmdi = Krypton.vsmdi + Local.testsettings = Local.testsettings + TraceAndTestImpact.testsettings = TraceAndTestImpact.testsettings + EndProjectSection +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(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 4 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = https://tfs.codeplex.com/tfs/tfs24 + SccLocalPath0 = . + SccProjectUniqueName1 = Krypton\\Krypton.csproj + SccProjectName1 = Krypton + SccLocalPath1 = Krypton + SccProjectUniqueName2 = KryptonTestbed\\KryptonTestbed\\KryptonTestbed.csproj + SccProjectName2 = KryptonTestbed/KryptonTestbed + SccLocalPath2 = KryptonTestbed\\KryptonTestbed + SccProjectUniqueName3 = KryptonTestbed\\KryptonTestbedContent\\KryptonTestbedContent.contentproj + SccProjectName3 = KryptonTestbed/KryptonTestbedContent + SccLocalPath3 = KryptonTestbed\\KryptonTestbedContent + EndGlobalSection + GlobalSection(TestCaseManagementSettings) = postSolution + CategoryFile = Krypton.vsmdi + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + 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|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 + {E9787BEE-7290-4C74-B919-79DC70AABE87}.Debug|Any CPU.ActiveCfg = Debug|x86 + {E9787BEE-7290-4C74-B919-79DC70AABE87}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {E9787BEE-7290-4C74-B919-79DC70AABE87}.Debug|Mixed Platforms.Build.0 = 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|Mixed Platforms.ActiveCfg = Release|x86 + {E9787BEE-7290-4C74-B919-79DC70AABE87}.Release|Mixed Platforms.Build.0 = 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|Mixed Platforms.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|Mixed Platforms.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/Krypton.vsmdi b/Krypton/Krypton.vsmdi new file mode 100755 index 0000000..7d71384 --- /dev/null +++ b/Krypton/Krypton.vsmdi @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Krypton/Krypton/Common/BoundingRect.cs b/Krypton/Krypton/Common/BoundingRect.cs new file mode 100755 index 0000000..6443c7f --- /dev/null +++ b/Krypton/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/Krypton/Krypton.csproj b/Krypton/Krypton/Krypton.csproj new file mode 100755 index 0000000..0e1209d --- /dev/null +++ b/Krypton/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/Krypton/KryptonEngine.cs b/Krypton/Krypton/KryptonEngine.cs new file mode 100755 index 0000000..9492ca7 --- /dev/null +++ b/Krypton/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 = 0f; + private RenderTarget2D mMapBlur; + + // Light maps + public RenderTarget2D mMap; + private Color mAmbientColor = new Color(0, 0, 0); + 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, 0); + 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/Krypton/KryptonRenderHelper.cs b/Krypton/Krypton/KryptonRenderHelper.cs new file mode 100755 index 0000000..361f6d9 --- /dev/null +++ b/Krypton/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 + + public static readonly 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 = new Color(0, 0, 0, 1-hull.Opacity); + + 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/Krypton/LightTextureBuilder.cs b/Krypton/Krypton/LightTextureBuilder.cs new file mode 100755 index 0000000..dae80a9 --- /dev/null +++ b/Krypton/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/Krypton/Lights/ILight2D.cs b/Krypton/Krypton/Lights/ILight2D.cs new file mode 100755 index 0000000..4e67e34 --- /dev/null +++ b/Krypton/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/Krypton/Lights/Light2D.cs b/Krypton/Krypton/Lights/Light2D.cs new file mode 100755 index 0000000..882f657 --- /dev/null +++ b/Krypton/Krypton/Lights/Light2D.cs @@ -0,0 +1,238 @@ +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 enum ShadowType + { + Solid = 1, + Illuminated = 2, + Occluded = 3 + }; + + 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; + private ShadowType mShadowType = ShadowType.Solid; + + #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); } + } + + /// + /// Gets or sets a value indicating what type of shadows this light should cast + /// + public ShadowType ShadowType + { + get { return this.mShadowType; } + set { this.mShadowType = value; } + } + + #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); + } + } + + // Set the effect and 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)); + + + switch (this.mShadowType) + { + case (ShadowType.Solid): + helper.Effect.CurrentTechnique = helper.Effect.Techniques["PointLight_Shadow_Solid"]; + break; + + case (ShadowType.Illuminated): + helper.Effect.CurrentTechnique = helper.Effect.Techniques["PointLight_Shadow_Illuminated"]; + break; + + case (ShadowType.Occluded): + helper.Effect.CurrentTechnique = helper.Effect.Techniques["PointLight_Shadow_Occluded"]; + break; + + default: + throw new NotImplementedException("Shadow Type does not exist: " + this.mShadowType); + } + + foreach (var pass in helper.Effect.CurrentTechnique.Passes) + { + pass.Apply(); + helper.BufferDraw(); + } + + helper.Effect.CurrentTechnique = helper.Effect.Techniques["PointLight_Light"]; + foreach (var pass in helper.Effect.CurrentTechnique.Passes) + { + pass.Apply(); + helper.DrawClippedFov(this.mPosition, this.mAngle, this.mRange * 2, this.mColor, this.mFov); + } + + helper.Effect.CurrentTechnique = helper.Effect.Techniques["ClearTarget_Alpha"]; + foreach (var pass in helper.Effect.CurrentTechnique.Passes) + { + pass.Apply(); + helper.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, KryptonRenderHelper.UnitQuad, 0, 2); + } + } + + /// + /// Determines if a vector's length is less than a specified value + /// + /// Offset + /// Distance + /// + private static bool IsInRange(Vector2 offset, float dist) + { + // a^2 + b^2 < c^2 ? + return offset.X * offset.X + offset.Y * offset.Y < dist * dist; + } + + /// + /// 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/Krypton/Properties/AssemblyInfo.cs b/Krypton/Krypton/Properties/AssemblyInfo.cs new file mode 100755 index 0000000..bfb5383 --- /dev/null +++ b/Krypton/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/Krypton/ShadowHull.cs b/Krypton/Krypton/ShadowHull.cs new file mode 100755 index 0000000..0d19404 --- /dev/null +++ b/Krypton/Krypton/ShadowHull.cs @@ -0,0 +1,246 @@ +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; + + /// + /// A value indicating how opaque the shadow is, and inversely how much light goes through the hull + /// + public float Opacity = 1f; + + #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/Krypton/ShadowHullPoint.cs b/Krypton/Krypton/ShadowHullPoint.cs new file mode 100755 index 0000000..14e959f --- /dev/null +++ b/Krypton/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/Krypton/ShadowHullVertex.cs b/Krypton/Krypton/ShadowHullVertex.cs new file mode 100755 index 0000000..85978fa --- /dev/null +++ b/Krypton/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/KryptonTestbed/KryptonTestbed/Game.ico b/Krypton/KryptonTestbed/KryptonTestbed/Game.ico new file mode 100755 index 0000000..8cff41e Binary files /dev/null and b/Krypton/KryptonTestbed/KryptonTestbed/Game.ico differ diff --git a/Krypton/KryptonTestbed/KryptonTestbed/GameKryptonDemo.cs b/Krypton/KryptonTestbed/KryptonTestbed/GameKryptonDemo.cs new file mode 100755 index 0000000..4dec1d8 --- /dev/null +++ b/Krypton/KryptonTestbed/KryptonTestbed/GameKryptonDemo.cs @@ -0,0 +1,313 @@ +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 = 25; + private int mNumHorzontalHulls = 20; + private int mNumVerticalHulls = 20; + + private float mVerticalUnits = 50; + + private Light2D mLight2D; + + 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); + + // Create a light we can control + this.mLight2D = new Light2D() + { + Texture = this.mLightTexture, + X = 0, + Y = 0, + Range = 25, + Color = Color.Multiply(Color.CornflowerBlue, 2.0f), + ShadowType = ShadowType.Occluded + }; + + this.krypton.Lights.Add(this.mLight2D); + } + + 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 + 5), + 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 + 0.5f) * w) / x) - w / 2 + (j % 2 == 0 ? w / x / 2 : 0); + var posY = (((j + 0.5f) * h) / y) - h / 2; // +(i % 2 == 0 ? h / y / 4 : 0); + + var hull = ShadowHull.CreateRectangle(Vector2.One*1f); + 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; + } + } + + var keyboard = Keyboard.GetState(); + + // Light Position Controls + if (keyboard.IsKeyDown(Keys.Up)) + this.mLight2D.Y += t * speed; + + if (keyboard.IsKeyDown(Keys.Down)) + this.mLight2D.Y -= t * speed; + + if (keyboard.IsKeyDown(Keys.Right)) + this.mLight2D.X += t * speed; + + if (keyboard.IsKeyDown(Keys.Left)) + this.mLight2D.X -= t * speed; + + // Shadow Type Controls + if (keyboard.IsKeyDown(Keys.D1)) + this.mLight2D.ShadowType = ShadowType.Solid; + + if (keyboard.IsKeyDown(Keys.D2)) + this.mLight2D.ShadowType = ShadowType.Illuminated; + + if (keyboard.IsKeyDown(Keys.D3)) + this.mLight2D.ShadowType = ShadowType.Occluded; + + // Shadow Opacity Controls + if (keyboard.IsKeyDown(Keys.O)) + this.krypton.Hulls.ForEach(x => x.Opacity = MathHelper.Clamp(x.Opacity - t, 0, 1)); + + if (keyboard.IsKeyDown(Keys.P)) + this.krypton.Hulls.ForEach(x => x.Opacity = MathHelper.Clamp(x.Opacity + t, 0, 1)); + + 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); + Matrix wvp = world * view * projection; + + // 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 = wvp; + 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 hulls + this.DebugDrawHulls(true); + + // 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); + + if (Keyboard.GetState().IsKeyDown(Keys.H)) + { + // Draw hulls + this.DebugDrawHulls(false); + } + + if (Keyboard.GetState().IsKeyDown(Keys.L)) + { + // Draw hulls + this.DebugDrawLights(); + } + + base.Draw(gameTime); + } + + private void DebugDrawHulls(bool drawSolid) + { + this.krypton.RenderHelper.Effect.CurrentTechnique = this.krypton.RenderHelper.Effect.Techniques["DebugDraw"]; + + this.GraphicsDevice.RasterizerState = new RasterizerState() + { + CullMode = CullMode.None, + FillMode = drawSolid ? FillMode.Solid : FillMode.WireFrame, + }; + + // 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(); + } + + } + + private void DebugDrawLights() + { + this.krypton.RenderHelper.Effect.CurrentTechnique = this.krypton.RenderHelper.Effect.Techniques["DebugDraw"]; + + this.GraphicsDevice.RasterizerState = new RasterizerState() + { + CullMode = CullMode.None, + FillMode = FillMode.WireFrame, + }; + + // Clear the helpers vertices + 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/KryptonTestbed/KryptonTestbed/GameThumbnail.png b/Krypton/KryptonTestbed/KryptonTestbed/GameThumbnail.png new file mode 100755 index 0000000..462311a Binary files /dev/null and b/Krypton/KryptonTestbed/KryptonTestbed/GameThumbnail.png differ diff --git a/Krypton/KryptonTestbed/KryptonTestbed/KryptonTestbed.csproj b/Krypton/KryptonTestbed/KryptonTestbed/KryptonTestbed.csproj new file mode 100755 index 0000000..b581550 --- /dev/null +++ b/Krypton/KryptonTestbed/KryptonTestbed/KryptonTestbed.csproj @@ -0,0 +1,149 @@ + + + + {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 + SAK + SAK + SAK + SAK + 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/KryptonTestbed/KryptonTestbed/Program.cs b/Krypton/KryptonTestbed/KryptonTestbed/Program.cs new file mode 100755 index 0000000..bbc294f --- /dev/null +++ b/Krypton/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/KryptonTestbed/KryptonTestbed/Properties/AssemblyInfo.cs b/Krypton/KryptonTestbed/KryptonTestbed/Properties/AssemblyInfo.cs new file mode 100755 index 0000000..a9780bc --- /dev/null +++ b/Krypton/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/KryptonTestbed/KryptonTestbedContent/KryptonEffect.fx b/Krypton/KryptonTestbed/KryptonTestbedContent/KryptonEffect.fx new file mode 100755 index 0000000..0f26190 --- /dev/null +++ b/Krypton/KryptonTestbed/KryptonTestbedContent/KryptonEffect.fx @@ -0,0 +1,438 @@ +// ------------------------------------------------------------------------------------------------ // +// ----- 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 VertexPositionColorTexture +{ + float4 Position : POSITION0; + float4 Color : COLOR0; + float2 TexCoord : TEXCOORD0; +}; + +struct VertexPositionTexture +{ + float4 Position : POSITION0; + float2 TexCoord : TEXCOORD0; +}; + +struct Color2 +{ + float4 Color0 : COLOR0; + float4 Color1 : COLOR1; +}; + +// ------------------------------------------------------------------------------------------------ // +// ----- Vertex Shaders --------------------------------------------------------------------------- // + +VertexPositionTexture VS_TextureNoTransform(VertexPositionTexture input) +{ + return input; +}; + +VertexPositionColorTexture VS_ColorTexture(VertexPositionColorTexture input) +{ + input.Position = mul(input.Position, Matrix); + + return input; +}; + +VertexPositionColor VS_Hull(ShadowHullVertex input) +{ + VertexPositionColor output; + + output.Position = mul(input.Position, Matrix); + output.Color = input.Color; + + return output; +}; + +VertexPositionColor VS_Hull_RadialStretch(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; +}; + +// ------------------------------------------------------------------------------------------------ // +// ----- Pixel Shaders ---------------------------------------------------------------------------- // + +// ------------------------------------------------------------------------------------------------ // +// ----- Techniques ------------------------------------------------------------------------------- // + +float4 PS_Texture(in float2 texCoord : TEXCOORD0) : COLOR0 +{ + return tex2D(tex0, texCoord + TexelBias); +}; + +float4 PS_ColorTexture(in float4 color : COLOR0, in float2 texCoord : TEXCOORD0) : COLOR0 +{ + return tex2D(tex0, texCoord) * color; +}; + +float4 PS_LightTexture(VertexPositionColorTexture input) : COLOR0 +{ + return pow(abs(tex2D(tex0, input.TexCoord)) * input.Color, LightIntensityFactor); +}; + +float4 PS_Color(in float4 color : COLOR0) : COLOR0 +{ + return color; +}; + +float4 PS_White() : COLOR0 +{ + return float4(1, 1, 1, 1); +}; + +float4 PS_Black() : COLOR0 +{ + return float4(0, 0, 0, 1); +}; + +float4 PS_Debug() : COLOR0 +{ + return float4(1, 0, 0, 1); +}; + +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: TextureToTarget --------------------------------------------------------------- + +technique TextureToTarget_Add +{ + pass Pass1 + { + StencilEnable = False; + + BlendOp = Add; + SrcBlend = One; + DestBlend = One; + + AlphaBlendEnable = True; + + CullMode = CCW; + + VertexShader = compile vs_2_0 VS_TextureNoTransform(); + PixelShader = compile ps_2_0 PS_Texture(); + } +}; + +technique TextureToTarget_Multiply +{ + pass Pass1 + { + StencilEnable = False; + + BlendOp = Add; + SrcBlend = Zero; + DestBlend = SrcColor; + + AlphaBlendEnable = True; + + CullMode = CCW; + + VertexShader = compile vs_2_0 VS_TextureNoTransform(); + PixelShader = compile ps_2_0 PS_Texture(); + } +}; + +technique LightTexture +{ + pass Pass1 + { + StencilEnable = False; + + BlendOp = Add; + DestBlend = Zero; + SrcBlend = SrcAlpha; + + AlphaBlendEnable = True; + + VertexShader = compile vs_2_0 VS_ColorTexture(); + PixelShader = compile ps_2_0 PS_LightTexture(); + } +}; + +// ------------------------------------------------------------------------------------------------ +// ----- Technique: PointLight_Shadow ------------------------------------------------------------- + +technique PointLight_Shadow_Solid +{ + pass Shadow + { + StencilEnable = False; + + ScissorTestEnable = True; + + AlphaBlendEnable = True; + BlendOp = Add; + SrcBlend = DestColor; + DestBlend = Zero; + + ColorWriteEnable = Alpha; + + VertexShader = compile vs_2_0 VS_Hull_RadialStretch(); + PixelShader = compile ps_2_0 PS_Color(); + } +}; + +technique PointLight_Shadow_Illuminated +{ + pass Shadow + { + StencilEnable = False; + + ScissorTestEnable = True; + + AlphaBlendEnable = True; + BlendOp = Add; + SrcBlend = DestAlpha; + DestBlend = Zero; + + ColorWriteEnable = Alpha; + + VertexShader = compile vs_2_0 VS_Hull_RadialStretch(); + PixelShader = compile ps_2_0 PS_Color(); + } + + pass Hull + { + StencilEnable = False; + + ScissorTestEnable = True; + + AlphaBlendEnable = True; + BlendOp = Add; + SrcBlend = One; + DestBlend = Zero; + + ColorWriteEnable = Alpha; + + VertexShader = compile vs_2_0 VS_Hull(); + PixelShader = compile ps_2_0 PS_White(); + } +}; + +technique PointLight_Shadow_Occluded +{ + pass Shadow + { + StencilEnable = True; + StencilFunc = Always; + StencilPass = IncrSat; + StencilFail = Keep; + + ScissorTestEnable = True; + + AlphaBlendEnable = True; + BlendOp = Add; + SrcBlend = DestAlpha; + DestBlend = Zero; + + ColorWriteEnable = Alpha; + + VertexShader = compile vs_2_0 VS_Hull_RadialStretch(); + PixelShader = compile ps_2_0 PS_Color(); + } + + pass Hull + { + StencilEnable = True; + StencilFunc = Equal; + StencilRef = 1; + StencilPass = Keep; + + ScissorTestEnable = True; + + AlphaBlendEnable = True; + BlendOp = Add; + SrcBlend = One; + DestBlend = Zero; + + ColorWriteEnable = Alpha; + + VertexShader = compile vs_2_0 VS_Hull(); + PixelShader = compile ps_2_0 PS_White(); + } +}; + +technique PointLight_Light +{ + pass Light + { + StencilEnable = False; + + ScissorTestEnable = False; + + AlphaBlendEnable = True; + BlendOp = Add; + SrcBlend = DestAlpha; + DestBlend = One; + + ColorWriteEnable = Red | Green | Blue; + + VertexShader = compile vs_2_0 VS_ColorTexture(); + PixelShader = compile ps_2_0 PS_LightTexture(); + } +}; + +technique ClearTarget_Alpha +{ + pass Pass1 + { + StencilEnable = False; + + AlphaBlendEnable = True; + BlendOp = Add; + SrcBlend = One; + DestBlend = One; + + ScissorTestEnable = True; + + ColorWriteEnable = Red | Green | Blue | Alpha; + + VertexShader = compile vs_2_0 VS_TextureNoTransform(); + PixelShader = compile ps_2_0 PS_Black(); + } +}; + +// ------------------------------------------------------------------------------------------------ +// ----- Technique: Blur -------------------------------------------------------------------------- + +technique Blur +{ + pass HorizontalBlur + { + ScissorTestEnable = False; + StencilEnable = False; + AlphaBlendEnable = False; + + CullMode = CCW; + + VertexShader = compile vs_2_0 VS_TextureNoTransform(); + PixelShader = compile ps_2_0 PS_BlurH(); + } + + pass VerticalBlur + { + ScissorTestEnable = False; + StencilEnable = False; + AlphaBlendEnable = False; + + CullMode = CCW; + + VertexShader = compile vs_2_0 VS_TextureNoTransform(); + PixelShader = compile ps_2_0 PS_BlurV(); + } +} + +// ------------------------------------------------------------------------------------------------ +// ----- Technique: DebugDraw --------------------------------------------------------------------- + +technique DebugDraw +{ + pass Solid + { + StencilEnable = False; + AlphaBlendEnable = False; + + VertexShader = compile vs_2_0 VS_Hull(); + PixelShader = compile ps_2_0 PS_Debug(); + } +}; \ No newline at end of file diff --git a/Krypton/KryptonTestbed/KryptonTestbedContent/KryptonTestbedContent.contentproj b/Krypton/KryptonTestbed/KryptonTestbedContent/KryptonTestbedContent.contentproj new file mode 100755 index 0000000..79f96ad --- /dev/null +++ b/Krypton/KryptonTestbed/KryptonTestbedContent/KryptonTestbedContent.contentproj @@ -0,0 +1,46 @@ + + + + {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 + SAK + SAK + SAK + SAK + + + KryptonTestbedContent + + + + KryptonEffect + EffectImporter + EffectProcessor + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Krypton/Local.testsettings b/Krypton/Local.testsettings new file mode 100755 index 0000000..aeb5241 --- /dev/null +++ b/Krypton/Local.testsettings @@ -0,0 +1,10 @@ + + + These are default test settings for a local test run. + + + + + + + \ No newline at end of file diff --git a/Krypton/TraceAndTestImpact.testsettings b/Krypton/TraceAndTestImpact.testsettings new file mode 100755 index 0000000..088e7d5 --- /dev/null +++ b/Krypton/TraceAndTestImpact.testsettings @@ -0,0 +1,9 @@ + + + These are test settings for Trace and Test Impact. + + + + + + \ No newline at end of file