diff --git a/OpenRA.FileFormats/Graphics/IGraphicsDevice.cs b/OpenRA.FileFormats/Graphics/IGraphicsDevice.cs index ec82cff24e..b8cf0787e4 100755 --- a/OpenRA.FileFormats/Graphics/IGraphicsDevice.cs +++ b/OpenRA.FileFormats/Graphics/IGraphicsDevice.cs @@ -37,6 +37,7 @@ namespace OpenRA.FileFormats.Graphics IVertexBuffer CreateVertexBuffer( int length ); ITexture CreateTexture( Bitmap bitmap ); ITexture CreateTexture(); + IFrameBuffer CreateFrameBuffer(Size s); IShader CreateShader( string name ); Size WindowSize { get; } @@ -81,6 +82,13 @@ namespace OpenRA.FileFormats.Graphics void SetData(byte[] colors, int width, int height); } + public interface IFrameBuffer + { + void Bind(); + void Unbind(); + ITexture Texture { get; } + } + public enum PrimitiveType { PointList, diff --git a/OpenRA.Renderer.Cg/GraphicsDevice.cs b/OpenRA.Renderer.Cg/GraphicsDevice.cs index 0ac9a1dff2..656dca6136 100755 --- a/OpenRA.Renderer.Cg/GraphicsDevice.cs +++ b/OpenRA.Renderer.Cg/GraphicsDevice.cs @@ -35,7 +35,8 @@ namespace OpenRA.Renderer.Cg { "GL_ARB_vertex_program", "GL_ARB_fragment_program", - "GL_ARB_vertex_buffer_object" + "GL_ARB_vertex_buffer_object", + "GL_ARB_framebuffer_object" }; internal IntPtr cgContext; diff --git a/OpenRA.Renderer.Gl/GraphicsDevice.cs b/OpenRA.Renderer.Gl/GraphicsDevice.cs index b9a091bac8..a2ffc688bc 100755 --- a/OpenRA.Renderer.Gl/GraphicsDevice.cs +++ b/OpenRA.Renderer.Gl/GraphicsDevice.cs @@ -34,7 +34,8 @@ namespace OpenRA.Renderer.Glsl { "GL_ARB_vertex_shader", "GL_ARB_fragment_shader", - "GL_ARB_vertex_buffer_object" + "GL_ARB_vertex_buffer_object", + "GL_ARB_framebuffer_object" }; public GraphicsDevice(Size size, WindowMode window) diff --git a/OpenRA.Renderer.Null/NullGraphicsDevice.cs b/OpenRA.Renderer.Null/NullGraphicsDevice.cs index cc8dd57233..359915d371 100644 --- a/OpenRA.Renderer.Null/NullGraphicsDevice.cs +++ b/OpenRA.Renderer.Null/NullGraphicsDevice.cs @@ -59,6 +59,7 @@ namespace OpenRA.Renderer.Null public IVertexBuffer CreateVertexBuffer(int size) { return new NullVertexBuffer(); } public ITexture CreateTexture() { return new NullTexture(); } public ITexture CreateTexture(Bitmap bitmap) { return new NullTexture(); } + public IFrameBuffer CreateFrameBuffer(Size s) { return new NullFrameBuffer(); } public IShader CreateShader(string name) { return new NullShader(); } } @@ -80,6 +81,13 @@ namespace OpenRA.Renderer.Null public void SetData(byte[] colors, int width, int height) { } } + public class NullFrameBuffer : IFrameBuffer + { + public void Bind() { } + public void Unbind() { } + public ITexture Texture { get { return new NullTexture(); } } + } + class NullVertexBuffer : IVertexBuffer { public void Bind() { } diff --git a/OpenRA.Renderer.SdlCommon/FrameBuffer.cs b/OpenRA.Renderer.SdlCommon/FrameBuffer.cs new file mode 100644 index 0000000000..ca96757b68 --- /dev/null +++ b/OpenRA.Renderer.SdlCommon/FrameBuffer.cs @@ -0,0 +1,123 @@ +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using OpenRA.FileFormats; +using OpenRA.FileFormats.Graphics; +using Tao.OpenGl; + +namespace OpenRA.Renderer.SdlCommon +{ + public class FrameBuffer : IFrameBuffer + { + Texture texture; + Size size; + int framebuffer, depth; + + public FrameBuffer(Size size) + { + this.size = size; + if (!Exts.IsPowerOf2(size.Width) || !Exts.IsPowerOf2(size.Height)) + throw new InvalidDataException("Non-power-of-two array {0}x{1}".F(size.Width, size.Height)); + + Gl.glGenFramebuffersEXT(1, out framebuffer); + ErrorHandler.CheckGlError(); + Gl.glBindFramebufferEXT(Gl.GL_FRAMEBUFFER_EXT, framebuffer); + ErrorHandler.CheckGlError(); + + // Color + texture = new Texture(); + texture.SetEmpty(size.Width, size.Height); + Gl.glFramebufferTexture2DEXT(Gl.GL_FRAMEBUFFER_EXT, Gl.GL_COLOR_ATTACHMENT0_EXT, Gl.GL_TEXTURE_2D, texture.ID, 0); + ErrorHandler.CheckGlError(); + + // Depth + Gl.glGenRenderbuffersEXT(1, out depth); + ErrorHandler.CheckGlError(); + + Gl.glBindRenderbufferEXT(Gl.GL_RENDERBUFFER_EXT, depth); + ErrorHandler.CheckGlError(); + + Gl.glRenderbufferStorageEXT(Gl.GL_RENDERBUFFER_EXT, Gl.GL_DEPTH_COMPONENT16, size.Width, size.Height); + ErrorHandler.CheckGlError(); + + Gl.glFramebufferRenderbufferEXT(Gl.GL_FRAMEBUFFER_EXT, Gl.GL_DEPTH_ATTACHMENT_EXT, Gl.GL_RENDERBUFFER_EXT, depth); + ErrorHandler.CheckGlError(); + + // Test for completeness + var status = Gl.glCheckFramebufferStatusEXT(Gl.GL_FRAMEBUFFER_EXT); + if (status != Gl.GL_FRAMEBUFFER_COMPLETE_EXT) + throw new InvalidOperationException("Error creating framebuffer"); + + // Restore default buffer + Gl.glBindFramebufferEXT(Gl.GL_FRAMEBUFFER_EXT, 0); + ErrorHandler.CheckGlError(); + } + + void FinalizeInner() + { + Gl.glDeleteFramebuffersEXT(1, ref framebuffer); + ErrorHandler.CheckGlError(); + Gl.glDeleteRenderbuffersEXT(1, ref depth); + ErrorHandler.CheckGlError(); + } + + ~FrameBuffer() { Game.RunAfterTick(FinalizeInner); } + + static int[] ViewportRectangle() + { + int[] v = new int[4]; + unsafe + { + fixed (int *ptr = &v[0]) + { + IntPtr intPtr = new IntPtr((void*)ptr); + Gl.glGetIntegerv(Gl.GL_VIEWPORT, intPtr); + } + } + ErrorHandler.CheckGlError(); + + return v; + } + + int[] cv = new int[4]; + public void Bind() + { + // Cache viewport rect to restore when unbinding + cv = ViewportRectangle(); + + Gl.glFlush(); + ErrorHandler.CheckGlError(); + Gl.glBindFramebufferEXT(Gl.GL_FRAMEBUFFER_EXT, framebuffer); + ErrorHandler.CheckGlError(); + Gl.glViewport(0, 0, size.Width, size.Height); + ErrorHandler.CheckGlError(); + Gl.glClearColor(0, 0, 0, 0); + ErrorHandler.CheckGlError(); + Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT); + ErrorHandler.CheckGlError(); + } + + public void Unbind() + { + Gl.glFlush(); + ErrorHandler.CheckGlError(); + Gl.glBindFramebufferEXT(Gl.GL_FRAMEBUFFER_EXT, 0); + ErrorHandler.CheckGlError(); + Gl.glViewport(cv[0], cv[1], cv[2], cv[3]); + ErrorHandler.CheckGlError(); + } + + public ITexture Texture { get { return texture; } } + } +} diff --git a/OpenRA.Renderer.SdlCommon/OpenRA.Renderer.SdlCommon.csproj b/OpenRA.Renderer.SdlCommon/OpenRA.Renderer.SdlCommon.csproj index 46589e297b..a489aae220 100644 --- a/OpenRA.Renderer.SdlCommon/OpenRA.Renderer.SdlCommon.csproj +++ b/OpenRA.Renderer.SdlCommon/OpenRA.Renderer.SdlCommon.csproj @@ -71,6 +71,7 @@ + diff --git a/OpenRA.Renderer.SdlCommon/SdlGraphics.cs b/OpenRA.Renderer.SdlCommon/SdlGraphics.cs index 0cf17f2d3e..0dd415474e 100644 --- a/OpenRA.Renderer.SdlCommon/SdlGraphics.cs +++ b/OpenRA.Renderer.SdlCommon/SdlGraphics.cs @@ -194,6 +194,7 @@ namespace OpenRA.Renderer.SdlCommon public IVertexBuffer CreateVertexBuffer(int size) { return new VertexBuffer(size); } public ITexture CreateTexture() { return new Texture(); } public ITexture CreateTexture(Bitmap bitmap) { return new Texture(bitmap); } + public IFrameBuffer CreateFrameBuffer(Size s) { return new FrameBuffer(s); } public abstract IShader CreateShader(string name); } }