Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for camera-specific post processing effects #1672

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4,081 changes: 2,023 additions & 2,058 deletions Engines/FlatRedBallXNA/FlatRedBall/Camera.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Graphics\Particle\EmitterList.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Graphics\Particle\TimedRemovalRecord.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Graphics\PostProcessing\IPostProcess.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Graphics\PostProcessing\PostProcessLogic.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Graphics\PostProcessing\SwapChain.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Graphics\RenderBreak.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Graphics\Renderer.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,6 @@ public enum TextureCoordinateType
}


public enum CameraModelCullMode
{
Frustum,
None
}

public enum CameraCullMode
{
UnrotatedDownZ,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,7 @@ public void Emit(SpriteList spriteList)

if (EmissionSettings.Billboarded)
{
SpriteManager.Camera.AddSpriteToBillboard(tempParticle);
tempParticle.IsBillboarded = true;
}


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace FlatRedBall.Graphics.PostProcessing;

internal static class PostProcessLogic
{
public static void DrawWithPostProcessing(List<IPostProcess> postProcesses,
SwapChain swapChain, Action drawCall)
{
bool hasGlobalPostProcessing = false;

foreach (var item in postProcesses)
{
if (item.IsEnabled)
{
hasGlobalPostProcessing = true;
break;
}
}
#if DEBUG
if (hasGlobalPostProcessing && swapChain == null)
{
throw new InvalidOperationException("SwapChain must be set prior to rendering the first frame if using any post processing");
}
#endif
if (hasGlobalPostProcessing)
{
SetStatesAndRenderTargetForPostProcessing(swapChain);
}
else
{
// Just in case we removed all post processing, but are on "B"
swapChain?.ResetForFrame();
}

drawCall();

if (hasGlobalPostProcessing)
{
ApplyPostProcessing(postProcesses, swapChain);
}
}

static void ApplyPostProcessing(List<IPostProcess> postProcesses, SwapChain swapChain)
{
foreach (var postProcess in postProcesses)
{
if (postProcess.IsEnabled)
{
#if DEBUG
Renderer.RenderBreaks.Add(new RenderBreak() { ObjectCausingBreak = postProcess });
#endif
swapChain.Swap();
postProcess.Apply(swapChain.CurrentTexture);
}
}

#if DEBUG
Renderer.RenderBreaks.Add(new RenderBreak() { ObjectCausingBreak = swapChain });
#endif
swapChain.RenderToScreen();
}

static void SetStatesAndRenderTargetForPostProcessing(SwapChain swapChain)
{
Renderer.ForceSetBlendOperation();
Renderer.ForceSetColorOperation(Renderer.ColorOperation);

swapChain.ResetForFrame();

// Set the render target before drawing anything
Renderer.GraphicsDevice.SetRenderTarget(swapChain.CurrentRenderTarget);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ public class SwapChain
public RenderTarget2D CurrentRenderTarget => isSwapped ? RenderTargetB : RenderTargetA;
public RenderTarget2D CurrentTexture => isSwapped ? RenderTargetA : RenderTargetB;

public int Width => RenderTargetA?.Width ?? 0;
public int Height => RenderTargetA?.Height ?? 0;

#region Construction / initialization

public SwapChain(int width, int height, bool shouldSwapClearRenderTarget = true,
SurfaceFormat? surfaceFormat = null)
Expand All @@ -32,6 +36,45 @@ public SwapChain(int width, int height, bool shouldSwapClearRenderTarget = true,
spriteBatch = new SpriteBatch(FlatRedBallServices.GraphicsDevice);
}


internal static void CreateRenderTarget(ref RenderTarget2D renderTarget, int width, int height)
{
CreateOrUpdateRenderTarget(ref renderTarget, width, height, FlatRedBallServices.GraphicsDevice.DisplayMode.Format, RenderTargetUsage.DiscardContents);
}

internal static void CreateRenderTarget(ref RenderTarget2D renderTarget, int width, int height, SurfaceFormat surfaceFormat)
{
CreateOrUpdateRenderTarget(ref renderTarget, width, height, surfaceFormat, RenderTargetUsage.DiscardContents);
}

/// <summary>
/// Assigns a new render target to the argument renderTarget if the argument render target size, format, or usage
/// does not match the parameters. If the argument renderTarget is not null then it is disposed.
/// </summary>
/// <param name="renderTarget"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="surfaceFormat"></param>
/// <param name="renderTargetUsage"></param>
internal static void CreateOrUpdateRenderTarget(ref RenderTarget2D renderTarget, int width, int height, SurfaceFormat surfaceFormat, RenderTargetUsage renderTargetUsage)
{
if (renderTarget == null
|| renderTarget.Width != width
|| renderTarget.Height != height
|| renderTarget.Format != surfaceFormat
|| renderTarget.RenderTargetUsage != renderTargetUsage)
{
renderTarget?.Dispose();

lock (FlatRedBallServices.GraphicsDevice)
{
renderTarget = new RenderTarget2D(FlatRedBallServices.GraphicsDevice, width, height, false, surfaceFormat, (DepthFormat)0, 0, renderTargetUsage);
}
}
}

#endregion

public void UpdateRenderTargetSize(int newWidth, int newHeight)
{
var shouldRecreate = RenderTargetA.Width != newWidth || RenderTargetA.Height != newHeight;
Expand All @@ -45,15 +88,17 @@ public void UpdateRenderTargetSize(int newWidth, int newHeight)
}
}

#region Rendering

public void RenderToScreen()
{
FlatRedBallServices.GraphicsDevice.SetRenderTarget(null);

// ...and draw the RenderTarget to the screen
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque);
var destinationRectangle = new Microsoft.Xna.Framework.Rectangle(0, 0, Renderer.SwapChain.CurrentRenderTarget.Width, Renderer.SwapChain.CurrentRenderTarget.Height);
var destinationRectangle = new Microsoft.Xna.Framework.Rectangle(0, 0, CurrentRenderTarget.Width, CurrentRenderTarget.Height);

spriteBatch.Draw(Renderer.SwapChain.CurrentRenderTarget, destinationRectangle,
spriteBatch.Draw(CurrentRenderTarget, destinationRectangle,
Microsoft.Xna.Framework.Color.White);
spriteBatch.End();
}
Expand All @@ -66,40 +111,14 @@ public void ResetForFrame()
public void Swap()
{
isSwapped = !isSwapped;
FlatRedBallServices.GraphicsDevice.SetRenderTarget(Renderer.SwapChain.CurrentRenderTarget);
FlatRedBallServices.GraphicsDevice.SetRenderTarget(CurrentRenderTarget);
if(ShouldSwapClearRenderTarget)
{
FlatRedBallServices.GraphicsDevice.Clear(Microsoft.Xna.Framework.Color.Transparent);
}
}

#endregion

internal static void CreateRenderTarget(ref RenderTarget2D renderTarget, int width, int height)
{
CreateRenderTarget(ref renderTarget, width, height, FlatRedBallServices.GraphicsDevice.DisplayMode.Format, RenderTargetUsage.DiscardContents);
}

internal static void CreateRenderTarget(ref RenderTarget2D renderTarget, int width, int height, SurfaceFormat surfaceFormat)
{
CreateRenderTarget(ref renderTarget, width, height, surfaceFormat, RenderTargetUsage.DiscardContents);
}

internal static void CreateRenderTarget(ref RenderTarget2D renderTarget, int width, int height, SurfaceFormat surfaceFormat, RenderTargetUsage renderTargetUsage)
{
if (renderTarget == null
|| renderTarget.Width != width
|| renderTarget.Height != height
|| renderTarget.Format != surfaceFormat
|| renderTarget.RenderTargetUsage != renderTargetUsage)
{
if (renderTarget != null)
renderTarget.Dispose();

lock (FlatRedBallServices.GraphicsDevice)
{
renderTarget = new RenderTarget2D(FlatRedBallServices.GraphicsDevice, width, height, false, surfaceFormat, (DepthFormat)0, 0, renderTargetUsage);
}
}
}
}
}
Loading