1use std::{num::NonZero, sync::Arc};
8
9use winit::dpi::PhysicalSize;
10
11use crate::{math::Point2, utils::ArcRef, window::Window};
12
13pub fn new<'a>(window: Option<&'a mut super::window::Window>) -> PixelBufferBuilder<'a> {
16 let builder = PixelBufferBuilder::new();
17
18 if let Some(window) = window {
19 builder.with_window(window)
20 } else {
21 builder
22 }
23}
24
25#[derive(Clone, Debug)]
27pub struct PixelBuffer {
28 pub(crate) inner: ArcRef<PixelBufferInner>,
29}
30
31impl PixelBuffer {
32 pub(crate) fn new(window: &Window) -> Result<Self, PixelBufferError> {
33 let window_inner = window.inner.wait_borrow_mut();
34
35 let window_handle = {
36 let handle = window_inner.window_pointer.as_ref();
37
38 if handle.is_none() {
39 return Err(PixelBufferError::WindowPointerIsNull);
40 }
41
42 let handle = handle.unwrap();
43 let window_handle = handle.lock().get_window().clone();
44
45 window_handle
46 };
47
48 let context = SoftbufferContext::new(window_handle.clone());
49
50 if context.is_err() {
51 return Err(PixelBufferError::ContextCreationFailed);
52 }
53
54 let context = context.unwrap();
55 let surface = SoftbufferSurface::new(&context, window_handle);
56
57 if surface.is_err() {
58 return Err(PixelBufferError::SurfaceCreationFailed);
59 }
60
61 let surface = surface.unwrap();
62 let softbuffer_inner = PixelBufferInner {
63 _context: context,
64 surface,
65 surface_size: Point2::new(0.0, 0.0),
66 };
67
68 let softbuffer_inner = ArcRef::new(softbuffer_inner);
69
70 Ok(PixelBuffer {
71 inner: softbuffer_inner,
72 })
73 }
74
75 pub fn size(&self) -> Point2 {
78 let inner = self.inner.wait_borrow();
79 inner.surface_size
80 }
81
82 pub fn write_buffers(&mut self, pixels: &[u32], size: Point2) -> Result<(), PixelBufferError> {
84 let mut inner = self.inner.wait_borrow_mut();
85
86 if pixels.len() != (size.x * size.y) as usize {
87 return Err(PixelBufferError::InvalidSize(size.x as u32, size.y as u32));
88 }
89
90 if inner.surface_size == Point2::new(0.0, 0.0) {
91 return Err(PixelBufferError::InvalidSurfaceSize);
92 }
93
94 let pixel_buffers = inner.surface.buffer_mut();
95 if pixel_buffers.is_err() {
96 return Err(PixelBufferError::BufferFetchFailed);
97 }
98
99 let mut pixel_buffers = pixel_buffers.unwrap();
100 if pixel_buffers.len() < pixels.len() {
101 return Err(PixelBufferError::BufferTooSmall);
102 }
103
104 for (i, pixel) in pixels.iter().enumerate() {
105 pixel_buffers[i] = *pixel;
106 }
107
108 let res = pixel_buffers.present();
109 if res.is_err() {
110 return Err(PixelBufferError::PresentFailed);
111 }
112
113 Ok(())
114 }
115}
116
117pub type SoftbufferSurface = softbuffer::Surface<Arc<winit::window::Window>, Arc<winit::window::Window>>;
118pub type SoftbufferContext = softbuffer::Context<Arc<winit::window::Window>>;
119
120pub(crate) struct PixelBufferInner {
121 pub _context: SoftbufferContext,
122 pub surface: SoftbufferSurface,
123 pub surface_size: Point2,
124}
125
126impl PixelBufferInner {
127 pub fn resize(&mut self, size: PhysicalSize<u32>) -> Result<(), String> {
128 if size.width == 0 || size.height == 0 {
129 return Err("Invalid size".to_string());
130 }
131
132 self.surface_size = Point2::new(size.width as f32, size.height as f32);
133
134 let width: NonZero<u32> = NonZero::new(size.width).ok_or("Width cannot be zero")?;
135 let height: NonZero<u32> = NonZero::new(size.height).ok_or("Height cannot be zero")?;
136
137 let result = self.surface.resize(width, height);
138 if result.is_err() {
139 return Err(format!(
140 "Failed to resize softbuffer surface: {:?}",
141 result.err()
142 ));
143 }
144
145 Ok(())
146 }
147}
148
149
150pub struct PixelBufferBuilder<'a> {
151 window: Option<&'a mut Window>,
152}
153
154impl<'a> PixelBufferBuilder<'a> {
155 pub(crate) fn new() -> Self {
156 PixelBufferBuilder { window: None }
157 }
158
159 pub fn with_window(mut self, window: &'a mut Window) -> Self {
162 self.window = Some(window);
163 self
164 }
165
166 pub fn build(self) -> Result<PixelBuffer, PixelBufferBuilderError> {
167 if self.window.is_none() {
168 return Err(PixelBufferBuilderError::WindowIsNull);
169 }
170
171 let window = self.window.unwrap();
172
173 let is_graphics_exist = {
174 let window_inner = window.inner.borrow();
175 window_inner.graphics.is_some()
176 };
177
178 if is_graphics_exist {
179 return Err(PixelBufferBuilderError::CannotUseWithGPUWindow);
180 }
181
182 let pixel_buffer =
183 PixelBuffer::new(window).map_err(|e| PixelBufferBuilderError::PixelBufferError(e))?;
184
185 let mut window_inner = window.inner.borrow_mut();
186 window_inner.pixelbuffer = Some(pixel_buffer.inner.clone());
187
188 Ok(pixel_buffer)
189 }
190}
191
192#[derive(Clone, Copy, Debug)]
193pub enum PixelWriteMode {
194 Copy,
196 Clear,
198 Blend,
200}
201
202#[derive(Clone, Copy, Debug)]
203pub enum PixelBlendMode {
204 Alpha,
206 Add,
208 Subtract,
210 Multiply,
212}
213
214#[derive(Clone, Copy, Debug)]
215pub enum PixelBufferError {
216 WindowPointerIsNull,
217 ContextCreationFailed,
218 SurfaceCreationFailed,
219 InvalidSize(u32, u32),
220 InvalidSurfaceSize,
221 BufferFetchFailed,
222 BufferTooSmall,
223 PresentFailed,
224}
225
226impl std::fmt::Display for PixelBufferError {
227 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
228 match self {
229 PixelBufferError::WindowPointerIsNull => write!(f, "Window pointer is null"),
230 PixelBufferError::ContextCreationFailed => {
231 write!(f, "Failed to create pixel buffer context")
232 }
233 PixelBufferError::SurfaceCreationFailed => {
234 write!(f, "Failed to create pixel buffer surface")
235 }
236 PixelBufferError::InvalidSize(width, height) => {
237 write!(f, "Invalid size: {}x{}", width, height)
238 }
239 PixelBufferError::InvalidSurfaceSize => write!(f, "Pixel buffer surface size is zero"),
240 PixelBufferError::BufferFetchFailed => write!(f, "Failed to fetch pixel buffer"),
241 PixelBufferError::BufferTooSmall => write!(f, "Pixel buffer is too small"),
242 PixelBufferError::PresentFailed => write!(f, "Failed to present pixel buffer"),
243 }
244 }
245}
246
247#[derive(Clone, Copy, Debug)]
248pub enum PixelBufferBuilderError {
249 WindowIsNull,
250 CannotUseWithGPUWindow,
251 PixelBufferError(PixelBufferError),
252}
253
254impl std::fmt::Display for PixelBufferBuilderError {
255 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
256 match self {
257 PixelBufferBuilderError::WindowIsNull => {
258 write!(f, "PixelBuffer must be created with a window")
259 }
260 PixelBufferBuilderError::CannotUseWithGPUWindow => write!(
261 f,
262 "PixelBuffer cannot be created alongside GPU (hardware rendering)"
263 ),
264 PixelBufferBuilderError::PixelBufferError(e) => write!(f, "PixelBuffer error: {}", e),
265 }
266 }
267}