/// <summary> /// Creates a framebuffer object and its associated resources (depth and frame buffers). /// </summary> /// <param name="size">Specifies the size (in pixels) of the framebuffer and its associated buffers.</param> /// <param name="attachments">Specifies the attachments to use for the frame buffer.</param> /// <param name="format">Specifies the internal pixel format for the frame buffer.</param> /// <param name="mipmaps">Specifies whether to build mipmaps after the frame buffer is unbound.</param> /// <param name="filterType">Specifies the type of filtering to apply to the frame buffer when bound as a texture.</param> /// <param name="pixelType">Specifies the pixel type to use for the underlying format of the frame buffer.</param> public FBO(Size size, FramebufferAttachment[] attachments, PixelInternalFormat format, bool mipmaps = false, TextureParameter filterType = TextureParameter.Linear, PixelType pixelType = PixelType.UnsignedByte) { this.Size = size; this.Attachments = attachments; this.Format = format; this.MipMaps = mipmaps; // First create the framebuffer BufferID = Gl.GenFramebuffer(); Gl.BindFramebuffer(FramebufferTarget.Framebuffer, BufferID); if (Attachments.Length == 1 && Attachments[0] == FramebufferAttachment.DepthAttachment) { // if this is a depth attachment only TextureID = new uint[] { Gl.GenTexture() }; Gl.BindTexture(TextureTarget.Texture2D, TextureID[0]); Gl.TexImage2D(TextureTarget.Texture2D, 0, Format, Size.Width, Size.Height, 0, PixelFormat.DepthComponent, PixelType.Float, IntPtr.Zero); Gl.TexParameteri(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, TextureParameter.Nearest); Gl.TexParameteri(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, TextureParameter.Nearest); Gl.TexParameteri(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, TextureParameter.ClampToEdge); Gl.TexParameteri(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, TextureParameter.ClampToEdge); Gl.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthAttachment, TextureID[0], 0); Gl.DrawBuffer(DrawBufferMode.None); Gl.ReadBuffer(ReadBufferMode.None); } else { // Create n texture buffers (known by the number of attachments) TextureID = new uint[Attachments.Length]; Gl.GenTextures(Attachments.Length, TextureID); // Bind the n texture buffers to the framebuffer for (int i = 0; i < Attachments.Length; i++) { Gl.BindTexture(TextureTarget.Texture2D, TextureID[i]); Gl.TexImage2D(TextureTarget.Texture2D, 0, Format, Size.Width, Size.Height, 0, PixelFormat.Rgba, pixelType, IntPtr.Zero); if (MipMaps) { Gl.TexParameteri(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, TextureParameter.Linear); Gl.TexParameteri(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, TextureParameter.LinearMipMapLinear); Gl.GenerateMipmap(GenerateMipmapTarget.Texture2D); } else { Gl.TexParameteri(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, filterType); Gl.TexParameteri(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, filterType); } Gl.FramebufferTexture(FramebufferTarget.Framebuffer, Attachments[i], TextureID[i], 0); } // Create and attach a 24-bit depth buffer to the framebuffer DepthID = Gl.GenTexture(); Gl.BindTexture(TextureTarget.Texture2D, DepthID); Gl.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Depth24Stencil8, Size.Width, Size.Height, 0, PixelFormat.DepthStencil, PixelType.UnsignedInt248, IntPtr.Zero); Gl.TexParameteri(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, TextureParameter.Nearest); Gl.TexParameteri(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, TextureParameter.Nearest); Gl.TexParameteri(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, TextureParameter.ClampToEdge); Gl.TexParameteri(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, TextureParameter.ClampToEdge); Gl.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthAttachment, DepthID, 0); Gl.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.StencilAttachment, DepthID, 0); } // Build the framebuffer and check for errors FramebufferErrorCode status = Gl.CheckFramebufferStatus(FramebufferTarget.Framebuffer); if (status != FramebufferErrorCode.FramebufferComplete) { Console.WriteLine("Frame buffer did not compile correctly. Returned {0}, glError: {1}", status.ToString(), Gl.GetError().ToString()); } Gl.BindFramebuffer(FramebufferTarget.Framebuffer, 0); }