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
use crate::*;
pub use comfy_core::*;

pub static BLOOD_CANVAS: OnceCell<AtomicRefCell<BloodCanvas>> = OnceCell::new();

pub fn blood_canvas_update_and_draw(f: fn(IVec2, &CanvasBlock)) {
    let mut canvas = BLOOD_CANVAS.get().unwrap().borrow_mut();
    let canvas = &mut *canvas;

    for (_, block) in canvas.blocks.iter_mut() {
        if block.modified {
            // info!("updating block at {}", key);
            block.modified = false;

            canvas
                .creator
                .borrow_mut()
                .update_texture(&block.image, block.handle);
        }
    }

    for (key, block) in canvas.blocks.iter() {
        f(*key, block);
    }
}

pub fn blood_canvas_reset() {
    BLOOD_CANVAS.get().unwrap().borrow_mut().blocks = HashMap::default();
}

pub fn blood_circle_at(position: Vec2, radius: i32, pixel_prob: f32, color: fn() -> Color) {
    BLOOD_CANVAS
        .get()
        .unwrap()
        .borrow_mut()
        .circle_at_internal(position, radius, pixel_prob, color);
}

pub fn blood_canvas_blit_at(
    texture: TextureHandle,
    position: Vec2,
    source_rect: Option<IRect>,
    tint: Color,
) {
    BLOOD_CANVAS
        .get()
        .unwrap()
        .borrow_mut()
        .blit_at(texture, position, source_rect, tint);
}

#[derive(Debug)]
pub struct WgpuTextureCreator {
    pub device: Arc<wgpu::Device>,
    pub queue: Arc<wgpu::Queue>,
    pub layout: Arc<wgpu::BindGroupLayout>,
    pub textures: Arc<Mutex<HashMap<TextureHandle, (wgpu::BindGroup, Texture)>>>,
}

impl TextureCreator for WgpuTextureCreator {
    fn handle_from_image(&self, name: &str, image: &DynamicImage) -> TextureHandle {
        let texture = Texture::from_image_uninit(&self.device, image, Some(name)).unwrap();

        let bind_group = self.device.simple_bind_group(name, &texture, &self.layout);

        let handle = texture_path(name);
        self.textures.lock().insert(handle, (bind_group, texture));

        handle
    }

    // TODO: flip order of params for better readability?
    fn update_texture(&self, image: &DynamicImage, handle: TextureHandle) {
        let size = wgpu::Extent3d {
            width: image.width(),
            height: image.height(),
            depth_or_array_layers: 1,
        };

        let textures = self.textures.lock();
        let texture = &textures.get(&handle).unwrap().1;

        self.queue.write_texture(
            wgpu::ImageCopyTexture {
                aspect: wgpu::TextureAspect::All,
                texture: &texture.texture,
                mip_level: 0,
                origin: wgpu::Origin3d::ZERO,
            },
            // TODO: check which one is correct
            // &image.as_bytes(),
            &image.to_rgba8(),
            wgpu::ImageDataLayout {
                offset: 0,
                bytes_per_row: Some(4 * image.width()),
                rows_per_image: None,
            },
            size,
        );
    }
}