Scissoring now works and implemented; Refactoring as well;

This commit is contained in:
Harrison Deng 2019-03-27 02:35:20 -05:00
parent b045033b25
commit d7ca521b9b
17 changed files with 129 additions and 119 deletions

View File

@ -52,8 +52,9 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Render\BasicCamera.cs" />
<Compile Include="Render\BasicScissor.cs" />
<Compile Include="Render\ConsistentSpriteBatch.cs" />
<Compile Include="Render\ScissorBox.cs" />
<Compile Include="Render\StencilBufferMask.cs" />
<Compile Include="Render\Camera2D.cs" />
<Compile Include="ContentSystem\ContentData.cs" />
<Compile Include="ContentSystem\ContentManagerController.cs" />

View File

@ -1,8 +1,7 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
namespace RecrownedAthenaeum.Camera
namespace RecrownedAthenaeum.Render
{
/// <summary>
/// A generic camera. Functions in 3D.

View File

@ -0,0 +1,60 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RecrownedAthenaeum.Render
{
/// <summary>
/// A simple utility object that will start and end a scissor setup given a <see cref="ConsistentSpriteBatch"/> to work with.
/// </summary>
public class BasicScissor
{
ConsistentSpriteBatch spriteBatch;
RasterizerState scissorRasterizer;
Rectangle scissorRectangle;
RasterizerState originalRasterizer;
Rectangle originalScissor;
/// <summary>
/// Initializes the basic scissor.
/// </summary>
public BasicScissor()
{
scissorRasterizer = new RasterizerState();
scissorRasterizer.MultiSampleAntiAlias = false;
scissorRasterizer.ScissorTestEnable = true;
}
/// <summary>
/// Begins the <see cref="ConsistentSpriteBatch"/> with scissoring in mind.
/// </summary>
/// <param name="scissorRectangle">The rectangle to use to outline the scissor.</param>
/// <param name="consistentSpriteBatch">The consistent sprite batch to use for this process.</param>
public void Begin(Rectangle scissorRectangle, ConsistentSpriteBatch consistentSpriteBatch)
{
originalRasterizer = consistentSpriteBatch.rasterizerState;
this.scissorRectangle = scissorRectangle;
spriteBatch = consistentSpriteBatch;
spriteBatch.Begin(rasterizerState: scissorRasterizer);
}
/// <summary>
/// Ends the scissor state of the spritebatch.
/// </summary>
public void End()
{
originalScissor = spriteBatch.GraphicsDevice.ScissorRectangle;
spriteBatch.GraphicsDevice.ScissorRectangle = scissorRectangle;
spriteBatch.End();
spriteBatch.rasterizerState = originalRasterizer;
spriteBatch.GraphicsDevice.ScissorRectangle = originalScissor;
}
}
}

View File

@ -2,7 +2,7 @@
using Microsoft.Xna.Framework.Graphics;
using System;
namespace RecrownedAthenaeum.Camera
namespace RecrownedAthenaeum.Render
{
/// <summary>
/// A virtual 2D camera that wraps the normal <see cref="BasicCamera"/>. Default projection is orthographic.

View File

@ -1,15 +1,11 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RecrownedAthenaeum.Render
{
/// <summary>
/// A <see cref="SpriteBatch"/> that keeps it's settings through begin and end unless manually changed either by the <see cref="Begin(SpriteSortMode, BlendState, SamplerState, DepthStencilState, RasterizerState, Effect, Matrix?)"/> or through changing the fields. Note that changing the fields while the batch has begun will not take effect until the next time the batch is started.
/// Casting this as a <see cref="SpriteBatch"/> will not persist the configuration and will call the normal <see cref="SpriteBatch.Begin(SpriteSortMode, BlendState, SamplerState, DepthStencilState, RasterizerState, Effect, Matrix?)"/>.
/// </summary>
public class ConsistentSpriteBatch : SpriteBatch
{
@ -17,37 +13,37 @@ namespace RecrownedAthenaeum.Render
/// How to blend the colors. Uses <see cref="SpriteBatch"/>'s default if not set before or during <see cref="Begin(SpriteSortMode, BlendState, SamplerState, DepthStencilState, RasterizerState, Effect, Matrix?)"/> call.
/// Changes will only take effect on <see cref="Begin(SpriteSortMode, BlendState, SamplerState, DepthStencilState, RasterizerState, Effect, Matrix?)"/> call.
/// </summary>
public BlendState BlendState;
public BlendState blendState;
/// <summary>
/// The state of sampler to use for the spritebatch. Uses <see cref="SpriteBatch"/>'s default if not set before or during <see cref="Begin(SpriteSortMode, BlendState, SamplerState, DepthStencilState, RasterizerState, Effect, Matrix?)"/> call.
/// Changes will only take effect on <see cref="Begin(SpriteSortMode, BlendState, SamplerState, DepthStencilState, RasterizerState, Effect, Matrix?)"/> call.
/// </summary>
public SamplerState SamplerState;
public SamplerState samplerState;
/// <summary>
/// The state of the depth-stencil buffer. Uses <see cref="SpriteBatch"/>'s defaultdefault if not set before or during <see cref="Begin(SpriteSortMode, BlendState, SamplerState, DepthStencilState, RasterizerState, Effect, Matrix?)"/> call.
/// Changes will only take effect on <see cref="Begin(SpriteSortMode, BlendState, SamplerState, DepthStencilState, RasterizerState, Effect, Matrix?)"/> call.
/// </summary>
public DepthStencilState DepthStencilState;
public DepthStencilState depthStencilState;
/// <summary>
/// The state of rasterizer to use. Uses <see cref="SpriteBatch"/>'s default if not set before or during <see cref="Begin(SpriteSortMode, BlendState, SamplerState, DepthStencilState, RasterizerState, Effect, Matrix?)"/> call.
/// Changes will only take effect on <see cref="Begin(SpriteSortMode, BlendState, SamplerState, DepthStencilState, RasterizerState, Effect, Matrix?)"/> call.
/// </summary>
public RasterizerState RasterizerState;
public RasterizerState rasterizerState;
/// <summary>
/// An effect to apply to the batch. Uses <see cref="SpriteBatch"/>'s default if not set before or during <see cref="Begin(SpriteSortMode, BlendState, SamplerState, DepthStencilState, RasterizerState, Effect, Matrix?)"/> call.
/// Changes will only take effect on <see cref="Begin(SpriteSortMode, BlendState, SamplerState, DepthStencilState, RasterizerState, Effect, Matrix?)"/> call.
/// </summary>
public Effect Effect;
public Effect effect;
/// <summary>
/// A matrix to be applied to transform the sprites geometry. An identity matrix is used if not provided before or during <see cref="Begin(SpriteSortMode, BlendState, SamplerState, DepthStencilState, RasterizerState, Effect, Matrix?)"/> call.
/// Changes will only take effect on <see cref="Begin(SpriteSortMode, BlendState, SamplerState, DepthStencilState, RasterizerState, Effect, Matrix?)"/> call.
/// </summary>
public Matrix? TransformMatrix;
public Matrix? transformMatrix;
/// <summary>
/// Creates a consistent sprite batch with default values.
@ -58,7 +54,7 @@ namespace RecrownedAthenaeum.Render
}
/// <summary>
/// Begins the consistent sprite batch.
/// Begins the consistent sprite batch. The configuration passed to this function is saved for later begin calls.
/// </summary>
/// <param name="sortMode">Defines the spritebatch's method of sorting the items in each batch. Uses <see cref="SpriteBatch"/>'s default.</param>
/// <param name="blendState">How to blend the colors. Uses <see cref="SpriteBatch"/>'s default if not set and field is also not set.</param>
@ -66,24 +62,46 @@ namespace RecrownedAthenaeum.Render
/// <param name="depthStencilState">What type of rasterization to use. Uses <see cref="SpriteBatch"/>'s default if not set and field is also not set.</param>
/// <param name="rasterizerState">What type of rasterization to use. Uses <see cref="SpriteBatch"/>'s default if not set and field is also not set.</param>
/// <param name="effect">An effect to apply to the batch. Uses <see cref="SpriteBatch"/>'s default if not set and field is also not set.</param>
/// <param name="transformMatrix">A matrix to be applied to transform the sprites geometry. An identity is used if not provided.</param>
/// <param name="transformMatrix">A matrix to be applied to transform the sprites geometry. Uses <see cref="SpriteBatch"/>'s default if not set and field is also not set.</param>
public new void Begin(SpriteSortMode sortMode = SpriteSortMode.Deferred, BlendState blendState = null, SamplerState samplerState = null, DepthStencilState depthStencilState = null, RasterizerState rasterizerState = null, Effect effect = null, Matrix? transformMatrix = null)
{
if (blendState != null) this.BlendState = blendState;
if (samplerState != null) this.SamplerState = samplerState;
if (depthStencilState != null) this.DepthStencilState = depthStencilState;
if (rasterizerState != null) this.RasterizerState = rasterizerState;
if (effect != null) this.Effect = effect;
if (transformMatrix != null) this.TransformMatrix = transformMatrix;
if (blendState != null) this.blendState = blendState;
if (samplerState != null) this.samplerState = samplerState;
if (depthStencilState != null) this.depthStencilState = depthStencilState;
if (rasterizerState != null) this.rasterizerState = rasterizerState;
if (effect != null) this.effect = effect;
if (transformMatrix != null) this.transformMatrix = transformMatrix;
base.Begin(
sortMode: sortMode,
blendState: blendState,
samplerState: samplerState,
depthStencilState: depthStencilState,
rasterizerState: rasterizerState,
effect: effect,
transformMatrix: transformMatrix);
blendState: this.blendState,
samplerState: this.samplerState,
depthStencilState: this.depthStencilState,
rasterizerState: this.rasterizerState,
effect: this.effect,
transformMatrix: this.transformMatrix);
}
/// <summary>
/// Begins the consistent sprite batch without saving the configuration. Useful for one time changes to one portion of the configuration.
/// </summary>
/// <param name="sortMode">Defines the spritebatch's method of sorting the items in each batch. Uses <see cref="SpriteBatch"/>'s default.</param>
/// <param name="blendState">How to blend the colors. Uses <see cref="SpriteBatch"/>'s default if not set and field is also not set.</param>
/// <param name="samplerState">The state of sampler to use for the spritebatch. Uses <see cref="SpriteBatch"/>'s default if not set and field is also not set.</param>
/// <param name="depthStencilState">What type of rasterization to use. Uses <see cref="SpriteBatch"/>'s default if not set and field is also not set.</param>
/// <param name="rasterizerState">What type of rasterization to use. Uses <see cref="SpriteBatch"/>'s default if not set and field is also not set.</param>
/// <param name="effect">An effect to apply to the batch. Uses <see cref="SpriteBatch"/>'s default if not set and field is also not set.</param>
/// <param name="transformMatrix">A matrix to be applied to transform the sprites geometry. Uses <see cref="SpriteBatch"/>'s default if not set and field is also not set.</param>
public void BeginWithoutSaving(SpriteSortMode sortMode = SpriteSortMode.Deferred, BlendState blendState = null, SamplerState samplerState = null, DepthStencilState depthStencilState = null, RasterizerState rasterizerState = null, Effect effect = null, Matrix? transformMatrix = null)
{
base.Begin(
sortMode: sortMode,
blendState: blendState ?? this.blendState,
samplerState: samplerState ?? this.samplerState,
depthStencilState: depthStencilState ?? this.depthStencilState,
rasterizerState: rasterizerState ?? this.rasterizerState,
effect: effect ?? this.effect,
transformMatrix: transformMatrix ?? this.transformMatrix);
}
}
}

View File

@ -1,6 +1,5 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using RecrownedAthenaeum.Camera;
using System;
namespace RecrownedAthenaeum.Render
@ -36,13 +35,17 @@ namespace RecrownedAthenaeum.Render
vertices = new VertexPositionColor[verticesPerBatch + 1];
this.graphicsDevice = graphicsDevice;
basicEffect = new BasicEffect(graphicsDevice);
basicEffect.VertexColorEnabled = true;
basicEffect.Projection = Matrix.CreateOrthographicOffCenter(0, graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height, 0, 0, 1);
basicEffect.World = Matrix.Identity;
basicEffect.View = Matrix.CreateLookAt(Vector3.Zero, Vector3.Forward, Vector3.Up);
}
/// <summary>
/// Starts the batch. Batch cannot be started twice.
/// </summary>
/// <param name="primitiveType">The type of primitive this batch would be drawing.</param>
/// <param name="effect">Effect to use to render the primitives. Default will use a <see cref="BasicEffect"/>.</param>
/// <param name="effect">Effect to use to render the primitives. Default will use a <see cref="BasicEffect"/> with parameters set up during creation.</param>
public void Begin(PrimitiveType primitiveType, Effect effect = null)
{
if (began) throw new InvalidOperationException("Begin is being called twice before being ended.");

View File

@ -1,6 +1,5 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using RecrownedAthenaeum.Camera;
using System;
namespace RecrownedAthenaeum.Render

View File

@ -1,52 +0,0 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace RecrownedAthenaeum.Render
{
/// <summary>
/// Box that crops off anything outside of the bounds.
/// </summary>
public class ScissorBox
{
ConsistentSpriteBatch spriteBatch;
Rectangle originalScissor;
RasterizerState originalRasterizerState;
RasterizerState scissorRasterizerState;
/// <summary>
/// Used to crop off anything that doesn't fit into the defined space.
/// </summary>
public ScissorBox()
{
scissorRasterizerState = new RasterizerState();
scissorRasterizerState.ScissorTestEnable = true;
}
/// <summary>
/// Starts spritebatch with scissoring enabled.
/// </summary>
/// <param name="rectangle"></param>
/// <param name="spriteBatch"></param>
public void Begin(Rectangle rectangle, ConsistentSpriteBatch spriteBatch)
{
this.spriteBatch = spriteBatch;
originalRasterizerState = spriteBatch.RasterizerState;
spriteBatch.Begin(rasterizerState: scissorRasterizerState);
originalScissor = spriteBatch.GraphicsDevice.ScissorRectangle;
spriteBatch.GraphicsDevice.ScissorRectangle = rectangle;
}
/// <summary>
/// Ends the scissoring and spritebatch.
/// </summary>
public void End()
{
spriteBatch.GraphicsDevice.ScissorRectangle = originalScissor;
spriteBatch.RasterizerState = originalRasterizerState;
spriteBatch.End();
}
}
}

View File

@ -1,6 +1,5 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using RecrownedAthenaeum.Camera;
using RecrownedAthenaeum.Render;
using System.Collections.Generic;

View File

@ -1,6 +1,5 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using RecrownedAthenaeum.Camera;
using RecrownedAthenaeum.Render;
using System;
using System.Diagnostics;

View File

@ -1,5 +1,4 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using RecrownedAthenaeum.Render;
namespace RecrownedAthenaeum.SpecialTypes

View File

@ -98,9 +98,7 @@ namespace RecrownedAthenaeum.SpecialTypes
throw new InvalidOperationException("Begin must be called to draw a nine patch!");
}
SamplerState originalSamplerState = spriteBatch.SamplerState;
GraphicsDevice graphics = spriteBatch.GraphicsDevice;
spriteBatch.Begin(samplerState: SamplerState.PointClamp);
spriteBatch.BeginWithoutSaving(samplerState: SamplerState.PointClamp);
Rectangle[] destinations = GenenerateDestinationRectangles(destination.Width, destination.Height);
for (int i = 0; i < destinations.Length; i++)
@ -111,7 +109,7 @@ namespace RecrownedAthenaeum.SpecialTypes
}
spriteBatch.End();
spriteBatch.Begin(samplerState: originalSamplerState);
spriteBatch.Begin();
}
/// <summary>

View File

@ -1,7 +1,5 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using RecrownedAthenaeum.Camera;
using RecrownedAthenaeum.ContentSystem;
using RecrownedAthenaeum.Input;
using RecrownedAthenaeum.Render;
@ -28,11 +26,7 @@ namespace RecrownedAthenaeum.UI.BookSystem
/// The camera to use to change between pages.
/// </summary>
public Camera2D camera;
/// <summary>
/// The scissorbox used to crop things.
/// </summary>
public ScissorBox scissorBox;
private BasicScissor basicScissor;
/// <summary>
/// Creates a book.
@ -40,14 +34,13 @@ namespace RecrownedAthenaeum.UI.BookSystem
/// <param name="assets"><see cref="ContentManagerController"/> that holds the assets that are to be used in the pages for this book during initialization.</param>
/// <param name="skin">The skin that will be passed to pages during their initialization.</param>
/// <param name="camera">Camera to move to change pages.</param>
/// <param name="scissorBox">The scissor box to use to crop the pages to the given dimensions. Default is null, and will not crop anything.</param>
public Book(ContentManagerController assets, ISkin skin, Camera2D camera, ScissorBox scissorBox = null)
public Book(ContentManagerController assets, ISkin skin, Camera2D camera)
{
this.assets = assets;
this.skin = skin;
this.camera = camera ?? throw new ArgumentNullException("Camera can't be null since book needs a camera to move to change between the slides (pages).");
this.scissorBox = scissorBox;
this.basicScissor = new BasicScissor();
}
/// <summary>
@ -57,8 +50,7 @@ namespace RecrownedAthenaeum.UI.BookSystem
/// </summary>
/// <param name="camera">Camera to move to change pages.</param>
/// <param name="dimensions">Dimensions of the book and the dimensions the pages will use.</param>
/// <param name="scissorBox">The scissor box to use to crop the pages to the given dimensions. Default is null, and will not crop anything.</param>
public void Initiate(Camera2D camera, Rectangle dimensions, ScissorBox scissorBox = null)
public void Initiate(Camera2D camera, Rectangle dimensions)
{
this.camera = camera;
}
@ -133,7 +125,7 @@ namespace RecrownedAthenaeum.UI.BookSystem
{
orderedPages.Add(page);
this.pages.Add(page.name, page);
page.Initialize(assets, skin, scissorBox);
page.Initialize(assets, skin, basicScissor);
}
}

View File

@ -48,10 +48,10 @@ namespace RecrownedAthenaeum.UI.BookSystem
/// </summary>
/// <param name="assets">The assets to be used during initialization passed by the book this page belongs to.</param>
/// <param name="skin">The skin the book containing this page is given that can be used by this page.</param>
/// <param name="scissorBox">The scissor box to use for cropping.</param>
protected internal virtual void Initialize(ContentManagerController assets, ISkin skin, ScissorBox scissorBox)
/// <param name="basicScissor">The scissor box to use for cropping.</param>
protected internal virtual void Initialize(ContentManagerController assets, ISkin skin, BasicScissor basicScissor)
{
this.scissorBox = scissorBox;
this.basicScissor = basicScissor;
}
}
}

View File

@ -1,5 +1,4 @@
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input;
using RecrownedAthenaeum.SpecialTypes;
using RecrownedAthenaeum.Input;
using RecrownedAthenaeum.UI.SkinSystem.Definitions;

View File

@ -1,5 +1,4 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using RecrownedAthenaeum.Input;
using RecrownedAthenaeum.Render;

View File

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using RecrownedAthenaeum.Render;
@ -18,18 +17,18 @@ namespace RecrownedAthenaeum.UI.Modular
/// <summary>
/// Set this to crop anything that flows out of the boundaries of this group. Will not crop if this is null.
/// </summary>
public ScissorBox scissorBox;
public BasicScissor basicScissor;
/// <summary>
/// Draws this group of modules. If scissoring, will use the matrix and effect designated in the <see cref="ScissorBox"/> to begin the batch normally again.
/// Draws this group of modules. If scissoring, will use the matrix and effect designated in the <see cref="BasicScissor"/> to begin the batch normally again.
/// </summary>
/// <param name="spriteBatch">Batch used to draw the group.</param>
public override void Draw(ConsistentSpriteBatch spriteBatch)
{
if (scissorBox != null)
if (basicScissor != null)
{
spriteBatch.End();
scissorBox.Begin(Boundaries, spriteBatch);
basicScissor.Begin(Boundaries, spriteBatch);
}
foreach (UIModule module in modules)
@ -43,11 +42,9 @@ namespace RecrownedAthenaeum.UI.Modular
module.situation.Y = offsetY;
}
if (scissorBox != null)
if (basicScissor != null)
{
scissorBox.End();
GraphicsDevice graphics = spriteBatch.GraphicsDevice;
basicScissor.End();
spriteBatch.Begin();
}
}