297 lines
12 KiB
C#
297 lines
12 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using Aiwaz.Contracts;
|
|
using Aiwaz.Core;
|
|
|
|
namespace Aiwaz.Resources
|
|
{
|
|
public abstract class RenderTarget : CommandUser, IRenderTargetBase, IDisposable
|
|
{
|
|
public RenderTarget()
|
|
: base()
|
|
{
|
|
Commands.Add(new Command(this, CommandFlags.EndChain | CommandFlags.FlushChain, setRenderTargetCommandType, 0, 0));
|
|
|
|
this.ClearDepth = 1.0f;
|
|
}
|
|
|
|
~RenderTarget()
|
|
{
|
|
if (Engine.Initialized)
|
|
this.Dispose();
|
|
}
|
|
|
|
#region IRenderTargetBase Members
|
|
|
|
internal static SlimDX.Direct3D10.ShaderResourceView[] emptyShaderResView = new SlimDX.Direct3D10.ShaderResourceView[128];
|
|
|
|
private SlimDX.Direct3D10.RenderTargetView[] renderTargetViews;
|
|
private List<IRenderTargetBase> additionalRenderTargets = new List<IRenderTargetBase>();
|
|
private SlimDX.Direct3D10.Viewport[] viewports;
|
|
|
|
protected int multiSampleCount = 1;
|
|
protected int multiSampleQuality = 0;
|
|
private BindFlags lastBindFlags = BindFlags.Default;
|
|
|
|
public float ClearDepth { get; set; }
|
|
public byte ClearStencil { get; set; }
|
|
public SlimDX.Color4 ClearColor { get; set; }
|
|
|
|
private ViewPort viewPort;
|
|
public ViewPort ViewPort
|
|
{
|
|
get { return viewPort; }
|
|
set
|
|
{
|
|
viewPort = value;
|
|
this.KillViewPortAndRenderTargetData();
|
|
this.BuildViewPortAndRenderTargetData();
|
|
}
|
|
}
|
|
|
|
public abstract int RenderTargetWidth { get; }
|
|
public abstract int RenderTargetHeight { get; }
|
|
public abstract SlimDX.DXGI.Format RenderTargetFormat { get; }
|
|
|
|
private bool hasDepthStencilBuffer;
|
|
public bool HasDepthStencilBuffer
|
|
{
|
|
get { return hasDepthStencilBuffer; }
|
|
set
|
|
{
|
|
hasDepthStencilBuffer = value;
|
|
|
|
Engine.Device.ClearState();
|
|
|
|
if (DX10DepthStencilView != null)
|
|
DX10DepthStencilView.Dispose();
|
|
DX10DepthStencilView = null;
|
|
|
|
if (DX10DepthStencilTexture != null)
|
|
DX10DepthStencilTexture.Dispose();
|
|
DX10DepthStencilTexture = null;
|
|
|
|
if (!hasDepthStencilBuffer)
|
|
return; // no further effort needed here
|
|
|
|
var depthTextureDesc = new SlimDX.Direct3D10.Texture2DDescription()
|
|
{
|
|
Width = this.RenderTargetWidth,
|
|
Height = this.RenderTargetHeight,
|
|
MipLevels = 1,
|
|
ArraySize = 1,
|
|
Format = SlimDX.DXGI.Format.D24_UNorm_S8_UInt,
|
|
SampleDescription = new SlimDX.DXGI.SampleDescription(multiSampleCount == 0 ? 1 : multiSampleCount, multiSampleQuality),
|
|
Usage = SlimDX.Direct3D10.ResourceUsage.Default,
|
|
BindFlags = SlimDX.Direct3D10.BindFlags.DepthStencil,
|
|
CpuAccessFlags = SlimDX.Direct3D10.CpuAccessFlags.None,
|
|
OptionFlags = SlimDX.Direct3D10.ResourceOptionFlags.None
|
|
};
|
|
|
|
DX10DepthStencilTexture = new SlimDX.Direct3D10.Texture2D(Engine.Device, depthTextureDesc);
|
|
if (DX10DepthStencilTexture == null)
|
|
throw new Aiwaz.Core.ActionFailedException("RenderTarget: Unable to create depth stencil texture.");
|
|
|
|
var depthStencilViewDesc = new SlimDX.Direct3D10.DepthStencilViewDescription()
|
|
{
|
|
Format = depthTextureDesc.Format,
|
|
Dimension = multiSampleCount >= 1 ? SlimDX.Direct3D10.DepthStencilViewDimension.Texture2DMultisampled : SlimDX.Direct3D10.DepthStencilViewDimension.Texture2D,
|
|
MipSlice = 0
|
|
};
|
|
|
|
DX10DepthStencilView = new SlimDX.Direct3D10.DepthStencilView(Engine.Device, DX10DepthStencilTexture, depthStencilViewDesc);
|
|
if (DX10DepthStencilView == null)
|
|
throw new Aiwaz.Core.ActionFailedException("RenderTarget: Unable to create depth stencil view.");
|
|
}
|
|
}
|
|
|
|
public SlimDX.Direct3D10.RenderTargetView DX10RenderTargetView { get; protected set; }
|
|
public SlimDX.Direct3D10.DepthStencilView DX10DepthStencilView { get; protected set; }
|
|
public SlimDX.Direct3D10.Texture2D DX10DepthStencilTexture { get; protected set; }
|
|
|
|
public void AddAdditionalRenderTarget(IRenderTargetBase target)
|
|
{
|
|
this.RemoveAdditionalRenderTarget(target);
|
|
//if (AdditionalRenderTargets.Count + 1 == D3D10_SIMULTANEOUS_RENDER_TARGET_COUNT)
|
|
// throw new Aiwaz.Core.ActionFailedException("RenderTarget: Unable to add an additional rendering target, list is full.");
|
|
|
|
additionalRenderTargets.Add(target);
|
|
this.KillViewPortAndRenderTargetData();
|
|
this.BuildViewPortAndRenderTargetData();
|
|
}
|
|
|
|
public void RemoveAdditionalRenderTarget(IRenderTargetBase target)
|
|
{
|
|
if (additionalRenderTargets.Remove(target))
|
|
{
|
|
this.KillViewPortAndRenderTargetData();
|
|
this.BuildViewPortAndRenderTargetData();
|
|
}
|
|
}
|
|
|
|
public void Bind(BindFlags bindFlags)
|
|
{
|
|
if ((bindFlags & ~ BindFlags.ClearAll) != (lastBindFlags & ~ BindFlags.ClearAll))
|
|
{
|
|
lastBindFlags = bindFlags;
|
|
this.KillViewPortAndRenderTargetData();
|
|
this.BuildViewPortAndRenderTargetData();
|
|
}
|
|
else
|
|
lastBindFlags = bindFlags;
|
|
|
|
this.Clear(bindFlags);
|
|
|
|
Engine.Device.PixelShader.SetShaderResources(emptyShaderResView, 0, 128);
|
|
Engine.Device.OutputMerger.SetTargets(DX10DepthStencilView, renderTargetViews);
|
|
Engine.Device.Rasterizer.SetViewports(viewports);
|
|
|
|
Engine.EngineStates.LastRenderTarget = this;
|
|
}
|
|
|
|
public void UnbindAllRenderTargets()
|
|
{
|
|
if (Engine.EngineStates.LastRenderTarget == this)
|
|
{
|
|
Engine.Device.OutputMerger.SetTargets(new SlimDX.Direct3D10.RenderTargetView[0]);
|
|
Engine.Device.Rasterizer.SetViewports(new SlimDX.Direct3D10.Viewport[0]);
|
|
Engine.EngineStates.LastRenderTarget = null;
|
|
}
|
|
}
|
|
|
|
protected void BuildViewPortAndRenderTargetData()
|
|
{
|
|
// Rebuild render targets
|
|
if (renderTargetViews == null && viewports == null)
|
|
{
|
|
if ((lastBindFlags & BindFlags.BindAllTextures) == BindFlags.BindAllTextures)
|
|
{
|
|
renderTargetViews = new SlimDX.Direct3D10.RenderTargetView[additionalRenderTargets.Count + 1];
|
|
viewports = new SlimDX.Direct3D10.Viewport[additionalRenderTargets.Count + 1];
|
|
|
|
renderTargetViews[0] = this.DX10RenderTargetView;
|
|
viewports[0] = this.ViewPort;
|
|
for (int i = 0; i < additionalRenderTargets.Count; ++i)
|
|
{
|
|
renderTargetViews[i + 1] = additionalRenderTargets[i].DX10RenderTargetView;
|
|
viewports[i + 1] = additionalRenderTargets[i].ViewPort;
|
|
}
|
|
}
|
|
else if ((lastBindFlags & BindFlags.BindAllTextures) != BindFlags.None)
|
|
{
|
|
var activeRenderTargetCount = 0;
|
|
if ((lastBindFlags & BindFlags.BindBaseTexture) != BindFlags.None) ++activeRenderTargetCount;
|
|
if ((lastBindFlags & BindFlags.BindAdditionalTexture0) != BindFlags.None) ++activeRenderTargetCount;
|
|
if ((lastBindFlags & BindFlags.BindAdditionalTexture1) != BindFlags.None) ++activeRenderTargetCount;
|
|
if ((lastBindFlags & BindFlags.BindAdditionalTexture2) != BindFlags.None) ++activeRenderTargetCount;
|
|
if ((lastBindFlags & BindFlags.BindAdditionalTexture3) != BindFlags.None) ++activeRenderTargetCount;
|
|
|
|
renderTargetViews = new SlimDX.Direct3D10.RenderTargetView[activeRenderTargetCount];
|
|
viewports = new SlimDX.Direct3D10.Viewport[activeRenderTargetCount];
|
|
|
|
int bufferIndex = 0;
|
|
if ((lastBindFlags & BindFlags.BindBaseTexture) != BindFlags.None)
|
|
{
|
|
renderTargetViews[bufferIndex] = this.DX10RenderTargetView;
|
|
viewports[bufferIndex++] = this.ViewPort;
|
|
}
|
|
if ((lastBindFlags & BindFlags.BindAdditionalTexture0) != BindFlags.None)
|
|
{
|
|
renderTargetViews[bufferIndex] = additionalRenderTargets[0].DX10RenderTargetView;
|
|
viewports[bufferIndex++] = additionalRenderTargets[0].ViewPort;
|
|
}
|
|
if ((lastBindFlags & BindFlags.BindAdditionalTexture1) != BindFlags.None)
|
|
{
|
|
renderTargetViews[bufferIndex] = additionalRenderTargets[1].DX10RenderTargetView;
|
|
viewports[bufferIndex++] = additionalRenderTargets[1].ViewPort;
|
|
}
|
|
if ((lastBindFlags & BindFlags.BindAdditionalTexture2) != BindFlags.None)
|
|
{
|
|
renderTargetViews[bufferIndex] = additionalRenderTargets[2].DX10RenderTargetView;
|
|
viewports[bufferIndex++] = additionalRenderTargets[2].ViewPort;
|
|
}
|
|
if ((lastBindFlags & BindFlags.BindAdditionalTexture3) != BindFlags.None)
|
|
{
|
|
renderTargetViews[bufferIndex] = additionalRenderTargets[3].DX10RenderTargetView;
|
|
viewports[bufferIndex++] = additionalRenderTargets[3].ViewPort;
|
|
}
|
|
}
|
|
else
|
|
throw new ActionFailedException("No render target bindable.");
|
|
}
|
|
}
|
|
|
|
|
|
protected void KillViewPortAndRenderTargetData()
|
|
{
|
|
renderTargetViews = null;
|
|
viewports = null;
|
|
|
|
if (Engine.EngineStates.LastRenderTarget == this)
|
|
Engine.EngineStates.LastRenderTarget = null;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IDisposable Members
|
|
|
|
protected void DisposeInternal()
|
|
{
|
|
this.KillViewPortAndRenderTargetData();
|
|
this.UnbindAllRenderTargets();
|
|
|
|
if (DX10RenderTargetView != null)
|
|
DX10RenderTargetView.Dispose();
|
|
DX10RenderTargetView = null;
|
|
|
|
if (DX10DepthStencilView != null)
|
|
DX10DepthStencilView.Dispose();
|
|
DX10DepthStencilView = null;
|
|
|
|
if (DX10DepthStencilTexture != null)
|
|
DX10DepthStencilTexture.Dispose();
|
|
DX10DepthStencilTexture = null;
|
|
}
|
|
|
|
public override void Dispose()
|
|
{
|
|
this.DisposeInternal();
|
|
base.Dispose();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region CommandUser
|
|
|
|
const byte setRenderTargetCommandType = 0;
|
|
public override CommandExecuteResult ExecuteCommand(byte commandType, CommandBuffer currentBuffer, int currentPositon)
|
|
{
|
|
if (commandType == setRenderTargetCommandType)
|
|
{
|
|
if (Engine.EngineStates.LastRenderTarget != this)
|
|
{
|
|
this.UnbindAllRenderTargets();
|
|
this.Bind(BindFlags.Default);
|
|
}
|
|
else
|
|
this.Clear(BindFlags.Default);
|
|
}
|
|
return CommandExecuteResult.None;
|
|
}
|
|
|
|
|
|
protected void Clear(BindFlags bindFlags)
|
|
{
|
|
if ((bindFlags & BindFlags.ClearColor) != BindFlags.None)
|
|
Engine.Device.ClearRenderTargetView(DX10RenderTargetView, ClearColor);
|
|
|
|
if ((bindFlags & BindFlags.ClearDepthStencil) != BindFlags.None && DX10DepthStencilView != null)
|
|
Engine.Device.ClearDepthStencilView(DX10DepthStencilView, SlimDX.Direct3D10.DepthStencilClearFlags.Depth | SlimDX.Direct3D10.DepthStencilClearFlags.Stencil, ClearDepth, ClearStencil);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|