use std::{error, fmt};
use crate::{
backend::{
color_slot::ColorSlot,
depth_stencil_slot::DepthStencilSlot,
framebuffer::{Framebuffer as FramebufferBackend, FramebufferBackBuffer},
},
context::GraphicsContext,
texture::{Dim2, Dimensionable, Sampler, TextureError},
};
pub struct Framebuffer<B, D, CS, DS>
where
B: ?Sized + FramebufferBackend<D>,
D: Dimensionable,
CS: ColorSlot<B, D>,
DS: DepthStencilSlot<B, D>,
{
pub(crate) repr: B::FramebufferRepr,
color_slot: CS::ColorTextures,
depth_stencil_slot: DS::DepthStencilTexture,
}
impl<B, D, CS, DS> Framebuffer<B, D, CS, DS>
where
B: ?Sized + FramebufferBackend<D>,
D: Dimensionable,
CS: ColorSlot<B, D>,
DS: DepthStencilSlot<B, D>,
{
pub fn new<C>(
ctx: &mut C,
size: D::Size,
mipmaps: usize,
sampler: Sampler,
) -> Result<Self, FramebufferError>
where
C: GraphicsContext<Backend = B>,
{
unsafe {
let mut repr = ctx
.backend()
.new_framebuffer::<CS, DS>(size, mipmaps, &sampler)?;
let color_slot = CS::reify_color_textures(ctx, size, mipmaps, &sampler, &mut repr, 0)?;
let depth_stencil_slot = DS::reify_depth_texture(ctx, size, mipmaps, &sampler, &mut repr)?;
let repr = B::validate_framebuffer(repr)?;
Ok(Framebuffer {
repr,
color_slot,
depth_stencil_slot,
})
}
}
pub fn size(&self) -> D::Size {
unsafe { B::framebuffer_size(&self.repr) }
}
pub fn color_slot(&mut self) -> &mut CS::ColorTextures {
&mut self.color_slot
}
pub fn depth_stencil_slot(&mut self) -> &mut DS::DepthStencilTexture {
&mut self.depth_stencil_slot
}
pub fn into_slots(self) -> (CS::ColorTextures, DS::DepthStencilTexture) {
(self.color_slot, self.depth_stencil_slot)
}
pub fn into_color_slot(self) -> CS::ColorTextures {
self.color_slot
}
pub fn into_depth_stencil_slot(self) -> DS::DepthStencilTexture {
self.depth_stencil_slot
}
}
impl<B> Framebuffer<B, Dim2, (), ()>
where
B: ?Sized + FramebufferBackend<Dim2> + FramebufferBackBuffer,
{
pub fn back_buffer<C>(
ctx: &mut C,
size: <Dim2 as Dimensionable>::Size,
) -> Result<Self, FramebufferError>
where
C: GraphicsContext<Backend = B>,
{
unsafe { ctx.backend().back_buffer(size) }.map(|repr| Framebuffer {
repr,
color_slot: (),
depth_stencil_slot: (),
})
}
}
#[non_exhaustive]
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum FramebufferError {
CannotCreate,
TextureError(TextureError),
Incomplete(IncompleteReason),
UnsupportedAttachment,
}
impl FramebufferError {
pub fn cannot_create() -> Self {
FramebufferError::CannotCreate
}
pub fn texture_error(e: TextureError) -> Self {
FramebufferError::TextureError(e)
}
pub fn incomplete(e: IncompleteReason) -> Self {
FramebufferError::Incomplete(e)
}
pub fn unsupported_attachment() -> Self {
FramebufferError::UnsupportedAttachment
}
}
impl fmt::Display for FramebufferError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
FramebufferError::CannotCreate => {
f.write_str("cannot create the framebuffer on the GPU side")
}
FramebufferError::TextureError(ref e) => write!(f, "framebuffer texture error: {}", e),
FramebufferError::Incomplete(ref e) => write!(f, "incomplete framebuffer: {}", e),
FramebufferError::UnsupportedAttachment => f.write_str("unsupported framebuffer attachment"),
}
}
}
impl std::error::Error for FramebufferError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
FramebufferError::CannotCreate => None,
FramebufferError::TextureError(e) => Some(e),
FramebufferError::Incomplete(e) => Some(e),
FramebufferError::UnsupportedAttachment => None,
}
}
}
impl From<TextureError> for FramebufferError {
fn from(e: TextureError) -> Self {
FramebufferError::TextureError(e)
}
}
impl From<IncompleteReason> for FramebufferError {
fn from(e: IncompleteReason) -> Self {
FramebufferError::Incomplete(e)
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum IncompleteReason {
Undefined,
IncompleteAttachment,
MissingAttachment,
IncompleteDrawBuffer,
IncompleteReadBuffer,
Unsupported,
IncompleteMultisample,
IncompleteLayerTargets,
}
impl fmt::Display for IncompleteReason {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
IncompleteReason::Undefined => write!(f, "incomplete reason"),
IncompleteReason::IncompleteAttachment => write!(f, "incomplete attachment"),
IncompleteReason::MissingAttachment => write!(f, "missing attachment"),
IncompleteReason::IncompleteDrawBuffer => write!(f, "incomplete draw buffer"),
IncompleteReason::IncompleteReadBuffer => write!(f, "incomplete read buffer"),
IncompleteReason::Unsupported => write!(f, "unsupported"),
IncompleteReason::IncompleteMultisample => write!(f, "incomplete multisample"),
IncompleteReason::IncompleteLayerTargets => write!(f, "incomplete layer targets"),
}
}
}
impl error::Error for IncompleteReason {}