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
use crate::runtime::state::ContextUpdate;
use crate::runtime::Connection;

/// Describes the viewport used by by a [GraphicsPipeline].
///
/// The viewport defines the affine transformation of `X` and `Y` from normalized device coordinates
/// to window coordinates.
///
/// Given a viewport with origin `(X_vp, Y_vp)`, width `width` and height `height`; let `X_nd` and
/// `Y_nd` be normalized device coordinates, then the corresponding window coordinates `X_w` and
/// `Y_w` are computed as:
///
/// `X_w = (X_nd + 1) * 0.5 * width + X_vp`
///
/// `Y_w = (X_nd + 1) * 0.5 * height + Y_vp`
///
/// There are two ways to define a [Viewport]:
///
/// 1. With explicit values:
///    ```
///    # #[allow(non_snake_case)] let X_vp = 0;
///    # #[allow(non_snake_case)] let Y_vp = 0;
///    # let width = 100;
///    # let height = 100;
///    use web_glitz::pipeline::graphics::Viewport;
///
///    let viewport = Viewport::Region((X_vp, Y_vp), width, height);
///    ```
///    Where `X_vp`, `Y_vp`, `width` and `height` correspond to the values used in the description
///    above.
///
/// 2. With automatic values:
///    ```
///    use web_glitz::pipeline::graphics::Viewport;
///
///    let viewport = Viewport::Auto;
///    ```
///    In this case, the origin will always be `(0, 0)`; determination of the `width` and `height`
///    is deferred until draw time, where they taken to be the width and height of the
///    [RenderTarget] that is being drawn to, such that the viewport will cover the [RenderTarget]
///    exactly. Note that the width and height of the [RenderTarget] are determined by the attached
///    images with the smallest width and height respectively.
///
#[derive(Clone, PartialEq, Debug)]
pub enum Viewport {
    Region((i32, i32), u32, u32),
    Auto,
}

impl Viewport {
    pub(crate) fn apply(&self, connection: &mut Connection, auto_dimensions: (u32, u32)) {
        let (gl, state) = unsafe { connection.unpack_mut() };

        let (x, y, width, height) = match self {
            Viewport::Region((x, y), width, height) => (*x, *y, *width, *height),
            Viewport::Auto => {
                let (width, height) = auto_dimensions;

                (0, 0, width, height)
            }
        };

        state
            .set_viewport(x, y, width as i32, height as i32)
            .apply(gl)
            .unwrap();
    }
}