1use crate::surface::Surface;
2
3use super::*;
4
5macro_rules! nz_is_err {
6 ($x:expr) => {{
7 let ret = $x;
8 if ret == 0 {
9 Ok(())
10 } else {
11 Err(get_error())
12 }
13 }};
14}
15
16#[derive(Clone, Copy, Default)]
17#[repr(transparent)]
18pub struct RendererFlags(SDL_RendererFlags);
19impl RendererFlags {
20 pub const SOFTWARE: Self = Self(SDL_RENDERER_SOFTWARE);
21 pub const ACCELERATED: Self = Self(SDL_RENDERER_ACCELERATED);
22 pub const VSYNC: Self = Self(SDL_RENDERER_PRESENTVSYNC);
23 pub const TARGETTEXTURE: Self = Self(SDL_RENDERER_TARGETTEXTURE);
24 pub const ACCELERATED_VSYNC: Self =
26 Self(SDL_RendererFlags(SDL_RENDERER_ACCELERATED.0 | SDL_RENDERER_PRESENTVSYNC.0));
27}
28impl core::fmt::Debug for RendererFlags {
29 #[inline]
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 let mut s = f.debug_set();
32 if (self.0 .0 & Self::SOFTWARE.0 .0) != 0 {
33 s.entry(&"Software");
34 }
35 if (self.0 .0 & Self::ACCELERATED.0 .0) != 0 {
36 s.entry(&"Accelerated");
37 }
38 if (self.0 .0 & Self::VSYNC.0 .0) != 0 {
39 s.entry(&"VSync");
40 }
41 if (self.0 .0 & Self::TARGETTEXTURE.0 .0) != 0 {
42 s.entry(&"TargetTexture");
43 }
44 s.finish()
45 }
46}
47
48#[derive(Clone, Copy, Default)]
49#[repr(transparent)]
50pub struct PixelFormatEnum(SDL_PixelFormatEnum);
51impl core::fmt::Debug for PixelFormatEnum {
52 #[inline]
53 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54 let s = match self.0 {
55 SDL_PIXELFORMAT_INDEX1LSB => "INDEX1LSB",
56 SDL_PIXELFORMAT_INDEX1MSB => "INDEX1MSB",
57 SDL_PIXELFORMAT_INDEX4LSB => "INDEX4LSB",
58 SDL_PIXELFORMAT_INDEX4MSB => "INDEX4MSB",
59 SDL_PIXELFORMAT_INDEX8 => "INDEX8",
60 SDL_PIXELFORMAT_RGB332 => "RGB332",
61 SDL_PIXELFORMAT_RGB444 => "RGB444",
62 SDL_PIXELFORMAT_RGB555 => "RGB555",
63 SDL_PIXELFORMAT_BGR555 => "BGR555",
64 SDL_PIXELFORMAT_ARGB4444 => "ARGB4444",
65 SDL_PIXELFORMAT_RGBA4444 => "RGBA4444",
66 SDL_PIXELFORMAT_ABGR4444 => "ABGR4444",
67 SDL_PIXELFORMAT_BGRA4444 => "BGRA4444",
68 SDL_PIXELFORMAT_ARGB1555 => "ARGB1555",
69 SDL_PIXELFORMAT_RGBA5551 => "RGBA5551",
70 SDL_PIXELFORMAT_ABGR1555 => "ABGR1555",
71 SDL_PIXELFORMAT_BGRA5551 => "BGRA5551",
72 SDL_PIXELFORMAT_RGB565 => "RGB565",
73 SDL_PIXELFORMAT_BGR565 => "BGR565",
74 SDL_PIXELFORMAT_RGB24 => "RGB24",
75 SDL_PIXELFORMAT_BGR24 => "BGR24",
76 SDL_PIXELFORMAT_RGB888 => "RGB888",
77 SDL_PIXELFORMAT_RGBX8888 => "RGBX8888",
78 SDL_PIXELFORMAT_BGR888 => "BGR888",
79 SDL_PIXELFORMAT_BGRX8888 => "BGRX8888",
80 SDL_PIXELFORMAT_ARGB8888 => "ARGB8888",
81 SDL_PIXELFORMAT_RGBA8888 => "RGBA8888",
82 SDL_PIXELFORMAT_ABGR8888 => "ABGR8888",
83 SDL_PIXELFORMAT_BGRA8888 => "BGRA8888",
84 SDL_PIXELFORMAT_ARGB2101010 => "ARGB2101010",
85 SDL_PIXELFORMAT_YV12 => "YV12",
86 SDL_PIXELFORMAT_IYUV => "IYUV",
87 SDL_PIXELFORMAT_YUY2 => "YUY2",
88 SDL_PIXELFORMAT_UYVY => "UYVY",
89 SDL_PIXELFORMAT_YVYU => "YVYU",
90 SDL_PIXELFORMAT_NV12 => "NV12",
91 SDL_PIXELFORMAT_NV21 => "NV21",
92 _ => "?",
93 };
94 write!(f, "{s}")
95 }
96}
97
98#[derive(Debug, Clone, Default)]
99pub struct RendererInfo {
100 pub name: String,
101 pub flags: RendererFlags,
102 pub texture_formats: Vec<PixelFormatEnum>,
103 pub max_texture_width: i32,
104 pub max_texture_height: i32,
105}
106
107impl Sdl {
108 #[inline]
109 pub fn get_renderer_driver_infos(&self) -> Result<Vec<RendererInfo>, SdlError> {
110 let num_drivers = unsafe { SDL_GetNumRenderDrivers() };
111 if num_drivers < 0 {
112 return Err(get_error());
113 }
114 let mut drivers = Vec::new();
115 for driver_index in 0..num_drivers {
116 let mut raw_info = SDL_RendererInfo::default();
117 let get_result = unsafe { SDL_GetRenderDriverInfo(driver_index, &mut raw_info) };
118 if get_result < 0 {
119 return Err(get_error());
120 } else {
121 let mut info = RendererInfo::default();
122 let mut p = raw_info.name.cast::<u8>();
123 while !p.is_null() && unsafe { *p } != 0 {
124 info.name.push(unsafe { *p } as char);
125 p = unsafe { p.add(1) };
126 }
127 for format in
128 raw_info.texture_formats.iter().copied().take(raw_info.num_texture_formats as _)
129 {
130 info.texture_formats.push(PixelFormatEnum(SDL_PixelFormatEnum(format)));
131 }
132 info.flags = RendererFlags(SDL_RendererFlags(raw_info.flags));
133 info.max_texture_width = raw_info.max_texture_width;
134 info.max_texture_height = raw_info.max_texture_height;
135 drivers.push(info);
136 }
137 }
138 Ok(drivers)
139 }
140}
141
142#[derive(Clone)]
143#[repr(C)]
144struct Window {
145 win: NonNull<SDL_Window>,
146 parent: Arc<SdlInit>,
147}
148impl Deref for Window {
149 type Target = CommonWindow;
150 #[inline]
151 fn deref(&self) -> &Self::Target {
152 unsafe { &*(self as *const Self).cast::<CommonWindow>() }
153 }
154}
155impl Drop for Window {
156 #[inline]
157 fn drop(&mut self) {
158 unsafe { SDL_DestroyWindow(self.win.as_ptr()) };
159 }
160}
161
162#[derive(Clone)]
163#[repr(C)]
164struct Renderer {
165 rend: NonNull<SDL_Renderer>,
166 win: Arc<Window>,
167}
168impl Deref for Renderer {
169 type Target = NonNull<SDL_Renderer>;
170 #[inline]
171 fn deref(&self) -> &Self::Target {
172 &self.rend
173 }
174}
175impl Drop for Renderer {
176 #[inline]
177 fn drop(&mut self) {
178 unsafe { SDL_DestroyRenderer(self.rend.as_ptr()) };
179 }
180}
181
182#[repr(C)]
183pub struct RendererWindow {
184 rend: Arc<Renderer>,
185 win: Arc<Window>,
186 init: Arc<SdlInit>,
187}
188impl Deref for RendererWindow {
189 type Target = CommonWindow;
190 #[inline]
191 fn deref(&self) -> &Self::Target {
192 &self.win
193 }
194}
195impl Sdl {
196 #[inline]
198 pub fn create_renderer_window(
199 &self, args: CreateWinArgs<'_>, flags: RendererFlags,
200 ) -> Result<RendererWindow, SdlError> {
201 let title_null: String = alloc::format!("{}\0", args.title);
202 let win_p: *mut SDL_Window = unsafe {
203 SDL_CreateWindow(
204 title_null.as_ptr().cast(),
205 SDL_WINDOWPOS_CENTERED,
206 SDL_WINDOWPOS_CENTERED,
207 args.width,
208 args.height,
209 args.window_flags().0,
210 )
211 };
212 let win = match NonNull::new(win_p) {
213 Some(win) => Arc::new(Window { win, parent: self.init.clone() }),
214 None => return Err(get_error()),
215 };
216 let rend_p: *mut SDL_Renderer = unsafe { SDL_CreateRenderer(win_p, -1, flags.0 .0) };
217 let rend = match NonNull::new(rend_p) {
218 Some(rend) => Arc::new(Renderer { rend, win: win.clone() }),
219 None => return Err(get_error()),
220 };
221 Ok(RendererWindow { rend, win, init: self.init.clone() })
222 }
223 #[inline]
225 pub fn compose_custom_blend_mode(
226 &self, src_color: BlendFactor, dst_color: BlendFactor, color_op: BlendOperation,
227 src_alpha: BlendFactor, dst_alpha: BlendFactor, alpha_op: BlendOperation,
228 ) -> BlendMode {
229 BlendMode(unsafe {
230 SDL_ComposeCustomBlendMode(
231 SDL_BlendFactor(src_color as _),
232 SDL_BlendFactor(dst_color as _),
233 SDL_BlendOperation(color_op as _),
234 SDL_BlendFactor(src_alpha as _),
235 SDL_BlendFactor(dst_alpha as _),
236 SDL_BlendOperation(alpha_op as _),
237 )
238 })
239 }
240}
241impl RendererWindow {
242 #[inline]
243 pub fn get_renderer_info(&self) -> Result<RendererInfo, SdlError> {
244 let mut raw_info = SDL_RendererInfo::default();
245 let get_result = unsafe { SDL_GetRendererInfo(self.rend.as_ptr(), &mut raw_info) };
246 if get_result < 0 {
247 Err(get_error())
248 } else {
249 let mut info = RendererInfo::default();
250 let mut p = raw_info.name.cast::<u8>();
251 while !p.is_null() && unsafe { *p } != 0 {
252 info.name.push(unsafe { *p } as char);
253 p = unsafe { p.add(1) };
254 }
255 for format in raw_info.texture_formats.iter().copied().take(raw_info.num_texture_formats as _)
256 {
257 info.texture_formats.push(PixelFormatEnum(SDL_PixelFormatEnum(format)));
258 }
259 info.flags = RendererFlags(SDL_RendererFlags(raw_info.flags));
260 info.max_texture_width = raw_info.max_texture_width;
261 info.max_texture_height = raw_info.max_texture_height;
262 Ok(info)
263 }
264 }
265 #[inline]
267 pub fn set_draw_blend_mode(&self, mode: BlendMode) -> Result<(), SdlError> {
268 nz_is_err!(unsafe { SDL_SetRenderDrawBlendMode(self.rend.as_ptr(), mode.0) })
269 }
270
271 #[inline]
273 pub fn create_texture_from_surface(&self, surface: &Surface) -> Result<Texture, SdlError> {
274 let tex_p = unsafe { SDL_CreateTextureFromSurface(self.rend.as_ptr(), surface.surf.as_ptr()) };
275 match NonNull::new(tex_p) {
276 Some(tex) => Ok(Texture { tex, parent: self.rend.clone() }),
277 None => Err(get_error()),
278 }
279 }
280 #[inline]
282 pub fn set_draw_color(&self, r: u8, g: u8, b: u8, a: u8) -> Result<(), SdlError> {
283 nz_is_err!(unsafe { SDL_SetRenderDrawColor(self.rend.as_ptr(), r, g, b, a) })
284 }
285 #[inline]
287 pub fn set_clip_rect(&self, rect: [c_int; 4]) -> Result<(), SdlError> {
288 nz_is_err!(unsafe {
289 SDL_RenderSetClipRect(self.rend.as_ptr(), rect.as_ptr().cast::<SDL_Rect>())
290 })
291 }
292 #[inline]
294 pub fn clear(&self) -> Result<(), SdlError> {
295 nz_is_err!(unsafe { SDL_RenderClear(self.rend.as_ptr()) })
296 }
297 #[inline]
299 pub fn present(&self) {
300 unsafe { SDL_RenderPresent(self.rend.as_ptr()) }
301 }
302 #[inline]
306 pub fn draw_lines(&self, points: &[[c_int; 2]]) -> Result<(), SdlError> {
307 nz_is_err!(unsafe {
308 SDL_RenderDrawLines(
309 self.rend.as_ptr(),
310 points.as_ptr().cast::<SDL_Point>(),
311 points.len().try_into().unwrap(),
312 )
313 })
314 }
315 #[inline]
319 pub fn draw_points(&self, points: &[[c_int; 2]]) -> Result<(), SdlError> {
320 nz_is_err!(unsafe {
321 SDL_RenderDrawPoints(
322 self.rend.as_ptr(),
323 points.as_ptr().cast::<SDL_Point>(),
324 points.len().try_into().unwrap(),
325 )
326 })
327 }
328 #[inline]
332 pub fn draw_rects(&self, points: &[[c_int; 4]]) -> Result<(), SdlError> {
333 nz_is_err!(unsafe {
334 SDL_RenderDrawRects(
335 self.rend.as_ptr(),
336 points.as_ptr().cast::<SDL_Rect>(),
337 points.len().try_into().unwrap(),
338 )
339 })
340 }
341 #[inline]
345 pub fn fill_rects(&self, points: &[[c_int; 4]]) -> Result<(), SdlError> {
346 nz_is_err!(unsafe {
347 SDL_RenderFillRects(
348 self.rend.as_ptr(),
349 points.as_ptr().cast::<SDL_Rect>(),
350 points.len().try_into().unwrap(),
351 )
352 })
353 }
354 #[inline]
356 pub fn copy(&self, t: &Texture, src: [c_int; 4], dst: [c_int; 4]) -> Result<(), SdlError> {
357 nz_is_err!(unsafe {
358 SDL_RenderCopy(
359 self.rend.as_ptr(),
360 t.tex.as_ptr(),
361 src.as_ptr().cast::<SDL_Rect>(),
362 dst.as_ptr().cast::<SDL_Rect>(),
363 )
364 })
365 }
366}
367
368#[derive(Debug, Clone, Copy, PartialEq, Eq)]
369#[repr(u32)]
370pub enum BlendOperation {
371 Add = SDL_BLENDOPERATION_ADD.0,
372 Subtract = SDL_BLENDOPERATION_SUBTRACT.0,
373 RevSubtract = SDL_BLENDOPERATION_REV_SUBTRACT.0,
374 Minimum = SDL_BLENDOPERATION_MINIMUM.0,
375 Maximum = SDL_BLENDOPERATION_MAXIMUM.0,
376}
377
378#[derive(Debug, Clone, Copy, PartialEq, Eq)]
379#[repr(u32)]
380pub enum BlendFactor {
381 Zero = SDL_BLENDFACTOR_ZERO.0,
382 One = SDL_BLENDFACTOR_ONE.0,
383 SrcColor = SDL_BLENDFACTOR_SRC_COLOR.0,
384 OneMinusSrcColor = SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR.0,
385 SrcAlpha = SDL_BLENDFACTOR_SRC_ALPHA.0,
386 OneMinusSrcAlpha = SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA.0,
387 DstColor = SDL_BLENDFACTOR_DST_COLOR.0,
388 OneMinusDstColor = SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR.0,
389 DstAlpha = SDL_BLENDFACTOR_DST_ALPHA.0,
390 OneMinusDstAlpha = SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA.0,
391}
392
393#[derive(Debug, Clone, Copy, PartialEq, Eq)]
394#[repr(transparent)]
395pub struct BlendMode(SDL_BlendMode);
396
397#[derive(Debug, Clone, Copy, PartialEq, Eq)]
398#[repr(i32)]
399pub enum TextureAccess {
400 Static = SDL_TEXTUREACCESS_STATIC.0,
401 Streaming = SDL_TEXTUREACCESS_STREAMING.0,
402 Target = SDL_TEXTUREACCESS_TARGET.0,
403}
404
405#[repr(C)]
410pub struct Texture {
411 tex: NonNull<SDL_Texture>,
412 parent: Arc<Renderer>,
413}
414impl Drop for Texture {
415 #[inline]
416 fn drop(&mut self) {
417 unsafe { SDL_DestroyTexture(self.tex.as_ptr()) };
418 }
419}