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
pub use glin::fbo::*;
use glin::{OffscreenBuffer, Fbo, Rect, Texture};
use std::cell::UnsafeCell;
use glin::Result;

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 color_attachment = gl.new_fbo_color_attachment()
            .texture_multisampled(w, h, samples, format)?;
        let fbo = gl.new_fbo().from_color(color_attachment)?;

        let fbo_blit = if samples > 0 {
            let color_attachment = gl.new_fbo_color_attachment()
                .texture(w, h, format)?;
            Some(UnsafeCell::new(gl.new_fbo().from_color(color_attachment)?))
        }else{
            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
    #[cfg(not(feature = "gles"))]
    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
    #[cfg(not(feature = "gles"))]
    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::Texture(ref tex) => Some(tex),
            _ => None
        }).unwrap()
    }

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

    /// 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()
    }

    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 OffscreenBuffer for SimpleFbo{
    fn render_buffer(&self) -> &Fbo{
        unsafe{
            (*self.changed.get()) = true;
        }
        &self.fbo
    }
}