sdl3/
surface.rs

1use std::marker::PhantomData;
2use std::mem;
3use std::ops::{Deref, DerefMut};
4use std::path::Path;
5use std::sync::Arc;
6
7use crate::get_error;
8use crate::iostream::IOStream;
9use crate::pixels;
10use crate::rect::Rect;
11use crate::render::{BlendMode, Canvas};
12use crate::render::{Texture, TextureCreator, TextureValueError};
13use crate::sys;
14use crate::Error;
15use libc::c_int;
16use std::convert::TryFrom;
17use std::mem::transmute;
18use std::ptr;
19use sys::blendmode::SDL_BLENDMODE_NONE;
20use sys::surface::{SDL_ScaleMode, SDL_MUSTLOCK, SDL_SCALEMODE_LINEAR};
21
22/// Holds a `SDL_Surface`
23///
24/// When the `SurfaceContext` is dropped, it frees the `SDL_Surface`
25///
26/// *INTERNAL USE ONLY*
27pub struct SurfaceContext<'a> {
28    raw: *mut sys::surface::SDL_Surface,
29    _marker: PhantomData<&'a ()>,
30}
31
32impl Drop for SurfaceContext<'_> {
33    #[inline]
34    #[doc(alias = "SDL_DestroySurface")]
35    fn drop(&mut self) {
36        unsafe {
37            sys::surface::SDL_DestroySurface(self.raw);
38        }
39    }
40}
41
42/// Holds an `Arc<SurfaceContext>`.
43///
44/// Note: If a `Surface` goes out of scope but it cloned its context,
45/// then the `SDL_Surface` will not be free'd until there are no more references to the `SurfaceContext`.
46pub struct Surface<'a> {
47    context: Arc<SurfaceContext<'a>>,
48}
49
50/// An unsized Surface reference.
51///
52/// This type is used whenever Surfaces need to be borrowed from the SDL library, without concern
53/// for freeing the Surface.
54pub struct SurfaceRef {
55    // It's nothing! (it gets transmuted to SDL_Surface later).
56    // The empty private field is need to a) make `std::mem::swap()` copy nothing instead of
57    // clobbering two surfaces (SDL_Surface's size could change in the future),
58    // and b) prevent user initialization of this type.
59    _raw: (),
60}
61
62impl AsRef<SurfaceRef> for SurfaceRef {
63    fn as_ref(&self) -> &SurfaceRef {
64        self
65    }
66}
67
68#[test]
69fn test_surface_ref_size() {
70    // `SurfaceRef` must be 0 bytes.
71    assert_eq!(::std::mem::size_of::<SurfaceRef>(), 0);
72}
73
74impl Deref for Surface<'_> {
75    type Target = SurfaceRef;
76
77    #[inline]
78    fn deref(&self) -> &SurfaceRef {
79        unsafe { mem::transmute(self.context.raw) }
80    }
81}
82
83impl DerefMut for Surface<'_> {
84    #[inline]
85    fn deref_mut(&mut self) -> &mut SurfaceRef {
86        unsafe { mem::transmute(self.context.raw) }
87    }
88}
89
90impl AsRef<SurfaceRef> for Surface<'_> {
91    #[inline]
92    fn as_ref(&self) -> &SurfaceRef {
93        unsafe { mem::transmute(self.context.raw) }
94    }
95}
96
97impl AsMut<SurfaceRef> for Surface<'_> {
98    #[inline]
99    fn as_mut(&mut self) -> &mut SurfaceRef {
100        unsafe { mem::transmute(self.context.raw) }
101    }
102}
103
104impl<'a> Surface<'a> {
105    pub unsafe fn from_ll<'b>(raw: *mut sys::surface::SDL_Surface) -> Surface<'b> {
106        let context = SurfaceContext {
107            raw,
108            _marker: PhantomData,
109        };
110        Surface {
111            context: Arc::new(context),
112        }
113    }
114
115    /// Creates a new surface using a pixel format.
116    ///
117    /// # Example
118    /// ```no_run
119    /// use sdl3::pixels::PixelFormat;
120    /// use sdl3::surface::Surface;
121    ///
122    /// let surface = Surface::new(512, 512, PixelFormat::RGB24).unwrap();
123    /// ```
124    pub fn new(
125        width: u32,
126        height: u32,
127        format: pixels::PixelFormat,
128    ) -> Result<Surface<'static>, Error> {
129        let masks = format.into_masks()?;
130        Surface::from_pixelmasks(width, height, &masks)
131    }
132
133    /// Creates a new surface using pixel masks.
134    ///
135    /// # Example
136    /// ```no_run
137    /// use sdl3::pixels::PixelFormat;
138    /// use sdl3::surface::Surface;
139    ///
140    /// let masks = PixelFormat::RGB24.into_masks().unwrap();
141    /// let surface = Surface::from_pixelmasks(512, 512, &masks).unwrap();
142    /// ```
143    #[doc(alias = "SDL_CreateSurface")]
144    pub fn from_pixelmasks(
145        width: u32,
146        height: u32,
147        masks: &pixels::PixelMasks,
148    ) -> Result<Surface<'static>, Error> {
149        unsafe {
150            if width >= (1 << 31) || height >= (1 << 31) {
151                Err(Error("Image is too large.".to_owned()))
152            } else {
153                let raw = sys::surface::SDL_CreateSurface(
154                    width as c_int,
155                    height as c_int,
156                    sys::pixels::SDL_GetPixelFormatForMasks(
157                        masks.bpp as c_int,
158                        masks.rmask,
159                        masks.gmask,
160                        masks.bmask,
161                        masks.amask,
162                    ),
163                );
164
165                if raw.is_null() {
166                    Err(get_error())
167                } else {
168                    Ok(Surface::from_ll(raw))
169                }
170            }
171        }
172    }
173
174    /// Creates a new surface from an existing buffer, using a pixel format.
175    pub fn from_data(
176        data: &'a mut [u8],
177        width: u32,
178        height: u32,
179        pitch: u32,
180        format: pixels::PixelFormat,
181    ) -> Result<Surface<'a>, Error> {
182        let masks = format.into_masks()?;
183        Surface::from_data_pixelmasks(data, width, height, pitch, &masks)
184    }
185
186    /// Creates a new surface from an existing buffer, using pixel masks.
187    #[doc(alias = "SDL_CreateSurfaceFrom")]
188    pub fn from_data_pixelmasks(
189        data: &'a mut [u8],
190        width: u32,
191        height: u32,
192        pitch: u32,
193        masks: &pixels::PixelMasks,
194    ) -> Result<Surface<'a>, Error> {
195        unsafe {
196            if width >= (1 << 31) || height >= (1 << 31) {
197                Err(Error("Image is too large.".to_owned()))
198            } else if pitch >= (1 << 31) {
199                Err(Error("Pitch is too large.".to_owned()))
200            } else {
201                let raw = sys::surface::SDL_CreateSurfaceFrom(
202                    width as c_int,
203                    height as c_int,
204                    sys::pixels::SDL_GetPixelFormatForMasks(
205                        masks.bpp as c_int,
206                        masks.rmask,
207                        masks.gmask,
208                        masks.bmask,
209                        masks.amask,
210                    ),
211                    data.as_mut_ptr() as *mut _,
212                    pitch as c_int,
213                );
214
215                if raw.is_null() {
216                    Err(get_error())
217                } else {
218                    Ok(Surface::from_ll(raw))
219                }
220            }
221        }
222    }
223
224    /// A convenience function for [`TextureCreator::create_texture_from_surface`].
225    ///
226    /// ```no_run
227    /// use sdl3::pixels::PixelFormat;
228    /// use sdl3::surface::Surface;
229    /// use sdl3::render::{Canvas, Texture};
230    /// use sdl3::video::Window;
231    ///
232    /// // We init systems.
233    /// let sdl_context = sdl3::init().expect("failed to init SDL");
234    /// let video_subsystem = sdl_context.video().expect("failed to get video context");
235    ///
236    /// // We create a window.
237    /// let window = video_subsystem.window("sdl3 demo", 800, 600)
238    ///     .build()
239    ///     .expect("failed to build window");
240    ///
241    /// // We get the canvas from which we can get the `TextureCreator`.
242    /// let mut canvas: Canvas<Window> = window.into_canvas();
243    /// let texture_creator = canvas.texture_creator();
244    ///
245    /// let surface = Surface::new(512, 512, PixelFormat::RGB24).unwrap();
246    /// let texture = surface.as_texture(&texture_creator).unwrap();
247    /// ```
248    #[cfg(not(feature = "unsafe_textures"))]
249    pub fn as_texture<'b, T>(
250        &self,
251        texture_creator: &'b TextureCreator<T>,
252    ) -> Result<Texture<'b>, TextureValueError> {
253        texture_creator.create_texture_from_surface(self)
254    }
255
256    /// A convenience function for [`TextureCreator::create_texture_from_surface`].
257    ///
258    /// ```no_run
259    /// use sdl3::pixels::PixelFormat;
260    /// use sdl3::surface::Surface;
261    /// use sdl3::render::{Canvas, Texture};
262    /// use sdl3::video::Window;
263    ///
264    /// // We init systems.
265    /// let sdl_context = sdl3::init().expect("failed to init SDL");
266    /// let video_subsystem = sdl_context.video().expect("failed to get video context");
267    ///
268    /// // We create a window.
269    /// let window = video_subsystem.window("sdl3 demo", 800, 600)
270    ///     .build()
271    ///     .expect("failed to build window");
272    ///
273    /// // We get the canvas from which we can get the `TextureCreator`.
274    /// let mut canvas: Canvas<Window> = window.into_canvas();
275    /// let texture_creator = canvas.texture_creator();
276    ///
277    /// let surface = Surface::new(512, 512, PixelFormat::RGB24).unwrap();
278    /// let texture = surface.as_texture(&texture_creator).unwrap();
279    /// ```
280    #[cfg(feature = "unsafe_textures")]
281    pub fn as_texture<T>(
282        &self,
283        texture_creator: &TextureCreator<T>,
284    ) -> Result<Texture, TextureValueError> {
285        texture_creator.create_texture_from_surface(self)
286    }
287
288    #[doc(alias = "SDL_LoadBMP_RW")]
289    pub fn load_bmp_rw(iostream: &mut IOStream) -> Result<Surface<'static>, Error> {
290        let raw = unsafe { sys::surface::SDL_LoadBMP_IO(iostream.raw(), false) };
291
292        if raw.is_null() {
293            Err(get_error())
294        } else {
295            Ok(unsafe { Surface::from_ll(raw) })
296        }
297    }
298
299    pub fn load_bmp<P: AsRef<Path>>(path: P) -> Result<Surface<'static>, Error> {
300        let mut file = IOStream::from_file(path, "rb")?;
301        Surface::load_bmp_rw(&mut file)
302    }
303
304    /// Creates a Software Canvas to allow rendering in the Surface itself. This `Canvas` will
305    /// never be accelerated materially, so there is no performance change between `Surface` and
306    /// `Canvas` coming from a `Surface`.
307    ///
308    /// The only change is this case is that `Canvas` has a
309    /// better API to draw stuff in the `Surface` in that case, but don't expect any performance
310    /// changes, there will be none.
311    pub fn into_canvas(self) -> Result<Canvas<Surface<'a>>, Error> {
312        Canvas::from_surface(self)
313    }
314
315    pub fn context(&self) -> Arc<SurfaceContext<'a>> {
316        self.context.clone()
317    }
318}
319
320impl SurfaceRef {
321    #[inline]
322    pub unsafe fn from_ll<'a>(raw: *const sys::surface::SDL_Surface) -> &'a SurfaceRef {
323        &*(raw as *const () as *const SurfaceRef)
324    }
325
326    #[inline]
327    pub unsafe fn from_ll_mut<'a>(raw: *mut sys::surface::SDL_Surface) -> &'a mut SurfaceRef {
328        &mut *(raw as *mut () as *mut SurfaceRef)
329    }
330
331    #[inline]
332    // this can prevent introducing UB until
333    // https://github.com/rust-lang/rust-clippy/issues/5953 is fixed
334    #[allow(clippy::trivially_copy_pass_by_ref)]
335    #[doc(alias = "SDL_Surface")]
336    pub fn raw(&self) -> *mut sys::surface::SDL_Surface {
337        self as *const SurfaceRef as *mut SurfaceRef as *mut () as *mut sys::surface::SDL_Surface
338    }
339
340    #[inline]
341    fn raw_ref(&self) -> &sys::surface::SDL_Surface {
342        unsafe { &*(self as *const _ as *const () as *const sys::surface::SDL_Surface) }
343    }
344
345    pub fn width(&self) -> u32 {
346        self.raw_ref().w as u32
347    }
348
349    pub fn height(&self) -> u32 {
350        self.raw_ref().h as u32
351    }
352
353    pub fn pitch(&self) -> u32 {
354        self.raw_ref().pitch as u32
355    }
356
357    pub fn size(&self) -> (u32, u32) {
358        (self.width(), self.height())
359    }
360
361    /// Gets the rect of the surface.
362    pub fn rect(&self) -> Rect {
363        Rect::new(0, 0, self.width(), self.height())
364    }
365
366    pub fn pixel_format(&self) -> pixels::PixelFormat {
367        unsafe { pixels::PixelFormat::from_ll(self.raw_ref().format) }
368    }
369
370    pub fn pixel_format_enum(&self) -> pixels::PixelFormat {
371        self.pixel_format()
372    }
373
374    /// Locks a surface so that the pixels can be directly accessed safely.
375    #[doc(alias = "SDL_LockSurface")]
376    pub fn with_lock<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
377        unsafe {
378            if !sys::surface::SDL_LockSurface(self.raw()) {
379                panic!("could not lock surface");
380            }
381
382            let raw_pixels = self.raw_ref().pixels as *const _;
383            let len = self.raw_ref().pitch as usize * (self.raw_ref().h as usize);
384            let pixels = ::std::slice::from_raw_parts(raw_pixels, len);
385            let rv = f(pixels);
386            sys::surface::SDL_UnlockSurface(self.raw());
387            rv
388        }
389    }
390
391    /// Locks a surface so that the pixels can be directly accessed safely.
392    #[doc(alias = "SDL_LockSurface")]
393    pub fn with_lock_mut<R, F: FnOnce(&mut [u8]) -> R>(&mut self, f: F) -> R {
394        unsafe {
395            if !sys::surface::SDL_LockSurface(self.raw()) {
396                panic!("could not lock surface");
397            }
398
399            let raw_pixels = self.raw_ref().pixels as *mut _;
400            let len = self.raw_ref().pitch as usize * (self.raw_ref().h as usize);
401            let pixels = ::std::slice::from_raw_parts_mut(raw_pixels, len);
402            let rv = f(pixels);
403            sys::surface::SDL_UnlockSurface(self.raw());
404            rv
405        }
406    }
407
408    /// Returns the Surface's pixel buffer if the Surface doesn't require locking
409    /// (e.g. it's a software surface).
410    pub unsafe fn without_lock(&self) -> Option<&[u8]> {
411        if self.must_lock() {
412            None
413        } else {
414            let raw_pixels = self.raw_ref().pixels as *const _;
415            let len = self.raw_ref().pitch as usize * (self.raw_ref().h as usize);
416
417            Some(::std::slice::from_raw_parts(raw_pixels, len))
418        }
419    }
420
421    /// Returns the Surface's pixel buffer if the Surface doesn't require locking
422    /// (e.g. it's a software surface).
423    pub unsafe fn without_lock_mut(&mut self) -> Option<&mut [u8]> {
424        if self.must_lock() {
425            None
426        } else {
427            let raw_pixels = self.raw_ref().pixels as *mut _;
428            let len = self.raw_ref().pitch as usize * (self.raw_ref().h as usize);
429
430            Some(::std::slice::from_raw_parts_mut(raw_pixels, len))
431        }
432    }
433
434    /// Returns true if the Surface needs to be locked before accessing the Surface pixels.
435    pub unsafe fn must_lock(&self) -> bool {
436        SDL_MUSTLOCK(self.raw_ref())
437    }
438
439    #[doc(alias = "SDL_SaveBMP_RW")]
440    pub fn save_bmp_rw(&self, iostream: &mut IOStream) -> Result<(), Error> {
441        let ret = unsafe { sys::surface::SDL_SaveBMP_IO(self.raw(), iostream.raw(), false) };
442        if !ret {
443            Ok(())
444        } else {
445            Err(get_error())
446        }
447    }
448
449    pub fn save_bmp<P: AsRef<Path>>(&self, path: P) -> Result<(), Error> {
450        let mut file = IOStream::from_file(path, "wb")?;
451        self.save_bmp_rw(&mut file)
452    }
453
454    #[doc(alias = "SDL_SetSurfacePalette")]
455    pub fn set_palette(&mut self, palette: &pixels::Palette) -> Result<(), Error> {
456        let result = unsafe { sys::surface::SDL_SetSurfacePalette(self.raw(), palette.raw()) };
457
458        match result {
459            true => Ok(()),
460            _ => Err(get_error()),
461        }
462    }
463
464    #[allow(non_snake_case)]
465    #[doc(alias = "SDL_SetSurfaceRLE")]
466    pub fn enable_RLE(&mut self) {
467        let result = unsafe { sys::surface::SDL_SetSurfaceRLE(self.raw(), true) };
468
469        if !result {
470            // Should only panic on a null Surface
471            panic!("{}", get_error());
472        }
473    }
474
475    #[allow(non_snake_case)]
476    #[doc(alias = "SDL_SetSurfaceRLE")]
477    pub fn disable_RLE(&mut self) {
478        let result = unsafe { sys::surface::SDL_SetSurfaceRLE(self.raw(), false) };
479
480        if !result {
481            // Should only panic on a null Surface
482            panic!("{}", get_error());
483        }
484    }
485
486    #[doc(alias = "SDL_SetSurfaceColorKey")]
487    pub fn set_color_key(&mut self, enable: bool, color: pixels::Color) -> Result<(), Error> {
488        let key = color.to_u32(&self.pixel_format());
489        let result = unsafe { sys::surface::SDL_SetSurfaceColorKey(self.raw(), enable, key) };
490        if result {
491            Ok(())
492        } else {
493            Err(get_error())
494        }
495    }
496
497    /// The function will fail if the surface doesn't have color key enabled.
498    #[doc(alias = "SDL_GetSurfaceColorKey")]
499    pub fn color_key(&self) -> Result<pixels::Color, Error> {
500        let mut key = 0;
501
502        // SDL_GetSurfaceColorKey does not mutate, but requires a non-const pointer anyway.
503
504        let result = unsafe { sys::surface::SDL_GetSurfaceColorKey(self.raw(), &mut key) };
505
506        if result {
507            Ok(pixels::Color::from_u32(&self.pixel_format(), key))
508        } else {
509            Err(get_error())
510        }
511    }
512
513    #[doc(alias = "SDL_SetSurfaceColorMod")]
514    pub fn set_color_mod(&mut self, color: pixels::Color) {
515        let (r, g, b) = color.rgb();
516        let result = unsafe { sys::surface::SDL_SetSurfaceColorMod(self.raw(), r, g, b) };
517
518        if !result {
519            // Should only fail on a null Surface
520            panic!("{}", get_error());
521        }
522    }
523
524    #[doc(alias = "SDL_GetSurfaceColorMod")]
525    pub fn color_mod(&self) -> pixels::Color {
526        let mut r = 0;
527        let mut g = 0;
528        let mut b = 0;
529
530        // SDL_GetSurfaceColorMod does not mutate, but requires a non-const pointer anyway.
531
532        let result =
533            unsafe { sys::surface::SDL_GetSurfaceColorMod(self.raw(), &mut r, &mut g, &mut b) };
534
535        if result {
536            pixels::Color::RGB(r, g, b)
537        } else {
538            // Should only fail on a null Surface
539            panic!("{}", get_error())
540        }
541    }
542
543    #[doc(alias = "SDL_FillSurfaceRect")]
544    pub fn fill_rect<R>(&mut self, rect: R, color: pixels::Color) -> Result<(), Error>
545    where
546        R: Into<Option<Rect>>,
547    {
548        unsafe {
549            let rect = rect.into();
550            let rect_ptr = mem::transmute(rect.as_ref()); // TODO find a better way to transform
551                                                          // Option<&...> into a *const _
552            let format = self.pixel_format();
553            let result =
554                sys::surface::SDL_FillSurfaceRect(self.raw(), rect_ptr, color.to_u32(&format));
555            match result {
556                true => Ok(()),
557                _ => Err(get_error()),
558            }
559        }
560    }
561
562    #[allow(clippy::clone_on_copy)]
563    pub fn fill_rects(&mut self, rects: &[Rect], color: pixels::Color) -> Result<(), Error> {
564        for rect in rects.iter() {
565            self.fill_rect(rect.clone(), color)?;
566        }
567
568        Ok(())
569    }
570
571    #[doc(alias = "SDL_SetSurfaceAlphaMod")]
572    pub fn set_alpha_mod(&mut self, alpha: u8) {
573        let result = unsafe { sys::surface::SDL_SetSurfaceAlphaMod(self.raw(), alpha) };
574
575        if !result {
576            // Should only fail on a null Surface
577            panic!("{}", get_error());
578        }
579    }
580
581    #[doc(alias = "SDL_GetSurfaceAlphaMod")]
582    pub fn alpha_mod(&self) -> u8 {
583        let mut alpha = 0;
584        let result = unsafe { sys::surface::SDL_GetSurfaceAlphaMod(self.raw(), &mut alpha) };
585
586        match result {
587            true => alpha,
588            // Should only fail on a null Surface
589            _ => panic!("{}", get_error()),
590        }
591    }
592
593    /// The function will fail if the blend mode is not supported by SDL.
594    #[doc(alias = "SDL_SetSurfaceBlendMode")]
595    pub fn set_blend_mode(&mut self, mode: BlendMode) -> Result<(), Error> {
596        let result = unsafe { sys::surface::SDL_SetSurfaceBlendMode(self.raw(), transmute(mode)) };
597
598        match result {
599            true => Ok(()),
600            _ => Err(get_error()),
601        }
602    }
603
604    #[doc(alias = "SDL_GetSurfaceBlendMode")]
605    pub fn blend_mode(&self) -> BlendMode {
606        let mut mode = SDL_BLENDMODE_NONE;
607        let result = unsafe { sys::surface::SDL_GetSurfaceBlendMode(self.raw(), &mut mode) };
608
609        match result {
610            true => BlendMode::try_from(mode).unwrap(),
611            // Should only fail on a null Surface
612            _ => panic!("{}", get_error()),
613        }
614    }
615
616    /// Sets the clip rectangle for the surface.
617    ///
618    /// If the rectangle is `None`, clipping will be disabled.
619    #[doc(alias = "SDL_SetSurfaceClipRect")]
620    pub fn set_clip_rect<R>(&mut self, rect: R) -> bool
621    where
622        R: Into<Option<Rect>>,
623    {
624        let rect = rect.into();
625        unsafe {
626            sys::surface::SDL_SetSurfaceClipRect(
627                self.raw(),
628                match rect {
629                    Some(rect) => rect.raw(),
630                    None => ptr::null(),
631                },
632            )
633        }
634    }
635
636    /// Gets the clip rectangle for the surface.
637    ///
638    /// Returns `None` if clipping is disabled.
639    #[doc(alias = "SDL_GetSurfaceClipRect")]
640    pub fn clip_rect(&self) -> Option<Rect> {
641        let mut raw = mem::MaybeUninit::uninit();
642        unsafe { sys::surface::SDL_GetSurfaceClipRect(self.raw(), raw.as_mut_ptr()) };
643        let raw = unsafe { raw.assume_init() };
644
645        if raw.w == 0 || raw.h == 0 {
646            None
647        } else {
648            Some(Rect::from_ll(raw))
649        }
650    }
651
652    /// Copies the surface into a new one that is optimized for blitting to a surface of a specified pixel format.
653    #[doc(alias = "SDL_ConvertSurface")]
654    pub fn convert(&self, format: &pixels::PixelFormat) -> Result<Surface<'static>, Error> {
655        // SDL_ConvertSurface takes a flag as the last parameter, which should be 0 by the docs.
656        let surface_ptr = unsafe { sys::surface::SDL_ConvertSurface(self.raw(), format.raw()) };
657
658        if surface_ptr.is_null() {
659            Err(get_error())
660        } else {
661            unsafe { Ok(Surface::from_ll(surface_ptr)) }
662        }
663    }
664
665    /// Copies the surface into a new one of a specified pixel format.
666    #[doc(alias = "SDL_ConvertSurfaceFormat")]
667    pub fn convert_format(&self, format: pixels::PixelFormat) -> Result<Surface<'static>, Error> {
668        // SDL_ConvertSurfaceFormat takes a flag as the last parameter, which should be 0 by the docs.
669        let surface_ptr = unsafe { sys::surface::SDL_ConvertSurface(self.raw(), format.raw()) };
670
671        if surface_ptr.is_null() {
672            Err(get_error())
673        } else {
674            unsafe { Ok(Surface::from_ll(surface_ptr)) }
675        }
676    }
677
678    /// Performs surface blitting (surface copying).
679    ///
680    /// Returns the final blit rectangle, if a `dst_rect` was provided.
681    #[doc(alias = "SDL_BlitSurface")]
682    pub fn blit<R1, R2>(
683        &self,
684        src_rect: R1,
685        dst: &mut SurfaceRef,
686        dst_rect: R2,
687    ) -> Result<Option<Rect>, Error>
688    where
689        R1: Into<Option<Rect>>,
690        R2: Into<Option<Rect>>,
691    {
692        let src_rect = src_rect.into();
693        let dst_rect = dst_rect.into();
694
695        unsafe {
696            let src_rect_ptr = src_rect.as_ref().map(|r| r.raw()).unwrap_or(ptr::null());
697
698            // Copy the rect here to make a mutable copy without requiring
699            // a mutable argument
700            let mut dst_rect = dst_rect;
701            let dst_rect_ptr = dst_rect
702                .as_mut()
703                .map(|r| r.raw_mut())
704                .unwrap_or(ptr::null_mut());
705            let result =
706                sys::surface::SDL_BlitSurface(self.raw(), src_rect_ptr, dst.raw(), dst_rect_ptr);
707
708            if result {
709                Ok(dst_rect)
710            } else {
711                Err(get_error())
712            }
713        }
714    }
715
716    /// Performs low-level surface blitting.
717    ///
718    /// Unless you know what you're doing, use `blit()` instead, which will clip the input rectangles.
719    /// This function could crash if the rectangles aren't pre-clipped to the surface, and is therefore unsafe.
720    #[doc(alias = "SDL_BlitSurfaceUnchecked")]
721    pub unsafe fn lower_blit<R1, R2>(
722        &self,
723        src_rect: R1,
724        dst: &mut SurfaceRef,
725        dst_rect: R2,
726    ) -> Result<(), Error>
727    where
728        R1: Into<Option<Rect>>,
729        R2: Into<Option<Rect>>,
730    {
731        let src_rect = src_rect.into();
732        let dst_rect = dst_rect.into();
733
734        // The rectangles don't change, but the function requires mutable pointers.
735        let src_rect_ptr = src_rect.as_ref().map(|r| r.raw()).unwrap_or(ptr::null()) as *mut _;
736        let dst_rect_ptr = dst_rect.as_ref().map(|r| r.raw()).unwrap_or(ptr::null()) as *mut _;
737        if sys::surface::SDL_BlitSurfaceUnchecked(self.raw(), src_rect_ptr, dst.raw(), dst_rect_ptr)
738        {
739            Ok(())
740        } else {
741            Err(get_error())
742        }
743    }
744
745    /// Performs bilinear scaling between two surfaces of the same format, 32BPP.
746    ///
747    /// Returns the final blit rectangle, if a `dst_rect` was provided.
748    #[doc(alias = "SDL_BlitSurfaceScaled")]
749    pub unsafe fn soft_stretch_linear<R1, R2>(
750        &self,
751        src_rect: R1,
752        dst: &mut SurfaceRef,
753        dst_rect: R2,
754    ) -> Result<Option<Rect>, Error>
755    where
756        R1: Into<Option<Rect>>,
757        R2: Into<Option<Rect>>,
758    {
759        let src_rect = src_rect.into();
760        let dst_rect = dst_rect.into();
761
762        let src_rect_ptr = src_rect.as_ref().map(|r| r.raw()).unwrap_or(ptr::null());
763
764        // Copy the rect here to make a mutable copy without requiring
765        // a mutable argument
766        let mut dst_rect = dst_rect;
767        let dst_rect_ptr = dst_rect
768            .as_mut()
769            .map(|r| r.raw_mut())
770            .unwrap_or(ptr::null_mut());
771
772        let result = unsafe {
773            sys::surface::SDL_BlitSurfaceScaled(
774                self.raw(),
775                src_rect_ptr,
776                dst.raw(),
777                dst_rect_ptr,
778                SDL_SCALEMODE_LINEAR,
779            )
780        };
781        if result {
782            Ok(dst_rect)
783        } else {
784            Err(get_error())
785        }
786    }
787
788    /// Performs scaled surface bliting (surface copying).
789    ///
790    /// Returns the final blit rectangle, if a `dst_rect` was provided.
791    #[doc(alias = "SDL_BlitSurfaceScaled")]
792    pub fn blit_scaled<R1, R2>(
793        &self,
794        src_rect: R1,
795        dst: &mut SurfaceRef,
796        dst_rect: R2,
797        scale_mode: SDL_ScaleMode,
798    ) -> Result<Option<Rect>, Error>
799    where
800        R1: Into<Option<Rect>>,
801        R2: Into<Option<Rect>>,
802    {
803        let src_rect = src_rect.into();
804        let dst_rect = dst_rect.into();
805
806        let src_rect_ptr = src_rect.as_ref().map(|r| r.raw()).unwrap_or(ptr::null());
807
808        // Copy the rect here to make a mutable copy without requiring
809        // a mutable argument
810        let mut dst_rect = dst_rect;
811        let dst_rect_ptr = dst_rect
812            .as_mut()
813            .map(|r| r.raw_mut())
814            .unwrap_or(ptr::null_mut());
815        let result = unsafe {
816            sys::surface::SDL_BlitSurfaceScaled(
817                self.raw(),
818                src_rect_ptr,
819                dst.raw(),
820                dst_rect_ptr,
821                scale_mode,
822            )
823        };
824        if result {
825            Ok(dst_rect)
826        } else {
827            Err(get_error())
828        }
829    }
830
831    /// Performs low-level scaled surface blitting.
832    ///
833    /// Unless you know what you're doing, use `blit_scaled()` instead, which will clip the input rectangles.
834    /// This function could crash if the rectangles aren't pre-clipped to the surface, and is therefore unsafe.
835    #[doc(alias = "SDL_BlitSurfaceUncheckedScaled")]
836    pub unsafe fn lower_blit_scaled<R1, R2>(
837        &self,
838        src_rect: R1,
839        dst: &mut SurfaceRef,
840        dst_rect: R2,
841        scale_mode: SDL_ScaleMode,
842    ) -> Result<(), Error>
843    where
844        R1: Into<Option<Rect>>,
845        R2: Into<Option<Rect>>,
846    {
847        // The rectangles don't change, but the function requires mutable pointers.
848        let src_rect_ptr = src_rect
849            .into()
850            .as_ref()
851            .map(|r| r.raw())
852            .unwrap_or(ptr::null()) as *mut _;
853        let dst_rect_ptr = dst_rect
854            .into()
855            .as_ref()
856            .map(|r| r.raw())
857            .unwrap_or(ptr::null()) as *mut _;
858        if sys::surface::SDL_BlitSurfaceUncheckedScaled(
859            self.raw(),
860            src_rect_ptr,
861            dst.raw(),
862            dst_rect_ptr,
863            scale_mode,
864        ) {
865            Ok(())
866        } else {
867            Err(get_error())
868        }
869    }
870
871    /*
872    pub fn SDL_ConvertPixels(width: c_int, height: c_int, src_format: uint32_t, src: *c_void, src_pitch: c_int, dst_format: uint32_t, dst: *c_void, dst_pitch: c_int) -> c_int;
873    */
874}