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
//! Utility for a texture view which can either be created by a [`TextureView`](wgpu::TextureView)
//! or [`SurfaceTexture`](wgpu::SurfaceTexture)

use std::ops::Deref;

use crate::render::{eventually::HasChanged, settings::Msaa};

/// Describes a [`TextureView`].
///
/// May be converted from a [`TextureView`](wgpu::TextureView) or [`SurfaceTexture`](wgpu::SurfaceTexture)
/// or dereferences to a wgpu [`TextureView`](wgpu::TextureView).
#[derive(Debug)]
pub enum TextureView {
    /// The value is an actual wgpu [`TextureView`](wgpu::TextureView).
    TextureView(wgpu::TextureView),

    /// The value is a wgpu [`SurfaceTexture`](wgpu::SurfaceTexture), but dereferences to
    /// a [`TextureView`](wgpu::TextureView).
    SurfaceTexture {
        // NOTE: The order of these fields is important because the view must be dropped before the
        // frame is dropped
        view: wgpu::TextureView,
        texture: wgpu::SurfaceTexture,
    },
}

impl TextureView {
    /// Returns the [`SurfaceTexture`](wgpu::SurfaceTexture) of the texture view if it is of that type.
    #[inline]
    pub fn take_surface_texture(self) -> Option<wgpu::SurfaceTexture> {
        match self {
            TextureView::TextureView(_) => None,
            TextureView::SurfaceTexture { texture, .. } => Some(texture),
        }
    }
}

impl From<wgpu::TextureView> for TextureView {
    fn from(value: wgpu::TextureView) -> Self {
        TextureView::TextureView(value)
    }
}

impl From<wgpu::SurfaceTexture> for TextureView {
    fn from(surface_texture: wgpu::SurfaceTexture) -> Self {
        let view = surface_texture.texture.create_view(&Default::default());

        TextureView::SurfaceTexture {
            texture: surface_texture,
            view,
        }
    }
}

impl Deref for TextureView {
    type Target = wgpu::TextureView;

    #[inline]
    fn deref(&self) -> &Self::Target {
        match &self {
            TextureView::TextureView(value) => value,
            TextureView::SurfaceTexture { view, .. } => view,
        }
    }
}

pub struct Texture {
    pub size: wgpu::Extent3d,
    pub texture: wgpu::Texture,
    pub view: TextureView,
}

impl Texture {
    pub fn new(
        label: wgpu::Label,
        device: &wgpu::Device,
        format: wgpu::TextureFormat,
        width: u32,
        height: u32,
        msaa: Msaa,
        usage: wgpu::TextureUsages,
    ) -> Texture {
        let size = wgpu::Extent3d {
            width,
            height,
            depth_or_array_layers: 1,
        };

        let texture = device.create_texture(&wgpu::TextureDescriptor {
            label,
            size,
            mip_level_count: 1,
            sample_count: msaa.samples,
            dimension: wgpu::TextureDimension::D2,
            format,
            usage,
            view_formats: &[format],
        });
        let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
        Self {
            size,
            texture,
            view: TextureView::TextureView(view),
        }
    }
}

impl HasChanged for Texture {
    type Criteria = (u32, u32);

    fn has_changed(&self, criteria: &Self::Criteria) -> bool {
        let size = (self.size.width, self.size.height);
        !size.eq(criteria)
    }
}