- Implemented the SkinnedEffect class (not tested yet, sample will come soon)

- Optimizations in the SpriteBatch and SpriteFont classes
This commit is contained in:
SND\AstrorEnales_cp 2012-09-11 13:51:20 +00:00
parent 8b735c16c2
commit 7350ca3d3a
10 changed files with 879 additions and 706 deletions

View File

@ -67,6 +67,8 @@ namespace ANX.Framework.Graphics
{
this.width = width;
this.height = height;
OneOverWidth = 1f / width;
OneOverHeight = 1f / height;
base.levelCount = 1;
base.format = SurfaceFormat.Color;

View File

@ -1,34 +1,189 @@
#region Using Statements
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ANX.Framework.NonXNA;
using ANX.Framework.Graphics;
#endregion // Using Statements
using ANX.Framework.NonXNA.Development;
// This file is part of the ANX.Framework created by the
// "ANX.Framework developer group" and released under the Ms-PL license.
// For details see: http://anxframework.codeplex.com/license
namespace ANX.Framework.Graphics
{
[PercentageComplete(100)]
[TestState(TestStateAttribute.TestState.Untested)]
[Developer("AstrorEnales")]
public class SkinnedEffect : Effect, IEffectMatrices, IEffectLights, IEffectFog
{
{
public const int MaxBones = 72;
#region Private
private Matrix world;
private Matrix view;
private Matrix projection;
private bool preferPerPixelLighting;
private bool isFogEnabled;
private Vector3 diffuseColor;
private Vector3 specularColor;
private Vector3 fogColor;
private Vector3 emissiveColor;
private Vector3 ambientLightColor;
private Matrix[] bones;
private int weightsPerBone;
#endregion
#region Public
public float FogEnd { get; set; }
public float FogStart { get; set; }
public Texture2D Texture { get; set; }
public float Alpha { get; set; }
public float SpecularPower { get; set; }
public DirectionalLight DirectionalLight0 { get; private set; }
public DirectionalLight DirectionalLight1 { get; private set; }
public DirectionalLight DirectionalLight2 { get; private set; }
public int WeightsPerVertex
{
get
{
return weightsPerBone;
}
set
{
if (value != 1 && value != 2 && value != 4)
throw new ArgumentOutOfRangeException("Weights per bone only allows 1, 2 or 4 as value!");
weightsPerBone = value;
}
}
public bool PreferPerPixelLighting
{
get { return preferPerPixelLighting; }
set
{
preferPerPixelLighting = value;
SelectTechnique();
}
}
public Matrix Projection
{
get { return projection; }
set { projection = value; }
}
public Matrix View
{
get { return view; }
set { view = value; }
}
public Matrix World
{
get { return world; }
set { world = value; }
}
public Vector3 AmbientLightColor
{
get { return ambientLightColor; }
set { ambientLightColor = value; }
}
public bool LightingEnabled
{
get { return true; }
set
{
if (value == false)
throw new NotSupportedException("SkinnedEffect without Lighting isn't supported!");
}
}
public Vector3 FogColor
{
get { return fogColor; }
set { fogColor = value; }
}
public bool FogEnabled
{
get { return isFogEnabled; }
set
{
isFogEnabled = value;
SelectTechnique();
}
}
public Vector3 DiffuseColor
{
get { return diffuseColor; }
set { diffuseColor = value; }
}
public Vector3 EmissiveColor
{
get { return emissiveColor; }
set { emissiveColor = value; }
}
public Vector3 SpecularColor
{
get { return specularColor; }
set { specularColor = value; }
}
#endregion
#region Constructor
public SkinnedEffect(GraphicsDevice graphics)
: base(graphics, GetByteCode(), GetSourceLanguage())
{
throw new NotImplementedException();
{
world = Matrix.Identity;
view = Matrix.Identity;
projection = Matrix.Identity;
FogStart = 0f;
FogEnd = 1f;
Alpha = 1f;
diffuseColor = Vector3.One;
ambientLightColor = Vector3.One;
emissiveColor = Vector3.One;
specularColor = Vector3.One;
SpecularPower = 16f;
WeightsPerVertex = 4;
CreateLights(null);
DirectionalLight0.Enabled = true;
bones = new Matrix[MaxBones];
for (int index = 0; index < MaxBones; index++)
bones[index] = Matrix.Identity;
SelectTechnique();
}
protected SkinnedEffect(SkinnedEffect cloneSource)
: base(cloneSource)
{
throw new NotImplementedException();
{
world = cloneSource.world;
view = cloneSource.view;
projection = cloneSource.projection;
preferPerPixelLighting = cloneSource.preferPerPixelLighting;
isFogEnabled = cloneSource.isFogEnabled;
diffuseColor = cloneSource.diffuseColor;
specularColor = cloneSource.specularColor;
fogColor = cloneSource.fogColor;
emissiveColor = cloneSource.emissiveColor;
ambientLightColor = cloneSource.ambientLightColor;
FogEnd = cloneSource.FogEnd;
FogStart = cloneSource.FogStart;
Texture = cloneSource.Texture;
SpecularPower = cloneSource.SpecularPower;
Alpha = cloneSource.Alpha;
WeightsPerVertex = cloneSource.WeightsPerVertex;
for (int index = 0; index < MaxBones; index++)
bones[index] = cloneSource.bones[index];
CreateLights(cloneSource);
SelectTechnique();
}
#endregion
#region GetByteCode
private static byte[] GetByteCode()
@ -46,245 +201,186 @@ namespace ANX.Framework.Graphics
}
#endregion
public override Effect Clone()
#region Clone
public override Effect Clone()
{
return new SkinnedEffect(this);
}
}
#endregion
public const int MaxBones = 72;
#region CreateLights
private void CreateLights(SkinnedEffect cloneSource)
{
DirectionalLight0 = new DirectionalLight(Parameters["DirLight0Direction"], Parameters["DirLight0DiffuseColor"],
null, (cloneSource != null) ? cloneSource.DirectionalLight0 : null);
DirectionalLight1 = new DirectionalLight(Parameters["DirLight1Direction"], Parameters["DirLight1DiffuseColor"],
null, (cloneSource != null) ? cloneSource.DirectionalLight1 : null);
DirectionalLight2 = new DirectionalLight(Parameters["DirLight2Direction"], Parameters["DirLight2DiffuseColor"],
null, (cloneSource != null) ? cloneSource.DirectionalLight2 : null);
}
#endregion
public bool PreferPerPixelLighting
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
#region EnableDefaultLighting
public void EnableDefaultLighting()
{
LightingEnabled = true;
ambientLightColor = new Vector3(0.05333332f, 0.09882354f, 0.1819608f);
public Matrix Projection
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
DirectionalLight0.Direction = new Vector3(-0.5265408f, -0.5735765f, -0.6275069f);
DirectionalLight0.DiffuseColor = new Vector3(1f, 0.9607844f, 0.8078432f);
DirectionalLight0.SpecularColor = DirectionalLight0.DiffuseColor;
DirectionalLight0.Enabled = true;
public Matrix View
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
DirectionalLight1.Direction = new Vector3(0.7198464f, 0.3420201f, 0.6040227f);
DirectionalLight1.DiffuseColor = new Vector3(0.9647059f, 0.7607844f, 0.4078432f);
DirectionalLight1.SpecularColor = Vector3.Zero;
DirectionalLight1.Enabled = true;
public Matrix World
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
DirectionalLight2.Direction = new Vector3(0.4545195f, -0.7660444f, 0.4545195f);
DirectionalLight2.DiffuseColor = new Vector3(0.3231373f, 0.3607844f, 0.3937255f);
DirectionalLight2.SpecularColor = DirectionalLight2.DiffuseColor;
DirectionalLight2.Enabled = true;
}
#endregion
public void EnableDefaultLighting()
{
throw new NotImplementedException();
}
#region GetBoneTransforms
public Matrix[] GetBoneTransforms(int count)
{
if (count <= 0)
throw new ArgumentOutOfRangeException("count");
if (count > 72)
throw new ArgumentException("The maximum number of allowed bones for the SkinnedEffect is " + MaxBones + "!");
public Vector3 AmbientLightColor
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
var result = new Matrix[MaxBones];
for (int index = 0; index < MaxBones; index++)
{
result[index] = bones[index];
}
return result;
}
#endregion
public DirectionalLight DirectionalLight0
{
get { throw new NotImplementedException(); }
}
#region SetBoneTransforms
public void SetBoneTransforms(Matrix[] boneTransforms)
{
if (boneTransforms == null || boneTransforms.Length == 0)
throw new ArgumentNullException("boneTransforms");
public DirectionalLight DirectionalLight1
{
get { throw new NotImplementedException(); }
}
if (boneTransforms.Length > 72)
throw new ArgumentException("The maximum number of allowed bones for the SkinnedEffect is " + MaxBones + "!");
public DirectionalLight DirectionalLight2
{
get { throw new NotImplementedException(); }
}
for (int index = 0; index < MaxBones; index++)
bones[index] = index < boneTransforms.Length ? boneTransforms[index] : Matrix.Identity;
}
#endregion
public bool LightingEnabled
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
#region PreBindSetParameters
internal override void PreBindSetParameters()
{
Matrix worldView;
Matrix.Multiply(ref world, ref view, out worldView);
Matrix wvp;
Matrix.Multiply(ref worldView, ref projection, out wvp);
Parameters["WorldViewProj"].SetValue(wvp);
public Vector3 FogColor
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
SetLightingMatrices();
SetMaterialColor();
public bool FogEnabled
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
Parameters["Bones"].SetValue(bones);
public float FogEnd
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
Parameters["FogColor"].SetValue(fogColor);
Parameters["SpecularPower"].SetValue(SpecularPower);
Parameters["SpecularColor"].SetValue(specularColor);
public float FogStart
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
if (Texture != null)
Parameters["Texture"].SetValue(Texture);
public Texture2D Texture
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
if (isFogEnabled)
SetFogVector(ref worldView);
else
Parameters["FogVector"].SetValue(Vector4.Zero);
public int WeightsPerVertex
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
SelectTechnique();
}
#endregion
public Vector3 DiffuseColor
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
#region SelectTechnique
private void SelectTechnique()
{
string name = "";
if (WeightsPerVertex == 1)
name = "OneBone";
else if (WeightsPerVertex == 2)
name = "TwoBones";
else if (WeightsPerVertex == 4)
name = "FourBones";
public Vector3 EmissiveColor
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
bool oneLight = DirectionalLight1.Enabled == false && DirectionalLight2.Enabled == false;
if (preferPerPixelLighting)
name += "PixelLighting";
else if (oneLight)
name += "OneLight";
else
name += "VertexLighting";
public Vector3 SpecularColor
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
if (isFogEnabled == false)
name += "NoFog";
public float SpecularPower
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
CurrentTechnique = Techniques[name];
}
#endregion
public float Alpha
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
#region SetLightingMatrices
private void SetLightingMatrices()
{
Matrix worldInverse;
Matrix.Invert(ref world, out worldInverse);
Matrix worldInverseTranspose;
Matrix.Transpose(ref worldInverse, out worldInverseTranspose);
public Matrix[] GetBoneTransforms(int count)
{
throw new NotImplementedException();
}
Parameters["World"].SetValue(world);
Parameters["WorldInverseTranspose"].SetValue(worldInverseTranspose);
public void SetBoneTransforms(Matrix[] boneTransforms)
{
throw new NotImplementedException();
}
Matrix viewInverse;
Matrix.Invert(ref view, out viewInverse);
Parameters["EyePosition"].SetValue(viewInverse.Translation);
}
#endregion
#region SetMaterialColor
private void SetMaterialColor()
{
Vector4 diffuse;
diffuse.X = diffuseColor.X * Alpha;
diffuse.Y = diffuseColor.Y * Alpha;
diffuse.Z = diffuseColor.Z * Alpha;
diffuse.W = Alpha;
Vector3 emissive;
emissive.X = (emissiveColor.X + ambientLightColor.X * diffuseColor.X) * Alpha;
emissive.Y = (emissiveColor.Y + ambientLightColor.Y * diffuseColor.Y) * Alpha;
emissive.Z = (emissiveColor.Z + ambientLightColor.Z * diffuseColor.Z) * Alpha;
Parameters["DiffuseColor"].SetValue(diffuse);
Parameters["EmissiveColor"].SetValue(emissive);
}
#endregion
#region SetFogVector
private void SetFogVector(ref Matrix worldView)
{
if (FogStart == FogEnd)
{
Parameters["FogVector"].SetValue(new Vector4(0f, 0f, 0f, 1f));
return;
}
float fogFactor = 1f / (FogStart - FogEnd);
Vector4 value;
value.X = worldView.M13 * fogFactor;
value.Y = worldView.M23 * fogFactor;
value.Z = worldView.M33 * fogFactor;
value.W = (worldView.M43 + FogStart) * fogFactor;
Parameters["FogVector"].SetValue(value);
}
#endregion
}
}

View File

@ -1,10 +1,8 @@
#region Using Statements
using System;
using System.Collections.Generic;
using System.Text;
using ANX.Framework.NonXNA;
#endregion // Using Statements
using ANX.Framework.NonXNA.Development;
// This file is part of the ANX.Framework created by the
// "ANX.Framework developer group" and released under the Ms-PL license.
@ -12,11 +10,14 @@ using ANX.Framework.NonXNA;
namespace ANX.Framework.Graphics
{
[PercentageComplete(100)]
[TestState(TestStateAttribute.TestState.Untested)]
[Developer("Glatzemann, AstrorEnales")]
public class SpriteBatch : GraphicsResource
{
#region Private Members
private const int InitialBatchSize = 1024;
{
private const int InitialBatchSize = 1024;
#region Private
private Effect spriteBatchEffect;
private bool hasBegun;
private SpriteSortMode currentSortMode;
@ -43,8 +44,7 @@ namespace ANX.Framework.Graphics
private static TextureComparer textureComparer = new TextureComparer();
private static FrontToBackComparer frontToBackComparer = new FrontToBackComparer();
private static BackToFrontComparer backToFrontComparer = new BackToFrontComparer();
#endregion // Private Members
#endregion
#region Constructor
public SpriteBatch(GraphicsDevice graphicsDevice)
@ -55,43 +55,55 @@ namespace ANX.Framework.Graphics
base.GraphicsDevice = graphicsDevice;
var renderSystemCreator = AddInSystemFactory.Instance.GetDefaultCreator<IRenderSystemCreator>();
this.spriteBatchEffect = new Effect(graphicsDevice, renderSystemCreator.GetShaderByteCode(NonXNA.PreDefinedShader.SpriteBatch), renderSystemCreator.GetStockShaderSourceLanguage);
this.spriteBatchEffect = new Effect(graphicsDevice,
renderSystemCreator.GetShaderByteCode(NonXNA.PreDefinedShader.SpriteBatch),
renderSystemCreator.GetStockShaderSourceLanguage);
this.spriteInfos = new SpriteInfo[InitialBatchSize];
this.InitializeIndexBuffer(InitialBatchSize);
this.InitializeVertexBuffer();
}
#endregion
#region Begin-Method
#region Begin
public void Begin()
{
Begin(SpriteSortMode.Texture, null, null, null, null, null, Matrix.Identity);
Begin(SpriteSortMode.Texture, null, null, null, null, null);
}
public void Begin(SpriteSortMode sortMode, BlendState blendState)
{
Begin(sortMode, blendState, null, null, null, null, Matrix.Identity);
Begin(sortMode, blendState, null, null, null, null);
}
public void Begin(SpriteSortMode sortMode, BlendState blendState, SamplerState samplerState, DepthStencilState depthStencilState, RasterizerState rasterizerState)
public void Begin(SpriteSortMode sortMode, BlendState blendState, SamplerState samplerState,
DepthStencilState depthStencilState, RasterizerState rasterizerState)
{
Begin(sortMode, blendState, samplerState, depthStencilState, rasterizerState, null, Matrix.Identity);
Begin(sortMode, blendState, samplerState, depthStencilState, rasterizerState, null);
}
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)
{
if (hasBegun == true)
throw new Exception("End() has to be called before a new SpriteBatch can be started with Begin()");
hasBegun = true;
this.currentSortMode = sortMode;
this.blendState = blendState;
this.samplerState = samplerState;
this.depthStencilState = depthStencilState;
this.rasterizerState = rasterizerState;
this.effect = effect;
this.transformMatrix = Matrix.Identity;
}
public void Begin(SpriteSortMode sortMode, BlendState blendState, SamplerState samplerState, DepthStencilState depthStencilState, RasterizerState rasterizerState, Effect effect, Matrix transformMatrix)
public void Begin(SpriteSortMode sortMode, BlendState blendState, SamplerState samplerState,
DepthStencilState depthStencilState, RasterizerState rasterizerState, Effect effect, Matrix transformMatrix)
{
if (this.hasBegun == true)
{
if (hasBegun == true)
throw new Exception("End() has to be called before a new SpriteBatch can be started with Begin()");
}
hasBegun = true;
@ -104,150 +116,186 @@ namespace ANX.Framework.Graphics
this.effect = effect;
this.transformMatrix = transformMatrix;
}
#endregion
#endregion // Begin-Method
#region Draw
public void Draw(Texture2D texture, Rectangle destinationRectangle, Color color)
{
Draw(texture, new Vector2(destinationRectangle.X, destinationRectangle.Y), new Vector2(destinationRectangle.Width,
destinationRectangle.Height), null, color, Vector2.Zero, 0f, 0f, Vector2.One, SpriteEffects.None);
}
#region Draw-Method
public void Draw (Texture2D texture, Rectangle destinationRectangle, Color color)
public void Draw(Texture2D texture, Rectangle destinationRectangle, Nullable<Rectangle> sourceRectangle, Color color)
{
Draw(texture, new Vector2(destinationRectangle.X, destinationRectangle.Y), new Vector2(destinationRectangle.Width,
destinationRectangle.Height), sourceRectangle, color, Vector2.Zero, 0f, 0f, Vector2.One, SpriteEffects.None);
}
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), null, color, Vector2.Zero, 0.0f, 0.0f, Vector2.One, SpriteEffects.None);
}
public void Draw (Texture2D texture, Rectangle destinationRectangle, Nullable<Rectangle> sourceRectangle, Color color)
{
Draw(texture, new Vector2(destinationRectangle.X, destinationRectangle.Y), new Vector2(destinationRectangle.Width, destinationRectangle.Height), sourceRectangle, color, Vector2.Zero, 0.0f, 0.0f, Vector2.One, SpriteEffects.None);
}
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, rotation, 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)
{
Draw(texture, position, new Vector2(texture.Width, texture.Height), null, color, Vector2.Zero, 0.0f, 0.0f, Vector2.One, SpriteEffects.None);
Draw(texture, position, new Vector2(texture.Width, texture.Height), null, color, Vector2.Zero, 0f, 0f, Vector2.One,
SpriteEffects.None);
}
public void Draw(Texture2D texture, Vector2 position, Nullable<Rectangle> sourceRectangle, Color color)
{
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);
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, 0f, 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)
public void Draw(Texture2D texture, Vector2 position, Nullable<Rectangle> sourceRectangle, Color color, Single rotation,
Vector2 origin, Single scale, SpriteEffects effects, Single layerDepth)
{
Vector2 size = sourceRectangle.HasValue ? new Vector2(sourceRectangle.Value.Width, sourceRectangle.Value.Height) : new Vector2(texture.Width, texture.Height);
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)
{
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);
public void Draw(Texture2D texture, Vector2 position, Nullable<Rectangle> sourceRectangle, Color color, Single rotation,
Vector2 origin, Vector2 scale, SpriteEffects effects, Single layerDepth)
{
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
#region DrawOptimizedText
internal void DrawOptimizedText(Texture2D texture, Vector2 position, ref Rectangle sourceRectangle, ref Color color,
float rotation, Vector2 scale, SpriteEffects effects, float layerDepth)
{
Vector2 size = new Vector2(sourceRectangle.Width, sourceRectangle.Height);
Draw(texture, position, size, sourceRectangle, color, Vector2.Zero, layerDepth, rotation, scale, effects);
}
internal void DrawOptimizedText(Texture2D texture, Vector2 position, ref Rectangle sourceRectangle, ref Color color)
{
if (hasBegun == false)
throw new InvalidOperationException("Begin() must be called before Draw()");
if (texture == null)
throw new ArgumentNullException("texture");
ResizeIfNeeded();
Vector2 bottomRight;
bottomRight.X = position.X + sourceRectangle.Width;
bottomRight.Y = position.Y + sourceRectangle.Height;
SpriteInfo currentSprite = spriteInfos[currentBatchPosition];
currentSprite.Corners = new Vector2[]
{
position,
new Vector2(bottomRight.X, position.Y),
bottomRight,
new Vector2(position.X, bottomRight.Y)
};
currentSprite.Tint = color;
currentSprite.texture = texture;
currentSprite.topLeftUV.X = sourceRectangle.X * texture.OneOverWidth;
currentSprite.topLeftUV.Y = sourceRectangle.Y * texture.OneOverHeight;
currentSprite.bottomRightUV.X = (sourceRectangle.X + sourceRectangle.Width) * texture.OneOverWidth;
currentSprite.bottomRightUV.Y = (sourceRectangle.Y + sourceRectangle.Height) * texture.OneOverHeight;
currentSprite.origin = Vector2.Zero;
currentSprite.rotation = 0f;
currentSprite.layerDepth = 1f;
spriteInfos[currentBatchPosition] = currentSprite;
currentBatchPosition++;
if (this.currentSortMode == SpriteSortMode.Immediate)
{
BatchRender(0, 1);
Flush();
}
}
#endregion
#region DrawString
public void DrawString(SpriteFont font, String text, Vector2 position, Color color)
{
if (font == null)
throw new ArgumentNullException("font");
if (text == null)
throw new ArgumentNullException("text");
font.DrawString(text, this, position, color);
}
#endregion // Draw-Method
public void DrawString(SpriteFont font, StringBuilder text, Vector2 position, Color color)
{
if (font == null)
throw new ArgumentNullException("font");
if (text == null)
throw new ArgumentNullException("text");
#region DrawString-Method
public void DrawString(SpriteFont font, String text, Vector2 position, Color color)
{
if (font == null)
{
throw new ArgumentNullException("font");
}
font.DrawString(text.ToString(), this, position, color);
}
if (text == null)
{
throw new ArgumentNullException("text");
}
public void DrawString(SpriteFont font, String text, Vector2 position, Color color, Single rotation, Vector2 origin,
Single scale, SpriteEffects effects, Single layerDepth)
{
if (font == null)
throw new ArgumentNullException("font");
if (text == null)
throw new ArgumentNullException("text");
font.DrawString(ref text, this, position, color, Vector2.One, Vector2.Zero, 0.0f, 1.0f, SpriteEffects.None);
font.DrawString(text, this, position, color, new Vector2(scale), origin, rotation, layerDepth, effects);
}
public void DrawString(SpriteFont font, String text, Vector2 position, Color color, Single rotation, Vector2 origin, Single scale, SpriteEffects effects, Single layerDepth)
{
if (font == null)
{
throw new ArgumentNullException("font");
}
public void DrawString(SpriteFont font, String text, Vector2 position, Color color, Single rotation, Vector2 origin,
Vector2 scale, SpriteEffects effects, Single layerDepth)
{
if (font == null)
throw new ArgumentNullException("font");
if (text == null)
throw new ArgumentNullException("text");
if (text == null)
{
throw new ArgumentNullException("text");
}
font.DrawString(ref text, this, position, color, new Vector2(scale), origin, rotation, layerDepth, effects);
font.DrawString(text, this, position, color, scale, origin, rotation, layerDepth, effects);
}
public void DrawString(SpriteFont font, String text, Vector2 position, Color color, Single rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, Single layerDepth)
{
if (font == null)
{
throw new ArgumentNullException("font");
}
public void DrawString(SpriteFont font, StringBuilder text, Vector2 position, Color color, Single rotation,
Vector2 origin, Single scale, SpriteEffects effects, Single layerDepth)
{
if (font == null)
throw new ArgumentNullException("font");
if (text == null)
throw new ArgumentNullException("text");
if (text == null)
{
throw new ArgumentNullException("text");
}
font.DrawString(text.ToString(), this, position, color, new Vector2(scale), origin, rotation, layerDepth, effects);
}
font.DrawString(ref text, this, position, color, scale, origin, rotation, layerDepth, effects);
}
public void DrawString(SpriteFont font, StringBuilder text, Vector2 position, Color color, Single rotation,
Vector2 origin, Vector2 scale, SpriteEffects effects, Single layerDepth)
{
if (font == null)
throw new ArgumentNullException("font");
if (text == null)
throw new ArgumentNullException("text");
public void DrawString (SpriteFont font, StringBuilder text, Vector2 position, Color color)
{
if (font == null)
{
throw new ArgumentNullException("font");
}
if (text == null)
{
throw new ArgumentNullException("text");
}
DrawString(font, text.ToString(), position, color);
}
public void DrawString (SpriteFont font, StringBuilder text, Vector2 position, Color color, Single rotation, Vector2 origin, Single scale, SpriteEffects effects, Single layerDepth)
{
if (font == null)
{
throw new ArgumentNullException("font");
}
if (text == null)
{
throw new ArgumentNullException("text");
}
DrawString(font, text.ToString(), position, color, rotation, origin, scale, effects, layerDepth);
}
public void DrawString (SpriteFont font, StringBuilder text, Vector2 position, Color color, Single rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, Single layerDepth)
{
if (font == null)
{
throw new ArgumentNullException("font");
}
if (text == null)
{
throw new ArgumentNullException("text");
}
DrawString(font, text.ToString(), position, color, rotation, origin, scale, effects, layerDepth);
}
#endregion // DrawString-Method
font.DrawString(text.ToString(), this, position, color, scale, origin, rotation, layerDepth, effects);
}
#endregion
#region End
public void End()
{
if (hasBegun == false)
{
throw new Exception("Begin() has to be called before End()");
}
hasBegun = false;
@ -256,17 +304,11 @@ namespace ANX.Framework.Graphics
if (currentBatchPosition > 0)
{
if (this.currentSortMode == SpriteSortMode.Texture)
{
Array.Sort<SpriteInfo>(spriteInfos, 0, currentBatchPosition, textureComparer);
}
else if (this.currentSortMode == SpriteSortMode.BackToFront)
{
Array.Sort<SpriteInfo>(spriteInfos, 0, currentBatchPosition, backToFrontComparer);
}
else if (this.currentSortMode == SpriteSortMode.FrontToBack)
{
Array.Sort<SpriteInfo>(spriteInfos, 0, currentBatchPosition, frontToBackComparer);
}
int startOffset = 0;
Texture2D lastTexture = spriteInfos[0].texture;
@ -285,57 +327,72 @@ namespace ANX.Framework.Graphics
Flush();
}
#endregion
#endregion
private void Draw(Texture2D texture, Vector2 topLeft, Vector2 destinationSize, Rectangle? sourceRectangle, Color tint, Vector2 origin, float layerDepth, float rotation, Vector2 scale, SpriteEffects effects)
#region ResizeIfNeeded
private void ResizeIfNeeded()
{
if (currentBatchPosition >= spriteInfos.Length)
{
int newSize = spriteInfos.Length * 2;
Array.Resize<SpriteInfo>(ref spriteInfos, newSize);
InitializeIndexBuffer(newSize);
}
}
#endregion
#region Draw
private void Draw(Texture2D texture, Vector2 topLeft, Vector2 destinationSize, Rectangle? sourceRectangle,
Color tint, Vector2 origin, float layerDepth, float rotation, Vector2 scale, SpriteEffects effects)
{
if (hasBegun == false)
{
throw new InvalidOperationException("Begin() must be called before Draw()");
}
if (texture == null)
{
throw new ArgumentNullException("texture");
}
if (currentBatchPosition >= spriteInfos.Length)
{
int newSize = spriteInfos.Length * 2;
Array.Resize<SpriteInfo>(ref spriteInfos, newSize);
InitializeIndexBuffer(newSize);
}
ResizeIfNeeded();
Vector2 bottomRight = topLeft + (destinationSize * scale);
Vector2 bottomRight = new Vector2(topLeft.X + (destinationSize.X * scale.X),
topLeft.Y + (destinationSize.Y * scale.Y));
spriteInfos[currentBatchPosition].Corners = new Vector2[] { topLeft, new Vector2(bottomRight.X, topLeft.Y), bottomRight, new Vector2(topLeft.X, bottomRight.Y) };
SpriteInfo currentSprite = spriteInfos[currentBatchPosition];
currentSprite.Corners = new Vector2[]
{
topLeft,
new Vector2(bottomRight.X, topLeft.Y),
bottomRight,
new Vector2(topLeft.X, bottomRight.Y)
};
spriteInfos[currentBatchPosition].Tint = tint;
spriteInfos[currentBatchPosition].texture = texture;
currentSprite.Tint = tint;
currentSprite.texture = texture;
if (sourceRectangle.HasValue)
{
spriteInfos[currentBatchPosition].topLeftUV = new Vector2(sourceRectangle.Value.X / (float)texture.Width, sourceRectangle.Value.Y / (float)texture.Height);
spriteInfos[currentBatchPosition].bottomRightUV = new Vector2((sourceRectangle.Value.X + sourceRectangle.Value.Width) / (float)texture.Width, (sourceRectangle.Value.Y + sourceRectangle.Value.Height) / (float)texture.Height);
currentSprite.topLeftUV.X = sourceRectangle.Value.X * texture.OneOverWidth;
currentSprite.topLeftUV.Y = sourceRectangle.Value.Y * texture.OneOverHeight;
currentSprite.bottomRightUV.X = (sourceRectangle.Value.X + sourceRectangle.Value.Width) * texture.OneOverWidth;
currentSprite.bottomRightUV.Y = (sourceRectangle.Value.Y + sourceRectangle.Value.Height) * texture.OneOverHeight;
}
else
{
spriteInfos[currentBatchPosition].topLeftUV = Vector2.Zero;
spriteInfos[currentBatchPosition].bottomRightUV = Vector2.One;
currentSprite.topLeftUV = Vector2.Zero;
currentSprite.bottomRightUV = Vector2.One;
}
if ((effects & SpriteEffects.FlipHorizontally) == SpriteEffects.FlipHorizontally)
{
float tempY = spriteInfos[currentBatchPosition].bottomRightUV.Y;
spriteInfos[currentBatchPosition].bottomRightUV.Y = spriteInfos[currentBatchPosition].topLeftUV.Y;
spriteInfos[currentBatchPosition].topLeftUV.Y = tempY;
float tempY = currentSprite.bottomRightUV.Y;
currentSprite.bottomRightUV.Y = currentSprite.topLeftUV.Y;
currentSprite.topLeftUV.Y = tempY;
}
if ((effects & SpriteEffects.FlipVertically) == SpriteEffects.FlipVertically)
{
float tempX = spriteInfos[currentBatchPosition].bottomRightUV.X;
spriteInfos[currentBatchPosition].bottomRightUV.X = spriteInfos[currentBatchPosition].topLeftUV.X;
spriteInfos[currentBatchPosition].topLeftUV.X = tempX;
float tempX = currentSprite.bottomRightUV.X;
currentSprite.bottomRightUV.X = currentSprite.topLeftUV.X;
currentSprite.topLeftUV.X = tempX;
}
if (rotation != 0f)
@ -348,17 +405,22 @@ namespace ANX.Framework.Graphics
Vector2 transformVector;
Vector2 result;
float offsetX = topLeft.X + origin.X;
float offsetY = topLeft.Y + origin.Y;
for (int i = 0; i < 4; i++)
{
transformVector = spriteInfos[currentBatchPosition].Corners[i] - topLeft - origin;
transformVector.X = currentSprite.Corners[i].X - offsetX;
transformVector.Y = currentSprite.Corners[i].Y - offsetY;
Vector2.Transform(ref transformVector, ref this.cachedRotationMatrix, out result);
spriteInfos[currentBatchPosition].Corners[i] = result + topLeft + origin;
currentSprite.Corners[i].X = result.X + offsetX;
currentSprite.Corners[i].Y = result.Y + offsetY;
}
}
spriteInfos[currentBatchPosition].origin = origin;
spriteInfos[currentBatchPosition].rotation = rotation;
spriteInfos[currentBatchPosition].layerDepth = layerDepth;
currentSprite.origin = origin;
currentSprite.rotation = rotation;
currentSprite.layerDepth = layerDepth;
spriteInfos[currentBatchPosition] = currentSprite;
currentBatchPosition++;
@ -367,20 +429,18 @@ namespace ANX.Framework.Graphics
BatchRender(0, 1);
Flush();
}
}
}
#endregion
private void BatchRender(int offset, int count)
#region BatchRender
private void BatchRender(int offset, int count)
{
int vertexCount = count * 4;
if (this.vertices == null)
{
this.vertices = new VertexPositionColorTexture[vertexCount];
}
else if (this.vertices.Length < vertexCount)
{
Array.Resize<VertexPositionColorTexture>(ref this.vertices, vertexCount);
}
int vertexPos = 0;
for (int i = offset; i < offset + count; i++)
@ -415,27 +475,34 @@ namespace ANX.Framework.Graphics
spriteBatchEffect.Parameters["Texture"].SetValue(this.spriteInfos[offset].texture);
GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, vertexCount, 0, count * 2);
}
}
#endregion
private void Flush()
#region Flush
private void Flush()
{
currentBatchPosition = 0;
}
#endregion
private void InitializeIndexBuffer(int size)
#region InitializeIndexBuffer
private void InitializeIndexBuffer(int size)
{
int indexCount = size * 6;
if (this.indexBuffer == null)
{
this.indexBuffer = new DynamicIndexBuffer(this.GraphicsDevice, IndexElementSize.SixteenBits, indexCount, BufferUsage.WriteOnly);
this.indexBuffer = new DynamicIndexBuffer(this.GraphicsDevice, IndexElementSize.SixteenBits, indexCount,
BufferUsage.WriteOnly);
this.indexBuffer.ContentLost += new EventHandler<EventArgs>(indexBuffer_ContentLost);
}
SetIndexData(indexCount);
}
}
#endregion
private void indexBuffer_ContentLost(object sender, EventArgs e)
#region indexBuffer_ContentLost
private void indexBuffer_ContentLost(object sender, EventArgs e)
{
if (this.indexBuffer != null)
{
@ -445,11 +512,13 @@ namespace ANX.Framework.Graphics
}
InitializeIndexBuffer(InitialBatchSize);
}
}
#endregion
private void SetIndexData(int indexCount)
#region SetIndexData
private void SetIndexData(int indexCount)
{
short[] indices = new short[indexCount];
var indices = new ushort[indexCount];
int baseIndex;
int baseArrayIndex;
@ -458,27 +527,32 @@ namespace ANX.Framework.Graphics
baseIndex = i * 4;
baseArrayIndex = baseIndex + i + i;
indices[baseArrayIndex] = (short)baseIndex;
indices[baseArrayIndex + 1] = (short)(baseIndex + 1);
indices[baseArrayIndex + 2] = (short)(baseIndex + 2);
indices[baseArrayIndex + 3] = (short)baseIndex;
indices[baseArrayIndex + 4] = (short)(baseIndex + 2);
indices[baseArrayIndex + 5] = (short)(baseIndex + 3);
indices[baseArrayIndex] = (ushort)baseIndex;
indices[baseArrayIndex + 1] = (ushort)(baseIndex + 1);
indices[baseArrayIndex + 2] = (ushort)(baseIndex + 2);
indices[baseArrayIndex + 3] = (ushort)baseIndex;
indices[baseArrayIndex + 4] = (ushort)(baseIndex + 2);
indices[baseArrayIndex + 5] = (ushort)(baseIndex + 3);
}
this.indexBuffer.SetData<short>(indices);
}
this.indexBuffer.SetData<ushort>(indices);
}
#endregion
private void InitializeVertexBuffer()
#region InitializeVertexBuffer
private void InitializeVertexBuffer()
{
if (this.vertexBuffer == null)
{
this.vertexBuffer = new DynamicVertexBuffer(this.GraphicsDevice, typeof(VertexPositionColorTexture), InitialBatchSize * 4, BufferUsage.WriteOnly);
this.vertexBuffer.ContentLost += new EventHandler<EventArgs>(vertexBuffer_ContentLost);
this.vertexBuffer = new DynamicVertexBuffer(this.GraphicsDevice, typeof(VertexPositionColorTexture),
InitialBatchSize * 4, BufferUsage.WriteOnly);
this.vertexBuffer.ContentLost += vertexBuffer_ContentLost;
}
}
#endregion
private void vertexBuffer_ContentLost(object sender, EventArgs e)
#region vertexBuffer_ContentLost
private void vertexBuffer_ContentLost(object sender, EventArgs e)
{
this.currentBatchPosition = 0;
@ -490,16 +564,19 @@ namespace ANX.Framework.Graphics
}
InitializeVertexBuffer();
}
}
#endregion
private void SetRenderStates()
#region SetRenderStates
private void SetRenderStates()
{
GraphicsDevice.BlendState = this.blendState != null ? this.blendState : BlendState.AlphaBlend;
GraphicsDevice.DepthStencilState = this.depthStencilState != null ? this.depthStencilState : DepthStencilState.None;
GraphicsDevice.RasterizerState = this.rasterizerState != null ? this.rasterizerState : RasterizerState.CullCounterClockwise;
GraphicsDevice.SamplerStates[0] = this.samplerState != null ? this.samplerState : SamplerState.LinearClamp;
GraphicsDevice.BlendState = blendState != null ? blendState : BlendState.AlphaBlend;
GraphicsDevice.DepthStencilState = depthStencilState != null ? depthStencilState : DepthStencilState.None;
GraphicsDevice.RasterizerState = rasterizerState != null ? rasterizerState : RasterizerState.CullCounterClockwise;
GraphicsDevice.SamplerStates[0] = samplerState != null ? samplerState : SamplerState.LinearClamp;
if (cachedTransformMatrix == null || GraphicsDevice.Viewport.Width != viewportWidth || GraphicsDevice.Viewport.Height != viewportHeight)
if (cachedTransformMatrix == null || GraphicsDevice.Viewport.Width != viewportWidth ||
GraphicsDevice.Viewport.Height != viewportHeight)
{
this.viewportWidth = GraphicsDevice.Viewport.Width;
this.viewportHeight = GraphicsDevice.Viewport.Height;
@ -518,14 +595,18 @@ namespace ANX.Framework.Graphics
cachedTransformMatrix.M42 -= cachedTransformMatrix.M22;
}
this.spriteBatchEffect.Parameters["MatrixTransform"].SetValue(this.transformMatrix * cachedTransformMatrix);
Matrix result;
Matrix.Multiply(ref transformMatrix, ref cachedTransformMatrix, out result);
this.spriteBatchEffect.Parameters["MatrixTransform"].SetValue(result);
spriteBatchEffect.NativeEffect.Apply(GraphicsDevice);
GraphicsDevice.Indices = this.indexBuffer;
GraphicsDevice.SetVertexBuffer(this.vertexBuffer);
}
}
#endregion
public override void Dispose()
#region Dispose
public override void Dispose()
{
if (this.spriteBatchEffect != null)
{
@ -550,19 +631,18 @@ namespace ANX.Framework.Graphics
{
throw new NotImplementedException();
}
#endregion
private class TextureComparer : IComparer<SpriteInfo>
private class TextureComparer : IComparer<SpriteInfo>
{
public int Compare(SpriteInfo x, SpriteInfo y)
{
if (x.texture.GetHashCode() > y.texture.GetHashCode())
{
int hash1 = x.texture.GetHashCode();
int hash2 = y.texture.GetHashCode();
if (hash1 > hash2)
return -1;
}
else if (x.texture.GetHashCode() < y.texture.GetHashCode())
{
else if (hash1 < hash2)
return 1;
}
return 0;
}
@ -573,13 +653,9 @@ namespace ANX.Framework.Graphics
public int Compare(SpriteInfo x, SpriteInfo y)
{
if (x.layerDepth > y.layerDepth)
{
return 1;
}
else if (x.layerDepth < y.layerDepth)
{
return -1;
}
return 0;
}
@ -590,17 +666,12 @@ namespace ANX.Framework.Graphics
public int Compare(SpriteInfo x, SpriteInfo y)
{
if (x.layerDepth > y.layerDepth)
{
return -1;
}
else if (x.layerDepth < y.layerDepth)
{
return 1;
}
return 0;
}
}
}
}

View File

@ -1,9 +1,8 @@
#region Using Statements
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
#endregion // Using Statements
using ANX.Framework.NonXNA.Development;
// This file is part of the ANX.Framework created by the
// "ANX.Framework developer group" and released under the Ms-PL license.
@ -11,252 +10,262 @@ using System.Text;
namespace ANX.Framework.Graphics
{
[PercentageComplete(100)]
[TestState(TestStateAttribute.TestState.Untested)]
[Developer("Glatzemann, AstrorEnales")]
public sealed class SpriteFont
{
#region Private Members
#region Private
private Texture2D texture;
private List<Rectangle> glyphs;
private List<Rectangle> cropping;
private Rectangle[] glyphs;
private Rectangle[] cropping;
private List<char> characterMap;
private int lineSpacing;
private float horizontalSpacing;
private List<Vector3> kerning;
private char? defaultCharacter;
private ReadOnlyCollection<Char> characters;
private Vector3[] kernings;
private char? defaultCharacter;
Vector2 topLeft;
Vector2 position;
#endregion
#endregion // Private Members
public ReadOnlyCollection<Char> Characters
{
get { return characters; }
}
#region Public
public ReadOnlyCollection<Char> Characters { get; private set; }
public int LineSpacing { get; set; }
public float Spacing { get; set; }
public char? DefaultCharacter
{
get { return defaultCharacter; }
set
{
if (value.HasValue && !this.characterMap.Contains(value.Value))
{
if (value.HasValue && this.characterMap.Contains(value.Value) == false)
throw new NotSupportedException("Character is not in used font");
}
this.defaultCharacter = value;
}
}
#endregion
public int LineSpacing
{
get { return lineSpacing; }
set { lineSpacing = value; }
}
public float Spacing
{
get { return horizontalSpacing; }
set { horizontalSpacing = value; }
}
internal SpriteFont(
Texture2D texture, List<Rectangle> glyphs, List<Rectangle> cropping, List<char> charMap,
int lineSpacing, float horizontalSpacing, List<Vector3> kerning, char? defaultCharacter)
#region Constructor
internal SpriteFont(Texture2D texture, List<Rectangle> glyphs, List<Rectangle> cropping, List<char> charMap,
int lineSpacing, float horizontalSpacing, List<Vector3> kerning, char? defaultCharacter)
{
this.texture = texture;
this.glyphs = glyphs;
this.cropping = cropping;
this.glyphs = glyphs.ToArray();
this.cropping = cropping.ToArray();
this.characterMap = charMap;
this.lineSpacing = lineSpacing;
this.horizontalSpacing = horizontalSpacing;
this.kerning = kerning;
this.LineSpacing = lineSpacing;
this.Spacing = horizontalSpacing;
this.kernings = kerning.ToArray();
this.defaultCharacter = defaultCharacter;
this.characters = new ReadOnlyCollection<char>(characterMap);
Characters = new ReadOnlyCollection<char>(characterMap);
}
#endregion
public Vector2 MeasureString(string text)
#region MeasureString
public Vector2 MeasureString(string text)
{
if (text == null)
{
throw new ArgumentNullException("text");
}
return InternalMeasure(ref text);
return InternalMeasure(text);
}
public Vector2 MeasureString(StringBuilder text)
{
if (text == null)
{
throw new ArgumentNullException("text");
}
String cachedText = text.ToString();
return InternalMeasure(ref cachedText);
return InternalMeasure(text.ToString());
}
#endregion
internal void DrawString(ref String text, SpriteBatch spriteBatch, Vector2 textPos, Color color, Vector2 scale, Vector2 origin, float rotation, float layerDepth, SpriteEffects effects)
#region DrawString
internal void DrawString(string text, SpriteBatch spriteBatch, Vector2 textPos, Color color, Vector2 scale,
Vector2 origin, float rotation, float layerDepth, SpriteEffects effects)
{
Matrix transformation = Matrix.CreateRotationZ(rotation) * Matrix.CreateTranslation(-origin.X * scale.X, -origin.Y * scale.Y, 0f);
Matrix rotationMatrix;
Matrix.CreateRotationZ(rotation, out rotationMatrix);
Matrix translationMatrix;
Matrix.CreateTranslation(-origin.X * scale.X, -origin.Y * scale.Y, 0f, out translationMatrix);
Matrix transformation;
Matrix.Multiply(ref rotationMatrix, ref translationMatrix, out transformation);
topLeft.X = topLeft.Y = 0f;
int horizontalFlipModifier = 1;
float width = 0f;
Vector2 topLeft = new Vector2();
bool firstCharacterInLine = true;
bool flipVertically = (effects & SpriteEffects.FlipVertically) == SpriteEffects.FlipVertically;
bool flipHorizontally = (effects & SpriteEffects.FlipHorizontally) == SpriteEffects.FlipHorizontally;
if ((effects & SpriteEffects.FlipHorizontally) == SpriteEffects.FlipHorizontally)
if (flipHorizontally)
{
topLeft.X = width = this.InternalMeasure(ref text).X * scale.X;
topLeft.X = width = InternalMeasure(text).X * scale.X;
horizontalFlipModifier = -1;
}
if ((effects & SpriteEffects.FlipVertically) == SpriteEffects.FlipVertically)
{
topLeft.Y = (this.InternalMeasure(ref text).Y - this.lineSpacing) * scale.Y;
}
if (flipVertically)
topLeft.Y = (InternalMeasure(text).Y - LineSpacing) * scale.Y;
for (int i = 0; i < text.Length; i++)
{
char currentCharacter = text[i];
switch (currentCharacter)
{
case '\r':
break;
bool firstCharacterInLine = true;
for (int i = 0; i < text.Length; i++)
{
char currentCharacter = text[i];
if (currentCharacter == '\r')
continue;
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;
if (currentCharacter == '\n')
{
firstCharacterInLine = true;
topLeft.X = width;
float factor = LineSpacing * scale.Y;
topLeft.Y += flipVertically ? -factor : factor;
continue;
}
default:
{
int characterIndex = GetIndexForCharacter(currentCharacter);
Vector3 kerning = this.kerning[characterIndex];
Rectangle glyphRect = this.glyphs[characterIndex];
Rectangle croppingRect = this.cropping[characterIndex];
int characterIndex = GetIndexForCharacter(currentCharacter);
Vector3 kerning = kernings[characterIndex];
Rectangle croppingRect = cropping[characterIndex];
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 (firstCharacterInLine)
kerning.X = Math.Max(kerning.X, 0f);
else
topLeft.X += (Spacing * 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;
}
}
}
topLeft.X += (kerning.X * scale.X) * horizontalFlipModifier;
if (flipVertically)
croppingRect.Y = (LineSpacing - glyphs[characterIndex].Height) - croppingRect.Y;
if (flipHorizontally)
croppingRect.X -= croppingRect.Width;
position.X = topLeft.X + (croppingRect.X * scale.X);
position.Y = topLeft.Y + (croppingRect.Y * scale.Y);
Vector2 result;
Vector2.Transform(ref position, ref transformation, out result);
result.X += textPos.X;
result.Y += textPos.Y;
spriteBatch.DrawOptimizedText(texture, result, ref glyphs[characterIndex], ref color, rotation, scale,
effects, layerDepth);
firstCharacterInLine = false;
topLeft.X += ((kerning.Y + kerning.Z) * scale.X) * horizontalFlipModifier;
}
}
#endregion
private Vector2 InternalMeasure(ref String text)
#region DrawString
internal void DrawString(string text, SpriteBatch spriteBatch, Vector2 textPos, Color color)
{
topLeft.X = topLeft.Y = 0f;
bool firstCharacterInLine = true;
for (int i = 0; i < text.Length; i++)
{
char currentCharacter = text[i];
if (currentCharacter == '\r')
continue;
if (currentCharacter == '\n')
{
firstCharacterInLine = true;
topLeft.X = 0f;
topLeft.Y += LineSpacing;
continue;
}
int characterIndex = GetIndexForCharacter(currentCharacter);
Vector3 kerning = kernings[characterIndex];
Rectangle croppingRect = cropping[characterIndex];
if (firstCharacterInLine)
kerning.X = Math.Max(kerning.X, 0f);
else
topLeft.X += Spacing;
topLeft.X += kerning.X;
position.X = topLeft.X + croppingRect.X + textPos.X;
position.Y = topLeft.Y + croppingRect.Y + textPos.Y;
spriteBatch.DrawOptimizedText(texture, position, ref glyphs[characterIndex], ref color);
firstCharacterInLine = false;
topLeft.X += kerning.Y + kerning.Z;
}
}
#endregion
#region InternalMeasure
private Vector2 InternalMeasure(string text)
{
if (text.Length < 1)
{
return Vector2.Zero;
}
Vector2 size = Vector2.Zero;
size.Y = this.lineSpacing;
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];
for (int i = 0; i < text.Length; i++)
{
char currentChar = text[i];
if (currentChar == '\r')
continue;
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 = LineSpacing;
firstCharacterInLine = true;
currentCharacter++;
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;
int currentCharIndex = GetIndexForCharacter(currentChar);
Vector3 kerning = kernings[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)cropping[currentCharIndex].Height);
firstCharacterInLine = false;
}
size.Y += currentCharacter * LineSpacing;
size.X = Math.Max(Math.Max(z, 0) + size.X, maxWidth);
return size;
}
}
#endregion
private int GetIndexForCharacter(char character)
{
int currentIndex = 0;
int upperBound = this.characterMap.Count - 1;
char testChar;
int searchPos;
#region GetIndexForCharacter
private int GetIndexForCharacter(char character)
{
int currentIndex = 0;
int upperBound = this.characterMap.Count - 1;
char testChar;
int searchPos;
while (currentIndex <= upperBound)
{
searchPos = currentIndex + ((upperBound - currentIndex) >> 1);
testChar = this.characterMap[searchPos];
if (testChar == character)
{
return searchPos;
}
else if (testChar > character)
{
upperBound = searchPos - 1;
}
else
{
currentIndex = searchPos + 1;
}
}
while (currentIndex <= upperBound)
{
searchPos = currentIndex + ((upperBound - currentIndex) >> 1);
testChar = characterMap[searchPos];
if (testChar == character)
return searchPos;
else if (testChar > character)
upperBound = searchPos - 1;
else
currentIndex = searchPos + 1;
}
if (this.defaultCharacter.HasValue)
{
return this.GetIndexForCharacter(this.defaultCharacter.Value);
}
throw new ArgumentException("character not found");
}
if (defaultCharacter.HasValue)
return GetIndexForCharacter(defaultCharacter.Value);
throw new ArgumentException("character not found");
}
#endregion
}
}

View File

@ -8,16 +8,13 @@ namespace ANX.Framework.Graphics
{
internal struct SpriteInfo
{
//public Vector2 TopLeft;
//public Vector2 BottomRight;
public Vector2[] Corners;
public Color Tint;
public Texture2D texture;
public Single rotation;
public float rotation;
public Vector2 origin;
public Single layerDepth;
public float layerDepth;
public Vector2 topLeftUV;
public Vector2 bottomRightUV;

View File

@ -16,6 +16,9 @@ namespace ANX.Framework.Graphics
protected internal int width;
protected internal int height;
internal float OneOverWidth;
internal float OneOverHeight;
private INativeTexture2D nativeTexture2D;
private INativeTexture2D NativeTexture2D
{
@ -66,6 +69,8 @@ namespace ANX.Framework.Graphics
{
this.width = width;
this.height = height;
OneOverWidth = 1f / width;
OneOverHeight = 1f / height;
base.levelCount = 1;
base.format = SurfaceFormat.Color;
@ -79,6 +84,9 @@ namespace ANX.Framework.Graphics
{
this.width = width;
this.height = height;
OneOverWidth = 1f / width;
OneOverHeight = 1f / height;
// TODO: pass the mipmap parameter to the creation of the texture to let the graphics card generate mipmaps!
base.levelCount = 1;
base.format = format;
@ -91,6 +99,8 @@ namespace ANX.Framework.Graphics
{
this.width = width;
this.height = height;
OneOverWidth = 1f / width;
OneOverHeight = 1f / height;
base.levelCount = mipCount;
base.format = format;

View File

@ -16,9 +16,6 @@ namespace ANX.Framework.Graphics
public class VertexBuffer : GraphicsResource, IGraphicsResource
{
#region Private
private VertexDeclaration vertexDeclaration;
private int vertexCount;
private BufferUsage bufferUsage;
private INativeVertexBuffer nativeVertexBuffer;
#endregion
@ -29,55 +26,31 @@ namespace ANX.Framework.Graphics
{
get
{
if (this.nativeVertexBuffer == null)
{
if (nativeVertexBuffer == null)
CreateNativeBuffer();
}
return this.nativeVertexBuffer;
return nativeVertexBuffer;
}
}
public BufferUsage BufferUsage
{
get
{
return this.bufferUsage;
}
}
public int VertexCount
{
get
{
return this.vertexCount;
}
}
public VertexDeclaration VertexDeclaration
{
get
{
return this.vertexDeclaration;
}
}
public BufferUsage BufferUsage { get; private set; }
public int VertexCount { get; private set; }
public VertexDeclaration VertexDeclaration { get; private set; }
#endregion
#region Constructor
public VertexBuffer(GraphicsDevice graphicsDevice, Type vertexType,
int vertexCount, BufferUsage usage)
: this(graphicsDevice, VertexBuffer.TypeToVertexDeclaration(vertexType),
vertexCount, usage)
public VertexBuffer(GraphicsDevice graphicsDevice, Type vertexType, int vertexCount, BufferUsage usage)
: this(graphicsDevice, VertexTypeHelper.GetDeclaration(vertexType), vertexCount, usage)
{
}
public VertexBuffer(GraphicsDevice graphicsDevice,
VertexDeclaration vertexDeclaration, int vertexCount, BufferUsage usage)
public VertexBuffer(GraphicsDevice graphicsDevice, VertexDeclaration vertexDeclaration, int vertexCount,
BufferUsage usage)
: base(graphicsDevice)
{
this.vertexCount = vertexCount;
this.vertexDeclaration = vertexDeclaration;
this.bufferUsage = usage;
VertexCount = vertexCount;
VertexDeclaration = vertexDeclaration;
BufferUsage = usage;
base.GraphicsDevice.ResourceCreated += GraphicsDevice_ResourceCreated;
base.GraphicsDevice.ResourceDestroyed += GraphicsDevice_ResourceDestroyed;
@ -120,17 +93,16 @@ namespace ANX.Framework.Graphics
#region CreateNativeBuffer
private void CreateNativeBuffer()
{
this.nativeVertexBuffer =
AddInSystemFactory.Instance.GetDefaultCreator<IRenderSystemCreator>().CreateVertexBuffer(GraphicsDevice, this, vertexDeclaration, vertexCount, bufferUsage);
var creator = AddInSystemFactory.Instance.GetDefaultCreator<IRenderSystemCreator>();
this.nativeVertexBuffer = creator.CreateVertexBuffer(GraphicsDevice, this, VertexDeclaration, VertexCount,
BufferUsage);
}
#endregion
#region GetData
public void GetData<T>(int offsetInBytes, T[] data, int startIndex,
int elementCount, int vertexStride) where T : struct
public void GetData<T>(int offsetInBytes, T[] data, int startIndex, int elementCount, int vertexStride) where T : struct
{
NativeVertexBuffer.GetData(offsetInBytes, data, startIndex,
elementCount, vertexStride);
NativeVertexBuffer.GetData(offsetInBytes, data, startIndex, elementCount, vertexStride);
}
public void GetData<T>(T[] data) where T : struct
@ -138,19 +110,16 @@ namespace ANX.Framework.Graphics
NativeVertexBuffer.GetData(data);
}
public void GetData<T>(T[] data, int startIndex, int elementCount)
where T : struct
public void GetData<T>(T[] data, int startIndex, int elementCount) where T : struct
{
NativeVertexBuffer.GetData(data, startIndex, elementCount);
}
#endregion
#region SetData
public void SetData<T>(int offsetInBytes, T[] data, int startIndex,
int elementCount, int vertexStride) where T : struct
public void SetData<T>(int offsetInBytes, T[] data, int startIndex, int elementCount, int vertexStride) where T : struct
{
NativeVertexBuffer.SetData(GraphicsDevice, offsetInBytes, data,
startIndex, elementCount, vertexStride);
NativeVertexBuffer.SetData(GraphicsDevice, offsetInBytes, data, startIndex, elementCount, vertexStride);
}
public void SetData<T>(T[] data) where T : struct
@ -164,19 +133,6 @@ namespace ANX.Framework.Graphics
}
#endregion
#region TypeToVertexDeclaration
private static VertexDeclaration TypeToVertexDeclaration(Type t)
{
IVertexType vt = Activator.CreateInstance(t) as IVertexType;
if (vt != null)
{
return vt.VertexDeclaration;
}
return null;
}
#endregion
#region Dispose
public override void Dispose()
{
@ -186,16 +142,17 @@ namespace ANX.Framework.Graphics
nativeVertexBuffer = null;
}
if (vertexDeclaration != null)
{
// do not dispose the VertexDeclaration here, because it's only a reference
vertexDeclaration = null;
}
// do not dispose the VertexDeclaration here, because it's only a reference
if (VertexDeclaration != null)
VertexDeclaration = null;
}
protected override void Dispose([MarshalAs(UnmanagedType.U1)] bool disposeManaged)
{
throw new NotImplementedException();
if (disposeManaged)
{
Dispose();
}
}
#endregion
}

View File

@ -2,6 +2,10 @@
using System.Collections.Generic;
using ANX.Framework.Graphics;
// This file is part of the ANX.Framework created by the
// "ANX.Framework developer group" and released under the Ms-PL license.
// For details see: http://anxframework.codeplex.com/license
namespace ANX.Framework.NonXNA.RenderSystem
{
internal static class VertexTypeHelper
@ -14,7 +18,17 @@ namespace ANX.Framework.NonXNA.RenderSystem
if (rememberedInstances.ContainsKey(type) == false)
rememberedInstances.Add(type, Activator.CreateInstance<T>());
return rememberedInstances[type].VertexDeclaration;
var result = rememberedInstances[type];
return result != null ? result.VertexDeclaration : null;
}
public static VertexDeclaration GetDeclaration(Type type)
{
if (rememberedInstances.ContainsKey(type) == false)
rememberedInstances.Add(type, Activator.CreateInstance(type) as IVertexType);
var result = rememberedInstances[type];
return result != null ? result.VertexDeclaration : null;
}
}
}

View File

@ -21,11 +21,18 @@ namespace TextRendering
SpriteFont debugFont;
int fps = 60;
int fpsCount = 0;
float fpsTimer = 0f;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
graphics.PreparingDeviceSettings += new EventHandler<PreparingDeviceSettingsEventArgs>(graphics_PreparingDeviceSettings);
Content.RootDirectory = "SampleContent";
IsFixedTimeStep = false;
graphics.SynchronizeWithVerticalRetrace = false;
}
void graphics_PreparingDeviceSettings(object sender, PreparingDeviceSettingsEventArgs e)
@ -55,6 +62,15 @@ namespace TextRendering
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
fpsCount++;
fpsTimer += (float)gameTime.ElapsedGameTime.TotalSeconds;
if (fpsTimer >= 1f)
{
fpsTimer -= 1f;
fps = fpsCount;
fpsCount = 0;
}
base.Update(gameTime);
}
@ -63,7 +79,7 @@ namespace TextRendering
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(SpriteSortMode.FrontToBack, null);
spriteBatch.DrawString(this.debugFont, "Hello World!", new Vector2(100, 100), Color.White);
spriteBatch.DrawString(this.debugFont, "Hello World! FPS: " + fps, new Vector2(100, 100), Color.White);
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);

View File

@ -11,6 +11,7 @@ namespace TextRendering
static void Main(string[] args)
{
//AddInSystemFactory.Instance.SetPreferredSystem(AddInType.RenderSystem, "OpenGL3");
AddInSystemFactory.Instance.SetPreferredSystem(AddInType.RenderSystem, "DirectX10");
//AddInSystemFactory.Instance.SetPreferredSystem(AddInType.RenderSystem, "DirectX11");
using (Game1 game = new Game1())