aboutsummaryrefslogtreecommitdiff
path: root/src/components.rs
blob: 1768448251edff06aff62e669853d11578bdb93f (plain)
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 bevy::{
    prelude::*,
    render::{
        extract_component::ExtractComponent,
        render_asset::RenderAssetUsages,
        render_resource::{Extent3d, TextureDimension, TextureFormat, TextureUsages},
    },
};

/// Component which, when inserted into an entity with a camera, enables the dither post-processing
/// effect.
#[derive(Component, ExtractComponent, Clone)]
pub struct DitherPostProcessSettings(Handle<Image>);

impl DitherPostProcessSettings {
    /// Constructs a new instance ofthis component, enabling the dither effect using a bayer
    /// matrix of the given level. A given level *n* will generate a square bayer matrix with a size of *(n+1)^2*.
    pub fn new(level: u32, asset_server: &AssetServer) -> Self {
        let power = level + 1;
        let map_size: u32 = 1 << power;
        let mut buffer = Vec::<u8>::new();

        for row in 0..map_size {
            for col in 0..map_size {
                let a = row ^ col;
                // Interleave bits of `a` with bits of y coordinate in reverse order
                let mut result: u64 = 0;
                let mut bit = 0;
                let mut mask = power as i32 - 1;
                loop {
                    if bit >= 2 * power {
                        break;
                    }
                    result |= (((col >> mask) & 1) << bit) as u64;
                    bit += 1;
                    result |= (((a >> mask) & 1) << bit) as u64;
                    bit += 1;
                    mask -= 1;
                }
                let value = ((result as f32 / map_size.pow(2) as f32) * 255.0) as u8;
                buffer.push(value);
            }
        }

        let mut image = Image::new(
            Extent3d {
                width: map_size,
                height: map_size,
                depth_or_array_layers: 1,
            },
            TextureDimension::D2,
            buffer,
            TextureFormat::R8Unorm,
            RenderAssetUsages::RENDER_WORLD,
        );
        image.texture_descriptor.usage = TextureUsages::COPY_DST
            | TextureUsages::STORAGE_BINDING
            | TextureUsages::TEXTURE_BINDING;

        let handle = asset_server.add(image);

        Self(handle)
    }
    /// Gets the handle of the texture representing this component's Bayer matrix
    pub fn handle(&self) -> Handle<Image> {    
        self.0.clone()
    }
}