SpriteBatch: fixed some issues with sizing when the sourceRectangle parameter was set

SpriteBatch/SpriteFonts: rendering of SpriteFonts is finished now
Added test cases for Vector2 static Transform
Added test cases for Matrix: CreateRotationX, CreateRotationY, CreateRotationZ, Multiply and CreateTranslation
Matrix: Fixed a bug in CreateRotationY (wrong result)
This commit is contained in:
Glatzemann 2011-11-02 16:01:05 +00:00
parent 1004432931
commit 593f33b541
8 changed files with 301 additions and 23 deletions

View File

@ -165,6 +165,60 @@ namespace ANX.Framework.TestCenter.Strukturen
ConvertEquals(xnaM1 * xnaM2, anxM1 * anxM2, "MultiplyOperator");
}
[Test, TestCaseSource("sixteenfloats")]
public void Multiply(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24, float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44)
{
XNAMatrix xnaM1 = new XNAMatrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44);
XNAMatrix xnaM2 = new XNAMatrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44);
ANXMatrix anxM1 = new ANXMatrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44);
ANXMatrix anxM2 = new ANXMatrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44);
ConvertEquals(XNAMatrix.Multiply(xnaM1, xnaM2), ANXMatrix.Multiply(anxM1, anxM2), "Multiply");
}
[Test, TestCaseSource("sixteenfloats")]
public void Multiply2(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24, float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44)
{
XNAMatrix xnaM1 = new XNAMatrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44);
XNAMatrix xnaM2 = new XNAMatrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44);
XNAMatrix xnaResult;
ANXMatrix anxM1 = new ANXMatrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44);
ANXMatrix anxM2 = new ANXMatrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44);
ANXMatrix anxResult;
XNAMatrix.Multiply(ref xnaM1, ref xnaM2, out xnaResult);
ANXMatrix.Multiply(ref anxM1, ref anxM2, out anxResult);
ConvertEquals(xnaResult, anxResult, "Multiply2");
}
[Test, TestCaseSource("sixteenfloats")]
public void Multiply3(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24, float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44)
{
XNAMatrix xnaM1 = new XNAMatrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44);
ANXMatrix anxM1 = new ANXMatrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44);
ConvertEquals(XNAMatrix.Multiply(xnaM1, m11), ANXMatrix.Multiply(anxM1, m11), "Multiply3");
}
[Test, TestCaseSource("sixteenfloats")]
public void Multiply4(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24, float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44)
{
XNAMatrix xnaM1 = new XNAMatrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44);
XNAMatrix xnaResult;
ANXMatrix anxM1 = new ANXMatrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44);
ANXMatrix anxResult;
XNAMatrix.Multiply(ref xnaM1, m11, out xnaResult);
ANXMatrix.Multiply(ref anxM1, m11, out anxResult);
ConvertEquals(xnaResult, anxResult, "Multiply4");
}
[Test, TestCaseSource("sixteenfloats")]
public void AddOperator(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24, float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44)
{
@ -201,5 +255,42 @@ namespace ANX.Framework.TestCenter.Strukturen
ConvertEquals(xnaM1 / xnaM2, anxM1 / anxM2, "DivideOperator");
}
[Test, TestCaseSource("sixteenfloats")]
public void CreateRotationX(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24, float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44)
{
XNAMatrix xnaMatrix = XNAMatrix.CreateRotationX(m11);
ANXMatrix anxMatrix = ANXMatrix.CreateRotationX(m11);
ConvertEquals(xnaMatrix, anxMatrix, "CreateRotationX");
}
[Test, TestCaseSource("sixteenfloats")]
public void CreateRotationY(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24, float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44)
{
XNAMatrix xnaMatrix = XNAMatrix.CreateRotationY(m11);
ANXMatrix anxMatrix = ANXMatrix.CreateRotationY(m11);
ConvertEquals(xnaMatrix, anxMatrix, "CreateRotationY");
}
[Test, TestCaseSource("sixteenfloats")]
public void CreateRotationZ(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24, float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44)
{
XNAMatrix xnaMatrix = XNAMatrix.CreateRotationZ(m11);
ANXMatrix anxMatrix = ANXMatrix.CreateRotationZ(m11);
ConvertEquals(xnaMatrix, anxMatrix, "CreateRotationZ");
}
[Test, TestCaseSource("sixteenfloats")]
public void CreateTranslation(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24, float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44)
{
XNAMatrix xnaMatrix = XNAMatrix.CreateTranslation(m11, m12, m13);
ANXMatrix anxMatrix = ANXMatrix.CreateTranslation(m11, m12, m13);
ConvertEquals(xnaMatrix, anxMatrix, "CreateTranslation");
}
}
}

View File

@ -4,11 +4,13 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using XNAVector2 = Microsoft.Xna.Framework.Vector2;
using ANXVector2 = ANX.Framework.Vector2;
using NUnit.Framework;
using XNAMatrix = Microsoft.Xna.Framework.Matrix;
using ANXMatrix = ANX.Framework.Matrix;
#endregion // Using Statements
@ -78,6 +80,19 @@ namespace ANX.Framework.TestCenter.Strukturen
}
}
public void ConvertEquals(ANXVector2 xna, ANXVector2 anx, String test)
{
//comparing string to catch "not defined" and "infinity" (which seems not to be equal)
if (anx.X.ToString().Equals(anx.X.ToString()) && anx.Y.ToString().Equals(anx.Y.ToString()))
{
Assert.Pass(test + " passed");
}
else
{
Assert.Fail(test + " failed: anx({" + xna.X + "}{" + xna.Y + "}) compared to anx({" + anx.X + "}{" + anx.Y + "})");
}
}
#endregion
#region Testdata
@ -526,6 +541,51 @@ namespace ANX.Framework.TestCenter.Strukturen
Assert.AreEqual(xnaR, anxR);
}
[Test, TestCaseSource("ninefloats")]
public void StaticTransform(float x1, float y1, float x2, float y2, float nop1, float nop2, float nop3, float nop4, float nop5)
{
XNAVector2 xna1 = new XNAVector2(x1, y1);
XNAVector2 xnaResult;
XNAMatrix xnaMatrix = XNAMatrix.CreateRotationX(nop1) * XNAMatrix.CreateRotationY(nop2) * XNAMatrix.CreateRotationZ(nop3) * XNAMatrix.CreateTranslation(nop4, nop5, nop1);
ANXVector2 anx1 = new ANXVector2(x1, y1);
ANXVector2 anxResult;
ANXMatrix anxMatrix = ANXMatrix.CreateRotationX(nop1) * ANXMatrix.CreateRotationY(nop2) * ANXMatrix.CreateRotationZ(nop3) * ANXMatrix.CreateTranslation(nop4, nop5, nop1);
XNAVector2.Transform(ref xna1, ref xnaMatrix, out xnaResult);
ANXVector2.Transform(ref anx1, ref anxMatrix, out anxResult);
ConvertEquals(xnaResult, anxResult, "StaticTransform");
}
[Test, TestCaseSource("ninefloats")]
public void StaticTransform2(float x1, float y1, float x2, float y2, float nop1, float nop2, float nop3, float nop4, float nop5)
{
XNAVector2 xna1 = new XNAVector2(x1, y1);
XNAMatrix xnaMatrix = XNAMatrix.CreateRotationX(nop1) * XNAMatrix.CreateRotationY(nop2) * XNAMatrix.CreateRotationZ(nop3) * XNAMatrix.CreateTranslation(nop4, nop5, nop1);
XNAVector2 xnaResult = XNAVector2.Transform(xna1, xnaMatrix);
ANXVector2 anx1 = new ANXVector2(x1, y1);
ANXMatrix anxMatrix = ANXMatrix.CreateRotationX(nop1) * ANXMatrix.CreateRotationY(nop2) * ANXMatrix.CreateRotationZ(nop3) * ANXMatrix.CreateTranslation(nop4, nop5, nop1);
ANXVector2 anxResult = ANXVector2.Transform(anx1, anxMatrix);
ConvertEquals(xnaResult, anxResult, "StaticTransform2");
}
[Test, TestCaseSource("ninefloats")]
public void StaticTransform3_ANXonly(float x1, float y1, float x2, float y2, float nop1, float nop2, float nop3, float nop4, float nop5)
{
ANXVector2 anx1 = new ANXVector2(x1, y1);
ANXMatrix anxMatrix = ANXMatrix.CreateRotationX(nop1) * ANXMatrix.CreateRotationY(nop2) * ANXMatrix.CreateRotationZ(nop3) * ANXMatrix.CreateTranslation(nop4, nop5, nop1);
ANXVector2 anxResult1 = ANXVector2.Transform(anx1, anxMatrix);
ANXVector2 anxResult2;
Vector2.Transform(ref anx1, ref anxMatrix, out anxResult2);
ConvertEquals(anxResult1, anxResult2, "StaticTransform3_ANXonly");
}
/*
public static Vector2 Transform(Vector2 position, Matrix matrix)
{

View File

@ -163,7 +163,7 @@ namespace ANX.Framework.Graphics
public void Draw(Texture2D texture, Rectangle destinationRectangle, Nullable<Rectangle> sourceRectangle, Color color, Single rotation, Vector2 origin, SpriteEffects effects, Single layerDepth)
{
Draw(texture, new Vector2(destinationRectangle.X, destinationRectangle.Y), new Vector2(destinationRectangle.Width, destinationRectangle.Height), sourceRectangle, color, origin, layerDepth, 0.0f, Vector2.One, effects);
Draw(texture, new Vector2(destinationRectangle.X, destinationRectangle.Y), new Vector2(destinationRectangle.Width, destinationRectangle.Height), sourceRectangle, color, origin, layerDepth, rotation, Vector2.One, effects);
}
public void Draw(Texture2D texture, Vector2 position, Color color)
@ -173,17 +173,20 @@ namespace ANX.Framework.Graphics
public void Draw(Texture2D texture, Vector2 position, Nullable<Rectangle> sourceRectangle, Color color)
{
Draw(texture, position, new Vector2(texture.Width, texture.Height), sourceRectangle, color, Vector2.Zero, 0.0f, 0.0f, Vector2.One, SpriteEffects.None);
Vector2 size = sourceRectangle.HasValue ? new Vector2(sourceRectangle.Value.Width, sourceRectangle.Value.Height) : new Vector2(texture.Width, texture.Height);
Draw(texture, position, size, sourceRectangle, color, Vector2.Zero, 0.0f, 0.0f, Vector2.One, SpriteEffects.None);
}
public void Draw(Texture2D texture, Vector2 position, Nullable<Rectangle> sourceRectangle, Color color, Single rotation, Vector2 origin, Single scale, SpriteEffects effects, Single layerDepth)
{
Draw(texture, position, new Vector2(texture.Width, texture.Height), sourceRectangle, color, origin, layerDepth, rotation, new Vector2(scale), effects);
Vector2 size = sourceRectangle.HasValue ? new Vector2(sourceRectangle.Value.Width, sourceRectangle.Value.Height) : new Vector2(texture.Width, texture.Height);
Draw(texture, position, size, sourceRectangle, color, origin, layerDepth, rotation, new Vector2(scale), effects);
}
public void Draw(Texture2D texture, Vector2 position, Nullable<Rectangle> sourceRectangle, Color color, Single rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, Single layerDepth)
{
Draw(texture, position, new Vector2(texture.Width, texture.Height), sourceRectangle, color, origin, layerDepth, rotation, scale, effects);
Vector2 size = sourceRectangle.HasValue ? new Vector2(sourceRectangle.Value.Width, sourceRectangle.Value.Height) : new Vector2(texture.Width, texture.Height);
Draw(texture, position, size, sourceRectangle, color, origin, layerDepth, rotation, scale, effects);
}
#endregion // Draw-Method

View File

@ -56,6 +56,7 @@ namespace ANX.Framework.Graphics
{
public sealed class SpriteFont
{
#region Private Members
private Texture2D texture;
private List<Rectangle> glyphs;
private List<Rectangle> cropping;
@ -64,8 +65,10 @@ namespace ANX.Framework.Graphics
private float horizontalSpacing;
private List<Vector3> kerning;
private char? defaultCharacter;
private ReadOnlyCollection<Char> characters;
#endregion // Private Members
public ReadOnlyCollection<Char> Characters
{
get { return characters; }
@ -98,7 +101,7 @@ namespace ANX.Framework.Graphics
internal SpriteFont(
Texture2D texture, List<Rectangle> glyphs, List<Rectangle> cropping, List<char> charMap,
Texture2D texture, List<Rectangle> glyphs, List<Rectangle> cropping, List<char> charMap,
int lineSpacing, float horizontalSpacing, List<Vector3> kerning, char? defaultCharacter)
{
this.texture = texture;
@ -120,7 +123,7 @@ namespace ANX.Framework.Graphics
throw new ArgumentNullException("text");
}
throw new NotImplementedException();
return InternalMeasure(ref text);
}
public Vector2 MeasureString(StringBuilder text)
@ -130,31 +133,141 @@ namespace ANX.Framework.Graphics
throw new ArgumentNullException("text");
}
throw new NotImplementedException();
String cachedText = text.ToString();
return InternalMeasure(ref cachedText);
}
internal void DrawString(ref String text, SpriteBatch spriteBatch, Vector2 position, Color color, Vector2 scale, Vector2 origin, float rotation, float layerDepth, SpriteEffects effects)
internal void DrawString(ref String text, SpriteBatch spriteBatch, Vector2 textPos, Color color, Vector2 scale, Vector2 origin, float rotation, float layerDepth, SpriteEffects effects)
{
int posX = (int)position.X;
int posY = (int)position.Y;
Matrix transformation = Matrix.CreateRotationZ(rotation) * Matrix.CreateTranslation(-origin.X * scale.X, -origin.Y * scale.Y, 0f);
int horizontalFlipModifier = 1;
float width = 0f;
Vector2 topLeft = new Vector2();
bool firstCharacterInLine = true;
if ((effects & SpriteEffects.FlipHorizontally) == SpriteEffects.FlipHorizontally)
{
topLeft.X = width = this.InternalMeasure(ref text).X * scale.X;
horizontalFlipModifier = -1;
}
if ((effects & SpriteEffects.FlipVertically) == SpriteEffects.FlipVertically)
{
topLeft.Y = (this.InternalMeasure(ref text).Y - this.lineSpacing) * scale.Y;
}
for (int i = 0; i < text.Length; i++)
{
char currentCharacter = text[i];
int characterIndex = GetIndexForCharacter(currentCharacter);
Vector3 kerning = this.kerning[characterIndex];
Rectangle glyphRect = this.glyphs[characterIndex];
Rectangle croppingRect = this.cropping[characterIndex];
switch (currentCharacter)
{
case '\r':
break;
posX += (int)(croppingRect.X);
posY = (int)(position.Y + croppingRect.Y);
case '\n':
firstCharacterInLine = true;
topLeft.X = width;
if ((effects & SpriteEffects.FlipVertically) == SpriteEffects.FlipVertically)
{
topLeft.Y -= this.lineSpacing * scale.Y;
}
else
{
topLeft.Y += this.lineSpacing * scale.Y;
}
break;
spriteBatch.Draw(this.texture, new Rectangle(posX, posY, glyphRect.Width, glyphRect.Height), glyphRect, color, 0.0f, origin, SpriteEffects.None, layerDepth);
default:
{
int characterIndex = GetIndexForCharacter(currentCharacter);
Vector3 kerning = this.kerning[characterIndex];
Rectangle glyphRect = this.glyphs[characterIndex];
Rectangle croppingRect = this.cropping[characterIndex];
posX += (int)(glyphRect.Width + this.Spacing + kerning.X);
if (firstCharacterInLine)
{
kerning.X = Math.Max(kerning.X, 0f);
}
else
{
topLeft.X += (this.Spacing * scale.X) * horizontalFlipModifier;
}
topLeft.X += (kerning.X * scale.X) * horizontalFlipModifier;
if ((effects & SpriteEffects.FlipVertically) == SpriteEffects.FlipVertically)
{
croppingRect.Y = (this.lineSpacing - glyphRect.Height) - croppingRect.Y;
}
if ((effects & SpriteEffects.FlipHorizontally) == SpriteEffects.FlipHorizontally)
{
croppingRect.X -= croppingRect.Width;
}
Vector2 position = Vector2.Transform(topLeft + (new Vector2(croppingRect.X, croppingRect.Y) * scale), transformation);
spriteBatch.Draw(this.texture, position + textPos, glyphRect, color, rotation, Vector2.Zero, scale, effects, layerDepth);
firstCharacterInLine = false;
topLeft.X += ((kerning.Y + kerning.Z) * scale.X) * horizontalFlipModifier;
break;
}
}
}
}
private Vector2 InternalMeasure(ref String text)
{
if (text.Length < 1)
{
return Vector2.Zero;
}
Vector2 size = Vector2.Zero;
size.Y = this.lineSpacing;
float maxWidth = 0f;
int currentCharacter = 0;
float z = 0f;
bool firstCharacterInLine = true;
for (int i = 0; i < text.Length; i++)
{
char currentChar = text[i];
if (currentChar == '\r')
{
continue;
}
if (currentChar == '\n')
{
size.X += Math.Max(z, 0f);
z = 0f;
maxWidth = Math.Max(size.X, maxWidth);
size = Vector2.Zero;
size.Y = this.lineSpacing;
firstCharacterInLine = true;
currentCharacter++;
}
else
{
int currentCharIndex = this.GetIndexForCharacter(currentChar);
Vector3 kerning = this.kerning[currentCharIndex];
if (firstCharacterInLine)
{
kerning.X = Math.Max(kerning.X, 0f);
}
else
{
size.X += this.Spacing + z;
}
size.X += kerning.X + kerning.Y;
z = kerning.Z;
size.Y = Math.Max(size.Y, (float)this.cropping[currentCharIndex].Height);
firstCharacterInLine = false;
}
}
size.Y += currentCharacter * this.lineSpacing;
size.X = Math.Max(Math.Max(z, 0) + size.X, maxWidth);
return size;
}
private int GetIndexForCharacter(char character)
{
int currentIndex = 0;

View File

@ -936,7 +936,8 @@ namespace ANX.Framework
{
result = Matrix.Identity;
result.M11 = (float)Math.Cos(radians);
result.M13 = (float)Math.Sin(radians);
result.M13 = (float)-Math.Sin(radians);
result.M22 = 1f;
result.M31 = -result.M13;
result.M33 = result.M11;
}

View File

@ -77,6 +77,13 @@
<Processor>FontDescriptionProcessor</Processor>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Include="Textures\Test_100x100.png">
<Name>Test_100x100</Name>
<Importer>TextureImporter</Importer>
<Processor>TextureProcessor</Processor>
</Compile>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\$(XnaFrameworkVersion)\Microsoft.Xna.GameStudio.ContentPipeline.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -103,8 +103,11 @@ namespace TextRendering
spriteBatch.Begin(SpriteSortMode.FrontToBack, null);
spriteBatch.DrawString(this.debugFont, "Hello World!", new Vector2(100, 100), Color.White);
spriteBatch.DrawString(this.debugFont, "This screen is powered by the ANX.Framework!", new Vector2( 99, 101 + this.debugFont.LineSpacing), Color.Black, 0.0f, Vector2.Zero, Vector2.One, SpriteEffects.None, 0.0f);
spriteBatch.DrawString(this.debugFont, "This screen is powered by the ANX.Framework!", new Vector2(100, 100 + this.debugFont.LineSpacing), Color.Red, 0.0f, Vector2.Zero, Vector2.One, SpriteEffects.None, 1.0f);
spriteBatch.DrawString(this.debugFont, "This screen is powered by the ANX.Framework!\r\nsecond line", new Vector2(100, 100 + this.debugFont.LineSpacing), Color.Black, 0.0f, new Vector2(1, -1), Vector2.One, SpriteEffects.None, 0.0f);
spriteBatch.DrawString(this.debugFont, "This screen is powered by the ANX.Framework!\r\nsecond line", new Vector2(100, 100 + this.debugFont.LineSpacing), Color.Red, 0.0f, Vector2.Zero, Vector2.One, SpriteEffects.None, 1.0f);
spriteBatch.DrawString(this.debugFont, "rotated Text", new Vector2(100, 150), Color.Green, MathHelper.ToRadians(90), Vector2.Zero, 1.0f, SpriteEffects.None, 1.0f);
spriteBatch.End();
base.Draw(gameTime);