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
use glium::{
    uniforms::{
        AsUniformValue,
        UniformValue,
    },
    Program,
    Surface,
    Texture2d,
};

use crate::{
    graph::{
        node::Node,
        NodeId,
        UniformMap,
    },
    util::RectStrip,
};

pub enum Buffer {
    Single(Texture2d),
    Double(Texture2d, Texture2d),
}

impl Buffer {
    pub fn new_double<F: Fn() -> Texture2d>(f: F) -> Buffer {
        Buffer::Double(f(), f())
    }

    pub fn front(&self) -> &Texture2d {
        match self {
            Buffer::Single(ref texture) => texture,
            Buffer::Double(ref front, _back) => front,
        }
    }
    pub fn back(&self) -> Option<&Texture2d> {
        match self {
            Buffer::Single(_) => None,
            Buffer::Double(_front, back) => Some(back),
        }
    }

    pub fn swap(&mut self) {
        // Using `Box`, the swap is cheap.
        if let Buffer::Double(ref mut front, ref mut back) = self {
            std::mem::swap(front, back);
        }
    }
}

// TODO: Remove `pub` on struct fields

/// Represents a single shader, the inputs it expects,
/// and the texture it owns that is updated in each forward
/// pass.
pub struct ShaderNode {
    pub shader: Program,
    pub inputs: Vec<NodeId>,
    pub buffer: Buffer,
}

impl std::fmt::Debug for ShaderNode {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("ShaderGraph")
            .field("inputs", &self.inputs)
            .finish()
    }
}

impl Node for ShaderNode {
    fn inputs(&self) -> Vec<NodeId> { self.inputs.to_owned() }

    fn outputs(&self) -> (&str, UniformValue) {
        match self.buffer {
            Buffer::Single(ref texture) => {
                ("texture", texture.as_uniform_value())
            },
            Buffer::Double(ref texture, _) => {
                ("texture", texture.as_uniform_value())
            },
        }
    }

    fn texture(&self) -> Option<&Texture2d> { Some(self.buffer.front()) }

    fn forward(&mut self, rect_strip: &RectStrip, uniforms: UniformMap) {
        self.buffer.swap();

        let front = self.buffer.front();
        let resolution =
            [front.get_width() as f32, front.get_height().unwrap() as f32];

        let mut uniforms = uniforms;
        uniforms.add("resolution", UniformValue::Vec2(resolution));
        if let Some(back) = self.buffer.back() {
            uniforms.add("previous", back.as_uniform_value());
        }

        // taking the previous inputs,
        // render out the next texture using a shader,
        // overwriting its previous contents.
        front
            .as_surface()
            .draw(
                &rect_strip.buffer,
                &rect_strip.indices,
                &self.shader,
                &uniforms,
                &Default::default(),
            )
            .unwrap();
    }
}