Skip to content

sprites now have limited support for Texture and Renderer #3035

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions buildconfig/stubs/pygame/sprite.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ from typing import (
SupportsFloat,
TypeVar,
Union,
overload,
)

# use typing_extensions for compatibility with older Python versions
Expand All @@ -22,6 +23,7 @@ if sys.version_info >= (3, 11):
else:
from typing_extensions import Self

from pygame._sdl2.video import Renderer, Texture
from pygame.mask import Mask
from pygame.rect import FRect, Rect
from pygame.surface import Surface
Expand All @@ -37,7 +39,7 @@ class _HasRect(Protocol):
# image in addition to rect
class _HasImageAndRect(_HasRect, Protocol):
@property
def image(self) -> Optional[Surface]: ...
def image(self) -> Optional[Union[Surface, Texture]]: ...

# mask in addition to rect
class _HasMaskAndRect(_HasRect, Protocol):
Expand All @@ -54,9 +56,9 @@ _Group = AbstractGroup[Any]
# and allows the use of any class with the required attributes and methods
class _SupportsSprite(_HasImageAndRect, Protocol):
@property
def image(self) -> Optional[Surface]: ...
def image(self) -> Optional[Union[Surface, Texture]]: ...
@image.setter
def image(self, value: Optional[Surface]) -> None: ...
def image(self, value: Optional[Union[Surface, Texture]]) -> None: ...
@property
def rect(self) -> Optional[Union[FRect, Rect]]: ...
@rect.setter
Expand Down Expand Up @@ -87,9 +89,9 @@ class _SupportsDirtySprite(_SupportsSprite, Protocol):
# concrete sprite implementation class
class Sprite(_SupportsSprite):
@property
def image(self) -> Optional[Surface]: ...
def image(self) -> Optional[Union[Surface, Texture]]: ...
@image.setter
def image(self, value: Optional[Surface]) -> None: ...
def image(self, value: Optional[Union[Surface, Texture]]) -> None: ...
@property
def rect(self) -> Optional[Union[FRect, Rect]]: ...
@rect.setter
Expand Down Expand Up @@ -146,7 +148,10 @@ class AbstractGroup(Generic[_TSprite]):
def has(self, *sprites: _SpriteOrIterable[_TSprite]) -> bool: ...
def update(self, *args: Any, **kwargs: Any) -> None: ...
def draw(
self, surface: Surface, bgd: Optional[Surface] = None, special_flags: int = 0
self,
surface: Union[Surface, Renderer],
bgd: Optional[Surface] = None,
special_flags: int = 0,
) -> list[Union[FRect, Rect]]: ...
def clear(
self,
Expand Down Expand Up @@ -192,7 +197,7 @@ class LayeredUpdates(AbstractGroup[_TSprite]):
class LayeredDirty(LayeredUpdates[_TDirtySprite]):
def draw(
self,
surface: Surface,
surface: Union[Surface, Renderer],
bgd: Optional[Surface] = None,
special_flags: Optional[int] = None,
) -> list[Union[FRect, Rect]]: ...
Expand Down
31 changes: 27 additions & 4 deletions docs/reST/ref/sprite.rst
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,17 @@ extend those when you add a Sprite or Group class.

Sprites are not thread safe. So lock them yourself if using threads.

.. note:: As of version 2.5.6, you can use ``Sprite`` and ``Group`` with ``Renderer``
and ``Texture`` from ``_sdl2.video``, at least partially. Instead of ``Sprite.image``
needing to be a ``Surface``, it needs to be a ``Texture`` to do this. This behavior
is still very experimental, so please report any weirdness to the developers as an
issue on the ``pygame-ce`` github repository. Also note that ``LayeredDirty.draw``
does not currently work in this manner. Other group types might work, but have not
been thorougly tested.

.. versionchanged:: 2.5.6 ``Sprite`` and ``Group``
have some compatibility with ``_sdl2.video``

.. class:: Sprite

| :sl:`Simple base class for visible game objects.`
Expand Down Expand Up @@ -291,17 +302,29 @@ Sprites are not thread safe. So lock them yourself if using threads.
.. method:: draw

| :sl:`blit the Sprite images`
| :sg:`draw(Surface, bgd=None, special_flags=0) -> list[Rect]`
| :sg:`draw(Surface, bgd=None, special_flags=0) -> list[Union[Rect, FRect]]`
| :sg:`draw(Renderer, bgd=None, special_flags=0) -> list[Union[Rect, FRect]]`

Draws the contained Sprites to the Surface or _sdl2.video.Renderer argument.

Surface
-------
This uses the ``Sprite.image`` attribute for the source surface, and ``Sprite.rect``
for the position.

Renderer
--------
This uses the ``Sprite.image`` attribute for the source Texture, and ``Sprite.rect``
for the position.

Draws the contained Sprites to the Surface argument. This uses the
``Sprite.image`` attribute for the source surface, and ``Sprite.rect``
for the position. ``special_flags`` is passed to ``Surface.blit()``.
``special_flags`` is passed to ``Surface.blit()``.
``bgd`` is unused in this method but ``LayeredDirty.draw()`` uses
it.

The Group keeps sprites in the order they were added, they will be drawn in this order.

.. versionchanged:: 2.5.4 Added the ``bgd`` and ``special_flags`` arguments
.. versionchanged:: 2.5.6 Now accepts a renderer for use with ``_sdl2.video`` and ``Sprite.rect`` supports ``FRect``s

.. ## Group.draw ##

Expand Down
10 changes: 9 additions & 1 deletion src_c/cython/pygame/_sdl2/video.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,14 @@ cdef extern from "pygame.h" nogil:
cdef SDL_Rect r
cdef object weakreflist

ctypedef class pygame.rect.FRect [object pgFRectObject]:
cdef SDL_FRect r
cdef object weakreflist

ctypedef fused RectLike:
Rect
FRect

ctypedef class pygame.window.Window [object pgWindowObject]:
cdef SDL_Window *_win
cdef SDL_bool _is_borrowed
Expand Down Expand Up @@ -465,7 +473,7 @@ cdef class Renderer:
cdef int _is_borrowed

cpdef object get_viewport(self)
cpdef object blit(self, object source, Rect dest=*, Rect area=*, int special_flags=*)
cpdef object blit(self, object source, RectLike dest=*, RectLike area=*, int special_flags=*)

cdef class Texture:
cdef SDL_Texture* _tex
Expand Down
2 changes: 1 addition & 1 deletion src_c/cython/pygame/_sdl2/video.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -998,7 +998,7 @@ cdef class Renderer:
else:
raise TypeError('target must be a Texture or None')

cpdef object blit(self, object source, Rect dest=None, Rect area=None, int special_flags=0):
cpdef object blit(self, object source, RectLike dest=None, RectLike area=None, int special_flags=0):
"""Draw textures using a Surface-like API

For compatibility purposes. Draws :class:`Texture` objects onto the
Expand Down
2 changes: 1 addition & 1 deletion src_c/doc/sprite_doc.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#define DOC_SPRITE_GROUP_REMOVE "remove(*sprites) -> None\nremove Sprites from the Group"
#define DOC_SPRITE_GROUP_HAS "has(*sprites) -> bool\ntest if a Group contains Sprites"
#define DOC_SPRITE_GROUP_UPDATE "update(*args, **kwargs) -> None\ncall the update method on contained Sprites"
#define DOC_SPRITE_GROUP_DRAW "draw(Surface, bgd=None, special_flags=0) -> list[Rect]\nblit the Sprite images"
#define DOC_SPRITE_GROUP_DRAW "draw(Surface, bgd=None, special_flags=0) -> list[Union[Rect, FRect]]\ndraw(Renderer, bgd=None, special_flags=0) -> list[Union[Rect, FRect]]\nblit the Sprite images"
#define DOC_SPRITE_GROUP_CLEAR "clear(Surface_dest, background) -> None\ndraw a background over the Sprites"
#define DOC_SPRITE_GROUP_EMPTY "empty() -> None\nremove all Sprites"
#define DOC_SPRITE_RENDERUPDATES "RenderUpdates(*sprites) -> RenderUpdates\nGroup sub-class that tracks dirty updates."
Expand Down
19 changes: 19 additions & 0 deletions test/sprite_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import pygame
from pygame import sprite
from pygame._sdl2.video import Renderer, Texture

################################# MODULE LEVEL #################################

Expand Down Expand Up @@ -585,6 +586,24 @@ def test_draw(self):
self.assertEqual(self.ag.spritedict[self.s1], pygame.Rect(0, 0, 10, 10))
self.assertEqual(self.ag.spritedict[self.s2], pygame.Rect(10, 0, 10, 10))

def test_draw_sdl2(self):
win = pygame.Window()
group = sprite.Group()
renderer = Renderer(win)
renderer.draw_color = "blue"
gpusprite = sprite.Sprite(group)

gpusprite.image = Texture(renderer, (50, 50), target=True)
renderer.target = gpusprite.image
renderer.clear()
gpusprite.rect = gpusprite.image.get_rect()

renderer.target = None
group.draw(renderer)
self.assertEqual(group.spritedict[gpusprite], pygame.Rect(0, 0, 50, 50))

renderer.present()

def test_empty(self):
self.ag.empty()
self.assertFalse(self.s1 in self.ag)
Expand Down
Loading