diff --git a/MonoGame.Framework/BoundingBox.cs b/MonoGame.Framework/BoundingBox.cs index 1b5cd71943a..6edb6f0e2b7 100644 --- a/MonoGame.Framework/BoundingBox.cs +++ b/MonoGame.Framework/BoundingBox.cs @@ -38,525 +38,569 @@ Olivier Dufour (Duff) #region Using Statements using System; using System.Collections.Generic; -using System.ComponentModel; using System.Runtime.Serialization; #endregion namespace Microsoft.Xna.Framework { - [DataContract] - public struct BoundingBox : IEquatable - { - #region Public Fields - - [DataMember] - public Vector3 Min; - - [DataMember] - public Vector3 Max; - - public const int CornerCount = 8; - - #endregion - - #region Private Static Variables - - private static readonly Vector3 MaxVector3 = new Vector3(float.MaxValue); - private static readonly Vector3 MinVector3 = new Vector3(float.MinValue); - - #endregion - - #region Public Constructors - - public BoundingBox(Vector3 min, Vector3 max) - { - this.Min = min; - this.Max = max; - } - - #endregion - - #region Public Methods - - public ContainmentType Contains(BoundingBox box) - { - //test if all corner is in the same side of a face by just checking min and max - if (box.Max.X < Min.X - || box.Min.X > Max.X - || box.Max.Y < Min.Y - || box.Min.Y > Max.Y - || box.Max.Z < Min.Z - || box.Min.Z > Max.Z) - return ContainmentType.Disjoint; - - - if (box.Min.X >= Min.X - && box.Max.X <= Max.X - && box.Min.Y >= Min.Y - && box.Max.Y <= Max.Y - && box.Min.Z >= Min.Z - && box.Max.Z <= Max.Z) - return ContainmentType.Contains; - - return ContainmentType.Intersects; - } - - public void Contains(ref BoundingBox box, out ContainmentType result) - { - result = Contains(box); - } - - public ContainmentType Contains(BoundingFrustum frustum) - { - //TODO: bad done here need a fix. - //Because question is not frustum contain box but reverse and this is not the same - int i; - ContainmentType contained; - Vector3[] corners = frustum.GetCorners(); - - // First we check if frustum is in box - for (i = 0; i < corners.Length; i++) - { - this.Contains(ref corners[i], out contained); - if (contained == ContainmentType.Disjoint) - break; - } - - if (i == corners.Length) // This means we checked all the corners and they were all contain or instersect - return ContainmentType.Contains; - - if (i != 0) // if i is not equal to zero, we can fastpath and say that this box intersects - return ContainmentType.Intersects; - - - // If we get here, it means the first (and only) point we checked was actually contained in the frustum. - // So we assume that all other points will also be contained. If one of the points is disjoint, we can - // exit immediately saying that the result is Intersects - i++; - for (; i < corners.Length; i++) - { - this.Contains(ref corners[i], out contained); - if (contained != ContainmentType.Contains) - return ContainmentType.Intersects; - - } - - // If we get here, then we know all the points were actually contained, therefore result is Contains - return ContainmentType.Contains; - } - - public ContainmentType Contains(BoundingSphere sphere) - { - if (sphere.Center.X - Min.X >= sphere.Radius - && sphere.Center.Y - Min.Y >= sphere.Radius - && sphere.Center.Z - Min.Z >= sphere.Radius - && Max.X - sphere.Center.X >= sphere.Radius - && Max.Y - sphere.Center.Y >= sphere.Radius - && Max.Z - sphere.Center.Z >= sphere.Radius) - return ContainmentType.Contains; - - double dmin = 0; - - double e = sphere.Center.X - Min.X; - if (e < 0) - { - if (e < -sphere.Radius) - { - return ContainmentType.Disjoint; - } - dmin += e * e; - } - else - { - e = sphere.Center.X - Max.X; - if (e > 0) - { - if (e > sphere.Radius) - { - return ContainmentType.Disjoint; - } - dmin += e * e; - } - } - - e = sphere.Center.Y - Min.Y; - if (e < 0) - { - if (e < -sphere.Radius) - { - return ContainmentType.Disjoint; - } - dmin += e * e; - } - else - { - e = sphere.Center.Y - Max.Y; - if (e > 0) - { - if (e > sphere.Radius) - { - return ContainmentType.Disjoint; - } - dmin += e * e; - } - } - - e = sphere.Center.Z - Min.Z; - if (e < 0) - { - if (e < -sphere.Radius) - { - return ContainmentType.Disjoint; - } - dmin += e * e; - } - else - { - e = sphere.Center.Z - Max.Z; - if (e > 0) - { - if (e > sphere.Radius) - { - return ContainmentType.Disjoint; - } - dmin += e * e; - } - } - - if (dmin <= sphere.Radius * sphere.Radius) - return ContainmentType.Intersects; - - return ContainmentType.Disjoint; - } - - public void Contains(ref BoundingSphere sphere, out ContainmentType result) - { - result = this.Contains(sphere); - } - - public ContainmentType Contains(Vector3 point) - { - ContainmentType result; - this.Contains(ref point, out result); - return result; - } - - public void Contains(ref Vector3 point, out ContainmentType result) - { - //first we get if point is out of box - if (point.X < this.Min.X - || point.X > this.Max.X - || point.Y < this.Min.Y - || point.Y > this.Max.Y - || point.Z < this.Min.Z - || point.Z > this.Max.Z) - { - result = ContainmentType.Disjoint; - }//or if point is on box because coordonate of point is lesser or equal - else if (point.X == this.Min.X - || point.X == this.Max.X - || point.Y == this.Min.Y - || point.Y == this.Max.Y - || point.Z == this.Min.Z - || point.Z == this.Max.Z) - result = ContainmentType.Intersects; - else - result = ContainmentType.Contains; - } - - public Vector3[] GetCorners() - { - return new Vector3[] { - new Vector3(this.Min.X, this.Max.Y, this.Max.Z), - new Vector3(this.Max.X, this.Max.Y, this.Max.Z), - new Vector3(this.Max.X, this.Min.Y, this.Max.Z), - new Vector3(this.Min.X, this.Min.Y, this.Max.Z), - new Vector3(this.Min.X, this.Max.Y, this.Min.Z), - new Vector3(this.Max.X, this.Max.Y, this.Min.Z), - new Vector3(this.Max.X, this.Min.Y, this.Min.Z), - new Vector3(this.Min.X, this.Min.Y, this.Min.Z) - }; - } - - public void GetCorners(Vector3[] corners) - { - if (corners == null) - { - throw new ArgumentNullException("corners"); - } - if (corners.Length < 8) - { - throw new ArgumentOutOfRangeException("corners", "Not Enought Corners"); - } - corners[0].X = this.Min.X; - corners[0].Y = this.Max.Y; - corners[0].Z = this.Max.Z; - corners[1].X = this.Max.X; - corners[1].Y = this.Max.Y; - corners[1].Z = this.Max.Z; - corners[2].X = this.Max.X; - corners[2].Y = this.Min.Y; - corners[2].Z = this.Max.Z; - corners[3].X = this.Min.X; - corners[3].Y = this.Min.Y; - corners[3].Z = this.Max.Z; - corners[4].X = this.Min.X; - corners[4].Y = this.Max.Y; - corners[4].Z = this.Min.Z; - corners[5].X = this.Max.X; - corners[5].Y = this.Max.Y; - corners[5].Z = this.Min.Z; - corners[6].X = this.Max.X; - corners[6].Y = this.Min.Y; - corners[6].Z = this.Min.Z; - corners[7].X = this.Min.X; - corners[7].Y = this.Min.Y; - corners[7].Z = this.Min.Z; - } - - public bool Intersects(BoundingBox box) - { - bool result; - Intersects(ref box, out result); - return result; - } - - public void Intersects(ref BoundingBox box, out bool result) - { - if ((this.Max.X >= box.Min.X) && (this.Min.X <= box.Max.X)) - { - if ((this.Max.Y < box.Min.Y) || (this.Min.Y > box.Max.Y)) - { - result = false; - return; - } - - result = (this.Max.Z >= box.Min.Z) && (this.Min.Z <= box.Max.Z); - return; - } - - result = false; - return; - } - - public bool Intersects(BoundingFrustum frustum) - { - return frustum.Intersects(this); - } - - public bool Intersects(BoundingSphere sphere) - { - if (sphere.Center.X - Min.X > sphere.Radius - && sphere.Center.Y - Min.Y > sphere.Radius - && sphere.Center.Z - Min.Z > sphere.Radius - && Max.X - sphere.Center.X > sphere.Radius - && Max.Y - sphere.Center.Y > sphere.Radius - && Max.Z - sphere.Center.Z > sphere.Radius) - return true; - - double dmin = 0; - - if (sphere.Center.X - Min.X <= sphere.Radius) - dmin += (sphere.Center.X - Min.X) * (sphere.Center.X - Min.X); - else if (Max.X - sphere.Center.X <= sphere.Radius) - dmin += (sphere.Center.X - Max.X) * (sphere.Center.X - Max.X); - - if (sphere.Center.Y - Min.Y <= sphere.Radius) - dmin += (sphere.Center.Y - Min.Y) * (sphere.Center.Y - Min.Y); - else if (Max.Y - sphere.Center.Y <= sphere.Radius) - dmin += (sphere.Center.Y - Max.Y) * (sphere.Center.Y - Max.Y); - - if (sphere.Center.Z - Min.Z <= sphere.Radius) - dmin += (sphere.Center.Z - Min.Z) * (sphere.Center.Z - Min.Z); - else if (Max.Z - sphere.Center.Z <= sphere.Radius) - dmin += (sphere.Center.Z - Max.Z) * (sphere.Center.Z - Max.Z); - - if (dmin <= sphere.Radius * sphere.Radius) - return true; - - return false; - } - - public void Intersects(ref BoundingSphere sphere, out bool result) - { - result = Intersects(sphere); - } - - public PlaneIntersectionType Intersects(Plane plane) - { - PlaneIntersectionType result; - Intersects(ref plane, out result); - return result; - } - - public void Intersects(ref Plane plane, out PlaneIntersectionType result) - { - // See http://zach.in.tu-clausthal.de/teaching/cg_literatur/lighthouse3d_view_frustum_culling/index.html - - Vector3 positiveVertex; - Vector3 negativeVertex; - - if (plane.Normal.X >= 0) - { - positiveVertex.X = Max.X; - negativeVertex.X = Min.X; - } - else - { - positiveVertex.X = Min.X; - negativeVertex.X = Max.X; - } - - if (plane.Normal.Y >= 0) - { - positiveVertex.Y = Max.Y; - negativeVertex.Y = Min.Y; - } - else - { - positiveVertex.Y = Min.Y; - negativeVertex.Y = Max.Y; - } - - if (plane.Normal.Z >= 0) - { - positiveVertex.Z = Max.Z; - negativeVertex.Z = Min.Z; - } - else - { - positiveVertex.Z = Min.Z; - negativeVertex.Z = Max.Z; - } - - var distance = Vector3.Dot(plane.Normal, negativeVertex) + plane.D; - if (distance > 0) - { - result = PlaneIntersectionType.Front; - return; - } - - distance = Vector3.Dot(plane.Normal, positiveVertex) + plane.D; - if (distance < 0) - { - result = PlaneIntersectionType.Back; - return; - } - - result = PlaneIntersectionType.Intersecting; - } - - public Nullable Intersects(Ray ray) - { - return ray.Intersects(this); - } - - public void Intersects(ref Ray ray, out Nullable result) - { - result = Intersects(ray); - } - - public bool Equals(BoundingBox other) - { - return (this.Min == other.Min) && (this.Max == other.Max); - } - - #endregion - - #region Public Static Methods - - /// - /// Create a bounding box from the given list of points. - /// - /// The list of Vector3 instances defining the point cloud to bound - /// A bounding box that encapsulates the given point cloud. - /// Thrown if the given list has no points. - public static BoundingBox CreateFromPoints(IEnumerable points) - { - if (points == null) - throw new ArgumentNullException(); - - var empty = true; - var minVec = MaxVector3; - var maxVec = MinVector3; - foreach (var ptVector in points) - { - minVec.X = (minVec.X < ptVector.X) ? minVec.X : ptVector.X; - minVec.Y = (minVec.Y < ptVector.Y) ? minVec.Y : ptVector.Y; - minVec.Z = (minVec.Z < ptVector.Z) ? minVec.Z : ptVector.Z; - - maxVec.X = (maxVec.X > ptVector.X) ? maxVec.X : ptVector.X; - maxVec.Y = (maxVec.Y > ptVector.Y) ? maxVec.Y : ptVector.Y; - maxVec.Z = (maxVec.Z > ptVector.Z) ? maxVec.Z : ptVector.Z; - - empty = false; - } - if (empty) - throw new ArgumentException(); - - return new BoundingBox(minVec, maxVec); - } - - public static BoundingBox CreateFromSphere(BoundingSphere sphere) - { - BoundingBox result; - CreateFromSphere(ref sphere, out result); - return result; - } - - public static void CreateFromSphere(ref BoundingSphere sphere, out BoundingBox result) - { - var corner = new Vector3(sphere.Radius); - result.Min = sphere.Center - corner; - result.Max = sphere.Center + corner; - } - - public static BoundingBox CreateMerged(BoundingBox original, BoundingBox additional) - { - BoundingBox result; - CreateMerged(ref original, ref additional, out result); - return result; - } - - public static void CreateMerged(ref BoundingBox original, ref BoundingBox additional, out BoundingBox result) - { - result.Min.X = Math.Min(original.Min.X, additional.Min.X); - result.Min.Y = Math.Min(original.Min.Y, additional.Min.Y); - result.Min.Z = Math.Min(original.Min.Z, additional.Min.Z); - result.Max.X = Math.Max(original.Max.X, additional.Max.X); - result.Max.Y = Math.Max(original.Max.Y, additional.Max.Y); - result.Max.Z = Math.Max(original.Max.Z, additional.Max.Z); - } - - #endregion - - #region Public Static Operators and Override Methods - - public override bool Equals(object obj) - { - return (obj is BoundingBox) ? this.Equals((BoundingBox)obj) : false; - } - - public override int GetHashCode() - { - return this.Min.GetHashCode() + this.Max.GetHashCode(); - } - - public static bool operator ==(BoundingBox a, BoundingBox b) - { - return a.Equals(b); - } - - public static bool operator !=(BoundingBox a, BoundingBox b) - { - return !a.Equals(b); - } - - public override string ToString() - { - return string.Format("{{Min:{0} Max:{1}}}", this.Min.ToString(), this.Max.ToString()); - } - - #endregion - } + [DataContract] + public struct BoundingBox : IEquatable + { + #region Public Fields + + [DataMember] + public Vector3 Min; + + [DataMember] + public Vector3 Max; + + public const int CornerCount = 8; + + #endregion + + #region Private Static Variables + + private static readonly Vector3 MaxVector3 = new Vector3(float.MaxValue); + private static readonly Vector3 MinVector3 = new Vector3(float.MinValue); + + #endregion + + #region Public Constructors + + public BoundingBox(Vector3 min, Vector3 max) + { + this.Min = min; + this.Max = max; + } + + #endregion + + #region Public Methods + + public void Contains(ref BoundingBox box, out ContainmentType result) + { + result = Contains(box); + } + + public void Contains(ref BoundingSphere sphere, out ContainmentType result) + { + result = this.Contains(sphere); + } + + public ContainmentType Contains(Vector3 point) + { + ContainmentType result; + this.Contains(ref point, out result); + return result; + } + + public ContainmentType Contains(BoundingBox box) + { + // Test if all corner is in the same side of a face by just checking min and max + if ( box.Max.X < Min.X + || box.Min.X > Max.X + || box.Max.Y < Min.Y + || box.Min.Y > Max.Y + || box.Max.Z < Min.Z + || box.Min.Z > Max.Z ) + { + return ContainmentType.Disjoint; + } + + + if ( box.Min.X >= Min.X + && box.Max.X <= Max.X + && box.Min.Y >= Min.Y + && box.Max.Y <= Max.Y + && box.Min.Z >= Min.Z + && box.Max.Z <= Max.Z ) + { + return ContainmentType.Contains; + } + + return ContainmentType.Intersects; + } + + public ContainmentType Contains(BoundingFrustum frustum) + { + /* TODO: bad done here need a fix. + * Because question is not frustum contain box but reverse and this is not the same + */ + int i; + ContainmentType contained; + Vector3[] corners = frustum.GetCorners(); + + // First we check if frustum is in box + for (i = 0; i < corners.Length; i += 1) + { + this.Contains(ref corners[i], out contained); + if (contained == ContainmentType.Disjoint) + { + break; + } + } + + // This means we checked all the corners and they were all contain or instersect + if (i == corners.Length) + { + return ContainmentType.Contains; + } + + // if i is not equal to zero, we can fastpath and say that this box intersects + if (i != 0) + { + return ContainmentType.Intersects; + } + + + /* If we get here, it means the first (and only) point we checked was actually contained in the frustum. + * So we assume that all other points will also be contained. If one of the points is disjoint, we can + * exit immediately saying that the result is Intersects + */ + i += 1; + for (; i < corners.Length; i += 1) + { + this.Contains(ref corners[i], out contained); + if (contained != ContainmentType.Contains) + { + return ContainmentType.Intersects; + } + + } + + // If we get here, then we know all the points were actually contained, therefore result is Contains + return ContainmentType.Contains; + } + + public ContainmentType Contains(BoundingSphere sphere) + { + if ( sphere.Center.X - Min.X >= sphere.Radius + && sphere.Center.Y - Min.Y >= sphere.Radius + && sphere.Center.Z - Min.Z >= sphere.Radius + && Max.X - sphere.Center.X >= sphere.Radius + && Max.Y - sphere.Center.Y >= sphere.Radius + && Max.Z - sphere.Center.Z >= sphere.Radius ) + { + return ContainmentType.Contains; + } + + double dmin = 0; + + double e = sphere.Center.X - Min.X; + if (e < 0) + { + if (e < -sphere.Radius) + { + return ContainmentType.Disjoint; + } + dmin += e * e; + } + else + { + e = sphere.Center.X - Max.X; + if (e > 0) + { + if (e > sphere.Radius) + { + return ContainmentType.Disjoint; + } + dmin += e * e; + } + } + + e = sphere.Center.Y - Min.Y; + if (e < 0) + { + if (e < -sphere.Radius) + { + return ContainmentType.Disjoint; + } + dmin += e * e; + } + else + { + e = sphere.Center.Y - Max.Y; + if (e > 0) + { + if (e > sphere.Radius) + { + return ContainmentType.Disjoint; + } + dmin += e * e; + } + } + + e = sphere.Center.Z - Min.Z; + if (e < 0) + { + if (e < -sphere.Radius) + { + return ContainmentType.Disjoint; + } + dmin += e * e; + } + else + { + e = sphere.Center.Z - Max.Z; + if (e > 0) + { + if (e > sphere.Radius) + { + return ContainmentType.Disjoint; + } + dmin += e * e; + } + } + + if (dmin <= sphere.Radius * sphere.Radius) + { + return ContainmentType.Intersects; + } + + return ContainmentType.Disjoint; + } + + public void Contains(ref Vector3 point, out ContainmentType result) + { + // first we get if point is out of box + if ( point.X < this.Min.X + || point.X > this.Max.X + || point.Y < this.Min.Y + || point.Y > this.Max.Y + || point.Z < this.Min.Z + || point.Z > this.Max.Z ) + { + result = ContainmentType.Disjoint; + } + // or if point is on box because coordonate of point is lesser or equal + else if ( point.X == this.Min.X + || point.X == this.Max.X + || point.Y == this.Min.Y + || point.Y == this.Max.Y + || point.Z == this.Min.Z + || point.Z == this.Max.Z ) + { + result = ContainmentType.Intersects; + } + else + { + result = ContainmentType.Contains; + } + } + + public Vector3[] GetCorners() + { + return new Vector3[] { + new Vector3(this.Min.X, this.Max.Y, this.Max.Z), + new Vector3(this.Max.X, this.Max.Y, this.Max.Z), + new Vector3(this.Max.X, this.Min.Y, this.Max.Z), + new Vector3(this.Min.X, this.Min.Y, this.Max.Z), + new Vector3(this.Min.X, this.Max.Y, this.Min.Z), + new Vector3(this.Max.X, this.Max.Y, this.Min.Z), + new Vector3(this.Max.X, this.Min.Y, this.Min.Z), + new Vector3(this.Min.X, this.Min.Y, this.Min.Z) + }; + } + + public void GetCorners(Vector3[] corners) + { + if (corners == null) + { + throw new ArgumentNullException("corners"); + } + if (corners.Length < 8) + { + throw new ArgumentOutOfRangeException("corners", "Not Enought Corners"); + } + corners[0].X = this.Min.X; + corners[0].Y = this.Max.Y; + corners[0].Z = this.Max.Z; + corners[1].X = this.Max.X; + corners[1].Y = this.Max.Y; + corners[1].Z = this.Max.Z; + corners[2].X = this.Max.X; + corners[2].Y = this.Min.Y; + corners[2].Z = this.Max.Z; + corners[3].X = this.Min.X; + corners[3].Y = this.Min.Y; + corners[3].Z = this.Max.Z; + corners[4].X = this.Min.X; + corners[4].Y = this.Max.Y; + corners[4].Z = this.Min.Z; + corners[5].X = this.Max.X; + corners[5].Y = this.Max.Y; + corners[5].Z = this.Min.Z; + corners[6].X = this.Max.X; + corners[6].Y = this.Min.Y; + corners[6].Z = this.Min.Z; + corners[7].X = this.Min.X; + corners[7].Y = this.Min.Y; + corners[7].Z = this.Min.Z; + } + + public Nullable Intersects(Ray ray) + { + return ray.Intersects(this); + } + + public void Intersects(ref Ray ray, out Nullable result) + { + result = Intersects(ray); + } + + public bool Intersects(BoundingFrustum frustum) + { + return frustum.Intersects(this); + } + + public void Intersects(ref BoundingSphere sphere, out bool result) + { + result = Intersects(sphere); + } + + public bool Intersects(BoundingBox box) + { + bool result; + Intersects(ref box, out result); + return result; + } + + public PlaneIntersectionType Intersects(Plane plane) + { + PlaneIntersectionType result; + Intersects(ref plane, out result); + return result; + } + + public void Intersects(ref BoundingBox box, out bool result) + { + if ((this.Max.X >= box.Min.X) && (this.Min.X <= box.Max.X)) + { + if ((this.Max.Y < box.Min.Y) || (this.Min.Y > box.Max.Y)) + { + result = false; + return; + } + + result = (this.Max.Z >= box.Min.Z) && (this.Min.Z <= box.Max.Z); + return; + } + + result = false; + return; + } + + public bool Intersects(BoundingSphere sphere) + { + if ( sphere.Center.X - Min.X > sphere.Radius + && sphere.Center.Y - Min.Y > sphere.Radius + && sphere.Center.Z - Min.Z > sphere.Radius + && Max.X - sphere.Center.X > sphere.Radius + && Max.Y - sphere.Center.Y > sphere.Radius + && Max.Z - sphere.Center.Z > sphere.Radius ) + { + return true; + } + + double dmin = 0; + + if (sphere.Center.X - Min.X <= sphere.Radius) + { + dmin += (sphere.Center.X - Min.X) * (sphere.Center.X - Min.X); + } + else if (Max.X - sphere.Center.X <= sphere.Radius) + { + dmin += (sphere.Center.X - Max.X) * (sphere.Center.X - Max.X); + } + + if (sphere.Center.Y - Min.Y <= sphere.Radius) + { + dmin += (sphere.Center.Y - Min.Y) * (sphere.Center.Y - Min.Y); + } + else if (Max.Y - sphere.Center.Y <= sphere.Radius) + { + dmin += (sphere.Center.Y - Max.Y) * (sphere.Center.Y - Max.Y); + } + + if (sphere.Center.Z - Min.Z <= sphere.Radius) + { + dmin += (sphere.Center.Z - Min.Z) * (sphere.Center.Z - Min.Z); + } + else if (Max.Z - sphere.Center.Z <= sphere.Radius) + { + dmin += (sphere.Center.Z - Max.Z) * (sphere.Center.Z - Max.Z); + } + + if (dmin <= sphere.Radius * sphere.Radius) + { + return true; + } + + return false; + } + + public void Intersects(ref Plane plane, out PlaneIntersectionType result) + { + // See http://zach.in.tu-clausthal.de/teaching/cg_literatur/lighthouse3d_view_frustum_culling/index.html + + Vector3 positiveVertex; + Vector3 negativeVertex; + + if (plane.Normal.X >= 0) + { + positiveVertex.X = Max.X; + negativeVertex.X = Min.X; + } + else + { + positiveVertex.X = Min.X; + negativeVertex.X = Max.X; + } + + if (plane.Normal.Y >= 0) + { + positiveVertex.Y = Max.Y; + negativeVertex.Y = Min.Y; + } + else + { + positiveVertex.Y = Min.Y; + negativeVertex.Y = Max.Y; + } + + if (plane.Normal.Z >= 0) + { + positiveVertex.Z = Max.Z; + negativeVertex.Z = Min.Z; + } + else + { + positiveVertex.Z = Min.Z; + negativeVertex.Z = Max.Z; + } + + float distance = Vector3.Dot(plane.Normal, negativeVertex) + plane.D; + if (distance > 0) + { + result = PlaneIntersectionType.Front; + return; + } + + distance = Vector3.Dot(plane.Normal, positiveVertex) + plane.D; + if (distance < 0) + { + result = PlaneIntersectionType.Back; + return; + } + + result = PlaneIntersectionType.Intersecting; + } + + public bool Equals(BoundingBox other) + { + return (this.Min == other.Min) && (this.Max == other.Max); + } + + #endregion + + #region Public Static Methods + + /// + /// Create a bounding box from the given list of points. + /// + /// The list of Vector3 instances defining the point cloud to bound + /// A bounding box that encapsulates the given point cloud. + /// Thrown if the given list has no points. + public static BoundingBox CreateFromPoints(IEnumerable points) + { + if (points == null) + { + throw new ArgumentNullException(); + } + + bool empty = true; + Vector3 minVec = MaxVector3; + Vector3 maxVec = MinVector3; + foreach (Vector3 ptVector in points) + { + minVec.X = (minVec.X < ptVector.X) ? minVec.X : ptVector.X; + minVec.Y = (minVec.Y < ptVector.Y) ? minVec.Y : ptVector.Y; + minVec.Z = (minVec.Z < ptVector.Z) ? minVec.Z : ptVector.Z; + + maxVec.X = (maxVec.X > ptVector.X) ? maxVec.X : ptVector.X; + maxVec.Y = (maxVec.Y > ptVector.Y) ? maxVec.Y : ptVector.Y; + maxVec.Z = (maxVec.Z > ptVector.Z) ? maxVec.Z : ptVector.Z; + + empty = false; + } + if (empty) + { + throw new ArgumentException(); + } + + return new BoundingBox(minVec, maxVec); + } + + public static BoundingBox CreateFromSphere(BoundingSphere sphere) + { + BoundingBox result; + CreateFromSphere(ref sphere, out result); + return result; + } + + public static void CreateFromSphere(ref BoundingSphere sphere, out BoundingBox result) + { + Vector3 corner = new Vector3(sphere.Radius); + result.Min = sphere.Center - corner; + result.Max = sphere.Center + corner; + } + + public static BoundingBox CreateMerged(BoundingBox original, BoundingBox additional) + { + BoundingBox result; + CreateMerged(ref original, ref additional, out result); + return result; + } + + public static void CreateMerged(ref BoundingBox original, ref BoundingBox additional, out BoundingBox result) + { + result.Min.X = Math.Min(original.Min.X, additional.Min.X); + result.Min.Y = Math.Min(original.Min.Y, additional.Min.Y); + result.Min.Z = Math.Min(original.Min.Z, additional.Min.Z); + result.Max.X = Math.Max(original.Max.X, additional.Max.X); + result.Max.Y = Math.Max(original.Max.Y, additional.Max.Y); + result.Max.Z = Math.Max(original.Max.Z, additional.Max.Z); + } + + #endregion + + #region Public Static Operators and Override Methods + + public override bool Equals(object obj) + { + return (obj is BoundingBox) ? this.Equals((BoundingBox)obj) : false; + } + + public override int GetHashCode() + { + return this.Min.GetHashCode() + this.Max.GetHashCode(); + } + + public static bool operator ==(BoundingBox a, BoundingBox b) + { + return a.Equals(b); + } + + public static bool operator !=(BoundingBox a, BoundingBox b) + { + return !a.Equals(b); + } + + public override string ToString() + { + return string.Format("{{Min:{0} Max:{1}}}", this.Min.ToString(), this.Max.ToString()); + } + + #endregion + } } diff --git a/MonoGame.Framework/BoundingFrustum.cs b/MonoGame.Framework/BoundingFrustum.cs index 3b031062825..89306e291cd 100644 --- a/MonoGame.Framework/BoundingFrustum.cs +++ b/MonoGame.Framework/BoundingFrustum.cs @@ -37,386 +37,449 @@ Olivier Dufour (Duff) #region Using Statements using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Runtime.InteropServices; using System.Text; #endregion namespace Microsoft.Xna.Framework { - public class BoundingFrustum : IEquatable - { - #region Public Properties - - public Matrix Matrix - { - get { return this.matrix; } - set - { - this.matrix = value; - this.CreatePlanes(); // FIXME: The odds are the planes will be used a lot more often than the matrix - this.CreateCorners(); // is updated, so this should help performance. I hope ;) - } - } - - public Plane Near - { - get { return this.planes[0]; } - } - - public Plane Far - { - get { return this.planes[1]; } - } - - public Plane Left - { - get { return this.planes[2]; } - } - - public Plane Right - { - get { return this.planes[3]; } - } - - public Plane Top - { - get { return this.planes[4]; } - } - - public Plane Bottom - { - get { return this.planes[5]; } - } - - #endregion - - #region Public Fields - - public const int CornerCount = 8; - - #endregion - - #region Private Fields - - private Matrix matrix; - private readonly Vector3[] corners = new Vector3[CornerCount]; - private readonly Plane[] planes = new Plane[PlaneCount]; - - private const int PlaneCount = 6; - - #endregion - - #region Public Constructors - - public BoundingFrustum(Matrix value) - { - this.matrix = value; - this.CreatePlanes(); - this.CreateCorners(); - } - - #endregion - - #region Public Methods - - public ContainmentType Contains(BoundingBox box) - { - var result = default(ContainmentType); - this.Contains(ref box, out result); - return result; - } - - public void Contains(ref BoundingBox box, out ContainmentType result) - { - var intersects = false; - for (var i = 0; i < PlaneCount; ++i) - { - var planeIntersectionType = default(PlaneIntersectionType); - box.Intersects(ref this.planes[i], out planeIntersectionType); - switch (planeIntersectionType) - { - case PlaneIntersectionType.Front: - result = ContainmentType.Disjoint; - return; - case PlaneIntersectionType.Intersecting: - intersects = true; - break; - } - } - result = intersects ? ContainmentType.Intersects : ContainmentType.Contains; - } - - /* - public ContainmentType Contains(BoundingFrustum frustum) - { - if (this == frustum) // We check to see if the two frustums are equal - return ContainmentType.Contains;// If they are, there's no need to go any further. - - throw new NotImplementedException(); - } - */ - - public ContainmentType Contains(BoundingSphere sphere) - { - var result = default(ContainmentType); - this.Contains(ref sphere, out result); - return result; - } - - public void Contains(ref BoundingSphere sphere, out ContainmentType result) - { - var intersects = false; - for (var i = 0; i < PlaneCount; ++i) - { - var planeIntersectionType = default(PlaneIntersectionType); - - // TODO: we might want to inline this for performance reasons - sphere.Intersects(ref this.planes[i], out planeIntersectionType); - switch (planeIntersectionType) - { - case PlaneIntersectionType.Front: - result = ContainmentType.Disjoint; - return; - case PlaneIntersectionType.Intersecting: - intersects = true; - break; - } - } - result = intersects ? ContainmentType.Intersects : ContainmentType.Contains; - } - - public ContainmentType Contains(Vector3 point) - { - var result = default(ContainmentType); - this.Contains(ref point, out result); - return result; - } - - public void Contains(ref Vector3 point, out ContainmentType result) - { - for (var i = 0; i < PlaneCount; ++i) - { - // TODO: we might want to inline this for performance reasons - if (PlaneHelper.ClassifyPoint(ref point, ref this.planes[i]) > 0) - { - result = ContainmentType.Disjoint; - return; - } - } - result = ContainmentType.Contains; - } - - public bool Equals(BoundingFrustum other) - { - return (this == other); - } - - public Vector3[] GetCorners() - { - return (Vector3[])this.corners.Clone(); - } - - public void GetCorners(Vector3[] corners) - { - if (corners == null) throw new ArgumentNullException("corners"); - if (corners.Length < CornerCount) throw new ArgumentOutOfRangeException("corners"); + public class BoundingFrustum : IEquatable + { + #region Public Properties + + public Matrix Matrix + { + get + { + return this.matrix; + } + set + { + /* FIXME: The odds are the planes will be used a lot more often than the matrix + * is updated, so this should help performance. I hope ;) + */ + this.matrix = value; + this.CreatePlanes(); + this.CreateCorners(); + } + } + + public Plane Near + { + get + { + return this.planes[0]; + } + } + + public Plane Far + { + get + { + return this.planes[1]; + } + } + + public Plane Left + { + get + { + return this.planes[2]; + } + } + + public Plane Right + { + get + { + return this.planes[3]; + } + } + + public Plane Top + { + get + { + return this.planes[4]; + } + } + + public Plane Bottom + { + get + { + return this.planes[5]; + } + } + + #endregion + + #region Public Fields + + public const int CornerCount = 8; + + #endregion + + #region Private Fields + + private Matrix matrix; + private readonly Vector3[] corners = new Vector3[CornerCount]; + private readonly Plane[] planes = new Plane[PlaneCount]; + + private const int PlaneCount = 6; + + #endregion - this.corners.CopyTo(corners, 0); - } + #region Public Constructors - public override int GetHashCode() - { - return this.matrix.GetHashCode(); - } + public BoundingFrustum(Matrix value) + { + this.matrix = value; + this.CreatePlanes(); + this.CreateCorners(); + } + + #endregion + + #region Public Methods + + public ContainmentType Contains(BoundingBox box) + { + ContainmentType result = default(ContainmentType); + this.Contains(ref box, out result); + return result; + } + + public void Contains(ref BoundingBox box, out ContainmentType result) + { + bool intersects = false; + for (int i = 0; i < PlaneCount; i += 1) + { + PlaneIntersectionType planeIntersectionType = default(PlaneIntersectionType); + box.Intersects(ref this.planes[i], out planeIntersectionType); + switch (planeIntersectionType) + { + case PlaneIntersectionType.Front: + result = ContainmentType.Disjoint; + return; + case PlaneIntersectionType.Intersecting: + intersects = true; + break; + } + } + result = intersects ? ContainmentType.Intersects : ContainmentType.Contains; + } + + public ContainmentType Contains(BoundingSphere sphere) + { + ContainmentType result = default(ContainmentType); + this.Contains(ref sphere, out result); + return result; + } + + public void Contains(ref BoundingSphere sphere, out ContainmentType result) + { + bool intersects = false; + for (int i = 0; i < PlaneCount; i += 1) + { + PlaneIntersectionType planeIntersectionType = default(PlaneIntersectionType); + + // TODO: we might want to inline this for performance reasons + sphere.Intersects(ref this.planes[i], out planeIntersectionType); + switch (planeIntersectionType) + { + case PlaneIntersectionType.Front: + result = ContainmentType.Disjoint; + return; + case PlaneIntersectionType.Intersecting: + intersects = true; + break; + } + } + result = intersects ? ContainmentType.Intersects : ContainmentType.Contains; + } + + public ContainmentType Contains(Vector3 point) + { + ContainmentType result = default(ContainmentType); + this.Contains(ref point, out result); + return result; + } + + public void Contains(ref Vector3 point, out ContainmentType result) + { + for (int i = 0; i < PlaneCount; i += 1) + { + // TODO: we might want to inline this for performance reasons + if (PlaneHelper.ClassifyPoint(ref point, ref this.planes[i]) > 0) + { + result = ContainmentType.Disjoint; + return; + } + } + result = ContainmentType.Contains; + } + + public bool Equals(BoundingFrustum other) + { + return (this == other); + } + + public Vector3[] GetCorners() + { + return (Vector3[]) this.corners.Clone(); + } - public bool Intersects(BoundingBox box) - { - var result = false; + public void GetCorners(Vector3[] corners) + { + if (corners == null) + { + throw new ArgumentNullException("corners"); + } + if (corners.Length < CornerCount) + { + throw new ArgumentOutOfRangeException("corners"); + } + + this.corners.CopyTo(corners, 0); + } + + public override int GetHashCode() + { + return this.matrix.GetHashCode(); + } + + public bool Intersects(BoundingBox box) + { + bool result = false; this.Intersects(ref box, out result); return result; - } + } - public void Intersects(ref BoundingBox box, out bool result) - { - var containment = default(ContainmentType); + public void Intersects(ref BoundingBox box, out bool result) + { + ContainmentType containment = default(ContainmentType); this.Contains(ref box, out containment); result = containment != ContainmentType.Disjoint; } - /* - public bool Intersects(BoundingFrustum frustum) - { - throw new NotImplementedException(); - } - */ - - public bool Intersects(BoundingSphere sphere) - { - var result = default(bool); - this.Intersects(ref sphere, out result); - return result; - } - - public void Intersects(ref BoundingSphere sphere, out bool result) - { - var containment = default(ContainmentType); - this.Contains(ref sphere, out containment); - result = containment != ContainmentType.Disjoint; - } - - /* - public PlaneIntersectionType Intersects(Plane plane) - { - throw new NotImplementedException(); - } - - public void Intersects(ref Plane plane, out PlaneIntersectionType result) - { - throw new NotImplementedException(); - } - - public Nullable Intersects(Ray ray) - { - throw new NotImplementedException(); - } - - public void Intersects(ref Ray ray, out Nullable result) - { - throw new NotImplementedException(); - } - */ - - #endregion - - #region Private Methods - - private void CreateCorners() - { - IntersectionPoint(ref this.planes[0], ref this.planes[2], ref this.planes[4], out this.corners[0]); - IntersectionPoint(ref this.planes[0], ref this.planes[3], ref this.planes[4], out this.corners[1]); - IntersectionPoint(ref this.planes[0], ref this.planes[3], ref this.planes[5], out this.corners[2]); - IntersectionPoint(ref this.planes[0], ref this.planes[2], ref this.planes[5], out this.corners[3]); - IntersectionPoint(ref this.planes[1], ref this.planes[2], ref this.planes[4], out this.corners[4]); - IntersectionPoint(ref this.planes[1], ref this.planes[3], ref this.planes[4], out this.corners[5]); - IntersectionPoint(ref this.planes[1], ref this.planes[3], ref this.planes[5], out this.corners[6]); - IntersectionPoint(ref this.planes[1], ref this.planes[2], ref this.planes[5], out this.corners[7]); - } - - private void CreatePlanes() - { - this.planes[0] = new Plane(-this.matrix.M13, -this.matrix.M23, -this.matrix.M33, -this.matrix.M43); - this.planes[1] = new Plane(this.matrix.M13 - this.matrix.M14, this.matrix.M23 - this.matrix.M24, this.matrix.M33 - this.matrix.M34, this.matrix.M43 - this.matrix.M44); - this.planes[2] = new Plane(-this.matrix.M14 - this.matrix.M11, -this.matrix.M24 - this.matrix.M21, -this.matrix.M34 - this.matrix.M31, -this.matrix.M44 - this.matrix.M41); - this.planes[3] = new Plane(this.matrix.M11 - this.matrix.M14, this.matrix.M21 - this.matrix.M24, this.matrix.M31 - this.matrix.M34, this.matrix.M41 - this.matrix.M44); - this.planes[4] = new Plane(this.matrix.M12 - this.matrix.M14, this.matrix.M22 - this.matrix.M24, this.matrix.M32 - this.matrix.M34, this.matrix.M42 - this.matrix.M44); - this.planes[5] = new Plane(-this.matrix.M14 - this.matrix.M12, -this.matrix.M24 - this.matrix.M22, -this.matrix.M34 - this.matrix.M32, -this.matrix.M44 - this.matrix.M42); - - this.NormalizePlane(ref this.planes[0]); - this.NormalizePlane(ref this.planes[1]); - this.NormalizePlane(ref this.planes[2]); - this.NormalizePlane(ref this.planes[3]); - this.NormalizePlane(ref this.planes[4]); - this.NormalizePlane(ref this.planes[5]); - } - - private void NormalizePlane(ref Plane p) - { - float factor = 1f / p.Normal.Length(); - p.Normal.X *= factor; - p.Normal.Y *= factor; - p.Normal.Z *= factor; - p.D *= factor; - } - - #endregion - - #region Private Static Methods - - private static void IntersectionPoint(ref Plane a, ref Plane b, ref Plane c, out Vector3 result) - { - // Formula used - // d1 ( N2 * N3 ) + d2 ( N3 * N1 ) + d3 ( N1 * N2 ) - //P = ------------------------------------------------------------------------- - // N1 . ( N2 * N3 ) - // - // Note: N refers to the normal, d refers to the displacement. '.' means dot product. '*' means cross product - - Vector3 v1, v2, v3; - Vector3 cross; - - Vector3.Cross(ref b.Normal, ref c.Normal, out cross); - - float f; - Vector3.Dot(ref a.Normal, ref cross, out f); - f *= -1.0f; - - Vector3.Cross(ref b.Normal, ref c.Normal, out cross); - Vector3.Multiply(ref cross, a.D, out v1); - //v1 = (a.D * (Vector3.Cross(b.Normal, c.Normal))); - - - Vector3.Cross(ref c.Normal, ref a.Normal, out cross); - Vector3.Multiply(ref cross, b.D, out v2); - //v2 = (b.D * (Vector3.Cross(c.Normal, a.Normal))); - - - Vector3.Cross(ref a.Normal, ref b.Normal, out cross); - Vector3.Multiply(ref cross, c.D, out v3); - //v3 = (c.D * (Vector3.Cross(a.Normal, b.Normal))); - - result.X = (v1.X + v2.X + v3.X) / f; - result.Y = (v1.Y + v2.Y + v3.Y) / f; - result.Z = (v1.Z + v2.Z + v3.Z) / f; - } - - #endregion - - #region Public Static Operators and Override Methods - - public static bool operator ==(BoundingFrustum a, BoundingFrustum b) - { - if (object.Equals(a, null)) - return (object.Equals(b, null)); - - if (object.Equals(b, null)) - return (object.Equals(a, null)); - - return a.matrix == (b.matrix); - } - - public static bool operator !=(BoundingFrustum a, BoundingFrustum b) - { - return !(a == b); - } - - public override bool Equals(object obj) - { - BoundingFrustum f = obj as BoundingFrustum; - return (object.Equals(f, null)) ? false : (this == f); - } - - public override string ToString() - { - StringBuilder sb = new StringBuilder(256); - sb.Append("{Near:"); - sb.Append(this.planes[0].ToString()); - sb.Append(" Far:"); - sb.Append(this.planes[1].ToString()); - sb.Append(" Left:"); - sb.Append(this.planes[2].ToString()); - sb.Append(" Right:"); - sb.Append(this.planes[3].ToString()); - sb.Append(" Top:"); - sb.Append(this.planes[4].ToString()); - sb.Append(" Bottom:"); - sb.Append(this.planes[5].ToString()); - sb.Append("}"); - return sb.ToString(); - } - - #endregion - } + public bool Intersects(BoundingSphere sphere) + { + bool result = default(bool); + this.Intersects(ref sphere, out result); + return result; + } + + public void Intersects(ref BoundingSphere sphere, out bool result) + { + ContainmentType containment = default(ContainmentType); + this.Contains(ref sphere, out containment); + result = containment != ContainmentType.Disjoint; + } + + #endregion + + #region Private Methods + + private void CreateCorners() + { + IntersectionPoint( + ref this.planes[0], + ref this.planes[2], + ref this.planes[4], + out this.corners[0] + ); + IntersectionPoint( + ref this.planes[0], + ref this.planes[3], + ref this.planes[4], + out this.corners[1] + ); + IntersectionPoint( + ref this.planes[0], + ref this.planes[3], + ref this.planes[5], + out this.corners[2] + ); + IntersectionPoint( + ref this.planes[0], + ref this.planes[2], + ref this.planes[5], + out this.corners[3] + ); + IntersectionPoint( + ref this.planes[1], + ref this.planes[2], + ref this.planes[4], + out this.corners[4] + ); + IntersectionPoint( + ref this.planes[1], + ref this.planes[3], + ref this.planes[4], + out this.corners[5] + ); + IntersectionPoint( + ref this.planes[1], + ref this.planes[3], + ref this.planes[5], + out this.corners[6] + ); + IntersectionPoint( + ref this.planes[1], + ref this.planes[2], + ref this.planes[5], + out this.corners[7] + ); + } + + private void CreatePlanes() + { + this.planes[0] = new Plane( + -this.matrix.M13, + -this.matrix.M23, + -this.matrix.M33, + -this.matrix.M43 + ); + this.planes[1] = new Plane( + this.matrix.M13 - this.matrix.M14, + this.matrix.M23 - this.matrix.M24, + this.matrix.M33 - this.matrix.M34, + this.matrix.M43 - this.matrix.M44 + ); + this.planes[2] = new Plane( + -this.matrix.M14 - this.matrix.M11, + -this.matrix.M24 - this.matrix.M21, + -this.matrix.M34 - this.matrix.M31, + -this.matrix.M44 - this.matrix.M41 + ); + this.planes[3] = new Plane( + this.matrix.M11 - this.matrix.M14, + this.matrix.M21 - this.matrix.M24, + this.matrix.M31 - this.matrix.M34, + this.matrix.M41 - this.matrix.M44 + ); + this.planes[4] = new Plane( + this.matrix.M12 - this.matrix.M14, + this.matrix.M22 - this.matrix.M24, + this.matrix.M32 - this.matrix.M34, + this.matrix.M42 - this.matrix.M44 + ); + this.planes[5] = new Plane( + -this.matrix.M14 - this.matrix.M12, + -this.matrix.M24 - this.matrix.M22, + -this.matrix.M34 - this.matrix.M32, + -this.matrix.M44 - this.matrix.M42 + ); + + this.NormalizePlane(ref this.planes[0]); + this.NormalizePlane(ref this.planes[1]); + this.NormalizePlane(ref this.planes[2]); + this.NormalizePlane(ref this.planes[3]); + this.NormalizePlane(ref this.planes[4]); + this.NormalizePlane(ref this.planes[5]); + } + + private void NormalizePlane(ref Plane p) + { + float factor = 1f / p.Normal.Length(); + p.Normal.X *= factor; + p.Normal.Y *= factor; + p.Normal.Z *= factor; + p.D *= factor; + } + + #endregion + + #region Private Static Methods + + private static void IntersectionPoint(ref Plane a, ref Plane b, ref Plane c, out Vector3 result) + { + /* Formula used + * d1 ( N2 * N3 ) + d2 ( N3 * N1 ) + d3 ( N1 * N2 ) + * P = ------------------------------------------------------------------------- + * N1 . ( N2 * N3 ) + * + * Note: N refers to the normal, d refers to the displacement. '.' means dot product. '*' means cross product + */ + + Vector3 v1, v2, v3; + Vector3 cross; + + Vector3.Cross(ref b.Normal, ref c.Normal, out cross); + + float f; + Vector3.Dot(ref a.Normal, ref cross, out f); + f *= -1.0f; + + Vector3.Cross(ref b.Normal, ref c.Normal, out cross); + Vector3.Multiply(ref cross, a.D, out v1); + // v1 = (a.D * (Vector3.Cross(b.Normal, c.Normal))); + + + Vector3.Cross(ref c.Normal, ref a.Normal, out cross); + Vector3.Multiply(ref cross, b.D, out v2); + // v2 = (b.D * (Vector3.Cross(c.Normal, a.Normal))); + + + Vector3.Cross(ref a.Normal, ref b.Normal, out cross); + Vector3.Multiply(ref cross, c.D, out v3); + // v3 = (c.D * (Vector3.Cross(a.Normal, b.Normal))); + + result.X = (v1.X + v2.X + v3.X) / f; + result.Y = (v1.Y + v2.Y + v3.Y) / f; + result.Z = (v1.Z + v2.Z + v3.Z) / f; + } + + #endregion + + #region Public Static Operators and Override Methods + + public static bool operator ==(BoundingFrustum a, BoundingFrustum b) + { + if (object.Equals(a, null)) + { + return (object.Equals(b, null)); + } + + if (object.Equals(b, null)) + { + return (object.Equals(a, null)); + } + + return a.matrix == (b.matrix); + } + + public static bool operator !=(BoundingFrustum a, BoundingFrustum b) + { + return !(a == b); + } + + public override bool Equals(object obj) + { + BoundingFrustum f = obj as BoundingFrustum; + return (object.Equals(f, null)) ? false : (this == f); + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(256); + sb.Append("{Near:"); + sb.Append(this.planes[0].ToString()); + sb.Append(" Far:"); + sb.Append(this.planes[1].ToString()); + sb.Append(" Left:"); + sb.Append(this.planes[2].ToString()); + sb.Append(" Right:"); + sb.Append(this.planes[3].ToString()); + sb.Append(" Top:"); + sb.Append(this.planes[4].ToString()); + sb.Append(" Bottom:"); + sb.Append(this.planes[5].ToString()); + sb.Append("}"); + return sb.ToString(); + } + + #endregion + } } diff --git a/MonoGame.Framework/BoundingSphere.cs b/MonoGame.Framework/BoundingSphere.cs index 9f0f68ed258..48fcffe50d6 100644 --- a/MonoGame.Framework/BoundingSphere.cs +++ b/MonoGame.Framework/BoundingSphere.cs @@ -39,354 +39,432 @@ Olivier Dufour (Duff) using System; using System.Collections.Generic; using System.Globalization; -using System.ComponentModel; using System.Runtime.Serialization; #endregion namespace Microsoft.Xna.Framework { - - [DataContract] - public struct BoundingSphere : IEquatable - { - #region Public Fields - - [DataMember] - public Vector3 Center; - - [DataMember] - public float Radius; - - #endregion - - #region Public Constructors - - public BoundingSphere(Vector3 center, float radius) - { - this.Center = center; - this.Radius = radius; - } - - #endregion - - #region Public Methods - - public BoundingSphere Transform(Matrix matrix) - { - BoundingSphere sphere = new BoundingSphere(); - sphere.Center = Vector3.Transform(this.Center, matrix); - sphere.Radius = this.Radius * ((float)Math.Sqrt((double)Math.Max(((matrix.M11 * matrix.M11) + (matrix.M12 * matrix.M12)) + (matrix.M13 * matrix.M13), Math.Max(((matrix.M21 * matrix.M21) + (matrix.M22 * matrix.M22)) + (matrix.M23 * matrix.M23), ((matrix.M31 * matrix.M31) + (matrix.M32 * matrix.M32)) + (matrix.M33 * matrix.M33))))); - return sphere; - } - - public void Transform(ref Matrix matrix, out BoundingSphere result) - { - result.Center = Vector3.Transform(this.Center, matrix); - result.Radius = this.Radius * ((float)Math.Sqrt((double)Math.Max(((matrix.M11 * matrix.M11) + (matrix.M12 * matrix.M12)) + (matrix.M13 * matrix.M13), Math.Max(((matrix.M21 * matrix.M21) + (matrix.M22 * matrix.M22)) + (matrix.M23 * matrix.M23), ((matrix.M31 * matrix.M31) + (matrix.M32 * matrix.M32)) + (matrix.M33 * matrix.M33))))); - } - - public ContainmentType Contains(BoundingBox box) - { - //check if all corner is in sphere - bool inside = true; - foreach (Vector3 corner in box.GetCorners()) - { - if (this.Contains(corner) == ContainmentType.Disjoint) - { - inside = false; - break; - } - } - - if (inside) - return ContainmentType.Contains; - - //check if the distance from sphere center to cube face < radius - double dmin = 0; - - if (Center.X < box.Min.X) - dmin += (Center.X - box.Min.X) * (Center.X - box.Min.X); + [DataContract] + public struct BoundingSphere : IEquatable + { + #region Public Fields + + [DataMember] + public Vector3 Center; + + [DataMember] + public float Radius; + + #endregion + + #region Public Constructors + + public BoundingSphere(Vector3 center, float radius) + { + this.Center = center; + this.Radius = radius; + } + + #endregion + + #region Public Methods + + public BoundingSphere Transform(Matrix matrix) + { + BoundingSphere sphere = new BoundingSphere(); + sphere.Center = Vector3.Transform(this.Center, matrix); + sphere.Radius = this.Radius * + ( + (float) Math.Sqrt((double) Math.Max( + ((matrix.M11 * matrix.M11) + (matrix.M12 * matrix.M12)) + (matrix.M13 * matrix.M13), + Math.Max( + ((matrix.M21 * matrix.M21) + (matrix.M22 * matrix.M22)) + (matrix.M23 * matrix.M23), + ((matrix.M31 * matrix.M31) + (matrix.M32 * matrix.M32)) + (matrix.M33 * matrix.M33)) + ) + ) + ); + return sphere; + } + + public void Transform(ref Matrix matrix, out BoundingSphere result) + { + result.Center = Vector3.Transform(this.Center, matrix); + result.Radius = this.Radius * + ( + (float) Math.Sqrt((double) Math.Max( + ((matrix.M11 * matrix.M11) + (matrix.M12 * matrix.M12)) + (matrix.M13 * matrix.M13), + Math.Max( + ((matrix.M21 * matrix.M21) + (matrix.M22 * matrix.M22)) + (matrix.M23 * matrix.M23), + ((matrix.M31 * matrix.M31) + (matrix.M32 * matrix.M32)) + (matrix.M33 * matrix.M33)) + ) + ) + ); + } + + public void Contains(ref BoundingBox box, out ContainmentType result) + { + result = this.Contains(box); + } + + public void Contains(ref BoundingSphere sphere, out ContainmentType result) + { + result = Contains(sphere); + } + + public void Contains(ref Vector3 point, out ContainmentType result) + { + result = Contains(point); + } + + public ContainmentType Contains(BoundingBox box) + { + // Check if all corner is in sphere + bool inside = true; + foreach (Vector3 corner in box.GetCorners()) + { + if (this.Contains(corner) == ContainmentType.Disjoint) + { + inside = false; + break; + } + } + + if (inside) + { + return ContainmentType.Contains; + } + + // Check if the distance from sphere center to cube face < radius + double dmin = 0; + + if (Center.X < box.Min.X) + { + dmin += (Center.X - box.Min.X) * (Center.X - box.Min.X); + } else if (Center.X > box.Max.X) - dmin += (Center.X - box.Max.X) * (Center.X - box.Max.X); + { + dmin += (Center.X - box.Max.X) * (Center.X - box.Max.X); + } if (Center.Y < box.Min.Y) + { dmin += (Center.Y - box.Min.Y) * (Center.Y - box.Min.Y); - + } else if (Center.Y > box.Max.Y) + { dmin += (Center.Y - box.Max.Y) * (Center.Y - box.Max.Y); + } if (Center.Z < box.Min.Z) + { dmin += (Center.Z - box.Min.Z) * (Center.Z - box.Min.Z); - + } else if (Center.Z > box.Max.Z) + { dmin += (Center.Z - box.Max.Z) * (Center.Z - box.Max.Z); + } - if (dmin <= Radius * Radius) + if (dmin <= Radius * Radius) + { return ContainmentType.Intersects; - - //else disjoint - return ContainmentType.Disjoint; - - } - - public void Contains(ref BoundingBox box, out ContainmentType result) - { - result = this.Contains(box); - } - - public ContainmentType Contains(BoundingFrustum frustum) - { - //check if all corner is in sphere - bool inside = true; - - Vector3[] corners = frustum.GetCorners(); - foreach (Vector3 corner in corners) - { - if (this.Contains(corner) == ContainmentType.Disjoint) - { - inside = false; - break; - } - } - if (inside) - return ContainmentType.Contains; - - //check if the distance from sphere center to frustrum face < radius - double dmin = 0; - //TODO : calcul dmin - - if (dmin <= Radius * Radius) - return ContainmentType.Intersects; - - //else disjoint - return ContainmentType.Disjoint; - } - - public ContainmentType Contains(BoundingSphere sphere) - { - float val = Vector3.Distance(sphere.Center, Center); - - if (val > sphere.Radius + Radius) - return ContainmentType.Disjoint; - - else if (val <= Radius - sphere.Radius) - return ContainmentType.Contains; - - else - return ContainmentType.Intersects; - } - - public void Contains(ref BoundingSphere sphere, out ContainmentType result) - { - result = Contains(sphere); - } - - public ContainmentType Contains(Vector3 point) - { - float distance = Vector3.Distance(point, Center); - - if (distance > this.Radius) - return ContainmentType.Disjoint; - - else if (distance < this.Radius) - return ContainmentType.Contains; - - return ContainmentType.Intersects; - } - - public void Contains(ref Vector3 point, out ContainmentType result) - { - result = Contains(point); - } - - public bool Equals(BoundingSphere other) - { - return this.Center == other.Center && this.Radius == other.Radius; - } - - #endregion - - #region Public Static Methods - - public static BoundingSphere CreateFromBoundingBox(BoundingBox box) - { - // Find the center of the box. - Vector3 center = new Vector3((box.Min.X + box.Max.X) / 2.0f, - (box.Min.Y + box.Max.Y) / 2.0f, - (box.Min.Z + box.Max.Z) / 2.0f); - - // Find the distance between the center and one of the corners of the box. - float radius = Vector3.Distance(center, box.Max); - - return new BoundingSphere(center, radius); - } - - public static void CreateFromBoundingBox(ref BoundingBox box, out BoundingSphere result) - { - result = CreateFromBoundingBox(box); - } - - public static BoundingSphere CreateFromFrustum(BoundingFrustum frustum) - { - return BoundingSphere.CreateFromPoints(frustum.GetCorners()); - } - - public static BoundingSphere CreateFromPoints(IEnumerable points) - { - if (points == null) - throw new ArgumentNullException("points"); - - float radius = 0; - Vector3 center = new Vector3(); - // First, we'll find the center of gravity for the point 'cloud'. - int num_points = 0; // The number of points (there MUST be a better way to get this instead of counting the number of points one by one?) - - foreach (Vector3 v in points) - { - center += v; // If we actually knew the number of points, we'd get better accuracy by adding v / num_points. - ++num_points; - } - - center /= (float)num_points; - - // Calculate the radius of the needed sphere (it equals the distance between the center and the point further away). - foreach (Vector3 v in points) - { - float distance = ((Vector3)(v - center)).Length(); - - if (distance > radius) - radius = distance; - } - - return new BoundingSphere(center, radius); - } - - public static BoundingSphere CreateMerged(BoundingSphere original, BoundingSphere additional) - { - Vector3 ocenterToaCenter = Vector3.Subtract(additional.Center, original.Center); - float distance = ocenterToaCenter.Length(); - if (distance <= original.Radius + additional.Radius)//intersect - { - if (distance <= original.Radius - additional.Radius)//original contain additional - return original; - if (distance <= additional.Radius - original.Radius)//additional contain original - return additional; - } - - //else find center of new sphere and radius - float leftRadius = Math.Max(original.Radius - distance, additional.Radius); - float Rightradius = Math.Max(original.Radius + distance, additional.Radius); - ocenterToaCenter = ocenterToaCenter + (((leftRadius - Rightradius) / (2 * ocenterToaCenter.Length())) * ocenterToaCenter);//oCenterToResultCenter - - BoundingSphere result = new BoundingSphere(); - result.Center = original.Center + ocenterToaCenter; - result.Radius = (leftRadius + Rightradius) / 2; - return result; - } - - public static void CreateMerged(ref BoundingSphere original, ref BoundingSphere additional, out BoundingSphere result) - { - result = BoundingSphere.CreateMerged(original, additional); - } - - public bool Intersects(BoundingBox box) - { - return box.Intersects(this); - } - - public void Intersects(ref BoundingBox box, out bool result) - { - result = Intersects(box); - } + } + + // Else disjoint + return ContainmentType.Disjoint; + } + + public ContainmentType Contains(BoundingFrustum frustum) + { + // Check if all corner is in sphere + bool inside = true; + + Vector3[] corners = frustum.GetCorners(); + foreach (Vector3 corner in corners) + { + if (this.Contains(corner) == ContainmentType.Disjoint) + { + inside = false; + break; + } + } + if (inside) + { + return ContainmentType.Contains; + } + + // Check if the distance from sphere center to frustrum face < radius + double dmin = 0; + // TODO : calcul dmin + + if (dmin <= Radius * Radius) + { + return ContainmentType.Intersects; + } - /* - public bool Intersects(BoundingFrustum frustum) - { - if (frustum == null) - throw new NullReferenceException(); + // Else disjoint + return ContainmentType.Disjoint; + } - throw new NotImplementedException(); - } - */ + public ContainmentType Contains(BoundingSphere sphere) + { + float val = Vector3.Distance(sphere.Center, Center); - public bool Intersects(BoundingSphere sphere) - { - float val = Vector3.Distance(sphere.Center, Center); if (val > sphere.Radius + Radius) - return false; - return true; - } - - public void Intersects(ref BoundingSphere sphere, out bool result) - { - result = Intersects(sphere); - } - - public PlaneIntersectionType Intersects(Plane plane) - { - var result = default(PlaneIntersectionType); - // TODO: we might want to inline this for performance reasons - this.Intersects(ref plane, out result); - return result; - } - - public void Intersects(ref Plane plane, out PlaneIntersectionType result) - { - var distance = default(float); - // TODO: we might want to inline this for performance reasons - Vector3.Dot(ref plane.Normal, ref this.Center, out distance); - distance += plane.D; - if (distance > this.Radius) - result = PlaneIntersectionType.Front; - else if (distance < -this.Radius) - result = PlaneIntersectionType.Back; - else - result = PlaneIntersectionType.Intersecting; - } - - public Nullable Intersects(Ray ray) - { - return ray.Intersects(this); - } - - public void Intersects(ref Ray ray, out Nullable result) - { - result = Intersects(ray); - } - - #endregion - - #region Public Static Operators and Override Methods - - public override bool Equals(object obj) - { - if (obj is BoundingSphere) - return this.Equals((BoundingSphere)obj); - - return false; - } + { + return ContainmentType.Disjoint; + } + else if (val <= Radius - sphere.Radius) + { + return ContainmentType.Contains; + } + else + { + return ContainmentType.Intersects; + } + } + + public ContainmentType Contains(Vector3 point) + { + float distance = Vector3.Distance(point, Center); + + if (distance > this.Radius) + { + return ContainmentType.Disjoint; + } + else if (distance < this.Radius) + { + return ContainmentType.Contains; + } + + return ContainmentType.Intersects; + } + + public bool Equals(BoundingSphere other) + { + return this.Center == other.Center && this.Radius == other.Radius; + } + + #endregion + + #region Public Static Methods + + public static void CreateFromBoundingBox(ref BoundingBox box, out BoundingSphere result) + { + result = CreateFromBoundingBox(box); + } + + public static BoundingSphere CreateFromBoundingBox(BoundingBox box) + { + // Find the center of the box. + Vector3 center = new Vector3( + (box.Min.X + box.Max.X) / 2.0f, + (box.Min.Y + box.Max.Y) / 2.0f, + (box.Min.Z + box.Max.Z) / 2.0f + ); + + // Find the distance between the center and one of the corners of the box. + float radius = Vector3.Distance(center, box.Max); + + return new BoundingSphere(center, radius); + } + + public static BoundingSphere CreateFromFrustum(BoundingFrustum frustum) + { + return BoundingSphere.CreateFromPoints(frustum.GetCorners()); + } + + public static BoundingSphere CreateFromPoints(IEnumerable points) + { + if (points == null) + { + throw new ArgumentNullException("points"); + } + + float radius = 0; + Vector3 center = new Vector3(); + // First, we'll find the center of gravity for the point 'cloud'. + + /* The number of points (there MUST be a better way to get this + * instead of counting the number of points one by one?) + */ + int num_points = 0; + + foreach (Vector3 v in points) + { + /* If we actually knew the number of points, + * we'd get better accuracy by adding v / num_points. + */ + center += v; + ++num_points; + } + + center /= (float) num_points; + + /* Calculate the radius of the needed sphere + * (it equals the distance between the center and the point further away). + */ + foreach (Vector3 v in points) + { + float distance = ((Vector3) (v - center)).Length(); + + if (distance > radius) + { + radius = distance; + } + } + + return new BoundingSphere(center, radius); + } + + public static BoundingSphere CreateMerged(BoundingSphere original, BoundingSphere additional) + { + Vector3 ocenterToaCenter = Vector3.Subtract(additional.Center, original.Center); + float distance = ocenterToaCenter.Length(); + + // Intersect + if (distance <= original.Radius + additional.Radius) + { + // Original contain additional + if (distance <= original.Radius - additional.Radius) + { + return original; + } + + // Additional contain original + if (distance <= additional.Radius - original.Radius) + { + return additional; + } + } + + // Else find center of new sphere and radius + float leftRadius = Math.Max(original.Radius - distance, additional.Radius); + float Rightradius = Math.Max(original.Radius + distance, additional.Radius); + + // oCenterToResultCenter + ocenterToaCenter = ocenterToaCenter + + ( + ((leftRadius - Rightradius) / (2 * ocenterToaCenter.Length())) + * ocenterToaCenter + ); + + BoundingSphere result = new BoundingSphere(); + result.Center = original.Center + ocenterToaCenter; + result.Radius = (leftRadius + Rightradius) / 2; + return result; + } + + public static void CreateMerged( + ref BoundingSphere original, + ref BoundingSphere additional, + out BoundingSphere result + ) { + result = BoundingSphere.CreateMerged(original, additional); + } + + public bool Intersects(BoundingBox box) + { + return box.Intersects(this); + } - public override int GetHashCode() - { - return this.Center.GetHashCode() + this.Radius.GetHashCode(); - } + public void Intersects(ref BoundingBox box, out bool result) + { + result = Intersects(box); + } - public static bool operator ==(BoundingSphere a, BoundingSphere b) - { - return a.Equals(b); - } + public void Intersects(ref BoundingSphere sphere, out bool result) + { + result = Intersects(sphere); + } - public static bool operator !=(BoundingSphere a, BoundingSphere b) - { - return !a.Equals(b); - } + public void Intersects(ref Ray ray, out Nullable result) + { + result = Intersects(ray); + } - public override string ToString() - { - return string.Format(CultureInfo.CurrentCulture, "{{Center:{0} Radius:{1}}}", this.Center.ToString(), this.Radius.ToString()); - } + public Nullable Intersects(Ray ray) + { + return ray.Intersects(this); + } - #endregion - } + public bool Intersects(BoundingSphere sphere) + { + float val = Vector3.Distance(sphere.Center, Center); + if (val > sphere.Radius + Radius) + { + return false; + } + return true; + } + + public PlaneIntersectionType Intersects(Plane plane) + { + PlaneIntersectionType result = default(PlaneIntersectionType); + // TODO: we might want to inline this for performance reasons + this.Intersects(ref plane, out result); + return result; + } + + public void Intersects(ref Plane plane, out PlaneIntersectionType result) + { + float distance = default(float); + // TODO: we might want to inline this for performance reasons + Vector3.Dot(ref plane.Normal, ref this.Center, out distance); + distance += plane.D; + if (distance > this.Radius) + { + result = PlaneIntersectionType.Front; + } + else if (distance < -this.Radius) + { + result = PlaneIntersectionType.Back; + } + else + { + result = PlaneIntersectionType.Intersecting; + } + } + + #endregion + + #region Public Static Operators and Override Methods + + public override bool Equals(object obj) + { + if (obj is BoundingSphere) + { + return this.Equals((BoundingSphere)obj); + } + + return false; + } + + public override int GetHashCode() + { + return this.Center.GetHashCode() + this.Radius.GetHashCode(); + } + + public static bool operator ==(BoundingSphere a, BoundingSphere b) + { + return a.Equals(b); + } + + public static bool operator !=(BoundingSphere a, BoundingSphere b) + { + return !a.Equals(b); + } + + public override string ToString() + { + return string.Format( + CultureInfo.CurrentCulture, + "{{Center:{0} Radius:{1}}}", + this.Center.ToString(), + this.Radius.ToString() + ); + } + + #endregion + } } diff --git a/MonoGame.Framework/Color.cs b/MonoGame.Framework/Color.cs index 29ca8011255..602c5c4ef4a 100644 --- a/MonoGame.Framework/Color.cs +++ b/MonoGame.Framework/Color.cs @@ -41,1871 +41,1893 @@ MIT License namespace Microsoft.Xna.Framework { - /// - /// Describe a 32-bit packed color. - /// - [DataContract] - [TypeConverter(typeof(XNAColorConverter))] - public struct Color : IEquatable - { - #region Public Properties - - /// - /// Gets or sets the blue component of . - /// - [DataMember] - public byte B - { - get - { - return (byte)(this._packedValue >> 16); - } - set - { - this._packedValue = (this._packedValue & 0xff00ffff) | (uint)(value << 16); - } - } - - /// - /// Gets or sets the green component of . - /// - [DataMember] - public byte G - { - get - { - return (byte)(this._packedValue >> 8); - } - set - { - this._packedValue = (this._packedValue & 0xffff00ff) | ((uint)(value << 8)); - } - } - - /// - /// Gets or sets the red component of . - /// - [DataMember] - public byte R - { - get - { - return (byte)(this._packedValue); - } - set - { - this._packedValue = (this._packedValue & 0xffffff00) | value; - } - } - - /// - /// Gets or sets the alpha component of . - /// - [DataMember] - public byte A - { - get - { - return (byte)(this._packedValue >> 24); - } - set - { - this._packedValue = (this._packedValue & 0x00ffffff) | ((uint)(value << 24)); - } - } - - /// - /// Gets or sets packed value of this . - /// - [CLSCompliant(false)] - public UInt32 PackedValue - { - get { return _packedValue; } - set { _packedValue = value; } - } - - #endregion - - #region Public Static Color Properties - - /// - /// TransparentBlack color (R:0,G:0,B:0,A:0). - /// - public static Color TransparentBlack - { - get; - private set; - } - - /// - /// Transparent color (R:0,G:0,B:0,A:0). - /// - public static Color Transparent - { - get; - private set; - } - - /// - /// AliceBlue color (R:240,G:248,B:255,A:255). - /// - public static Color AliceBlue - { - get; - private set; - } - - /// - /// AntiqueWhite color (R:250,G:235,B:215,A:255). - /// - public static Color AntiqueWhite - { - get; - private set; - } - - /// - /// Aqua color (R:0,G:255,B:255,A:255). - /// - public static Color Aqua - { - get; - private set; - } - - /// - /// Aquamarine color (R:127,G:255,B:212,A:255). - /// - public static Color Aquamarine - { - get; - private set; - } - - /// - /// Azure color (R:240,G:255,B:255,A:255). - /// - public static Color Azure - { - get; - private set; - } - - /// - /// Beige color (R:245,G:245,B:220,A:255). - /// - public static Color Beige - { - get; - private set; - } - - /// - /// Bisque color (R:255,G:228,B:196,A:255). - /// - public static Color Bisque - { - get; - private set; - } - - /// - /// Black color (R:0,G:0,B:0,A:255). - /// - public static Color Black - { - get; - private set; - } - - /// - /// BlanchedAlmond color (R:255,G:235,B:205,A:255). - /// - public static Color BlanchedAlmond - { - get; - private set; - } - - /// - /// Blue color (R:0,G:0,B:255,A:255). - /// - public static Color Blue - { - get; - private set; - } - - /// - /// BlueViolet color (R:138,G:43,B:226,A:255). - /// - public static Color BlueViolet - { - get; - private set; - } - - /// - /// Brown color (R:165,G:42,B:42,A:255). - /// - public static Color Brown - { - get; - private set; - } - - /// - /// BurlyWood color (R:222,G:184,B:135,A:255). - /// - public static Color BurlyWood - { - get; - private set; - } - - /// - /// CadetBlue color (R:95,G:158,B:160,A:255). - /// - public static Color CadetBlue - { - get; - private set; - } - - /// - /// Chartreuse color (R:127,G:255,B:0,A:255). - /// - public static Color Chartreuse - { - get; - private set; - } - - /// - /// Chocolate color (R:210,G:105,B:30,A:255). - /// - public static Color Chocolate - { - get; - private set; - } - - /// - /// Coral color (R:255,G:127,B:80,A:255). - /// - public static Color Coral - { - get; - private set; - } - - /// - /// CornflowerBlue color (R:100,G:149,B:237,A:255). - /// - public static Color CornflowerBlue - { - get; - private set; - } - - /// - /// Cornsilk color (R:255,G:248,B:220,A:255). - /// - public static Color Cornsilk - { - get; - private set; - } - - /// - /// Crimson color (R:220,G:20,B:60,A:255). - /// - public static Color Crimson - { - get; - private set; - } - - /// - /// Cyan color (R:0,G:255,B:255,A:255). - /// - public static Color Cyan - { - get; - private set; - } - - /// - /// DarkBlue color (R:0,G:0,B:139,A:255). - /// - public static Color DarkBlue - { - get; - private set; - } - - /// - /// DarkCyan color (R:0,G:139,B:139,A:255). - /// - public static Color DarkCyan - { - get; - private set; - } - - /// - /// DarkGoldenrod color (R:184,G:134,B:11,A:255). - /// - public static Color DarkGoldenrod - { - get; - private set; - } - - /// - /// DarkGray color (R:169,G:169,B:169,A:255). - /// - public static Color DarkGray - { - get; - private set; - } - - /// - /// DarkGreen color (R:0,G:100,B:0,A:255). - /// - public static Color DarkGreen - { - get; - private set; - } - - /// - /// DarkKhaki color (R:189,G:183,B:107,A:255). - /// - public static Color DarkKhaki - { - get; - private set; - } - - /// - /// DarkMagenta color (R:139,G:0,B:139,A:255). - /// - public static Color DarkMagenta - { - get; - private set; - } - - /// - /// DarkOliveGreen color (R:85,G:107,B:47,A:255). - /// - public static Color DarkOliveGreen - { - get; - private set; - } - - /// - /// DarkOrange color (R:255,G:140,B:0,A:255). - /// - public static Color DarkOrange - { - get; - private set; - } - - /// - /// DarkOrchid color (R:153,G:50,B:204,A:255). - /// - public static Color DarkOrchid - { - get; - private set; - } - - /// - /// DarkRed color (R:139,G:0,B:0,A:255). - /// - public static Color DarkRed - { - get; - private set; - } - - /// - /// DarkSalmon color (R:233,G:150,B:122,A:255). - /// - public static Color DarkSalmon - { - get; - private set; - } - - /// - /// DarkSeaGreen color (R:143,G:188,B:139,A:255). - /// - public static Color DarkSeaGreen - { - get; - private set; - } - - /// - /// DarkSlateBlue color (R:72,G:61,B:139,A:255). - /// - public static Color DarkSlateBlue - { - get; - private set; - } - - /// - /// DarkSlateGray color (R:47,G:79,B:79,A:255). - /// - public static Color DarkSlateGray - { - get; - private set; - } - - /// - /// DarkTurquoise color (R:0,G:206,B:209,A:255). - /// - public static Color DarkTurquoise - { - get; - private set; - } - - /// - /// DarkViolet color (R:148,G:0,B:211,A:255). - /// - public static Color DarkViolet - { - get; - private set; - } - - /// - /// DeepPink color (R:255,G:20,B:147,A:255). - /// - public static Color DeepPink - { - get; - private set; - } - - /// - /// DeepSkyBlue color (R:0,G:191,B:255,A:255). - /// - public static Color DeepSkyBlue - { - get; - private set; - } - - /// - /// DimGray color (R:105,G:105,B:105,A:255). - /// - public static Color DimGray - { - get; - private set; - } - - /// - /// DodgerBlue color (R:30,G:144,B:255,A:255). - /// - public static Color DodgerBlue - { - get; - private set; - } - - /// - /// Firebrick color (R:178,G:34,B:34,A:255). - /// - public static Color Firebrick - { - get; - private set; - } - - /// - /// FloralWhite color (R:255,G:250,B:240,A:255). - /// - public static Color FloralWhite - { - get; - private set; - } - - /// - /// ForestGreen color (R:34,G:139,B:34,A:255). - /// - public static Color ForestGreen - { - get; - private set; - } - - /// - /// Fuchsia color (R:255,G:0,B:255,A:255). - /// - public static Color Fuchsia - { - get; - private set; - } - - /// - /// Gainsboro color (R:220,G:220,B:220,A:255). - /// - public static Color Gainsboro - { - get; - private set; - } - - /// - /// GhostWhite color (R:248,G:248,B:255,A:255). - /// - public static Color GhostWhite - { - get; - private set; - } - /// - /// Gold color (R:255,G:215,B:0,A:255). - /// - public static Color Gold - { - get; - private set; - } - - /// - /// Goldenrod color (R:218,G:165,B:32,A:255). - /// - public static Color Goldenrod - { - get; - private set; - } - - /// - /// Gray color (R:128,G:128,B:128,A:255). - /// - public static Color Gray - { - get; - private set; - } - - /// - /// Green color (R:0,G:128,B:0,A:255). - /// - public static Color Green - { - get; - private set; - } - - /// - /// GreenYellow color (R:173,G:255,B:47,A:255). - /// - public static Color GreenYellow - { - get; - private set; - } - - /// - /// Honeydew color (R:240,G:255,B:240,A:255). - /// - public static Color Honeydew - { - get; - private set; - } - - /// - /// HotPink color (R:255,G:105,B:180,A:255). - /// - public static Color HotPink - { - get; - private set; - } - - /// - /// IndianRed color (R:205,G:92,B:92,A:255). - /// - public static Color IndianRed - { - get; - private set; - } - - /// - /// Indigo color (R:75,G:0,B:130,A:255). - /// - public static Color Indigo - { - get; - private set; - } - - /// - /// Ivory color (R:255,G:255,B:240,A:255). - /// - public static Color Ivory - { - get; - private set; - } - - /// - /// Khaki color (R:240,G:230,B:140,A:255). - /// - public static Color Khaki - { - get; - private set; - } - - /// - /// Lavender color (R:230,G:230,B:250,A:255). - /// - public static Color Lavender - { - get; - private set; - } - - /// - /// LavenderBlush color (R:255,G:240,B:245,A:255). - /// - public static Color LavenderBlush - { - get; - private set; - } - - /// - /// LawnGreen color (R:124,G:252,B:0,A:255). - /// - public static Color LawnGreen - { - get; - private set; - } - - /// - /// LemonChiffon color (R:255,G:250,B:205,A:255). - /// - public static Color LemonChiffon - { - get; - private set; - } - - /// - /// LightBlue color (R:173,G:216,B:230,A:255). - /// - public static Color LightBlue - { - get; - private set; - } - - /// - /// LightCoral color (R:240,G:128,B:128,A:255). - /// - public static Color LightCoral - { - get; - private set; - } - - /// - /// LightCyan color (R:224,G:255,B:255,A:255). - /// - public static Color LightCyan - { - get; - private set; - } - - /// - /// LightGoldenrodYellow color (R:250,G:250,B:210,A:255). - /// - public static Color LightGoldenrodYellow - { - get; - private set; - } - - /// - /// LightGray color (R:211,G:211,B:211,A:255). - /// - public static Color LightGray - { - get; - private set; - } - - /// - /// LightGreen color (R:144,G:238,B:144,A:255). - /// - public static Color LightGreen - { - get; - private set; - } - - /// - /// LightPink color (R:255,G:182,B:193,A:255). - /// - public static Color LightPink - { - get; - private set; - } - - /// - /// LightSalmon color (R:255,G:160,B:122,A:255). - /// - public static Color LightSalmon - { - get; - private set; - } - - /// - /// LightSeaGreen color (R:32,G:178,B:170,A:255). - /// - public static Color LightSeaGreen - { - get; - private set; - } - - /// - /// LightSkyBlue color (R:135,G:206,B:250,A:255). - /// - public static Color LightSkyBlue - { - get; - private set; - } - - /// - /// LightSlateGray color (R:119,G:136,B:153,A:255). - /// - public static Color LightSlateGray - { - get; - private set; - } - - /// - /// LightSteelBlue color (R:176,G:196,B:222,A:255). - /// - public static Color LightSteelBlue - { - get; - private set; - } - - /// - /// LightYellow color (R:255,G:255,B:224,A:255). - /// - public static Color LightYellow - { - get; - private set; - } - - /// - /// Lime color (R:0,G:255,B:0,A:255). - /// - public static Color Lime - { - get; - private set; - } - - /// - /// LimeGreen color (R:50,G:205,B:50,A:255). - /// - public static Color LimeGreen - { - get; - private set; - } - - /// - /// Linen color (R:250,G:240,B:230,A:255). - /// - public static Color Linen - { - get; - private set; - } - - /// - /// Magenta color (R:255,G:0,B:255,A:255). - /// - public static Color Magenta - { - get; - private set; - } - - /// - /// Maroon color (R:128,G:0,B:0,A:255). - /// - public static Color Maroon - { - get; - private set; - } - - /// - /// MediumAquamarine color (R:102,G:205,B:170,A:255). - /// - public static Color MediumAquamarine - { - get; - private set; - } - - /// - /// MediumBlue color (R:0,G:0,B:205,A:255). - /// - public static Color MediumBlue - { - get; - private set; - } - - /// - /// MediumOrchid color (R:186,G:85,B:211,A:255). - /// - public static Color MediumOrchid - { - get; - private set; - } - - /// - /// MediumPurple color (R:147,G:112,B:219,A:255). - /// - public static Color MediumPurple - { - get; - private set; - } - - /// - /// MediumSeaGreen color (R:60,G:179,B:113,A:255). - /// - public static Color MediumSeaGreen - { - get; - private set; - } - - /// - /// MediumSlateBlue color (R:123,G:104,B:238,A:255). - /// - public static Color MediumSlateBlue - { - get; - private set; - } - - /// - /// MediumSpringGreen color (R:0,G:250,B:154,A:255). - /// - public static Color MediumSpringGreen - { - get; - private set; - } - - /// - /// MediumTurquoise color (R:72,G:209,B:204,A:255). - /// - public static Color MediumTurquoise - { - get; - private set; - } - - /// - /// MediumVioletRed color (R:199,G:21,B:133,A:255). - /// - public static Color MediumVioletRed - { - get; - private set; - } - - /// - /// MidnightBlue color (R:25,G:25,B:112,A:255). - /// - public static Color MidnightBlue - { - get; - private set; - } - - /// - /// MintCream color (R:245,G:255,B:250,A:255). - /// - public static Color MintCream - { - get; - private set; - } - - /// - /// MistyRose color (R:255,G:228,B:225,A:255). - /// - public static Color MistyRose - { - get; - private set; - } - - /// - /// Moccasin color (R:255,G:228,B:181,A:255). - /// - public static Color Moccasin - { - get; - private set; - } - - /// - /// NavajoWhite color (R:255,G:222,B:173,A:255). - /// - public static Color NavajoWhite - { - get; - private set; - } - - /// - /// Navy color (R:0,G:0,B:128,A:255). - /// - public static Color Navy - { - get; - private set; - } - - /// - /// OldLace color (R:253,G:245,B:230,A:255). - /// - public static Color OldLace - { - get; - private set; - } - - /// - /// Olive color (R:128,G:128,B:0,A:255). - /// - public static Color Olive - { - get; - private set; - } - - /// - /// OliveDrab color (R:107,G:142,B:35,A:255). - /// - public static Color OliveDrab - { - get; - private set; - } - - /// - /// Orange color (R:255,G:165,B:0,A:255). - /// - public static Color Orange - { - get; - private set; - } - - /// - /// OrangeRed color (R:255,G:69,B:0,A:255). - /// - public static Color OrangeRed - { - get; - private set; - } - - /// - /// Orchid color (R:218,G:112,B:214,A:255). - /// - public static Color Orchid - { - get; - private set; - } - - /// - /// PaleGoldenrod color (R:238,G:232,B:170,A:255). - /// - public static Color PaleGoldenrod - { - get; - private set; - } - - /// - /// PaleGreen color (R:152,G:251,B:152,A:255). - /// - public static Color PaleGreen - { - get; - private set; - } - - /// - /// PaleTurquoise color (R:175,G:238,B:238,A:255). - /// - public static Color PaleTurquoise - { - get; - private set; - } - /// - /// PaleVioletRed color (R:219,G:112,B:147,A:255). - /// - public static Color PaleVioletRed - { - get; - private set; - } - - /// - /// PapayaWhip color (R:255,G:239,B:213,A:255). - /// - public static Color PapayaWhip - { - get; - private set; - } - - /// - /// PeachPuff color (R:255,G:218,B:185,A:255). - /// - public static Color PeachPuff - { - get; - private set; - } - - /// - /// Peru color (R:205,G:133,B:63,A:255). - /// - public static Color Peru - { - get; - private set; - } - - /// - /// Pink color (R:255,G:192,B:203,A:255). - /// - public static Color Pink - { - get; - private set; - } - - /// - /// Plum color (R:221,G:160,B:221,A:255). - /// - public static Color Plum - { - get; - private set; - } - - /// - /// PowderBlue color (R:176,G:224,B:230,A:255). - /// - public static Color PowderBlue - { - get; - private set; - } - - /// - /// Purple color (R:128,G:0,B:128,A:255). - /// - public static Color Purple - { - get; - private set; - } - - /// - /// Red color (R:255,G:0,B:0,A:255). - /// - public static Color Red - { - get; - private set; - } - - /// - /// RosyBrown color (R:188,G:143,B:143,A:255). - /// - public static Color RosyBrown - { - get; - private set; - } - - /// - /// RoyalBlue color (R:65,G:105,B:225,A:255). - /// - public static Color RoyalBlue - { - get; - private set; - } - - /// - /// SaddleBrown color (R:139,G:69,B:19,A:255). - /// - public static Color SaddleBrown - { - get; - private set; - } - - /// - /// Salmon color (R:250,G:128,B:114,A:255). - /// - public static Color Salmon - { - get; - private set; - } - - /// - /// SandyBrown color (R:244,G:164,B:96,A:255). - /// - public static Color SandyBrown - { - get; - private set; - } - - /// - /// SeaGreen color (R:46,G:139,B:87,A:255). - /// - public static Color SeaGreen - { - get; - private set; - } - - /// - /// SeaShell color (R:255,G:245,B:238,A:255). - /// - public static Color SeaShell - { - get; - private set; - } - - /// - /// Sienna color (R:160,G:82,B:45,A:255). - /// - public static Color Sienna - { - get; - private set; - } - - /// - /// Silver color (R:192,G:192,B:192,A:255). - /// - public static Color Silver - { - get; - private set; - } - - /// - /// SkyBlue color (R:135,G:206,B:235,A:255). - /// - public static Color SkyBlue - { - get; - private set; - } - - /// - /// SlateBlue color (R:106,G:90,B:205,A:255). - /// - public static Color SlateBlue - { - get; - private set; - } - - /// - /// SlateGray color (R:112,G:128,B:144,A:255). - /// - public static Color SlateGray - { - get; - private set; - } - - /// - /// Snow color (R:255,G:250,B:250,A:255). - /// - public static Color Snow - { - get; - private set; - } - - /// - /// SpringGreen color (R:0,G:255,B:127,A:255). - /// - public static Color SpringGreen - { - get; - private set; - } - - /// - /// SteelBlue color (R:70,G:130,B:180,A:255). - /// - public static Color SteelBlue - { - get; - private set; - } - - /// - /// Tan color (R:210,G:180,B:140,A:255). - /// - public static Color Tan - { - get; - private set; - } - - /// - /// Teal color (R:0,G:128,B:128,A:255). - /// - public static Color Teal - { - get; - private set; - } - - /// - /// Thistle color (R:216,G:191,B:216,A:255). - /// - public static Color Thistle - { - get; - private set; - } - - /// - /// Tomato color (R:255,G:99,B:71,A:255). - /// - public static Color Tomato - { - get; - private set; - } - - /// - /// Turquoise color (R:64,G:224,B:208,A:255). - /// - public static Color Turquoise - { - get; - private set; - } - - /// - /// Violet color (R:238,G:130,B:238,A:255). - /// - public static Color Violet - { - get; - private set; - } - - /// - /// Wheat color (R:245,G:222,B:179,A:255). - /// - public static Color Wheat - { - get; - private set; - } - - /// - /// White color (R:255,G:255,B:255,A:255). - /// - public static Color White - { - get; - private set; - } - - /// - /// WhiteSmoke color (R:245,G:245,B:245,A:255). - /// - public static Color WhiteSmoke - { - get; - private set; - } - - /// - /// Yellow color (R:255,G:255,B:0,A:255). - /// - public static Color Yellow - { - get; - private set; - } - - /// - /// YellowGreen color (R:154,G:205,B:50,A:255). - /// - public static Color YellowGreen - { - get; - private set; - } - - #endregion - - #region Private Variables - - // ARGB - private uint _packedValue; - - #endregion - - #region Private Static Constructors - - static Color() - { - TransparentBlack = new Color(0); - Transparent = new Color(0); - AliceBlue = new Color(0xfffff8f0); - AntiqueWhite = new Color(0xffd7ebfa); - Aqua = new Color(0xffffff00); - Aquamarine = new Color(0xffd4ff7f); - Azure = new Color(0xfffffff0); - Beige = new Color(0xffdcf5f5); - Bisque = new Color(0xffc4e4ff); - Black = new Color(0xff000000); - BlanchedAlmond = new Color(0xffcdebff); - Blue = new Color(0xffff0000); - BlueViolet = new Color(0xffe22b8a); - Brown = new Color(0xff2a2aa5); - BurlyWood = new Color(0xff87b8de); - CadetBlue = new Color(0xffa09e5f); - Chartreuse = new Color(0xff00ff7f); - Chocolate = new Color(0xff1e69d2); - Coral = new Color(0xff507fff); - CornflowerBlue = new Color(0xffed9564); - Cornsilk = new Color(0xffdcf8ff); - Crimson = new Color(0xff3c14dc); - Cyan = new Color(0xffffff00); - DarkBlue = new Color(0xff8b0000); - DarkCyan = new Color(0xff8b8b00); - DarkGoldenrod = new Color(0xff0b86b8); - DarkGray = new Color(0xffa9a9a9); - DarkGreen = new Color(0xff006400); - DarkKhaki = new Color(0xff6bb7bd); - DarkMagenta = new Color(0xff8b008b); - DarkOliveGreen = new Color(0xff2f6b55); - DarkOrange = new Color(0xff008cff); - DarkOrchid = new Color(0xffcc3299); - DarkRed = new Color(0xff00008b); - DarkSalmon = new Color(0xff7a96e9); - DarkSeaGreen = new Color(0xff8bbc8f); - DarkSlateBlue = new Color(0xff8b3d48); - DarkSlateGray = new Color(0xff4f4f2f); - DarkTurquoise = new Color(0xffd1ce00); - DarkViolet = new Color(0xffd30094); - DeepPink = new Color(0xff9314ff); - DeepSkyBlue = new Color(0xffffbf00); - DimGray = new Color(0xff696969); - DodgerBlue = new Color(0xffff901e); - Firebrick = new Color(0xff2222b2); - FloralWhite = new Color(0xfff0faff); - ForestGreen = new Color(0xff228b22); - Fuchsia = new Color(0xffff00ff); - Gainsboro = new Color(0xffdcdcdc); - GhostWhite = new Color(0xfffff8f8); - Gold = new Color(0xff00d7ff); - Goldenrod = new Color(0xff20a5da); - Gray = new Color(0xff808080); - Green = new Color(0xff008000); - GreenYellow = new Color(0xff2fffad); - Honeydew = new Color(0xfff0fff0); - HotPink = new Color(0xffb469ff); - IndianRed = new Color(0xff5c5ccd); - Indigo = new Color(0xff82004b); - Ivory = new Color(0xfff0ffff); - Khaki = new Color(0xff8ce6f0); - Lavender = new Color(0xfffae6e6); - LavenderBlush = new Color(0xfff5f0ff); - LawnGreen = new Color(0xff00fc7c); - LemonChiffon = new Color(0xffcdfaff); - LightBlue = new Color(0xffe6d8ad); - LightCoral = new Color(0xff8080f0); - LightCyan = new Color(0xffffffe0); - LightGoldenrodYellow = new Color(0xffd2fafa); - LightGray = new Color(0xffd3d3d3); - LightGreen = new Color(0xff90ee90); - LightPink = new Color(0xffc1b6ff); - LightSalmon = new Color(0xff7aa0ff); - LightSeaGreen = new Color(0xffaab220); - LightSkyBlue = new Color(0xffface87); - LightSlateGray = new Color(0xff998877); - LightSteelBlue = new Color(0xffdec4b0); - LightYellow = new Color(0xffe0ffff); - Lime = new Color(0xff00ff00); - LimeGreen = new Color(0xff32cd32); - Linen = new Color(0xffe6f0fa); - Magenta = new Color(0xffff00ff); - Maroon = new Color(0xff000080); - MediumAquamarine = new Color(0xffaacd66); - MediumBlue = new Color(0xffcd0000); - MediumOrchid = new Color(0xffd355ba); - MediumPurple = new Color(0xffdb7093); - MediumSeaGreen = new Color(0xff71b33c); - MediumSlateBlue = new Color(0xffee687b); - MediumSpringGreen = new Color(0xff9afa00); - MediumTurquoise = new Color(0xffccd148); - MediumVioletRed = new Color(0xff8515c7); - MidnightBlue = new Color(0xff701919); - MintCream = new Color(0xfffafff5); - MistyRose = new Color(0xffe1e4ff); - Moccasin = new Color(0xffb5e4ff); - NavajoWhite = new Color(0xffaddeff); - Navy = new Color(0xff800000); - OldLace = new Color(0xffe6f5fd); - Olive = new Color(0xff008080); - OliveDrab = new Color(0xff238e6b); - Orange = new Color(0xff00a5ff); - OrangeRed = new Color(0xff0045ff); - Orchid = new Color(0xffd670da); - PaleGoldenrod = new Color(0xffaae8ee); - PaleGreen = new Color(0xff98fb98); - PaleTurquoise = new Color(0xffeeeeaf); - PaleVioletRed = new Color(0xff9370db); - PapayaWhip = new Color(0xffd5efff); - PeachPuff = new Color(0xffb9daff); - Peru = new Color(0xff3f85cd); - Pink = new Color(0xffcbc0ff); - Plum = new Color(0xffdda0dd); - PowderBlue = new Color(0xffe6e0b0); - Purple = new Color(0xff800080); - Red = new Color(0xff0000ff); - RosyBrown = new Color(0xff8f8fbc); - RoyalBlue = new Color(0xffe16941); - SaddleBrown = new Color(0xff13458b); - Salmon= new Color(0xff7280fa); - SandyBrown = new Color(0xff60a4f4); - SeaGreen = new Color(0xff578b2e); - SeaShell = new Color(0xffeef5ff); - Sienna = new Color(0xff2d52a0); - Silver = new Color(0xffc0c0c0); - SkyBlue = new Color(0xffebce87); - SlateBlue= new Color(0xffcd5a6a); - SlateGray= new Color(0xff908070); - Snow= new Color(0xfffafaff); - SpringGreen= new Color(0xff7fff00); - SteelBlue= new Color(0xffb48246); - Tan= new Color(0xff8cb4d2); - Teal= new Color(0xff808000); - Thistle= new Color(0xffd8bfd8); - Tomato= new Color(0xff4763ff); - Turquoise= new Color(0xffd0e040); - Violet= new Color(0xffee82ee); - Wheat= new Color(0xffb3def5); - White= new Color(uint.MaxValue); - WhiteSmoke= new Color(0xfff5f5f5); - Yellow = new Color(0xff00ffff); - YellowGreen = new Color(0xff32cd9a); - } - - #endregion - - #region Public Constructors - - /// - /// Creates a new instance of struct. - /// - /// A representing color. - public Color(Vector4 color) - { - _packedValue = 0; - - R = (byte)MathHelper.Clamp(color.X * 255, Byte.MinValue, Byte.MaxValue); - G = (byte)MathHelper.Clamp(color.Y * 255, Byte.MinValue, Byte.MaxValue); - B = (byte)MathHelper.Clamp(color.Z * 255, Byte.MinValue, Byte.MaxValue); - A = (byte)MathHelper.Clamp(color.W * 255, Byte.MinValue, Byte.MaxValue); - } - - /// - /// Creates a new instance of struct. - /// - /// A representing color. - public Color(Vector3 color) - { - _packedValue = 0; - - R = (byte)MathHelper.Clamp(color.X * 255, Byte.MinValue, Byte.MaxValue); - G = (byte)MathHelper.Clamp(color.Y * 255, Byte.MinValue, Byte.MaxValue); - B = (byte)MathHelper.Clamp(color.Z * 255, Byte.MinValue, Byte.MaxValue); - A = 255; - } - - /// - /// Creates a new instance of struct. - /// - /// A for RGB values of new instance. - /// Alpha component value. - public Color(Color color, int alpha) - { - _packedValue = 0; - - R = color.R; - G = color.G; - B = color.B; - A = (byte)MathHelper.Clamp(alpha, Byte.MinValue, Byte.MaxValue); - } - - /// - /// Creates a new instance of struct. - /// - /// A for RGB values of new instance. - /// Alpha component value. - public Color(Color color, float alpha) - { - _packedValue = 0; - - R = color.R; - G = color.G; - B = color.B; - A = (byte)MathHelper.Clamp(alpha * 255, Byte.MinValue, Byte.MaxValue); - } - - /// - /// Creates a new instance of struct. - /// - /// Red component value. - /// Green component value. - /// Blue component value - public Color(float r, float g, float b) - { - _packedValue = 0; - - R = (byte)MathHelper.Clamp(r * 255, Byte.MinValue, Byte.MaxValue); - G = (byte)MathHelper.Clamp(g * 255, Byte.MinValue, Byte.MaxValue); - B = (byte)MathHelper.Clamp(b * 255, Byte.MinValue, Byte.MaxValue); - A = 255; - } - - /// - /// Creates a new instance of struct. - /// - /// Red component value. - /// Green component value. - /// Blue component value - public Color(int r, int g, int b) - { - _packedValue = 0; - R = (byte)MathHelper.Clamp(r, Byte.MinValue, Byte.MaxValue); - G = (byte)MathHelper.Clamp(g, Byte.MinValue, Byte.MaxValue); - B = (byte)MathHelper.Clamp(b, Byte.MinValue, Byte.MaxValue); - A = (byte)255; - } - - /// - /// Creates a new instance of struct. - /// - /// Red component value. - /// Green component value. - /// Blue component value - /// Alpha component value. - public Color(int r, int g, int b, int alpha) - { - _packedValue = 0; - R = (byte)MathHelper.Clamp(r, Byte.MinValue, Byte.MaxValue); - G = (byte)MathHelper.Clamp(g, Byte.MinValue, Byte.MaxValue); - B = (byte)MathHelper.Clamp(b, Byte.MinValue, Byte.MaxValue); - A = (byte)MathHelper.Clamp(alpha, Byte.MinValue, Byte.MaxValue); - } - - /// - /// Creates a new instance of struct. - /// - /// Red component value. - /// Green component value. - /// Blue component value - /// Alpha component value. - public Color(float r, float g, float b, float alpha) - { - _packedValue = 0; - - R = (byte)MathHelper.Clamp(r * 255, Byte.MinValue, Byte.MaxValue); - G = (byte)MathHelper.Clamp(g * 255, Byte.MinValue, Byte.MaxValue); - B = (byte)MathHelper.Clamp(b * 255, Byte.MinValue, Byte.MaxValue); - A = (byte)MathHelper.Clamp(alpha * 255, Byte.MinValue, Byte.MaxValue); - } - - #endregion - - #region Private Constructors - - private Color(uint packedValue) - { - _packedValue = packedValue; - // ARGB - //_packedValue = (packedValue << 8) | ((packedValue & 0xff000000) >> 24); - // ABGR - //_packedValue = (packedValue & 0xff00ff00) | ((packedValue & 0x000000ff) << 16) | ((packedValue & 0x00ff0000) >> 16); - } - - #endregion - - #region Public Methods - - /// - /// Compares whether current instance is equal to specified . - /// - /// The to compare. - /// true if the instances are equal; false otherwise. - public bool Equals(Color other) - { - return this.PackedValue == other.PackedValue; - } - - /// - /// Converts to . - /// - /// Converted color. - public Vector3 ToVector3() - { - return new Vector3(R / 255.0f, G / 255.0f, B / 255.0f); - } - - /// - /// Converts to . - /// - /// Converted color. - public Vector4 ToVector4() - { - return new Vector4(R / 255.0f, G / 255.0f, B / 255.0f, A / 255.0f); - } - - #endregion - - #region Public Static Methods - - /// - /// Performs linear interpolation of . - /// - /// Source . - /// Destination . - /// Interpolation factor. - /// Interpolated . - public static Color Lerp(Color value1, Color value2, Single amount) - { - return new Color( - (int)MathHelper.Lerp(value1.R, value2.R, amount), - (int)MathHelper.Lerp(value1.G, value2.G, amount), - (int)MathHelper.Lerp(value1.B, value2.B, amount), - (int)MathHelper.Lerp(value1.A, value2.A, amount)); - } - - /// - /// Translate a non-premultipled alpha to a that contains premultiplied alpha. - /// - /// A representing color. - /// A which contains premultiplied alpha data. - public static Color FromNonPremultiplied(Vector4 vector) - { - return new Color(vector.X * vector.W, vector.Y * vector.W, vector.Z * vector.W, vector.W); - } - - /// - /// Translate a non-premultipled alpha to a that contains premultiplied alpha. - /// - /// Red component value. - /// Green component value. - /// Blue component value. - /// Alpha component value. - /// A which contains premultiplied alpha data. - public static Color FromNonPremultiplied(int r, int g, int b, int a) - { - return new Color((byte)(r * a / 255), (byte)(g * a / 255), (byte)(b * a / 255), a); - } - - #endregion - - #region Public Static Operators and Override Methods - - /// - /// Compares whether two instances are equal. - /// - /// instance on the left of the equal sign. - /// instance on the right of the equal sign. - /// true if the instances are equal; false otherwise. - public static bool operator ==(Color a, Color b) - { - return (a.A == b.A && - a.R == b.R && - a.G == b.G && - a.B == b.B); - } - /// - /// Compares whether two instances are not equal. - /// - /// instance on the left of the not equal sign. - /// instance on the right of the not equal sign. - /// true if the instances are not equal; false otherwise. - public static bool operator !=(Color a, Color b) - { - return !(a == b); - } - - /// - /// Gets the hash code for instance. - /// - /// Hash code of the object. - public override int GetHashCode() - { - return this._packedValue.GetHashCode(); - } - - /// - /// Compares whether current instance is equal to specified object. - /// - /// The to compare. - /// true if the instances are equal; false otherwise. - public override bool Equals(object obj) - { - return ((obj is Color) && this.Equals((Color)obj)); - } - - /// - /// Multiply by value. - /// - /// Source . - /// Multiplicator. - /// Multiplication result. - public static Color Multiply(Color value, float scale) - { - return new Color((int)(value.R * scale), (int)(value.G * scale), (int)(value.B * scale), (int)(value.A * scale)); - } - - /// - /// Multiply by value. - /// - /// Source . - /// Multiplicator. - /// Multiplication result. - public static Color operator *(Color value, float scale) - { - return new Color((int)(value.R * scale), (int)(value.G * scale), (int)(value.B * scale), (int)(value.A * scale)); - } - - /// - /// Converts the color values of this instance to its equivalent string representation. - /// - /// The string representation of the color value of this instance. - public override string ToString() - { - StringBuilder sb = new StringBuilder(25); - sb.Append("{R:"); - sb.Append(R); - sb.Append(" G:"); - sb.Append(G); - sb.Append(" B:"); - sb.Append(B); - sb.Append(" A:"); - sb.Append(A); - sb.Append("}"); - return sb.ToString(); - } - - #endregion - } - - #region XNAColorConverter Class - - public class XNAColorConverter : TypeConverter - { - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) - { - if (sourceType == typeof(string)) - { - return true; - } - return base.CanConvertFrom(context, sourceType); - } - - public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) - { - if (value is string) - { - string[] v = ((string) value).Split(culture.NumberFormat.NumberGroupSeparator.ToCharArray()); - return new Color( - float.Parse(v[0], culture), - float.Parse(v[1], culture), - float.Parse(v[2], culture), - float.Parse(v[3], culture) - ); - } - return base.ConvertFrom(context, culture, value); - } - - public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) - { - if (destinationType == typeof(string)) - { - Color src = (Color) value; - string sep = culture.NumberFormat.NumberGroupSeparator; - return src.R.ToString(culture) + sep + src.B.ToString(culture) + sep + src.B.ToString(culture) + sep + src.A.ToString(culture); - } - return base.ConvertTo(context, culture, value, destinationType); - } - } - - #endregion + /// Describe a 32-bit packed color. + /// + [DataContract] + [TypeConverter(typeof(XNAColorConverter))] + public struct Color : IEquatable + { + #region Public Properties + + /// + /// Gets or sets the blue component of . + /// + [DataMember] + public byte B + { + get + { + return (byte) (this._packedValue >> 16); + } + set + { + this._packedValue = (this._packedValue & 0xff00ffff) | (uint) (value << 16); + } + } + + /// + /// Gets or sets the green component of . + /// + [DataMember] + public byte G + { + get + { + return (byte) (this._packedValue >> 8); + } + set + { + this._packedValue = (this._packedValue & 0xffff00ff) | ((uint) (value << 8)); + } + } + + /// + /// Gets or sets the red component of . + /// + [DataMember] + public byte R + { + get + { + return (byte) (this._packedValue); + } + set + { + this._packedValue = (this._packedValue & 0xffffff00) | value; + } + } + + /// + /// Gets or sets the alpha component of . + /// + [DataMember] + public byte A + { + get + { + return (byte) (this._packedValue >> 24); + } + set + { + this._packedValue = (this._packedValue & 0x00ffffff) | ((uint) (value << 24)); + } + } + + /// + /// Gets or sets packed value of this . + /// + [CLSCompliant(false)] + public UInt32 PackedValue + { + get + { + return _packedValue; + } + set + { + _packedValue = value; + } + } + + #endregion + + #region Public Static Color Properties + + /// + /// TransparentBlack color (R:0,G:0,B:0,A:0). + /// + public static Color TransparentBlack + { + get; + private set; + } + + /// + /// Transparent color (R:0,G:0,B:0,A:0). + /// + public static Color Transparent + { + get; + private set; + } + + /// + /// AliceBlue color (R:240,G:248,B:255,A:255). + /// + public static Color AliceBlue + { + get; + private set; + } + + /// + /// AntiqueWhite color (R:250,G:235,B:215,A:255). + /// + public static Color AntiqueWhite + { + get; + private set; + } + + /// + /// Aqua color (R:0,G:255,B:255,A:255). + /// + public static Color Aqua + { + get; + private set; + } + + /// + /// Aquamarine color (R:127,G:255,B:212,A:255). + /// + public static Color Aquamarine + { + get; + private set; + } + + /// + /// Azure color (R:240,G:255,B:255,A:255). + /// + public static Color Azure + { + get; + private set; + } + + /// + /// Beige color (R:245,G:245,B:220,A:255). + /// + public static Color Beige + { + get; + private set; + } + + /// + /// Bisque color (R:255,G:228,B:196,A:255). + /// + public static Color Bisque + { + get; + private set; + } + + /// + /// Black color (R:0,G:0,B:0,A:255). + /// + public static Color Black + { + get; + private set; + } + + /// + /// BlanchedAlmond color (R:255,G:235,B:205,A:255). + /// + public static Color BlanchedAlmond + { + get; + private set; + } + + /// + /// Blue color (R:0,G:0,B:255,A:255). + /// + public static Color Blue + { + get; + private set; + } + + /// + /// BlueViolet color (R:138,G:43,B:226,A:255). + /// + public static Color BlueViolet + { + get; + private set; + } + + /// + /// Brown color (R:165,G:42,B:42,A:255). + /// + public static Color Brown + { + get; + private set; + } + + /// + /// BurlyWood color (R:222,G:184,B:135,A:255). + /// + public static Color BurlyWood + { + get; + private set; + } + + /// + /// CadetBlue color (R:95,G:158,B:160,A:255). + /// + public static Color CadetBlue + { + get; + private set; + } + + /// + /// Chartreuse color (R:127,G:255,B:0,A:255). + /// + public static Color Chartreuse + { + get; + private set; + } + + /// + /// Chocolate color (R:210,G:105,B:30,A:255). + /// + public static Color Chocolate + { + get; + private set; + } + + /// + /// Coral color (R:255,G:127,B:80,A:255). + /// + public static Color Coral + { + get; + private set; + } + + /// + /// CornflowerBlue color (R:100,G:149,B:237,A:255). + /// + public static Color CornflowerBlue + { + get; + private set; + } + + /// + /// Cornsilk color (R:255,G:248,B:220,A:255). + /// + public static Color Cornsilk + { + get; + private set; + } + + /// + /// Crimson color (R:220,G:20,B:60,A:255). + /// + public static Color Crimson + { + get; + private set; + } + + /// + /// Cyan color (R:0,G:255,B:255,A:255). + /// + public static Color Cyan + { + get; + private set; + } + + /// + /// DarkBlue color (R:0,G:0,B:139,A:255). + /// + public static Color DarkBlue + { + get; + private set; + } + + /// + /// DarkCyan color (R:0,G:139,B:139,A:255). + /// + public static Color DarkCyan + { + get; + private set; + } + + /// + /// DarkGoldenrod color (R:184,G:134,B:11,A:255). + /// + public static Color DarkGoldenrod + { + get; + private set; + } + + /// + /// DarkGray color (R:169,G:169,B:169,A:255). + /// + public static Color DarkGray + { + get; + private set; + } + + /// + /// DarkGreen color (R:0,G:100,B:0,A:255). + /// + public static Color DarkGreen + { + get; + private set; + } + + /// + /// DarkKhaki color (R:189,G:183,B:107,A:255). + /// + public static Color DarkKhaki + { + get; + private set; + } + + /// + /// DarkMagenta color (R:139,G:0,B:139,A:255). + /// + public static Color DarkMagenta + { + get; + private set; + } + + /// + /// DarkOliveGreen color (R:85,G:107,B:47,A:255). + /// + public static Color DarkOliveGreen + { + get; + private set; + } + + /// + /// DarkOrange color (R:255,G:140,B:0,A:255). + /// + public static Color DarkOrange + { + get; + private set; + } + + /// + /// DarkOrchid color (R:153,G:50,B:204,A:255). + /// + public static Color DarkOrchid + { + get; + private set; + } + + /// + /// DarkRed color (R:139,G:0,B:0,A:255). + /// + public static Color DarkRed + { + get; + private set; + } + + /// + /// DarkSalmon color (R:233,G:150,B:122,A:255). + /// + public static Color DarkSalmon + { + get; + private set; + } + + /// + /// DarkSeaGreen color (R:143,G:188,B:139,A:255). + /// + public static Color DarkSeaGreen + { + get; + private set; + } + + /// + /// DarkSlateBlue color (R:72,G:61,B:139,A:255). + /// + public static Color DarkSlateBlue + { + get; + private set; + } + + /// + /// DarkSlateGray color (R:47,G:79,B:79,A:255). + /// + public static Color DarkSlateGray + { + get; + private set; + } + + /// + /// DarkTurquoise color (R:0,G:206,B:209,A:255). + /// + public static Color DarkTurquoise + { + get; + private set; + } + + /// + /// DarkViolet color (R:148,G:0,B:211,A:255). + /// + public static Color DarkViolet + { + get; + private set; + } + + /// + /// DeepPink color (R:255,G:20,B:147,A:255). + /// + public static Color DeepPink + { + get; + private set; + } + + /// + /// DeepSkyBlue color (R:0,G:191,B:255,A:255). + /// + public static Color DeepSkyBlue + { + get; + private set; + } + + /// + /// DimGray color (R:105,G:105,B:105,A:255). + /// + public static Color DimGray + { + get; + private set; + } + + /// + /// DodgerBlue color (R:30,G:144,B:255,A:255). + /// + public static Color DodgerBlue + { + get; + private set; + } + + /// + /// Firebrick color (R:178,G:34,B:34,A:255). + /// + public static Color Firebrick + { + get; + private set; + } + + /// + /// FloralWhite color (R:255,G:250,B:240,A:255). + /// + public static Color FloralWhite + { + get; + private set; + } + + /// + /// ForestGreen color (R:34,G:139,B:34,A:255). + /// + public static Color ForestGreen + { + get; + private set; + } + + /// + /// Fuchsia color (R:255,G:0,B:255,A:255). + /// + public static Color Fuchsia + { + get; + private set; + } + + /// + /// Gainsboro color (R:220,G:220,B:220,A:255). + /// + public static Color Gainsboro + { + get; + private set; + } + + /// + /// GhostWhite color (R:248,G:248,B:255,A:255). + /// + public static Color GhostWhite + { + get; + private set; + } + /// + /// Gold color (R:255,G:215,B:0,A:255). + /// + public static Color Gold + { + get; + private set; + } + + /// + /// Goldenrod color (R:218,G:165,B:32,A:255). + /// + public static Color Goldenrod + { + get; + private set; + } + + /// + /// Gray color (R:128,G:128,B:128,A:255). + /// + public static Color Gray + { + get; + private set; + } + + /// + /// Green color (R:0,G:128,B:0,A:255). + /// + public static Color Green + { + get; + private set; + } + + /// + /// GreenYellow color (R:173,G:255,B:47,A:255). + /// + public static Color GreenYellow + { + get; + private set; + } + + /// + /// Honeydew color (R:240,G:255,B:240,A:255). + /// + public static Color Honeydew + { + get; + private set; + } + + /// + /// HotPink color (R:255,G:105,B:180,A:255). + /// + public static Color HotPink + { + get; + private set; + } + + /// + /// IndianRed color (R:205,G:92,B:92,A:255). + /// + public static Color IndianRed + { + get; + private set; + } + + /// + /// Indigo color (R:75,G:0,B:130,A:255). + /// + public static Color Indigo + { + get; + private set; + } + + /// + /// Ivory color (R:255,G:255,B:240,A:255). + /// + public static Color Ivory + { + get; + private set; + } + + /// + /// Khaki color (R:240,G:230,B:140,A:255). + /// + public static Color Khaki + { + get; + private set; + } + + /// + /// Lavender color (R:230,G:230,B:250,A:255). + /// + public static Color Lavender + { + get; + private set; + } + + /// + /// LavenderBlush color (R:255,G:240,B:245,A:255). + /// + public static Color LavenderBlush + { + get; + private set; + } + + /// + /// LawnGreen color (R:124,G:252,B:0,A:255). + /// + public static Color LawnGreen + { + get; + private set; + } + + /// + /// LemonChiffon color (R:255,G:250,B:205,A:255). + /// + public static Color LemonChiffon + { + get; + private set; + } + + /// + /// LightBlue color (R:173,G:216,B:230,A:255). + /// + public static Color LightBlue + { + get; + private set; + } + + /// + /// LightCoral color (R:240,G:128,B:128,A:255). + /// + public static Color LightCoral + { + get; + private set; + } + + /// + /// LightCyan color (R:224,G:255,B:255,A:255). + /// + public static Color LightCyan + { + get; + private set; + } + + /// + /// LightGoldenrodYellow color (R:250,G:250,B:210,A:255). + /// + public static Color LightGoldenrodYellow + { + get; + private set; + } + + /// + /// LightGray color (R:211,G:211,B:211,A:255). + /// + public static Color LightGray + { + get; + private set; + } + + /// + /// LightGreen color (R:144,G:238,B:144,A:255). + /// + public static Color LightGreen + { + get; + private set; + } + + /// + /// LightPink color (R:255,G:182,B:193,A:255). + /// + public static Color LightPink + { + get; + private set; + } + + /// + /// LightSalmon color (R:255,G:160,B:122,A:255). + /// + public static Color LightSalmon + { + get; + private set; + } + + /// + /// LightSeaGreen color (R:32,G:178,B:170,A:255). + /// + public static Color LightSeaGreen + { + get; + private set; + } + + /// + /// LightSkyBlue color (R:135,G:206,B:250,A:255). + /// + public static Color LightSkyBlue + { + get; + private set; + } + + /// + /// LightSlateGray color (R:119,G:136,B:153,A:255). + /// + public static Color LightSlateGray + { + get; + private set; + } + + /// + /// LightSteelBlue color (R:176,G:196,B:222,A:255). + /// + public static Color LightSteelBlue + { + get; + private set; + } + + /// + /// LightYellow color (R:255,G:255,B:224,A:255). + /// + public static Color LightYellow + { + get; + private set; + } + + /// + /// Lime color (R:0,G:255,B:0,A:255). + /// + public static Color Lime + { + get; + private set; + } + + /// + /// LimeGreen color (R:50,G:205,B:50,A:255). + /// + public static Color LimeGreen + { + get; + private set; + } + + /// + /// Linen color (R:250,G:240,B:230,A:255). + /// + public static Color Linen + { + get; + private set; + } + + /// + /// Magenta color (R:255,G:0,B:255,A:255). + /// + public static Color Magenta + { + get; + private set; + } + + /// + /// Maroon color (R:128,G:0,B:0,A:255). + /// + public static Color Maroon + { + get; + private set; + } + + /// + /// MediumAquamarine color (R:102,G:205,B:170,A:255). + /// + public static Color MediumAquamarine + { + get; + private set; + } + + /// + /// MediumBlue color (R:0,G:0,B:205,A:255). + /// + public static Color MediumBlue + { + get; + private set; + } + + /// + /// MediumOrchid color (R:186,G:85,B:211,A:255). + /// + public static Color MediumOrchid + { + get; + private set; + } + + /// + /// MediumPurple color (R:147,G:112,B:219,A:255). + /// + public static Color MediumPurple + { + get; + private set; + } + + /// + /// MediumSeaGreen color (R:60,G:179,B:113,A:255). + /// + public static Color MediumSeaGreen + { + get; + private set; + } + + /// + /// MediumSlateBlue color (R:123,G:104,B:238,A:255). + /// + public static Color MediumSlateBlue + { + get; + private set; + } + + /// + /// MediumSpringGreen color (R:0,G:250,B:154,A:255). + /// + public static Color MediumSpringGreen + { + get; + private set; + } + + /// + /// MediumTurquoise color (R:72,G:209,B:204,A:255). + /// + public static Color MediumTurquoise + { + get; + private set; + } + + /// + /// MediumVioletRed color (R:199,G:21,B:133,A:255). + /// + public static Color MediumVioletRed + { + get; + private set; + } + + /// + /// MidnightBlue color (R:25,G:25,B:112,A:255). + /// + public static Color MidnightBlue + { + get; + private set; + } + + /// + /// MintCream color (R:245,G:255,B:250,A:255). + /// + public static Color MintCream + { + get; + private set; + } + + /// + /// MistyRose color (R:255,G:228,B:225,A:255). + /// + public static Color MistyRose + { + get; + private set; + } + + /// + /// Moccasin color (R:255,G:228,B:181,A:255). + /// + public static Color Moccasin + { + get; + private set; + } + + /// + /// NavajoWhite color (R:255,G:222,B:173,A:255). + /// + public static Color NavajoWhite + { + get; + private set; + } + + /// + /// Navy color (R:0,G:0,B:128,A:255). + /// + public static Color Navy + { + get; + private set; + } + + /// + /// OldLace color (R:253,G:245,B:230,A:255). + /// + public static Color OldLace + { + get; + private set; + } + + /// + /// Olive color (R:128,G:128,B:0,A:255). + /// + public static Color Olive + { + get; + private set; + } + + /// + /// OliveDrab color (R:107,G:142,B:35,A:255). + /// + public static Color OliveDrab + { + get; + private set; + } + + /// + /// Orange color (R:255,G:165,B:0,A:255). + /// + public static Color Orange + { + get; + private set; + } + + /// + /// OrangeRed color (R:255,G:69,B:0,A:255). + /// + public static Color OrangeRed + { + get; + private set; + } + + /// + /// Orchid color (R:218,G:112,B:214,A:255). + /// + public static Color Orchid + { + get; + private set; + } + + /// + /// PaleGoldenrod color (R:238,G:232,B:170,A:255). + /// + public static Color PaleGoldenrod + { + get; + private set; + } + + /// + /// PaleGreen color (R:152,G:251,B:152,A:255). + /// + public static Color PaleGreen + { + get; + private set; + } + + /// + /// PaleTurquoise color (R:175,G:238,B:238,A:255). + /// + public static Color PaleTurquoise + { + get; + private set; + } + /// + /// PaleVioletRed color (R:219,G:112,B:147,A:255). + /// + public static Color PaleVioletRed + { + get; + private set; + } + + /// + /// PapayaWhip color (R:255,G:239,B:213,A:255). + /// + public static Color PapayaWhip + { + get; + private set; + } + + /// + /// PeachPuff color (R:255,G:218,B:185,A:255). + /// + public static Color PeachPuff + { + get; + private set; + } + + /// + /// Peru color (R:205,G:133,B:63,A:255). + /// + public static Color Peru + { + get; + private set; + } + + /// + /// Pink color (R:255,G:192,B:203,A:255). + /// + public static Color Pink + { + get; + private set; + } + + /// + /// Plum color (R:221,G:160,B:221,A:255). + /// + public static Color Plum + { + get; + private set; + } + + /// + /// PowderBlue color (R:176,G:224,B:230,A:255). + /// + public static Color PowderBlue + { + get; + private set; + } + + /// + /// Purple color (R:128,G:0,B:128,A:255). + /// + public static Color Purple + { + get; + private set; + } + + /// + /// Red color (R:255,G:0,B:0,A:255). + /// + public static Color Red + { + get; + private set; + } + + /// + /// RosyBrown color (R:188,G:143,B:143,A:255). + /// + public static Color RosyBrown + { + get; + private set; + } + + /// + /// RoyalBlue color (R:65,G:105,B:225,A:255). + /// + public static Color RoyalBlue + { + get; + private set; + } + + /// + /// SaddleBrown color (R:139,G:69,B:19,A:255). + /// + public static Color SaddleBrown + { + get; + private set; + } + + /// + /// Salmon color (R:250,G:128,B:114,A:255). + /// + public static Color Salmon + { + get; + private set; + } + + /// + /// SandyBrown color (R:244,G:164,B:96,A:255). + /// + public static Color SandyBrown + { + get; + private set; + } + + /// + /// SeaGreen color (R:46,G:139,B:87,A:255). + /// + public static Color SeaGreen + { + get; + private set; + } + + /// + /// SeaShell color (R:255,G:245,B:238,A:255). + /// + public static Color SeaShell + { + get; + private set; + } + + /// + /// Sienna color (R:160,G:82,B:45,A:255). + /// + public static Color Sienna + { + get; + private set; + } + + /// + /// Silver color (R:192,G:192,B:192,A:255). + /// + public static Color Silver + { + get; + private set; + } + + /// + /// SkyBlue color (R:135,G:206,B:235,A:255). + /// + public static Color SkyBlue + { + get; + private set; + } + + /// + /// SlateBlue color (R:106,G:90,B:205,A:255). + /// + public static Color SlateBlue + { + get; + private set; + } + + /// + /// SlateGray color (R:112,G:128,B:144,A:255). + /// + public static Color SlateGray + { + get; + private set; + } + + /// + /// Snow color (R:255,G:250,B:250,A:255). + /// + public static Color Snow + { + get; + private set; + } + + /// + /// SpringGreen color (R:0,G:255,B:127,A:255). + /// + public static Color SpringGreen + { + get; + private set; + } + + /// + /// SteelBlue color (R:70,G:130,B:180,A:255). + /// + public static Color SteelBlue + { + get; + private set; + } + + /// + /// Tan color (R:210,G:180,B:140,A:255). + /// + public static Color Tan + { + get; + private set; + } + + /// + /// Teal color (R:0,G:128,B:128,A:255). + /// + public static Color Teal + { + get; + private set; + } + + /// + /// Thistle color (R:216,G:191,B:216,A:255). + /// + public static Color Thistle + { + get; + private set; + } + + /// + /// Tomato color (R:255,G:99,B:71,A:255). + /// + public static Color Tomato + { + get; + private set; + } + + /// + /// Turquoise color (R:64,G:224,B:208,A:255). + /// + public static Color Turquoise + { + get; + private set; + } + + /// + /// Violet color (R:238,G:130,B:238,A:255). + /// + public static Color Violet + { + get; + private set; + } + + /// + /// Wheat color (R:245,G:222,B:179,A:255). + /// + public static Color Wheat + { + get; + private set; + } + + /// + /// White color (R:255,G:255,B:255,A:255). + /// + public static Color White + { + get; + private set; + } + + /// + /// WhiteSmoke color (R:245,G:245,B:245,A:255). + /// + public static Color WhiteSmoke + { + get; + private set; + } + + /// + /// Yellow color (R:255,G:255,B:0,A:255). + /// + public static Color Yellow + { + get; + private set; + } + + /// + /// YellowGreen color (R:154,G:205,B:50,A:255). + /// + public static Color YellowGreen + { + get; + private set; + } + + #endregion + + #region Private Variables + + // ARGB + private uint _packedValue; + + #endregion + + #region Private Static Constructors + + static Color() + { + TransparentBlack = new Color(0); + Transparent = new Color(0); + AliceBlue = new Color(0xfffff8f0); + AntiqueWhite = new Color(0xffd7ebfa); + Aqua = new Color(0xffffff00); + Aquamarine = new Color(0xffd4ff7f); + Azure = new Color(0xfffffff0); + Beige = new Color(0xffdcf5f5); + Bisque = new Color(0xffc4e4ff); + Black = new Color(0xff000000); + BlanchedAlmond = new Color(0xffcdebff); + Blue = new Color(0xffff0000); + BlueViolet = new Color(0xffe22b8a); + Brown = new Color(0xff2a2aa5); + BurlyWood = new Color(0xff87b8de); + CadetBlue = new Color(0xffa09e5f); + Chartreuse = new Color(0xff00ff7f); + Chocolate = new Color(0xff1e69d2); + Coral = new Color(0xff507fff); + CornflowerBlue = new Color(0xffed9564); + Cornsilk = new Color(0xffdcf8ff); + Crimson = new Color(0xff3c14dc); + Cyan = new Color(0xffffff00); + DarkBlue = new Color(0xff8b0000); + DarkCyan = new Color(0xff8b8b00); + DarkGoldenrod = new Color(0xff0b86b8); + DarkGray = new Color(0xffa9a9a9); + DarkGreen = new Color(0xff006400); + DarkKhaki = new Color(0xff6bb7bd); + DarkMagenta = new Color(0xff8b008b); + DarkOliveGreen = new Color(0xff2f6b55); + DarkOrange = new Color(0xff008cff); + DarkOrchid = new Color(0xffcc3299); + DarkRed = new Color(0xff00008b); + DarkSalmon = new Color(0xff7a96e9); + DarkSeaGreen = new Color(0xff8bbc8f); + DarkSlateBlue = new Color(0xff8b3d48); + DarkSlateGray = new Color(0xff4f4f2f); + DarkTurquoise = new Color(0xffd1ce00); + DarkViolet = new Color(0xffd30094); + DeepPink = new Color(0xff9314ff); + DeepSkyBlue = new Color(0xffffbf00); + DimGray = new Color(0xff696969); + DodgerBlue = new Color(0xffff901e); + Firebrick = new Color(0xff2222b2); + FloralWhite = new Color(0xfff0faff); + ForestGreen = new Color(0xff228b22); + Fuchsia = new Color(0xffff00ff); + Gainsboro = new Color(0xffdcdcdc); + GhostWhite = new Color(0xfffff8f8); + Gold = new Color(0xff00d7ff); + Goldenrod = new Color(0xff20a5da); + Gray = new Color(0xff808080); + Green = new Color(0xff008000); + GreenYellow = new Color(0xff2fffad); + Honeydew = new Color(0xfff0fff0); + HotPink = new Color(0xffb469ff); + IndianRed = new Color(0xff5c5ccd); + Indigo = new Color(0xff82004b); + Ivory = new Color(0xfff0ffff); + Khaki = new Color(0xff8ce6f0); + Lavender = new Color(0xfffae6e6); + LavenderBlush = new Color(0xfff5f0ff); + LawnGreen = new Color(0xff00fc7c); + LemonChiffon = new Color(0xffcdfaff); + LightBlue = new Color(0xffe6d8ad); + LightCoral = new Color(0xff8080f0); + LightCyan = new Color(0xffffffe0); + LightGoldenrodYellow = new Color(0xffd2fafa); + LightGray = new Color(0xffd3d3d3); + LightGreen = new Color(0xff90ee90); + LightPink = new Color(0xffc1b6ff); + LightSalmon = new Color(0xff7aa0ff); + LightSeaGreen = new Color(0xffaab220); + LightSkyBlue = new Color(0xffface87); + LightSlateGray = new Color(0xff998877); + LightSteelBlue = new Color(0xffdec4b0); + LightYellow = new Color(0xffe0ffff); + Lime = new Color(0xff00ff00); + LimeGreen = new Color(0xff32cd32); + Linen = new Color(0xffe6f0fa); + Magenta = new Color(0xffff00ff); + Maroon = new Color(0xff000080); + MediumAquamarine = new Color(0xffaacd66); + MediumBlue = new Color(0xffcd0000); + MediumOrchid = new Color(0xffd355ba); + MediumPurple = new Color(0xffdb7093); + MediumSeaGreen = new Color(0xff71b33c); + MediumSlateBlue = new Color(0xffee687b); + MediumSpringGreen = new Color(0xff9afa00); + MediumTurquoise = new Color(0xffccd148); + MediumVioletRed = new Color(0xff8515c7); + MidnightBlue = new Color(0xff701919); + MintCream = new Color(0xfffafff5); + MistyRose = new Color(0xffe1e4ff); + Moccasin = new Color(0xffb5e4ff); + NavajoWhite = new Color(0xffaddeff); + Navy = new Color(0xff800000); + OldLace = new Color(0xffe6f5fd); + Olive = new Color(0xff008080); + OliveDrab = new Color(0xff238e6b); + Orange = new Color(0xff00a5ff); + OrangeRed = new Color(0xff0045ff); + Orchid = new Color(0xffd670da); + PaleGoldenrod = new Color(0xffaae8ee); + PaleGreen = new Color(0xff98fb98); + PaleTurquoise = new Color(0xffeeeeaf); + PaleVioletRed = new Color(0xff9370db); + PapayaWhip = new Color(0xffd5efff); + PeachPuff = new Color(0xffb9daff); + Peru = new Color(0xff3f85cd); + Pink = new Color(0xffcbc0ff); + Plum = new Color(0xffdda0dd); + PowderBlue = new Color(0xffe6e0b0); + Purple = new Color(0xff800080); + Red = new Color(0xff0000ff); + RosyBrown = new Color(0xff8f8fbc); + RoyalBlue = new Color(0xffe16941); + SaddleBrown = new Color(0xff13458b); + Salmon= new Color(0xff7280fa); + SandyBrown = new Color(0xff60a4f4); + SeaGreen = new Color(0xff578b2e); + SeaShell = new Color(0xffeef5ff); + Sienna = new Color(0xff2d52a0); + Silver = new Color(0xffc0c0c0); + SkyBlue = new Color(0xffebce87); + SlateBlue= new Color(0xffcd5a6a); + SlateGray= new Color(0xff908070); + Snow= new Color(0xfffafaff); + SpringGreen= new Color(0xff7fff00); + SteelBlue= new Color(0xffb48246); + Tan= new Color(0xff8cb4d2); + Teal= new Color(0xff808000); + Thistle= new Color(0xffd8bfd8); + Tomato= new Color(0xff4763ff); + Turquoise= new Color(0xffd0e040); + Violet= new Color(0xffee82ee); + Wheat= new Color(0xffb3def5); + White= new Color(uint.MaxValue); + WhiteSmoke= new Color(0xfff5f5f5); + Yellow = new Color(0xff00ffff); + YellowGreen = new Color(0xff32cd9a); + } + + #endregion + + #region Public Constructors + + /// + /// Creates a new instance of struct. + /// + /// A representing color. + public Color(Vector4 color) + { + _packedValue = 0; + + R = (byte) MathHelper.Clamp(color.X * 255, Byte.MinValue, Byte.MaxValue); + G = (byte) MathHelper.Clamp(color.Y * 255, Byte.MinValue, Byte.MaxValue); + B = (byte) MathHelper.Clamp(color.Z * 255, Byte.MinValue, Byte.MaxValue); + A = (byte) MathHelper.Clamp(color.W * 255, Byte.MinValue, Byte.MaxValue); + } + + /// + /// Creates a new instance of struct. + /// + /// A representing color. + public Color(Vector3 color) + { + _packedValue = 0; + + R = (byte) MathHelper.Clamp(color.X * 255, Byte.MinValue, Byte.MaxValue); + G = (byte) MathHelper.Clamp(color.Y * 255, Byte.MinValue, Byte.MaxValue); + B = (byte) MathHelper.Clamp(color.Z * 255, Byte.MinValue, Byte.MaxValue); + A = 255; + } + + /// + /// Creates a new instance of struct. + /// + /// A for RGB values of new instance. + /// Alpha component value. + public Color(Color color, int alpha) + { + _packedValue = 0; + + R = color.R; + G = color.G; + B = color.B; + A = (byte) MathHelper.Clamp(alpha, Byte.MinValue, Byte.MaxValue); + } + + /// + /// Creates a new instance of struct. + /// + /// A for RGB values of new instance. + /// Alpha component value. + public Color(Color color, float alpha) + { + _packedValue = 0; + + R = color.R; + G = color.G; + B = color.B; + A = (byte) MathHelper.Clamp(alpha * 255, Byte.MinValue, Byte.MaxValue); + } + + /// + /// Creates a new instance of struct. + /// + /// Red component value. + /// Green component value. + /// Blue component value + public Color(float r, float g, float b) + { + _packedValue = 0; + + R = (byte) MathHelper.Clamp(r * 255, Byte.MinValue, Byte.MaxValue); + G = (byte) MathHelper.Clamp(g * 255, Byte.MinValue, Byte.MaxValue); + B = (byte) MathHelper.Clamp(b * 255, Byte.MinValue, Byte.MaxValue); + A = 255; + } + + /// + /// Creates a new instance of struct. + /// + /// Red component value. + /// Green component value. + /// Blue component value + public Color(int r, int g, int b) + { + _packedValue = 0; + R = (byte) MathHelper.Clamp(r, Byte.MinValue, Byte.MaxValue); + G = (byte) MathHelper.Clamp(g, Byte.MinValue, Byte.MaxValue); + B = (byte) MathHelper.Clamp(b, Byte.MinValue, Byte.MaxValue); + A = (byte)255; + } + + /// + /// Creates a new instance of struct. + /// + /// Red component value. + /// Green component value. + /// Blue component value + /// Alpha component value. + public Color(int r, int g, int b, int alpha) + { + _packedValue = 0; + R = (byte) MathHelper.Clamp(r, Byte.MinValue, Byte.MaxValue); + G = (byte) MathHelper.Clamp(g, Byte.MinValue, Byte.MaxValue); + B = (byte) MathHelper.Clamp(b, Byte.MinValue, Byte.MaxValue); + A = (byte) MathHelper.Clamp(alpha, Byte.MinValue, Byte.MaxValue); + } + + /// + /// Creates a new instance of struct. + /// + /// Red component value. + /// Green component value. + /// Blue component value + /// Alpha component value. + public Color(float r, float g, float b, float alpha) + { + _packedValue = 0; + + R = (byte) MathHelper.Clamp(r * 255, Byte.MinValue, Byte.MaxValue); + G = (byte) MathHelper.Clamp(g * 255, Byte.MinValue, Byte.MaxValue); + B = (byte) MathHelper.Clamp(b * 255, Byte.MinValue, Byte.MaxValue); + A = (byte) MathHelper.Clamp(alpha * 255, Byte.MinValue, Byte.MaxValue); + } + + #endregion + + #region Private Constructors + + private Color(uint packedValue) + { + _packedValue = packedValue; + } + + #endregion + + #region Public Methods + + /// + /// Compares whether current instance is equal to specified . + /// + /// The to compare. + /// true if the instances are equal; false otherwise. + public bool Equals(Color other) + { + return this.PackedValue == other.PackedValue; + } + + /// + /// Converts to . + /// + /// Converted color. + public Vector3 ToVector3() + { + return new Vector3(R / 255.0f, G / 255.0f, B / 255.0f); + } + + /// + /// Converts to . + /// + /// Converted color. + public Vector4 ToVector4() + { + return new Vector4(R / 255.0f, G / 255.0f, B / 255.0f, A / 255.0f); + } + + #endregion + + #region Public Static Methods + + /// + /// Performs linear interpolation of . + /// + /// Source . + /// Destination . + /// Interpolation factor. + /// Interpolated . + public static Color Lerp(Color value1, Color value2, Single amount) + { + return new Color( + (int )MathHelper.Lerp(value1.R, value2.R, amount), + (int) MathHelper.Lerp(value1.G, value2.G, amount), + (int) MathHelper.Lerp(value1.B, value2.B, amount), + (int) MathHelper.Lerp(value1.A, value2.A, amount)); + } + + /// + /// Translate a non-premultipled alpha to a that contains premultiplied alpha. + /// + /// A representing color. + /// A which contains premultiplied alpha data. + public static Color FromNonPremultiplied(Vector4 vector) + { + return new Color(vector.X * vector.W, vector.Y * vector.W, vector.Z * vector.W, vector.W); + } + + /// + /// Translate a non-premultipled alpha to a that contains premultiplied alpha. + /// + /// Red component value. + /// Green component value. + /// Blue component value. + /// Alpha component value. + /// A which contains premultiplied alpha data. + public static Color FromNonPremultiplied(int r, int g, int b, int a) + { + return new Color((byte) (r * a / 255), (byte) (g * a / 255), (byte) (b * a / 255), a); + } + + #endregion + + #region Public Static Operators and Override Methods + + /// + /// Compares whether two instances are equal. + /// + /// instance on the left of the equal sign. + /// instance on the right of the equal sign. + /// true if the instances are equal; false otherwise. + public static bool operator ==(Color a, Color b) + { + return (a.A == b.A && + a.R == b.R && + a.G == b.G && + a.B == b.B); + } + + /// + /// Compares whether two instances are not equal. + /// + /// instance on the left of the not equal sign. + /// instance on the right of the not equal sign. + /// true if the instances are not equal; false otherwise. + public static bool operator !=(Color a, Color b) + { + return !(a == b); + } + + /// + /// Gets the hash code for instance. + /// + /// Hash code of the object. + public override int GetHashCode() + { + return this._packedValue.GetHashCode(); + } + + /// + /// Compares whether current instance is equal to specified object. + /// + /// The to compare. + /// true if the instances are equal; false otherwise. + public override bool Equals(object obj) + { + return ((obj is Color) && this.Equals((Color) obj)); + } + + /// + /// Multiply by value. + /// + /// Source . + /// Multiplicator. + /// Multiplication result. + public static Color Multiply(Color value, float scale) + { + return new Color((int) (value.R * scale), + (int) (value.G * scale), + (int) (value.B * scale), + (int) (value.A * scale) + ); + } + + /// + /// Multiply by value. + /// + /// Source . + /// Multiplicator. + /// Multiplication result. + public static Color operator *(Color value, float scale) + { + return new Color((int) (value.R * scale), + (int) (value.G * scale), + (int) (value.B * scale), + (int) (value.A * scale) + ); + } + + /// + /// Converts the color values of this instance to its equivalent string representation. + /// + /// The string representation of the color value of this instance. + public override string ToString() + { + StringBuilder sb = new StringBuilder(25); + sb.Append("{R:"); + sb.Append(R); + sb.Append(" G:"); + sb.Append(G); + sb.Append(" B:"); + sb.Append(B); + sb.Append(" A:"); + sb.Append(A); + sb.Append("}"); + return sb.ToString(); + } + + #endregion + } + + #region XNAColorConverter Class + + public class XNAColorConverter : TypeConverter + { + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string)) + { + return true; + } + return base.CanConvertFrom(context, sourceType); + } + + public override object ConvertFrom( + ITypeDescriptorContext context, + System.Globalization.CultureInfo culture, + object value + ) { + if (value is string) + { + string[] v = ((string) value).Split( + culture.NumberFormat.NumberGroupSeparator.ToCharArray() + ); + return new Color( + float.Parse(v[0], culture), + float.Parse(v[1], culture), + float.Parse(v[2], culture), + float.Parse(v[3], culture) + ); + } + return base.ConvertFrom(context, culture, value); + } + + public override object ConvertTo( + ITypeDescriptorContext context, + System.Globalization.CultureInfo culture, + object value, + Type destinationType + ) { + if (destinationType == typeof(string)) + { + Color src = (Color) value; + string sep = culture.NumberFormat.NumberGroupSeparator; + return src.R.ToString(culture) + + sep + src.B.ToString(culture) + + sep + src.B.ToString(culture) + + sep + src.A.ToString(culture); + } + return base.ConvertTo(context, culture, value, destinationType); + } + } + + #endregion } diff --git a/MonoGame.Framework/Curve.cs b/MonoGame.Framework/Curve.cs index b79678f2152..41a627d9c17 100644 --- a/MonoGame.Framework/Curve.cs +++ b/MonoGame.Framework/Curve.cs @@ -34,278 +34,329 @@ MIT License #region Using Statements using System; -using System.ComponentModel; using System.Runtime.Serialization; #endregion namespace Microsoft.Xna.Framework { // TODO [TypeConverter(ExpandableObjectConverter)] - [DataContract] - public class Curve - { - #region Public Properties - - [DataMember] - public bool IsConstant - { - get { return this.keys.Count <= 1; } - } - - [DataMember] - public CurveKeyCollection Keys - { - get { return this.keys; } - } - - [DataMember] - public CurveLoopType PostLoop - { - get { return this.postLoop; } - set { this.postLoop = value; } - } - - [DataMember] - public CurveLoopType PreLoop - { - get { return this.preLoop; } - set { this.preLoop = value; } - } - - #endregion - - #region Private Fields - - private CurveKeyCollection keys; - private CurveLoopType postLoop; - private CurveLoopType preLoop; - - #endregion - - #region Public Constructors - - public Curve() - { - this.keys = new CurveKeyCollection(); - } - - #endregion - - #region Public Methods - - public Curve Clone() - { - Curve curve = new Curve(); - - curve.keys = this.keys.Clone(); - curve.preLoop = this.preLoop; - curve.postLoop = this.postLoop; - - return curve; - } - - public float Evaluate(float position) - { - CurveKey first = keys[0]; - CurveKey last = keys[keys.Count - 1]; - - if (position < first.Position) - { - switch (this.PreLoop) - { - case CurveLoopType.Constant: - //constant - return first.Value; - - case CurveLoopType.Linear: - // linear y = a*x +b with a tangeant of last point - return first.Value - first.TangentIn * (first.Position - position); - - case CurveLoopType.Cycle: - //start -> end / start -> end - int cycle = GetNumberOfCycle(position); - float virtualPos = position - (cycle * (last.Position - first.Position)); - return GetCurvePosition(virtualPos); - - case CurveLoopType.CycleOffset: - //make the curve continue (with no step) so must up the curve each cycle of delta(value) - cycle = GetNumberOfCycle(position); - virtualPos = position - (cycle * (last.Position - first.Position)); - return (GetCurvePosition(virtualPos) + cycle * (last.Value - first.Value)); - - case CurveLoopType.Oscillate: - //go back on curve from end and target start - // start-> end / end -> start - cycle = GetNumberOfCycle(position); - if (0 == cycle % 2f)//if pair - virtualPos = position - (cycle * (last.Position - first.Position)); - else - virtualPos = last.Position - position + first.Position + (cycle * (last.Position - first.Position)); - return GetCurvePosition(virtualPos); - } - } - else if (position > last.Position) - { - int cycle; - switch (this.PostLoop) - { - case CurveLoopType.Constant: - //constant - return last.Value; - - case CurveLoopType.Linear: - // linear y = a*x +b with a tangeant of last point - return last.Value + first.TangentOut * (position - last.Position); - - case CurveLoopType.Cycle: - //start -> end / start -> end - cycle = GetNumberOfCycle(position); - float virtualPos = position - (cycle * (last.Position - first.Position)); - return GetCurvePosition(virtualPos); - - case CurveLoopType.CycleOffset: - //make the curve continue (with no step) so must up the curve each cycle of delta(value) - cycle = GetNumberOfCycle(position); - virtualPos = position - (cycle * (last.Position - first.Position)); - return (GetCurvePosition(virtualPos) + cycle * (last.Value - first.Value)); - - case CurveLoopType.Oscillate: - //go back on curve from end and target start - // start-> end / end -> start - cycle = GetNumberOfCycle(position); - virtualPos = position - (cycle * (last.Position - first.Position)); - if (0 == cycle % 2f)//if pair - virtualPos = position - (cycle * (last.Position - first.Position)); - else - virtualPos = last.Position - position + first.Position + (cycle * (last.Position - first.Position)); - return GetCurvePosition(virtualPos); - } - } - - //in curve - return GetCurvePosition(position); - } + [DataContract] + public class Curve + { + #region Public Properties + + [DataMember] + public bool IsConstant + { + get + { + return this.keys.Count <= 1; + } + } + + [DataMember] + public CurveKeyCollection Keys + { + get + { + return this.keys; + } + } + + [DataMember] + public CurveLoopType PostLoop + { + get + { + return this.postLoop; + } + set + { + this.postLoop = value; + } + } + + [DataMember] + public CurveLoopType PreLoop + { + get + { + return this.preLoop; + } + set + { + this.preLoop = value; + } + } + + #endregion + + #region Private Fields + + private CurveKeyCollection keys; + private CurveLoopType postLoop; + private CurveLoopType preLoop; + + #endregion + + #region Public Constructors + + public Curve() + { + this.keys = new CurveKeyCollection(); + } + + #endregion + + #region Public Methods + + public Curve Clone() + { + Curve curve = new Curve(); + + curve.keys = this.keys.Clone(); + curve.preLoop = this.preLoop; + curve.postLoop = this.postLoop; + + return curve; + } + + public float Evaluate(float position) + { + CurveKey first = keys[0]; + CurveKey last = keys[keys.Count - 1]; + + if (position < first.Position) + { + switch (this.PreLoop) + { + case CurveLoopType.Constant: + // constant + return first.Value; + + case CurveLoopType.Linear: + // linear y = a*x +b with a tangeant of last point + return first.Value - first.TangentIn * (first.Position - position); + + case CurveLoopType.Cycle: + // start -> end / start -> end + int cycle = GetNumberOfCycle(position); + float virtualPos = position - (cycle * (last.Position - first.Position)); + return GetCurvePosition(virtualPos); + + case CurveLoopType.CycleOffset: + // make the curve continue (with no step) so must up the curve each cycle of delta(value) + cycle = GetNumberOfCycle(position); + virtualPos = position - (cycle * (last.Position - first.Position)); + return (GetCurvePosition(virtualPos) + cycle * (last.Value - first.Value)); + + case CurveLoopType.Oscillate: + /* go back on curve from end and target start + * start-> end / end -> start + */ + cycle = GetNumberOfCycle(position); + // if pair + if (0 == cycle % 2f) + { + virtualPos = position - (cycle * (last.Position - first.Position)); + } + else + { + virtualPos = last.Position - position + first.Position + (cycle * (last.Position - first.Position)); + } + return GetCurvePosition(virtualPos); + } + } + else if (position > last.Position) + { + int cycle; + switch (this.PostLoop) + { + case CurveLoopType.Constant: + // constant + return last.Value; + + case CurveLoopType.Linear: + // linear y = a*x +b with a tangeant of last point + return last.Value + first.TangentOut * (position - last.Position); + + case CurveLoopType.Cycle: + // start -> end / start -> end + cycle = GetNumberOfCycle(position); + float virtualPos = position - (cycle * (last.Position - first.Position)); + return GetCurvePosition(virtualPos); + + case CurveLoopType.CycleOffset: + // Make the curve continue (with no step) so must up the curve each cycle of delta(value) + cycle = GetNumberOfCycle(position); + virtualPos = position - (cycle * (last.Position - first.Position)); + return (GetCurvePosition(virtualPos) + cycle * (last.Value - first.Value)); + + case CurveLoopType.Oscillate: + /* Go back on curve from end and target start + * start-> end / end -> start + */ + cycle = GetNumberOfCycle(position); + virtualPos = position - (cycle * (last.Position - first.Position)); + + // if pair + if (0 == cycle % 2f) + { + virtualPos = position - (cycle * (last.Position - first.Position)); + } + else + { + virtualPos = + last.Position - position + first.Position + + (cycle * (last.Position - first.Position) + ); + } + return GetCurvePosition(virtualPos); + } + } + + // in curve + return GetCurvePosition(position); + } public void ComputeTangents (CurveTangent tangentType ) { - ComputeTangents(tangentType, tangentType); + ComputeTangents(tangentType, tangentType); } - + public void ComputeTangents(CurveTangent tangentInType, CurveTangent tangentOutType) { - for (var i = 0; i < Keys.Count; i++) - ComputeTangent(i, tangentInType, tangentOutType); + for (int i = 0; i < Keys.Count; i += 1) + { + ComputeTangent(i, tangentInType, tangentOutType); + } + } + + public void ComputeTangent(int keyIndex, CurveTangent tangentType) + { + ComputeTangent(keyIndex, tangentType, tangentType); + } + + public void ComputeTangent(int keyIndex, CurveTangent tangentInType, CurveTangent tangentOutType) + { + // See http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.curvetangent.aspx + + CurveKey key = keys[keyIndex]; + + float p0, p, p1; + p0 = p = p1 = key.Position; + + float v0, v, v1; + v0 = v = v1 = key.Value; + + if (keyIndex > 0) + { + p0 = keys[keyIndex - 1].Position; + v0 = keys[keyIndex - 1].Value; + } + + if (keyIndex < keys.Count-1) + { + p1 = keys[keyIndex + 1].Position; + v1 = keys[keyIndex + 1].Value; + } + + switch (tangentInType) + { + case CurveTangent.Flat: + key.TangentIn = 0; + break; + case CurveTangent.Linear: + key.TangentIn = v - v0; + break; + case CurveTangent.Smooth: + float pn = p1 - p0; + if (Math.Abs(pn) < float.Epsilon) + { + key.TangentIn = 0; + } + else + { + key.TangentIn = (v1 - v0) * ((p - p0) / pn); + } + break; + } + + switch (tangentOutType) + { + case CurveTangent.Flat: + key.TangentOut = 0; + break; + case CurveTangent.Linear: + key.TangentOut = v1 - v; + break; + case CurveTangent.Smooth: + float pn = p1 - p0; + if (Math.Abs(pn) < float.Epsilon) + { + key.TangentOut = 0; + } + else + { + key.TangentOut = (v1 - v0) * ((p1 - p) / pn); + } + break; + } + } + + #endregion + + #region Private Methods + + private int GetNumberOfCycle(float position) + { + float cycle = (position - keys[0].Position) / + (keys[keys.Count - 1].Position - keys[0].Position); + if (cycle < 0f) + { + cycle -= 1; + } + return (int) cycle; + } + + private float GetCurvePosition(float position) + { + // only for position in curve + CurveKey prev = this.keys[0]; + CurveKey next; + for (int i = 1; i < this.keys.Count; i++) + { + next = this.Keys[i]; + if (next.Position >= position) + { + if (prev.Continuity == CurveContinuity.Step) + { + if (position >= 1f) + { + return next.Value; + } + return prev.Value; + } + // To have t in [0,1] + float t = (position - prev.Position) / (next.Position - prev.Position); + float ts = t * t; + float tss = ts * t; + /* After a lot of search on internet I have found all about spline function + * and bezier (phi'sss ancien) but finaly use hermite curve + * http://en.wikipedia.org/wiki/Cubic_Hermite_spline + * P(t) = (2*t^3 - 3t^2 + 1)*P0 + (t^3 - 2t^2 + t)m0 + (-2t^3 + 3t^2)P1 + (t^3-t^2)m1 + * with P0.value = prev.value , m0 = prev.tangentOut, P1= next.value, m1 = next.TangentIn + */ + return (2 * tss - 3 * ts + 1f) * prev.Value + + (tss - 2 * ts + t) * prev.TangentOut + + (3 * ts - 2 * tss) * next.Value + + (tss - ts) * next.TangentIn; + } + prev = next; + } + return 0f; } - public void ComputeTangent(int keyIndex, CurveTangent tangentType) - { - ComputeTangent(keyIndex, tangentType, tangentType); - } - - public void ComputeTangent(int keyIndex, CurveTangent tangentInType, CurveTangent tangentOutType) - { - // See http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.curvetangent.aspx - - var key = keys[keyIndex]; - - float p0, p, p1; - p0 = p = p1 = key.Position; - - float v0, v, v1; - v0 = v = v1 = key.Value; - - if ( keyIndex > 0 ) - { - p0 = keys[keyIndex - 1].Position; - v0 = keys[keyIndex - 1].Value; - } - - if (keyIndex < keys.Count-1) - { - p1 = keys[keyIndex + 1].Position; - v1 = keys[keyIndex + 1].Value; - } - - switch (tangentInType) - { - case CurveTangent.Flat: - key.TangentIn = 0; - break; - case CurveTangent.Linear: - key.TangentIn = v - v0; - break; - case CurveTangent.Smooth: - var pn = p1 - p0; - if (Math.Abs(pn) < float.Epsilon) - key.TangentIn = 0; - else - key.TangentIn = (v1 - v0) * ((p - p0) / pn); - break; - } - - switch (tangentOutType) - { - case CurveTangent.Flat: - key.TangentOut = 0; - break; - case CurveTangent.Linear: - key.TangentOut = v1 - v; - break; - case CurveTangent.Smooth: - var pn = p1 - p0; - if (Math.Abs(pn) < float.Epsilon) - key.TangentOut = 0; - else - key.TangentOut = (v1 - v0) * ((p1 - p) / pn); - break; - } - } - - #endregion - - #region Private Methods - - private int GetNumberOfCycle(float position) - { - float cycle = (position - keys[0].Position) / (keys[keys.Count - 1].Position - keys[0].Position); - if (cycle < 0f) - cycle--; - return (int)cycle; - } - - private float GetCurvePosition(float position) - { - //only for position in curve - CurveKey prev = this.keys[0]; - CurveKey next; - for (int i = 1; i < this.keys.Count; i++) - { - next = this.Keys[i]; - if (next.Position >= position) - { - if (prev.Continuity == CurveContinuity.Step) - { - if (position >= 1f) - { - return next.Value; - } - return prev.Value; - } - float t = (position - prev.Position) / (next.Position - prev.Position);//to have t in [0,1] - float ts = t * t; - float tss = ts * t; - //After a lot of search on internet I have found all about spline function - // and bezier (phi'sss ancien) but finaly use hermite curve - //http://en.wikipedia.org/wiki/Cubic_Hermite_spline - //P(t) = (2*t^3 - 3t^2 + 1)*P0 + (t^3 - 2t^2 + t)m0 + (-2t^3 + 3t^2)P1 + (t^3-t^2)m1 - //with P0.value = prev.value , m0 = prev.tangentOut, P1= next.value, m1 = next.TangentIn - return (2 * tss - 3 * ts + 1f) * prev.Value + (tss - 2 * ts + t) * prev.TangentOut + (3 * ts - 2 * tss) * next.Value + (tss - ts) * next.TangentIn; - } - prev = next; - } - return 0f; - } - - #endregion - } + #endregion + } } diff --git a/MonoGame.Framework/Graphics/SpriteBatcher.cs b/MonoGame.Framework/Graphics/SpriteBatcher.cs index aa217e94c57..0f7501ee5ab 100644 --- a/MonoGame.Framework/Graphics/SpriteBatcher.cs +++ b/MonoGame.Framework/Graphics/SpriteBatcher.cs @@ -148,8 +148,9 @@ public void DrawBatch(SpriteSortMode sortMode) } EnsureArrayCapacity(numBatchesToProcess); // Draw the batches - foreach (SpriteBatchItem item in _batchItemList) + for (int i = 0; i < numBatchesToProcess; i += 1, batchIndex += 1) { + SpriteBatchItem item = _batchItemList[batchIndex]; // if the texture changed, we need to flush and bind the new texture bool shouldFlush = !ReferenceEquals(item.Texture, tex); if (shouldFlush)