#region License
#endregion
#region Using Statements
using
System;
using
System.Collections.Generic;
using
System.Runtime.InteropServices;
using
System.Text;
#endregion
namespace
Microsoft.Xna.Framework.Graphics
{
public
class
SpriteBatch : GraphicsResource
{
#region Private Constant Values
private
const
int
MAX_SPRITES = 2048;
private
const
int
MAX_VERTICES = MAX_SPRITES * 4;
private
const
int
MAX_INDICES = MAX_SPRITES * 6;
private
static
readonly
Vector2[] axisDirection =
new
Vector2[]
{
new
Vector2(-1, -1),
new
Vector2( 1, -1),
new
Vector2(-1, 1),
new
Vector2( 1, 1)
};
private
static
readonly
Vector2[] axisIsMirrored =
new
Vector2[]
{
new
Vector2(0, 0),
new
Vector2(1, 0),
new
Vector2(0, 1),
new
Vector2(1, 1)
};
private
static
readonly
float
[] CornerOffsetX =
new
float
[]
{
0.0f,
1.0f,
0.0f,
1.0f
};
private
static
readonly
float
[] CornerOffsetY =
new
float
[]
{
0.0f,
0.0f,
1.0f,
1.0f
};
#endregion
#region Private Variables
private
DynamicVertexBuffer vertexBuffer;
private
IndexBuffer indexBuffer;
private
VertexPositionColorTexture4[] vertexInfo;
private
Texture2D[] textureInfo;
private
Effect spriteEffect;
private
EffectParameter spriteMatrixTransform;
private
EffectPass spriteEffectPass;
private
bool
beginCalled;
private
SpriteSortMode sortMode;
private
BlendState blendState;
private
SamplerState samplerState;
private
DepthStencilState depthStencilState;
private
RasterizerState rasterizerState;
private
int
numSprites;
private
Matrix transformMatrix;
private
Effect customEffect;
#endregion
#region Private Static Variables
private
static
readonly
short
[] indexData = GenerateIndexArray();
private
static
readonly
byte
[] spriteEffectCode = Resources.SpriteEffect;
private
static
readonly
TextureComparer TextureCompare =
new
TextureComparer();
private
static
readonly
BackToFrontComparer BackToFrontCompare =
new
BackToFrontComparer();
private
static
readonly
FrontToBackComparer FrontToBackCompare =
new
FrontToBackComparer();
#endregion
#region Public Constructor
public
SpriteBatch(GraphicsDevice graphicsDevice)
{
if
(graphicsDevice ==
null
)
{
throw
new
ArgumentNullException(
"graphicsDevice"
);
}
GraphicsDevice = graphicsDevice;
vertexInfo =
new
VertexPositionColorTexture4[MAX_SPRITES];
textureInfo =
new
Texture2D[MAX_SPRITES];
vertexBuffer =
new
DynamicVertexBuffer(
graphicsDevice,
typeof
(VertexPositionColorTexture),
MAX_VERTICES,
BufferUsage.WriteOnly
);
indexBuffer =
new
IndexBuffer(
graphicsDevice,
IndexElementSize.SixteenBits,
MAX_INDICES,
BufferUsage.WriteOnly
);
indexBuffer.SetData(indexData);
spriteEffect =
new
Effect(
graphicsDevice,
spriteEffectCode
);
spriteMatrixTransform = spriteEffect.Parameters[
"MatrixTransform"
];
spriteEffectPass = spriteEffect.CurrentTechnique.Passes[0];
beginCalled =
false
;
numSprites = 0;
}
#endregion
#region Public Dispose Method
protected
override
void
Dispose(
bool
disposing)
{
if
(!IsDisposed && disposing)
{
spriteEffect.Dispose();
indexBuffer.Dispose();
vertexBuffer.Dispose();
}
base
.Dispose(disposing);
}
#endregion
#region Public Begin Methods
public
void
Begin()
{
Begin(
SpriteSortMode.Deferred,
BlendState.AlphaBlend,
SamplerState.LinearClamp,
DepthStencilState.None,
RasterizerState.CullCounterClockwise,
null
,
Matrix.Identity
);
}
public
void
Begin(
SpriteSortMode sortMode,
BlendState blendState
) {
Begin(
sortMode,
blendState,
SamplerState.LinearClamp,
DepthStencilState.None,
RasterizerState.CullCounterClockwise,
null
,
Matrix.Identity
);
}
public
void
Begin(
SpriteSortMode sortMode,
BlendState blendState,
SamplerState samplerState,
DepthStencilState depthStencilState,
RasterizerState rasterizerState
) {
Begin(
sortMode,
blendState,
samplerState,
depthStencilState,
rasterizerState,
null
,
Matrix.Identity
);
}
public
void
Begin(
SpriteSortMode sortMode,
BlendState blendState,
SamplerState samplerState,
DepthStencilState depthStencilState,
RasterizerState rasterizerState,
Effect effect
) {
Begin(
sortMode,
blendState,
samplerState,
depthStencilState,
rasterizerState,
effect,
Matrix.Identity
);
}
public
void
Begin(
SpriteSortMode sortMode,
BlendState blendState,
SamplerState samplerState,
DepthStencilState depthStencilState,
RasterizerState rasterizerState,
Effect effect,
Matrix transformationMatrix
) {
if
(beginCalled)
{
throw
new
InvalidOperationException(
"Begin has been called before calling End"
+
" after the last call to Begin."
+
" Begin cannot be called again until"
+
" End has been successfully called."
);
}
beginCalled =
true
;
this
.sortMode = sortMode;
this
.blendState = blendState ?? BlendState.AlphaBlend;
this
.samplerState = samplerState ?? SamplerState.LinearClamp;
this
.depthStencilState = depthStencilState ?? DepthStencilState.None;
this
.rasterizerState = rasterizerState ?? RasterizerState.CullCounterClockwise;
customEffect = effect;
transformMatrix = transformationMatrix;
if
(sortMode == SpriteSortMode.Immediate)
{
PrepRenderState();
}
}
#endregion
#region Public End Method
public
void
End()
{
if
(!beginCalled)
{
throw
new
InvalidOperationException(
"End was called, but Begin has not yet"
+
" been called. You must call Begin "
+
" successfully before you can call End."
);
}
beginCalled =
false
;
if
(sortMode != SpriteSortMode.Immediate)
{
FlushBatch();
}
customEffect =
null
;
}
#endregion
#region Public Draw Methods
public
void
Draw(
Texture2D texture,
Vector2 position,
Color color
) {
CheckBegin(
"Draw"
);
PushSprite(
texture,
null
,
new
Vector4(
position.X,
position.Y,
1.0f,
1.0f
),
color,
Vector2.Zero,
0.0f,
0.0f,
0,
false
);
}
public
void
Draw(
Texture2D texture,
Vector2 position,
Rectangle? sourceRectangle,
Color color
) {
CheckBegin(
"Draw"
);
PushSprite(
texture,
sourceRectangle,
new
Vector4(
position.X,
position.Y,
1.0f,
1.0f
),
color,
Vector2.Zero,
0.0f,
0.0f,
0,
false
);
}
public
void
Draw(
Texture2D texture,
Vector2 position,
Rectangle? sourceRectangle,
Color color,
float
rotation,
Vector2 origin,
float
scale,
SpriteEffects effects,
float
layerDepth
) {
CheckBegin(
"Draw"
);
PushSprite(
texture,
sourceRectangle,
new
Vector4(
position.X,
position.Y,
scale,
scale
),
color,
origin,
rotation,
layerDepth,
(
byte
) effects,
false
);
}
public
void
Draw(
Texture2D texture,
Vector2 position,
Rectangle? sourceRectangle,
Color color,
float
rotation,
Vector2 origin,
Vector2 scale,
SpriteEffects effects,
float
layerDepth
) {
CheckBegin(
"Draw"
);
PushSprite(
texture,
sourceRectangle,
new
Vector4(
position.X,
position.Y,
scale.X,
scale.Y
),
color,
origin,
rotation,
layerDepth,
(
byte
) effects,
false
);
}
public
void
Draw(
Texture2D texture,
Rectangle destinationRectangle,
Color color
) {
CheckBegin(
"Draw"
);
PushSprite(
texture,
null
,
new
Vector4(
destinationRectangle.X,
destinationRectangle.Y,
destinationRectangle.Width,
destinationRectangle.Height
),
color,
Vector2.Zero,
0.0f,
0.0f,
0,
true
);
}
public
void
Draw(
Texture2D texture,
Rectangle destinationRectangle,
Rectangle? sourceRectangle,
Color color
) {
CheckBegin(
"Draw"
);
PushSprite(
texture,
sourceRectangle,
new
Vector4(
destinationRectangle.X,
destinationRectangle.Y,
destinationRectangle.Width,
destinationRectangle.Height
),
color,
Vector2.Zero,
0.0f,
0.0f,
0,
true
);
}
public
void
Draw(
Texture2D texture,
Rectangle destinationRectangle,
Rectangle? sourceRectangle,
Color color,
float
rotation,
Vector2 origin,
SpriteEffects effects,
float
layerDepth
) {
CheckBegin(
"Draw"
);
PushSprite(
texture,
sourceRectangle,
new
Vector4(
destinationRectangle.X,
destinationRectangle.Y,
destinationRectangle.Width,
destinationRectangle.Height
),
color,
origin,
rotation,
layerDepth,
(
byte
) effects,
true
);
}
#endregion
#region Public DrawString Methods
public
void
DrawString(
SpriteFont spriteFont,
StringBuilder text,
Vector2 position,
Color color
) {
if
(text ==
null
)
{
throw
new
ArgumentNullException(
"text"
);
}
DrawString(
spriteFont,
text,
position,
color,
0.0f,
Vector2.Zero,
new
Vector2(1.0f),
SpriteEffects.None,
0.0f
);
}
public
void
DrawString(
SpriteFont spriteFont,
StringBuilder text,
Vector2 position,
Color color,
float
rotation,
Vector2 origin,
float
scale,
SpriteEffects effects,
float
layerDepth
) {
if
(text ==
null
)
{
throw
new
ArgumentNullException(
"text"
);
}
DrawString(
spriteFont,
text,
position,
color,
rotation,
origin,
new
Vector2(scale),
effects,
layerDepth
);
}
public
void
DrawString(
SpriteFont spriteFont,
StringBuilder text,
Vector2 position,
Color color,
float
rotation,
Vector2 origin,
Vector2 scale,
SpriteEffects effects,
float
layerDepth
) {
CheckBegin(
"DrawString"
);
if
(text ==
null
)
{
throw
new
ArgumentNullException(
"text"
);
}
if
(text.Length == 0)
{
return
;
}
Vector2 baseOffset = origin;
if
(effects != SpriteEffects.None)
{
baseOffset -= spriteFont.MeasureString(text) * axisIsMirrored[(
int
) effects];
}
Vector2 curOffset = Vector2.Zero;
bool
firstInLine =
true
;
for
(
int
i = 0; i < text.Length; i += 1)
{
char
c = text[i];
if
(c ==
'\r'
)
{
continue
;
}
if
(c ==
'\n'
)
{
curOffset.X = 0.0f;
curOffset.Y += spriteFont.LineSpacing;
firstInLine =
true
;
continue
;
}
int
index = spriteFont.characterMap.IndexOf(c);
if
(index == -1)
{
if
(!spriteFont.DefaultCharacter.HasValue)
{
throw
new
ArgumentException(
"Text contains characters that cannot be"
+
" resolved by this SpriteFont."
,
"text"
);
}
index = spriteFont.characterMap.IndexOf(
spriteFont.DefaultCharacter.Value
);
}
if
(firstInLine)
{
curOffset.X += Math.Abs(spriteFont.kerning[index].X);
firstInLine =
false
;
}
else
{
curOffset.X += spriteFont.Spacing + spriteFont.kerning[index].X;
}
Vector2 offset = baseOffset;
offset.X += (curOffset.X + spriteFont.croppingData[index].X) * axisDirection[(
int
) effects].X;
offset.Y += (curOffset.Y + spriteFont.croppingData[index].Y) * axisDirection[(
int
) effects].Y;
if
(effects != SpriteEffects.None)
{
offset +=
new
Vector2(
spriteFont.glyphData[index].Width,
spriteFont.glyphData[index].Height
) * axisIsMirrored[(
int
) effects];
}
PushSprite(
spriteFont.textureValue,
spriteFont.glyphData[index],
new
Vector4(
position.X,
position.Y,
scale.X,
scale.Y
),
color,
offset,
rotation,
layerDepth,
(
byte
) effects,
false
);
curOffset.X += spriteFont.kerning[index].Y + spriteFont.kerning[index].Z;
}
}
public
void
DrawString(
SpriteFont spriteFont,
string
text,
Vector2 position,
Color color
) {
DrawString(
spriteFont,
text,
position,
color,
0.0f,
Vector2.Zero,
new
Vector2(1.0f),
SpriteEffects.None,
0.0f
);
}
public
void
DrawString(
SpriteFont spriteFont,
string
text,
Vector2 position,
Color color,
float
rotation,
Vector2 origin,
float
scale,
SpriteEffects effects,
float
layerDepth
) {
DrawString(
spriteFont,
text,
position,
color,
rotation,
origin,
new
Vector2(scale),
effects,
layerDepth
);
}
public
void
DrawString(
SpriteFont spriteFont,
string
text,
Vector2 position,
Color color,
float
rotation,
Vector2 origin,
Vector2 scale,
SpriteEffects effects,
float
layerDepth
) {
CheckBegin(
"DrawString"
);
if
(text ==
null
)
{
throw
new
ArgumentNullException(
"text"
);
}
if
(text.Length == 0)
{
return
;
}
Vector2 baseOffset = origin;
if
(effects != SpriteEffects.None)
{
baseOffset -= spriteFont.MeasureString(text) * axisIsMirrored[(
int
) effects];
}
Vector2 curOffset = Vector2.Zero;
bool
firstInLine =
true
;
foreach
(
char
c
in
text)
{
if
(c ==
'\r'
)
{
continue
;
}
if
(c ==
'\n'
)
{
curOffset.X = 0.0f;
curOffset.Y += spriteFont.LineSpacing;
firstInLine =
true
;
continue
;
}
int
index = spriteFont.characterMap.IndexOf(c);
if
(index == -1)
{
if
(!spriteFont.DefaultCharacter.HasValue)
{
throw
new
ArgumentException(
"Text contains characters that cannot be"
+
" resolved by this SpriteFont."
,
"text"
);
}
index = spriteFont.characterMap.IndexOf(
spriteFont.DefaultCharacter.Value
);
}
if
(firstInLine)
{
curOffset.X += Math.Abs(spriteFont.kerning[index].X);
firstInLine =
false
;
}
else
{
curOffset.X += spriteFont.Spacing + spriteFont.kerning[index].X;
}
Vector2 offset = baseOffset;
offset.X += (curOffset.X + spriteFont.croppingData[index].X) * axisDirection[(
int
) effects].X;
offset.Y += (curOffset.Y + spriteFont.croppingData[index].Y) * axisDirection[(
int
) effects].Y;
if
(effects != SpriteEffects.None)
{
offset +=
new
Vector2(
spriteFont.glyphData[index].Width,
spriteFont.glyphData[index].Height
) * axisIsMirrored[(
int
) effects];
}
PushSprite(
spriteFont.textureValue,
spriteFont.glyphData[index],
new
Vector4(
position.X,
position.Y,
scale.X,
scale.Y
),
color,
offset,
rotation,
layerDepth,
(
byte
) effects,
false
);
curOffset.X += spriteFont.kerning[index].Y + spriteFont.kerning[index].Z;
}
}
#endregion
#region Private Methods
private
void
PushSprite(
Texture2D texture,
Rectangle? sourceRectangle,
Vector4 destination,
Color color,
Vector2 origin,
float
rotation,
float
depth,
byte
effects,
bool
destSizeInPixels
) {
if
(numSprites >= MAX_SPRITES)
{
FlushBatch();
}
float
sourceX, sourceY, sourceW, sourceH;
float
destW = destination.Z;
float
destH = destination.W;
float
originX, originY;
if
(sourceRectangle.HasValue)
{
float
inverseTexW = 1.0f / (
float
) texture.Width;
float
inverseTexH = 1.0f / (
float
) texture.Height;
sourceX = sourceRectangle.Value.X * inverseTexW;
sourceY = sourceRectangle.Value.Y * inverseTexH;
sourceW = Math.Max(
sourceRectangle.Value.Width,
MathHelper.MachineEpsilonFloat
) * inverseTexW;
sourceH = Math.Max(
sourceRectangle.Value.Height,
MathHelper.MachineEpsilonFloat
) * inverseTexH;
originX = (origin.X / sourceW) * inverseTexW;
originY = (origin.Y / sourceH) * inverseTexH;
if
(!destSizeInPixels)
{
destW *= sourceRectangle.Value.Width;
destH *= sourceRectangle.Value.Height;
}
}
else
{
sourceX = 0.0f;
sourceY = 0.0f;
sourceW = 1.0f;
sourceH = 1.0f;
originX = origin.X * (1.0f / (
float
) texture.Width);
originY = origin.Y * (1.0f / (
float
) texture.Height);
if
(!destSizeInPixels)
{
destW *= texture.Width;
destH *= texture.Height;
}
}
float
rotationMatrix1X;
float
rotationMatrix1Y;
float
rotationMatrix2X;
float
rotationMatrix2Y;
if
(!MathHelper.WithinEpsilon(rotation, 0.0f))
{
float
sin = (
float
) Math.Sin(rotation);
float
cos = (
float
) Math.Cos(rotation);
rotationMatrix1X = cos;
rotationMatrix1Y = sin;
rotationMatrix2X = -sin;
rotationMatrix2Y = cos;
}
else
{
rotationMatrix1X = 1.0f;
rotationMatrix1Y = 0.0f;
rotationMatrix2X = 0.0f;
rotationMatrix2Y = 1.0f;
}
float
cornerX = (CornerOffsetX[0] - originX) * destW;
float
cornerY = (CornerOffsetY[0] - originY) * destH;
vertexInfo[numSprites].Position0.X = (
(rotationMatrix2X * cornerY) +
(rotationMatrix1X * cornerX) +
destination.X
);
vertexInfo[numSprites].Position0.Y = (
(rotationMatrix2Y * cornerY) +
(rotationMatrix1Y * cornerX) +
destination.Y
);
cornerX = (CornerOffsetX[1] - originX) * destW;
cornerY = (CornerOffsetY[1] - originY) * destH;
vertexInfo[numSprites].Position1.X = (
(rotationMatrix2X * cornerY) +
(rotationMatrix1X * cornerX) +
destination.X
);
vertexInfo[numSprites].Position1.Y = (
(rotationMatrix2Y * cornerY) +
(rotationMatrix1Y * cornerX) +
destination.Y
);
cornerX = (CornerOffsetX[2] - originX) * destW;
cornerY = (CornerOffsetY[2] - originY) * destH;
vertexInfo[numSprites].Position2.X = (
(rotationMatrix2X * cornerY) +
(rotationMatrix1X * cornerX) +
destination.X
);
vertexInfo[numSprites].Position2.Y = (
(rotationMatrix2Y * cornerY) +
(rotationMatrix1Y * cornerX) +
destination.Y
);
cornerX = (CornerOffsetX[3] - originX) * destW;
cornerY = (CornerOffsetY[3] - originY) * destH;
vertexInfo[numSprites].Position3.X = (
(rotationMatrix2X * cornerY) +
(rotationMatrix1X * cornerX) +
destination.X
);
vertexInfo[numSprites].Position3.Y = (
(rotationMatrix2Y * cornerY) +
(rotationMatrix1Y * cornerX) +
destination.Y
);
vertexInfo[numSprites].TextureCoordinate0.X = (CornerOffsetX[0 ^ effects] * sourceW) + sourceX;
vertexInfo[numSprites].TextureCoordinate0.Y = (CornerOffsetY[0 ^ effects] * sourceH) + sourceY;
vertexInfo[numSprites].TextureCoordinate1.X = (CornerOffsetX[1 ^ effects] * sourceW) + sourceX;
vertexInfo[numSprites].TextureCoordinate1.Y = (CornerOffsetY[1 ^ effects] * sourceH) + sourceY;
vertexInfo[numSprites].TextureCoordinate2.X = (CornerOffsetX[2 ^ effects] * sourceW) + sourceX;
vertexInfo[numSprites].TextureCoordinate2.Y = (CornerOffsetY[2 ^ effects] * sourceH) + sourceY;
vertexInfo[numSprites].TextureCoordinate3.X = (CornerOffsetX[3 ^ effects] * sourceW) + sourceX;
vertexInfo[numSprites].TextureCoordinate3.Y = (CornerOffsetY[3 ^ effects] * sourceH) + sourceY;
vertexInfo[numSprites].Position0.Z = depth;
vertexInfo[numSprites].Position1.Z = depth;
vertexInfo[numSprites].Position2.Z = depth;
vertexInfo[numSprites].Position3.Z = depth;
vertexInfo[numSprites].Color0 = color;
vertexInfo[numSprites].Color1 = color;
vertexInfo[numSprites].Color2 = color;
vertexInfo[numSprites].Color3 = color;
if
(sortMode == SpriteSortMode.Immediate)
{
vertexBuffer.SetData(
0,
vertexInfo,
0,
1,
VertexPositionColorTexture4.RealStride,
SetDataOptions.None
);
DrawPrimitives(texture, 0, 1);
}
else
{
textureInfo[numSprites] = texture;
numSprites += 1;
}
}
private
void
FlushBatch()
{
int
offset = 0;
Texture2D curTexture =
null
;
PrepRenderState();
if
(numSprites == 0)
{
return
;
}
if
(sortMode == SpriteSortMode.Texture)
{
Array.Sort(
textureInfo,
vertexInfo,
0,
numSprites,
TextureCompare
);
}
else
if
(sortMode == SpriteSortMode.BackToFront)
{
Array.Sort(
vertexInfo,
textureInfo,
0,
numSprites,
BackToFrontCompare
);
}
else
if
(sortMode == SpriteSortMode.FrontToBack)
{
Array.Sort(
vertexInfo,
textureInfo,
0,
numSprites,
FrontToBackCompare
);
}
vertexBuffer.SetData(
0,
vertexInfo,
0,
numSprites,
VertexPositionColorTexture4.RealStride,
SetDataOptions.None
);
curTexture = textureInfo[0];
for
(
int
i = 0; i < numSprites; i += 1)
{
if
(textureInfo[i] != curTexture)
{
DrawPrimitives(curTexture, offset, i - offset);
curTexture = textureInfo[i];
offset = i;
}
}
DrawPrimitives(curTexture, offset, numSprites - offset);
numSprites = 0;
}
private
void
PrepRenderState()
{
GraphicsDevice.BlendState = blendState;
GraphicsDevice.SamplerStates[0] = samplerState;
GraphicsDevice.DepthStencilState = depthStencilState;
GraphicsDevice.RasterizerState = rasterizerState;
GraphicsDevice.SetVertexBuffer(vertexBuffer);
GraphicsDevice.Indices = indexBuffer;
Viewport viewport = GraphicsDevice.Viewport;
Matrix projection =
new
Matrix(
(
float
) (2.0 / (
double
) viewport.Width),
0.0f,
0.0f,
0.0f,
0.0f,
(
float
) (-2.0 / (
double
) viewport.Height),
0.0f,
0.0f,
0.0f,
0.0f,
1.0f,
0.0f,
-1.0f,
1.0f,
0.0f,
1.0f
);
Matrix.Multiply(
ref
transformMatrix,
ref
projection,
out
projection
);
spriteMatrixTransform.SetValue(projection);
spriteEffectPass.Apply();
}
private
void
DrawPrimitives(Texture texture,
int
baseSprite,
int
batchSize)
{
GraphicsDevice.Textures[0] = texture;
if
(customEffect !=
null
)
{
foreach
(EffectPass pass
in
customEffect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.DrawIndexedPrimitives(
PrimitiveType.TriangleList,
baseSprite * 4,
0,
batchSize * 4,
0,
batchSize * 2
);
}
}
else
{
GraphicsDevice.DrawIndexedPrimitives(
PrimitiveType.TriangleList,
baseSprite * 4,
0,
batchSize * 4,
0,
batchSize * 2
);
}
}
[System.Diagnostics.Conditional(
"DEBUG"
)]
private
void
CheckBegin(
string
method)
{
if
(!beginCalled)
{
throw
new
InvalidOperationException(
method +
" was called, but Begin has"
+
" not yet been called. Begin must be"
+
" called successfully before you can"
+
" call "
+ method +
"."
);
}
}
#endregion
#region Private Static Methods
private
static
short
[] GenerateIndexArray()
{
short
[] result =
new
short
[MAX_INDICES];
for
(
int
i = 0, j = 0; i < MAX_INDICES; i += 6, j += 4)
{
result[i] = (
short
) (j);
result[i + 1] = (
short
) (j + 1);
result[i + 2] = (
short
) (j + 2);
result[i + 3] = (
short
) (j + 3);
result[i + 4] = (
short
) (j + 2);
result[i + 5] = (
short
) (j + 1);
}
return
result;
}
#endregion
#region Private Sprite Data Container Class
[StructLayout(LayoutKind.Sequential, Pack = 1)]
private
struct
VertexPositionColorTexture4 : IVertexType
{
public
const
int
RealStride = 96;
VertexDeclaration IVertexType.VertexDeclaration
{
get
{
throw
new
NotImplementedException();
}
}
public
Vector3 Position0;
public
Color Color0;
public
Vector2 TextureCoordinate0;
public
Vector3 Position1;
public
Color Color1;
public
Vector2 TextureCoordinate1;
public
Vector3 Position2;
public
Color Color2;
public
Vector2 TextureCoordinate2;
public
Vector3 Position3;
public
Color Color3;
public
Vector2 TextureCoordinate3;
}
#endregion
#region Private Sprite Comparison Classes
private
class
TextureComparer : IComparer<Texture2D>
{
public
int
Compare(Texture2D x, Texture2D y)
{
return
x.GetHashCode().CompareTo(y.GetHashCode());
}
}
private
class
BackToFrontComparer : IComparer<VertexPositionColorTexture4>
{
public
int
Compare(VertexPositionColorTexture4 x, VertexPositionColorTexture4 y)
{
return
y.Position0.Z.CompareTo(x.Position0.Z);
}
}
private
class
FrontToBackComparer : IComparer<VertexPositionColorTexture4>
{
public
int
Compare(VertexPositionColorTexture4 x, VertexPositionColorTexture4 y)
{
return
x.Position0.Z.CompareTo(y.Position0.Z);
}
}
#endregion
}
}