1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
pub use glin::fbo::*;
use glin::{OffscreenBuffer, Fbo, Rect, Texture};
use std::cell::UnsafeCell;
use glin::Result;
use super::Renderer;

/// Wrapper over fbo that creates attachments and fbo in one call
///
/// Also creates a secondary attachement when using multisampled
/// buffers and automatically blits ithe multisampled to the non multisampled
/// so ti can be drawn with a normal fragment shader
pub struct SimpleFbo{
    fbo: Fbo,
    fbo_blit: Option<UnsafeCell<Fbo>>,
    changed: UnsafeCell<bool>,
}

impl SimpleFbo{
    pub(crate) fn new(gl: &Renderer, w: u32, h: u32, samples: u32, format: ColorFormat) -> Result<SimpleFbo>{
        let fbo_blit;
        let fbo;
        if samples > 0 {
            let color_attachment = gl.new_fbo_color_attachment()
                .render_buffer_multisampled(w, h, samples, format)?;
            fbo = gl.new_fbo().from_color(color_attachment)?;

            let color_attachment = gl.new_fbo_color_attachment()
                .texture(w, h, format)?;

            fbo_blit = Some(UnsafeCell::new(gl.new_fbo().from_color(color_attachment)?))
        }else{
            let color_attachment = gl.new_fbo_color_attachment()
                .texture(w, h, format)?;
            fbo = gl.new_fbo().from_color(color_attachment)?;

            fbo_blit = None;
        };

        Ok(SimpleFbo{
            fbo,
            fbo_blit: fbo_blit,
            changed: UnsafeCell::new(false),
        })
    }

    /// Copy the contents of the color attachments of this `Fbo` to dst
    ///
    /// From the src_rect rectangle to dst_rect
    pub fn blit(&self, fbo2: &mut Fbo, src_rect: &Rect, dst_rect: &Rect){
        self.fbo.blit(fbo2, src_rect, dst_rect)
    }

    /// Copy the contents of the depth attachments of this `Fbo` to dst
    ///
    /// From the src_rect rectangle to dst_rect
    pub fn blit_depth(&self, fbo2: &mut Fbo, src_rect: &Rect, dst_rect: &Rect){
        self.fbo.blit_depth(fbo2, src_rect, dst_rect)
    }

    /// Returns the color attachent idx's texture if it exists
    pub fn color_tex(&self, idx: usize) -> &Texture{
        self.non_multisampled_buffer().color(idx).and_then(|color| match color{
            &ColorAttachment::TextureLevel(ref tex, _) => Some(tex),
            _ => None
        }).unwrap()
    }

    /// Returns the depth attachent
    pub fn depth(&self) -> &DepthAttachment{
        self.non_multisampled_buffer().depth().unwrap()
    }

    /// Returns the default viewport for this `Fbo`
    pub fn viewport(&self) -> Rect{
        self.fbo.viewport()
    }

    /// Returns the width for this `Fbo`
    pub fn width(&self) -> u32{
        self.fbo.width()
    }

    /// Returns the height for this `Fbo`
    pub fn height(&self) -> u32{
        self.fbo.height()
    }

    /// Returns the aspect ratio for this `Fbo`
    pub fn aspect_ratio(&self) -> f32{
        self.fbo.aspect_ratio()
    }

    /// Returns the width and height for this `Fbo`
    pub fn size(&self) -> (u32, u32){
        self.fbo.size()
    }

    /// Returns the fbo that can be drawn
    pub fn non_multisampled_buffer(&self) -> &Fbo{
        unsafe{
            if let Some(fbo_blit) = self.fbo_blit.as_ref() {
                if *self.changed.get() {
                    self.fbo.blit(&mut *fbo_blit.get(), &self.fbo.viewport(), &self.fbo.viewport());
                    (*self.changed.get()) = false;
                }
                &*fbo_blit.get()
            }else{
                &self.fbo
            }
        }
    }
}

impl<'a> OffscreenBuffer for &'a SimpleFbo{
    type ColorAttach = ColorAttachment;
    type DepthAttach = DepthAttachment;

    fn render_buffer(&self) -> &Fbo{
        unsafe{
            (*self.changed.get()) = true;
        }
        &self.fbo
    }

    fn color_attachment(&self, idx: usize) -> Option<&ColorAttachment>{
        self.non_multisampled_buffer().color(idx)
    }

    fn depth_attachment(&self) -> Option<&DepthAttachment>{
        self.non_multisampled_buffer().depth()
    }
}