add SpriteBatch

This commit is contained in:
Gered 2013-08-18 12:59:17 -04:00
parent d53ed4147e
commit 2461a7ca26
2 changed files with 763 additions and 0 deletions

View file

@ -130,6 +130,7 @@
<Compile Include="Graphics\CustomShaders\CustomStandardShader.cs" />
<Compile Include="Graphics\CustomShaders\CustomVertexLerpShader.cs" />
<Compile Include="Graphics\CustomShaders\CustomVertexSkinningShader.cs" />
<Compile Include="Graphics\SpriteBatch.cs" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<ItemGroup>

View 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
}
}