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
22pub 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
42pub struct Surface<'a> {
47 context: Arc<SurfaceContext<'a>>,
48}
49
50pub struct SurfaceRef {
55 _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 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 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 #[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 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 #[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 #[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 #[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 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 #[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 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 #[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 #[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 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 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 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 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 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 #[doc(alias = "SDL_GetSurfaceColorKey")]
499 pub fn color_key(&self) -> Result<pixels::Color, Error> {
500 let mut key = 0;
501
502 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 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 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 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()); 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 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 _ => panic!("{}", get_error()),
590 }
591 }
592
593 #[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 _ => panic!("{}", get_error()),
613 }
614 }
615
616 #[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 #[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 #[doc(alias = "SDL_ConvertSurface")]
654 pub fn convert(&self, format: &pixels::PixelFormat) -> Result<Surface<'static>, Error> {
655 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 #[doc(alias = "SDL_ConvertSurfaceFormat")]
667 pub fn convert_format(&self, format: pixels::PixelFormat) -> Result<Surface<'static>, Error> {
668 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 #[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 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 #[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 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 #[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 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 #[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 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 #[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 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 }