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
//! Types for constructing render passes.

use amethyst_core::specs::prelude::SystemData;

use error::Result;
use pipe::{Effect, NewEffect, Target};
use types::{Encoder, Factory};

/// Used to fetch data from the game world for rendering in the pass.
pub trait PassData<'a> {
    /// The data itself.
    type Data: SystemData<'a> + Send;
}

/// Structures implementing this provide a renderer pass.
pub trait Pass: for<'a> PassData<'a> {
    /// The pass is given an opportunity to compile shaders and store them in an `Effect`
    /// which is then passed to the pass in `apply`.
    fn compile(&mut self, effect: NewEffect) -> Result<Effect>;
    /// Called whenever the renderer is ready to apply the pass.  Feed commands into the
    /// encoder here.
    fn apply<'a, 'b: 'a>(
        &'a mut self,
        encoder: &mut Encoder,
        effect: &mut Effect,
        factory: Factory,
        data: <Self as PassData<'b>>::Data,
    );
}

/// A compiled pass.  These are created and managed by the `Renderer`.  This should not be
/// used directly outside of the renderer.
#[derive(Clone, Debug)]
pub struct CompiledPass<P> {
    effect: Effect,
    inner: P,
}

impl<P> CompiledPass<P>
where
    P: Pass,
{
    pub(super) fn compile(
        mut pass: P,
        fac: &mut Factory,
        out: &Target,
        multisampling: u16,
    ) -> Result<Self> {
        let effect = pass.compile(NewEffect::new(fac, out, multisampling))?;
        Ok(CompiledPass {
            effect,
            inner: pass,
        })
    }
}

impl<P> CompiledPass<P> {
    /// Applies the inner pass.
    pub fn apply<'a, 'b: 'a>(
        &'a mut self,
        encoder: &mut Encoder,
        factory: Factory,
        data: <P as PassData<'b>>::Data,
    ) where
        P: Pass,
    {
        self.inner.apply(encoder, &mut self.effect, factory, data)
    }

    /// Distributes new target data to the pass.
    pub fn new_target(&mut self, target: &Target) {
        // Distribute new targets that don't blend.
        self.effect.data.out_colors.clear();
        self.effect
            .data
            .out_colors
            .extend(target.color_bufs().iter().map(|cb| &cb.as_output).cloned());

        // Distribute new blend targets
        self.effect.data.out_blends.clear();
        self.effect
            .data
            .out_blends
            .extend(target.color_bufs().iter().map(|cb| &cb.as_output).cloned());

        // Distribute new depth buffer
        self.effect.data.out_depth = target.depth_buf().map(|db| (db.as_output.clone(), (0, 0)));
    }
}