/// <summary> /// Attaches a <see cref="RenderbufferObject"/> to this <see cref="FramebufferObject"/> in a specified attachment point. /// </summary> /// <param name="renderbuffer">The <see cref="RenderbufferObject"/> to attach.</param> /// <param name="attachmentPoint">The attachment point to attach the <see cref="RenderbufferObject"/> to.</param> public void Attach(RenderbufferObject renderbuffer, FramebufferAttachmentPoint attachmentPoint) { if (renderbuffer == null) { throw new ArgumentNullException(nameof(renderbuffer)); } ValidateAttachmentTypeExists(attachmentPoint); ValidateAttachmentTypeNotUsed(attachmentPoint); if (attachmentPoint == FramebufferAttachmentPoint.Depth && !renderbuffer.IsDepthOnly) { throw new InvalidFramebufferAttachmentException("When attaching a renderbuffer to a depth attachment point, the renderbuffer's format must be depth-only"); } if (attachmentPoint == FramebufferAttachmentPoint.DepthStencil && !renderbuffer.IsDepthStencil) { throw new InvalidFramebufferAttachmentException("When attaching a renderbuffer to a depth-stencil attachment point, the renderbuffer's format must be depth-stencil"); } if (attachmentPoint == FramebufferAttachmentPoint.Stencil && !renderbuffer.IsStencilOnly) { throw new InvalidFramebufferAttachmentException("When attaching a renderbuffer to a stencil attachment point, the renderbuffer's format must be stencil-only"); } if (TrippyUtils.IsFramebufferAttachmentPointColor(attachmentPoint) && !renderbuffer.IsColorRenderableFormat) { throw new InvalidFramebufferAttachmentException("When attaching a renderbuffer to a color attachment point, the renderbuffer's format must be color-renderable"); } GraphicsDevice.Framebuffer = this; GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, (FramebufferAttachment)attachmentPoint, RenderbufferTarget.Renderbuffer, renderbuffer.Handle); renderbufferAttachments.Add(new FramebufferRenderbufferAttachment(renderbuffer, attachmentPoint)); }
/// <summary> /// Creates a <see cref="Framebuffer2D"/> with the given width, height, and other optional parameters. /// </summary> /// <param name="graphicsDevice">The <see cref="GraphicsDevice"/> this <see cref="Framebuffer2D"/> will use.</param> /// <param name="width">The width of the <see cref="Framebuffer2D"/>'s image.</param> /// <param name="height">The height of the <see cref="Framebuffer2D"/>'s image.</param> /// <param name="depthStencilFormat">The depth-stencil format for an optional renderbuffer attachment.</param> /// <param name="samples">The amount of samples for the <see cref="Framebuffer2D"/>'s image.</param> /// <param name="imageFormat">The format of the <see cref="Framebuffer2D"/>'s image.</param> /// <param name="useDepthStencilTexture">Whether to use a texture for the depth-stencil buffer instead of a renderbuffer.</param> public Framebuffer2D(GraphicsDevice graphicsDevice, uint width, uint height, DepthStencilFormat depthStencilFormat, uint samples = 0, TextureImageFormat imageFormat = TextureImageFormat.Color4b, bool useDepthStencilTexture = false) { Framebuffer = new FramebufferObject(graphicsDevice); Texture = new Texture2D(graphicsDevice, width, height, false, samples, imageFormat); if (depthStencilFormat != DepthStencilFormat.None) { if (useDepthStencilTexture) { TextureImageFormat dsFormat = TrippyUtils.DepthStencilFormatToTextureFormat(depthStencilFormat); Texture2D dsTexture = new Texture2D(graphicsDevice, width, height, false, samples, dsFormat); Framebuffer.Attach(dsTexture, TrippyUtils.GetCorrespondingTextureFramebufferAttachmentPoint(dsFormat)); } else { RenderbufferObject rbo = new RenderbufferObject(graphicsDevice, width, height, (RenderbufferFormat)depthStencilFormat, samples); Framebuffer.Attach(rbo, TrippyUtils.GetCorrespondingRenderbufferFramebufferAttachmentPoint(rbo.Format)); } } Framebuffer.Attach(Texture, FramebufferAttachmentPoint.Color0); Framebuffer.UpdateFramebufferData(); }
/// <summary> /// Creates a <see cref="FramebufferRenderbufferAttachment"/>. /// </summary> /// <param name="renderbuffer">The <see cref="RenderbufferObject"/> to attach in this attachment.</param> /// <param name="attachmentPoint">The attachment point to which this attachment attaches to.</param> public FramebufferRenderbufferAttachment(RenderbufferObject renderbuffer, FramebufferAttachmentPoint attachmentPoint) { Renderbuffer = renderbuffer; AttachmentPoint = attachmentPoint; }
/// <summary> /// Updates the <see cref="FramebufferObject"/>'s parameters and checks that the framebuffer is valid. /// This should always be called after being done attaching or detaching resources. /// </summary> public void UpdateFramebufferData() { uint width = uint.MaxValue; uint height = uint.MaxValue; uint samples = uint.MaxValue; for (int i = 0; i < textureAttachments.Count; i++) { Texture tex = textureAttachments[i].Texture; if (tex is Texture1D tex1d) { ValidateSize(tex1d.Width, 1); } else if (tex is Texture2D tex2d) { ValidateSize(tex2d.Width, tex2d.Height); } else { throw new FramebufferException("The texture format cannot be attached: " + tex.TextureType); } ValidateSamples(tex is TextureMultisamplable ms ? ms.Samples : 0); } for (int i = 0; i < renderbufferAttachments.Count; i++) { RenderbufferObject rend = renderbufferAttachments[i].Renderbuffer; ValidateSize(rend.Width, rend.Height); ValidateSamples(rend.Samples); } Width = width; Height = height; Samples = samples; void ValidateSize(uint w, uint h) { if (width == uint.MaxValue) { width = w; } else if (width != w) { throw new FramebufferException("All the attachments must be the same size"); } if (height == uint.MaxValue) { height = h; } else if (height != h) { throw new FramebufferException("All the attachments must be the same size"); } } void ValidateSamples(uint s) { if (samples == uint.MaxValue) { samples = s; } else if (samples != s) { throw new FramebufferException("All the attachments must have the same amount of samples"); } } FramebufferStatus c = GetStatus(); if (c != FramebufferStatus.FramebufferComplete) { throw new FramebufferException("The " + nameof(FramebufferObject) + " is not complete: " + c); } }