comfy_wgpu/
blood_canvas.rs

1use crate::*;
2pub use comfy_core::*;
3use image::{ImageBuffer, RgbaImage};
4
5pub static BLOOD_CANVAS: OnceCell<AtomicRefCell<BloodCanvas>> = OnceCell::new();
6
7pub fn blood_canvas_update_and_draw(f: fn(IVec2, &CanvasBlock)) {
8    let mut canvas = BLOOD_CANVAS.get().unwrap().borrow_mut();
9    let canvas = &mut *canvas;
10
11    for (_, block) in canvas.blocks.iter_mut() {
12        let _span = span!("canvas_block");
13
14        if block.modified {
15            // info!("updating block at {}", key);
16            block.modified = false;
17
18            canvas
19                .creator
20                .borrow_mut()
21                .update_texture(&block.image, block.handle);
22        }
23    }
24
25    for (key, block) in canvas.blocks.iter() {
26        f(*key, block);
27    }
28}
29
30pub fn blood_canvas_reset() {
31    BLOOD_CANVAS.get().unwrap().borrow_mut().blocks = HashMap::default();
32}
33
34pub fn blood_pixel_at(position: Vec2, color: Color) {
35    BLOOD_CANVAS.get().unwrap().borrow_mut().set_pixel(position, color);
36}
37
38pub fn blood_circle_at(
39    position: Vec2,
40    radius: i32,
41    pixel_prob: f32,
42    color: fn() -> Color,
43) {
44    BLOOD_CANVAS
45        .get()
46        .unwrap()
47        .borrow_mut()
48        .circle_at_internal(position, radius, pixel_prob, color);
49}
50
51pub fn blood_canvas_blit_at(
52    texture: TextureHandle,
53    position: Vec2,
54    source_rect: Option<IRect>,
55    tint: Color,
56) {
57    BLOOD_CANVAS.get().unwrap().borrow_mut().blit_at(
58        texture,
59        position,
60        source_rect,
61        tint,
62        false,
63        false,
64    );
65}
66
67pub fn blood_canvas_blit_at_pro(
68    texture: TextureHandle,
69    position: Vec2,
70    source_rect: Option<IRect>,
71    tint: Color,
72    flip_x: bool,
73    flip_y: bool,
74) {
75    BLOOD_CANVAS.get().unwrap().borrow_mut().blit_at(
76        texture,
77        position,
78        source_rect,
79        tint,
80        flip_x,
81        flip_y,
82    );
83}
84
85pub fn blood_canvas_blit_at_sized(
86    texture: TextureHandle,
87    position: Vec2,
88    source_rect: Option<IRect>,
89    tint: Color,
90    size: Vec2,
91) {
92    BLOOD_CANVAS.get().unwrap().borrow_mut().blit_at_sized(
93        texture,
94        position,
95        source_rect,
96        tint,
97        size,
98    );
99}
100
101// TODO: move this out of blood_canvas
102#[derive(Debug)]
103pub struct WgpuTextureCreator {
104    pub device: Arc<wgpu::Device>,
105    pub queue: Arc<wgpu::Queue>,
106    pub layout: Arc<wgpu::BindGroupLayout>,
107    pub textures: Arc<Mutex<TextureMap>>,
108}
109
110impl TextureCreator for WgpuTextureCreator {
111    fn handle_from_size(
112        &self,
113        name: &str,
114        size: UVec2,
115        color: Color,
116    ) -> TextureHandle {
117        let buffer =
118            ImageBuffer::from_pixel(size.x, size.y, color.to_image_rgba());
119
120        self.handle_from_image(name, &buffer)
121    }
122
123    fn handle_from_image(
124        &self,
125        name: &str,
126        image: &RgbaImage,
127    ) -> TextureHandle {
128        let dims = image.dimensions();
129        assert!(dims.0 > 0 && dims.1 > 0);
130
131        let dynamic_image = DynamicImage::ImageRgba8(image.clone());
132
133        let texture =
134            // Texture::from_image_uninit(&self.device, image, Some(name))
135            Texture::from_image(&self.device, &self.queue, &dynamic_image, Some(name), false)
136                .unwrap();
137
138        let bind_group =
139            self.device.simple_bind_group(Some(name), &texture, &self.layout);
140
141        let handle = texture_path(name);
142        self.textures
143            .lock()
144            .insert(handle, BindableTexture { bind_group, texture });
145
146        let assets = ASSETS.borrow_mut();
147        let mut image_map = assets.texture_image_map.lock();
148        image_map.insert(handle, Arc::new(image.clone()));
149
150        handle
151    }
152
153    fn update_texture_region(
154        &self,
155        handle: TextureHandle,
156        image: &RgbaImage,
157        region: IRect,
158    ) {
159        // assert_eq!(region.size.x, image.width() as i32);
160        // assert_eq!(region.size.y, image.height() as i32);
161
162        let size = wgpu::Extent3d {
163            width: image.width(),
164            height: image.height(),
165            depth_or_array_layers: 1,
166        };
167
168        let textures = self.textures.lock();
169        let texture = &textures.get(&handle).unwrap().texture;
170
171        self.queue.write_texture(
172            wgpu::ImageCopyTexture {
173                aspect: wgpu::TextureAspect::All,
174                texture: &texture.texture,
175                mip_level: 0,
176                origin: wgpu::Origin3d {
177                    x: region.offset.x as u32,
178                    y: region.offset.y as u32,
179                    z: 0,
180                },
181            },
182            &image,
183            wgpu::ImageDataLayout {
184                offset: 0,
185                bytes_per_row: Some(4 * image.width()),
186                rows_per_image: None,
187            },
188            size,
189        );
190    }
191
192    fn update_texture(&self, image: &RgbaImage, handle: TextureHandle) {
193        let size = wgpu::Extent3d {
194            width: image.width(),
195            height: image.height(),
196            depth_or_array_layers: 1,
197        };
198
199        let textures = self.textures.lock();
200        let texture = &textures.get(&handle).unwrap().texture;
201
202        self.queue.write_texture(
203            wgpu::ImageCopyTexture {
204                aspect: wgpu::TextureAspect::All,
205                texture: &texture.texture,
206                mip_level: 0,
207                origin: wgpu::Origin3d::ZERO,
208            },
209            &image,
210            wgpu::ImageDataLayout {
211                offset: 0,
212                bytes_per_row: Some(4 * image.width()),
213                rows_per_image: None,
214            },
215            size,
216        );
217    }
218}