(ded4a3e0a) v0.9.0.7
This commit is contained in:
@@ -0,0 +1,538 @@
|
||||
// MIT License - Copyright (C) The Mono.Xna Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Microsoft.Xna.Framework
|
||||
{
|
||||
[DataContract]
|
||||
[DebuggerDisplay("{DebugDisplayString,nq}")]
|
||||
public struct BoundingBox : IEquatable<BoundingBox>
|
||||
{
|
||||
|
||||
#region Public Fields
|
||||
|
||||
[DataMember]
|
||||
public Vector3 Min;
|
||||
|
||||
[DataMember]
|
||||
public Vector3 Max;
|
||||
|
||||
public const int CornerCount = 8;
|
||||
|
||||
#endregion Public Fields
|
||||
|
||||
|
||||
#region Public Constructors
|
||||
|
||||
public BoundingBox(Vector3 min, Vector3 max)
|
||||
{
|
||||
this.Min = min;
|
||||
this.Max = max;
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
|
||||
#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;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = ContainmentType.Contains;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Vector3 MaxVector3 = new Vector3(float.MaxValue);
|
||||
private static readonly Vector3 MinVector3 = new Vector3(float.MinValue);
|
||||
|
||||
/// <summary>
|
||||
/// Create a bounding box from the given list of points.
|
||||
/// </summary>
|
||||
/// <param name="points">The list of Vector3 instances defining the point cloud to bound</param>
|
||||
/// <returns>A bounding box that encapsulates the given point cloud.</returns>
|
||||
/// <exception cref="System.ArgumentException">Thrown if the given list has no points.</exception>
|
||||
public static BoundingBox CreateFromPoints(IEnumerable<Vector3> 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);
|
||||
}
|
||||
|
||||
public bool Equals(BoundingBox other)
|
||||
{
|
||||
return (this.Min == other.Min) && (this.Max == other.Max);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return (obj is BoundingBox) ? this.Equals((BoundingBox)obj) : false;
|
||||
}
|
||||
|
||||
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 override int GetHashCode()
|
||||
{
|
||||
return this.Min.GetHashCode() + this.Max.GetHashCode();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Inline Vector3.Dot(plane.Normal, negativeVertex) + plane.D;
|
||||
var distance = plane.Normal.X * negativeVertex.X + plane.Normal.Y * negativeVertex.Y + plane.Normal.Z * negativeVertex.Z + plane.D;
|
||||
if (distance > 0)
|
||||
{
|
||||
result = PlaneIntersectionType.Front;
|
||||
return;
|
||||
}
|
||||
|
||||
// Inline Vector3.Dot(plane.Normal, positiveVertex) + plane.D;
|
||||
distance = plane.Normal.X * positiveVertex.X + plane.Normal.Y * positiveVertex.Y + plane.Normal.Z * positiveVertex.Z + plane.D;
|
||||
if (distance < 0)
|
||||
{
|
||||
result = PlaneIntersectionType.Back;
|
||||
return;
|
||||
}
|
||||
|
||||
result = PlaneIntersectionType.Intersecting;
|
||||
}
|
||||
|
||||
public Nullable<float> Intersects(Ray ray)
|
||||
{
|
||||
return ray.Intersects(this);
|
||||
}
|
||||
|
||||
public void Intersects(ref Ray ray, out Nullable<float> result)
|
||||
{
|
||||
result = Intersects(ray);
|
||||
}
|
||||
|
||||
public static bool operator ==(BoundingBox a, BoundingBox b)
|
||||
{
|
||||
return a.Equals(b);
|
||||
}
|
||||
|
||||
public static bool operator !=(BoundingBox a, BoundingBox b)
|
||||
{
|
||||
return !a.Equals(b);
|
||||
}
|
||||
|
||||
internal string DebugDisplayString
|
||||
{
|
||||
get
|
||||
{
|
||||
return string.Concat(
|
||||
"Min( ", this.Min.DebugDisplayString, " ) \r\n",
|
||||
"Max( ",this.Max.DebugDisplayString, " )"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "{{Min:" + this.Min.ToString() + " Max:" + this.Max.ToString() + "}}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deconstruction method for <see cref="BoundingBox"/>.
|
||||
/// </summary>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
public void Deconstruct(out Vector3 min, out Vector3 max)
|
||||
{
|
||||
min = Min;
|
||||
max = Max;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,578 @@
|
||||
// MIT License - Copyright (C) The Mono.Xna Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Microsoft.Xna.Framework
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a viewing frustum for intersection operations.
|
||||
/// </summary>
|
||||
[DebuggerDisplay("{DebugDisplayString,nq}")]
|
||||
public class BoundingFrustum : IEquatable<BoundingFrustum>
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
private Matrix _matrix;
|
||||
private readonly Vector3[] _corners = new Vector3[CornerCount];
|
||||
private readonly Plane[] _planes = new Plane[PlaneCount];
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Fields
|
||||
|
||||
/// <summary>
|
||||
/// The number of planes in the frustum.
|
||||
/// </summary>
|
||||
public const int PlaneCount = 6;
|
||||
|
||||
/// <summary>
|
||||
/// The number of corner points in the frustum.
|
||||
/// </summary>
|
||||
public const int CornerCount = 8;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="Matrix"/> of the frustum.
|
||||
/// </summary>
|
||||
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 ;)
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the near plane of the frustum.
|
||||
/// </summary>
|
||||
public Plane Near
|
||||
{
|
||||
get { return this._planes[0]; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the far plane of the frustum.
|
||||
/// </summary>
|
||||
public Plane Far
|
||||
{
|
||||
get { return this._planes[1]; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the left plane of the frustum.
|
||||
/// </summary>
|
||||
public Plane Left
|
||||
{
|
||||
get { return this._planes[2]; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the right plane of the frustum.
|
||||
/// </summary>
|
||||
public Plane Right
|
||||
{
|
||||
get { return this._planes[3]; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the top plane of the frustum.
|
||||
/// </summary>
|
||||
public Plane Top
|
||||
{
|
||||
get { return this._planes[4]; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bottom plane of the frustum.
|
||||
/// </summary>
|
||||
public Plane Bottom
|
||||
{
|
||||
get { return this._planes[5]; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Properties
|
||||
|
||||
internal string DebugDisplayString
|
||||
{
|
||||
get
|
||||
{
|
||||
return string.Concat(
|
||||
"Near( ", this._planes[0].DebugDisplayString, " ) \r\n",
|
||||
"Far( ", this._planes[1].DebugDisplayString, " ) \r\n",
|
||||
"Left( ", this._planes[2].DebugDisplayString, " ) \r\n",
|
||||
"Right( ", this._planes[3].DebugDisplayString, " ) \r\n",
|
||||
"Top( ", this._planes[4].DebugDisplayString, " ) \r\n",
|
||||
"Bottom( ", this._planes[5].DebugDisplayString, " ) "
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs the frustum by extracting the view planes from a matrix.
|
||||
/// </summary>
|
||||
/// <param name="value">Combined matrix which usually is (View * Projection).</param>
|
||||
public BoundingFrustum(Matrix value)
|
||||
{
|
||||
this._matrix = value;
|
||||
this.CreatePlanes();
|
||||
this.CreateCorners();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Operators
|
||||
|
||||
/// <summary>
|
||||
/// Compares whether two <see cref="BoundingFrustum"/> instances are equal.
|
||||
/// </summary>
|
||||
/// <param name="a"><see cref="BoundingFrustum"/> instance on the left of the equal sign.</param>
|
||||
/// <param name="b"><see cref="BoundingFrustum"/> instance on the right of the equal sign.</param>
|
||||
/// <returns><c>true</c> if the instances are equal; <c>false</c> otherwise.</returns>
|
||||
public static bool operator ==(BoundingFrustum a, BoundingFrustum b)
|
||||
{
|
||||
if (Equals(a, null))
|
||||
return (Equals(b, null));
|
||||
|
||||
if (Equals(b, null))
|
||||
return (Equals(a, null));
|
||||
|
||||
return a._matrix == (b._matrix);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares whether two <see cref="BoundingFrustum"/> instances are not equal.
|
||||
/// </summary>
|
||||
/// <param name="a"><see cref="BoundingFrustum"/> instance on the left of the not equal sign.</param>
|
||||
/// <param name="b"><see cref="BoundingFrustum"/> instance on the right of the not equal sign.</param>
|
||||
/// <returns><c>true</c> if the instances are not equal; <c>false</c> otherwise.</returns>
|
||||
public static bool operator !=(BoundingFrustum a, BoundingFrustum b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
#region Contains
|
||||
|
||||
/// <summary>
|
||||
/// Containment test between this <see cref="BoundingFrustum"/> and specified <see cref="BoundingBox"/>.
|
||||
/// </summary>
|
||||
/// <param name="box">A <see cref="BoundingBox"/> for testing.</param>
|
||||
/// <returns>Result of testing for containment between this <see cref="BoundingFrustum"/> and specified <see cref="BoundingBox"/>.</returns>
|
||||
public ContainmentType Contains(BoundingBox box)
|
||||
{
|
||||
var result = default(ContainmentType);
|
||||
this.Contains(ref box, out result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Containment test between this <see cref="BoundingFrustum"/> and specified <see cref="BoundingBox"/>.
|
||||
/// </summary>
|
||||
/// <param name="box">A <see cref="BoundingBox"/> for testing.</param>
|
||||
/// <param name="result">Result of testing for containment between this <see cref="BoundingFrustum"/> and specified <see cref="BoundingBox"/> as an output parameter.</param>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Containment test between this <see cref="BoundingFrustum"/> and specified <see cref="BoundingFrustum"/>.
|
||||
/// </summary>
|
||||
/// <param name="frustum">A <see cref="BoundingFrustum"/> for testing.</param>
|
||||
/// <returns>Result of testing for containment between this <see cref="BoundingFrustum"/> and specified <see cref="BoundingFrustum"/>.</returns>
|
||||
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.
|
||||
|
||||
var intersects = false;
|
||||
for (var i = 0; i < PlaneCount; ++i)
|
||||
{
|
||||
PlaneIntersectionType planeIntersectionType;
|
||||
frustum.Intersects(ref _planes[i], out planeIntersectionType);
|
||||
switch (planeIntersectionType)
|
||||
{
|
||||
case PlaneIntersectionType.Front:
|
||||
return ContainmentType.Disjoint;
|
||||
case PlaneIntersectionType.Intersecting:
|
||||
intersects = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return intersects ? ContainmentType.Intersects : ContainmentType.Contains;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Containment test between this <see cref="BoundingFrustum"/> and specified <see cref="BoundingSphere"/>.
|
||||
/// </summary>
|
||||
/// <param name="sphere">A <see cref="BoundingSphere"/> for testing.</param>
|
||||
/// <returns>Result of testing for containment between this <see cref="BoundingFrustum"/> and specified <see cref="BoundingSphere"/>.</returns>
|
||||
public ContainmentType Contains(BoundingSphere sphere)
|
||||
{
|
||||
var result = default(ContainmentType);
|
||||
this.Contains(ref sphere, out result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Containment test between this <see cref="BoundingFrustum"/> and specified <see cref="BoundingSphere"/>.
|
||||
/// </summary>
|
||||
/// <param name="sphere">A <see cref="BoundingSphere"/> for testing.</param>
|
||||
/// <param name="result">Result of testing for containment between this <see cref="BoundingFrustum"/> and specified <see cref="BoundingSphere"/> as an output parameter.</param>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Containment test between this <see cref="BoundingFrustum"/> and specified <see cref="Vector3"/>.
|
||||
/// </summary>
|
||||
/// <param name="point">A <see cref="Vector3"/> for testing.</param>
|
||||
/// <returns>Result of testing for containment between this <see cref="BoundingFrustum"/> and specified <see cref="Vector3"/>.</returns>
|
||||
public ContainmentType Contains(Vector3 point)
|
||||
{
|
||||
var result = default(ContainmentType);
|
||||
this.Contains(ref point, out result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Containment test between this <see cref="BoundingFrustum"/> and specified <see cref="Vector3"/>.
|
||||
/// </summary>
|
||||
/// <param name="point">A <see cref="Vector3"/> for testing.</param>
|
||||
/// <param name="result">Result of testing for containment between this <see cref="BoundingFrustum"/> and specified <see cref="Vector3"/> as an output parameter.</param>
|
||||
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;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Compares whether current instance is equal to specified <see cref="BoundingFrustum"/>.
|
||||
/// </summary>
|
||||
/// <param name="other">The <see cref="BoundingFrustum"/> to compare.</param>
|
||||
/// <returns><c>true</c> if the instances are equal; <c>false</c> otherwise.</returns>
|
||||
public bool Equals(BoundingFrustum other)
|
||||
{
|
||||
return (this == other);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares whether current instance is equal to specified <see cref="BoundingFrustum"/>.
|
||||
/// </summary>
|
||||
/// <param name="obj">The <see cref="Object"/> to compare.</param>
|
||||
/// <returns><c>true</c> if the instances are equal; <c>false</c> otherwise.</returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return (obj is BoundingFrustum) && this == ((BoundingFrustum)obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a copy of internal corners array.
|
||||
/// </summary>
|
||||
/// <returns>The array of corners.</returns>
|
||||
public Vector3[] GetCorners()
|
||||
{
|
||||
return (Vector3[])this._corners.Clone();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a copy of internal corners array.
|
||||
/// </summary>
|
||||
/// <param name="corners">The array which values will be replaced to corner values of this instance. It must have size of <see cref="BoundingFrustum.CornerCount"/>.</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hash code of this <see cref="BoundingFrustum"/>.
|
||||
/// </summary>
|
||||
/// <returns>Hash code of this <see cref="BoundingFrustum"/>.</returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this._matrix.GetHashCode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not a specified <see cref="BoundingBox"/> intersects with this <see cref="BoundingFrustum"/>.
|
||||
/// </summary>
|
||||
/// <param name="box">A <see cref="BoundingBox"/> for intersection test.</param>
|
||||
/// <returns><c>true</c> if specified <see cref="BoundingBox"/> intersects with this <see cref="BoundingFrustum"/>; <c>false</c> otherwise.</returns>
|
||||
public bool Intersects(BoundingBox box)
|
||||
{
|
||||
var result = false;
|
||||
this.Intersects(ref box, out result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not a specified <see cref="BoundingBox"/> intersects with this <see cref="BoundingFrustum"/>.
|
||||
/// </summary>
|
||||
/// <param name="box">A <see cref="BoundingBox"/> for intersection test.</param>
|
||||
/// <param name="result"><c>true</c> if specified <see cref="BoundingBox"/> intersects with this <see cref="BoundingFrustum"/>; <c>false</c> otherwise as an output parameter.</param>
|
||||
public void Intersects(ref BoundingBox box, out bool result)
|
||||
{
|
||||
var containment = default(ContainmentType);
|
||||
this.Contains(ref box, out containment);
|
||||
result = containment != ContainmentType.Disjoint;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not a specified <see cref="BoundingFrustum"/> intersects with this <see cref="BoundingFrustum"/>.
|
||||
/// </summary>
|
||||
/// <param name="frustum">An other <see cref="BoundingFrustum"/> for intersection test.</param>
|
||||
/// <returns><c>true</c> if other <see cref="BoundingFrustum"/> intersects with this <see cref="BoundingFrustum"/>; <c>false</c> otherwise.</returns>
|
||||
public bool Intersects(BoundingFrustum frustum)
|
||||
{
|
||||
return Contains(frustum) != ContainmentType.Disjoint;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not a specified <see cref="BoundingSphere"/> intersects with this <see cref="BoundingFrustum"/>.
|
||||
/// </summary>
|
||||
/// <param name="sphere">A <see cref="BoundingSphere"/> for intersection test.</param>
|
||||
/// <returns><c>true</c> if specified <see cref="BoundingSphere"/> intersects with this <see cref="BoundingFrustum"/>; <c>false</c> otherwise.</returns>
|
||||
public bool Intersects(BoundingSphere sphere)
|
||||
{
|
||||
var result = default(bool);
|
||||
this.Intersects(ref sphere, out result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not a specified <see cref="BoundingSphere"/> intersects with this <see cref="BoundingFrustum"/>.
|
||||
/// </summary>
|
||||
/// <param name="sphere">A <see cref="BoundingSphere"/> for intersection test.</param>
|
||||
/// <param name="result"><c>true</c> if specified <see cref="BoundingSphere"/> intersects with this <see cref="BoundingFrustum"/>; <c>false</c> otherwise as an output parameter.</param>
|
||||
public void Intersects(ref BoundingSphere sphere, out bool result)
|
||||
{
|
||||
var containment = default(ContainmentType);
|
||||
this.Contains(ref sphere, out containment);
|
||||
result = containment != ContainmentType.Disjoint;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets type of intersection between specified <see cref="Plane"/> and this <see cref="BoundingFrustum"/>.
|
||||
/// </summary>
|
||||
/// <param name="plane">A <see cref="Plane"/> for intersection test.</param>
|
||||
/// <returns>A plane intersection type.</returns>
|
||||
public PlaneIntersectionType Intersects(Plane plane)
|
||||
{
|
||||
PlaneIntersectionType result;
|
||||
Intersects(ref plane, out result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets type of intersection between specified <see cref="Plane"/> and this <see cref="BoundingFrustum"/>.
|
||||
/// </summary>
|
||||
/// <param name="plane">A <see cref="Plane"/> for intersection test.</param>
|
||||
/// <param name="result">A plane intersection type as an output parameter.</param>
|
||||
public void Intersects(ref Plane plane, out PlaneIntersectionType result)
|
||||
{
|
||||
result = plane.Intersects(ref _corners[0]);
|
||||
for (int i = 1; i < _corners.Length; i++)
|
||||
if (plane.Intersects(ref _corners[i]) != result)
|
||||
result = PlaneIntersectionType.Intersecting;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the distance of intersection of <see cref="Ray"/> and this <see cref="BoundingFrustum"/> or null if no intersection happens.
|
||||
/// </summary>
|
||||
/// <param name="ray">A <see cref="Ray"/> for intersection test.</param>
|
||||
/// <returns>Distance at which ray intersects with this <see cref="BoundingFrustum"/> or null if no intersection happens.</returns>
|
||||
public float? Intersects(Ray ray)
|
||||
{
|
||||
float? result;
|
||||
Intersects(ref ray, out result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the distance of intersection of <see cref="Ray"/> and this <see cref="BoundingFrustum"/> or null if no intersection happens.
|
||||
/// </summary>
|
||||
/// <param name="ray">A <see cref="Ray"/> for intersection test.</param>
|
||||
/// <param name="result">Distance at which ray intersects with this <see cref="BoundingFrustum"/> or null if no intersection happens as an output parameter.</param>
|
||||
public void Intersects(ref Ray ray, out float? result)
|
||||
{
|
||||
ContainmentType ctype;
|
||||
this.Contains(ref ray.Position, out ctype);
|
||||
|
||||
switch (ctype)
|
||||
{
|
||||
case ContainmentType.Disjoint:
|
||||
result = null;
|
||||
return;
|
||||
case ContainmentType.Contains:
|
||||
result = 0.0f;
|
||||
return;
|
||||
case ContainmentType.Intersects:
|
||||
throw new NotImplementedException();
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="String"/> representation of this <see cref="BoundingFrustum"/> in the format:
|
||||
/// {Near:[nearPlane] Far:[farPlane] Left:[leftPlane] Right:[rightPlane] Top:[topPlane] Bottom:[bottomPlane]}
|
||||
/// </summary>
|
||||
/// <returns><see cref="String"/> representation of this <see cref="BoundingFrustum"/>.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return "{Near: " + this._planes[0] +
|
||||
" Far:" + this._planes[1] +
|
||||
" Left:" + this._planes[2] +
|
||||
" Right:" + this._planes[3] +
|
||||
" Top:" + this._planes[4] +
|
||||
" Bottom:" + this._planes[5] +
|
||||
"}";
|
||||
}
|
||||
|
||||
#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 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;
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,640 @@
|
||||
// MIT License - Copyright (C) The Mono.Xna Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Microsoft.Xna.Framework
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes a sphere in 3D-space for bounding operations.
|
||||
/// </summary>
|
||||
[DataContract]
|
||||
[DebuggerDisplay("{DebugDisplayString,nq}")]
|
||||
public struct BoundingSphere : IEquatable<BoundingSphere>
|
||||
{
|
||||
#region Public Fields
|
||||
|
||||
/// <summary>
|
||||
/// The sphere center.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public Vector3 Center;
|
||||
|
||||
/// <summary>
|
||||
/// The sphere radius.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public float Radius;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Properties
|
||||
|
||||
internal string DebugDisplayString
|
||||
{
|
||||
get
|
||||
{
|
||||
return string.Concat(
|
||||
"Center( ", this.Center.DebugDisplayString, " ) \r\n",
|
||||
"Radius( ", this.Radius.ToString(), " )"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a bounding sphere with the specified center and radius.
|
||||
/// </summary>
|
||||
/// <param name="center">The sphere center.</param>
|
||||
/// <param name="radius">The sphere radius.</param>
|
||||
public BoundingSphere(Vector3 center, float radius)
|
||||
{
|
||||
this.Center = center;
|
||||
this.Radius = radius;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
#region Contains
|
||||
|
||||
/// <summary>
|
||||
/// Test if a bounding box is fully inside, outside, or just intersecting the sphere.
|
||||
/// </summary>
|
||||
/// <param name="box">The box for testing.</param>
|
||||
/// <returns>The containment type.</returns>
|
||||
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);
|
||||
|
||||
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)
|
||||
return ContainmentType.Intersects;
|
||||
|
||||
//else disjoint
|
||||
return ContainmentType.Disjoint;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test if a bounding box is fully inside, outside, or just intersecting the sphere.
|
||||
/// </summary>
|
||||
/// <param name="box">The box for testing.</param>
|
||||
/// <param name="result">The containment type as an output parameter.</param>
|
||||
public void Contains(ref BoundingBox box, out ContainmentType result)
|
||||
{
|
||||
result = this.Contains(box);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test if a frustum is fully inside, outside, or just intersecting the sphere.
|
||||
/// </summary>
|
||||
/// <param name="frustum">The frustum for testing.</param>
|
||||
/// <returns>The containment type.</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test if a frustum is fully inside, outside, or just intersecting the sphere.
|
||||
/// </summary>
|
||||
/// <param name="frustum">The frustum for testing.</param>
|
||||
/// <param name="result">The containment type as an output parameter.</param>
|
||||
public void Contains(ref BoundingFrustum frustum,out ContainmentType result)
|
||||
{
|
||||
result = this.Contains(frustum);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test if a sphere is fully inside, outside, or just intersecting the sphere.
|
||||
/// </summary>
|
||||
/// <param name="sphere">The other sphere for testing.</param>
|
||||
/// <returns>The containment type.</returns>
|
||||
public ContainmentType Contains(BoundingSphere sphere)
|
||||
{
|
||||
ContainmentType result;
|
||||
Contains(ref sphere, out result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test if a sphere is fully inside, outside, or just intersecting the sphere.
|
||||
/// </summary>
|
||||
/// <param name="sphere">The other sphere for testing.</param>
|
||||
/// <param name="result">The containment type as an output parameter.</param>
|
||||
public void Contains(ref BoundingSphere sphere, out ContainmentType result)
|
||||
{
|
||||
float sqDistance;
|
||||
Vector3.DistanceSquared(ref sphere.Center, ref Center, out sqDistance);
|
||||
|
||||
if (sqDistance > (sphere.Radius + Radius) * (sphere.Radius + Radius))
|
||||
result = ContainmentType.Disjoint;
|
||||
|
||||
else if (sqDistance <= (Radius - sphere.Radius) * (Radius - sphere.Radius))
|
||||
result = ContainmentType.Contains;
|
||||
|
||||
else
|
||||
result = ContainmentType.Intersects;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test if a point is fully inside, outside, or just intersecting the sphere.
|
||||
/// </summary>
|
||||
/// <param name="point">The vector in 3D-space for testing.</param>
|
||||
/// <returns>The containment type.</returns>
|
||||
public ContainmentType Contains(Vector3 point)
|
||||
{
|
||||
ContainmentType result;
|
||||
Contains(ref point, out result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test if a point is fully inside, outside, or just intersecting the sphere.
|
||||
/// </summary>
|
||||
/// <param name="point">The vector in 3D-space for testing.</param>
|
||||
/// <param name="result">The containment type as an output parameter.</param>
|
||||
public void Contains(ref Vector3 point, out ContainmentType result)
|
||||
{
|
||||
float sqRadius = Radius * Radius;
|
||||
float sqDistance;
|
||||
Vector3.DistanceSquared(ref point, ref Center, out sqDistance);
|
||||
|
||||
if (sqDistance > sqRadius)
|
||||
result = ContainmentType.Disjoint;
|
||||
|
||||
else if (sqDistance < sqRadius)
|
||||
result = ContainmentType.Contains;
|
||||
|
||||
else
|
||||
result = ContainmentType.Intersects;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region CreateFromBoundingBox
|
||||
|
||||
/// <summary>
|
||||
/// Creates the smallest <see cref="BoundingSphere"/> that can contain a specified <see cref="BoundingBox"/>.
|
||||
/// </summary>
|
||||
/// <param name="box">The box to create the sphere from.</param>
|
||||
/// <returns>The new <see cref="BoundingSphere"/>.</returns>
|
||||
public static BoundingSphere CreateFromBoundingBox(BoundingBox box)
|
||||
{
|
||||
BoundingSphere result;
|
||||
CreateFromBoundingBox(ref box, out result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the smallest <see cref="BoundingSphere"/> that can contain a specified <see cref="BoundingBox"/>.
|
||||
/// </summary>
|
||||
/// <param name="box">The box to create the sphere from.</param>
|
||||
/// <param name="result">The new <see cref="BoundingSphere"/> as an output parameter.</param>
|
||||
public static void CreateFromBoundingBox(ref BoundingBox box, out BoundingSphere result)
|
||||
{
|
||||
// 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);
|
||||
|
||||
result = new BoundingSphere(center, radius);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Creates the smallest <see cref="BoundingSphere"/> that can contain a specified <see cref="BoundingFrustum"/>.
|
||||
/// </summary>
|
||||
/// <param name="frustum">The frustum to create the sphere from.</param>
|
||||
/// <returns>The new <see cref="BoundingSphere"/>.</returns>
|
||||
public static BoundingSphere CreateFromFrustum(BoundingFrustum frustum)
|
||||
{
|
||||
return CreateFromPoints(frustum.GetCorners());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the smallest <see cref="BoundingSphere"/> that can contain a specified list of points in 3D-space.
|
||||
/// </summary>
|
||||
/// <param name="points">List of point to create the sphere from.</param>
|
||||
/// <returns>The new <see cref="BoundingSphere"/>.</returns>
|
||||
public static BoundingSphere CreateFromPoints(IEnumerable<Vector3> points)
|
||||
{
|
||||
if (points == null )
|
||||
throw new ArgumentNullException("points");
|
||||
|
||||
// From "Real-Time Collision Detection" (Page 89)
|
||||
|
||||
var minx = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
|
||||
var maxx = -minx;
|
||||
var miny = minx;
|
||||
var maxy = -minx;
|
||||
var minz = minx;
|
||||
var maxz = -minx;
|
||||
|
||||
// Find the most extreme points along the principle axis.
|
||||
var numPoints = 0;
|
||||
foreach (var pt in points)
|
||||
{
|
||||
++numPoints;
|
||||
|
||||
if (pt.X < minx.X)
|
||||
minx = pt;
|
||||
if (pt.X > maxx.X)
|
||||
maxx = pt;
|
||||
if (pt.Y < miny.Y)
|
||||
miny = pt;
|
||||
if (pt.Y > maxy.Y)
|
||||
maxy = pt;
|
||||
if (pt.Z < minz.Z)
|
||||
minz = pt;
|
||||
if (pt.Z > maxz.Z)
|
||||
maxz = pt;
|
||||
}
|
||||
|
||||
if (numPoints == 0)
|
||||
throw new ArgumentException("You should have at least one point in points.");
|
||||
|
||||
var sqDistX = Vector3.DistanceSquared(maxx, minx);
|
||||
var sqDistY = Vector3.DistanceSquared(maxy, miny);
|
||||
var sqDistZ = Vector3.DistanceSquared(maxz, minz);
|
||||
|
||||
// Pick the pair of most distant points.
|
||||
var min = minx;
|
||||
var max = maxx;
|
||||
if (sqDistY > sqDistX && sqDistY > sqDistZ)
|
||||
{
|
||||
max = maxy;
|
||||
min = miny;
|
||||
}
|
||||
if (sqDistZ > sqDistX && sqDistZ > sqDistY)
|
||||
{
|
||||
max = maxz;
|
||||
min = minz;
|
||||
}
|
||||
|
||||
var center = (min + max) * 0.5f;
|
||||
var radius = Vector3.Distance(max, center);
|
||||
|
||||
// Test every point and expand the sphere.
|
||||
// The current bounding sphere is just a good approximation and may not enclose all points.
|
||||
// From: Mathematics for 3D Game Programming and Computer Graphics, Eric Lengyel, Third Edition.
|
||||
// Page 218
|
||||
float sqRadius = radius * radius;
|
||||
foreach (var pt in points)
|
||||
{
|
||||
Vector3 diff = (pt-center);
|
||||
float sqDist = diff.LengthSquared();
|
||||
if (sqDist > sqRadius)
|
||||
{
|
||||
float distance = (float)Math.Sqrt(sqDist); // equal to diff.Length();
|
||||
Vector3 direction = diff / distance;
|
||||
Vector3 G = center - radius * direction;
|
||||
center = (G + pt) / 2;
|
||||
radius = Vector3.Distance(pt, center);
|
||||
sqRadius = radius * radius;
|
||||
}
|
||||
}
|
||||
|
||||
return new BoundingSphere(center, radius);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the smallest <see cref="BoundingSphere"/> that can contain two spheres.
|
||||
/// </summary>
|
||||
/// <param name="original">First sphere.</param>
|
||||
/// <param name="additional">Second sphere.</param>
|
||||
/// <returns>The new <see cref="BoundingSphere"/>.</returns>
|
||||
public static BoundingSphere CreateMerged(BoundingSphere original, BoundingSphere additional)
|
||||
{
|
||||
BoundingSphere result;
|
||||
CreateMerged(ref original, ref additional, out result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the smallest <see cref="BoundingSphere"/> that can contain two spheres.
|
||||
/// </summary>
|
||||
/// <param name="original">First sphere.</param>
|
||||
/// <param name="additional">Second sphere.</param>
|
||||
/// <param name="result">The new <see cref="BoundingSphere"/> as an output parameter.</param>
|
||||
public static void CreateMerged(ref BoundingSphere original, ref BoundingSphere additional, out BoundingSphere result)
|
||||
{
|
||||
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
|
||||
{
|
||||
result = original;
|
||||
return;
|
||||
}
|
||||
if (distance <= additional.Radius - original.Radius)//additional contain original
|
||||
{
|
||||
result = additional;
|
||||
return;
|
||||
}
|
||||
}
|
||||
//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
|
||||
|
||||
result = new BoundingSphere();
|
||||
result.Center = original.Center + ocenterToaCenter;
|
||||
result.Radius = (leftRadius + Rightradius) / 2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares whether current instance is equal to specified <see cref="BoundingSphere"/>.
|
||||
/// </summary>
|
||||
/// <param name="other">The <see cref="BoundingSphere"/> to compare.</param>
|
||||
/// <returns><c>true</c> if the instances are equal; <c>false</c> otherwise.</returns>
|
||||
public bool Equals(BoundingSphere other)
|
||||
{
|
||||
return this.Center == other.Center && this.Radius == other.Radius;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares whether current instance is equal to specified <see cref="Object"/>.
|
||||
/// </summary>
|
||||
/// <param name="obj">The <see cref="Object"/> to compare.</param>
|
||||
/// <returns><c>true</c> if the instances are equal; <c>false</c> otherwise.</returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is BoundingSphere)
|
||||
return this.Equals((BoundingSphere)obj);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hash code of this <see cref="BoundingSphere"/>.
|
||||
/// </summary>
|
||||
/// <returns>Hash code of this <see cref="BoundingSphere"/>.</returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.Center.GetHashCode() + this.Radius.GetHashCode();
|
||||
}
|
||||
|
||||
#region Intersects
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not a specified <see cref="BoundingBox"/> intersects with this sphere.
|
||||
/// </summary>
|
||||
/// <param name="box">The box for testing.</param>
|
||||
/// <returns><c>true</c> if <see cref="BoundingBox"/> intersects with this sphere; <c>false</c> otherwise.</returns>
|
||||
public bool Intersects(BoundingBox box)
|
||||
{
|
||||
return box.Intersects(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not a specified <see cref="BoundingBox"/> intersects with this sphere.
|
||||
/// </summary>
|
||||
/// <param name="box">The box for testing.</param>
|
||||
/// <param name="result"><c>true</c> if <see cref="BoundingBox"/> intersects with this sphere; <c>false</c> otherwise. As an output parameter.</param>
|
||||
public void Intersects(ref BoundingBox box, out bool result)
|
||||
{
|
||||
box.Intersects(ref this, out result);
|
||||
}
|
||||
|
||||
/*
|
||||
TODO : Make the public bool Intersects(BoundingFrustum frustum) overload
|
||||
|
||||
public bool Intersects(BoundingFrustum frustum)
|
||||
{
|
||||
if (frustum == null)
|
||||
throw new NullReferenceException();
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not the other <see cref="BoundingSphere"/> intersects with this sphere.
|
||||
/// </summary>
|
||||
/// <param name="sphere">The other sphere for testing.</param>
|
||||
/// <returns><c>true</c> if other <see cref="BoundingSphere"/> intersects with this sphere; <c>false</c> otherwise.</returns>
|
||||
public bool Intersects(BoundingSphere sphere)
|
||||
{
|
||||
bool result;
|
||||
Intersects(ref sphere, out result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not the other <see cref="BoundingSphere"/> intersects with this sphere.
|
||||
/// </summary>
|
||||
/// <param name="sphere">The other sphere for testing.</param>
|
||||
/// <param name="result"><c>true</c> if other <see cref="BoundingSphere"/> intersects with this sphere; <c>false</c> otherwise. As an output parameter.</param>
|
||||
public void Intersects(ref BoundingSphere sphere, out bool result)
|
||||
{
|
||||
float sqDistance;
|
||||
Vector3.DistanceSquared(ref sphere.Center, ref Center, out sqDistance);
|
||||
|
||||
if (sqDistance > (sphere.Radius + Radius) * (sphere.Radius + Radius))
|
||||
result = false;
|
||||
else
|
||||
result = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not a specified <see cref="Plane"/> intersects with this sphere.
|
||||
/// </summary>
|
||||
/// <param name="plane">The plane for testing.</param>
|
||||
/// <returns>Type of intersection.</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not a specified <see cref="Plane"/> intersects with this sphere.
|
||||
/// </summary>
|
||||
/// <param name="plane">The plane for testing.</param>
|
||||
/// <param name="result">Type of intersection as an output parameter.</param>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not a specified <see cref="Ray"/> intersects with this sphere.
|
||||
/// </summary>
|
||||
/// <param name="ray">The ray for testing.</param>
|
||||
/// <returns>Distance of ray intersection or <c>null</c> if there is no intersection.</returns>
|
||||
public float? Intersects(Ray ray)
|
||||
{
|
||||
return ray.Intersects(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not a specified <see cref="Ray"/> intersects with this sphere.
|
||||
/// </summary>
|
||||
/// <param name="ray">The ray for testing.</param>
|
||||
/// <param name="result">Distance of ray intersection or <c>null</c> if there is no intersection as an output parameter.</param>
|
||||
public void Intersects(ref Ray ray, out float? result)
|
||||
{
|
||||
ray.Intersects(ref this, out result);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="String"/> representation of this <see cref="BoundingSphere"/> in the format:
|
||||
/// {Center:[<see cref="Center"/>] Radius:[<see cref="Radius"/>]}
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="String"/> representation of this <see cref="BoundingSphere"/>.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return "{Center:" + this.Center + " Radius:" + this.Radius + "}";
|
||||
}
|
||||
|
||||
#region Transform
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="BoundingSphere"/> that contains a transformation of translation and scale from this sphere by the specified <see cref="Matrix"/>.
|
||||
/// </summary>
|
||||
/// <param name="matrix">The transformation <see cref="Matrix"/>.</param>
|
||||
/// <returns>Transformed <see cref="BoundingSphere"/>.</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="BoundingSphere"/> that contains a transformation of translation and scale from this sphere by the specified <see cref="Matrix"/>.
|
||||
/// </summary>
|
||||
/// <param name="matrix">The transformation <see cref="Matrix"/>.</param>
|
||||
/// <param name="result">Transformed <see cref="BoundingSphere"/> as an output parameter.</param>
|
||||
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)))));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Deconstruction method for <see cref="BoundingSphere"/>.
|
||||
/// </summary>
|
||||
/// <param name="center"></param>
|
||||
/// <param name="radius"></param>
|
||||
public void Deconstruct(out Vector3 center, out float radius)
|
||||
{
|
||||
center = Center;
|
||||
radius = Radius;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Operators
|
||||
|
||||
/// <summary>
|
||||
/// Compares whether two <see cref="BoundingSphere"/> instances are equal.
|
||||
/// </summary>
|
||||
/// <param name="a"><see cref="BoundingSphere"/> instance on the left of the equal sign.</param>
|
||||
/// <param name="b"><see cref="BoundingSphere"/> instance on the right of the equal sign.</param>
|
||||
/// <returns><c>true</c> if the instances are equal; <c>false</c> otherwise.</returns>
|
||||
public static bool operator == (BoundingSphere a, BoundingSphere b)
|
||||
{
|
||||
return a.Equals(b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares whether two <see cref="BoundingSphere"/> instances are not equal.
|
||||
/// </summary>
|
||||
/// <param name="a"><see cref="BoundingSphere"/> instance on the left of the not equal sign.</param>
|
||||
/// <param name="b"><see cref="BoundingSphere"/> instance on the right of the not equal sign.</param>
|
||||
/// <returns><c>true</c> if the instances are not equal; <c>false</c> otherwise.</returns>
|
||||
public static bool operator != (BoundingSphere a, BoundingSphere b)
|
||||
{
|
||||
return !a.Equals(b);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
//TODO: maybe make this compile even if SDL isn't available
|
||||
|
||||
namespace Microsoft.Xna.Framework
|
||||
{
|
||||
public static class Clipboard
|
||||
{
|
||||
public static string GetText()
|
||||
{
|
||||
return Sdl.GetClipboardText();
|
||||
}
|
||||
|
||||
public static void SetText(string text)
|
||||
{
|
||||
Sdl.SetClipboardText(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
||||
// MIT License - Copyright (C) The Mono.Xna Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
namespace Microsoft.Xna.Framework
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines how the bounding volumes intersects or contain one another.
|
||||
/// </summary>
|
||||
public enum ContainmentType
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that there is no overlap between two bounding volumes.
|
||||
/// </summary>
|
||||
Disjoint,
|
||||
/// <summary>
|
||||
/// Indicates that one bounding volume completely contains another volume.
|
||||
/// </summary>
|
||||
Contains,
|
||||
/// <summary>
|
||||
/// Indicates that bounding volumes partially overlap one another.
|
||||
/// </summary>
|
||||
Intersects
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal static class ContentExtensions
|
||||
{
|
||||
public static ConstructorInfo GetDefaultConstructor(this Type type)
|
||||
{
|
||||
#if NET45
|
||||
var typeInfo = type.GetTypeInfo();
|
||||
var ctor = typeInfo.DeclaredConstructors.FirstOrDefault(c => !c.IsStatic && c.GetParameters().Length == 0);
|
||||
return ctor;
|
||||
#else
|
||||
var attrs = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance;
|
||||
return type.GetConstructor(attrs, null, new Type[0], null);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static PropertyInfo[] GetAllProperties(this Type type)
|
||||
{
|
||||
|
||||
// Sometimes, overridden properties of abstract classes can show up even with
|
||||
// BindingFlags.DeclaredOnly is passed to GetProperties. Make sure that
|
||||
// all properties in this list are defined in this class by comparing
|
||||
// its get method with that of it's base class. If they're the same
|
||||
// Then it's an overridden property.
|
||||
#if NET45
|
||||
PropertyInfo[] infos= type.GetTypeInfo().DeclaredProperties.ToArray();
|
||||
var nonStaticPropertyInfos = from p in infos
|
||||
where (p.GetMethod != null) && (!p.GetMethod.IsStatic) &&
|
||||
(p.GetMethod == p.GetMethod.GetRuntimeBaseDefinition())
|
||||
select p;
|
||||
return nonStaticPropertyInfos.ToArray();
|
||||
#else
|
||||
const BindingFlags attrs = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly;
|
||||
var allProps = type.GetProperties(attrs).ToList();
|
||||
var props = allProps.FindAll(p => p.GetGetMethod(true) != null && p.GetGetMethod(true) == p.GetGetMethod(true).GetBaseDefinition()).ToArray();
|
||||
return props;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
public static FieldInfo[] GetAllFields(this Type type)
|
||||
{
|
||||
#if NET45
|
||||
FieldInfo[] fields= type.GetTypeInfo().DeclaredFields.ToArray();
|
||||
var nonStaticFields = from field in fields
|
||||
where !field.IsStatic
|
||||
select field;
|
||||
return nonStaticFields.ToArray();
|
||||
#else
|
||||
var attrs = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly;
|
||||
return type.GetFields(attrs);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static bool IsClass(this Type type)
|
||||
{
|
||||
#if NET45
|
||||
return type.GetTypeInfo().IsClass;
|
||||
#else
|
||||
return type.IsClass;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
#region License
|
||||
/*
|
||||
Microsoft Public License (Ms-PL)
|
||||
MonoGame - Copyright © 2009 The MonoGame Team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
This license governs use of the accompanying software. If you use the software, you accept this license. If you do not
|
||||
accept the license, do not use the software.
|
||||
|
||||
1. Definitions
|
||||
The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under
|
||||
U.S. copyright law.
|
||||
|
||||
A "contribution" is the original software, or any additions or changes to the software.
|
||||
A "contributor" is any person that distributes its contribution under this license.
|
||||
"Licensed patents" are a contributor's patent claims that read directly on its contribution.
|
||||
|
||||
2. Grant of Rights
|
||||
(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3,
|
||||
each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
|
||||
(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3,
|
||||
each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
|
||||
|
||||
3. Conditions and Limitations
|
||||
(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
|
||||
(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software,
|
||||
your patent license from such contributor to the software ends automatically.
|
||||
(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution
|
||||
notices that are present in the software.
|
||||
(D) If you distribute any portion of the software in source code form, you may do so only under this license by including
|
||||
a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object
|
||||
code form, you may only do so under a license that complies with this license.
|
||||
(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees
|
||||
or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent
|
||||
permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular
|
||||
purpose and non-infringement.
|
||||
*/
|
||||
#endregion License
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
public class ContentLoadException : Exception
|
||||
{
|
||||
public ContentLoadException() : base()
|
||||
{
|
||||
}
|
||||
|
||||
public ContentLoadException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public ContentLoadException(string message, Exception innerException) : base(message,innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,505 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using MonoGame.Utilities;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
public partial class ContentManager : IDisposable
|
||||
{
|
||||
const byte ContentCompressedLzx = 0x80;
|
||||
const byte ContentCompressedLz4 = 0x40;
|
||||
|
||||
private string _rootDirectory = string.Empty;
|
||||
private IServiceProvider serviceProvider;
|
||||
private IGraphicsDeviceService graphicsDeviceService;
|
||||
private Dictionary<string, object> loadedAssets = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
|
||||
private List<IDisposable> disposableAssets = new List<IDisposable>();
|
||||
private bool disposed;
|
||||
private byte[] scratchBuffer;
|
||||
|
||||
private static object ContentManagerLock = new object();
|
||||
private static List<WeakReference> ContentManagers = new List<WeakReference>();
|
||||
|
||||
private static readonly List<char> targetPlatformIdentifiers = new List<char>()
|
||||
{
|
||||
'w', // Windows (XNA & DirectX)
|
||||
'x', // Xbox360 (XNA)
|
||||
'm', // WindowsPhone7.0 (XNA)
|
||||
'i', // iOS
|
||||
'a', // Android
|
||||
'd', // DesktopGL
|
||||
'X', // MacOSX
|
||||
'W', // WindowsStoreApp
|
||||
'n', // NativeClient
|
||||
'M', // WindowsPhone8
|
||||
'r', // RaspberryPi
|
||||
'P', // PlayStation4
|
||||
'v', // PSVita
|
||||
'O', // XboxOne
|
||||
'S', // Nintendo Switch
|
||||
|
||||
// NOTE: There are additional idenfiers for consoles that
|
||||
// are not defined in this repository. Be sure to ask the
|
||||
// console port maintainers to ensure no collisions occur.
|
||||
|
||||
|
||||
// Legacy identifiers... these could be reused in the
|
||||
// future if we feel enough time has passed.
|
||||
|
||||
'p', // PlayStationMobile
|
||||
'g', // Windows (OpenGL)
|
||||
'l', // Linux
|
||||
};
|
||||
|
||||
|
||||
static partial void PlatformStaticInit();
|
||||
|
||||
static ContentManager()
|
||||
{
|
||||
// Allow any per-platform static initialization to occur.
|
||||
PlatformStaticInit();
|
||||
}
|
||||
|
||||
private static void AddContentManager(ContentManager contentManager)
|
||||
{
|
||||
lock (ContentManagerLock)
|
||||
{
|
||||
// Check if the list contains this content manager already. Also take
|
||||
// the opportunity to prune the list of any finalized content managers.
|
||||
bool contains = false;
|
||||
for (int i = ContentManagers.Count - 1; i >= 0; --i)
|
||||
{
|
||||
var contentRef = ContentManagers[i];
|
||||
if (ReferenceEquals(contentRef.Target, contentManager))
|
||||
contains = true;
|
||||
if (!contentRef.IsAlive)
|
||||
ContentManagers.RemoveAt(i);
|
||||
}
|
||||
if (!contains)
|
||||
ContentManagers.Add(new WeakReference(contentManager));
|
||||
}
|
||||
}
|
||||
|
||||
private static void RemoveContentManager(ContentManager contentManager)
|
||||
{
|
||||
lock (ContentManagerLock)
|
||||
{
|
||||
// Check if the list contains this content manager and remove it. Also
|
||||
// take the opportunity to prune the list of any finalized content managers.
|
||||
for (int i = ContentManagers.Count - 1; i >= 0; --i)
|
||||
{
|
||||
var contentRef = ContentManagers[i];
|
||||
if (!contentRef.IsAlive || ReferenceEquals(contentRef.Target, contentManager))
|
||||
ContentManagers.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void ReloadGraphicsContent()
|
||||
{
|
||||
lock (ContentManagerLock)
|
||||
{
|
||||
// Reload the graphic assets of each content manager. Also take the
|
||||
// opportunity to prune the list of any finalized content managers.
|
||||
for (int i = ContentManagers.Count - 1; i >= 0; --i)
|
||||
{
|
||||
var contentRef = ContentManagers[i];
|
||||
if (contentRef.IsAlive)
|
||||
{
|
||||
var contentManager = (ContentManager)contentRef.Target;
|
||||
if (contentManager != null)
|
||||
contentManager.ReloadGraphicsAssets();
|
||||
}
|
||||
else
|
||||
{
|
||||
ContentManagers.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use C# destructor syntax for finalization code.
|
||||
// This destructor will run only if the Dispose method
|
||||
// does not get called.
|
||||
// It gives your base class the opportunity to finalize.
|
||||
// Do not provide destructors in types derived from this class.
|
||||
~ContentManager()
|
||||
{
|
||||
// Do not re-create Dispose clean-up code here.
|
||||
// Calling Dispose(false) is optimal in terms of
|
||||
// readability and maintainability.
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public ContentManager(IServiceProvider serviceProvider)
|
||||
{
|
||||
if (serviceProvider == null)
|
||||
{
|
||||
throw new ArgumentNullException("serviceProvider");
|
||||
}
|
||||
this.serviceProvider = serviceProvider;
|
||||
AddContentManager(this);
|
||||
}
|
||||
|
||||
public ContentManager(IServiceProvider serviceProvider, string rootDirectory)
|
||||
{
|
||||
if (serviceProvider == null)
|
||||
{
|
||||
throw new ArgumentNullException("serviceProvider");
|
||||
}
|
||||
if (rootDirectory == null)
|
||||
{
|
||||
throw new ArgumentNullException("rootDirectory");
|
||||
}
|
||||
this.RootDirectory = rootDirectory;
|
||||
this.serviceProvider = serviceProvider;
|
||||
AddContentManager(this);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
// Tell the garbage collector not to call the finalizer
|
||||
// since all the cleanup will already be done.
|
||||
GC.SuppressFinalize(this);
|
||||
// Once disposed, content manager wont be used again
|
||||
RemoveContentManager(this);
|
||||
}
|
||||
|
||||
// If disposing is true, it was called explicitly and we should dispose managed objects.
|
||||
// If disposing is false, it was called by the finalizer and managed objects should not be disposed.
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
Unload();
|
||||
}
|
||||
|
||||
scratchBuffer = null;
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual T LoadLocalized<T> (string assetName)
|
||||
{
|
||||
string [] cultureNames =
|
||||
{
|
||||
CultureInfo.CurrentCulture.Name, // eg. "en-US"
|
||||
CultureInfo.CurrentCulture.TwoLetterISOLanguageName // eg. "en"
|
||||
};
|
||||
|
||||
// Look first for a specialized language-country version of the asset,
|
||||
// then if that fails, loop back around to see if we can find one that
|
||||
// specifies just the language without the country part.
|
||||
foreach (string cultureName in cultureNames) {
|
||||
string localizedAssetName = assetName + '.' + cultureName;
|
||||
|
||||
try {
|
||||
return Load<T> (localizedAssetName);
|
||||
} catch (ContentLoadException) { }
|
||||
}
|
||||
|
||||
// If we didn't find any localized asset, fall back to the default name.
|
||||
return Load<T> (assetName);
|
||||
}
|
||||
|
||||
public virtual T Load<T>(string assetName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(assetName))
|
||||
{
|
||||
throw new ArgumentNullException("assetName");
|
||||
}
|
||||
if (disposed)
|
||||
{
|
||||
throw new ObjectDisposedException("ContentManager");
|
||||
}
|
||||
|
||||
T result = default(T);
|
||||
|
||||
// On some platforms, name and slash direction matter.
|
||||
// We store the asset by a /-seperating key rather than how the
|
||||
// path to the file was passed to us to avoid
|
||||
// loading "content/asset1.xnb" and "content\\ASSET1.xnb" as if they were two
|
||||
// different files. This matches stock XNA behavior.
|
||||
// The dictionary will ignore case differences
|
||||
var key = assetName.Replace('\\', '/');
|
||||
|
||||
// Check for a previously loaded asset first
|
||||
object asset = null;
|
||||
if (loadedAssets.TryGetValue(key, out asset))
|
||||
{
|
||||
if (asset is T)
|
||||
{
|
||||
return (T)asset;
|
||||
}
|
||||
}
|
||||
|
||||
// Load the asset.
|
||||
result = ReadAsset<T>(assetName, null);
|
||||
|
||||
loadedAssets[key] = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
protected virtual Stream OpenStream(string assetName)
|
||||
{
|
||||
Stream stream;
|
||||
try
|
||||
{
|
||||
var assetPath = Path.Combine(RootDirectory, assetName) + ".xnb";
|
||||
|
||||
// This is primarily for editor support.
|
||||
// Setting the RootDirectory to an absolute path is useful in editor
|
||||
// situations, but TitleContainer can ONLY be passed relative paths.
|
||||
#if DESKTOPGL || WINDOWS
|
||||
if (Path.IsPathRooted(assetPath))
|
||||
stream = File.OpenRead(assetPath);
|
||||
else
|
||||
#endif
|
||||
stream = TitleContainer.OpenStream(assetPath);
|
||||
#if ANDROID
|
||||
// Read the asset into memory in one go. This results in a ~50% reduction
|
||||
// in load times on Android due to slow Android asset streams.
|
||||
MemoryStream memStream = new MemoryStream();
|
||||
stream.CopyTo(memStream);
|
||||
memStream.Seek(0, SeekOrigin.Begin);
|
||||
stream.Close();
|
||||
stream = memStream;
|
||||
#endif
|
||||
}
|
||||
catch (FileNotFoundException fileNotFound)
|
||||
{
|
||||
throw new ContentLoadException("The content file was not found.", fileNotFound);
|
||||
}
|
||||
#if !WINDOWS_UAP
|
||||
catch (DirectoryNotFoundException directoryNotFound)
|
||||
{
|
||||
throw new ContentLoadException("The directory was not found.", directoryNotFound);
|
||||
}
|
||||
#endif
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new ContentLoadException("Opening stream error.", exception);
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
protected T ReadAsset<T>(string assetName, Action<IDisposable> recordDisposableObject)
|
||||
{
|
||||
if (string.IsNullOrEmpty(assetName))
|
||||
{
|
||||
throw new ArgumentNullException("assetName");
|
||||
}
|
||||
if (disposed)
|
||||
{
|
||||
throw new ObjectDisposedException("ContentManager");
|
||||
}
|
||||
|
||||
string originalAssetName = assetName;
|
||||
object result = null;
|
||||
|
||||
if (this.graphicsDeviceService == null)
|
||||
{
|
||||
this.graphicsDeviceService = serviceProvider.GetService(typeof(IGraphicsDeviceService)) as IGraphicsDeviceService;
|
||||
if (this.graphicsDeviceService == null)
|
||||
{
|
||||
throw new InvalidOperationException("No Graphics Device Service");
|
||||
}
|
||||
}
|
||||
|
||||
// Try to load as XNB file
|
||||
var stream = OpenStream(assetName);
|
||||
using (var xnbReader = new BinaryReader(stream))
|
||||
{
|
||||
using (var reader = GetContentReaderFromXnb(assetName, stream, xnbReader, recordDisposableObject))
|
||||
{
|
||||
result = reader.ReadAsset<T>();
|
||||
if (result is GraphicsResource)
|
||||
((GraphicsResource)result).Name = originalAssetName;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == null)
|
||||
throw new ContentLoadException("Could not load " + originalAssetName + " asset!");
|
||||
|
||||
return (T)result;
|
||||
}
|
||||
|
||||
private ContentReader GetContentReaderFromXnb(string originalAssetName, Stream stream, BinaryReader xnbReader, Action<IDisposable> recordDisposableObject)
|
||||
{
|
||||
// The first 4 bytes should be the "XNB" header. i use that to detect an invalid file
|
||||
byte x = xnbReader.ReadByte();
|
||||
byte n = xnbReader.ReadByte();
|
||||
byte b = xnbReader.ReadByte();
|
||||
byte platform = xnbReader.ReadByte();
|
||||
|
||||
if (x != 'X' || n != 'N' || b != 'B' ||
|
||||
!(targetPlatformIdentifiers.Contains((char)platform)))
|
||||
{
|
||||
throw new ContentLoadException("Asset does not appear to be a valid XNB file. Did you process your content for Windows?");
|
||||
}
|
||||
|
||||
byte version = xnbReader.ReadByte();
|
||||
byte flags = xnbReader.ReadByte();
|
||||
|
||||
bool compressedLzx = (flags & ContentCompressedLzx) != 0;
|
||||
bool compressedLz4 = (flags & ContentCompressedLz4) != 0;
|
||||
if (version != 5 && version != 4)
|
||||
{
|
||||
throw new ContentLoadException("Invalid XNB version");
|
||||
}
|
||||
|
||||
// The next int32 is the length of the XNB file
|
||||
int xnbLength = xnbReader.ReadInt32();
|
||||
|
||||
Stream decompressedStream = null;
|
||||
if (compressedLzx || compressedLz4)
|
||||
{
|
||||
// Decompress the xnb
|
||||
int decompressedSize = xnbReader.ReadInt32();
|
||||
|
||||
if (compressedLzx)
|
||||
{
|
||||
int compressedSize = xnbLength - 14;
|
||||
decompressedStream = new LzxDecoderStream(stream, decompressedSize, compressedSize);
|
||||
}
|
||||
else if (compressedLz4)
|
||||
{
|
||||
decompressedStream = new Lz4DecoderStream(stream);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
decompressedStream = stream;
|
||||
}
|
||||
|
||||
var reader = new ContentReader(this, decompressedStream, this.graphicsDeviceService.GraphicsDevice,
|
||||
originalAssetName, version, recordDisposableObject);
|
||||
|
||||
return reader;
|
||||
}
|
||||
|
||||
internal void RecordDisposable(IDisposable disposable)
|
||||
{
|
||||
Debug.Assert(disposable != null, "The disposable is null!");
|
||||
|
||||
// Avoid recording disposable objects twice. ReloadAsset will try to record the disposables again.
|
||||
// We don't know which asset recorded which disposable so just guard against storing multiple of the same instance.
|
||||
if (!disposableAssets.Contains(disposable))
|
||||
disposableAssets.Add(disposable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Virtual property to allow a derived ContentManager to have it's assets reloaded
|
||||
/// </summary>
|
||||
protected virtual Dictionary<string, object> LoadedAssets
|
||||
{
|
||||
get { return loadedAssets; }
|
||||
}
|
||||
|
||||
protected virtual void ReloadGraphicsAssets()
|
||||
{
|
||||
foreach (var asset in LoadedAssets)
|
||||
{
|
||||
// This never executes as asset.Key is never null. This just forces the
|
||||
// linker to include the ReloadAsset function when AOT compiled.
|
||||
if (asset.Key == null)
|
||||
ReloadAsset(asset.Key, Convert.ChangeType(asset.Value, asset.Value.GetType()));
|
||||
|
||||
var methodInfo = ReflectionHelpers.GetMethodInfo(typeof(ContentManager), "ReloadAsset");
|
||||
var genericMethod = methodInfo.MakeGenericMethod(asset.Value.GetType());
|
||||
genericMethod.Invoke(this, new object[] { asset.Key, Convert.ChangeType(asset.Value, asset.Value.GetType()) });
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void ReloadAsset<T>(string originalAssetName, T currentAsset)
|
||||
{
|
||||
string assetName = originalAssetName;
|
||||
if (string.IsNullOrEmpty(assetName))
|
||||
{
|
||||
throw new ArgumentNullException("assetName");
|
||||
}
|
||||
if (disposed)
|
||||
{
|
||||
throw new ObjectDisposedException("ContentManager");
|
||||
}
|
||||
|
||||
if (this.graphicsDeviceService == null)
|
||||
{
|
||||
this.graphicsDeviceService = serviceProvider.GetService(typeof(IGraphicsDeviceService)) as IGraphicsDeviceService;
|
||||
if (this.graphicsDeviceService == null)
|
||||
{
|
||||
throw new InvalidOperationException("No Graphics Device Service");
|
||||
}
|
||||
}
|
||||
|
||||
var stream = OpenStream(assetName);
|
||||
using (var xnbReader = new BinaryReader(stream))
|
||||
{
|
||||
using (var reader = GetContentReaderFromXnb(assetName, stream, xnbReader, null))
|
||||
{
|
||||
reader.ReadAsset<T>(currentAsset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Unload()
|
||||
{
|
||||
// Look for disposable assets.
|
||||
foreach (var disposable in disposableAssets)
|
||||
{
|
||||
if (disposable != null)
|
||||
disposable.Dispose();
|
||||
}
|
||||
disposableAssets.Clear();
|
||||
loadedAssets.Clear();
|
||||
}
|
||||
|
||||
public string RootDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
return _rootDirectory;
|
||||
}
|
||||
set
|
||||
{
|
||||
_rootDirectory = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal string RootDirectoryFullPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(TitleContainer.Location, RootDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
public IServiceProvider ServiceProvider
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.serviceProvider;
|
||||
}
|
||||
}
|
||||
|
||||
internal byte[] GetScratchBuffer(int size)
|
||||
{
|
||||
size = Math.Max(size, 1024 * 1024);
|
||||
if (scratchBuffer == null || scratchBuffer.Length < size)
|
||||
scratchBuffer = new byte[size];
|
||||
return scratchBuffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,308 @@
|
||||
// MIT License - Copyright (C) The Mono.Xna Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using MonoGame.Utilities;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
public sealed class ContentReader : BinaryReader
|
||||
{
|
||||
private ContentManager contentManager;
|
||||
private Action<IDisposable> recordDisposableObject;
|
||||
private ContentTypeReaderManager typeReaderManager;
|
||||
private GraphicsDevice graphicsDevice;
|
||||
private string assetName;
|
||||
private List<KeyValuePair<int, Action<object>>> sharedResourceFixups;
|
||||
private ContentTypeReader[] typeReaders;
|
||||
internal int version;
|
||||
internal int sharedResourceCount;
|
||||
|
||||
internal ContentTypeReader[] TypeReaders
|
||||
{
|
||||
get
|
||||
{
|
||||
return typeReaders;
|
||||
}
|
||||
}
|
||||
|
||||
internal GraphicsDevice GraphicsDevice
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.graphicsDevice;
|
||||
}
|
||||
}
|
||||
|
||||
internal ContentReader(ContentManager manager, Stream stream, GraphicsDevice graphicsDevice, string assetName, int version, Action<IDisposable> recordDisposableObject)
|
||||
: base(stream)
|
||||
{
|
||||
this.graphicsDevice = graphicsDevice;
|
||||
this.recordDisposableObject = recordDisposableObject;
|
||||
this.contentManager = manager;
|
||||
this.assetName = assetName;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public ContentManager ContentManager
|
||||
{
|
||||
get
|
||||
{
|
||||
return contentManager;
|
||||
}
|
||||
}
|
||||
|
||||
public string AssetName
|
||||
{
|
||||
get
|
||||
{
|
||||
return assetName;
|
||||
}
|
||||
}
|
||||
|
||||
internal object ReadAsset<T>()
|
||||
{
|
||||
InitializeTypeReaders();
|
||||
|
||||
// Read primary object
|
||||
object result = ReadObject<T>();
|
||||
|
||||
// Read shared resources
|
||||
ReadSharedResources();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal object ReadAsset<T>(T existingInstance)
|
||||
{
|
||||
InitializeTypeReaders();
|
||||
|
||||
// Read primary object
|
||||
object result = ReadObject<T>(existingInstance);
|
||||
|
||||
// Read shared resources
|
||||
ReadSharedResources();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void InitializeTypeReaders()
|
||||
{
|
||||
typeReaderManager = new ContentTypeReaderManager();
|
||||
typeReaders = typeReaderManager.LoadAssetReaders(this);
|
||||
sharedResourceCount = Read7BitEncodedInt();
|
||||
sharedResourceFixups = new List<KeyValuePair<int, Action<object>>>();
|
||||
}
|
||||
|
||||
internal void ReadSharedResources()
|
||||
{
|
||||
if (sharedResourceCount <= 0)
|
||||
return;
|
||||
|
||||
var sharedResources = new object[sharedResourceCount];
|
||||
for (var i = 0; i < sharedResourceCount; ++i)
|
||||
sharedResources[i] = InnerReadObject<object>(null);
|
||||
|
||||
// Fixup shared resources by calling each registered action
|
||||
foreach (var fixup in sharedResourceFixups)
|
||||
fixup.Value(sharedResources[fixup.Key]);
|
||||
}
|
||||
|
||||
public T ReadExternalReference<T>()
|
||||
{
|
||||
var externalReference = ReadString();
|
||||
|
||||
if (!String.IsNullOrEmpty(externalReference))
|
||||
{
|
||||
return contentManager.Load<T>(FileHelpers.ResolveRelativePath(assetName, externalReference));
|
||||
}
|
||||
|
||||
return default(T);
|
||||
}
|
||||
|
||||
public Matrix ReadMatrix()
|
||||
{
|
||||
Matrix result = new Matrix();
|
||||
result.M11 = ReadSingle();
|
||||
result.M12 = ReadSingle();
|
||||
result.M13 = ReadSingle();
|
||||
result.M14 = ReadSingle();
|
||||
result.M21 = ReadSingle();
|
||||
result.M22 = ReadSingle();
|
||||
result.M23 = ReadSingle();
|
||||
result.M24 = ReadSingle();
|
||||
result.M31 = ReadSingle();
|
||||
result.M32 = ReadSingle();
|
||||
result.M33 = ReadSingle();
|
||||
result.M34 = ReadSingle();
|
||||
result.M41 = ReadSingle();
|
||||
result.M42 = ReadSingle();
|
||||
result.M43 = ReadSingle();
|
||||
result.M44 = ReadSingle();
|
||||
return result;
|
||||
}
|
||||
|
||||
private void RecordDisposable<T>(T result)
|
||||
{
|
||||
var disposable = result as IDisposable;
|
||||
if (disposable == null)
|
||||
return;
|
||||
|
||||
if (recordDisposableObject != null)
|
||||
recordDisposableObject(disposable);
|
||||
else
|
||||
contentManager.RecordDisposable(disposable);
|
||||
}
|
||||
|
||||
public T ReadObject<T>()
|
||||
{
|
||||
return InnerReadObject(default(T));
|
||||
}
|
||||
|
||||
public T ReadObject<T>(ContentTypeReader typeReader)
|
||||
{
|
||||
var result = (T)typeReader.Read(this, default(T));
|
||||
RecordDisposable(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public T ReadObject<T>(T existingInstance)
|
||||
{
|
||||
return InnerReadObject(existingInstance);
|
||||
}
|
||||
|
||||
private T InnerReadObject<T>(T existingInstance)
|
||||
{
|
||||
var typeReaderIndex = Read7BitEncodedInt();
|
||||
if (typeReaderIndex == 0)
|
||||
return existingInstance;
|
||||
|
||||
if (typeReaderIndex > typeReaders.Length)
|
||||
throw new ContentLoadException("Incorrect type reader index found!");
|
||||
|
||||
var typeReader = typeReaders[typeReaderIndex - 1];
|
||||
var result = (T)typeReader.Read(this, existingInstance);
|
||||
|
||||
RecordDisposable(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public T ReadObject<T>(ContentTypeReader typeReader, T existingInstance)
|
||||
{
|
||||
if (!ReflectionHelpers.IsValueType(typeReader.TargetType))
|
||||
return ReadObject(existingInstance);
|
||||
|
||||
var result = (T)typeReader.Read(this, existingInstance);
|
||||
|
||||
RecordDisposable(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public Quaternion ReadQuaternion()
|
||||
{
|
||||
Quaternion result = new Quaternion();
|
||||
result.X = ReadSingle();
|
||||
result.Y = ReadSingle();
|
||||
result.Z = ReadSingle();
|
||||
result.W = ReadSingle();
|
||||
return result;
|
||||
}
|
||||
|
||||
public T ReadRawObject<T>()
|
||||
{
|
||||
return (T)ReadRawObject<T> (default(T));
|
||||
}
|
||||
|
||||
public T ReadRawObject<T>(ContentTypeReader typeReader)
|
||||
{
|
||||
return (T)ReadRawObject<T>(typeReader, default(T));
|
||||
}
|
||||
|
||||
public T ReadRawObject<T>(T existingInstance)
|
||||
{
|
||||
Type objectType = typeof(T);
|
||||
foreach(ContentTypeReader typeReader in typeReaders)
|
||||
{
|
||||
if(typeReader.TargetType == objectType)
|
||||
return (T)ReadRawObject<T>(typeReader,existingInstance);
|
||||
}
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public T ReadRawObject<T>(ContentTypeReader typeReader, T existingInstance)
|
||||
{
|
||||
return (T)typeReader.Read(this, existingInstance);
|
||||
}
|
||||
|
||||
public void ReadSharedResource<T>(Action<T> fixup)
|
||||
{
|
||||
int index = Read7BitEncodedInt();
|
||||
if (index > 0)
|
||||
{
|
||||
sharedResourceFixups.Add(new KeyValuePair<int, Action<object>>(index - 1, delegate(object v)
|
||||
{
|
||||
if (!(v is T))
|
||||
{
|
||||
throw new ContentLoadException(String.Format("Error loading shared resource. Expected type {0}, received type {1}", typeof(T).Name, v.GetType().Name));
|
||||
}
|
||||
fixup((T)v);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2 ReadVector2()
|
||||
{
|
||||
Vector2 result = new Vector2();
|
||||
result.X = ReadSingle();
|
||||
result.Y = ReadSingle();
|
||||
return result;
|
||||
}
|
||||
|
||||
public Vector3 ReadVector3()
|
||||
{
|
||||
Vector3 result = new Vector3();
|
||||
result.X = ReadSingle();
|
||||
result.Y = ReadSingle();
|
||||
result.Z = ReadSingle();
|
||||
return result;
|
||||
}
|
||||
|
||||
public Vector4 ReadVector4()
|
||||
{
|
||||
Vector4 result = new Vector4();
|
||||
result.X = ReadSingle();
|
||||
result.Y = ReadSingle();
|
||||
result.Z = ReadSingle();
|
||||
result.W = ReadSingle();
|
||||
return result;
|
||||
}
|
||||
|
||||
public Color ReadColor()
|
||||
{
|
||||
Color result = new Color();
|
||||
result.R = ReadByte();
|
||||
result.G = ReadByte();
|
||||
result.B = ReadByte();
|
||||
result.A = ReadByte();
|
||||
return result;
|
||||
}
|
||||
|
||||
internal new int Read7BitEncodedInt()
|
||||
{
|
||||
return base.Read7BitEncodedInt();
|
||||
}
|
||||
|
||||
internal BoundingSphere ReadBoundingSphere()
|
||||
{
|
||||
var position = ReadVector3();
|
||||
var radius = ReadSingle();
|
||||
return new BoundingSphere(position, radius);
|
||||
}
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
class AlphaTestEffectReader : ContentTypeReader<AlphaTestEffect>
|
||||
{
|
||||
protected internal override AlphaTestEffect Read(ContentReader input, AlphaTestEffect existingInstance)
|
||||
{
|
||||
var effect = new AlphaTestEffect(input.GraphicsDevice);
|
||||
|
||||
effect.Texture = input.ReadExternalReference<Texture>() as Texture2D;
|
||||
effect.AlphaFunction = (CompareFunction)input.ReadInt32();
|
||||
effect.ReferenceAlpha = (int)input.ReadUInt32();
|
||||
effect.DiffuseColor = input.ReadVector3();
|
||||
effect.Alpha = input.ReadSingle();
|
||||
effect.VertexColorEnabled = input.ReadBoolean();
|
||||
return effect;
|
||||
}
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using MonoGame.Utilities;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class ArrayReader<T> : ContentTypeReader<T[]>
|
||||
{
|
||||
ContentTypeReader elementReader;
|
||||
|
||||
public ArrayReader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override void Initialize(ContentTypeReaderManager manager)
|
||||
{
|
||||
Type readerType = typeof(T);
|
||||
elementReader = manager.GetTypeReader(readerType);
|
||||
}
|
||||
|
||||
protected internal override T[] Read(ContentReader input, T[] existingInstance)
|
||||
{
|
||||
uint count = input.ReadUInt32();
|
||||
T[] array = existingInstance;
|
||||
if (array == null)
|
||||
array = new T[count];
|
||||
|
||||
if (ReflectionHelpers.IsValueType(typeof(T)))
|
||||
{
|
||||
for (uint i = 0; i < count; i++)
|
||||
{
|
||||
array[i] = input.ReadObject<T>(elementReader);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint i = 0; i < count; i++)
|
||||
{
|
||||
var readerType = input.Read7BitEncodedInt();
|
||||
array[i] = readerType > 0 ? input.ReadObject<T>(input.TypeReaders[readerType - 1]) : default(T);
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class BasicEffectReader : ContentTypeReader<BasicEffect>
|
||||
{
|
||||
protected internal override BasicEffect Read(ContentReader input, BasicEffect existingInstance)
|
||||
{
|
||||
var effect = new BasicEffect(input.GraphicsDevice);
|
||||
var texture = input.ReadExternalReference<Texture>() as Texture2D;
|
||||
if (texture != null)
|
||||
{
|
||||
effect.Texture = texture;
|
||||
effect.TextureEnabled = true;
|
||||
}
|
||||
|
||||
effect.DiffuseColor = input.ReadVector3();
|
||||
effect.EmissiveColor = input.ReadVector3();
|
||||
effect.SpecularColor = input.ReadVector3();
|
||||
effect.SpecularPower = input.ReadSingle();
|
||||
effect.Alpha = input.ReadSingle();
|
||||
effect.VertexColorEnabled = input.ReadBoolean();
|
||||
return effect;
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class BooleanReader : ContentTypeReader<bool>
|
||||
{
|
||||
public BooleanReader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override bool Read(ContentReader input, bool existingInstance)
|
||||
{
|
||||
return input.ReadBoolean();
|
||||
}
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
class BoundingBoxReader : ContentTypeReader<BoundingBox>
|
||||
{
|
||||
protected internal override BoundingBox Read(ContentReader input, BoundingBox existingInstance)
|
||||
{
|
||||
var min = input.ReadVector3();
|
||||
var max = input.ReadVector3();
|
||||
var result = new BoundingBox(min, max);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class BoundingFrustumReader : ContentTypeReader<BoundingFrustum>
|
||||
{
|
||||
public BoundingFrustumReader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override BoundingFrustum Read(ContentReader input, BoundingFrustum existingInstance)
|
||||
{
|
||||
return new BoundingFrustum(input.ReadMatrix());
|
||||
}
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class BoundingSphereReader : ContentTypeReader<BoundingSphere>
|
||||
{
|
||||
public BoundingSphereReader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override BoundingSphere Read(ContentReader input, BoundingSphere existingInstance)
|
||||
{
|
||||
Vector3 center = input.ReadVector3();
|
||||
float radius = input.ReadSingle();
|
||||
return new BoundingSphere(center, radius);
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class ByteReader : ContentTypeReader<byte>
|
||||
{
|
||||
public ByteReader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override byte Read(ContentReader input, byte existingInstance)
|
||||
{
|
||||
return input.ReadByte();
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class CharReader : ContentTypeReader<char>
|
||||
{
|
||||
public CharReader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override char Read(ContentReader input, char existingInstance)
|
||||
{
|
||||
return input.ReadChar();
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class ColorReader : ContentTypeReader<Color>
|
||||
{
|
||||
public ColorReader ()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override Color Read (ContentReader input, Color existingInstance)
|
||||
{
|
||||
// Read RGBA as four separate bytes to make sure we comply with XNB format document
|
||||
byte r = input.ReadByte();
|
||||
byte g = input.ReadByte();
|
||||
byte b = input.ReadByte();
|
||||
byte a = input.ReadByte();
|
||||
return new Color(r, g, b, a);
|
||||
}
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class CurveReader : ContentTypeReader<Curve>
|
||||
{
|
||||
protected internal override Curve Read(ContentReader input, Curve existingInstance)
|
||||
{
|
||||
Curve curve = existingInstance;
|
||||
if (curve == null)
|
||||
{
|
||||
curve = new Curve();
|
||||
}
|
||||
|
||||
curve.PreLoop = (CurveLoopType)input.ReadInt32();
|
||||
curve.PostLoop = (CurveLoopType)input.ReadInt32();
|
||||
int num6 = input.ReadInt32();
|
||||
|
||||
for (int i = 0; i < num6; i++)
|
||||
{
|
||||
float position = input.ReadSingle();
|
||||
float num4 = input.ReadSingle();
|
||||
float tangentIn = input.ReadSingle();
|
||||
float tangentOut = input.ReadSingle();
|
||||
CurveContinuity continuity = (CurveContinuity)input.ReadInt32();
|
||||
curve.Keys.Add(new CurveKey(position, num4, tangentIn, tangentOut, continuity));
|
||||
}
|
||||
return curve;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class DateTimeReader : ContentTypeReader<DateTime>
|
||||
{
|
||||
public DateTimeReader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override DateTime Read(ContentReader input, DateTime existingInstance)
|
||||
{
|
||||
UInt64 value = input.ReadUInt64();
|
||||
UInt64 mask = (UInt64)3 << 62;
|
||||
long ticks = (long)(value & ~mask);
|
||||
DateTimeKind kind = (DateTimeKind)((value >> 62) & 3);
|
||||
return new DateTime(ticks, kind);
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class DecimalReader : ContentTypeReader<decimal>
|
||||
{
|
||||
public DecimalReader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override decimal Read(ContentReader input, decimal existingInstance)
|
||||
{
|
||||
return input.ReadDecimal();
|
||||
}
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MonoGame.Utilities;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
|
||||
internal class DictionaryReader<TKey, TValue> : ContentTypeReader<Dictionary<TKey, TValue>>
|
||||
{
|
||||
ContentTypeReader keyReader;
|
||||
ContentTypeReader valueReader;
|
||||
|
||||
Type keyType;
|
||||
Type valueType;
|
||||
|
||||
public DictionaryReader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override void Initialize(ContentTypeReaderManager manager)
|
||||
{
|
||||
keyType = typeof(TKey);
|
||||
valueType = typeof(TValue);
|
||||
|
||||
keyReader = manager.GetTypeReader(keyType);
|
||||
valueReader = manager.GetTypeReader(valueType);
|
||||
}
|
||||
|
||||
public override bool CanDeserializeIntoExistingObject
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
protected internal override Dictionary<TKey, TValue> Read(ContentReader input, Dictionary<TKey, TValue> existingInstance)
|
||||
{
|
||||
int count = input.ReadInt32();
|
||||
Dictionary<TKey, TValue> dictionary = existingInstance;
|
||||
if (dictionary == null)
|
||||
dictionary = new Dictionary<TKey, TValue>(count);
|
||||
else
|
||||
dictionary.Clear();
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
TKey key;
|
||||
TValue value;
|
||||
|
||||
if (ReflectionHelpers.IsValueType(keyType))
|
||||
{
|
||||
key = input.ReadObject<TKey>(keyReader);
|
||||
}
|
||||
else
|
||||
{
|
||||
var readerType = input.Read7BitEncodedInt();
|
||||
key = readerType > 0 ? input.ReadObject<TKey>(input.TypeReaders[readerType - 1]) : default(TKey);
|
||||
}
|
||||
|
||||
if (ReflectionHelpers.IsValueType(valueType))
|
||||
{
|
||||
value = input.ReadObject<TValue>(valueReader);
|
||||
}
|
||||
else
|
||||
{
|
||||
var readerType = input.Read7BitEncodedInt();
|
||||
value = readerType > 0 ? input.ReadObject<TValue>(input.TypeReaders[readerType - 1]) : default(TValue);
|
||||
}
|
||||
|
||||
dictionary.Add(key, value);
|
||||
}
|
||||
return dictionary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class DoubleReader : ContentTypeReader<double>
|
||||
{
|
||||
public DoubleReader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override double Read(ContentReader input, double existingInstance)
|
||||
{
|
||||
return input.ReadDouble();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
class DualTextureEffectReader : ContentTypeReader<DualTextureEffect>
|
||||
{
|
||||
protected internal override DualTextureEffect Read(ContentReader input, DualTextureEffect existingInstance)
|
||||
{
|
||||
DualTextureEffect effect = new DualTextureEffect(input.GraphicsDevice);
|
||||
effect.Texture = input.ReadExternalReference<Texture>() as Texture2D;
|
||||
effect.Texture2 = input.ReadExternalReference<Texture>() as Texture2D;
|
||||
effect.DiffuseColor = input.ReadVector3 ();
|
||||
effect.Alpha = input.ReadSingle ();
|
||||
effect.VertexColorEnabled = input.ReadBoolean ();
|
||||
return effect;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using MonoGame.Utilities;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class EffectMaterialReader : ContentTypeReader<EffectMaterial>
|
||||
{
|
||||
protected internal override EffectMaterial Read (ContentReader input, EffectMaterial existingInstance)
|
||||
{
|
||||
var effect = input.ReadExternalReference<Effect> ();
|
||||
var effectMaterial = new EffectMaterial (effect);
|
||||
|
||||
var dict = input.ReadObject<Dictionary<string, object>> ();
|
||||
|
||||
foreach (KeyValuePair<string, object> item in dict) {
|
||||
var parameter = effectMaterial.Parameters [item.Key];
|
||||
if (parameter != null) {
|
||||
|
||||
Type itemType = item.Value.GetType();
|
||||
|
||||
if (ReflectionHelpers.IsAssignableFromType(typeof(Texture), itemType)) {
|
||||
parameter.SetValue ((Texture)item.Value);
|
||||
}
|
||||
else if (ReflectionHelpers.IsAssignableFromType(typeof(int), itemType)) {
|
||||
parameter.SetValue((int) item.Value);
|
||||
}
|
||||
else if (ReflectionHelpers.IsAssignableFromType(typeof(bool), itemType)) {
|
||||
parameter.SetValue((bool) item.Value);
|
||||
}
|
||||
else if (ReflectionHelpers.IsAssignableFromType(typeof(float), itemType)) {
|
||||
parameter.SetValue((float) item.Value);
|
||||
}
|
||||
else if (ReflectionHelpers.IsAssignableFromType(typeof(float []), itemType)) {
|
||||
parameter.SetValue((float[]) item.Value);
|
||||
}
|
||||
else if (ReflectionHelpers.IsAssignableFromType(typeof(Vector2), itemType)) {
|
||||
parameter.SetValue((Vector2) item.Value);
|
||||
}
|
||||
else if (ReflectionHelpers.IsAssignableFromType(typeof(Vector2 []), itemType)) {
|
||||
parameter.SetValue((Vector2 []) item.Value);
|
||||
}
|
||||
else if (ReflectionHelpers.IsAssignableFromType(typeof(Vector3), itemType)) {
|
||||
parameter.SetValue((Vector3) item.Value);
|
||||
}
|
||||
else if (ReflectionHelpers.IsAssignableFromType(typeof(Vector3 []), itemType)) {
|
||||
parameter.SetValue((Vector3 []) item.Value);
|
||||
}
|
||||
else if (ReflectionHelpers.IsAssignableFromType(typeof(Vector4), itemType)) {
|
||||
parameter.SetValue((Vector4) item.Value);
|
||||
}
|
||||
else if (ReflectionHelpers.IsAssignableFromType(typeof(Vector4 []), itemType)) {
|
||||
parameter.SetValue((Vector4 []) item.Value);
|
||||
}
|
||||
else if (ReflectionHelpers.IsAssignableFromType(typeof(Matrix), itemType)) {
|
||||
parameter.SetValue((Matrix) item.Value);
|
||||
}
|
||||
else if (ReflectionHelpers.IsAssignableFromType(typeof(Matrix []), itemType)) {
|
||||
parameter.SetValue((Matrix[]) item.Value);
|
||||
}
|
||||
else if (ReflectionHelpers.IsAssignableFromType(typeof(Quaternion), itemType)) {
|
||||
parameter.SetValue((Quaternion) item.Value);
|
||||
}
|
||||
else {
|
||||
throw new NotSupportedException ("Parameter type is not supported");
|
||||
}
|
||||
} else {
|
||||
Debug.WriteLine ("No parameter " + item.Key);
|
||||
}
|
||||
}
|
||||
|
||||
return effectMaterial;
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class EffectReader : ContentTypeReader<Effect>
|
||||
{
|
||||
public EffectReader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override Effect Read(ContentReader input, Effect existingInstance)
|
||||
{
|
||||
int dataSize = input.ReadInt32();
|
||||
byte[] data = input.ContentManager.GetScratchBuffer(dataSize);
|
||||
input.Read(data, 0, dataSize);
|
||||
var effect = new Effect(input.GraphicsDevice, data, 0, dataSize);
|
||||
effect.Name = input.AssetName;
|
||||
return effect;
|
||||
}
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class EnumReader<T> : ContentTypeReader<T>
|
||||
{
|
||||
ContentTypeReader elementReader;
|
||||
|
||||
public EnumReader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override void Initialize(ContentTypeReaderManager manager)
|
||||
{
|
||||
Type readerType = Enum.GetUnderlyingType(typeof(T));
|
||||
elementReader = manager.GetTypeReader(readerType);
|
||||
}
|
||||
|
||||
protected internal override T Read(ContentReader input, T existingInstance)
|
||||
{
|
||||
return input.ReadRawObject<T>(elementReader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
class EnvironmentMapEffectReader : ContentTypeReader<EnvironmentMapEffect>
|
||||
{
|
||||
protected internal override EnvironmentMapEffect Read(ContentReader input, EnvironmentMapEffect existingInstance)
|
||||
{
|
||||
var effect = new EnvironmentMapEffect(input.GraphicsDevice);
|
||||
effect.Texture = input.ReadExternalReference<Texture>() as Texture2D;
|
||||
effect.EnvironmentMap = input.ReadExternalReference<TextureCube>() as TextureCube;
|
||||
effect.EnvironmentMapAmount = input.ReadSingle ();
|
||||
effect.EnvironmentMapSpecular = input.ReadVector3 ();
|
||||
effect.FresnelFactor = input.ReadSingle ();
|
||||
effect.DiffuseColor = input.ReadVector3 ();
|
||||
effect.EmissiveColor = input.ReadVector3 ();
|
||||
effect.Alpha = input.ReadSingle ();
|
||||
return effect;
|
||||
}
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
/// <summary>
|
||||
/// External reference reader, provided for compatibility with XNA Framework built content
|
||||
/// </summary>
|
||||
internal class ExternalReferenceReader : ContentTypeReader
|
||||
{
|
||||
public ExternalReferenceReader()
|
||||
: base(null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected internal override object Read(ContentReader input, object existingInstance)
|
||||
{
|
||||
return input.ReadExternalReference<object>();
|
||||
}
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
class IndexBufferReader : ContentTypeReader<IndexBuffer>
|
||||
{
|
||||
protected internal override IndexBuffer Read(ContentReader input, IndexBuffer existingInstance)
|
||||
{
|
||||
IndexBuffer indexBuffer = existingInstance;
|
||||
|
||||
bool sixteenBits = input.ReadBoolean();
|
||||
int dataSize = input.ReadInt32();
|
||||
byte[] data = input.ContentManager.GetScratchBuffer(dataSize);
|
||||
input.Read(data, 0, dataSize);
|
||||
|
||||
if (indexBuffer == null)
|
||||
{
|
||||
indexBuffer = new IndexBuffer(input.GraphicsDevice,
|
||||
sixteenBits ? IndexElementSize.SixteenBits : IndexElementSize.ThirtyTwoBits,
|
||||
dataSize / (sixteenBits ? 2 : 4), BufferUsage.None);
|
||||
}
|
||||
|
||||
indexBuffer.SetData(data, 0, dataSize);
|
||||
return indexBuffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class Int16Reader : ContentTypeReader<short>
|
||||
{
|
||||
public Int16Reader ()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override short Read (ContentReader input, short existingInstance)
|
||||
{
|
||||
return input.ReadInt16 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class Int32Reader : ContentTypeReader<int>
|
||||
{
|
||||
public Int32Reader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override int Read(ContentReader input, int existingInstance)
|
||||
{
|
||||
return input.ReadInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class Int64Reader : ContentTypeReader<long>
|
||||
{
|
||||
public Int64Reader ()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override long Read (ContentReader input, long existingInstance)
|
||||
{
|
||||
return input.ReadInt64 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using MonoGame.Utilities;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class ListReader<T> : ContentTypeReader<List<T>>
|
||||
{
|
||||
ContentTypeReader elementReader;
|
||||
|
||||
public ListReader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override void Initialize(ContentTypeReaderManager manager)
|
||||
{
|
||||
Type readerType = typeof(T);
|
||||
elementReader = manager.GetTypeReader(readerType);
|
||||
}
|
||||
|
||||
public override bool CanDeserializeIntoExistingObject
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
protected internal override List<T> Read(ContentReader input, List<T> existingInstance)
|
||||
{
|
||||
int count = input.ReadInt32();
|
||||
List<T> list = existingInstance;
|
||||
if (list == null) list = new List<T>(count);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (ReflectionHelpers.IsValueType(typeof(T)))
|
||||
{
|
||||
list.Add(input.ReadObject<T>(elementReader));
|
||||
}
|
||||
else
|
||||
{
|
||||
var readerType = input.Read7BitEncodedInt();
|
||||
list.Add(readerType > 0 ? input.ReadObject<T>(input.TypeReaders[readerType - 1]) : default(T));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
class MatrixReader : ContentTypeReader<Matrix>
|
||||
{
|
||||
protected internal override Matrix Read(ContentReader input, Matrix existingInstance)
|
||||
{
|
||||
var m11 = input.ReadSingle();
|
||||
var m12 = input.ReadSingle();
|
||||
var m13 = input.ReadSingle();
|
||||
var m14 = input.ReadSingle();
|
||||
var m21 = input.ReadSingle();
|
||||
var m22 = input.ReadSingle();
|
||||
var m23 = input.ReadSingle();
|
||||
var m24 = input.ReadSingle();
|
||||
var m31 = input.ReadSingle();
|
||||
var m32 = input.ReadSingle();
|
||||
var m33 = input.ReadSingle();
|
||||
var m34 = input.ReadSingle();
|
||||
var m41 = input.ReadSingle();
|
||||
var m42 = input.ReadSingle();
|
||||
var m43 = input.ReadSingle();
|
||||
var m44 = input.ReadSingle();
|
||||
return new Matrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44);
|
||||
}
|
||||
}
|
||||
}
|
||||
+199
@@ -0,0 +1,199 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class ModelReader : ContentTypeReader<Model>
|
||||
{
|
||||
// List<VertexBuffer> vertexBuffers = new List<VertexBuffer>();
|
||||
// List<IndexBuffer> indexBuffers = new List<IndexBuffer>();
|
||||
// List<Effect> effects = new List<Effect>();
|
||||
// List<GraphicsResource> sharedResources = new List<GraphicsResource>();
|
||||
|
||||
public ModelReader ()
|
||||
{
|
||||
}
|
||||
|
||||
static int ReadBoneReference(ContentReader reader, uint boneCount)
|
||||
{
|
||||
uint boneId;
|
||||
|
||||
// Read the bone ID, which may be encoded as either an 8 or 32 bit value.
|
||||
if (boneCount < 255)
|
||||
{
|
||||
boneId = reader.ReadByte();
|
||||
}
|
||||
else
|
||||
{
|
||||
boneId = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
// Print out the bone ID.
|
||||
if (boneId != 0)
|
||||
{
|
||||
//Debug.WriteLine("bone #{0}", boneId - 1);
|
||||
return (int)(boneId - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Debug.WriteLine("null");
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
protected internal override Model Read(ContentReader reader, Model existingInstance)
|
||||
{
|
||||
// Read the bone names and transforms.
|
||||
uint boneCount = reader.ReadUInt32();
|
||||
//Debug.WriteLine("Bone count: {0}", boneCount);
|
||||
|
||||
List<ModelBone> bones = new List<ModelBone>((int)boneCount);
|
||||
|
||||
for (uint i = 0; i < boneCount; i++)
|
||||
{
|
||||
string name = reader.ReadObject<string>();
|
||||
var matrix = reader.ReadMatrix();
|
||||
var bone = new ModelBone { Transform = matrix, Index = (int)i, Name = name };
|
||||
bones.Add(bone);
|
||||
}
|
||||
|
||||
// Read the bone hierarchy.
|
||||
for (int i = 0; i < boneCount; i++)
|
||||
{
|
||||
var bone = bones[i];
|
||||
|
||||
//Debug.WriteLine("Bone {0} hierarchy:", i);
|
||||
|
||||
// Read the parent bone reference.
|
||||
//Debug.WriteLine("Parent: ");
|
||||
var parentIndex = ReadBoneReference(reader, boneCount);
|
||||
|
||||
if (parentIndex != -1)
|
||||
{
|
||||
bone.Parent = bones[parentIndex];
|
||||
}
|
||||
|
||||
// Read the child bone references.
|
||||
uint childCount = reader.ReadUInt32();
|
||||
|
||||
if (childCount != 0)
|
||||
{
|
||||
//Debug.WriteLine("Children:");
|
||||
|
||||
for (uint j = 0; j < childCount; j++)
|
||||
{
|
||||
var childIndex = ReadBoneReference(reader, boneCount);
|
||||
if (childIndex != -1)
|
||||
{
|
||||
bone.AddChild(bones[childIndex]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<ModelMesh> meshes = new List<ModelMesh>();
|
||||
|
||||
//// Read the mesh data.
|
||||
int meshCount = reader.ReadInt32();
|
||||
//Debug.WriteLine("Mesh count: {0}", meshCount);
|
||||
|
||||
for (int i = 0; i < meshCount; i++)
|
||||
{
|
||||
|
||||
//Debug.WriteLine("Mesh {0}", i);
|
||||
string name = reader.ReadObject<string>();
|
||||
var parentBoneIndex = ReadBoneReference(reader, boneCount);
|
||||
var boundingSphere = reader.ReadBoundingSphere();
|
||||
|
||||
// Tag
|
||||
var meshTag = reader.ReadObject<object>();
|
||||
|
||||
// Read the mesh part data.
|
||||
int partCount = reader.ReadInt32();
|
||||
//Debug.WriteLine("Mesh part count: {0}", partCount);
|
||||
|
||||
List<ModelMeshPart> parts = new List<ModelMeshPart>(partCount);
|
||||
|
||||
for (uint j = 0; j < partCount; j++)
|
||||
{
|
||||
ModelMeshPart part;
|
||||
if (existingInstance != null)
|
||||
part = existingInstance.Meshes[i].MeshParts[(int)j];
|
||||
else
|
||||
part = new ModelMeshPart();
|
||||
|
||||
part.VertexOffset = reader.ReadInt32();
|
||||
part.NumVertices = reader.ReadInt32();
|
||||
part.StartIndex = reader.ReadInt32();
|
||||
part.PrimitiveCount = reader.ReadInt32();
|
||||
|
||||
// tag
|
||||
part.Tag = reader.ReadObject<object>();
|
||||
|
||||
parts.Add(part);
|
||||
|
||||
int jj = (int)j;
|
||||
reader.ReadSharedResource<VertexBuffer>(delegate (VertexBuffer v)
|
||||
{
|
||||
parts[jj].VertexBuffer = v;
|
||||
});
|
||||
reader.ReadSharedResource<IndexBuffer>(delegate (IndexBuffer v)
|
||||
{
|
||||
parts[jj].IndexBuffer = v;
|
||||
});
|
||||
reader.ReadSharedResource<Effect>(delegate (Effect v)
|
||||
{
|
||||
parts[jj].Effect = v;
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (existingInstance != null)
|
||||
continue;
|
||||
|
||||
ModelMesh mesh = new ModelMesh(reader.GraphicsDevice, parts);
|
||||
|
||||
// Tag reassignment
|
||||
mesh.Tag = meshTag;
|
||||
|
||||
mesh.Name = name;
|
||||
mesh.ParentBone = bones[parentBoneIndex];
|
||||
mesh.ParentBone.AddMesh(mesh);
|
||||
mesh.BoundingSphere = boundingSphere;
|
||||
meshes.Add(mesh);
|
||||
}
|
||||
|
||||
if (existingInstance != null)
|
||||
{
|
||||
// Read past remaining data and return existing instance
|
||||
ReadBoneReference(reader, boneCount);
|
||||
reader.ReadObject<object>();
|
||||
return existingInstance;
|
||||
}
|
||||
|
||||
// Read the final pieces of model data.
|
||||
var rootBoneIndex = ReadBoneReference(reader, boneCount);
|
||||
|
||||
Model model = new Model(reader.GraphicsDevice, bones, meshes);
|
||||
|
||||
model.Root = bones[rootBoneIndex];
|
||||
|
||||
model.BuildHierarchy();
|
||||
|
||||
// Tag?
|
||||
model.Tag = reader.ReadObject<object>();
|
||||
|
||||
return model;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using MonoGame.Utilities;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class MultiArrayReader<T> : ContentTypeReader<Array>
|
||||
{
|
||||
ContentTypeReader elementReader;
|
||||
|
||||
public MultiArrayReader() { }
|
||||
|
||||
protected internal override void Initialize(ContentTypeReaderManager manager)
|
||||
{
|
||||
Type readerType = typeof(T);
|
||||
elementReader = manager.GetTypeReader(readerType);
|
||||
}
|
||||
|
||||
protected internal override Array Read(ContentReader input, Array existingInstance)
|
||||
{
|
||||
var rank = input.ReadInt32();
|
||||
if (rank < 1)
|
||||
throw new RankException();
|
||||
|
||||
var dimensions = new int[rank];
|
||||
var count = 1;
|
||||
for (int d = 0; d < dimensions.Length; d++)
|
||||
count *= dimensions[d] = input.ReadInt32();
|
||||
|
||||
|
||||
var array = existingInstance;
|
||||
if (array == null)
|
||||
array = Array.CreateInstance(typeof(T), dimensions);//new T[count];
|
||||
else if (dimensions.Length != array.Rank)
|
||||
throw new RankException("existingInstance");
|
||||
|
||||
var indices = new int[rank];
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
T value;
|
||||
if (ReflectionHelpers.IsValueType(typeof(T)))
|
||||
value = input.ReadObject<T>(elementReader);
|
||||
else
|
||||
{
|
||||
var readerType = input.Read7BitEncodedInt();
|
||||
if (readerType > 0)
|
||||
value = input.ReadObject<T>(input.TypeReaders[readerType - 1]);
|
||||
else
|
||||
value = default(T);
|
||||
}
|
||||
|
||||
CalcIndices(array, i, indices);
|
||||
array.SetValue(value, indices);
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
static void CalcIndices(Array array, int index, int[] indices)
|
||||
{
|
||||
if (array.Rank != indices.Length)
|
||||
throw new Exception("indices");
|
||||
|
||||
for (int d = 0; d < indices.Length; d++)
|
||||
{
|
||||
if (index == 0)
|
||||
indices[d] = 0;
|
||||
else
|
||||
{
|
||||
indices[d] = index % array.GetLength(d);
|
||||
index /= array.GetLength(d);
|
||||
}
|
||||
}
|
||||
|
||||
if (index != 0)
|
||||
throw new ArgumentOutOfRangeException("index");
|
||||
}
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class NullableReader<T> : ContentTypeReader<T?> where T : struct
|
||||
{
|
||||
ContentTypeReader elementReader;
|
||||
|
||||
public NullableReader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override void Initialize(ContentTypeReaderManager manager)
|
||||
{
|
||||
Type readerType = typeof(T);
|
||||
elementReader = manager.GetTypeReader(readerType);
|
||||
}
|
||||
|
||||
protected internal override T? Read(ContentReader input, T? existingInstance)
|
||||
{
|
||||
if(input.ReadBoolean())
|
||||
return input.ReadObject<T>(elementReader);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class PlaneReader : ContentTypeReader<Plane>
|
||||
{
|
||||
public PlaneReader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override Plane Read(ContentReader input, Plane existingInstance)
|
||||
{
|
||||
existingInstance.Normal = input.ReadVector3();
|
||||
existingInstance.D = input.ReadSingle();
|
||||
return existingInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class PointReader : ContentTypeReader<Point>
|
||||
{
|
||||
public PointReader ()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override Point Read (ContentReader input, Point existingInstance)
|
||||
{
|
||||
int X = input.ReadInt32 ();
|
||||
int Y = input.ReadInt32 ();
|
||||
return new Point ( X, Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class QuaternionReader : ContentTypeReader<Quaternion>
|
||||
{
|
||||
public QuaternionReader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override Quaternion Read(ContentReader input, Quaternion existingInstance)
|
||||
{
|
||||
return input.ReadQuaternion();
|
||||
}
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class RayReader : ContentTypeReader<Ray>
|
||||
{
|
||||
public RayReader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override Ray Read(ContentReader input, Ray existingInstance)
|
||||
{
|
||||
Vector3 position = input.ReadVector3();
|
||||
Vector3 direction = input.ReadVector3();
|
||||
return new Ray(position, direction);
|
||||
}
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
|
||||
internal class RectangleReader : ContentTypeReader<Rectangle>
|
||||
{
|
||||
public RectangleReader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override Rectangle Read(ContentReader input, Rectangle existingInstance)
|
||||
{
|
||||
int left = input.ReadInt32();
|
||||
int top = input.ReadInt32();
|
||||
int width = input.ReadInt32();
|
||||
int height = input.ReadInt32();
|
||||
return new Rectangle(left, top, width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
+191
@@ -0,0 +1,191 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using MonoGame.Utilities;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class ReflectiveReader<T> : ContentTypeReader
|
||||
{
|
||||
delegate void ReadElement(ContentReader input, object parent);
|
||||
|
||||
private List<ReadElement> _readers;
|
||||
|
||||
private ConstructorInfo _constructor;
|
||||
|
||||
private ContentTypeReader _baseTypeReader;
|
||||
|
||||
|
||||
public ReflectiveReader()
|
||||
: base(typeof(T))
|
||||
{
|
||||
}
|
||||
|
||||
public override bool CanDeserializeIntoExistingObject
|
||||
{
|
||||
get { return TargetType.IsClass(); }
|
||||
}
|
||||
|
||||
protected internal override void Initialize(ContentTypeReaderManager manager)
|
||||
{
|
||||
base.Initialize(manager);
|
||||
|
||||
var baseType = ReflectionHelpers.GetBaseType(TargetType);
|
||||
if (baseType != null && baseType != typeof(object))
|
||||
_baseTypeReader = manager.GetTypeReader(baseType);
|
||||
|
||||
_constructor = TargetType.GetDefaultConstructor();
|
||||
|
||||
var properties = TargetType.GetAllProperties();
|
||||
var fields = TargetType.GetAllFields();
|
||||
_readers = new List<ReadElement>(fields.Length + properties.Length);
|
||||
|
||||
// Gather the properties.
|
||||
foreach (var property in properties)
|
||||
{
|
||||
var read = GetElementReader(manager, property);
|
||||
if (read != null)
|
||||
_readers.Add(read);
|
||||
}
|
||||
|
||||
// Gather the fields.
|
||||
foreach (var field in fields)
|
||||
{
|
||||
var read = GetElementReader(manager, field);
|
||||
if (read != null)
|
||||
_readers.Add(read);
|
||||
}
|
||||
}
|
||||
|
||||
private static ReadElement GetElementReader(ContentTypeReaderManager manager, MemberInfo member)
|
||||
{
|
||||
var property = member as PropertyInfo;
|
||||
var field = member as FieldInfo;
|
||||
Debug.Assert(field != null || property != null);
|
||||
|
||||
if (property != null)
|
||||
{
|
||||
// Properties must have at least a getter.
|
||||
if (property.CanRead == false)
|
||||
return null;
|
||||
|
||||
// Skip over indexer properties.
|
||||
if (property.GetIndexParameters().Any())
|
||||
return null;
|
||||
}
|
||||
|
||||
// Are we explicitly asked to ignore this item?
|
||||
if (ReflectionHelpers.GetCustomAttribute<ContentSerializerIgnoreAttribute>(member) != null)
|
||||
return null;
|
||||
|
||||
var contentSerializerAttribute = ReflectionHelpers.GetCustomAttribute<ContentSerializerAttribute>(member);
|
||||
if (contentSerializerAttribute == null)
|
||||
{
|
||||
if (property != null)
|
||||
{
|
||||
// There is no ContentSerializerAttribute, so non-public
|
||||
// properties cannot be deserialized.
|
||||
if (!ReflectionHelpers.PropertyIsPublic(property))
|
||||
return null;
|
||||
|
||||
// If the read-only property has a type reader,
|
||||
// and CanDeserializeIntoExistingObject is true,
|
||||
// then it is safe to deserialize into the existing object.
|
||||
if (!property.CanWrite)
|
||||
{
|
||||
var typeReader = manager.GetTypeReader(property.PropertyType);
|
||||
if (typeReader == null || !typeReader.CanDeserializeIntoExistingObject)
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// There is no ContentSerializerAttribute, so non-public
|
||||
// fields cannot be deserialized.
|
||||
if (!field.IsPublic)
|
||||
return null;
|
||||
|
||||
// evolutional: Added check to skip initialise only fields
|
||||
if (field.IsInitOnly)
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Action<object, object> setter;
|
||||
Type elementType;
|
||||
if (property != null)
|
||||
{
|
||||
elementType = property.PropertyType;
|
||||
if (property.CanWrite)
|
||||
setter = (o, v) => property.SetValue(o, v, null);
|
||||
else
|
||||
setter = (o, v) => { };
|
||||
}
|
||||
else
|
||||
{
|
||||
elementType = field.FieldType;
|
||||
setter = field.SetValue;
|
||||
}
|
||||
|
||||
// Shared resources get special treatment.
|
||||
if (contentSerializerAttribute != null && contentSerializerAttribute.SharedResource)
|
||||
{
|
||||
return (input, parent) =>
|
||||
{
|
||||
Action<object> action = value => setter(parent, value);
|
||||
input.ReadSharedResource(action);
|
||||
};
|
||||
}
|
||||
|
||||
// We need to have a reader at this point.
|
||||
var reader = manager.GetTypeReader(elementType);
|
||||
if (reader == null)
|
||||
if (elementType == typeof(System.Array))
|
||||
reader = new ArrayReader<Array>();
|
||||
else
|
||||
throw new ContentLoadException(string.Format("Content reader could not be found for {0} type.", elementType.FullName));
|
||||
|
||||
// We use the construct delegate to pick the correct existing
|
||||
// object to be the target of deserialization.
|
||||
Func<object, object> construct = parent => null;
|
||||
if (property != null && !property.CanWrite)
|
||||
construct = parent => property.GetValue(parent, null);
|
||||
|
||||
return (input, parent) =>
|
||||
{
|
||||
var existing = construct(parent);
|
||||
var obj2 = input.ReadObject(reader, existing);
|
||||
setter(parent, obj2);
|
||||
};
|
||||
}
|
||||
|
||||
protected internal override object Read(ContentReader input, object existingInstance)
|
||||
{
|
||||
T obj;
|
||||
if (existingInstance != null)
|
||||
obj = (T)existingInstance;
|
||||
else
|
||||
obj = (_constructor == null ? (T)Activator.CreateInstance(typeof(T)) : (T)_constructor.Invoke(null));
|
||||
|
||||
if(_baseTypeReader != null)
|
||||
_baseTypeReader.Read(input, obj);
|
||||
|
||||
// Box the type.
|
||||
var boxed = (object)obj;
|
||||
|
||||
foreach (var reader in _readers)
|
||||
reader(input, boxed);
|
||||
|
||||
// Unbox it... required for value types.
|
||||
obj = (T)boxed;
|
||||
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class SByteReader : ContentTypeReader<sbyte>
|
||||
{
|
||||
public SByteReader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override sbyte Read(ContentReader input, sbyte existingInstance)
|
||||
{
|
||||
return input.ReadSByte();
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class SingleReader : ContentTypeReader<float>
|
||||
{
|
||||
public SingleReader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override float Read(ContentReader input, float existingInstance)
|
||||
{
|
||||
return input.ReadSingle();
|
||||
}
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
class SkinnedEffectReader : ContentTypeReader<SkinnedEffect>
|
||||
{
|
||||
protected internal override SkinnedEffect Read(ContentReader input, SkinnedEffect existingInstance)
|
||||
{
|
||||
var effect = new SkinnedEffect(input.GraphicsDevice);
|
||||
effect.Texture = input.ReadExternalReference<Texture> () as Texture2D;
|
||||
effect.WeightsPerVertex = input.ReadInt32 ();
|
||||
effect.DiffuseColor = input.ReadVector3 ();
|
||||
effect.EmissiveColor = input.ReadVector3 ();
|
||||
effect.SpecularColor = input.ReadVector3 ();
|
||||
effect.SpecularPower = input.ReadSingle ();
|
||||
effect.Alpha = input.ReadSingle ();
|
||||
return effect;
|
||||
}
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class SpriteFontReader : ContentTypeReader<SpriteFont>
|
||||
{
|
||||
public SpriteFontReader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override SpriteFont Read(ContentReader input, SpriteFont existingInstance)
|
||||
{
|
||||
if (existingInstance != null)
|
||||
{
|
||||
// Read the texture into the existing texture instance
|
||||
input.ReadObject<Texture2D>(existingInstance.Texture);
|
||||
|
||||
// discard the rest of the SpriteFont data as we are only reloading GPU resources for now
|
||||
input.ReadObject<List<Rectangle>>();
|
||||
input.ReadObject<List<Rectangle>>();
|
||||
input.ReadObject<List<char>>();
|
||||
input.ReadInt32();
|
||||
input.ReadSingle();
|
||||
input.ReadObject<List<Vector3>>();
|
||||
if (input.ReadBoolean())
|
||||
{
|
||||
input.ReadChar();
|
||||
}
|
||||
|
||||
return existingInstance;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create a fresh SpriteFont instance
|
||||
Texture2D texture = input.ReadObject<Texture2D>();
|
||||
List<Rectangle> glyphs = input.ReadObject<List<Rectangle>>();
|
||||
List<Rectangle> cropping = input.ReadObject<List<Rectangle>>();
|
||||
List<char> charMap = input.ReadObject<List<char>>();
|
||||
int lineSpacing = input.ReadInt32();
|
||||
float spacing = input.ReadSingle();
|
||||
List<Vector3> kerning = input.ReadObject<List<Vector3>>();
|
||||
char? defaultCharacter = null;
|
||||
if (input.ReadBoolean())
|
||||
{
|
||||
defaultCharacter = new char?(input.ReadChar());
|
||||
}
|
||||
return new SpriteFont(texture, glyphs, cropping, charMap, lineSpacing, spacing, kerning, defaultCharacter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class StringReader : ContentTypeReader<String>
|
||||
{
|
||||
public StringReader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override string Read(ContentReader input, string existingInstance)
|
||||
{
|
||||
return input.ReadString();
|
||||
}
|
||||
}
|
||||
}
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using Microsoft.Xna;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class Texture2DReader : ContentTypeReader<Texture2D>
|
||||
{
|
||||
public Texture2DReader()
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
protected internal override Texture2D Read(ContentReader reader, Texture2D existingInstance)
|
||||
{
|
||||
Texture2D texture = null;
|
||||
|
||||
var surfaceFormat = (SurfaceFormat)reader.ReadInt32();
|
||||
int width = reader.ReadInt32();
|
||||
int height = reader.ReadInt32();
|
||||
int levelCount = reader.ReadInt32();
|
||||
int levelCountOutput = levelCount;
|
||||
|
||||
// If the system does not fully support Power of Two textures,
|
||||
// skip any mip maps supplied with any non PoT textures.
|
||||
if (levelCount > 1 && !reader.GraphicsDevice.GraphicsCapabilities.SupportsNonPowerOfTwo &&
|
||||
(!MathHelper.IsPowerOfTwo(width) || !MathHelper.IsPowerOfTwo(height)))
|
||||
{
|
||||
levelCountOutput = 1;
|
||||
System.Diagnostics.Debug.WriteLine(
|
||||
"Device does not support non Power of Two textures. Skipping mipmaps.");
|
||||
}
|
||||
|
||||
SurfaceFormat convertedFormat = surfaceFormat;
|
||||
switch (surfaceFormat)
|
||||
{
|
||||
case SurfaceFormat.Dxt1:
|
||||
case SurfaceFormat.Dxt1a:
|
||||
if (!reader.GraphicsDevice.GraphicsCapabilities.SupportsDxt1)
|
||||
convertedFormat = SurfaceFormat.Color;
|
||||
break;
|
||||
case SurfaceFormat.Dxt1SRgb:
|
||||
if (!reader.GraphicsDevice.GraphicsCapabilities.SupportsDxt1)
|
||||
convertedFormat = SurfaceFormat.ColorSRgb;
|
||||
break;
|
||||
case SurfaceFormat.Dxt3:
|
||||
case SurfaceFormat.Dxt5:
|
||||
if (!reader.GraphicsDevice.GraphicsCapabilities.SupportsS3tc)
|
||||
convertedFormat = SurfaceFormat.Color;
|
||||
break;
|
||||
case SurfaceFormat.Dxt3SRgb:
|
||||
case SurfaceFormat.Dxt5SRgb:
|
||||
if (!reader.GraphicsDevice.GraphicsCapabilities.SupportsS3tc)
|
||||
convertedFormat = SurfaceFormat.ColorSRgb;
|
||||
break;
|
||||
case SurfaceFormat.NormalizedByte4:
|
||||
convertedFormat = SurfaceFormat.Color;
|
||||
break;
|
||||
}
|
||||
|
||||
texture = existingInstance ?? new Texture2D(reader.GraphicsDevice, width, height, levelCountOutput > 1, convertedFormat);
|
||||
#if OPENGL
|
||||
Threading.BlockOnUIThread(() =>
|
||||
{
|
||||
#endif
|
||||
for (int level = 0; level < levelCount; level++)
|
||||
{
|
||||
var levelDataSizeInBytes = reader.ReadInt32();
|
||||
var levelData = reader.ContentManager.GetScratchBuffer(levelDataSizeInBytes);
|
||||
reader.Read(levelData, 0, levelDataSizeInBytes);
|
||||
int levelWidth = Math.Max(width >> level, 1);
|
||||
int levelHeight = Math.Max(height >> level, 1);
|
||||
|
||||
if (level >= levelCountOutput)
|
||||
continue;
|
||||
|
||||
//Convert the image data if required
|
||||
switch (surfaceFormat)
|
||||
{
|
||||
case SurfaceFormat.Dxt1:
|
||||
case SurfaceFormat.Dxt1SRgb:
|
||||
case SurfaceFormat.Dxt1a:
|
||||
if (!reader.GraphicsDevice.GraphicsCapabilities.SupportsDxt1 && convertedFormat == SurfaceFormat.Color)
|
||||
{
|
||||
levelData = DxtUtil.DecompressDxt1(levelData, levelWidth, levelHeight);
|
||||
levelDataSizeInBytes = levelData.Length;
|
||||
}
|
||||
break;
|
||||
case SurfaceFormat.Dxt3:
|
||||
case SurfaceFormat.Dxt3SRgb:
|
||||
if (!reader.GraphicsDevice.GraphicsCapabilities.SupportsS3tc)
|
||||
if (!reader.GraphicsDevice.GraphicsCapabilities.SupportsS3tc &&
|
||||
convertedFormat == SurfaceFormat.Color)
|
||||
{
|
||||
levelData = DxtUtil.DecompressDxt3(levelData, levelWidth, levelHeight);
|
||||
levelDataSizeInBytes = levelData.Length;
|
||||
}
|
||||
break;
|
||||
case SurfaceFormat.Dxt5:
|
||||
case SurfaceFormat.Dxt5SRgb:
|
||||
if (!reader.GraphicsDevice.GraphicsCapabilities.SupportsS3tc)
|
||||
if (!reader.GraphicsDevice.GraphicsCapabilities.SupportsS3tc &&
|
||||
convertedFormat == SurfaceFormat.Color)
|
||||
{
|
||||
levelData = DxtUtil.DecompressDxt5(levelData, levelWidth, levelHeight);
|
||||
levelDataSizeInBytes = levelData.Length;
|
||||
}
|
||||
break;
|
||||
case SurfaceFormat.Bgra5551:
|
||||
{
|
||||
#if OPENGL
|
||||
// Shift the channels to suit OpenGL
|
||||
int offset = 0;
|
||||
for (int y = 0; y < levelHeight; y++)
|
||||
{
|
||||
for (int x = 0; x < levelWidth; x++)
|
||||
{
|
||||
ushort pixel = BitConverter.ToUInt16(levelData, offset);
|
||||
pixel = (ushort)(((pixel & 0x7FFF) << 1) | ((pixel & 0x8000) >> 15));
|
||||
levelData[offset] = (byte)(pixel);
|
||||
levelData[offset + 1] = (byte)(pixel >> 8);
|
||||
offset += 2;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case SurfaceFormat.Bgra4444:
|
||||
{
|
||||
#if OPENGL
|
||||
// Shift the channels to suit OpenGL
|
||||
int offset = 0;
|
||||
for (int y = 0; y < levelHeight; y++)
|
||||
{
|
||||
for (int x = 0; x < levelWidth; x++)
|
||||
{
|
||||
ushort pixel = BitConverter.ToUInt16(levelData, offset);
|
||||
pixel = (ushort)(((pixel & 0x0FFF) << 4) | ((pixel & 0xF000) >> 12));
|
||||
levelData[offset] = (byte)(pixel);
|
||||
levelData[offset + 1] = (byte)(pixel >> 8);
|
||||
offset += 2;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case SurfaceFormat.NormalizedByte4:
|
||||
{
|
||||
int bytesPerPixel = surfaceFormat.GetSize();
|
||||
int pitch = levelWidth * bytesPerPixel;
|
||||
for (int y = 0; y < levelHeight; y++)
|
||||
{
|
||||
for (int x = 0; x < levelWidth; x++)
|
||||
{
|
||||
int color = BitConverter.ToInt32(levelData, y * pitch + x * bytesPerPixel);
|
||||
levelData[y * pitch + x * 4] = (byte)(((color >> 16) & 0xff)); //R:=W
|
||||
levelData[y * pitch + x * 4 + 1] = (byte)(((color >> 8) & 0xff)); //G:=V
|
||||
levelData[y * pitch + x * 4 + 2] = (byte)(((color) & 0xff)); //B:=U
|
||||
levelData[y * pitch + x * 4 + 3] = (byte)(((color >> 24) & 0xff)); //A:=Q
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
texture.SetData(level, null, levelData, 0, levelDataSizeInBytes);
|
||||
}
|
||||
#if OPENGL
|
||||
});
|
||||
#endif
|
||||
|
||||
return texture;
|
||||
}
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class Texture3DReader : ContentTypeReader<Texture3D>
|
||||
{
|
||||
protected internal override Texture3D Read(ContentReader reader, Texture3D existingInstance)
|
||||
{
|
||||
Texture3D texture = null;
|
||||
|
||||
SurfaceFormat format = (SurfaceFormat)reader.ReadInt32();
|
||||
int width = reader.ReadInt32();
|
||||
int height = reader.ReadInt32();
|
||||
int depth = reader.ReadInt32();
|
||||
int levelCount = reader.ReadInt32();
|
||||
|
||||
if (existingInstance == null)
|
||||
texture = new Texture3D(reader.GraphicsDevice, width, height, depth, levelCount > 1, format);
|
||||
else
|
||||
texture = existingInstance;
|
||||
|
||||
#if OPENGL
|
||||
Threading.BlockOnUIThread(() =>
|
||||
{
|
||||
#endif
|
||||
for (int i = 0; i < levelCount; i++)
|
||||
{
|
||||
int dataSize = reader.ReadInt32();
|
||||
byte[] data = reader.ContentManager.GetScratchBuffer(dataSize);
|
||||
reader.Read(data, 0, dataSize);
|
||||
texture.SetData(i, 0, 0, width, height, 0, depth, data, 0, dataSize);
|
||||
|
||||
// Calculate dimensions of next mip level.
|
||||
width = Math.Max(width >> 1, 1);
|
||||
height = Math.Max(height >> 1, 1);
|
||||
depth = Math.Max(depth >> 1, 1);
|
||||
}
|
||||
#if OPENGL
|
||||
});
|
||||
#endif
|
||||
|
||||
return texture;
|
||||
}
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class TextureCubeReader : ContentTypeReader<TextureCube>
|
||||
{
|
||||
|
||||
protected internal override TextureCube Read(ContentReader reader, TextureCube existingInstance)
|
||||
{
|
||||
TextureCube textureCube = null;
|
||||
|
||||
SurfaceFormat surfaceFormat = (SurfaceFormat)reader.ReadInt32();
|
||||
int size = reader.ReadInt32();
|
||||
int levels = reader.ReadInt32();
|
||||
|
||||
if (existingInstance == null)
|
||||
textureCube = new TextureCube(reader.GraphicsDevice, size, levels > 1, surfaceFormat);
|
||||
else
|
||||
textureCube = existingInstance;
|
||||
|
||||
#if OPENGL
|
||||
Threading.BlockOnUIThread(() =>
|
||||
{
|
||||
#endif
|
||||
for (int face = 0; face < 6; face++)
|
||||
{
|
||||
for (int i = 0; i < levels; i++)
|
||||
{
|
||||
int faceSize = reader.ReadInt32();
|
||||
byte[] faceData = reader.ContentManager.GetScratchBuffer(faceSize);
|
||||
reader.Read(faceData, 0, faceSize);
|
||||
textureCube.SetData<byte>((CubeMapFace)face, i, null, faceData, 0, faceSize);
|
||||
}
|
||||
}
|
||||
#if OPENGL
|
||||
});
|
||||
#endif
|
||||
|
||||
return textureCube;
|
||||
}
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class TextureReader : ContentTypeReader<Texture>
|
||||
{
|
||||
protected internal override Texture Read(ContentReader reader, Texture existingInstance)
|
||||
{
|
||||
return existingInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class TimeSpanReader : ContentTypeReader<TimeSpan>
|
||||
{
|
||||
public TimeSpanReader ()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override TimeSpan Read (ContentReader input, TimeSpan existingInstance)
|
||||
{
|
||||
// Could not find any information on this really but from all the searching it looks
|
||||
// like the constructor of number of ticks is long so I have placed that here for now
|
||||
// long is a Int64 so we read with 64
|
||||
// <Duration>PT2S</Duration>
|
||||
//
|
||||
|
||||
return new TimeSpan(input.ReadInt64 ());
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class UInt16Reader : ContentTypeReader<ushort>
|
||||
{
|
||||
public UInt16Reader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override ushort Read(ContentReader input, ushort existingInstance)
|
||||
{
|
||||
return input.ReadUInt16();
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class UInt32Reader : ContentTypeReader<uint>
|
||||
{
|
||||
public UInt32Reader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override uint Read(ContentReader input, uint existingInstance)
|
||||
{
|
||||
return input.ReadUInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class UInt64Reader : ContentTypeReader<ulong>
|
||||
{
|
||||
public UInt64Reader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override ulong Read(ContentReader input, ulong existingInstance)
|
||||
{
|
||||
return input.ReadUInt64();
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class Vector2Reader : ContentTypeReader<Vector2>
|
||||
{
|
||||
public Vector2Reader ()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override Vector2 Read (ContentReader input, Vector2 existingInstance)
|
||||
{
|
||||
return input.ReadVector2 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class Vector3Reader : ContentTypeReader<Vector3>
|
||||
{
|
||||
public Vector3Reader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override Vector3 Read(ContentReader input, Vector3 existingInstance)
|
||||
{
|
||||
return input.ReadVector3();
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class Vector4Reader : ContentTypeReader<Vector4>
|
||||
{
|
||||
public Vector4Reader()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal override Vector4 Read(ContentReader input, Vector4 existingInstance)
|
||||
{
|
||||
return input.ReadVector4();
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
class VertexBufferReader : ContentTypeReader<VertexBuffer>
|
||||
{
|
||||
protected internal override VertexBuffer Read(ContentReader input, VertexBuffer existingInstance)
|
||||
{
|
||||
var declaration = input.ReadRawObject<VertexDeclaration>();
|
||||
var vertexCount = (int)input.ReadUInt32();
|
||||
int dataSize = vertexCount * declaration.VertexStride;
|
||||
byte[] data = input.ContentManager.GetScratchBuffer(dataSize);
|
||||
input.Read(data, 0, dataSize);
|
||||
|
||||
var buffer = new VertexBuffer(input.GraphicsDevice, declaration, vertexCount, BufferUsage.None);
|
||||
buffer.SetData(data, 0, dataSize);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
internal class VertexDeclarationReader : ContentTypeReader<VertexDeclaration>
|
||||
{
|
||||
protected internal override VertexDeclaration Read(ContentReader reader, VertexDeclaration existingInstance)
|
||||
{
|
||||
var vertexStride = reader.ReadInt32();
|
||||
var elementCount = reader.ReadInt32();
|
||||
VertexElement[] elements = new VertexElement[elementCount];
|
||||
for (int i = 0; i < elementCount; ++i)
|
||||
{
|
||||
var offset = reader.ReadInt32();
|
||||
var elementFormat = (VertexElementFormat)reader.ReadInt32();
|
||||
var elementUsage = (VertexElementUsage)reader.ReadInt32();
|
||||
var usageIndex = reader.ReadInt32();
|
||||
elements[i] = new VertexElement(offset, elementFormat, elementUsage, usageIndex);
|
||||
}
|
||||
|
||||
return VertexDeclaration.GetOrCreate(vertexStride, elements);
|
||||
}
|
||||
}
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
|
||||
public sealed class ContentSerializerAttribute : Attribute
|
||||
{
|
||||
private string _collectionItemName;
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the attribute.
|
||||
/// </summary>
|
||||
public ContentSerializerAttribute()
|
||||
{
|
||||
AllowNull = true;
|
||||
}
|
||||
|
||||
public bool AllowNull { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the overriden XML element name or the default "Item".
|
||||
/// </summary>
|
||||
public string CollectionItemName
|
||||
{
|
||||
get
|
||||
{
|
||||
// Return the defaul if unset.
|
||||
if (string.IsNullOrEmpty(_collectionItemName))
|
||||
return "Item";
|
||||
|
||||
return _collectionItemName;
|
||||
}
|
||||
set
|
||||
{
|
||||
_collectionItemName = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string ElementName { get; set; }
|
||||
|
||||
public bool FlattenContent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the default CollectionItemName value was overridden.
|
||||
/// </summary>
|
||||
public bool HasCollectionItemName
|
||||
{
|
||||
get
|
||||
{
|
||||
return !string.IsNullOrEmpty(_collectionItemName);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Optional { get; set; }
|
||||
|
||||
public bool SharedResource { get; set; }
|
||||
|
||||
public ContentSerializerAttribute Clone()
|
||||
{
|
||||
var clone = new ContentSerializerAttribute ();
|
||||
clone.AllowNull = AllowNull;
|
||||
clone._collectionItemName = _collectionItemName;
|
||||
clone.ElementName = ElementName;
|
||||
clone.FlattenContent = FlattenContent;
|
||||
clone.Optional = Optional;
|
||||
clone.SharedResource = SharedResource;
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
/// <summary>
|
||||
/// This is used to specify the XML element name to use for each item in a collection.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public sealed class ContentSerializerCollectionItemNameAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an instance of the attribute.
|
||||
/// </summary>
|
||||
/// <param name="collectionItemName">The XML element name to use for each item in the collection.</param>
|
||||
public ContentSerializerCollectionItemNameAttribute(string collectionItemName)
|
||||
{
|
||||
CollectionItemName = collectionItemName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The XML element name to use for each item in the collection.
|
||||
/// </summary>
|
||||
public string CollectionItemName { get; private set;}
|
||||
}
|
||||
}
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
// #region License
|
||||
// /*
|
||||
// Microsoft Public License (Ms-PL)
|
||||
// MonoGame - Copyright © 2009 The MonoGame Team
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// This license governs use of the accompanying software. If you use the software, you accept this license. If you do not
|
||||
// accept the license, do not use the software.
|
||||
//
|
||||
// 1. Definitions
|
||||
// The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under
|
||||
// U.S. copyright law.
|
||||
//
|
||||
// A "contribution" is the original software, or any additions or changes to the software.
|
||||
// A "contributor" is any person that distributes its contribution under this license.
|
||||
// "Licensed patents" are a contributor's patent claims that read directly on its contribution.
|
||||
//
|
||||
// 2. Grant of Rights
|
||||
// (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3,
|
||||
// each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
|
||||
// (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3,
|
||||
// each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
|
||||
//
|
||||
// 3. Conditions and Limitations
|
||||
// (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
|
||||
// (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software,
|
||||
// your patent license from such contributor to the software ends automatically.
|
||||
// (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution
|
||||
// notices that are present in the software.
|
||||
// (D) If you distribute any portion of the software in source code form, you may do so only under this license by including
|
||||
// a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object
|
||||
// code form, you may only do so under a license that complies with this license.
|
||||
// (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees
|
||||
// or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent
|
||||
// permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular
|
||||
// purpose and non-infringement.
|
||||
// */
|
||||
// #endregion License
|
||||
//
|
||||
// Author: Kenneth James Pouncey
|
||||
//
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
// http://msdn.microsoft.com/en-us/library/bb195465.aspx
|
||||
// The class definition on msdn site shows: [AttributeUsageAttribute(384)]
|
||||
// The following code var ff = (AttributeTargets)384; shows that ff is Field | Property
|
||||
// so that is what we use.
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
|
||||
public sealed class ContentSerializerIgnoreAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
/// <summary>
|
||||
/// This is used to specify the type to use when deserializing this object at runtime.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class)]
|
||||
public sealed class ContentSerializerRuntimeTypeAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an instance of the attribute.
|
||||
/// </summary>
|
||||
/// <param name="runtimeType">The name of the type to use at runtime.</param>
|
||||
public ContentSerializerRuntimeTypeAttribute(string runtimeType)
|
||||
{
|
||||
RuntimeType = runtimeType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The name of the type to use at runtime.
|
||||
/// </summary>
|
||||
public string RuntimeType { get; private set;}
|
||||
}
|
||||
}
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
/// <summary>
|
||||
/// This is used to specify the version when deserializing this object at runtime.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class)]
|
||||
public sealed class ContentSerializerTypeVersionAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an instance of the attribute.
|
||||
/// </summary>
|
||||
/// <param name="typeVersion">The version passed to the type at runtime.</param>
|
||||
public ContentSerializerTypeVersionAttribute(int typeVersion)
|
||||
{
|
||||
TypeVersion = typeVersion;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The version passed to the type at runtime.
|
||||
/// </summary>
|
||||
public int TypeVersion { get; private set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
public abstract class ContentTypeReader
|
||||
{
|
||||
private Type _targetType;
|
||||
|
||||
public virtual bool CanDeserializeIntoExistingObject
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public Type TargetType
|
||||
{
|
||||
get { return _targetType; }
|
||||
}
|
||||
|
||||
public virtual int TypeVersion
|
||||
{
|
||||
get { return 0; } // The default version (unless overridden) is zero
|
||||
}
|
||||
|
||||
protected ContentTypeReader(Type targetType)
|
||||
{
|
||||
_targetType = targetType;
|
||||
}
|
||||
|
||||
protected internal virtual void Initialize(ContentTypeReaderManager manager)
|
||||
{
|
||||
// Do nothing. Are we supposed to add ourselves to the manager?
|
||||
}
|
||||
|
||||
protected internal abstract object Read(ContentReader input, object existingInstance);
|
||||
}
|
||||
|
||||
public abstract class ContentTypeReader<T> : ContentTypeReader
|
||||
{
|
||||
protected ContentTypeReader()
|
||||
: base(typeof(T))
|
||||
{
|
||||
// Nothing
|
||||
}
|
||||
|
||||
protected internal override object Read(ContentReader input, object existingInstance)
|
||||
{
|
||||
// as per the documentation http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.content.contenttypereader.read.aspx
|
||||
// existingInstance
|
||||
// The object receiving the data, or null if a new instance of the object should be created.
|
||||
if (existingInstance == null)
|
||||
{
|
||||
return Read(input, default(T));
|
||||
}
|
||||
return Read(input, (T)existingInstance);
|
||||
}
|
||||
|
||||
protected internal abstract T Read(ContentReader input, T existingInstance);
|
||||
}
|
||||
}
|
||||
+247
@@ -0,0 +1,247 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Collections.Generic;
|
||||
using MonoGame.Utilities;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
public sealed class ContentTypeReaderManager
|
||||
{
|
||||
private static readonly object _locker;
|
||||
|
||||
private static readonly Dictionary<Type, ContentTypeReader> _contentReadersCache;
|
||||
|
||||
private Dictionary<Type, ContentTypeReader> _contentReaders;
|
||||
|
||||
private static readonly string _assemblyName;
|
||||
|
||||
|
||||
static ContentTypeReaderManager()
|
||||
{
|
||||
_locker = new object();
|
||||
_contentReadersCache = new Dictionary<Type, ContentTypeReader>(255);
|
||||
_assemblyName = ReflectionHelpers.GetAssembly(typeof(ContentTypeReaderManager)).FullName;
|
||||
}
|
||||
|
||||
public ContentTypeReader GetTypeReader(Type targetType)
|
||||
{
|
||||
if (targetType.IsArray && targetType.GetArrayRank() > 1)
|
||||
targetType = typeof(Array);
|
||||
|
||||
ContentTypeReader reader;
|
||||
if (_contentReaders.TryGetValue(targetType, out reader))
|
||||
return reader;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Trick to prevent the linker removing the code, but not actually execute the code
|
||||
static bool falseflag = false;
|
||||
|
||||
internal ContentTypeReader[] LoadAssetReaders(ContentReader reader)
|
||||
{
|
||||
#pragma warning disable 0219, 0649
|
||||
// Trick to prevent the linker removing the code, but not actually execute the code
|
||||
if (falseflag)
|
||||
{
|
||||
// Dummy variables required for it to work on iDevices ** DO NOT DELETE **
|
||||
// This forces the classes not to be optimized out when deploying to iDevices
|
||||
var hByteReader = new ByteReader();
|
||||
var hSByteReader = new SByteReader();
|
||||
var hDateTimeReader = new DateTimeReader();
|
||||
var hDecimalReader = new DecimalReader();
|
||||
var hBoundingSphereReader = new BoundingSphereReader();
|
||||
var hBoundingFrustumReader = new BoundingFrustumReader();
|
||||
var hRayReader = new RayReader();
|
||||
var hCharListReader = new ListReader<Char>();
|
||||
var hRectangleListReader = new ListReader<Rectangle>();
|
||||
var hRectangleArrayReader = new ArrayReader<Rectangle>();
|
||||
var hVector3ListReader = new ListReader<Vector3>();
|
||||
var hStringListReader = new ListReader<StringReader>();
|
||||
var hIntListReader = new ListReader<Int32>();
|
||||
var hSpriteFontReader = new SpriteFontReader();
|
||||
var hTexture2DReader = new Texture2DReader();
|
||||
var hCharReader = new CharReader();
|
||||
var hRectangleReader = new RectangleReader();
|
||||
var hStringReader = new StringReader();
|
||||
var hVector2Reader = new Vector2Reader();
|
||||
var hVector3Reader = new Vector3Reader();
|
||||
var hVector4Reader = new Vector4Reader();
|
||||
var hCurveReader = new CurveReader();
|
||||
var hIndexBufferReader = new IndexBufferReader();
|
||||
var hBoundingBoxReader = new BoundingBoxReader();
|
||||
var hMatrixReader = new MatrixReader();
|
||||
var hBasicEffectReader = new BasicEffectReader();
|
||||
var hVertexBufferReader = new VertexBufferReader();
|
||||
var hAlphaTestEffectReader = new AlphaTestEffectReader();
|
||||
var hEnumSpriteEffectsReader = new EnumReader<Graphics.SpriteEffects>();
|
||||
var hArrayFloatReader = new ArrayReader<float>();
|
||||
var hArrayVector2Reader = new ArrayReader<Vector2>();
|
||||
var hListVector2Reader = new ListReader<Vector2>();
|
||||
var hArrayMatrixReader = new ArrayReader<Matrix>();
|
||||
var hEnumBlendReader = new EnumReader<Graphics.Blend>();
|
||||
var hNullableRectReader = new NullableReader<Rectangle>();
|
||||
var hEffectMaterialReader = new EffectMaterialReader();
|
||||
var hExternalReferenceReader = new ExternalReferenceReader();
|
||||
var hModelReader = new ModelReader();
|
||||
var hInt32Reader = new Int32Reader();
|
||||
var hEffectReader = new EffectReader();
|
||||
var hSingleReader = new SingleReader();
|
||||
}
|
||||
#pragma warning restore 0219, 0649
|
||||
|
||||
// The first content byte i read tells me the number of content readers in this XNB file
|
||||
var numberOfReaders = reader.Read7BitEncodedInt();
|
||||
var contentReaders = new ContentTypeReader[numberOfReaders];
|
||||
var needsInitialize = new BitArray(numberOfReaders);
|
||||
_contentReaders = new Dictionary<Type, ContentTypeReader>(numberOfReaders);
|
||||
|
||||
// Lock until we're done allocating and initializing any new
|
||||
// content type readers... this ensures we can load content
|
||||
// from multiple threads and still cache the readers.
|
||||
lock (_locker)
|
||||
{
|
||||
// For each reader in the file, we read out the length of the string which contains the type of the reader,
|
||||
// then we read out the string. Finally we instantiate an instance of that reader using reflection
|
||||
for (var i = 0; i < numberOfReaders; i++)
|
||||
{
|
||||
// This string tells us what reader we need to decode the following data
|
||||
// string readerTypeString = reader.ReadString();
|
||||
string originalReaderTypeString = reader.ReadString();
|
||||
|
||||
Func<ContentTypeReader> readerFunc;
|
||||
if (typeCreators.TryGetValue(originalReaderTypeString, out readerFunc))
|
||||
{
|
||||
contentReaders[i] = readerFunc();
|
||||
needsInitialize[i] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//System.Diagnostics.Debug.WriteLine(originalReaderTypeString);
|
||||
|
||||
// Need to resolve namespace differences
|
||||
string readerTypeString = originalReaderTypeString;
|
||||
|
||||
readerTypeString = PrepareType(readerTypeString);
|
||||
|
||||
var l_readerType = Type.GetType(readerTypeString);
|
||||
if (l_readerType != null)
|
||||
{
|
||||
ContentTypeReader typeReader;
|
||||
if (!_contentReadersCache.TryGetValue(l_readerType, out typeReader))
|
||||
{
|
||||
try
|
||||
{
|
||||
typeReader = l_readerType.GetDefaultConstructor().Invoke(null) as ContentTypeReader;
|
||||
}
|
||||
catch (TargetInvocationException ex)
|
||||
{
|
||||
// If you are getting here, the Mono runtime is most likely not able to JIT the type.
|
||||
// In particular, MonoTouch needs help instantiating types that are only defined in strings in Xnb files.
|
||||
throw new InvalidOperationException(
|
||||
"Failed to get default constructor for ContentTypeReader. To work around, add a creation function to ContentTypeReaderManager.AddTypeCreator() " +
|
||||
"with the following failed type string: " + originalReaderTypeString, ex);
|
||||
}
|
||||
|
||||
needsInitialize[i] = true;
|
||||
|
||||
_contentReadersCache.Add(l_readerType, typeReader);
|
||||
}
|
||||
|
||||
contentReaders[i] = typeReader;
|
||||
}
|
||||
else
|
||||
throw new ContentLoadException(
|
||||
"Could not find ContentTypeReader Type. Please ensure the name of the Assembly that contains the Type matches the assembly in the full type name: " +
|
||||
originalReaderTypeString + " (" + readerTypeString + ")");
|
||||
}
|
||||
|
||||
var targetType = contentReaders[i].TargetType;
|
||||
if (targetType != null)
|
||||
if (!_contentReaders.ContainsKey(targetType))
|
||||
_contentReaders.Add(targetType, contentReaders[i]);
|
||||
|
||||
// I think the next 4 bytes refer to the "Version" of the type reader,
|
||||
// although it always seems to be zero
|
||||
reader.ReadInt32();
|
||||
}
|
||||
|
||||
// Initialize any new readers.
|
||||
for (var i = 0; i < contentReaders.Length; i++)
|
||||
{
|
||||
if (needsInitialize.Get(i))
|
||||
contentReaders[i].Initialize(this);
|
||||
}
|
||||
|
||||
} // lock (_locker)
|
||||
|
||||
return contentReaders;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes Version, Culture and PublicKeyToken from a type string.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Supports multiple generic types (e.g. Dictionary<TKey,TValue>) and nested generic types (e.g. List<List<int>>).
|
||||
/// </remarks>
|
||||
/// <param name="type">
|
||||
/// A <see cref="System.String"/>
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="System.String"/>
|
||||
/// </returns>
|
||||
public static string PrepareType(string type)
|
||||
{
|
||||
//Needed to support nested types
|
||||
int count = type.Split(new[] {"[["}, StringSplitOptions.None).Length - 1;
|
||||
|
||||
string preparedType = type;
|
||||
|
||||
for(int i=0; i<count; i++)
|
||||
{
|
||||
preparedType = Regex.Replace(preparedType, @"\[(.+?), Version=.+?\]", "[$1]");
|
||||
}
|
||||
|
||||
//Handle non generic types
|
||||
if(preparedType.Contains("PublicKeyToken"))
|
||||
preparedType = Regex.Replace(preparedType, @"(.+?), Version=.+?$", "$1");
|
||||
|
||||
// TODO: For WinRT this is most likely broken!
|
||||
preparedType = preparedType.Replace(", Microsoft.Xna.Framework.Graphics", string.Format(", {0}", _assemblyName));
|
||||
preparedType = preparedType.Replace(", Microsoft.Xna.Framework.Video", string.Format(", {0}", _assemblyName));
|
||||
preparedType = preparedType.Replace(", Microsoft.Xna.Framework", string.Format(", {0}", _assemblyName));
|
||||
|
||||
return preparedType;
|
||||
}
|
||||
|
||||
// Static map of type names to creation functions. Required as iOS requires all types at compile time
|
||||
private static Dictionary<string, Func<ContentTypeReader>> typeCreators = new Dictionary<string, Func<ContentTypeReader>>();
|
||||
|
||||
/// <summary>
|
||||
/// Adds the type creator.
|
||||
/// </summary>
|
||||
/// <param name='typeString'>
|
||||
/// Type string.
|
||||
/// </param>
|
||||
/// <param name='createFunction'>
|
||||
/// Create function.
|
||||
/// </param>
|
||||
public static void AddTypeCreator(string typeString, Func<ContentTypeReader> createFunction)
|
||||
{
|
||||
if (!typeCreators.ContainsKey(typeString))
|
||||
typeCreators.Add(typeString, createFunction);
|
||||
}
|
||||
|
||||
public static void ClearTypeCreators()
|
||||
{
|
||||
typeCreators.Clear();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,780 @@
|
||||
#region HEADER
|
||||
/* This file was derived from libmspack
|
||||
* (C) 2003-2004 Stuart Caie.
|
||||
* (C) 2011 Ali Scissons.
|
||||
*
|
||||
* The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted
|
||||
* by Microsoft Corporation.
|
||||
*
|
||||
* This source file is Dual licensed; meaning the end-user of this source file
|
||||
* may redistribute/modify it under the LGPL 2.1 or MS-PL licenses.
|
||||
*/
|
||||
#region LGPL License
|
||||
/* GNU LESSER GENERAL PUBLIC LICENSE version 2.1
|
||||
* LzxDecoder is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||
*/
|
||||
#endregion
|
||||
#region MS-PL License
|
||||
/*
|
||||
* MICROSOFT PUBLIC LICENSE
|
||||
* This source code is subject to the terms of the Microsoft Public License (Ms-PL).
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* is permitted provided that redistributions of the source code retain the above
|
||||
* copyright notices and this file header.
|
||||
*
|
||||
* Additional copyright notices should be appended to the list above.
|
||||
*
|
||||
* For details, see <http://www.opensource.org/licenses/ms-pl.html>.
|
||||
*/
|
||||
#endregion
|
||||
/*
|
||||
* This derived work is recognized by Stuart Caie and is authorized to adapt
|
||||
* any changes made to lzxd.c in his libmspack library and will still retain
|
||||
* this dual licensing scheme. Big thanks to Stuart Caie!
|
||||
*
|
||||
* DETAILS
|
||||
* This file is a pure C# port of the lzxd.c file from libmspack, with minor
|
||||
* changes towards the decompression of XNB files. The original decompression
|
||||
* software of LZX encoded data was written by Suart Caie in his
|
||||
* libmspack/cabextract projects, which can be located at
|
||||
* http://http://www.cabextract.org.uk/
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
using System.IO;
|
||||
|
||||
class LzxDecoder
|
||||
{
|
||||
public static uint[] position_base = null;
|
||||
public static byte[] extra_bits = null;
|
||||
|
||||
private LzxState m_state;
|
||||
|
||||
public LzxDecoder (int window)
|
||||
{
|
||||
uint wndsize = (uint)(1 << window);
|
||||
int posn_slots;
|
||||
|
||||
// setup proper exception
|
||||
if(window < 15 || window > 21) throw new UnsupportedWindowSizeRange();
|
||||
|
||||
// let's initialise our state
|
||||
m_state = new LzxState();
|
||||
m_state.actual_size = 0;
|
||||
m_state.window = new byte[wndsize];
|
||||
for(int i = 0; i < wndsize; i++) m_state.window[i] = 0xDC;
|
||||
m_state.actual_size = wndsize;
|
||||
m_state.window_size = wndsize;
|
||||
m_state.window_posn = 0;
|
||||
|
||||
/* initialize static tables */
|
||||
if(extra_bits == null)
|
||||
{
|
||||
extra_bits = new byte[52];
|
||||
for(int i = 0, j = 0; i <= 50; i += 2)
|
||||
{
|
||||
extra_bits[i] = extra_bits[i+1] = (byte)j;
|
||||
if ((i != 0) && (j < 17)) j++;
|
||||
}
|
||||
}
|
||||
if(position_base == null)
|
||||
{
|
||||
position_base = new uint[51];
|
||||
for(int i = 0, j = 0; i <= 50; i++)
|
||||
{
|
||||
position_base[i] = (uint)j;
|
||||
j += 1 << extra_bits[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* calculate required position slots */
|
||||
if(window == 20) posn_slots = 42;
|
||||
else if(window == 21) posn_slots = 50;
|
||||
else posn_slots = window << 1;
|
||||
|
||||
m_state.R0 = m_state.R1 = m_state.R2 = 1;
|
||||
m_state.main_elements = (ushort)(LzxConstants.NUM_CHARS + (posn_slots << 3));
|
||||
m_state.header_read = 0;
|
||||
m_state.frames_read = 0;
|
||||
m_state.block_remaining = 0;
|
||||
m_state.block_type = LzxConstants.BLOCKTYPE.INVALID;
|
||||
m_state.intel_curpos = 0;
|
||||
m_state.intel_started = 0;
|
||||
|
||||
// yo dawg i herd u liek arrays so we put arrays in ur arrays so u can array while u array
|
||||
m_state.PRETREE_table = new ushort[(1 << LzxConstants.PRETREE_TABLEBITS) + (LzxConstants.PRETREE_MAXSYMBOLS << 1)];
|
||||
m_state.PRETREE_len = new byte[LzxConstants.PRETREE_MAXSYMBOLS + LzxConstants.LENTABLE_SAFETY];
|
||||
m_state.MAINTREE_table = new ushort[(1 << LzxConstants.MAINTREE_TABLEBITS) + (LzxConstants.MAINTREE_MAXSYMBOLS << 1)];
|
||||
m_state.MAINTREE_len = new byte[LzxConstants.MAINTREE_MAXSYMBOLS + LzxConstants.LENTABLE_SAFETY];
|
||||
m_state.LENGTH_table = new ushort[(1 << LzxConstants.LENGTH_TABLEBITS) + (LzxConstants.LENGTH_MAXSYMBOLS << 1)];
|
||||
m_state.LENGTH_len = new byte[LzxConstants.LENGTH_MAXSYMBOLS + LzxConstants.LENTABLE_SAFETY];
|
||||
m_state.ALIGNED_table = new ushort[(1 << LzxConstants.ALIGNED_TABLEBITS) + (LzxConstants.ALIGNED_MAXSYMBOLS << 1)];
|
||||
m_state.ALIGNED_len = new byte[LzxConstants.ALIGNED_MAXSYMBOLS + LzxConstants.LENTABLE_SAFETY];
|
||||
/* initialise tables to 0 (because deltas will be applied to them) */
|
||||
for(int i = 0; i < LzxConstants.MAINTREE_MAXSYMBOLS; i++) m_state.MAINTREE_len[i] = 0;
|
||||
for(int i = 0; i < LzxConstants.LENGTH_MAXSYMBOLS; i++) m_state.LENGTH_len[i] = 0;
|
||||
}
|
||||
|
||||
public int Decompress(Stream inData, int inLen, Stream outData, int outLen)
|
||||
{
|
||||
BitBuffer bitbuf = new BitBuffer(inData);
|
||||
long startpos = inData.Position;
|
||||
long endpos = inData.Position + inLen;
|
||||
|
||||
byte[] window = m_state.window;
|
||||
|
||||
uint window_posn = m_state.window_posn;
|
||||
uint window_size = m_state.window_size;
|
||||
uint R0 = m_state.R0;
|
||||
uint R1 = m_state.R1;
|
||||
uint R2 = m_state.R2;
|
||||
uint i, j;
|
||||
|
||||
int togo = outLen, this_run, main_element, match_length, match_offset, length_footer, extra, verbatim_bits;
|
||||
int rundest, runsrc, copy_length, aligned_bits;
|
||||
|
||||
bitbuf.InitBitStream();
|
||||
|
||||
/* read header if necessary */
|
||||
if(m_state.header_read == 0)
|
||||
{
|
||||
uint intel = bitbuf.ReadBits(1);
|
||||
if(intel != 0)
|
||||
{
|
||||
// read the filesize
|
||||
i = bitbuf.ReadBits(16); j = bitbuf.ReadBits(16);
|
||||
m_state.intel_filesize = (int)((i << 16) | j);
|
||||
}
|
||||
m_state.header_read = 1;
|
||||
}
|
||||
|
||||
/* main decoding loop */
|
||||
while(togo > 0)
|
||||
{
|
||||
/* last block finished, new block expected */
|
||||
if(m_state.block_remaining == 0)
|
||||
{
|
||||
// TODO may screw something up here
|
||||
if(m_state.block_type == LzxConstants.BLOCKTYPE.UNCOMPRESSED) {
|
||||
if((m_state.block_length & 1) == 1) inData.ReadByte(); /* realign bitstream to word */
|
||||
bitbuf.InitBitStream();
|
||||
}
|
||||
|
||||
m_state.block_type = (LzxConstants.BLOCKTYPE)bitbuf.ReadBits(3);;
|
||||
i = bitbuf.ReadBits(16);
|
||||
j = bitbuf.ReadBits(8);
|
||||
m_state.block_remaining = m_state.block_length = (uint)((i << 8) | j);
|
||||
|
||||
switch(m_state.block_type)
|
||||
{
|
||||
case LzxConstants.BLOCKTYPE.ALIGNED:
|
||||
for(i = 0, j = 0; i < 8; i++) { j = bitbuf.ReadBits(3); m_state.ALIGNED_len[i] = (byte)j; }
|
||||
MakeDecodeTable(LzxConstants.ALIGNED_MAXSYMBOLS, LzxConstants.ALIGNED_TABLEBITS,
|
||||
m_state.ALIGNED_len, m_state.ALIGNED_table);
|
||||
/* rest of aligned header is same as verbatim */
|
||||
goto case LzxConstants.BLOCKTYPE.VERBATIM;
|
||||
|
||||
case LzxConstants.BLOCKTYPE.VERBATIM:
|
||||
ReadLengths(m_state.MAINTREE_len, 0, 256, bitbuf);
|
||||
ReadLengths(m_state.MAINTREE_len, 256, m_state.main_elements, bitbuf);
|
||||
MakeDecodeTable(LzxConstants.MAINTREE_MAXSYMBOLS, LzxConstants.MAINTREE_TABLEBITS,
|
||||
m_state.MAINTREE_len, m_state.MAINTREE_table);
|
||||
if(m_state.MAINTREE_len[0xE8] != 0) m_state.intel_started = 1;
|
||||
|
||||
ReadLengths(m_state.LENGTH_len, 0, LzxConstants.NUM_SECONDARY_LENGTHS, bitbuf);
|
||||
MakeDecodeTable(LzxConstants.LENGTH_MAXSYMBOLS, LzxConstants.LENGTH_TABLEBITS,
|
||||
m_state.LENGTH_len, m_state.LENGTH_table);
|
||||
break;
|
||||
|
||||
case LzxConstants.BLOCKTYPE.UNCOMPRESSED:
|
||||
m_state.intel_started = 1; /* because we can't assume otherwise */
|
||||
bitbuf.EnsureBits(16); /* get up to 16 pad bits into the buffer */
|
||||
if(bitbuf.GetBitsLeft() > 16) inData.Seek(-2, SeekOrigin.Current); /* and align the bitstream! */
|
||||
byte hi, mh, ml, lo;
|
||||
lo = (byte)inData.ReadByte(); ml = (byte)inData.ReadByte(); mh = (byte)inData.ReadByte(); hi = (byte)inData.ReadByte();
|
||||
R0 = (uint)(lo | ml << 8 | mh << 16 | hi << 24);
|
||||
lo = (byte)inData.ReadByte(); ml = (byte)inData.ReadByte(); mh = (byte)inData.ReadByte(); hi = (byte)inData.ReadByte();
|
||||
R1 = (uint)(lo | ml << 8 | mh << 16 | hi << 24);
|
||||
lo = (byte)inData.ReadByte(); ml = (byte)inData.ReadByte(); mh = (byte)inData.ReadByte(); hi = (byte)inData.ReadByte();
|
||||
R2 = (uint)(lo | ml << 8 | mh << 16 | hi << 24);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1; // TODO throw proper exception
|
||||
}
|
||||
}
|
||||
|
||||
/* buffer exhaustion check */
|
||||
if(inData.Position > (startpos + inLen))
|
||||
{
|
||||
/* it's possible to have a file where the next run is less than
|
||||
* 16 bits in size. In this case, the READ_HUFFSYM() macro used
|
||||
* in building the tables will exhaust the buffer, so we should
|
||||
* allow for this, but not allow those accidentally read bits to
|
||||
* be used (so we check that there are at least 16 bits
|
||||
* remaining - in this boundary case they aren't really part of
|
||||
* the compressed data)
|
||||
*/
|
||||
//Debug.WriteLine("WTF");
|
||||
|
||||
if(inData.Position > (startpos+inLen+2) || bitbuf.GetBitsLeft() < 16) return -1; //TODO throw proper exception
|
||||
}
|
||||
|
||||
while((this_run = (int)m_state.block_remaining) > 0 && togo > 0)
|
||||
{
|
||||
if(this_run > togo) this_run = togo;
|
||||
togo -= this_run;
|
||||
m_state.block_remaining -= (uint)this_run;
|
||||
|
||||
/* apply 2^x-1 mask */
|
||||
window_posn &= window_size - 1;
|
||||
/* runs can't straddle the window wraparound */
|
||||
if((window_posn + this_run) > window_size)
|
||||
return -1; //TODO throw proper exception
|
||||
|
||||
switch(m_state.block_type)
|
||||
{
|
||||
case LzxConstants.BLOCKTYPE.VERBATIM:
|
||||
while(this_run > 0)
|
||||
{
|
||||
main_element = (int)ReadHuffSym(m_state.MAINTREE_table, m_state.MAINTREE_len,
|
||||
LzxConstants.MAINTREE_MAXSYMBOLS, LzxConstants.MAINTREE_TABLEBITS,
|
||||
bitbuf);
|
||||
if(main_element < LzxConstants.NUM_CHARS)
|
||||
{
|
||||
/* literal: 0 to NUM_CHARS-1 */
|
||||
window[window_posn++] = (byte)main_element;
|
||||
this_run--;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* match: NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
|
||||
main_element -= LzxConstants.NUM_CHARS;
|
||||
|
||||
match_length = main_element & LzxConstants.NUM_PRIMARY_LENGTHS;
|
||||
if(match_length == LzxConstants.NUM_PRIMARY_LENGTHS)
|
||||
{
|
||||
length_footer = (int)ReadHuffSym(m_state.LENGTH_table, m_state.LENGTH_len,
|
||||
LzxConstants.LENGTH_MAXSYMBOLS, LzxConstants.LENGTH_TABLEBITS,
|
||||
bitbuf);
|
||||
match_length += length_footer;
|
||||
}
|
||||
match_length += LzxConstants.MIN_MATCH;
|
||||
|
||||
match_offset = main_element >> 3;
|
||||
|
||||
if(match_offset > 2)
|
||||
{
|
||||
/* not repeated offset */
|
||||
if(match_offset != 3)
|
||||
{
|
||||
extra = extra_bits[match_offset];
|
||||
verbatim_bits = (int)bitbuf.ReadBits((byte)extra);
|
||||
match_offset = (int)position_base[match_offset] - 2 + verbatim_bits;
|
||||
}
|
||||
else
|
||||
{
|
||||
match_offset = 1;
|
||||
}
|
||||
|
||||
/* update repeated offset LRU queue */
|
||||
R2 = R1; R1 = R0; R0 = (uint)match_offset;
|
||||
}
|
||||
else if(match_offset == 0)
|
||||
{
|
||||
match_offset = (int)R0;
|
||||
}
|
||||
else if(match_offset == 1)
|
||||
{
|
||||
match_offset = (int)R1;
|
||||
R1 = R0; R0 = (uint)match_offset;
|
||||
}
|
||||
else /* match_offset == 2 */
|
||||
{
|
||||
match_offset = (int)R2;
|
||||
R2 = R0; R0 = (uint)match_offset;
|
||||
}
|
||||
|
||||
rundest = (int)window_posn;
|
||||
this_run -= match_length;
|
||||
|
||||
/* copy any wrapped around source data */
|
||||
if(window_posn >= match_offset)
|
||||
{
|
||||
/* no wrap */
|
||||
runsrc = rundest - match_offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
runsrc = rundest + ((int)window_size - match_offset);
|
||||
copy_length = match_offset - (int)window_posn;
|
||||
if(copy_length < match_length)
|
||||
{
|
||||
match_length -= copy_length;
|
||||
window_posn += (uint)copy_length;
|
||||
while(copy_length-- > 0) window[rundest++] = window[runsrc++];
|
||||
runsrc = 0;
|
||||
}
|
||||
}
|
||||
window_posn += (uint)match_length;
|
||||
|
||||
/* copy match data - no worries about destination wraps */
|
||||
while(match_length-- > 0) window[rundest++] = window[runsrc++];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LzxConstants.BLOCKTYPE.ALIGNED:
|
||||
while(this_run > 0)
|
||||
{
|
||||
main_element = (int)ReadHuffSym(m_state.MAINTREE_table, m_state.MAINTREE_len,
|
||||
LzxConstants.MAINTREE_MAXSYMBOLS, LzxConstants.MAINTREE_TABLEBITS,
|
||||
bitbuf);
|
||||
|
||||
if(main_element < LzxConstants.NUM_CHARS)
|
||||
{
|
||||
/* literal 0 to NUM_CHARS-1 */
|
||||
window[window_posn++] = (byte)main_element;
|
||||
this_run--;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* match: NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
|
||||
main_element -= LzxConstants.NUM_CHARS;
|
||||
|
||||
match_length = main_element & LzxConstants.NUM_PRIMARY_LENGTHS;
|
||||
if(match_length == LzxConstants.NUM_PRIMARY_LENGTHS)
|
||||
{
|
||||
length_footer = (int)ReadHuffSym(m_state.LENGTH_table, m_state.LENGTH_len,
|
||||
LzxConstants.LENGTH_MAXSYMBOLS, LzxConstants.LENGTH_TABLEBITS,
|
||||
bitbuf);
|
||||
match_length += length_footer;
|
||||
}
|
||||
match_length += LzxConstants.MIN_MATCH;
|
||||
|
||||
match_offset = main_element >> 3;
|
||||
|
||||
if(match_offset > 2)
|
||||
{
|
||||
/* not repeated offset */
|
||||
extra = extra_bits[match_offset];
|
||||
match_offset = (int)position_base[match_offset] - 2;
|
||||
if(extra > 3)
|
||||
{
|
||||
/* verbatim and aligned bits */
|
||||
extra -= 3;
|
||||
verbatim_bits = (int)bitbuf.ReadBits((byte)extra);
|
||||
match_offset += (verbatim_bits << 3);
|
||||
aligned_bits = (int)ReadHuffSym(m_state.ALIGNED_table, m_state.ALIGNED_len,
|
||||
LzxConstants.ALIGNED_MAXSYMBOLS, LzxConstants.ALIGNED_TABLEBITS,
|
||||
bitbuf);
|
||||
match_offset += aligned_bits;
|
||||
}
|
||||
else if(extra == 3)
|
||||
{
|
||||
/* aligned bits only */
|
||||
aligned_bits = (int)ReadHuffSym(m_state.ALIGNED_table, m_state.ALIGNED_len,
|
||||
LzxConstants.ALIGNED_MAXSYMBOLS, LzxConstants.ALIGNED_TABLEBITS,
|
||||
bitbuf);
|
||||
match_offset += aligned_bits;
|
||||
}
|
||||
else if (extra > 0) /* extra==1, extra==2 */
|
||||
{
|
||||
/* verbatim bits only */
|
||||
verbatim_bits = (int)bitbuf.ReadBits((byte)extra);
|
||||
match_offset += verbatim_bits;
|
||||
}
|
||||
else /* extra == 0 */
|
||||
{
|
||||
/* ??? */
|
||||
match_offset = 1;
|
||||
}
|
||||
|
||||
/* update repeated offset LRU queue */
|
||||
R2 = R1; R1 = R0; R0 = (uint)match_offset;
|
||||
}
|
||||
else if( match_offset == 0)
|
||||
{
|
||||
match_offset = (int)R0;
|
||||
}
|
||||
else if(match_offset == 1)
|
||||
{
|
||||
match_offset = (int)R1;
|
||||
R1 = R0; R0 = (uint)match_offset;
|
||||
}
|
||||
else /* match_offset == 2 */
|
||||
{
|
||||
match_offset = (int)R2;
|
||||
R2 = R0; R0 = (uint)match_offset;
|
||||
}
|
||||
|
||||
rundest = (int)window_posn;
|
||||
this_run -= match_length;
|
||||
|
||||
/* copy any wrapped around source data */
|
||||
if(window_posn >= match_offset)
|
||||
{
|
||||
/* no wrap */
|
||||
runsrc = rundest - match_offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
runsrc = rundest + ((int)window_size - match_offset);
|
||||
copy_length = match_offset - (int)window_posn;
|
||||
if(copy_length < match_length)
|
||||
{
|
||||
match_length -= copy_length;
|
||||
window_posn += (uint)copy_length;
|
||||
while(copy_length-- > 0) window[rundest++] = window[runsrc++];
|
||||
runsrc = 0;
|
||||
}
|
||||
}
|
||||
window_posn += (uint)match_length;
|
||||
|
||||
/* copy match data - no worries about destination wraps */
|
||||
while(match_length-- > 0) window[rundest++] = window[runsrc++];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LzxConstants.BLOCKTYPE.UNCOMPRESSED:
|
||||
if((inData.Position + this_run) > endpos) return -1; //TODO throw proper exception
|
||||
byte[] temp_buffer = new byte[this_run];
|
||||
inData.Read(temp_buffer, 0, this_run);
|
||||
temp_buffer.CopyTo(window, (int)window_posn);
|
||||
window_posn += (uint)this_run;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1; //TODO throw proper exception
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(togo != 0) return -1; //TODO throw proper exception
|
||||
int start_window_pos = (int)window_posn;
|
||||
if(start_window_pos == 0) start_window_pos = (int)window_size;
|
||||
start_window_pos -= outLen;
|
||||
outData.Write(window, start_window_pos, outLen);
|
||||
|
||||
m_state.window_posn = window_posn;
|
||||
m_state.R0 = R0;
|
||||
m_state.R1 = R1;
|
||||
m_state.R2 = R2;
|
||||
|
||||
// TODO finish intel E8 decoding
|
||||
/* intel E8 decoding */
|
||||
if((m_state.frames_read++ < 32768) && m_state.intel_filesize != 0)
|
||||
{
|
||||
if(outLen <= 6 || m_state.intel_started == 0)
|
||||
{
|
||||
m_state.intel_curpos += outLen;
|
||||
}
|
||||
else
|
||||
{
|
||||
int dataend = outLen - 10;
|
||||
uint curpos = (uint)m_state.intel_curpos;
|
||||
|
||||
m_state.intel_curpos = (int)curpos + outLen;
|
||||
|
||||
while(outData.Position < dataend)
|
||||
{
|
||||
if(outData.ReadByte() != 0xE8) { curpos++; continue; }
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// READ_LENGTHS(table, first, last)
|
||||
// if(lzx_read_lens(LENTABLE(table), first, last, bitsleft))
|
||||
// return ERROR (ILLEGAL_DATA)
|
||||
//
|
||||
|
||||
// TODO make returns throw exceptions
|
||||
private int MakeDecodeTable(uint nsyms, uint nbits, byte[] length, ushort[] table)
|
||||
{
|
||||
ushort sym;
|
||||
uint leaf;
|
||||
byte bit_num = 1;
|
||||
uint fill;
|
||||
uint pos = 0; /* the current position in the decode table */
|
||||
uint table_mask = (uint)(1 << (int)nbits);
|
||||
uint bit_mask = table_mask >> 1; /* don't do 0 length codes */
|
||||
uint next_symbol = bit_mask; /* base of allocation for long codes */
|
||||
|
||||
/* fill entries for codes short enough for a direct mapping */
|
||||
while (bit_num <= nbits )
|
||||
{
|
||||
for(sym = 0; sym < nsyms; sym++)
|
||||
{
|
||||
if(length[sym] == bit_num)
|
||||
{
|
||||
leaf = pos;
|
||||
|
||||
if((pos += bit_mask) > table_mask) return 1; /* table overrun */
|
||||
|
||||
/* fill all possible lookups of this symbol with the symbol itself */
|
||||
fill = bit_mask;
|
||||
while(fill-- > 0) table[leaf++] = sym;
|
||||
}
|
||||
}
|
||||
bit_mask >>= 1;
|
||||
bit_num++;
|
||||
}
|
||||
|
||||
/* if there are any codes longer than nbits */
|
||||
if(pos != table_mask)
|
||||
{
|
||||
/* clear the remainder of the table */
|
||||
for(sym = (ushort)pos; sym < table_mask; sym++) table[sym] = 0;
|
||||
|
||||
/* give ourselves room for codes to grow by up to 16 more bits */
|
||||
pos <<= 16;
|
||||
table_mask <<= 16;
|
||||
bit_mask = 1 << 15;
|
||||
|
||||
while(bit_num <= 16)
|
||||
{
|
||||
for(sym = 0; sym < nsyms; sym++)
|
||||
{
|
||||
if(length[sym] == bit_num)
|
||||
{
|
||||
leaf = pos >> 16;
|
||||
for(fill = 0; fill < bit_num - nbits; fill++)
|
||||
{
|
||||
/* if this path hasn't been taken yet, 'allocate' two entries */
|
||||
if(table[leaf] == 0)
|
||||
{
|
||||
table[(next_symbol << 1)] = 0;
|
||||
table[(next_symbol << 1) + 1] = 0;
|
||||
table[leaf] = (ushort)(next_symbol++);
|
||||
}
|
||||
/* follow the path and select either left or right for next bit */
|
||||
leaf = (uint)(table[leaf] << 1);
|
||||
if(((pos >> (int)(15-fill)) & 1) == 1) leaf++;
|
||||
}
|
||||
table[leaf] = sym;
|
||||
|
||||
if((pos += bit_mask) > table_mask) return 1;
|
||||
}
|
||||
}
|
||||
bit_mask >>= 1;
|
||||
bit_num++;
|
||||
}
|
||||
}
|
||||
|
||||
/* full talbe? */
|
||||
if(pos == table_mask) return 0;
|
||||
|
||||
/* either erroneous table, or all elements are 0 - let's find out. */
|
||||
for(sym = 0; sym < nsyms; sym++) if(length[sym] != 0) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO throw exceptions instead of returns
|
||||
private void ReadLengths(byte[] lens, uint first, uint last, BitBuffer bitbuf)
|
||||
{
|
||||
uint x, y;
|
||||
int z;
|
||||
|
||||
// hufftbl pointer here?
|
||||
|
||||
for(x = 0; x < 20; x++)
|
||||
{
|
||||
y = bitbuf.ReadBits(4);
|
||||
m_state.PRETREE_len[x] = (byte)y;
|
||||
}
|
||||
MakeDecodeTable(LzxConstants.PRETREE_MAXSYMBOLS, LzxConstants.PRETREE_TABLEBITS,
|
||||
m_state.PRETREE_len, m_state.PRETREE_table);
|
||||
|
||||
for(x = first; x < last;)
|
||||
{
|
||||
z = (int)ReadHuffSym(m_state.PRETREE_table, m_state.PRETREE_len,
|
||||
LzxConstants.PRETREE_MAXSYMBOLS, LzxConstants.PRETREE_TABLEBITS, bitbuf);
|
||||
if(z == 17)
|
||||
{
|
||||
y = bitbuf.ReadBits(4); y += 4;
|
||||
while(y-- != 0) lens[x++] = 0;
|
||||
}
|
||||
else if(z == 18)
|
||||
{
|
||||
y = bitbuf.ReadBits(5); y += 20;
|
||||
while(y-- != 0) lens[x++] = 0;
|
||||
}
|
||||
else if(z == 19)
|
||||
{
|
||||
y = bitbuf.ReadBits(1); y += 4;
|
||||
z = (int)ReadHuffSym(m_state.PRETREE_table, m_state.PRETREE_len,
|
||||
LzxConstants.PRETREE_MAXSYMBOLS, LzxConstants.PRETREE_TABLEBITS, bitbuf);
|
||||
z = lens[x] - z; if(z < 0) z += 17;
|
||||
while(y-- != 0) lens[x++] = (byte)z;
|
||||
}
|
||||
else
|
||||
{
|
||||
z = lens[x] - z; if(z < 0) z += 17;
|
||||
lens[x++] = (byte)z;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private uint ReadHuffSym(ushort[] table, byte[] lengths, uint nsyms, uint nbits, BitBuffer bitbuf)
|
||||
{
|
||||
uint i, j;
|
||||
bitbuf.EnsureBits(16);
|
||||
if((i = table[bitbuf.PeekBits((byte)nbits)]) >= nsyms)
|
||||
{
|
||||
j = (uint)(1 << (int)((sizeof(uint)*8) - nbits));
|
||||
do
|
||||
{
|
||||
j >>= 1; i <<= 1; i |= (bitbuf.GetBuffer() & j) != 0 ? (uint)1 : 0;
|
||||
if(j == 0) return 0; // TODO throw proper exception
|
||||
} while((i = table[i]) >= nsyms);
|
||||
}
|
||||
j = lengths[i];
|
||||
bitbuf.RemoveBits((byte)j);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
#region Our BitBuffer Class
|
||||
private class BitBuffer
|
||||
{
|
||||
uint buffer;
|
||||
byte bitsleft;
|
||||
Stream byteStream;
|
||||
|
||||
public BitBuffer(Stream stream)
|
||||
{
|
||||
byteStream = stream;
|
||||
InitBitStream();
|
||||
}
|
||||
|
||||
public void InitBitStream()
|
||||
{
|
||||
buffer = 0;
|
||||
bitsleft = 0;
|
||||
}
|
||||
|
||||
public void EnsureBits(byte bits)
|
||||
{
|
||||
while(bitsleft < bits) {
|
||||
int lo = (byte)byteStream.ReadByte();
|
||||
int hi = (byte)byteStream.ReadByte();
|
||||
//int amount2shift = sizeof(uint)*8 - 16 - bitsleft;
|
||||
buffer |= (uint)(((hi << 8) | lo) << (sizeof(uint)*8 - 16 - bitsleft));
|
||||
bitsleft += 16;
|
||||
}
|
||||
}
|
||||
|
||||
public uint PeekBits(byte bits)
|
||||
{
|
||||
return (buffer >> ((sizeof(uint)*8) - bits));
|
||||
}
|
||||
|
||||
public void RemoveBits(byte bits)
|
||||
{
|
||||
buffer <<= bits;
|
||||
bitsleft -= bits;
|
||||
}
|
||||
|
||||
public uint ReadBits(byte bits)
|
||||
{
|
||||
uint ret = 0;
|
||||
|
||||
if(bits > 0)
|
||||
{
|
||||
EnsureBits(bits);
|
||||
ret = PeekBits(bits);
|
||||
RemoveBits(bits);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public uint GetBuffer()
|
||||
{
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public byte GetBitsLeft()
|
||||
{
|
||||
return bitsleft;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
struct LzxState {
|
||||
public uint R0, R1, R2; /* for the LRU offset system */
|
||||
public ushort main_elements; /* number of main tree elements */
|
||||
public int header_read; /* have we started decoding at all yet? */
|
||||
public LzxConstants.BLOCKTYPE block_type; /* type of this block */
|
||||
public uint block_length; /* uncompressed length of this block */
|
||||
public uint block_remaining; /* uncompressed bytes still left to decode */
|
||||
public uint frames_read; /* the number of CFDATA blocks processed */
|
||||
public int intel_filesize; /* magic header value used for transform */
|
||||
public int intel_curpos; /* current offset in transform space */
|
||||
public int intel_started; /* have we seen any translateable data yet? */
|
||||
|
||||
public ushort[] PRETREE_table;
|
||||
public byte[] PRETREE_len;
|
||||
public ushort[] MAINTREE_table;
|
||||
public byte[] MAINTREE_len;
|
||||
public ushort[] LENGTH_table;
|
||||
public byte[] LENGTH_len;
|
||||
public ushort[] ALIGNED_table;
|
||||
public byte[] ALIGNED_len;
|
||||
|
||||
// NEEDED MEMBERS
|
||||
// CAB actualsize
|
||||
// CAB window
|
||||
// CAB window_size
|
||||
// CAB window_posn
|
||||
public uint actual_size;
|
||||
public byte[] window;
|
||||
public uint window_size;
|
||||
public uint window_posn;
|
||||
}
|
||||
}
|
||||
|
||||
/* CONSTANTS */
|
||||
struct LzxConstants {
|
||||
public const ushort MIN_MATCH = 2;
|
||||
public const ushort MAX_MATCH = 257;
|
||||
public const ushort NUM_CHARS = 256;
|
||||
public enum BLOCKTYPE {
|
||||
INVALID = 0,
|
||||
VERBATIM = 1,
|
||||
ALIGNED = 2,
|
||||
UNCOMPRESSED = 3
|
||||
}
|
||||
public const ushort PRETREE_NUM_ELEMENTS = 20;
|
||||
public const ushort ALIGNED_NUM_ELEMENTS = 8;
|
||||
public const ushort NUM_PRIMARY_LENGTHS = 7;
|
||||
public const ushort NUM_SECONDARY_LENGTHS = 249;
|
||||
|
||||
public const ushort PRETREE_MAXSYMBOLS = PRETREE_NUM_ELEMENTS;
|
||||
public const ushort PRETREE_TABLEBITS = 6;
|
||||
public const ushort MAINTREE_MAXSYMBOLS = NUM_CHARS + 50*8;
|
||||
public const ushort MAINTREE_TABLEBITS = 12;
|
||||
public const ushort LENGTH_MAXSYMBOLS = NUM_SECONDARY_LENGTHS + 1;
|
||||
public const ushort LENGTH_TABLEBITS = 12;
|
||||
public const ushort ALIGNED_MAXSYMBOLS = ALIGNED_NUM_ELEMENTS;
|
||||
public const ushort ALIGNED_TABLEBITS = 7;
|
||||
|
||||
public const ushort LENTABLE_SAFETY = 64;
|
||||
}
|
||||
|
||||
/* EXCEPTIONS */
|
||||
class UnsupportedWindowSizeRange : Exception
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Resources;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Content
|
||||
{
|
||||
public class ResourceContentManager : ContentManager
|
||||
{
|
||||
private ResourceManager resource;
|
||||
|
||||
public ResourceContentManager(IServiceProvider servicesProvider, ResourceManager resource)
|
||||
: base(servicesProvider)
|
||||
{
|
||||
if (resource == null)
|
||||
{
|
||||
throw new ArgumentNullException("resource");
|
||||
}
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
protected override System.IO.Stream OpenStream(string assetName)
|
||||
{
|
||||
object obj = this.resource.GetObject(assetName);
|
||||
if (obj == null)
|
||||
{
|
||||
throw new ContentLoadException("Resource not found");
|
||||
}
|
||||
if (!(obj is byte[]))
|
||||
{
|
||||
throw new ContentLoadException("Resource is not in binary format");
|
||||
}
|
||||
return new MemoryStream(obj as byte[]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,338 @@
|
||||
// MIT License - Copyright (C) The Mono.Xna Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Microsoft.Xna.Framework
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains a collection of <see cref="CurveKey"/> points in 2D space and provides methods for evaluating features of the curve they define.
|
||||
/// </summary>
|
||||
// TODO : [TypeConverter(typeof(ExpandableObjectConverter))]
|
||||
[DataContract]
|
||||
public class Curve
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
private CurveLoopType _preLoop;
|
||||
private CurveLoopType _postLoop;
|
||||
private CurveKeyCollection _keys;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Returns <c>true</c> if this curve is constant (has zero or one points); <c>false</c> otherwise.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public bool IsConstant
|
||||
{
|
||||
get { return this._keys.Count <= 1; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines how to handle weighting values that are less than the first control point in the curve.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public CurveLoopType PreLoop
|
||||
{
|
||||
get { return this._preLoop; }
|
||||
set { this._preLoop = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines how to handle weighting values that are greater than the last control point in the curve.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public CurveLoopType PostLoop
|
||||
{
|
||||
get { return this._postLoop; }
|
||||
set { this._postLoop = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The collection of curve keys.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public CurveKeyCollection Keys
|
||||
{
|
||||
get { return this._keys; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a curve.
|
||||
/// </summary>
|
||||
public Curve()
|
||||
{
|
||||
this._keys = new CurveKeyCollection();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Creates a copy of this curve.
|
||||
/// </summary>
|
||||
/// <returns>A copy of this curve.</returns>
|
||||
public Curve Clone()
|
||||
{
|
||||
Curve curve = new Curve();
|
||||
|
||||
curve._keys = this._keys.Clone();
|
||||
curve._preLoop = this._preLoop;
|
||||
curve._postLoop = this._postLoop;
|
||||
|
||||
return curve;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evaluate the value at a position of this <see cref="Curve"/>.
|
||||
/// </summary>
|
||||
/// <param name="position">The position on this <see cref="Curve"/>.</param>
|
||||
/// <returns>Value at the position on this <see cref="Curve"/>.</returns>
|
||||
public float Evaluate(float position)
|
||||
{
|
||||
if (_keys.Count == 0)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
if (_keys.Count == 1)
|
||||
{
|
||||
return _keys[0].Value;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes tangents for all keys in the collection.
|
||||
/// </summary>
|
||||
/// <param name="tangentType">The tangent type for both in and out.</param>
|
||||
public void ComputeTangents (CurveTangent tangentType)
|
||||
{
|
||||
ComputeTangents(tangentType, tangentType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes tangents for all keys in the collection.
|
||||
/// </summary>
|
||||
/// <param name="tangentInType">The tangent in-type. <see cref="CurveKey.TangentIn"/> for more details.</param>
|
||||
/// <param name="tangentOutType">The tangent out-type. <see cref="CurveKey.TangentOut"/> for more details.</param>
|
||||
public void ComputeTangents(CurveTangent tangentInType, CurveTangent tangentOutType)
|
||||
{
|
||||
for (var i = 0; i < Keys.Count; ++i)
|
||||
{
|
||||
ComputeTangent(i, tangentInType, tangentOutType);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes tangent for the specific key in the collection.
|
||||
/// </summary>
|
||||
/// <param name="keyIndex">The index of a key in the collection.</param>
|
||||
/// <param name="tangentType">The tangent type for both in and out.</param>
|
||||
public void ComputeTangent(int keyIndex, CurveTangent tangentType)
|
||||
{
|
||||
ComputeTangent(keyIndex, tangentType, tangentType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes tangent for the specific key in the collection.
|
||||
/// </summary>
|
||||
/// <param name="keyIndex">The index of key in the collection.</param>
|
||||
/// <param name="tangentInType">The tangent in-type. <see cref="CurveKey.TangentIn"/> for more details.</param>
|
||||
/// <param name="tangentOutType">The tangent out-type. <see cref="CurveKey.TangentOut"/> for more details.</param>
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// MIT License - Copyright (C) The Mono.Xna Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
namespace Microsoft.Xna.Framework
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the continuity of keys on a <see cref="Curve"/>.
|
||||
/// </summary>
|
||||
public enum CurveContinuity
|
||||
{
|
||||
/// <summary>
|
||||
/// Interpolation can be used between this key and the next.
|
||||
/// </summary>
|
||||
Smooth,
|
||||
/// <summary>
|
||||
/// Interpolation cannot be used. A position between the two points returns this point.
|
||||
/// </summary>
|
||||
Step
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
// MIT License - Copyright (C) The Mono.Xna Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Microsoft.Xna.Framework
|
||||
{
|
||||
/// <summary>
|
||||
/// Key point on the <see cref="Curve"/>.
|
||||
/// </summary>
|
||||
// TODO : [TypeConverter(typeof(ExpandableObjectConverter))]
|
||||
[DataContract]
|
||||
public class CurveKey : IEquatable<CurveKey>, IComparable<CurveKey>
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
private CurveContinuity _continuity;
|
||||
private readonly float _position;
|
||||
private float _tangentIn;
|
||||
private float _tangentOut;
|
||||
private float _value;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the indicator whether the segment between this point and the next point on the curve is discrete or continuous.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public CurveContinuity Continuity
|
||||
{
|
||||
get { return this._continuity; }
|
||||
set { this._continuity = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a position of the key on the curve.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public float Position
|
||||
{
|
||||
get { return this._position; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a tangent when approaching this point from the previous point on the curve.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public float TangentIn
|
||||
{
|
||||
get { return this._tangentIn; }
|
||||
set { this._tangentIn = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a tangent when leaving this point to the next point on the curve.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public float TangentOut
|
||||
{
|
||||
get { return this._tangentOut; }
|
||||
set { this._tangentOut = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value of this point.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public float Value
|
||||
{
|
||||
get { return this._value; }
|
||||
set { this._value = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="CurveKey"/> class with position: 0 and value: 0.
|
||||
/// </summary>
|
||||
public CurveKey() : this(0, 0)
|
||||
{
|
||||
// This parameterless constructor is needed for correct serialization of CurveKeyCollection and CurveKey.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="CurveKey"/> class.
|
||||
/// </summary>
|
||||
/// <param name="position">Position on the curve.</param>
|
||||
/// <param name="value">Value of the control point.</param>
|
||||
public CurveKey(float position, float value)
|
||||
: this(position, value, 0, 0, CurveContinuity.Smooth)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="CurveKey"/> class.
|
||||
/// </summary>
|
||||
/// <param name="position">Position on the curve.</param>
|
||||
/// <param name="value">Value of the control point.</param>
|
||||
/// <param name="tangentIn">Tangent approaching point from the previous point on the curve.</param>
|
||||
/// <param name="tangentOut">Tangent leaving point toward next point on the curve.</param>
|
||||
public CurveKey(float position, float value, float tangentIn, float tangentOut)
|
||||
: this(position, value, tangentIn, tangentOut, CurveContinuity.Smooth)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="CurveKey"/> class.
|
||||
/// </summary>
|
||||
/// <param name="position">Position on the curve.</param>
|
||||
/// <param name="value">Value of the control point.</param>
|
||||
/// <param name="tangentIn">Tangent approaching point from the previous point on the curve.</param>
|
||||
/// <param name="tangentOut">Tangent leaving point toward next point on the curve.</param>
|
||||
/// <param name="continuity">Indicates whether the curve is discrete or continuous.</param>
|
||||
public CurveKey(float position, float value, float tangentIn, float tangentOut, CurveContinuity continuity)
|
||||
{
|
||||
this._position = position;
|
||||
this._value = value;
|
||||
this._tangentIn = tangentIn;
|
||||
this._tangentOut = tangentOut;
|
||||
this._continuity = continuity;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// Compares whether two <see cref="CurveKey"/> instances are not equal.
|
||||
/// </summary>
|
||||
/// <param name="value1"><see cref="CurveKey"/> instance on the left of the not equal sign.</param>
|
||||
/// <param name="value2"><see cref="CurveKey"/> instance on the right of the not equal sign.</param>
|
||||
/// <returns><c>true</c> if the instances are not equal; <c>false</c> otherwise.</returns>
|
||||
public static bool operator !=(CurveKey value1, CurveKey value2)
|
||||
{
|
||||
return !(value1 == value2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares whether two <see cref="CurveKey"/> instances are equal.
|
||||
/// </summary>
|
||||
/// <param name="value1"><see cref="CurveKey"/> instance on the left of the equal sign.</param>
|
||||
/// <param name="value2"><see cref="CurveKey"/> instance on the right of the equal sign.</param>
|
||||
/// <returns><c>true</c> if the instances are equal; <c>false</c> otherwise.</returns>
|
||||
public static bool operator ==(CurveKey value1, CurveKey value2)
|
||||
{
|
||||
if (object.Equals(value1, null))
|
||||
return object.Equals(value2, null);
|
||||
|
||||
if (object.Equals(value2, null))
|
||||
return object.Equals(value1, null);
|
||||
|
||||
return (value1._position == value2._position)
|
||||
&& (value1._value == value2._value)
|
||||
&& (value1._tangentIn == value2._tangentIn)
|
||||
&& (value1._tangentOut == value2._tangentOut)
|
||||
&& (value1._continuity == value2._continuity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a copy of this key.
|
||||
/// </summary>
|
||||
/// <returns>A copy of this key.</returns>
|
||||
public CurveKey Clone()
|
||||
{
|
||||
return new CurveKey(this._position, this._value, this._tangentIn, this._tangentOut, this._continuity);
|
||||
}
|
||||
|
||||
#region Inherited Methods
|
||||
|
||||
public int CompareTo(CurveKey other)
|
||||
{
|
||||
return this._position.CompareTo(other._position);
|
||||
}
|
||||
|
||||
public bool Equals(CurveKey other)
|
||||
{
|
||||
return (this == other);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return (obj as CurveKey) != null && Equals((CurveKey)obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this._position.GetHashCode() ^ this._value.GetHashCode() ^ this._tangentIn.GetHashCode() ^
|
||||
this._tangentOut.GetHashCode() ^ this._continuity.GetHashCode();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
// MIT License - Copyright (C) The Mono.Xna Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Microsoft.Xna.Framework
|
||||
{
|
||||
/// <summary>
|
||||
/// The collection of the <see cref="CurveKey"/> elements and a part of the <see cref="Curve"/> class.
|
||||
/// </summary>
|
||||
// TODO : [TypeConverter(typeof(ExpandableObjectConverter))]
|
||||
[DataContract]
|
||||
public class CurveKeyCollection : ICollection<CurveKey>
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
private readonly List<CurveKey> _keys;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Indexer.
|
||||
/// </summary>
|
||||
/// <param name="index">The index of key in this collection.</param>
|
||||
/// <returns><see cref="CurveKey"/> at <paramref name="index"/> position.</returns>
|
||||
[DataMember(Name = "Items")]
|
||||
public CurveKey this[int index]
|
||||
{
|
||||
get { return _keys[index]; }
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException();
|
||||
|
||||
if (index >= _keys.Count)
|
||||
throw new IndexOutOfRangeException();
|
||||
|
||||
if (_keys[index].Position == value.Position)
|
||||
_keys[index] = value;
|
||||
else
|
||||
{
|
||||
_keys.RemoveAt(index);
|
||||
_keys.Add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the count of keys in this collection.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public int Count
|
||||
{
|
||||
get { return _keys.Count; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns false because it is not a read-only collection.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="CurveKeyCollection"/> class.
|
||||
/// </summary>
|
||||
public CurveKeyCollection()
|
||||
{
|
||||
_keys = new List<CurveKey>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return _keys.GetEnumerator();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Adds a key to this collection.
|
||||
/// </summary>
|
||||
/// <param name="item">New key for the collection.</param>
|
||||
/// <exception cref="ArgumentNullException">Throws if <paramref name="item"/> is null.</exception>
|
||||
/// <remarks>The new key would be added respectively to a position of that key and the position of other keys.</remarks>
|
||||
public void Add(CurveKey item)
|
||||
{
|
||||
if (item == null)
|
||||
throw new ArgumentNullException("item");
|
||||
|
||||
if (_keys.Count == 0)
|
||||
{
|
||||
this._keys.Add(item);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < this._keys.Count; i++)
|
||||
{
|
||||
if (item.Position < this._keys[i].Position)
|
||||
{
|
||||
this._keys.Insert(i, item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this._keys.Add(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all keys from this collection.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
_keys.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a copy of this collection.
|
||||
/// </summary>
|
||||
/// <returns>A copy of this collection.</returns>
|
||||
public CurveKeyCollection Clone()
|
||||
{
|
||||
CurveKeyCollection ckc = new CurveKeyCollection();
|
||||
foreach (CurveKey key in this._keys)
|
||||
ckc.Add(key);
|
||||
return ckc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this collection contains a specific key.
|
||||
/// </summary>
|
||||
/// <param name="item">The key to locate in this collection.</param>
|
||||
/// <returns><c>true</c> if the key is found; <c>false</c> otherwise.</returns>
|
||||
public bool Contains(CurveKey item)
|
||||
{
|
||||
return _keys.Contains(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the keys of this collection to an array, starting at the array index provided.
|
||||
/// </summary>
|
||||
/// <param name="array">Destination array where elements will be copied.</param>
|
||||
/// <param name="arrayIndex">The zero-based index in the array to start copying from.</param>
|
||||
public void CopyTo(CurveKey[] array, int arrayIndex)
|
||||
{
|
||||
_keys.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through the collection.
|
||||
/// </summary>
|
||||
/// <returns>An enumerator for the <see cref="CurveKeyCollection"/>.</returns>
|
||||
public IEnumerator<CurveKey> GetEnumerator()
|
||||
{
|
||||
return _keys.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds element in the collection and returns its index.
|
||||
/// </summary>
|
||||
/// <param name="item">Element for the search.</param>
|
||||
/// <returns>Index of the element; or -1 if item is not found.</returns>
|
||||
public int IndexOf(CurveKey item)
|
||||
{
|
||||
return _keys.IndexOf(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes element at the specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">The index which element will be removed.</param>
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
_keys.RemoveAt(index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes specific element.
|
||||
/// </summary>
|
||||
/// <param name="item">The element</param>
|
||||
/// <returns><c>true</c> if item is successfully removed; <c>false</c> otherwise. This method also returns <c>false</c> if item was not found.</returns>
|
||||
public bool Remove(CurveKey item)
|
||||
{
|
||||
return _keys.Remove(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// MIT License - Copyright (C) The Mono.Xna Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
namespace Microsoft.Xna.Framework
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines how the <see cref="Curve"/> value is determined for position before first point or after the end point on the <see cref="Curve"/>.
|
||||
/// </summary>
|
||||
public enum CurveLoopType
|
||||
{
|
||||
/// <summary>
|
||||
/// The value of <see cref="Curve"/> will be evaluated as first point for positions before the beginning and end point for positions after the end.
|
||||
/// </summary>
|
||||
Constant,
|
||||
/// <summary>
|
||||
/// The positions will wrap around from the end to beginning of the <see cref="Curve"/> for determined the value.
|
||||
/// </summary>
|
||||
Cycle,
|
||||
/// <summary>
|
||||
/// The positions will wrap around from the end to beginning of the <see cref="Curve"/>.
|
||||
/// The value will be offset by the difference between the values of first and end <see cref="CurveKey"/> multiplied by the wrap amount.
|
||||
/// If the position is before the beginning of the <see cref="Curve"/> the difference will be subtracted from its value; otherwise the difference will be added.
|
||||
/// </summary>
|
||||
CycleOffset,
|
||||
/// <summary>
|
||||
/// The value at the end of the <see cref="Curve"/> act as an offset from the same side of the <see cref="Curve"/> toward the opposite side.
|
||||
/// </summary>
|
||||
Oscillate,
|
||||
/// <summary>
|
||||
/// The linear interpolation will be performed for determined the value.
|
||||
/// </summary>
|
||||
Linear
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
namespace Microsoft.Xna.Framework
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the different tangent types to be calculated for <see cref="CurveKey"/> points in a <see cref="Curve"/>.
|
||||
/// </summary>
|
||||
public enum CurveTangent
|
||||
{
|
||||
/// <summary>
|
||||
/// The tangent which always has a value equal to zero.
|
||||
/// </summary>
|
||||
Flat,
|
||||
/// <summary>
|
||||
/// The tangent which contains a difference between current tangent value and the tangent value from the previous <see cref="CurveKey"/>.
|
||||
/// </summary>
|
||||
Linear,
|
||||
/// <summary>
|
||||
/// The smoouth tangent which contains the inflection between <see cref="CurveKey.TangentIn"/> and <see cref="CurveKey.TangentOut"/> by taking into account the values of both neighbors of the <see cref="CurveKey"/>.
|
||||
/// </summary>
|
||||
Smooth
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Design
|
||||
{
|
||||
public class Vector2TypeConverter : TypeConverter
|
||||
{
|
||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
||||
{
|
||||
if (VectorConversion.CanConvertTo(context, destinationType))
|
||||
return true;
|
||||
if (destinationType == typeof(string))
|
||||
return true;
|
||||
|
||||
return base.CanConvertTo(context, destinationType);
|
||||
}
|
||||
|
||||
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
|
||||
{
|
||||
var vec = (Vector2)value;
|
||||
|
||||
if (VectorConversion.CanConvertTo(context, destinationType))
|
||||
{
|
||||
var vec4 = new Vector4(vec.X, vec.Y, 0.0f, 0.0f);
|
||||
return VectorConversion.ConvertToFromVector4(context, culture, vec4, destinationType);
|
||||
}
|
||||
|
||||
if (destinationType == typeof(string))
|
||||
{
|
||||
var terms = new string[2];
|
||||
terms[0] = vec.X.ToString("R", culture);
|
||||
terms[1] = vec.Y.ToString("R", culture);
|
||||
|
||||
return string.Join(culture.TextInfo.ListSeparator + " ", terms);
|
||||
}
|
||||
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
|
||||
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, CultureInfo culture, object value)
|
||||
{
|
||||
var sourceType = value.GetType();
|
||||
var vec = Vector2.Zero;
|
||||
|
||||
if (sourceType == typeof(string))
|
||||
{
|
||||
var str = (string)value;
|
||||
var words = str.Split(culture.TextInfo.ListSeparator.ToCharArray());
|
||||
|
||||
vec.X = float.Parse(words[0], culture);
|
||||
vec.Y = float.Parse(words[1], culture);
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Design
|
||||
{
|
||||
public class Vector3TypeConverter : TypeConverter
|
||||
{
|
||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
||||
{
|
||||
if (VectorConversion.CanConvertTo(context, destinationType))
|
||||
return true;
|
||||
if (destinationType == typeof(string))
|
||||
return true;
|
||||
|
||||
return base.CanConvertTo(context, destinationType);
|
||||
}
|
||||
|
||||
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
|
||||
{
|
||||
var vec = (Vector3)value;
|
||||
|
||||
if (VectorConversion.CanConvertTo(context, destinationType))
|
||||
{
|
||||
var vec4 = new Vector4(vec.X, vec.Y, vec.Z, 0.0f);
|
||||
return VectorConversion.ConvertToFromVector4(context, culture, vec4, destinationType);
|
||||
}
|
||||
|
||||
if (destinationType == typeof(string))
|
||||
{
|
||||
var terms = new string[3];
|
||||
terms[0] = vec.X.ToString("R", culture);
|
||||
terms[1] = vec.Y.ToString("R", culture);
|
||||
terms[2] = vec.Z.ToString("R", culture);
|
||||
|
||||
return string.Join(culture.TextInfo.ListSeparator + " ", terms);
|
||||
}
|
||||
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
|
||||
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, CultureInfo culture, object value)
|
||||
{
|
||||
var sourceType = value.GetType();
|
||||
var vec = Vector3.Zero;
|
||||
|
||||
if (sourceType == typeof(string))
|
||||
{
|
||||
var str = (string)value;
|
||||
var words = str.Split(culture.TextInfo.ListSeparator.ToCharArray());
|
||||
|
||||
vec.X = float.Parse(words[0], culture);
|
||||
vec.Y = float.Parse(words[1], culture);
|
||||
vec.Z = float.Parse(words[2], culture);
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Design
|
||||
{
|
||||
public class Vector4TypeConverter : TypeConverter
|
||||
{
|
||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
||||
{
|
||||
if (VectorConversion.CanConvertTo(context, destinationType))
|
||||
return true;
|
||||
if (destinationType == typeof(string))
|
||||
return true;
|
||||
|
||||
return base.CanConvertTo(context, destinationType);
|
||||
}
|
||||
|
||||
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
|
||||
{
|
||||
var vec = (Vector4)value;
|
||||
|
||||
if (VectorConversion.CanConvertTo(context, destinationType))
|
||||
{
|
||||
return VectorConversion.ConvertToFromVector4(context, culture, vec, destinationType);
|
||||
}
|
||||
|
||||
if (destinationType == typeof(string))
|
||||
{
|
||||
var terms = new string[4];
|
||||
terms[0] = vec.X.ToString("R", culture);
|
||||
terms[1] = vec.Y.ToString("R", culture);
|
||||
terms[2] = vec.Z.ToString("R", culture);
|
||||
terms[3] = vec.W.ToString("R", culture);
|
||||
|
||||
return string.Join(culture.TextInfo.ListSeparator + " ", terms);
|
||||
}
|
||||
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
|
||||
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, CultureInfo culture, object value)
|
||||
{
|
||||
var sourceType = value.GetType();
|
||||
var vec = Vector4.Zero;
|
||||
|
||||
if (sourceType == typeof(string))
|
||||
{
|
||||
var str = (string)value;
|
||||
var words = str.Split(culture.TextInfo.ListSeparator.ToCharArray());
|
||||
|
||||
vec.X = float.Parse(words[0], culture);
|
||||
vec.Y = float.Parse(words[1], culture);
|
||||
vec.Z = float.Parse(words[2], culture);
|
||||
vec.W = float.Parse(words[3], culture);
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using Microsoft.Xna.Framework.Graphics.PackedVector;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Design
|
||||
{
|
||||
internal static class VectorConversion
|
||||
{
|
||||
public static bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
||||
{
|
||||
if (destinationType == typeof(float))
|
||||
return true;
|
||||
if (destinationType == typeof(Vector2))
|
||||
return true;
|
||||
if (destinationType == typeof(Vector3))
|
||||
return true;
|
||||
if (destinationType == typeof(Vector4))
|
||||
return true;
|
||||
if (destinationType.GetInterface("IPackedVector") != null)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static object ConvertToFromVector4(ITypeDescriptorContext context, CultureInfo culture, Vector4 value, Type destinationType)
|
||||
{
|
||||
if (destinationType == typeof(float))
|
||||
return value.X;
|
||||
if (destinationType == typeof(Vector2))
|
||||
return new Vector2(value.X, value.Y);
|
||||
if (destinationType == typeof(Vector3))
|
||||
return new Vector3(value.X, value.Y, value.Z);
|
||||
if (destinationType == typeof(Vector4))
|
||||
return new Vector4(value.X, value.Y, value.Z, value.W);
|
||||
if (destinationType.GetInterface("IPackedVector") != null)
|
||||
{
|
||||
var packedVec = (IPackedVector)Activator.CreateInstance(destinationType);
|
||||
packedVec.PackFromVector4(value);
|
||||
return packedVec;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,330 @@
|
||||
#region License
|
||||
/*
|
||||
Microsoft Public License (Ms-PL)
|
||||
MonoGame - Copyright © 2009 The MonoGame Team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
This license governs use of the accompanying software. If you use the software, you accept this license. If you do not
|
||||
accept the license, do not use the software.
|
||||
|
||||
1. Definitions
|
||||
The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under
|
||||
U.S. copyright law.
|
||||
|
||||
A "contribution" is the original software, or any additions or changes to the software.
|
||||
A "contributor" is any person that distributes its contribution under this license.
|
||||
"Licensed patents" are a contributor's patent claims that read directly on its contribution.
|
||||
|
||||
2. Grant of Rights
|
||||
(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3,
|
||||
each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
|
||||
(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3,
|
||||
each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
|
||||
|
||||
3. Conditions and Limitations
|
||||
(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
|
||||
(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software,
|
||||
your patent license from such contributor to the software ends automatically.
|
||||
(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution
|
||||
notices that are present in the software.
|
||||
(D) If you distribute any portion of the software in source code form, you may do so only under this license by including
|
||||
a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object
|
||||
code form, you may only do so under a license that complies with this license.
|
||||
(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees
|
||||
or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent
|
||||
permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular
|
||||
purpose and non-infringement.
|
||||
*/
|
||||
#endregion License
|
||||
|
||||
#region Using clause
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Runtime.Remoting.Messaging;
|
||||
|
||||
using Microsoft.Xna.Framework.Net;
|
||||
|
||||
|
||||
#endregion Using clause
|
||||
|
||||
namespace Microsoft.Xna.Framework.GamerServices
|
||||
{
|
||||
public static class Guide
|
||||
{
|
||||
private static bool isScreenSaverEnabled;
|
||||
private static bool isTrialMode;
|
||||
private static bool isVisible;
|
||||
private static bool simulateTrialMode;
|
||||
|
||||
delegate string ShowKeyboardInputDelegate(
|
||||
PlayerIndex player,
|
||||
string title,
|
||||
string description,
|
||||
string defaultText,
|
||||
bool usePasswordMode);
|
||||
|
||||
public static string ShowKeyboardInput(
|
||||
PlayerIndex player,
|
||||
string title,
|
||||
string description,
|
||||
string defaultText,
|
||||
bool usePasswordMode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static IAsyncResult BeginShowKeyboardInput (
|
||||
PlayerIndex player,
|
||||
string title,
|
||||
string description,
|
||||
string defaultText,
|
||||
AsyncCallback callback,
|
||||
Object state)
|
||||
{
|
||||
return BeginShowKeyboardInput(player, title, description, defaultText, callback, state, false );
|
||||
}
|
||||
|
||||
public static IAsyncResult BeginShowKeyboardInput (
|
||||
PlayerIndex player,
|
||||
string title,
|
||||
string description,
|
||||
string defaultText,
|
||||
AsyncCallback callback,
|
||||
Object state,
|
||||
bool usePasswordMode)
|
||||
{
|
||||
return BeginShowKeyboardInput(player, title, description, defaultText, callback, state, false );
|
||||
}
|
||||
|
||||
public static string EndShowKeyboardInput (IAsyncResult result)
|
||||
{
|
||||
ShowKeyboardInputDelegate ski = (ShowKeyboardInputDelegate)result.AsyncState;
|
||||
|
||||
return ski.EndInvoke(result);
|
||||
}
|
||||
|
||||
delegate Nullable<int> ShowMessageBoxDelegate( string title,
|
||||
string text,
|
||||
IEnumerable<string> buttons,
|
||||
int focusButton,
|
||||
MessageBoxIcon icon);
|
||||
|
||||
public static Nullable<int> ShowMessageBox( string title,
|
||||
string text,
|
||||
IEnumerable<string> buttons,
|
||||
int focusButton,
|
||||
MessageBoxIcon icon)
|
||||
{
|
||||
int? result = null;
|
||||
IsVisible = true;
|
||||
|
||||
IsVisible = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
public static IAsyncResult BeginShowMessageBox(
|
||||
PlayerIndex player,
|
||||
string title,
|
||||
string text,
|
||||
IEnumerable<string> buttons,
|
||||
int focusButton,
|
||||
MessageBoxIcon icon,
|
||||
AsyncCallback callback,
|
||||
Object state
|
||||
)
|
||||
{
|
||||
if (IsVisible)
|
||||
throw new Exception("The function cannot be completed at this time: the Guide UI is already active. Wait until Guide.IsVisible is false before issuing this call.");
|
||||
|
||||
if (player != PlayerIndex.One)
|
||||
throw new ArgumentOutOfRangeException("player", "Specified argument was out of the range of valid values.");
|
||||
if (title == null)
|
||||
throw new ArgumentNullException("title", "This string cannot be null or empty, and must be less than 256 characters long.");
|
||||
if (text == null)
|
||||
throw new ArgumentNullException("text", "This string cannot be null or empty, and must be less than 256 characters long.");
|
||||
if (buttons == null)
|
||||
throw new ArgumentNullException("buttons", "Value can not be null.");
|
||||
|
||||
ShowMessageBoxDelegate smb = ShowMessageBox;
|
||||
|
||||
return smb.BeginInvoke(title, text, buttons, focusButton, icon, callback, smb);
|
||||
}
|
||||
|
||||
public static IAsyncResult BeginShowMessageBox (
|
||||
string title,
|
||||
string text,
|
||||
IEnumerable<string> buttons,
|
||||
int focusButton,
|
||||
MessageBoxIcon icon,
|
||||
AsyncCallback callback,
|
||||
Object state
|
||||
)
|
||||
{
|
||||
return BeginShowMessageBox(PlayerIndex.One, title, text, buttons, focusButton, icon, callback, state);
|
||||
}
|
||||
|
||||
public static Nullable<int> EndShowMessageBox (IAsyncResult result)
|
||||
{
|
||||
return ((ShowMessageBoxDelegate)result.AsyncState).EndInvoke(result);
|
||||
}
|
||||
|
||||
|
||||
public static void ShowMarketplace (PlayerIndex player )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static void Show ()
|
||||
{
|
||||
ShowSignIn(1, false);
|
||||
}
|
||||
|
||||
public static void ShowSignIn (int paneCount, bool onlineOnly)
|
||||
{
|
||||
if ( paneCount != 1 && paneCount != 2 && paneCount != 4)
|
||||
{
|
||||
new ArgumentException("paneCount Can only be 1, 2 or 4 on Windows");
|
||||
return;
|
||||
}
|
||||
|
||||
Microsoft.Xna.Framework.GamerServices.MonoGameGamerServicesHelper.ShowSigninSheet();
|
||||
if (GamerServicesComponent.LocalNetworkGamer == null)
|
||||
{
|
||||
GamerServicesComponent.LocalNetworkGamer = new LocalNetworkGamer();
|
||||
}
|
||||
else
|
||||
{
|
||||
GamerServicesComponent.LocalNetworkGamer.SignedInGamer.BeginAuthentication(null, null);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ShowLeaderboard()
|
||||
{
|
||||
//if ( ( Gamer.SignedInGamers.Count > 0 ) && ( Gamer.SignedInGamers[0].IsSignedInToLive ) )
|
||||
//{
|
||||
// // Lazy load it
|
||||
// if ( leaderboardController == null )
|
||||
// {
|
||||
// leaderboardController = new GKLeaderboardViewController();
|
||||
// }
|
||||
|
||||
// if (leaderboardController != null)
|
||||
// {
|
||||
// leaderboardController.DidFinish += delegate(object sender, EventArgs e)
|
||||
// {
|
||||
// leaderboardController.DismissModalViewControllerAnimated(true);
|
||||
// isVisible = false;
|
||||
// };
|
||||
|
||||
// if (Window !=null)
|
||||
// {
|
||||
// if(viewController == null)
|
||||
// {
|
||||
// viewController = new UIViewController();
|
||||
// Window.Add(viewController.View);
|
||||
// viewController.View.Hidden = true;
|
||||
// }
|
||||
|
||||
// viewController.PresentModalViewController(leaderboardController, true);
|
||||
// isVisible = true;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
public static void ShowAchievements()
|
||||
{
|
||||
//if ( ( Gamer.SignedInGamers.Count > 0 ) && ( Gamer.SignedInGamers[0].IsSignedInToLive ) )
|
||||
//{
|
||||
// // Lazy load it
|
||||
// if ( achievementController == null )
|
||||
// {
|
||||
// achievementController = new GKAchievementViewController();
|
||||
// }
|
||||
|
||||
// if (achievementController != null)
|
||||
// {
|
||||
// achievementController.DidFinish += delegate(object sender, EventArgs e)
|
||||
// {
|
||||
// leaderboardController.DismissModalViewControllerAnimated(true);
|
||||
// isVisible = false;
|
||||
// };
|
||||
|
||||
// if (Window !=null)
|
||||
// {
|
||||
// if(viewController == null)
|
||||
// {
|
||||
// viewController = new UIViewController();
|
||||
// Window.Add(viewController.View);
|
||||
// viewController.View.Hidden = true;
|
||||
// }
|
||||
|
||||
// viewController.PresentModalViewController(achievementController, true);
|
||||
// isVisible = true;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
#region Properties
|
||||
public static bool IsScreenSaverEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return isScreenSaverEnabled;
|
||||
}
|
||||
set
|
||||
{
|
||||
isScreenSaverEnabled = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsTrialMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return simulateTrialMode || isTrialMode;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsVisible
|
||||
{
|
||||
get
|
||||
{
|
||||
return isVisible;
|
||||
}
|
||||
set
|
||||
{
|
||||
isVisible = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool SimulateTrialMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return simulateTrialMode;
|
||||
}
|
||||
set
|
||||
{
|
||||
simulateTrialMode = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static GameWindow Window
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
#endregion
|
||||
|
||||
internal static void Initialise(Game game)
|
||||
{
|
||||
MonoGameGamerServicesHelper.Initialise(game);
|
||||
}
|
||||
}
|
||||
}
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
using System;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Microsoft.Xna.Framework.GamerServices
|
||||
{
|
||||
internal class MonoGameGamerServicesHelper
|
||||
{
|
||||
private static MonoLiveGuide guide = null;
|
||||
|
||||
|
||||
|
||||
public static void ShowSigninSheet()
|
||||
{
|
||||
guide.Enabled = true;
|
||||
guide.Visible = true;
|
||||
Guide.IsVisible = true;
|
||||
}
|
||||
|
||||
internal static void Initialise(Game game)
|
||||
{
|
||||
if (guide == null)
|
||||
{
|
||||
guide = new MonoLiveGuide(game);
|
||||
game.Components.Add(guide);
|
||||
}
|
||||
}}
|
||||
|
||||
internal class MonoLiveGuide : DrawableGameComponent
|
||||
{
|
||||
SpriteBatch spriteBatch;
|
||||
Texture2D signInProgress;
|
||||
Color alphaColor = new Color(128, 128, 128, 0);
|
||||
byte startalpha = 0;
|
||||
|
||||
public MonoLiveGuide(Game game)
|
||||
: base(game)
|
||||
{
|
||||
this.Enabled = false;
|
||||
this.Visible = false;
|
||||
//Guide.IsVisible = false;
|
||||
this.DrawOrder = Int32.MaxValue;
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
}
|
||||
|
||||
Texture2D Circle(GraphicsDevice graphics, int radius)
|
||||
{
|
||||
int aDiameter = radius * 2;
|
||||
Vector2 aCenter = new Vector2(radius, radius);
|
||||
|
||||
Texture2D aCircle = new Texture2D(graphics, aDiameter, aDiameter, false, SurfaceFormat.Color);
|
||||
Color[] aColors = new Color[aDiameter * aDiameter];
|
||||
|
||||
for (int i = 0; i < aColors.Length; i++)
|
||||
{
|
||||
int x = (i + 1) % aDiameter;
|
||||
int y = (i + 1) / aDiameter;
|
||||
|
||||
Vector2 aDistance = new Vector2(Math.Abs(aCenter.X - x), Math.Abs(aCenter.Y - y));
|
||||
|
||||
|
||||
if (Math.Sqrt((aDistance.X * aDistance.X) + (aDistance.Y * aDistance.Y)) > radius)
|
||||
{
|
||||
aColors[i] = Color.Transparent;
|
||||
}
|
||||
else
|
||||
{
|
||||
aColors[i] = Color.White;
|
||||
}
|
||||
}
|
||||
|
||||
aCircle.SetData<Color>(aColors);
|
||||
|
||||
return aCircle;
|
||||
}
|
||||
|
||||
protected override void LoadContent()
|
||||
{
|
||||
spriteBatch = new SpriteBatch(this.Game.GraphicsDevice);
|
||||
|
||||
signInProgress = Circle(this.Game.GraphicsDevice, 10);
|
||||
|
||||
base.LoadContent();
|
||||
}
|
||||
|
||||
protected override void UnloadContent()
|
||||
{
|
||||
base.UnloadContent();
|
||||
}
|
||||
|
||||
public override void Draw(GameTime gameTime)
|
||||
{
|
||||
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
|
||||
|
||||
Vector2 center = new Vector2(this.Game.GraphicsDevice.PresentationParameters.BackBufferWidth / 2, this.Game.GraphicsDevice.PresentationParameters.BackBufferHeight - 100);
|
||||
Vector2 loc = Vector2.Zero;
|
||||
alphaColor.A = startalpha;
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
float angle = (float)(i / 12.0 * Math.PI * 2);
|
||||
loc = new Vector2(center.X + (float)Math.Cos(angle) * 50, center.Y + (float)Math.Sin(angle) * 50);
|
||||
spriteBatch.Draw(signInProgress, loc, alphaColor);
|
||||
alphaColor.A += 255 / 12;
|
||||
if (alphaColor.A > 255) alphaColor.A = 0;
|
||||
}
|
||||
spriteBatch.End();
|
||||
base.Draw(gameTime);
|
||||
}
|
||||
|
||||
TimeSpan gt = TimeSpan.Zero;
|
||||
TimeSpan last = TimeSpan.Zero;
|
||||
|
||||
public override void Update(GameTime gameTime)
|
||||
{
|
||||
if (gt == TimeSpan.Zero) gt = last = gameTime.TotalGameTime;
|
||||
|
||||
if ((gameTime.TotalGameTime - last).Milliseconds > 100)
|
||||
{
|
||||
last = gameTime.TotalGameTime;
|
||||
startalpha += 255 / 12;
|
||||
}
|
||||
|
||||
if ((gameTime.TotalGameTime - gt).TotalSeconds > 5) // close after 10 seconds
|
||||
{
|
||||
string strUsr = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
|
||||
|
||||
if (strUsr.Contains(@"\"))
|
||||
{
|
||||
int idx = strUsr.IndexOf(@"\") + 1;
|
||||
strUsr = strUsr.Substring(idx, strUsr.Length - idx);
|
||||
}
|
||||
|
||||
SignedInGamer sig = new SignedInGamer();
|
||||
sig.DisplayName = strUsr;
|
||||
sig.Gamertag = strUsr;
|
||||
|
||||
Gamer.SignedInGamers.Add(sig);
|
||||
|
||||
this.Visible = false;
|
||||
this.Enabled = false;
|
||||
//Guide.IsVisible = false;
|
||||
gt = TimeSpan.Zero;
|
||||
}
|
||||
base.Update(gameTime);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+327
@@ -0,0 +1,327 @@
|
||||
#region License
|
||||
/*
|
||||
Microsoft Public License (Ms-PL)
|
||||
MonoGame - Copyright © 2009 The MonoGame Team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
This license governs use of the accompanying software. If you use the software, you accept this license. If you do not
|
||||
accept the license, do not use the software.
|
||||
|
||||
1. Definitions
|
||||
The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under
|
||||
U.S. copyright law.
|
||||
|
||||
A "contribution" is the original software, or any additions or changes to the software.
|
||||
A "contributor" is any person that distributes its contribution under this license.
|
||||
"Licensed patents" are a contributor's patent claims that read directly on its contribution.
|
||||
|
||||
2. Grant of Rights
|
||||
(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3,
|
||||
each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
|
||||
(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3,
|
||||
each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
|
||||
|
||||
3. Conditions and Limitations
|
||||
(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
|
||||
(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software,
|
||||
your patent license from such contributor to the software ends automatically.
|
||||
(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution
|
||||
notices that are present in the software.
|
||||
(D) If you distribute any portion of the software in source code form, you may do so only under this license by including
|
||||
a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object
|
||||
code form, you may only do so under a license that complies with this license.
|
||||
(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees
|
||||
or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent
|
||||
permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular
|
||||
purpose and non-infringement.
|
||||
*/
|
||||
#endregion License
|
||||
|
||||
#region Statement
|
||||
using System;
|
||||
|
||||
#endregion Statement
|
||||
|
||||
|
||||
namespace Microsoft.Xna.Framework.GamerServices
|
||||
{
|
||||
public class SignedInGamer : Gamer
|
||||
{
|
||||
private AchievementCollection gamerAchievements;
|
||||
private FriendCollection friendCollection;
|
||||
|
||||
delegate void AuthenticationDelegate();
|
||||
|
||||
public IAsyncResult BeginAuthentication(AsyncCallback callback, Object asyncState)
|
||||
{
|
||||
// Go off authenticate
|
||||
AuthenticationDelegate ad = DoAuthentication;
|
||||
|
||||
return ad.BeginInvoke(callback, ad);
|
||||
}
|
||||
|
||||
public void EndAuthentication( IAsyncResult result )
|
||||
{
|
||||
AuthenticationDelegate ad = (AuthenticationDelegate)result.AsyncState;
|
||||
|
||||
ad.EndInvoke(result);
|
||||
}
|
||||
|
||||
private void DoAuthentication()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public SignedInGamer()
|
||||
{
|
||||
|
||||
var result = BeginAuthentication(null, null);
|
||||
EndAuthentication( result );
|
||||
}
|
||||
|
||||
private void AuthenticationCompletedCallback( IAsyncResult result )
|
||||
{
|
||||
EndAuthentication(result);
|
||||
}
|
||||
|
||||
#region Methods
|
||||
public FriendCollection GetFriends()
|
||||
{
|
||||
if(IsSignedInToLive)
|
||||
{
|
||||
if ( friendCollection == null )
|
||||
{
|
||||
friendCollection = new FriendCollection();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return friendCollection;
|
||||
}
|
||||
|
||||
public bool IsFriend (Gamer gamer)
|
||||
{
|
||||
if ( gamer == null )
|
||||
throw new ArgumentNullException();
|
||||
|
||||
if ( gamer.IsDisposed )
|
||||
throw new ObjectDisposedException(gamer.ToString());
|
||||
|
||||
bool found = false;
|
||||
foreach(FriendGamer f in friendCollection)
|
||||
{
|
||||
if ( f.Gamertag == gamer.Gamertag )
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
|
||||
}
|
||||
|
||||
delegate AchievementCollection GetAchievementsDelegate();
|
||||
|
||||
public IAsyncResult BeginGetAchievements( AsyncCallback callback, Object asyncState)
|
||||
{
|
||||
// Go off and grab achievements
|
||||
GetAchievementsDelegate gad = GetAchievements;
|
||||
|
||||
return gad.BeginInvoke(callback, gad);
|
||||
}
|
||||
|
||||
private void GetAchievementCompletedCallback( IAsyncResult result )
|
||||
{
|
||||
// get the delegate that was used to call that method
|
||||
GetAchievementsDelegate gad = (GetAchievementsDelegate)result.AsyncState;
|
||||
|
||||
// get the return value from that method call
|
||||
gamerAchievements = gad.EndInvoke(result);
|
||||
}
|
||||
|
||||
public AchievementCollection EndGetAchievements( IAsyncResult result )
|
||||
{
|
||||
GetAchievementsDelegate gad = (GetAchievementsDelegate)result.AsyncState;
|
||||
|
||||
gamerAchievements = gad.EndInvoke(result);
|
||||
|
||||
return gamerAchievements;
|
||||
}
|
||||
|
||||
public AchievementCollection GetAchievements()
|
||||
{
|
||||
if ( IsSignedInToLive )
|
||||
{
|
||||
if (gamerAchievements == null)
|
||||
{
|
||||
gamerAchievements = new AchievementCollection();
|
||||
}
|
||||
|
||||
}
|
||||
return gamerAchievements;
|
||||
}
|
||||
|
||||
delegate void AwardAchievementDelegate(string achievementId, double percentageComplete);
|
||||
|
||||
public IAsyncResult BeginAwardAchievement(string achievementId, AsyncCallback callback, Object state)
|
||||
{
|
||||
return BeginAwardAchievement(achievementId, 100.0, callback, state);
|
||||
}
|
||||
|
||||
public IAsyncResult BeginAwardAchievement(
|
||||
string achievementId,
|
||||
double percentageComplete,
|
||||
AsyncCallback callback,
|
||||
Object state
|
||||
)
|
||||
{
|
||||
// Go off and award the achievement
|
||||
AwardAchievementDelegate aad = DoAwardAchievement;
|
||||
|
||||
return aad.BeginInvoke(achievementId, percentageComplete, callback, aad);
|
||||
}
|
||||
|
||||
public void EndAwardAchievement(IAsyncResult result)
|
||||
{
|
||||
AwardAchievementDelegate aad = (AwardAchievementDelegate)result.AsyncState;
|
||||
|
||||
aad.EndInvoke(result);
|
||||
}
|
||||
|
||||
private void AwardAchievementCompletedCallback( IAsyncResult result )
|
||||
{
|
||||
EndAwardAchievement(result);
|
||||
}
|
||||
|
||||
public void AwardAchievement( string achievementId )
|
||||
{
|
||||
AwardAchievement(achievementId, 100.0f);
|
||||
}
|
||||
|
||||
public void DoAwardAchievement( string achievementId, double percentageComplete )
|
||||
{
|
||||
}
|
||||
|
||||
public void AwardAchievement( string achievementId, double percentageComplete )
|
||||
{
|
||||
if (IsSignedInToLive)
|
||||
{
|
||||
BeginAwardAchievement( achievementId, percentageComplete, AwardAchievementCompletedCallback, null );
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateScore( string aCategory, long aScore )
|
||||
{
|
||||
if (IsSignedInToLive)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetAchievements()
|
||||
{
|
||||
if (IsSignedInToLive)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
public GameDefaults GameDefaults
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsGuest
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSignedInToLive
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public int PartySize
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
set
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public PlayerIndex PlayerIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
return PlayerIndex.One;
|
||||
}
|
||||
}
|
||||
|
||||
public GamerPresence Presence
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
GamerPrivileges _privileges = new GamerPrivileges();
|
||||
public GamerPrivileges Privileges
|
||||
{
|
||||
get
|
||||
{
|
||||
return _privileges;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
protected virtual void OnSignedIn(SignedInEventArgs e)
|
||||
{
|
||||
EventHelpers.Raise(this, SignedIn, e);
|
||||
}
|
||||
|
||||
protected virtual void OnSignedOut(SignedOutEventArgs e)
|
||||
{
|
||||
EventHelpers.Raise(this, SignedOut, e);
|
||||
}
|
||||
|
||||
|
||||
#region Events
|
||||
public static event EventHandler<SignedInEventArgs> SignedIn;
|
||||
|
||||
public static event EventHandler<SignedOutEventArgs> SignedOut;
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class SignedInEventArgs : EventArgs
|
||||
{
|
||||
public SignedInEventArgs ( SignedInGamer gamer )
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class SignedOutEventArgs : EventArgs
|
||||
{
|
||||
public SignedOutEventArgs (SignedInGamer gamer )
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the orientation of the display.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum DisplayOrientation
|
||||
{
|
||||
/// <summary>
|
||||
/// The default orientation.
|
||||
/// </summary>
|
||||
Default = 0,
|
||||
/// <summary>
|
||||
/// The display is rotated counterclockwise into a landscape orientation. Width is greater than height.
|
||||
/// </summary>
|
||||
LandscapeLeft = 1,
|
||||
/// <summary>
|
||||
/// The display is rotated clockwise into a landscape orientation. Width is greater than height.
|
||||
/// </summary>
|
||||
LandscapeRight = 2,
|
||||
/// <summary>
|
||||
/// The display is rotated as portrait, where height is greater than width.
|
||||
/// </summary>
|
||||
Portrait = 4,
|
||||
/// <summary>
|
||||
/// The display is rotated as inverted portrait, where height is greater than width.
|
||||
/// </summary>
|
||||
PortraitDown = 8,
|
||||
/// <summary>
|
||||
/// Unknown display orientation.
|
||||
/// </summary>
|
||||
Unknown = 16
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework
|
||||
{
|
||||
public class DrawableGameComponent : GameComponent, IDrawable
|
||||
{
|
||||
private bool _initialized;
|
||||
private int _drawOrder;
|
||||
private bool _visible = true;
|
||||
|
||||
public Graphics.GraphicsDevice GraphicsDevice
|
||||
{
|
||||
get { return this.Game.GraphicsDevice; }
|
||||
}
|
||||
|
||||
public int DrawOrder
|
||||
{
|
||||
get { return _drawOrder; }
|
||||
set
|
||||
{
|
||||
if (_drawOrder != value)
|
||||
{
|
||||
_drawOrder = value;
|
||||
OnDrawOrderChanged(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Visible
|
||||
{
|
||||
get { return _visible; }
|
||||
set
|
||||
{
|
||||
if (_visible != value)
|
||||
{
|
||||
_visible = value;
|
||||
OnVisibleChanged(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<EventArgs> DrawOrderChanged;
|
||||
public event EventHandler<EventArgs> VisibleChanged;
|
||||
|
||||
public DrawableGameComponent(Game game)
|
||||
: base(game)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
_initialized = true;
|
||||
LoadContent();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void LoadContent() { }
|
||||
|
||||
protected virtual void UnloadContent () { }
|
||||
|
||||
public virtual void Draw(GameTime gameTime) { }
|
||||
|
||||
protected virtual void OnVisibleChanged(object sender, EventArgs args)
|
||||
{
|
||||
EventHelpers.Raise(sender, VisibleChanged, args);
|
||||
}
|
||||
|
||||
protected virtual void OnDrawOrderChanged(object sender, EventArgs args)
|
||||
{
|
||||
EventHelpers.Raise(sender, DrawOrderChanged, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides helper methods to make it easier
|
||||
/// to safely raise events.
|
||||
/// </summary>
|
||||
internal static class EventHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Safely raises an event by storing a copy of the event's delegate
|
||||
/// in the <paramref name="handler"/> parameter and checking it for
|
||||
/// null before invoking it.
|
||||
/// </summary>
|
||||
/// <typeparam name="TEventArgs"></typeparam>
|
||||
/// <param name="sender">The object raising the event.</param>
|
||||
/// <param name="handler"><see cref="EventHandler{TEventArgs}"/> to be invoked</param>
|
||||
/// <param name="e">The <typeparamref name="TEventArgs"/> passed to <see cref="EventHandler{TEventArgs}"/></param>
|
||||
internal static void Raise<TEventArgs>(object sender, EventHandler<TEventArgs> handler, TEventArgs e)
|
||||
where TEventArgs : EventArgs
|
||||
{
|
||||
if (handler != null)
|
||||
handler(sender, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Safely raises an event by storing a copy of the event's delegate
|
||||
/// in the <paramref name="handler"/> parameter and checking it for
|
||||
/// null before invoking it.
|
||||
/// </summary>
|
||||
/// <param name="sender">The object raising the event.</param>
|
||||
/// <param name="handler"><see cref="EventHandler"/> to be invoked</param>
|
||||
/// <param name="e">The <see cref="EventArgs"/> passed to <see cref="EventHandler"/></param>
|
||||
internal static void Raise(object sender, EventHandler handler, EventArgs e)
|
||||
{
|
||||
if (handler != null)
|
||||
handler(sender, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using Microsoft.Xna.Framework.Audio;
|
||||
|
||||
namespace Microsoft.Xna.Framework
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class for processing internal framework events.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If you use <see cref="Game"/> class, <see cref="Update()"/> is called automatically.
|
||||
/// Otherwise you must call it as part of your game loop.
|
||||
/// </remarks>
|
||||
public static class FrameworkDispatcher
|
||||
{
|
||||
private static bool _initialized = false;
|
||||
|
||||
/// <summary>
|
||||
/// Processes framework events.
|
||||
/// </summary>
|
||||
public static void Update()
|
||||
{
|
||||
if (!_initialized)
|
||||
Initialize();
|
||||
|
||||
DoUpdate();
|
||||
}
|
||||
|
||||
private static void DoUpdate()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private static void Initialize()
|
||||
{
|
||||
_initialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
namespace Microsoft.Xna.Framework
|
||||
{
|
||||
internal static class FrameworkResources
|
||||
{
|
||||
#region Error strings
|
||||
|
||||
internal const string ResourceCreationWhenDeviceIsNull = "The GraphicsDevice must not be null when creating new resources.";
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,92 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework
|
||||
{
|
||||
public class GameComponent : IGameComponent, IUpdateable, IComparable<GameComponent>, IDisposable
|
||||
{
|
||||
bool _enabled = true;
|
||||
int _updateOrder;
|
||||
|
||||
public Game Game { get; private set; }
|
||||
|
||||
public bool Enabled
|
||||
{
|
||||
get { return _enabled; }
|
||||
set
|
||||
{
|
||||
if (_enabled != value)
|
||||
{
|
||||
_enabled = value;
|
||||
OnEnabledChanged(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int UpdateOrder
|
||||
{
|
||||
get { return _updateOrder; }
|
||||
set
|
||||
{
|
||||
if (_updateOrder != value)
|
||||
{
|
||||
_updateOrder = value;
|
||||
OnUpdateOrderChanged(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<EventArgs> EnabledChanged;
|
||||
public event EventHandler<EventArgs> UpdateOrderChanged;
|
||||
|
||||
public GameComponent(Game game)
|
||||
{
|
||||
this.Game = game;
|
||||
}
|
||||
|
||||
~GameComponent()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public virtual void Initialize() { }
|
||||
|
||||
public virtual void Update(GameTime gameTime) { }
|
||||
|
||||
protected virtual void OnUpdateOrderChanged(object sender, EventArgs args)
|
||||
{
|
||||
EventHelpers.Raise(sender, UpdateOrderChanged, args);
|
||||
}
|
||||
|
||||
protected virtual void OnEnabledChanged(object sender, EventArgs args)
|
||||
{
|
||||
EventHelpers.Raise(sender, EnabledChanged, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shuts down the component.
|
||||
/// </summary>
|
||||
protected virtual void Dispose(bool disposing) { }
|
||||
|
||||
/// <summary>
|
||||
/// Shuts down the component.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
#region IComparable<GameComponent> Members
|
||||
// TODO: Should be removed, as it is not part of XNA 4.0
|
||||
public int CompareTo(GameComponent other)
|
||||
{
|
||||
return other.UpdateOrder - this.UpdateOrder;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Microsoft.Xna.Framework
|
||||
{
|
||||
public sealed class GameComponentCollection : Collection<IGameComponent>
|
||||
{
|
||||
/// <summary>
|
||||
/// Event that is triggered when a <see cref="GameComponent"/> is added
|
||||
/// to this <see cref="GameComponentCollection"/>.
|
||||
/// </summary>
|
||||
public event EventHandler<GameComponentCollectionEventArgs> ComponentAdded;
|
||||
|
||||
/// <summary>
|
||||
/// Event that is triggered when a <see cref="GameComponent"/> is removed
|
||||
/// from this <see cref="GameComponentCollection"/>.
|
||||
/// </summary>
|
||||
public event EventHandler<GameComponentCollectionEventArgs> ComponentRemoved;
|
||||
|
||||
/// <summary>
|
||||
/// Removes every <see cref="GameComponent"/> from this <see cref="GameComponentCollection"/>.
|
||||
/// Triggers <see cref="OnComponentRemoved"/> once for each <see cref="GameComponent"/> removed.
|
||||
/// </summary>
|
||||
protected override void ClearItems()
|
||||
{
|
||||
for (int i = 0; i < base.Count; i++)
|
||||
{
|
||||
this.OnComponentRemoved(new GameComponentCollectionEventArgs(base[i]));
|
||||
}
|
||||
base.ClearItems();
|
||||
}
|
||||
|
||||
protected override void InsertItem(int index, IGameComponent item)
|
||||
{
|
||||
if (base.IndexOf(item) != -1)
|
||||
{
|
||||
throw new ArgumentException("Cannot Add Same Component Multiple Times");
|
||||
}
|
||||
base.InsertItem(index, item);
|
||||
if (item != null)
|
||||
{
|
||||
this.OnComponentAdded(new GameComponentCollectionEventArgs(item));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnComponentAdded(GameComponentCollectionEventArgs eventArgs)
|
||||
{
|
||||
EventHelpers.Raise(this, ComponentAdded, eventArgs);
|
||||
}
|
||||
|
||||
private void OnComponentRemoved(GameComponentCollectionEventArgs eventArgs)
|
||||
{
|
||||
EventHelpers.Raise(this, ComponentRemoved, eventArgs);
|
||||
}
|
||||
|
||||
protected override void RemoveItem(int index)
|
||||
{
|
||||
IGameComponent gameComponent = base[index];
|
||||
base.RemoveItem(index);
|
||||
if (gameComponent != null)
|
||||
{
|
||||
this.OnComponentRemoved(new GameComponentCollectionEventArgs(gameComponent));
|
||||
}
|
||||
}
|
||||
|
||||
protected override void SetItem(int index, IGameComponent item)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework
|
||||
{
|
||||
public class GameComponentCollectionEventArgs : EventArgs
|
||||
{
|
||||
private IGameComponent _gameComponent;
|
||||
|
||||
public GameComponentCollectionEventArgs(IGameComponent gameComponent)
|
||||
{
|
||||
_gameComponent = gameComponent;
|
||||
}
|
||||
|
||||
public IGameComponent GameComponent
|
||||
{
|
||||
get
|
||||
{
|
||||
return _gameComponent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
#if WINDOWS_UAP
|
||||
using Windows.UI.ViewManagement;
|
||||
#endif
|
||||
|
||||
namespace Microsoft.Xna.Framework
|
||||
{
|
||||
partial class GamePlatform
|
||||
{
|
||||
internal static GamePlatform PlatformCreate(Game game)
|
||||
{
|
||||
#if DESKTOPGL || ANGLE || WINDOWS
|
||||
return new SdlGamePlatform(game);
|
||||
#elif WINDOWS_UAP
|
||||
return new UAPGamePlatform(game);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework
|
||||
{
|
||||
partial class GamePlatform
|
||||
{
|
||||
internal static GamePlatform PlatformCreate(Game game)
|
||||
{
|
||||
#if IOS
|
||||
return new iOSGamePlatform(game);
|
||||
#elif ANDROID
|
||||
return new AndroidGamePlatform(game);
|
||||
#elif WINDOWS_PHONE81
|
||||
return new MetroGamePlatform(game);
|
||||
#elif WEB
|
||||
return new WebGamePlatform(game);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using Microsoft.Xna.Framework.Input.Touch;
|
||||
|
||||
|
||||
namespace Microsoft.Xna.Framework
|
||||
{
|
||||
abstract partial class GamePlatform : IDisposable
|
||||
{
|
||||
#region Fields
|
||||
|
||||
protected TimeSpan _inactiveSleepTime = TimeSpan.FromMilliseconds(20.0);
|
||||
protected bool _needsToResetElapsedTime = false;
|
||||
bool disposed;
|
||||
protected bool InFullScreenMode = false;
|
||||
protected bool IsDisposed { get { return disposed; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Construction/Destruction
|
||||
|
||||
protected GamePlatform(Game game)
|
||||
{
|
||||
if (game == null)
|
||||
throw new ArgumentNullException("game");
|
||||
Game = game;
|
||||
}
|
||||
|
||||
~GamePlatform()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
#endregion Construction/Destruction
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// When implemented in a derived class, reports the default
|
||||
/// GameRunBehavior for this platform.
|
||||
/// </summary>
|
||||
public abstract GameRunBehavior DefaultRunBehavior { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Game instance that owns this GamePlatform instance.
|
||||
/// </summary>
|
||||
public Game Game
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
private bool _isActive;
|
||||
public bool IsActive
|
||||
{
|
||||
get { return _isActive; }
|
||||
internal set
|
||||
{
|
||||
if (_isActive != value)
|
||||
{
|
||||
_isActive = value;
|
||||
EventHelpers.Raise(this, _isActive ? Activated : Deactivated, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _isMouseVisible;
|
||||
public bool IsMouseVisible
|
||||
{
|
||||
get { return _isMouseVisible; }
|
||||
set
|
||||
{
|
||||
if (_isMouseVisible != value)
|
||||
{
|
||||
_isMouseVisible = value;
|
||||
OnIsMouseVisibleChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private GameWindow _window;
|
||||
public GameWindow Window
|
||||
{
|
||||
get { return _window; }
|
||||
|
||||
|
||||
protected set
|
||||
{
|
||||
if (_window == null)
|
||||
{
|
||||
Mouse.PrimaryWindow = value;
|
||||
TouchPanel.PrimaryWindow = value;
|
||||
}
|
||||
|
||||
_window = value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
public event EventHandler<EventArgs> AsyncRunLoopEnded;
|
||||
public event EventHandler<EventArgs> Activated;
|
||||
public event EventHandler<EventArgs> Deactivated;
|
||||
|
||||
/// <summary>
|
||||
/// Raises the AsyncRunLoopEnded event. This method must be called by
|
||||
/// derived classes when the asynchronous run loop they start has
|
||||
/// stopped running.
|
||||
/// </summary>
|
||||
protected void RaiseAsyncRunLoopEnded()
|
||||
{
|
||||
EventHelpers.Raise(this, AsyncRunLoopEnded, EventArgs.Empty);
|
||||
}
|
||||
|
||||
#endregion Events
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gives derived classes an opportunity to do work before any
|
||||
/// components are initialized. Note that the base implementation sets
|
||||
/// IsActive to true, so derived classes should either call the base
|
||||
/// implementation or set IsActive to true by their own means.
|
||||
/// </summary>
|
||||
public virtual void BeforeInitialize()
|
||||
{
|
||||
IsActive = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gives derived classes an opportunity to do work just before the
|
||||
/// run loop is begun. Implementations may also return false to prevent
|
||||
/// the run loop from starting.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual bool BeforeRun()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When implemented in a derived, ends the active run loop.
|
||||
/// </summary>
|
||||
public abstract void Exit();
|
||||
|
||||
/// <summary>
|
||||
/// When implemented in a derived, starts the run loop and blocks
|
||||
/// until it has ended.
|
||||
/// </summary>
|
||||
public abstract void RunLoop();
|
||||
|
||||
/// <summary>
|
||||
/// When implemented in a derived, starts the run loop and returns
|
||||
/// immediately.
|
||||
/// </summary>
|
||||
public abstract void StartRunLoop();
|
||||
|
||||
/// <summary>
|
||||
/// Gives derived classes an opportunity to do work just before Update
|
||||
/// is called for all IUpdatable components. Returning false from this
|
||||
/// method will result in this round of Update calls being skipped.
|
||||
/// </summary>
|
||||
/// <param name="gameTime"></param>
|
||||
/// <returns></returns>
|
||||
public abstract bool BeforeUpdate(GameTime gameTime);
|
||||
|
||||
/// <summary>
|
||||
/// Gives derived classes an opportunity to do work just before Draw
|
||||
/// is called for all IDrawable components. Returning false from this
|
||||
/// method will result in this round of Draw calls being skipped.
|
||||
/// </summary>
|
||||
/// <param name="gameTime"></param>
|
||||
/// <returns></returns>
|
||||
public abstract bool BeforeDraw(GameTime gameTime);
|
||||
|
||||
/// <summary>
|
||||
/// When implemented in a derived class, causes the game to enter
|
||||
/// full-screen mode.
|
||||
/// </summary>
|
||||
public abstract void EnterFullScreen();
|
||||
|
||||
/// <summary>
|
||||
/// When implemented in a derived class, causes the game to exit
|
||||
/// full-screen mode.
|
||||
/// </summary>
|
||||
public abstract void ExitFullScreen();
|
||||
|
||||
/// <summary>
|
||||
/// Gives derived classes an opportunity to modify
|
||||
/// Game.TargetElapsedTime before it is set.
|
||||
/// </summary>
|
||||
/// <param name="value">The proposed new value of TargetElapsedTime.</param>
|
||||
/// <returns>The new value of TargetElapsedTime that will be set.</returns>
|
||||
public virtual TimeSpan TargetElapsedTimeChanging(TimeSpan value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
/// <summary>
|
||||
/// Starts a device transition (windowed to full screen or vice versa).
|
||||
/// </summary>
|
||||
/// <param name='willBeFullScreen'>
|
||||
/// Specifies whether the device will be in full-screen mode upon completion of the change.
|
||||
/// </param>
|
||||
public abstract void BeginScreenDeviceChange (
|
||||
bool willBeFullScreen
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Completes a device transition.
|
||||
/// </summary>
|
||||
/// <param name='screenDeviceName'>
|
||||
/// Screen device name.
|
||||
/// </param>
|
||||
/// <param name='clientWidth'>
|
||||
/// The new width of the game's client window.
|
||||
/// </param>
|
||||
/// <param name='clientHeight'>
|
||||
/// The new height of the game's client window.
|
||||
/// </param>
|
||||
public abstract void EndScreenDeviceChange (
|
||||
string screenDeviceName,
|
||||
int clientWidth,
|
||||
int clientHeight
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Gives derived classes an opportunity to take action after
|
||||
/// Game.TargetElapsedTime has been set.
|
||||
/// </summary>
|
||||
public virtual void TargetElapsedTimeChanged() {}
|
||||
|
||||
/// <summary>
|
||||
/// MSDN: Use this method if your game is recovering from a slow-running state, and ElapsedGameTime is too large to be useful.
|
||||
/// Frame timing is generally handled by the Game class, but some platforms still handle it elsewhere. Once all platforms
|
||||
/// rely on the Game class's functionality, this method and any overrides should be removed.
|
||||
/// </summary>
|
||||
public virtual void ResetElapsedTime() {}
|
||||
|
||||
public virtual void Present() { }
|
||||
|
||||
protected virtual void OnIsMouseVisibleChanged() {}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the GraphicsDeviceManager to notify the platform
|
||||
/// that the presentation parameters have changed.
|
||||
/// </summary>
|
||||
/// <param name="pp">The new presentation parameters.</param>
|
||||
internal virtual void OnPresentationChanged(PresentationParameters pp)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
|
||||
#region IDisposable implementation
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing,
|
||||
/// releasing, or resetting unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposed)
|
||||
{
|
||||
Mouse.PrimaryWindow = null;
|
||||
TouchPanel.PrimaryWindow = null;
|
||||
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log the specified Message.
|
||||
/// </summary>
|
||||
/// <param name='Message'>
|
||||
///
|
||||
/// </param>
|
||||
[System.Diagnostics.Conditional("DEBUG")]
|
||||
public virtual void Log(string Message) {}
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// MonoGame - Copyright (C) The MonoGame Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
namespace Microsoft.Xna.Framework
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines how <see cref="Game"/> should be runned.
|
||||
/// </summary>
|
||||
public enum GameRunBehavior
|
||||
{
|
||||
/// <summary>
|
||||
/// The game loop will be runned asynchronous.
|
||||
/// </summary>
|
||||
Asynchronous,
|
||||
/// <summary>
|
||||
/// The game loop will be runned synchronous.
|
||||
/// </summary>
|
||||
Synchronous
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
// MIT License - Copyright (C) The Mono.Xna Team
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// file 'LICENSE.txt', which is part of this source code package.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MonoGame.Utilities;
|
||||
|
||||
namespace Microsoft.Xna.Framework
|
||||
{
|
||||
public class GameServiceContainer : IServiceProvider
|
||||
{
|
||||
Dictionary<Type, object> services;
|
||||
|
||||
public GameServiceContainer()
|
||||
{
|
||||
services = new Dictionary<Type, object>();
|
||||
}
|
||||
|
||||
public void AddService(Type type, object provider)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
if (provider == null)
|
||||
throw new ArgumentNullException("provider");
|
||||
if (!ReflectionHelpers.IsAssignableFrom(type, provider))
|
||||
throw new ArgumentException("The provider does not match the specified service type!");
|
||||
|
||||
services.Add(type, provider);
|
||||
}
|
||||
|
||||
public object GetService(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
object service;
|
||||
if (services.TryGetValue(type, out service))
|
||||
return service;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void RemoveService(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
services.Remove(type);
|
||||
}
|
||||
|
||||
public void AddService<T>(T provider)
|
||||
{
|
||||
AddService(typeof(T), provider);
|
||||
}
|
||||
|
||||
public T GetService<T>() where T : class
|
||||
{
|
||||
var service = GetService(typeof(T));
|
||||
|
||||
if (service == null)
|
||||
return null;
|
||||
|
||||
return (T)service;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user