@@ -483,7 +483,13 @@ surface_init(pgSurfaceObject *self, PyObject *args, PyObject *kwds)
483
483
int bpp ;
484
484
Uint32 Rmask , Gmask , Bmask , Amask ;
485
485
SDL_Surface * surface ;
486
+
487
+ #if SDL_VERSION_ATLEAST (3 , 0 , 0 )
488
+ PG_PixelFormatEnum format = SDL_PIXELFORMAT_UNKNOWN ;
489
+ #else
486
490
SDL_PixelFormat default_format ;
491
+ default_format .palette = NULL ;
492
+ #endif
487
493
488
494
char * kwids [] = {"size" , "flags" , "depth" , "masks" , NULL };
489
495
if (!PyArg_ParseTupleAndKeywords (args , kwds , "O|iOO" , kwids , & size , & flags ,
@@ -510,10 +516,172 @@ surface_init(pgSurfaceObject *self, PyObject *args, PyObject *kwds)
510
516
return -1 ;
511
517
}
512
518
513
- default_format .palette = NULL ;
514
-
515
519
surface_cleanup (self );
516
520
521
+ #if SDL_VERSION_ATLEAST (3 , 0 , 0 )
522
+ if (depth && masks ) { /* all info supplied, most errorchecking
523
+ * needed */
524
+ if (pgSurface_Check (depth )) {
525
+ PyErr_SetString (PyExc_ValueError ,
526
+ "cannot pass surface for depth and color masks" );
527
+ return -1 ;
528
+ }
529
+ if (!pg_IntFromObj (depth , & bpp )) {
530
+ PyErr_SetString (PyExc_ValueError ,
531
+ "invalid bits per pixel depth argument" );
532
+ return -1 ;
533
+ }
534
+ if (!PySequence_Check (masks ) || PySequence_Length (masks ) != 4 ) {
535
+ PyErr_SetString (PyExc_ValueError ,
536
+ "masks argument must be sequence of four numbers" );
537
+ return -1 ;
538
+ }
539
+ if (!pg_UintFromObjIndex (masks , 0 , & Rmask ) ||
540
+ !pg_UintFromObjIndex (masks , 1 , & Gmask ) ||
541
+ !pg_UintFromObjIndex (masks , 2 , & Bmask ) ||
542
+ !pg_UintFromObjIndex (masks , 3 , & Amask )) {
543
+ PyErr_SetString (PyExc_ValueError ,
544
+ "invalid mask values in masks sequence" );
545
+ return -1 ;
546
+ }
547
+
548
+ format = SDL_MasksToPixelFormatEnum (bpp , Rmask , Gmask , Bmask , Amask );
549
+ }
550
+ else if (depth && PyNumber_Check (depth )) { /* use default masks */
551
+ if (!pg_IntFromObj (depth , & bpp )) {
552
+ PyErr_SetString (PyExc_ValueError ,
553
+ "invalid bits per pixel depth argument" );
554
+ return -1 ;
555
+ }
556
+ if (flags & PGS_SRCALPHA ) {
557
+ switch (bpp ) {
558
+ case 16 :
559
+ format = SDL_PIXELFORMAT_ARGB4444 ;
560
+ break ;
561
+ case 32 :
562
+ format = SDL_PIXELFORMAT_ARGB8888 ;
563
+ break ;
564
+ default :
565
+ PyErr_SetString (
566
+ PyExc_ValueError ,
567
+ "no standard masks exist for given bitdepth with "
568
+ "alpha" );
569
+ return -1 ;
570
+ }
571
+ }
572
+ else {
573
+ switch (bpp ) {
574
+ case 8 :
575
+ format = SDL_PIXELFORMAT_INDEX8 ;
576
+ break ;
577
+ case 12 :
578
+ format = SDL_PIXELFORMAT_XRGB4444 ;
579
+ break ;
580
+ case 15 :
581
+ format = SDL_PIXELFORMAT_XRGB1555 ;
582
+ break ;
583
+ case 16 :
584
+ format = SDL_PIXELFORMAT_RGB565 ;
585
+ break ;
586
+ case 24 :
587
+ #if SDL_BYTEORDER == SDL_BIG_ENDIAN
588
+ format = SDL_PIXELFORMAT_RGB24 ;
589
+ #else
590
+ format = SDL_PIXELFORMAT_BGR24 ;
591
+ #endif
592
+ break ;
593
+ case 32 :
594
+ format = SDL_PIXELFORMAT_XRGB8888 ;
595
+ break ;
596
+ default :
597
+ PyErr_SetString (PyExc_ValueError ,
598
+ "nonstandard bit depth given" );
599
+ return -1 ;
600
+ }
601
+ }
602
+ }
603
+ else { /* no depth or surface */
604
+ if (depth && pgSurface_Check (depth )) {
605
+ format = PG_SURF_FORMATENUM (((pgSurfaceObject * )depth )-> surf );
606
+ }
607
+ else if (pg_GetDefaultWindowSurface ()) {
608
+ format = PG_SURF_FORMATENUM (
609
+ pgSurface_AsSurface (pg_GetDefaultWindowSurface ()));
610
+ }
611
+ else {
612
+ format = SDL_PIXELFORMAT_XRGB8888 ;
613
+ }
614
+
615
+ if (flags & PGS_SRCALPHA ) {
616
+ switch (SDL_BITSPERPIXEL (format )) {
617
+ case 16 :
618
+ format = SDL_PIXELFORMAT_ARGB4444 ;
619
+ break ;
620
+ case 24 :
621
+ // we automatically step up to 32 if video is 24, fall
622
+ // through to case below
623
+ case 32 :
624
+ format = SDL_PIXELFORMAT_ARGB8888 ;
625
+ break ;
626
+ default :
627
+ PyErr_SetString (
628
+ PyExc_ValueError ,
629
+ "no standard masks exist for given bitdepth with "
630
+ "alpha" );
631
+ return -1 ;
632
+ }
633
+ }
634
+ }
635
+
636
+ if (format == SDL_PIXELFORMAT_UNKNOWN ) {
637
+ PyErr_SetString (PyExc_ValueError , "Invalid mask values" );
638
+ return -1 ;
639
+ }
640
+
641
+ surface = PG_CreateSurface (width , height , format );
642
+ if (!surface ) {
643
+ PyErr_SetString (pgExc_SDLError , SDL_GetError ());
644
+ return -1 ;
645
+ }
646
+
647
+ if (!(flags & PGS_SRCALPHA )) {
648
+ /* We ignore the error if any. */
649
+ SDL_SetSurfaceBlendMode (surface , SDL_BLENDMODE_NONE );
650
+
651
+ /* When the display format has a full alpha channel (macOS right now),
652
+ * Surfaces may be created with an unreqested alpha channel, which
653
+ * could cause issues.
654
+ * pygame Surfaces are supposed to be (0, 0, 0, 255) by default.
655
+ * This is a simple fix to fill it with (0, 0, 0, 255) if necessary.
656
+ * See Github issue:
657
+ * https://github.com/pygame-community/pygame-ce/issues/796
658
+ */
659
+ PG_PixelFormat * surf_format ;
660
+ SDL_Palette * surf_palette ;
661
+ if (!PG_GetSurfaceDetails (surface , & surf_format , & surf_palette )) {
662
+ PyErr_SetString (pgExc_SDLError , SDL_GetError ());
663
+ SDL_FreeSurface (surface );
664
+ return -1 ;
665
+ }
666
+
667
+ if (surf_format -> Amask != 0 ) {
668
+ SDL_FillRect (surface , NULL ,
669
+ PG_MapRGBA (surf_format , surf_palette , 0 , 0 , 0 , 255 ));
670
+ }
671
+ }
672
+
673
+ if (SDL_ISPIXELFORMAT_INDEXED (PG_SURF_FORMATENUM (surface ))) {
674
+ /* Give the surface something other than an all white palette.
675
+ * */
676
+ SDL_Palette * surf_palette = SDL_CreateSurfacePalette (surface );
677
+ if (SDL_SetPaletteColors (surf_palette , default_palette_colors , 0 ,
678
+ default_palette_size - 1 ) != 0 ) {
679
+ PyErr_SetString (pgExc_SDLError , SDL_GetError ());
680
+ SDL_FreeSurface (surface );
681
+ return -1 ;
682
+ }
683
+ }
684
+ #else
517
685
if (depth && masks ) { /* all info supplied, most errorchecking
518
686
* needed */
519
687
if (pgSurface_Check (depth )) {
@@ -614,11 +782,7 @@ surface_init(pgSurfaceObject *self, PyObject *args, PyObject *kwds)
614
782
}
615
783
else {
616
784
pix = & default_format ;
617
- #if SDL_VERSION_ATLEAST (3 , 0 , 0 )
618
- pix -> bits_per_pixel = 32 ;
619
- #else
620
785
pix -> BitsPerPixel = 32 ;
621
- #endif
622
786
pix -> Amask = 0 ;
623
787
pix -> Rmask = 0xFF0000 ;
624
788
pix -> Gmask = 0xFF00 ;
@@ -702,6 +866,7 @@ surface_init(pgSurfaceObject *self, PyObject *args, PyObject *kwds)
702
866
return -1 ;
703
867
}
704
868
}
869
+ #endif
705
870
706
871
if (surface ) {
707
872
self -> surf = surface ;
@@ -1495,6 +1660,168 @@ surf_convert(pgSurfaceObject *self, PyObject *args)
1495
1660
1496
1661
pgSurface_Prep (self );
1497
1662
1663
+ #if SDL_VERSION_ATLEAST (3 , 0 , 0 )
1664
+ if ((has_colorkey = SDL_HasColorKey (surf ))) {
1665
+ PG_PixelFormat * surf_format ;
1666
+ SDL_Palette * surf_palette ;
1667
+ if (!PG_GetSurfaceDetails (surf , & surf_format , & surf_palette )) {
1668
+ return RAISE (pgExc_SDLError , SDL_GetError ());
1669
+ }
1670
+
1671
+ SDL_GetColorKey (surf , & colorkey );
1672
+ if (SDL_ISPIXELFORMAT_ALPHA (PG_SURF_FORMATENUM (surf ))) {
1673
+ PG_GetRGBA (colorkey , surf_format , surf_palette , & key_r , & key_g ,
1674
+ & key_b , & key_a );
1675
+ }
1676
+ else {
1677
+ PG_GetRGB (colorkey , surf_format , surf_palette , & key_r , & key_g ,
1678
+ & key_b );
1679
+ }
1680
+ }
1681
+
1682
+ if (argobject ) {
1683
+ if (pgSurface_Check (argobject )) {
1684
+ src = pgSurface_AsSurface (argobject );
1685
+ newsurf = PG_ConvertSurface (surf , src -> format );
1686
+ }
1687
+ else {
1688
+ /* will be updated later, initialize to make static analyzer happy
1689
+ */
1690
+ int bpp = 0 ;
1691
+ SDL_Palette * palette = NULL ;
1692
+ PG_PixelFormatEnum format_enum = SDL_PIXELFORMAT_UNKNOWN ;
1693
+
1694
+ // PATH 1 = from bpp
1695
+ if (pg_IntFromObj (argobject , & bpp )) {
1696
+ if (flags != UINT32_MAX && flags & PGS_SRCALPHA ) {
1697
+ switch (bpp ) {
1698
+ case 16 :
1699
+ format_enum = SDL_PIXELFORMAT_ARGB4444 ;
1700
+ break ;
1701
+ case 32 :
1702
+ format_enum = SDL_PIXELFORMAT_ARGB8888 ;
1703
+ break ;
1704
+ default :
1705
+ return RAISE (PyExc_ValueError ,
1706
+ "no standard masks exist for given "
1707
+ "bitdepth with alpha" );
1708
+ }
1709
+ }
1710
+ else {
1711
+ switch (bpp ) {
1712
+ case 8 :
1713
+ format_enum = SDL_PIXELFORMAT_INDEX8 ;
1714
+ break ;
1715
+ case 12 :
1716
+ format_enum = SDL_PIXELFORMAT_XRGB4444 ;
1717
+ break ;
1718
+ case 15 :
1719
+ format_enum = SDL_PIXELFORMAT_XRGB1555 ;
1720
+ break ;
1721
+ case 16 :
1722
+ format_enum = SDL_PIXELFORMAT_RGB565 ;
1723
+ break ;
1724
+ case 24 :
1725
+ #if SDL_BYTEORDER == SDL_BIG_ENDIAN
1726
+ format_enum = SDL_PIXELFORMAT_RGB24 ;
1727
+ #else
1728
+ format_enum = SDL_PIXELFORMAT_BGR24 ;
1729
+ #endif
1730
+ break ;
1731
+ case 32 :
1732
+ format_enum = SDL_PIXELFORMAT_XRGB8888 ;
1733
+ break ;
1734
+ default :
1735
+ return RAISE (PyExc_ValueError ,
1736
+ "nonstandard bit depth given" );
1737
+ }
1738
+ }
1739
+ }
1740
+ // PATH 2 = from masks only
1741
+ else if (PySequence_Check (argobject ) &&
1742
+ PySequence_Size (argobject ) == 4 ) {
1743
+ Uint32 Rmask , Gmask , Bmask , Amask ;
1744
+
1745
+ if (!pg_UintFromObjIndex (argobject , 0 , & Rmask ) ||
1746
+ !pg_UintFromObjIndex (argobject , 1 , & Gmask ) ||
1747
+ !pg_UintFromObjIndex (argobject , 2 , & Bmask ) ||
1748
+ !pg_UintFromObjIndex (argobject , 3 , & Amask )) {
1749
+ pgSurface_Unprep (self );
1750
+ return RAISE (PyExc_ValueError ,
1751
+ "invalid color masks given" );
1752
+ }
1753
+ Uint32 mask = Rmask | Gmask | Bmask | Amask ;
1754
+
1755
+ // This code shocked me. -Starbuck, Mar. 2025
1756
+ // Like what if you have a hole in the mask?
1757
+ // Like a blank alpha mask first-- it would just terminate
1758
+ // the whole loop right?
1759
+ // I think this whole code path should be deprecated.
1760
+ for (bpp = 0 ; bpp < 32 ; ++ bpp ) {
1761
+ if (!(mask >> bpp )) {
1762
+ break ;
1763
+ }
1764
+ }
1765
+
1766
+ format_enum = SDL_MasksToPixelFormatEnum (bpp , Rmask , Gmask ,
1767
+ Bmask , Amask );
1768
+ }
1769
+ else {
1770
+ pgSurface_Unprep (self );
1771
+ return RAISE (
1772
+ PyExc_ValueError ,
1773
+ "invalid argument specifying new format to convert to" );
1774
+ }
1775
+
1776
+ // If the destination format is indexed, provide a new palette or
1777
+ // copy over existing palette.
1778
+ if (SDL_ISPIXELFORMAT_INDEXED (format_enum )) {
1779
+ if (SDL_ISPIXELFORMAT_INDEXED (PG_SURF_FORMATENUM (surf ))) {
1780
+ palette = PG_GetSurfacePalette (surf );
1781
+ }
1782
+ else {
1783
+ /* Give the surface something other than an all white
1784
+ * palette.
1785
+ */
1786
+ palette = SDL_AllocPalette (default_palette_size );
1787
+ SDL_SetPaletteColors (palette , default_palette_colors , 0 ,
1788
+ default_palette_size );
1789
+ }
1790
+ }
1791
+
1792
+ newsurf = SDL_ConvertSurfaceAndColorspace (
1793
+ surf , format_enum , palette , SDL_GetSurfaceColorspace (surf ), 0 );
1794
+
1795
+ // In this scenario, we allocated the palette, so we also need
1796
+ // to remove our reference to it.
1797
+ if (SDL_ISPIXELFORMAT_INDEXED (format_enum ) &&
1798
+ !SDL_ISPIXELFORMAT_INDEXED (PG_SURF_FORMATENUM (surf ))) {
1799
+ SDL_FreePalette (palette );
1800
+ }
1801
+
1802
+ SDL_SetSurfaceBlendMode (newsurf , SDL_BLENDMODE_NONE );
1803
+ }
1804
+ }
1805
+ else {
1806
+ newsurf = pg_DisplayFormat (surf );
1807
+ if (newsurf ) {
1808
+ SDL_SetSurfaceBlendMode (newsurf , SDL_BLENDMODE_NONE );
1809
+ }
1810
+ }
1811
+
1812
+ if (newsurf == NULL ) {
1813
+ return RAISE (pgExc_SDLError , SDL_GetError ());
1814
+ }
1815
+
1816
+ if (has_colorkey ) {
1817
+ colorkey = SDL_MapSurfaceRGBA (newsurf , key_r , key_g , key_b , key_a );
1818
+ if (SDL_SetColorKey (newsurf , SDL_TRUE , colorkey ) != 0 ) {
1819
+ PyErr_SetString (pgExc_SDLError , SDL_GetError ());
1820
+ SDL_FreeSurface (newsurf );
1821
+ return NULL ;
1822
+ }
1823
+ }
1824
+ #else
1498
1825
if ((has_colorkey = SDL_HasColorKey (surf ))) {
1499
1826
SDL_GetColorKey (surf , & colorkey );
1500
1827
if (SDL_ISPIXELFORMAT_ALPHA (PG_SURF_FORMATENUM (surf ))) {
@@ -1607,13 +1934,8 @@ surf_convert(pgSurfaceObject *self, PyObject *args)
1607
1934
PyExc_ValueError ,
1608
1935
"invalid argument specifying new format to convert to" );
1609
1936
}
1610
- #if SDL_VERSION_ATLEAST (3 , 0 , 0 )
1611
- format .bits_per_pixel = (Uint8 )bpp ;
1612
- format .bytes_per_pixel = (bpp + 7 ) / 8 ;
1613
- #else
1614
1937
format .BitsPerPixel = (Uint8 )bpp ;
1615
1938
format .BytesPerPixel = (bpp + 7 ) / 8 ;
1616
- #endif
1617
1939
if (PG_FORMAT_BitsPerPixel ((& format )) > 8 ) {
1618
1940
/* Allow a 8 bit source surface with an empty palette to be
1619
1941
* converted to a format without a palette (pygame-ce issue
@@ -1662,6 +1984,7 @@ surf_convert(pgSurfaceObject *self, PyObject *args)
1662
1984
return NULL ;
1663
1985
}
1664
1986
}
1987
+ #endif
1665
1988
1666
1989
pgSurface_Unprep (self );
1667
1990
0 commit comments