145 lines
4.5 KiB
C#

using System;
using ANX.Framework.Graphics;
using ANX.Framework.NonXNA.RenderSystem;
using OpenTK.Graphics.OpenGL;
using ANX.RenderSystem.GL3.Helpers;
namespace ANX.RenderSystem.GL3
{
public class RenderTarget2DGL3 : Texture2DGL3, INativeRenderTarget2D
{
#region Private
private int framebufferHandle;
private int renderbufferHandle;
private bool generateMipmaps;
#endregion
// TODO: usage, preferredMultiSampleCount
#region Constructor
public RenderTarget2DGL3(int width, int height, bool mipMap,
SurfaceFormat preferredFormat, DepthFormat preferredDepthFormat,
int preferredMultiSampleCount, RenderTargetUsage usage)
: base()
{
generateMipmaps = mipMap;
PixelInternalFormat nativeFormat =
DatatypesMapping.SurfaceToPixelInternalFormat(preferredFormat);
#region Image creation
NativeHandle = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, NativeHandle);
GL.TexParameter(TextureTarget.Texture2D,
TextureParameterName.TextureMagFilter, (int)All.Linear);
GL.TexParameter(TextureTarget.Texture2D,
TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D,
TextureParameterName.TextureWrapT, (int)All.ClampToEdge);
if (generateMipmaps)
{
GL.TexParameter(TextureTarget.Texture2D,
TextureParameterName.GenerateMipmap, 1);
GL.TexParameter(TextureTarget.Texture2D,
TextureParameterName.TextureMinFilter, (int)All.LinearMipmapLinear);
}
else
{
GL.TexParameter(TextureTarget.Texture2D,
TextureParameterName.TextureMinFilter, (int)All.Linear);
}
GL.TexImage2D(TextureTarget.Texture2D, 0, nativeFormat,
width, height, 0, (PixelFormat)nativeFormat, PixelType.UnsignedByte,
IntPtr.Zero);
GL.BindTexture(TextureTarget.Texture2D, 0);
#endregion
// create a renderbuffer object to store depth info
GL.GenRenderbuffers(1, out renderbufferHandle);
GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, renderbufferHandle);
GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer,
DepthFormatConversion(preferredDepthFormat), width, height);
GL.BindRenderbuffer(RenderbufferTarget.RenderbufferExt, 0);
// create a framebuffer object
GL.GenFramebuffers(1, out framebufferHandle);
GL.BindFramebuffer(FramebufferTarget.Framebuffer, framebufferHandle);
// attach the texture to FBO color attachment point
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer,
FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2D,
NativeHandle, 0);
// attach the renderbuffer to depth attachment point
GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer,
FramebufferAttachment.DepthAttachment,
RenderbufferTarget.Renderbuffer, renderbufferHandle);
// check FBO status
FramebufferErrorCode status = GL.CheckFramebufferStatus(
FramebufferTarget.Framebuffer);
if (status != FramebufferErrorCode.FramebufferComplete)
{
throw new InvalidOperationException(
"Failed to create the render target! Error=" + status);
}
// switch back to window-system-provided framebuffer
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
}
#endregion
#region DepthFormatConversion
private RenderbufferStorage DepthFormatConversion(DepthFormat depthFormat)
{
switch(depthFormat)
{
default:
case DepthFormat.None:
// TODO
return RenderbufferStorage.DepthComponent16;
//return (RenderbufferStorage)All.DepthComponent;
case DepthFormat.Depth16:
return RenderbufferStorage.DepthComponent16;
case DepthFormat.Depth24:
return RenderbufferStorage.DepthComponent24;
case DepthFormat.Depth24Stencil8:
return RenderbufferStorage.DepthComponent32;
}
}
#endregion
#region Bind
public void Bind()
{
GL.BindFramebuffer(FramebufferTarget.Framebuffer, framebufferHandle);
}
#endregion
#region Unbind
public void Unbind()
{
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
if (generateMipmaps)
{
GL.BindTexture(TextureTarget.Texture2D, NativeHandle);
GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);
GL.BindTexture(TextureTarget.Texture2D, 0);
}
}
#endregion
#region Dispose
public override void Dispose()
{
base.Dispose();
GL.DeleteFramebuffers(1, ref framebufferHandle);
GL.DeleteRenderbuffers(1, ref renderbufferHandle);
}
#endregion
}
}