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