Files
bluflame/aiwaz/Aiwaz.Resources/RenderTarget.cs
2026-04-18 22:31:51 +02:00

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