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 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#[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(&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 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}