@@ -483,7 +483,13 @@ surface_init(pgSurfaceObject *self, PyObject *args, PyObject *kwds)
483483 int bpp ;
484484 Uint32 Rmask , Gmask , Bmask , Amask ;
485485 SDL_Surface * surface ;
486+
487+ #if SDL_VERSION_ATLEAST (3 , 0 , 0 )
488+ PG_PixelFormatEnum format = SDL_PIXELFORMAT_UNKNOWN ;
489+ #else
486490 SDL_PixelFormat default_format ;
491+ default_format .palette = NULL ;
492+ #endif
487493
488494 char * kwids [] = {"size" , "flags" , "depth" , "masks" , NULL };
489495 if (!PyArg_ParseTupleAndKeywords (args , kwds , "O|iOO" , kwids , & size , & flags ,
@@ -510,10 +516,172 @@ surface_init(pgSurfaceObject *self, PyObject *args, PyObject *kwds)
510516 return -1 ;
511517 }
512518
513- default_format .palette = NULL ;
514-
515519 surface_cleanup (self );
516520
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
517685 if (depth && masks ) { /* all info supplied, most errorchecking
518686 * needed */
519687 if (pgSurface_Check (depth )) {
@@ -614,11 +782,7 @@ surface_init(pgSurfaceObject *self, PyObject *args, PyObject *kwds)
614782 }
615783 else {
616784 pix = & default_format ;
617- #if SDL_VERSION_ATLEAST (3 , 0 , 0 )
618- pix -> bits_per_pixel = 32 ;
619- #else
620785 pix -> BitsPerPixel = 32 ;
621- #endif
622786 pix -> Amask = 0 ;
623787 pix -> Rmask = 0xFF0000 ;
624788 pix -> Gmask = 0xFF00 ;
@@ -702,6 +866,7 @@ surface_init(pgSurfaceObject *self, PyObject *args, PyObject *kwds)
702866 return -1 ;
703867 }
704868 }
869+ #endif
705870
706871 if (surface ) {
707872 self -> surf = surface ;
@@ -1495,6 +1660,168 @@ surf_convert(pgSurfaceObject *self, PyObject *args)
14951660
14961661 pgSurface_Prep (self );
14971662
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
14981825 if ((has_colorkey = SDL_HasColorKey (surf ))) {
14991826 SDL_GetColorKey (surf , & colorkey );
15001827 if (SDL_ISPIXELFORMAT_ALPHA (PG_SURF_FORMATENUM (surf ))) {
@@ -1607,13 +1934,8 @@ surf_convert(pgSurfaceObject *self, PyObject *args)
16071934 PyExc_ValueError ,
16081935 "invalid argument specifying new format to convert to" );
16091936 }
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
16141937 format .BitsPerPixel = (Uint8 )bpp ;
16151938 format .BytesPerPixel = (bpp + 7 ) / 8 ;
1616- #endif
16171939 if (PG_FORMAT_BitsPerPixel ((& format )) > 8 ) {
16181940 /* Allow a 8 bit source surface with an empty palette to be
16191941 * converted to a format without a palette (pygame-ce issue
@@ -1662,6 +1984,7 @@ surf_convert(pgSurfaceObject *self, PyObject *args)
16621984 return NULL ;
16631985 }
16641986 }
1987+ #endif
16651988
16661989 pgSurface_Unprep (self );
16671990
0 commit comments