using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Krypton.Common;
namespace Krypton.Lights
{
public class Light2D : ILight2D
{
private bool mIsOn = true;
private Vector2 mPosition = Vector2.Zero;
private float mAngle = 0;
private Texture2D mTexture = null;
private Color mColor = Color.White;
private float mRange = 1;
private float mFov = MathHelper.TwoPi;
private float mIntensity = 1;
#region Parameters
///
/// The light's position
///
public Vector2 Position
{
get { return this.mPosition; }
set { this.mPosition = value; }
}
///
/// The X coordinate of the light's position
///
public float X
{
get { return this.mPosition.X; }
set { this.mPosition.X = value; }
}
///
/// The Y coordinate of the light's position
///
public float Y
{
get { return this.mPosition.Y; }
set { this.mPosition.Y = value; }
}
///
/// The light's angle
///
public float Angle
{
get { return this.mAngle; }
set { this.mAngle = value; }
}
///
/// The texture used as the base light map, from which shadows will be subtracted
///
public Texture2D Texture
{
get { return this.mTexture; }
set { this.mTexture = value; }
}
///
/// The color used to tint the light's texture
///
public Color Color
{
get { return this.mColor; }
set { this.mColor = value; }
}
///
/// The light's maximum radius (or "half width", if you will)
///
public float Range
{
get { return this.mRange; }
set { this.mRange = value; }
}
///
/// Gets or sets the light's field of view. This value determines the angles at which the light will cease to draw
///
public float Fov
{
get { return this.mFov; }
set
{
this.mFov = MathHelper.Clamp(value, 0, MathHelper.TwoPi);
}
}
///
/// Gets or sets the light's intensity. Think pixel = (tex * color) ^ (1 / intensity)
///
public float Intensity
{
get { return this.mIntensity; }
set { this.mIntensity = MathHelper.Clamp(value, 0.01f, 3f); }
}
#endregion Parameters
///
/// Gets or sets a value indicating weither or not to draw the light
///
public bool IsOn
{
get { return this.mIsOn; }
set { this.mIsOn = value; }
}
///
/// Draws shadows from the light's position outward
///
/// A render helper for drawing shadows
/// The shadow hulls used to draw shadows
public void Draw(KryptonRenderHelper helper, List hulls)
{
// Draw the light only if it's on
if (!this.mIsOn)
return;
// Make sure we only render the following hulls
helper.ShadowHullVertices.Clear();
helper.ShadowHullIndicies.Clear();
// Loop through each hull
foreach (ShadowHull hull in hulls)
{
//if(hull.Bounds.Intersects(this.Bounds))
// Add the hulls to the buffer only if they are within the light's range
if (hull.Visible && Light2D.IsInRange(hull.Position - this.Position, hull.MaxRadius * Math.Max(hull.Scale.X, hull.Scale.Y) + this.Range))
{
helper.BufferAddShadowHull(hull);
}
}
var shadowEffect = helper.Effect.Techniques["PointLight_Shadow_Fast"];
helper.Effect.CurrentTechnique = shadowEffect;
// Set the effect parameters
helper.Effect.Parameters["LightPosition"].SetValue(this.mPosition);
helper.Effect.Parameters["Texture0"].SetValue(this.mTexture);
helper.Effect.Parameters["LightIntensityFactor"].SetValue(1 / (this.mIntensity * this.mIntensity));
shadowEffect.Passes["ShadowStencil"].Apply();
helper.BufferDraw();
shadowEffect.Passes["Light"].Apply();
helper.DrawClippedFov(this.mPosition, this.mAngle, this.mRange * 2, this.mColor, this.mFov);
}
///
/// Determines if a vector's length is less than a specified value
///
/// Offset
/// Distance
///
private static bool IsInRange(Vector2 offset, float dist)
{
if (offset.X * offset.X + offset.Y * offset.Y < dist * dist)
return true;
return false;
}
///
/// Gets the world-space bounds which contain the light
///
public BoundingRect Bounds
{
get
{
BoundingRect rect;
rect.Min.X = this.mPosition.X - this.mRange;
rect.Min.Y = this.mPosition.Y - this.mRange;
rect.Max.X = this.mPosition.X + this.mRange;
rect.Max.Y = this.mPosition.Y + this.mRange;
return rect;
}
}
}
}