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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
//! Render target used for storing 2D pixel representations of 3D scenes.

use fnv::FnvHashMap as HashMap;

use error::Result;
use types::{DepthStencilView, Encoder, Factory, RenderTargetView, ShaderResourceView, Window};

/// Target color buffer.
#[derive(Clone, Debug, PartialEq)]
pub struct ColorBuffer {
    /// Shader resource view.
    pub as_input: Option<ShaderResourceView<[f32; 4]>>,
    /// Target view.
    pub as_output: RenderTargetView,
}

/// Target depth-stencil buffer.
#[derive(Clone, Debug, PartialEq)]
pub struct DepthBuffer {
    /// Shader resource view.
    pub as_input: Option<ShaderResourceView<f32>>,
    /// Target view.
    pub as_output: DepthStencilView,
}

/// A hash map containing named render targets.
pub type Targets = HashMap<String, Target>;

/// A render target.
///
/// Each render target contains a certain number of color buffers and an
/// optional depth buffer.
#[derive(Clone, Debug, PartialEq)]
pub struct Target {
    color_bufs: Vec<ColorBuffer>,
    depth_buf: Option<DepthBuffer>,
    size: (u32, u32),
}

impl Target {
    /// Creates a new `Target` from a single color buffer and depth buffer pair.
    pub(crate) fn new(cb: ColorBuffer, db: DepthBuffer, size: (u32, u32)) -> Self {
        Target {
            color_bufs: vec![cb],
            depth_buf: Some(db),
            size: size,
        }
    }

    /// Creates a new TargetBuilder with the given name.
    pub fn named<N: Into<String>>(name: N) -> TargetBuilder {
        TargetBuilder::new(name)
    }

    /// Clears all color buffers to the given value.
    pub fn clear_color<V: Into<[f32; 4]>>(&self, enc: &mut Encoder, value: V) {
        let val = value.into();
        for buf in self.color_bufs.iter() {
            enc.clear(&buf.as_output, val);
        }
    }

    /// Clears the depth stencil buffer to the given value.
    pub fn clear_depth_stencil<V: Into<f32>>(&self, enc: &mut Encoder, value: V) {
        if let Some(ref buf) = self.depth_buf {
            let val = value.into();
            enc.clear_depth(&buf.as_output, val);
            enc.clear_stencil(&buf.as_output, val as u8);
        }
    }

    /// Returns the width and height of the render target, measured in pixels.
    pub fn size(&self) -> (u32, u32) {
        self.size
    }

    /// Returns the color buffer with index `i`.
    pub fn color_buf(&self, i: usize) -> Option<&ColorBuffer> {
        self.color_bufs.get(i)
    }

    /// Returns an array slice of the render target's color buffers.
    pub fn color_bufs(&self) -> &[ColorBuffer] {
        self.color_bufs.as_ref()
    }

    /// Returns the render target's depth-stencil buffer, if it has one.
    pub fn depth_buf(&self) -> Option<&DepthBuffer> {
        self.depth_buf.as_ref()
    }

    /// Creates the Direct3D 11 backend.
    #[cfg(all(feature = "d3d11", target_os = "windows"))]
    pub fn resize_main_target(window: &Window) -> Result<(Device, Factory, Target)> {
        unimplemented!()
    }

    #[cfg(all(feature = "metal", target_os = "macos"))]
    pub fn resize_main_target(window: &Window) -> Result<(Device, Factory, Target)> {
        unimplemented!()
    }

    /// Creates the OpenGL backend.
    #[cfg(feature = "opengl")]
    pub fn resize_main_target(&mut self, window: &Window) {
        if let Some(depth_buf) = self.depth_buf.as_mut() {
            for ref mut color_buf in &mut self.color_bufs {
                use gfx_window_glutin as win;
                win::update_views(window, &mut color_buf.as_output, &mut depth_buf.as_output);
            }
        }
    }
}

/// Builds new render targets.
///
/// By default, it creates render targets with one color buffer and no
/// depth-stencil buffer.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct TargetBuilder {
    custom_size: Option<(u32, u32)>,
    name: String,
    has_depth_buf: bool,
    num_color_bufs: usize,
}

impl TargetBuilder {
    /// Creates a new TargetBuilder.
    pub fn new<S: Into<String>>(name: S) -> Self {
        TargetBuilder {
            custom_size: None,
            name: name.into(),
            has_depth_buf: false,
            num_color_bufs: 1,
        }
    }

    /// Sets whether this render target should have a depth-stencil buffer.
    ///
    /// By default, render targets have no depth-stencil buffers included.
    pub fn with_depth_buf(mut self, has_buf: bool) -> Self {
        self.has_depth_buf = has_buf;
        self
    }

    /// Sets how many color buffers the render target will have. This number
    /// must be greater than zero or else `build()` will fail.
    ///
    /// By default, render targets have only one color buffer.
    pub fn with_num_color_bufs(mut self, num: usize) -> Self {
        self.num_color_bufs = num;
        self
    }

    /// Specifies a custom target size.
    pub fn with_size(mut self, size: (u32, u32)) -> Self {
        self.custom_size = Some(size);
        self
    }

    /// Builds and returns the new render target.
    pub(crate) fn build(self, fac: &mut Factory, size: (u32, u32)) -> Result<(String, Target)> {
        use gfx::Factory;

        let size = self.custom_size.unwrap_or(size);

        let color_bufs = (0..self.num_color_bufs)
            .into_iter()
            .map(|_| {
                let (w, h) = (size.0 as u16, size.1 as u16);
                let (_, res, rt) = fac.create_render_target(w, h)?;
                Ok(ColorBuffer {
                    as_input: Some(res),
                    as_output: rt,
                })
            })
            .collect::<Result<_>>()?;

        let depth_buf = if self.has_depth_buf {
            let (w, h) = (size.0 as u16, size.1 as u16);
            let (_, res, dt) = fac.create_depth_stencil(w, h)?;
            let depth = DepthBuffer {
                as_input: Some(res),
                as_output: dt,
            };
            Some(depth)
        } else {
            None
        };

        let target = Target {
            color_bufs: color_bufs,
            depth_buf: depth_buf,
            size: size,
        };

        Ok((self.name, target))
    }
}