1use std::marker::PhantomData;
2use std::mem;
3use std::ops::{Deref, DerefMut};
4use std::path::Path;
5use std::rc::Rc;
6
7use crate::get_error;
8use crate::pixels;
9use crate::rect::Rect;
10use crate::render::{BlendMode, Canvas};
11use crate::render::{Texture, TextureCreator, TextureValueError};
12use crate::rwops::RWops;
13use libc::c_int;
14use std::convert::TryFrom;
15use std::mem::transmute;
16use std::ptr;
17
18use crate::sys;
19
20pub struct SurfaceContext<'a> {
26 raw: *mut sys::SDL_Surface,
27 _marker: PhantomData<&'a ()>,
28}
29
30impl<'a> Drop for SurfaceContext<'a> {
31 #[inline]
32 #[doc(alias = "SDL_FreeSurface")]
33 fn drop(&mut self) {
34 unsafe {
35 sys::SDL_FreeSurface(self.raw);
36 }
37 }
38}
39
40pub struct Surface<'a> {
45 context: Rc<SurfaceContext<'a>>,
46}
47
48pub struct SurfaceRef {
53 _raw: (),
58}
59
60impl AsRef<SurfaceRef> for SurfaceRef {
61 fn as_ref(&self) -> &SurfaceRef {
62 self
63 }
64}
65
66#[test]
67fn test_surface_ref_size() {
68 assert_eq!(::std::mem::size_of::<SurfaceRef>(), 0);
70}
71
72impl<'a> Deref for Surface<'a> {
73 type Target = SurfaceRef;
74
75 #[inline]
76 fn deref(&self) -> &SurfaceRef {
77 self.as_ref()
78 }
79}
80
81impl<'a> DerefMut for Surface<'a> {
82 #[inline]
83 fn deref_mut(&mut self) -> &mut SurfaceRef {
84 self.as_mut()
85 }
86}
87
88impl<'a> AsRef<SurfaceRef> for Surface<'a> {
89 #[inline]
90 fn as_ref(&self) -> &SurfaceRef {
91 unsafe { &*(self.context.raw as *const SurfaceRef) }
92 }
93}
94
95impl<'a> AsMut<SurfaceRef> for Surface<'a> {
96 #[inline]
97 fn as_mut(&mut self) -> &mut SurfaceRef {
98 unsafe { &mut *(self.context.raw as *mut SurfaceRef) }
99 }
100}
101
102impl<'a> Surface<'a> {
103 pub unsafe fn from_ll<'b>(raw: *mut sys::SDL_Surface) -> Surface<'b> {
104 let context = SurfaceContext {
105 raw,
106 _marker: PhantomData,
107 };
108 Surface {
109 context: Rc::new(context),
110 }
111 }
112
113 pub fn new(
123 width: u32,
124 height: u32,
125 format: pixels::PixelFormatEnum,
126 ) -> Result<Surface<'static>, String> {
127 let masks = format.into_masks()?;
128 Surface::from_pixelmasks(width, height, &masks)
129 }
130
131 #[doc(alias = "SDL_CreateRGBSurface")]
142 pub fn from_pixelmasks(
143 width: u32,
144 height: u32,
145 masks: &pixels::PixelMasks,
146 ) -> Result<Surface<'static>, String> {
147 unsafe {
148 if width >= (1 << 31) || height >= (1 << 31) {
149 Err("Image is too large.".to_owned())
150 } else {
151 let raw = sys::SDL_CreateRGBSurface(
152 0,
153 width as c_int,
154 height as c_int,
155 masks.bpp as c_int,
156 masks.rmask,
157 masks.gmask,
158 masks.bmask,
159 masks.amask,
160 );
161
162 if raw.is_null() {
163 Err(get_error())
164 } else {
165 Ok(Surface::from_ll(raw))
166 }
167 }
168 }
169 }
170
171 pub fn from_data(
173 data: &'a mut [u8],
174 width: u32,
175 height: u32,
176 pitch: u32,
177 format: pixels::PixelFormatEnum,
178 ) -> Result<Surface<'a>, String> {
179 let masks = format.into_masks()?;
180 Surface::from_data_pixelmasks(data, width, height, pitch, &masks)
181 }
182
183 #[doc(alias = "SDL_CreateRGBSurfaceFrom")]
185 pub fn from_data_pixelmasks(
186 data: &'a mut [u8],
187 width: u32,
188 height: u32,
189 pitch: u32,
190 masks: &pixels::PixelMasks,
191 ) -> Result<Surface<'a>, String> {
192 unsafe {
193 if width >= (1 << 31) || height >= (1 << 31) {
194 Err("Image is too large.".to_owned())
195 } else if pitch >= (1 << 31) {
196 Err("Pitch is too large.".to_owned())
197 } else {
198 let raw = sys::SDL_CreateRGBSurfaceFrom(
199 data.as_mut_ptr() as *mut libc::c_void,
200 width as c_int,
201 height as c_int,
202 masks.bpp as c_int,
203 pitch as c_int,
204 masks.rmask,
205 masks.gmask,
206 masks.bmask,
207 masks.amask,
208 );
209
210 if raw.is_null() {
211 Err(get_error())
212 } else {
213 Ok(Surface::from_ll(raw))
214 }
215 }
216 }
217 }
218
219 #[cfg(not(feature = "unsafe_textures"))]
246 pub fn as_texture<'b, T>(
247 &self,
248 texture_creator: &'b TextureCreator<T>,
249 ) -> Result<Texture<'b>, TextureValueError> {
250 texture_creator.create_texture_from_surface(self)
251 }
252
253 #[cfg(feature = "unsafe_textures")]
280 pub fn as_texture<T>(
281 &self,
282 texture_creator: &TextureCreator<T>,
283 ) -> Result<Texture, TextureValueError> {
284 texture_creator.create_texture_from_surface(self)
285 }
286
287 #[doc(alias = "SDL_LoadBMP_RW")]
288 pub fn load_bmp_rw(rwops: &mut RWops) -> Result<Surface<'static>, String> {
289 let raw = unsafe { sys::SDL_LoadBMP_RW(rwops.raw(), 0) };
290
291 if raw.is_null() {
292 Err(get_error())
293 } else {
294 Ok(unsafe { Surface::from_ll(raw) })
295 }
296 }
297
298 pub fn load_bmp<P: AsRef<Path>>(path: P) -> Result<Surface<'static>, String> {
299 let mut file = RWops::from_file(path, "rb")?;
300 Surface::load_bmp_rw(&mut file)
301 }
302
303 pub fn into_canvas(self) -> Result<Canvas<Surface<'a>>, String> {
311 Canvas::from_surface(self)
312 }
313
314 pub fn context(&self) -> Rc<SurfaceContext<'a>> {
315 self.context.clone()
316 }
317}
318
319impl SurfaceRef {
320 #[inline]
321 pub unsafe fn from_ll<'a>(raw: *const sys::SDL_Surface) -> &'a SurfaceRef {
322 &*(raw as *const () as *const SurfaceRef)
323 }
324
325 #[inline]
326 pub unsafe fn from_ll_mut<'a>(raw: *mut sys::SDL_Surface) -> &'a mut SurfaceRef {
327 &mut *(raw as *mut () as *mut SurfaceRef)
328 }
329
330 #[inline]
331 #[allow(clippy::trivially_copy_pass_by_ref)]
334 #[doc(alias = "SDL_Surface")]
335 pub fn raw(&self) -> *mut sys::SDL_Surface {
336 self as *const SurfaceRef as *mut SurfaceRef as *mut () as *mut sys::SDL_Surface
337 }
338
339 #[inline]
340 fn raw_ref(&self) -> &sys::SDL_Surface {
341 unsafe { &*(self as *const _ as *const () as *const sys::SDL_Surface) }
342 }
343
344 pub fn width(&self) -> u32 {
345 self.raw_ref().w as u32
346 }
347
348 pub fn height(&self) -> u32 {
349 self.raw_ref().h as u32
350 }
351
352 pub fn pitch(&self) -> u32 {
353 self.raw_ref().pitch as u32
354 }
355
356 pub fn size(&self) -> (u32, u32) {
357 (self.width(), self.height())
358 }
359
360 pub fn rect(&self) -> Rect {
362 Rect::new(0, 0, self.width(), self.height())
363 }
364
365 pub fn pixel_format(&self) -> pixels::PixelFormat {
366 unsafe { pixels::PixelFormat::from_ll(self.raw_ref().format) }
367 }
368
369 pub fn pixel_format_enum(&self) -> pixels::PixelFormatEnum {
370 pixels::PixelFormatEnum::from(self.pixel_format())
371 }
372
373 #[doc(alias = "SDL_LockSurface")]
375 pub fn with_lock<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
376 unsafe {
377 if sys::SDL_LockSurface(self.raw()) != 0 {
378 panic!("could not lock surface");
379 }
380
381 let raw_pixels = self.raw_ref().pixels as *const u8;
382 let len = self.raw_ref().pitch as usize * (self.raw_ref().h as usize);
383 let pixels = ::std::slice::from_raw_parts(raw_pixels, len);
384 let rv = f(pixels);
385 sys::SDL_UnlockSurface(self.raw());
386 rv
387 }
388 }
389
390 #[doc(alias = "SDL_LockSurface")]
392 pub fn with_lock_mut<R, F: FnOnce(&mut [u8]) -> R>(&mut self, f: F) -> R {
393 unsafe {
394 if sys::SDL_LockSurface(self.raw()) != 0 {
395 panic!("could not lock surface");
396 }
397
398 let raw_pixels = self.raw_ref().pixels as *mut u8;
399 let len = self.raw_ref().pitch as usize * (self.raw_ref().h as usize);
400 let pixels = ::std::slice::from_raw_parts_mut(raw_pixels, len);
401 let rv = f(pixels);
402 sys::SDL_UnlockSurface(self.raw());
403 rv
404 }
405 }
406
407 pub fn without_lock(&self) -> Option<&[u8]> {
410 if self.must_lock() {
411 None
412 } else {
413 unsafe {
414 let raw_pixels = self.raw_ref().pixels as *const u8;
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
422 pub fn without_lock_mut(&mut self) -> Option<&mut [u8]> {
425 if self.must_lock() {
426 None
427 } else {
428 unsafe {
429 let raw_pixels = self.raw_ref().pixels as *mut u8;
430 let len = self.raw_ref().pitch as usize * (self.raw_ref().h as usize);
431
432 Some(::std::slice::from_raw_parts_mut(raw_pixels, len))
433 }
434 }
435 }
436
437 pub fn must_lock(&self) -> bool {
439 (self.raw_ref().flags & sys::SDL_RLEACCEL) != 0
441 }
442
443 #[doc(alias = "SDL_SaveBMP_RW")]
444 pub fn save_bmp_rw(&self, rwops: &mut RWops) -> Result<(), String> {
445 let ret = unsafe { sys::SDL_SaveBMP_RW(self.raw(), rwops.raw(), 0) };
446 if ret == 0 {
447 Ok(())
448 } else {
449 Err(get_error())
450 }
451 }
452
453 pub fn save_bmp<P: AsRef<Path>>(&self, path: P) -> Result<(), String> {
454 let mut file = RWops::from_file(path, "wb")?;
455 self.save_bmp_rw(&mut file)
456 }
457
458 #[doc(alias = "SDL_SetSurfacePalette")]
459 pub fn set_palette(&mut self, palette: &pixels::Palette) -> Result<(), String> {
460 let result = unsafe { sys::SDL_SetSurfacePalette(self.raw(), palette.raw()) };
461
462 match result {
463 0 => Ok(()),
464 _ => Err(get_error()),
465 }
466 }
467
468 #[allow(non_snake_case)]
469 #[doc(alias = "SDL_SetSurfaceRLE")]
470 pub fn enable_RLE(&mut self) {
471 let result = unsafe { sys::SDL_SetSurfaceRLE(self.raw(), 1) };
472
473 if result != 0 {
474 panic!("{}", get_error());
476 }
477 }
478
479 #[allow(non_snake_case)]
480 #[doc(alias = "SDL_SetSurfaceRLE")]
481 pub fn disable_RLE(&mut self) {
482 let result = unsafe { sys::SDL_SetSurfaceRLE(self.raw(), 0) };
483
484 if result != 0 {
485 panic!("{}", get_error());
487 }
488 }
489
490 #[doc(alias = "SDL_SetColorKey")]
491 pub fn set_color_key(&mut self, enable: bool, color: pixels::Color) -> Result<(), String> {
492 let key = color.to_u32(&self.pixel_format());
493 let result = unsafe { sys::SDL_SetColorKey(self.raw(), if enable { 1 } else { 0 }, key) };
494 if result == 0 {
495 Ok(())
496 } else {
497 Err(get_error())
498 }
499 }
500
501 #[doc(alias = "SDL_GetColorKey")]
503 pub fn color_key(&self) -> Result<pixels::Color, String> {
504 let mut key = 0;
505
506 let result = unsafe { sys::SDL_GetColorKey(self.raw(), &mut key) };
509
510 if result == 0 {
511 Ok(pixels::Color::from_u32(&self.pixel_format(), key))
512 } else {
513 Err(get_error())
514 }
515 }
516
517 #[doc(alias = "SDL_SetSurfaceColorMod")]
518 pub fn set_color_mod(&mut self, color: pixels::Color) {
519 let (r, g, b) = color.rgb();
520 let result = unsafe { sys::SDL_SetSurfaceColorMod(self.raw(), r, g, b) };
521
522 if result != 0 {
523 panic!("{}", get_error());
525 }
526 }
527
528 #[doc(alias = "SDL_GetSurfaceColorMod")]
529 pub fn color_mod(&self) -> pixels::Color {
530 let mut r = 0;
531 let mut g = 0;
532 let mut b = 0;
533
534 let result =
537 unsafe { sys::SDL_GetSurfaceColorMod(self.raw(), &mut r, &mut g, &mut b) == 0 };
538
539 if result {
540 pixels::Color::RGB(r, g, b)
541 } else {
542 panic!("{}", get_error())
544 }
545 }
546
547 #[doc(alias = "SDL_FillRect")]
548 pub fn fill_rect<R>(&mut self, rect: R, color: pixels::Color) -> Result<(), String>
549 where
550 R: Into<Option<Rect>>,
551 {
552 unsafe {
553 let rect = rect.into();
554 let rect_ptr = mem::transmute(rect.as_ref()); let format = self.pixel_format();
557 let result = sys::SDL_FillRect(self.raw(), rect_ptr, color.to_u32(&format));
558 match result {
559 0 => Ok(()),
560 _ => Err(get_error()),
561 }
562 }
563 }
564
565 #[allow(clippy::clone_on_copy)]
566 pub fn fill_rects(&mut self, rects: &[Rect], color: pixels::Color) -> Result<(), String> {
567 for rect in rects.iter() {
568 self.fill_rect(rect.clone(), color)?
569 }
570
571 Ok(())
572 }
573
574 #[doc(alias = "SDL_SetSurfaceAlphaMod")]
575 pub fn set_alpha_mod(&mut self, alpha: u8) {
576 let result = unsafe { sys::SDL_SetSurfaceAlphaMod(self.raw(), alpha) };
577
578 if result != 0 {
579 panic!("{}", get_error());
581 }
582 }
583
584 #[doc(alias = "SDL_GetSurfaceAlphaMod")]
585 pub fn alpha_mod(&self) -> u8 {
586 let mut alpha = 0;
587 let result = unsafe { sys::SDL_GetSurfaceAlphaMod(self.raw(), &mut alpha) };
588
589 match result {
590 0 => alpha,
591 _ => panic!("{}", get_error()),
593 }
594 }
595
596 #[doc(alias = "SDL_SetSurfaceBlendMode")]
598 pub fn set_blend_mode(&mut self, mode: BlendMode) -> Result<(), String> {
599 let result = unsafe { sys::SDL_SetSurfaceBlendMode(self.raw(), transmute(mode)) };
600
601 match result {
602 0 => Ok(()),
603 _ => Err(get_error()),
604 }
605 }
606
607 #[doc(alias = "SDL_GetSurfaceBlendMode")]
608 pub fn blend_mode(&self) -> BlendMode {
609 let mut mode = sys::SDL_BlendMode::SDL_BLENDMODE_NONE;
610 let result = unsafe { sys::SDL_GetSurfaceBlendMode(self.raw(), &mut mode) };
611
612 match result {
613 0 => BlendMode::try_from(mode as u32).unwrap(),
614 _ => panic!("{}", get_error()),
616 }
617 }
618
619 #[doc(alias = "SDL_SetClipRect")]
623 pub fn set_clip_rect<R>(&mut self, rect: R) -> bool
624 where
625 R: Into<Option<Rect>>,
626 {
627 let rect = rect.into();
628 unsafe {
629 sys::SDL_SetClipRect(
630 self.raw(),
631 match rect {
632 Some(rect) => rect.raw(),
633 None => ptr::null(),
634 },
635 ) == sys::SDL_bool::SDL_TRUE
636 }
637 }
638
639 #[doc(alias = "SDL_GetClipRect")]
643 pub fn clip_rect(&self) -> Option<Rect> {
644 let mut raw = mem::MaybeUninit::uninit();
645 unsafe { sys::SDL_GetClipRect(self.raw(), raw.as_mut_ptr()) };
646 let raw = unsafe { raw.assume_init() };
647
648 if raw.w == 0 || raw.h == 0 {
649 None
650 } else {
651 Some(Rect::from_ll(raw))
652 }
653 }
654
655 #[doc(alias = "SDL_ConvertSurface")]
657 pub fn convert(&self, format: &pixels::PixelFormat) -> Result<Surface<'static>, String> {
658 let surface_ptr = unsafe { sys::SDL_ConvertSurface(self.raw(), format.raw(), 0u32) };
660
661 if surface_ptr.is_null() {
662 Err(get_error())
663 } else {
664 unsafe { Ok(Surface::from_ll(surface_ptr)) }
665 }
666 }
667
668 #[doc(alias = "SDL_ConvertSurfaceFormat")]
670 pub fn convert_format(
671 &self,
672 format: pixels::PixelFormatEnum,
673 ) -> Result<Surface<'static>, String> {
674 let surface_ptr = unsafe { sys::SDL_ConvertSurfaceFormat(self.raw(), format as u32, 0u32) };
676
677 if surface_ptr.is_null() {
678 Err(get_error())
679 } else {
680 unsafe { Ok(Surface::from_ll(surface_ptr)) }
681 }
682 }
683
684 #[doc(alias = "SDL_UpperBlit")]
688 pub fn blit<R1, R2>(
689 &self,
690 src_rect: R1,
691 dst: &mut SurfaceRef,
692 dst_rect: R2,
693 ) -> Result<Option<Rect>, String>
694 where
695 R1: Into<Option<Rect>>,
696 R2: Into<Option<Rect>>,
697 {
698 let src_rect = src_rect.into();
699 let dst_rect = dst_rect.into();
700
701 unsafe {
702 let src_rect_ptr = src_rect.as_ref().map(|r| r.raw()).unwrap_or(ptr::null());
703
704 let mut dst_rect = dst_rect;
707 let dst_rect_ptr = dst_rect
708 .as_mut()
709 .map(|r| r.raw_mut())
710 .unwrap_or(ptr::null_mut());
711 let result = sys::SDL_UpperBlit(self.raw(), src_rect_ptr, dst.raw(), dst_rect_ptr);
712
713 if result == 0 {
714 Ok(dst_rect)
715 } else {
716 Err(get_error())
717 }
718 }
719 }
720
721 #[doc(alias = "SDL_LowerBlit")]
726 pub unsafe fn lower_blit<R1, R2>(
727 &self,
728 src_rect: R1,
729 dst: &mut SurfaceRef,
730 dst_rect: R2,
731 ) -> Result<(), String>
732 where
733 R1: Into<Option<Rect>>,
734 R2: Into<Option<Rect>>,
735 {
736 let src_rect = src_rect.into();
737 let dst_rect = dst_rect.into();
738
739 match {
740 let src_rect_ptr = src_rect.as_ref().map(|r| r.raw()).unwrap_or(ptr::null()) as *mut _;
742 let dst_rect_ptr = dst_rect.as_ref().map(|r| r.raw()).unwrap_or(ptr::null()) as *mut _;
743 sys::SDL_LowerBlit(self.raw(), src_rect_ptr, dst.raw(), dst_rect_ptr)
744 } {
745 0 => Ok(()),
746 _ => Err(get_error()),
747 }
748 }
749
750 #[doc(alias = "SDL_SoftStretchLinear")]
754 pub unsafe fn soft_stretch_linear<R1, R2>(
755 &self,
756 src_rect: R1,
757 dst: &mut SurfaceRef,
758 dst_rect: R2,
759 ) -> Result<Option<Rect>, String>
760 where
761 R1: Into<Option<Rect>>,
762 R2: Into<Option<Rect>>,
763 {
764 let src_rect = src_rect.into();
765 let dst_rect = dst_rect.into();
766
767 match {
768 let src_rect_ptr = src_rect.as_ref().map(|r| r.raw()).unwrap_or(ptr::null());
769
770 let mut dst_rect = dst_rect;
773 let dst_rect_ptr = dst_rect
774 .as_mut()
775 .map(|r| r.raw_mut())
776 .unwrap_or(ptr::null_mut());
777 sys::SDL_SoftStretchLinear(self.raw(), src_rect_ptr, dst.raw(), dst_rect_ptr)
778 } {
779 0 => Ok(dst_rect),
780 _ => Err(get_error()),
781 }
782 }
783
784 #[doc(alias = "SDL_UpperBlitScaled")]
788 pub fn blit_scaled<R1, R2>(
789 &self,
790 src_rect: R1,
791 dst: &mut SurfaceRef,
792 dst_rect: R2,
793 ) -> Result<Option<Rect>, String>
794 where
795 R1: Into<Option<Rect>>,
796 R2: Into<Option<Rect>>,
797 {
798 let src_rect = src_rect.into();
799 let dst_rect = dst_rect.into();
800
801 match unsafe {
802 let src_rect_ptr = src_rect.as_ref().map(|r| r.raw()).unwrap_or(ptr::null());
803
804 let mut dst_rect = dst_rect;
807 let dst_rect_ptr = dst_rect
808 .as_mut()
809 .map(|r| r.raw_mut())
810 .unwrap_or(ptr::null_mut());
811 sys::SDL_UpperBlitScaled(self.raw(), src_rect_ptr, dst.raw(), dst_rect_ptr)
812 } {
813 0 => Ok(dst_rect),
814 _ => Err(get_error()),
815 }
816 }
817
818 #[doc(alias = "SDL_LowerBlitScaled")]
823 pub unsafe fn lower_blit_scaled<R1, R2>(
824 &self,
825 src_rect: R1,
826 dst: &mut SurfaceRef,
827 dst_rect: R2,
828 ) -> Result<(), String>
829 where
830 R1: Into<Option<Rect>>,
831 R2: Into<Option<Rect>>,
832 {
833 match {
834 let src_rect_ptr = src_rect
836 .into()
837 .as_ref()
838 .map(|r| r.raw())
839 .unwrap_or(ptr::null()) as *mut _;
840 let dst_rect_ptr = dst_rect
841 .into()
842 .as_ref()
843 .map(|r| r.raw())
844 .unwrap_or(ptr::null()) as *mut _;
845 sys::SDL_LowerBlitScaled(self.raw(), src_rect_ptr, dst.raw(), dst_rect_ptr)
846 } {
847 0 => Ok(()),
848 _ => Err(get_error()),
849 }
850 }
851
852 }