11from __future__ import annotations
22
3+ import enum
34from typing import Any , Optional , Tuple
45
56import numpy as np
1011from tcod .sdl import _check , _check_p
1112
1213
14+ class TextureAccess (enum .IntEnum ):
15+ """Determines how a texture is expected to be used."""
16+
17+ STATIC = lib .SDL_TEXTUREACCESS_STATIC or 0
18+ """Texture rarely changes."""
19+ STREAMING = lib .SDL_TEXTUREACCESS_STREAMING or 0
20+ """Texture frequently changes."""
21+ TARGET = lib .SDL_TEXTUREACCESS_TARGET or 0
22+ """Texture will be used as a render target."""
23+
24+
1325class Texture :
1426 def __init__ (self , sdl_texture_p : Any , sdl_renderer_p : Any = None ) -> None :
1527 self .p = sdl_texture_p
@@ -56,7 +68,9 @@ def height(self) -> int:
5668 @property
5769 def alpha_mod (self ) -> int :
5870 """Texture alpha modulate value, can be set to: 0 - 255."""
59- return int (lib .SDL_GetTextureAlphaMod (self .p ))
71+ out = ffi .new ("uint8_t*" )
72+ _check (lib .SDL_GetTextureAlphaMod (self .p , out ))
73+ return int (out [0 ])
6074
6175 @alpha_mod .setter
6276 def alpha_mod (self , value : int ) -> None :
@@ -65,7 +79,9 @@ def alpha_mod(self, value: int) -> None:
6579 @property
6680 def blend_mode (self ) -> int :
6781 """Texture blend mode, can be set."""
68- return int (lib .SDL_GetTextureBlendMode (self .p ))
82+ out = ffi .new ("SDL_BlendMode*" )
83+ _check (lib .SDL_GetTextureBlendMode (self .p , out ))
84+ return int (out [0 ])
6985
7086 @blend_mode .setter
7187 def blend_mode (self , value : int ) -> None :
@@ -101,6 +117,8 @@ class Renderer:
101117 def __init__ (self , sdl_renderer_p : Any ) -> None :
102118 if ffi .typeof (sdl_renderer_p ) is not ffi .typeof ("struct SDL_Renderer*" ):
103119 raise TypeError (f"Expected a { ffi .typeof ('struct SDL_Window*' )} type (was { ffi .typeof (sdl_renderer_p )} )." )
120+ if not sdl_renderer_p :
121+ raise TypeError ("C pointer must not be null." )
104122 self .p = sdl_renderer_p
105123
106124 def __eq__ (self , other : Any ) -> bool :
@@ -124,34 +142,49 @@ def present(self) -> None:
124142 """Present the currently rendered image to the screen."""
125143 lib .SDL_RenderPresent (self .p )
126144
145+ def set_render_target (self , texture : Texture ) -> _RestoreTargetContext :
146+ """Change the render target to `texture`, returns a context that will restore the original target when exited."""
147+ restore = _RestoreTargetContext (self )
148+ _check (lib .SDL_SetRenderTarget (self .p , texture .p ))
149+ return restore
150+
127151 def new_texture (
128152 self , width : int , height : int , * , format : Optional [int ] = None , access : Optional [int ] = None
129153 ) -> Texture :
130- """Allocate and return a new Texture for this renderer."""
154+ """Allocate and return a new Texture for this renderer.
155+
156+ Args:
157+ width: The pixel width of the new texture.
158+ height: The pixel height of the new texture.
159+ format: The format the new texture.
160+ access: The access mode of the texture. Defaults to :any:`TextureAccess.STATIC`.
161+ See :any:`TextureAccess` for more options.
162+ """
131163 if format is None :
132164 format = 0
133165 if access is None :
134166 access = int (lib .SDL_TEXTUREACCESS_STATIC )
135167 texture_p = ffi .gc (lib .SDL_CreateTexture (self .p , format , access , width , height ), lib .SDL_DestroyTexture )
136168 return Texture (texture_p , self .p )
137169
138- def set_render_target (self , texture : Texture ) -> _RestoreTargetContext :
139- """Change the render target to `texture`, returns a context that will restore the original target when exited."""
140- restore = _RestoreTargetContext (self )
141- _check (lib .SDL_SetRenderTarget (self .p , texture .p ))
142- return restore
143-
144170 def upload_texture (
145171 self , pixels : NDArray [Any ], * , format : Optional [int ] = None , access : Optional [int ] = None
146172 ) -> Texture :
147- """Return a new Texture from an array of pixels."""
173+ """Return a new Texture from an array of pixels.
174+
175+ Args:
176+ pixels: An RGB or RGBA array of pixels in row-major order.
177+ format: The format of `pixels` when it isn't a simple RGB or RGBA array.
178+ access: The access mode of the texture. Defaults to :any:`TextureAccess.STATIC`.
179+ See :any:`TextureAccess` for more options.
180+ """
148181 if format is None :
149182 assert len (pixels .shape ) == 3
150183 assert pixels .dtype == np .uint8
151184 if pixels .shape [2 ] == 4 :
152185 format = int (lib .SDL_PIXELFORMAT_RGBA32 )
153186 elif pixels .shape [2 ] == 3 :
154- format = int (lib .SDL_PIXELFORMAT_RGB32 )
187+ format = int (lib .SDL_PIXELFORMAT_RGB24 )
155188 else :
156189 raise TypeError (f"Can't determine the format required for an array of shape { pixels .shape } ." )
157190
@@ -174,6 +207,13 @@ def new_renderer(
174207) -> Renderer :
175208 """Initialize and return a new SDL Renderer.
176209
210+ Args:
211+ window: The window that this renderer will be attached to.
212+ driver: Force SDL to use a specific video driver.
213+ software: If True then a software renderer will be forced. By default a hardware renderer is used.
214+ vsync: If True then Vsync will be enabled.
215+ target_textures: If True then target textures can be used by the renderer.
216+
177217 Example::
178218
179219 # Start by creating a window.
0 commit comments