add SpriteBatch
This commit is contained in:
parent
d53ed4147e
commit
2461a7ca26
|
@ -130,6 +130,7 @@
|
||||||
<Compile Include="Graphics\CustomShaders\CustomStandardShader.cs" />
|
<Compile Include="Graphics\CustomShaders\CustomStandardShader.cs" />
|
||||||
<Compile Include="Graphics\CustomShaders\CustomVertexLerpShader.cs" />
|
<Compile Include="Graphics\CustomShaders\CustomVertexLerpShader.cs" />
|
||||||
<Compile Include="Graphics\CustomShaders\CustomVertexSkinningShader.cs" />
|
<Compile Include="Graphics\CustomShaders\CustomVertexSkinningShader.cs" />
|
||||||
|
<Compile Include="Graphics\SpriteBatch.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
|
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
762
Blarg.GameFramework/Graphics/SpriteBatch.cs
Normal file
762
Blarg.GameFramework/Graphics/SpriteBatch.cs
Normal file
|
@ -0,0 +1,762 @@
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Blarg.GameFramework.Graphics
|
||||||
|
{
|
||||||
|
public class SpriteBatch
|
||||||
|
{
|
||||||
|
static StringBuilder _buffer = new StringBuilder(8192);
|
||||||
|
|
||||||
|
const int DefaultSpriteCount = 128;
|
||||||
|
const int ResizeSpriteIncrement = 16;
|
||||||
|
const int VerticesPerSprite = 4;
|
||||||
|
const int IndicesPerSprite = 6;
|
||||||
|
|
||||||
|
VertexBuffer _vertices;
|
||||||
|
IndexBuffer _indices;
|
||||||
|
Texture[] _textures;
|
||||||
|
RenderState _defaultRenderState;
|
||||||
|
RenderState _providedRenderState;
|
||||||
|
BlendState _defaultBlendState;
|
||||||
|
BlendState _providedBlendState;
|
||||||
|
SpriteShader _shader;
|
||||||
|
Matrix4x4 _previousProjection;
|
||||||
|
Matrix4x4 _previousModelView;
|
||||||
|
bool _isClipping;
|
||||||
|
RectF _clipRegion;
|
||||||
|
int _currentSpritePointer;
|
||||||
|
bool _hasBegunRendering;
|
||||||
|
Color _defaultSpriteColor = Color.White;
|
||||||
|
|
||||||
|
public GraphicsDevice GraphicsDevice { get; private set; }
|
||||||
|
|
||||||
|
public SpriteBatch(GraphicsDevice graphicsDevice)
|
||||||
|
{
|
||||||
|
if (graphicsDevice == null)
|
||||||
|
throw new ArgumentNullException("graphicsDevice");
|
||||||
|
|
||||||
|
GraphicsDevice = graphicsDevice;
|
||||||
|
|
||||||
|
int numSprites = DefaultSpriteCount;
|
||||||
|
|
||||||
|
_currentSpritePointer = 0;
|
||||||
|
|
||||||
|
_vertices = new VertexBuffer(GraphicsDevice, VertexAttributeDeclarations.TextureColorPosition2D, (numSprites * VerticesPerSprite), BufferObjectUsage.Stream);
|
||||||
|
_indices = new IndexBuffer(GraphicsDevice, (numSprites * IndicesPerSprite), BufferObjectUsage.Stream);
|
||||||
|
_textures = new Texture[numSprites];
|
||||||
|
|
||||||
|
FillSpriteIndicesFor(0, numSprites - 1);
|
||||||
|
|
||||||
|
_defaultRenderState = RenderState.NoDepthTesting;
|
||||||
|
_providedRenderState = null;
|
||||||
|
|
||||||
|
_defaultBlendState = BlendState.AlphaBlend;
|
||||||
|
_providedBlendState = null;
|
||||||
|
|
||||||
|
_hasBegunRendering = false;
|
||||||
|
_isClipping = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Begin/End
|
||||||
|
|
||||||
|
public void Begin(SpriteShader shader = null)
|
||||||
|
{
|
||||||
|
InternalBegin(null, null, shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Begin(RenderState renderState, SpriteShader shader = null)
|
||||||
|
{
|
||||||
|
InternalBegin(renderState, null, shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Begin(BlendState blendState, SpriteShader shader = null)
|
||||||
|
{
|
||||||
|
InternalBegin(null, blendState, shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Begin(RenderState renderState, BlendState blendState, SpriteShader shader = null)
|
||||||
|
{
|
||||||
|
InternalBegin(renderState, blendState, shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void End()
|
||||||
|
{
|
||||||
|
if (!_hasBegunRendering)
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
|
||||||
|
// don't do anything if nothing is to be rendered!
|
||||||
|
if (_currentSpritePointer == 0)
|
||||||
|
{
|
||||||
|
EndClipping();
|
||||||
|
_hasBegunRendering = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_providedRenderState != null)
|
||||||
|
_providedRenderState.Apply();
|
||||||
|
else
|
||||||
|
_defaultRenderState.Apply();
|
||||||
|
|
||||||
|
if (_providedBlendState != null)
|
||||||
|
_providedBlendState.Apply();
|
||||||
|
else
|
||||||
|
_defaultBlendState.Apply();
|
||||||
|
|
||||||
|
GraphicsDevice.BindShader(_shader);
|
||||||
|
_shader.SetModelViewMatrix(Matrix4x4.Identity);
|
||||||
|
_shader.SetProjectionMatrix(GraphicsDevice.ViewContext.OrthographicProjectionMatrix);
|
||||||
|
RenderQueue();
|
||||||
|
GraphicsDevice.UnbindShader();
|
||||||
|
|
||||||
|
EndClipping();
|
||||||
|
|
||||||
|
_hasBegunRendering = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InternalBegin(RenderState renderState, BlendState blendState, SpriteShader shader)
|
||||||
|
{
|
||||||
|
if (_hasBegunRendering)
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
|
||||||
|
_previousProjection = GraphicsDevice.ViewContext.ProjectionMatrix;
|
||||||
|
_previousModelView = GraphicsDevice.ViewContext.ModelViewMatrix;
|
||||||
|
|
||||||
|
if (shader == null)
|
||||||
|
_shader = GraphicsDevice.Sprite2DShader;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!shader.IsReadyForUse)
|
||||||
|
throw new InvalidOperationException("Shader not usable for rendering.");
|
||||||
|
_shader = shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (renderState != null)
|
||||||
|
_providedRenderState = renderState;
|
||||||
|
else
|
||||||
|
_providedRenderState = null;
|
||||||
|
|
||||||
|
if (blendState != null)
|
||||||
|
_providedBlendState = blendState;
|
||||||
|
else
|
||||||
|
_providedBlendState = null;
|
||||||
|
|
||||||
|
_currentSpritePointer = 0;
|
||||||
|
_hasBegunRendering = true;
|
||||||
|
_vertices.MoveToStart();
|
||||||
|
_indices.MoveToStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RenderQueue()
|
||||||
|
{
|
||||||
|
GraphicsDevice.BindVertexBuffer(_vertices);
|
||||||
|
GraphicsDevice.BindIndexBuffer(_indices);
|
||||||
|
|
||||||
|
int firstSpriteIndex = 0;
|
||||||
|
int lastSpriteIndex = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < _currentSpritePointer; ++i)
|
||||||
|
{
|
||||||
|
if (_textures[lastSpriteIndex] != _textures[i])
|
||||||
|
{
|
||||||
|
// if the next texture is different then the last range's
|
||||||
|
// texture, then we need to render the last range now
|
||||||
|
RenderQueueRange(firstSpriteIndex, lastSpriteIndex);
|
||||||
|
|
||||||
|
// switch to the new range with this new texture
|
||||||
|
firstSpriteIndex = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastSpriteIndex = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we'll have one last range to render at this point (the loop would have
|
||||||
|
// ended before it was caught by the checks inside the loop)
|
||||||
|
RenderQueueRange(firstSpriteIndex, lastSpriteIndex);
|
||||||
|
|
||||||
|
// clear out the texture's array so it's not holding references
|
||||||
|
// to stuff that might need to be collected by the GC
|
||||||
|
// (e.g. if we render a lot of sprites one frame, and then the next
|
||||||
|
// bunch of frames we don't render as much, the end of the array
|
||||||
|
// will still hold old references to Texture objects used previously)
|
||||||
|
for (int i = 0; i < _textures.Length; ++i)
|
||||||
|
_textures[i] = null;
|
||||||
|
|
||||||
|
GraphicsDevice.UnbindIndexBuffer();
|
||||||
|
GraphicsDevice.UnbindVertexBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RenderQueueRange(int firstSpriteIndex, int lastSpriteIndex)
|
||||||
|
{
|
||||||
|
int startVertexIndex = firstSpriteIndex * IndicesPerSprite;
|
||||||
|
int lastVertexIndex = (lastSpriteIndex + 1) * IndicesPerSprite; // render up to and including the last sprite
|
||||||
|
|
||||||
|
// take the texture from anywhere in this range (doesn't matter where, it should all be the same texture)
|
||||||
|
Texture spriteTexture = _textures[firstSpriteIndex];
|
||||||
|
bool hasAlphaOnly = spriteTexture.Format == TextureFormat.Alpha ? true : false;
|
||||||
|
|
||||||
|
GraphicsDevice.BindTexture(spriteTexture);
|
||||||
|
_shader.SetTextureHasAlphaOnly(hasAlphaOnly);
|
||||||
|
|
||||||
|
GraphicsDevice.RenderTriangles(startVertexIndex, (lastVertexIndex - startVertexIndex) / 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Render: Sprites
|
||||||
|
|
||||||
|
public void Render(Texture texture, int x, int y)
|
||||||
|
{
|
||||||
|
Render(texture, x, y, ref _defaultSpriteColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(Texture texture, int x, int y, ref Color color)
|
||||||
|
{
|
||||||
|
y = FixYCoord(y, texture.Height);
|
||||||
|
AddSprite(texture, x, y, x + texture.Width, y + texture.Height, 0, 0, texture.Width, texture.Height, ref color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(Texture texture, int x, int y, int width, int height)
|
||||||
|
{
|
||||||
|
Render(texture, x, y, width, height, ref _defaultSpriteColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(Texture texture, int x, int y, int width, int height, ref Color color)
|
||||||
|
{
|
||||||
|
y = FixYCoord(y, height);
|
||||||
|
AddSprite(texture, x, y, x + width, y + height, 0, 0, width, height, ref color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(Texture texture, int x, int y, float texCoordLeft, float texCoordTop, float texCoordRight, float texCoordBottom)
|
||||||
|
{
|
||||||
|
Render(texture, x, y, texCoordLeft, texCoordTop, texCoordRight, texCoordBottom, ref _defaultSpriteColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(Texture texture, int x, int y, float texCoordLeft, float texCoordTop, float texCoordRight, float texCoordBottom, ref Color color)
|
||||||
|
{
|
||||||
|
y = FixYCoord(y, texture.Height);
|
||||||
|
AddSprite(texture, x, y, x + texture.Width, y + texture.Height, texCoordLeft, texCoordTop, texCoordRight, texCoordBottom, ref color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(Texture texture, int x, int y, int width, int height, float texCoordLeft, float texCoordTop, float texCoordRight, float texCoordBottom)
|
||||||
|
{
|
||||||
|
Render(texture, x, y, width, height, texCoordLeft, texCoordTop, texCoordRight, texCoordBottom, ref _defaultSpriteColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(Texture texture, int x, int y, int width, int height, float texCoordLeft, float texCoordTop, float texCoordRight, float texCoordBottom, ref Color color)
|
||||||
|
{
|
||||||
|
y = FixYCoord(y, height);
|
||||||
|
AddSprite(texture, x, y, x + width, y + height, texCoordLeft, texCoordTop, texCoordRight, texCoordBottom, ref color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(Texture texture, ref Vector3 worldPosition)
|
||||||
|
{
|
||||||
|
Render(texture, ref worldPosition, ref _defaultSpriteColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(Texture texture, ref Vector3 worldPosition, ref Color color)
|
||||||
|
{
|
||||||
|
var screenCoordinates = GraphicsDevice.ViewContext.Camera.Project(ref worldPosition, ref _previousModelView, ref _previousProjection);
|
||||||
|
|
||||||
|
screenCoordinates.X -= texture.Width / 2;
|
||||||
|
screenCoordinates.Y -= texture.Height / 2;
|
||||||
|
|
||||||
|
Render(texture, screenCoordinates.X, screenCoordinates.Y, ref color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(Texture texture, ref Vector3 worldPosition, int width, int height)
|
||||||
|
{
|
||||||
|
Render(texture, ref worldPosition, width, height, ref _defaultSpriteColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(Texture texture, ref Vector3 worldPosition, int width, int height, ref Color color)
|
||||||
|
{
|
||||||
|
var screenCoordinates = GraphicsDevice.ViewContext.Camera.Project(ref worldPosition, ref _previousModelView, ref _previousProjection);
|
||||||
|
|
||||||
|
screenCoordinates.X -= width / 2;
|
||||||
|
screenCoordinates.Y -= height / 2;
|
||||||
|
|
||||||
|
Render(texture, screenCoordinates.X, screenCoordinates.Y, width, height, ref color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(Texture texture, ref Vector3 worldPosition, float texCoordLeft, float texCoordTop, float texCoordRight, float texCoordBottom)
|
||||||
|
{
|
||||||
|
Render(texture, ref worldPosition, texCoordLeft, texCoordTop, texCoordRight, texCoordBottom, ref _defaultSpriteColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(Texture texture, ref Vector3 worldPosition, float texCoordLeft, float texCoordTop, float texCoordRight, float texCoordBottom, ref Color color)
|
||||||
|
{
|
||||||
|
var screenCoordinates = GraphicsDevice.ViewContext.Camera.Project(ref worldPosition, ref _previousModelView, ref _previousProjection);
|
||||||
|
|
||||||
|
screenCoordinates.X -= texture.Width / 2;
|
||||||
|
screenCoordinates.Y -= texture.Height / 2;
|
||||||
|
|
||||||
|
Render(texture, screenCoordinates.X, screenCoordinates.Y, texCoordLeft, texCoordTop, texCoordRight, texCoordBottom, ref color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(Texture texture, ref Vector3 worldPosition, int width, int height, float texCoordLeft, float texCoordTop, float texCoordRight, float texCoordBottom)
|
||||||
|
{
|
||||||
|
Render(texture, ref worldPosition, width, height, texCoordLeft, texCoordTop, texCoordRight, texCoordBottom, ref _defaultSpriteColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(Texture texture, ref Vector3 worldPosition, int width, int height, float texCoordLeft, float texCoordTop, float texCoordRight, float texCoordBottom, ref Color color)
|
||||||
|
{
|
||||||
|
var screenCoordinates = GraphicsDevice.ViewContext.Camera.Project(ref worldPosition, ref _previousModelView, ref _previousProjection);
|
||||||
|
|
||||||
|
screenCoordinates.X -= width / 2;
|
||||||
|
screenCoordinates.Y -= height / 2;
|
||||||
|
|
||||||
|
Render(texture, screenCoordinates.X, screenCoordinates.Y, width, height, texCoordLeft, texCoordTop, texCoordRight, texCoordBottom, ref color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(TextureAtlas atlas, int index, int x, int y)
|
||||||
|
{
|
||||||
|
Render(atlas, index, x, y, ref _defaultSpriteColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(TextureAtlas atlas, int index, int x, int y, ref Color color)
|
||||||
|
{
|
||||||
|
RectF texCoords;
|
||||||
|
Rect dimensions;
|
||||||
|
atlas.GetTileTexCoords(index, out texCoords);
|
||||||
|
atlas.GetTileDimensions(index, out dimensions);
|
||||||
|
|
||||||
|
y = FixYCoord(y, dimensions.Height);
|
||||||
|
AddSprite(atlas.Texture, x, y, x + dimensions.Width, y + dimensions.Height, texCoords.Left, texCoords.Top, texCoords.Right, texCoords.Bottom, ref color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(TextureAtlas atlas, int index, int x, int y, int width, int height)
|
||||||
|
{
|
||||||
|
Render(atlas, index, x, y, width, height, ref _defaultSpriteColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(TextureAtlas atlas, int index, int x, int y, int width, int height, ref Color color)
|
||||||
|
{
|
||||||
|
RectF texCoords;
|
||||||
|
atlas.GetTileTexCoords(index, out texCoords);
|
||||||
|
|
||||||
|
y = FixYCoord(y, height);
|
||||||
|
AddSprite(atlas.Texture, x, y, x + width, y + height, texCoords.Left, texCoords.Top, texCoords.Right, texCoords.Bottom, ref color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(TextureAtlas atlas, int index, ref Vector3 worldPosition)
|
||||||
|
{
|
||||||
|
Render(atlas, index, ref worldPosition, ref _defaultSpriteColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(TextureAtlas atlas, int index, ref Vector3 worldPosition, ref Color color)
|
||||||
|
{
|
||||||
|
var screenCoordinates = GraphicsDevice.ViewContext.Camera.Project(ref worldPosition, ref _previousModelView, ref _previousProjection);
|
||||||
|
|
||||||
|
var tile = atlas.GetTile(index);
|
||||||
|
screenCoordinates.X -= tile.Dimensions.Width / 2;
|
||||||
|
screenCoordinates.Y -= tile.Dimensions.Height / 2;
|
||||||
|
|
||||||
|
Render(atlas, index, screenCoordinates.X, screenCoordinates.Y, ref color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(TextureAtlas atlas, int index, ref Vector3 worldPosition, int width, int height)
|
||||||
|
{
|
||||||
|
Render(atlas, index, ref worldPosition, width, height, ref _defaultSpriteColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(TextureAtlas atlas, int index, ref Vector3 worldPosition, int width, int height, ref Color color)
|
||||||
|
{
|
||||||
|
var screenCoordinates = GraphicsDevice.ViewContext.Camera.Project(ref worldPosition, ref _previousModelView, ref _previousProjection);
|
||||||
|
|
||||||
|
screenCoordinates.X -= width / 2;
|
||||||
|
screenCoordinates.Y -= height / 2;
|
||||||
|
|
||||||
|
Render(atlas, index, screenCoordinates.X, screenCoordinates.Y, width, height, ref color);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Render: Fonts
|
||||||
|
|
||||||
|
public void Render(SpriteFont font, int x, int y, ref Color color, string text)
|
||||||
|
{
|
||||||
|
y = FixYCoord(y, font.LetterHeight);
|
||||||
|
|
||||||
|
int drawX = x;
|
||||||
|
int drawY = y;
|
||||||
|
|
||||||
|
for (int i = 0; i < text.Length; ++i)
|
||||||
|
{
|
||||||
|
char c = text[i];
|
||||||
|
if (c == '\n')
|
||||||
|
{
|
||||||
|
// new line
|
||||||
|
drawX = x;
|
||||||
|
drawY -= font.LetterHeight;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RectF texCoords;
|
||||||
|
Rect dimensions;
|
||||||
|
font.GetCharTexCoords(c, out texCoords);
|
||||||
|
font.GetCharDimensions(c, out dimensions);
|
||||||
|
|
||||||
|
AddSprite(
|
||||||
|
font.Texture,
|
||||||
|
drawX, drawY, drawX + dimensions.Width, drawY + dimensions.Height,
|
||||||
|
texCoords.Left, texCoords.Top, texCoords.Right, texCoords.Bottom,
|
||||||
|
ref color
|
||||||
|
);
|
||||||
|
|
||||||
|
drawX += dimensions.Width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(SpriteFont font, int x, int y, ref Color color, float scale, string text)
|
||||||
|
{
|
||||||
|
float scaledLetterHeight = (float)font.LetterHeight * scale;
|
||||||
|
|
||||||
|
y = (int)FixYCoord(y, scaledLetterHeight);
|
||||||
|
|
||||||
|
float drawX = (float)x;
|
||||||
|
float drawY = (float)y;
|
||||||
|
|
||||||
|
for (int i = 0; i < text.Length; ++i)
|
||||||
|
{
|
||||||
|
char c = text[i];
|
||||||
|
if (c == '\n')
|
||||||
|
{
|
||||||
|
// new line
|
||||||
|
drawX = (float)x;
|
||||||
|
drawY -= scaledLetterHeight;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RectF texCoords;
|
||||||
|
Rect dimensions;
|
||||||
|
font.GetCharTexCoords(c, out texCoords);
|
||||||
|
font.GetCharDimensions(c, out dimensions);
|
||||||
|
|
||||||
|
float scaledGlyphWidth = (float)dimensions.Width * scale;
|
||||||
|
float scaledGlyphHeight = (float)dimensions.Height * scale;
|
||||||
|
|
||||||
|
AddSprite(
|
||||||
|
font.Texture,
|
||||||
|
drawX, drawY, drawX + scaledGlyphWidth, drawY + scaledGlyphHeight,
|
||||||
|
texCoords.Left, texCoords.Top, texCoords.Right, texCoords.Bottom,
|
||||||
|
ref color
|
||||||
|
);
|
||||||
|
|
||||||
|
drawX += scaledGlyphWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(SpriteFont font, ref Vector3 worldPosition, ref Color color, string text)
|
||||||
|
{
|
||||||
|
var screenCoordinates = GraphicsDevice.ViewContext.Camera.Project(ref worldPosition, ref _previousModelView, ref _previousProjection);
|
||||||
|
|
||||||
|
int textWidth;
|
||||||
|
int textHeight;
|
||||||
|
font.MeasureString(out textWidth, out textHeight, text);
|
||||||
|
|
||||||
|
screenCoordinates.X -= textWidth / 2;
|
||||||
|
screenCoordinates.Y -= textHeight / 2;
|
||||||
|
|
||||||
|
Render(font, screenCoordinates.X, screenCoordinates.Y, ref color, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(SpriteFont font, ref Vector3 worldPosition, ref Color color, float scale, string text)
|
||||||
|
{
|
||||||
|
var screenCoordinates = GraphicsDevice.ViewContext.Camera.Project(ref worldPosition, ref _previousModelView, ref _previousProjection);
|
||||||
|
|
||||||
|
int textWidth;
|
||||||
|
int textHeight;
|
||||||
|
font.MeasureString(out textWidth, out textHeight, scale, text);
|
||||||
|
|
||||||
|
screenCoordinates.X -= textWidth / 2;
|
||||||
|
screenCoordinates.Y -= textHeight / 2;
|
||||||
|
|
||||||
|
Render(font, screenCoordinates.X, screenCoordinates.Y, ref color, scale, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Printf(SpriteFont font, int x, int y, ref Color color, string format, params object[] args)
|
||||||
|
{
|
||||||
|
_buffer.Clear();
|
||||||
|
_buffer.AppendFormat(format, args);
|
||||||
|
|
||||||
|
Render(font, x, y, ref color, _buffer.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Printf(SpriteFont font, int x, int y, ref Color color, float scale, string format, params object[] args)
|
||||||
|
{
|
||||||
|
_buffer.Clear();
|
||||||
|
_buffer.AppendFormat(format, args);
|
||||||
|
|
||||||
|
Render(font, x, y, ref color, scale, _buffer.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Printf(SpriteFont font, ref Vector3 worldPosition, ref Color color, string format, params object[] args)
|
||||||
|
{
|
||||||
|
_buffer.Clear();
|
||||||
|
_buffer.AppendFormat(format, args);
|
||||||
|
|
||||||
|
Render(font, ref worldPosition, ref color, _buffer.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Printf(SpriteFont font, ref Vector3 worldPosition, ref Color color, float scale, string format, params object[] args)
|
||||||
|
{
|
||||||
|
_buffer.Clear();
|
||||||
|
_buffer.AppendFormat(format, args);
|
||||||
|
|
||||||
|
Render(font, ref worldPosition, ref color, scale, _buffer.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Internal Sprite Addition / Management
|
||||||
|
|
||||||
|
private void AddSprite(Texture texture, int destLeft, int destTop, int destRight, int destBottom, int sourceLeft, int sourceTop, int sourceRight, int sourceBottom, ref Color color)
|
||||||
|
{
|
||||||
|
if (!_hasBegunRendering)
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
|
||||||
|
int width = sourceRight - sourceLeft;
|
||||||
|
if (width < 1)
|
||||||
|
throw new InvalidOperationException("Zero-length width");
|
||||||
|
|
||||||
|
int height = sourceBottom - sourceTop;
|
||||||
|
if (height < 1)
|
||||||
|
throw new InvalidOperationException("Zero-length height.");
|
||||||
|
|
||||||
|
float texLeft = sourceLeft / (float)width;
|
||||||
|
float texTop = sourceTop / (float)height;
|
||||||
|
float texRight = sourceRight / (float)width;
|
||||||
|
float texBottom = sourceBottom / (float)height;
|
||||||
|
float destLeftF = (float)destLeft;
|
||||||
|
float destTopF = (float)destTop;
|
||||||
|
float destRightF = (float)destRight;
|
||||||
|
float destBottomF = (float)destBottom;
|
||||||
|
|
||||||
|
if (_isClipping)
|
||||||
|
{
|
||||||
|
if (!ClipSpriteCoords(ref destLeftF, ref destTopF, ref destRightF, ref destBottomF, ref texLeft, ref texTop, ref texRight, ref texBottom))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetRemainingSpriteSpaces() < 1)
|
||||||
|
AddMoreSpriteSpace(ResizeSpriteIncrement);
|
||||||
|
|
||||||
|
SetSpriteInfo(_currentSpritePointer, texture, destLeftF, destTopF, destRightF, destBottomF, texLeft, texTop, texRight, texBottom, ref color);
|
||||||
|
++_currentSpritePointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddSprite(Texture texture, int destLeft, int destTop, int destRight, int destBottom, float texCoordLeft, float texCoordTop, float texCoordRight, float texCoordBottom, ref Color color)
|
||||||
|
{
|
||||||
|
if (!_hasBegunRendering)
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
|
||||||
|
float destLeftF = (float)destLeft;
|
||||||
|
float destTopF = (float)destTop;
|
||||||
|
float destRightF = (float)destRight;
|
||||||
|
float destBottomF = (float)destBottom;
|
||||||
|
|
||||||
|
if (_isClipping)
|
||||||
|
{
|
||||||
|
if (!ClipSpriteCoords(ref destLeftF, ref destTopF, ref destRightF, ref destBottomF, ref texCoordLeft, ref texCoordTop, ref texCoordRight, ref texCoordBottom))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetRemainingSpriteSpaces() < 1)
|
||||||
|
AddMoreSpriteSpace(ResizeSpriteIncrement);
|
||||||
|
|
||||||
|
SetSpriteInfo(_currentSpritePointer, texture, destLeftF, destTopF, destRightF, destBottomF, texCoordLeft, texCoordTop, texCoordRight, texCoordBottom, ref color);
|
||||||
|
++_currentSpritePointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddSprite(Texture texture, float destLeft, float destTop, float destRight, float destBottom, float texCoordLeft, float texCoordTop, float texCoordRight, float texCoordBottom, ref Color color)
|
||||||
|
{
|
||||||
|
if (!_hasBegunRendering)
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
|
||||||
|
if (_isClipping)
|
||||||
|
{
|
||||||
|
if (!ClipSpriteCoords(ref destLeft, ref destTop, ref destRight, ref destBottom, ref texCoordLeft, ref texCoordTop, ref texCoordRight, ref texCoordBottom))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetRemainingSpriteSpaces() < 1)
|
||||||
|
AddMoreSpriteSpace(ResizeSpriteIncrement);
|
||||||
|
|
||||||
|
SetSpriteInfo(_currentSpritePointer, texture, destLeft, destTop, destRight, destBottom, texCoordLeft, texCoordTop, texCoordRight, texCoordBottom, ref color);
|
||||||
|
++_currentSpritePointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetSpriteInfo(int spriteIndex, Texture texture, float destLeft, float destTop, float destRight, float destBottom, float texCoordLeft, float texCoordTop, float texCoordRight, float texCoordBottom, ref Color color)
|
||||||
|
{
|
||||||
|
int baseVertexIndex = spriteIndex * VerticesPerSprite;
|
||||||
|
|
||||||
|
_vertices.SetPosition2D(baseVertexIndex + 0, destLeft, destTop);
|
||||||
|
_vertices.SetPosition2D(baseVertexIndex + 1, destRight, destTop);
|
||||||
|
_vertices.SetPosition2D(baseVertexIndex + 2, destRight, destBottom);
|
||||||
|
_vertices.SetPosition2D(baseVertexIndex + 3, destLeft, destBottom);
|
||||||
|
|
||||||
|
_vertices.SetTexCoord(baseVertexIndex + 0, texCoordLeft, texCoordBottom);
|
||||||
|
_vertices.SetTexCoord(baseVertexIndex + 1, texCoordRight, texCoordBottom);
|
||||||
|
_vertices.SetTexCoord(baseVertexIndex + 2, texCoordRight, texCoordTop);
|
||||||
|
_vertices.SetTexCoord(baseVertexIndex + 3, texCoordLeft, texCoordTop);
|
||||||
|
|
||||||
|
_vertices.SetColor(baseVertexIndex + 0, ref color);
|
||||||
|
_vertices.SetColor(baseVertexIndex + 1, ref color);
|
||||||
|
_vertices.SetColor(baseVertexIndex + 2, ref color);
|
||||||
|
_vertices.SetColor(baseVertexIndex + 3, ref color);
|
||||||
|
|
||||||
|
_textures[spriteIndex] = texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetRemainingSpriteSpaces()
|
||||||
|
{
|
||||||
|
int currentMaxSprites = _vertices.NumElements / VerticesPerSprite;
|
||||||
|
return currentMaxSprites - _currentSpritePointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddMoreSpriteSpace(int numSprites)
|
||||||
|
{
|
||||||
|
int numVerticesToAdd = numSprites * VerticesPerSprite;
|
||||||
|
int numIndicesToAdd = numSprites * IndicesPerSprite;
|
||||||
|
int newTextureArraySize = _textures.Length + numSprites;
|
||||||
|
|
||||||
|
int oldSpriteCount = _vertices.NumElements / VerticesPerSprite;
|
||||||
|
|
||||||
|
_vertices.Extend(numVerticesToAdd);
|
||||||
|
_indices.Extend(numIndicesToAdd);
|
||||||
|
Array.Resize(ref _textures, newTextureArraySize);
|
||||||
|
|
||||||
|
int newSpriteCount = _vertices.NumElements / VerticesPerSprite;
|
||||||
|
|
||||||
|
FillSpriteIndicesFor(oldSpriteCount - 1, newSpriteCount - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FillSpriteIndicesFor(int firstSprite, int lastSprite)
|
||||||
|
{
|
||||||
|
for (int i = firstSprite; i <= lastSprite; ++i)
|
||||||
|
{
|
||||||
|
int indicesStart = i * IndicesPerSprite;
|
||||||
|
int verticesStart = i * VerticesPerSprite;
|
||||||
|
|
||||||
|
_indices.Set(indicesStart + 0, (ushort)(verticesStart + 0));
|
||||||
|
_indices.Set(indicesStart + 1, (ushort)(verticesStart + 1));
|
||||||
|
_indices.Set(indicesStart + 2, (ushort)(verticesStart + 2));
|
||||||
|
_indices.Set(indicesStart + 3, (ushort)(verticesStart + 0));
|
||||||
|
_indices.Set(indicesStart + 4, (ushort)(verticesStart + 2));
|
||||||
|
_indices.Set(indicesStart + 5, (ushort)(verticesStart + 3));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int FixYCoord(int y, int sourceHeight)
|
||||||
|
{
|
||||||
|
return GraphicsDevice.ViewContext.ViewportHeight - y - sourceHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float FixYCoord(int y, float sourceHeight)
|
||||||
|
{
|
||||||
|
return (float)GraphicsDevice.ViewContext.ViewportHeight - (float)y - sourceHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Clipping
|
||||||
|
|
||||||
|
public void BeginClipping(ref Rect region)
|
||||||
|
{
|
||||||
|
if (!_hasBegunRendering)
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
if (_isClipping)
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
|
||||||
|
_isClipping = true;
|
||||||
|
|
||||||
|
int fixedTop = ((int)GraphicsDevice.ViewContext.ViewportHeight - region.Top - region.Height);
|
||||||
|
int fixedBottom = fixedTop + region.Height;
|
||||||
|
|
||||||
|
_clipRegion.Left = (float)region.Left;
|
||||||
|
_clipRegion.Top = (float)fixedTop;
|
||||||
|
_clipRegion.Right = (float)region.Right;
|
||||||
|
_clipRegion.Bottom = (float)fixedBottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void BeginClipping(int left, int top, int right, int bottom)
|
||||||
|
{
|
||||||
|
Rect r = new Rect();
|
||||||
|
r.Left = left;
|
||||||
|
r.Top = top;
|
||||||
|
r.Right = right;
|
||||||
|
r.Bottom = bottom;
|
||||||
|
BeginClipping(ref r);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EndClipping()
|
||||||
|
{
|
||||||
|
if (!_hasBegunRendering)
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
|
||||||
|
_isClipping = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ClipSpriteCoords(ref float left, ref float top, ref float right, ref float bottom, ref float texCoordLeft, ref float texCoordTop, ref float texCoordRight, ref float texCoordBottom)
|
||||||
|
{
|
||||||
|
// check for completely out of bounds scenarios first
|
||||||
|
if (left >= _clipRegion.Right)
|
||||||
|
return false;
|
||||||
|
if (right < _clipRegion.Left)
|
||||||
|
return false;
|
||||||
|
if (top >= _clipRegion.Bottom)
|
||||||
|
return false;
|
||||||
|
if (bottom < _clipRegion.Top)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
float clippedLeft = left;
|
||||||
|
float clippedTop = top;
|
||||||
|
float clippedRight = right;
|
||||||
|
float clippedBottom = bottom;
|
||||||
|
float clippedTexCoordLeft = texCoordLeft;
|
||||||
|
float clippedTexCoordTop = texCoordTop;
|
||||||
|
float clippedTexCoordRight = texCoordRight;
|
||||||
|
float clippedTexCoordBottom = texCoordBottom;
|
||||||
|
|
||||||
|
if (clippedLeft < _clipRegion.Left)
|
||||||
|
{
|
||||||
|
clippedLeft = _clipRegion.Left;
|
||||||
|
float t = MathHelpers.InverseLerp(left, right, clippedLeft);
|
||||||
|
clippedTexCoordLeft = MathHelpers.Lerp(texCoordLeft, texCoordRight, t);
|
||||||
|
}
|
||||||
|
if (clippedRight > _clipRegion.Right)
|
||||||
|
{
|
||||||
|
clippedRight = _clipRegion.Right;
|
||||||
|
float t = MathHelpers.InverseLerp(right, left, clippedRight);
|
||||||
|
clippedTexCoordRight = MathHelpers.Lerp(texCoordRight, texCoordLeft, t);
|
||||||
|
}
|
||||||
|
if (clippedTop < _clipRegion.Top)
|
||||||
|
{
|
||||||
|
clippedTop = _clipRegion.Top;
|
||||||
|
float t = MathHelpers.InverseLerp(top, bottom, clippedTop);
|
||||||
|
clippedTexCoordBottom = MathHelpers.Lerp(texCoordBottom, texCoordTop, t);
|
||||||
|
}
|
||||||
|
if (clippedBottom > _clipRegion.Bottom)
|
||||||
|
{
|
||||||
|
clippedBottom = _clipRegion.Bottom;
|
||||||
|
float t = MathHelpers.InverseLerp(bottom, top, clippedBottom);
|
||||||
|
clippedTexCoordTop = MathHelpers.Lerp(texCoordTop, texCoordBottom, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
left = clippedLeft;
|
||||||
|
top = clippedTop;
|
||||||
|
right = clippedRight;
|
||||||
|
bottom = clippedBottom;
|
||||||
|
texCoordLeft = clippedTexCoordLeft;
|
||||||
|
texCoordTop = clippedTexCoordTop;
|
||||||
|
texCoordRight = clippedTexCoordRight;
|
||||||
|
texCoordBottom = clippedTexCoordBottom;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
Reference in a new issue