Skip to content

Commit 8492014

Browse files
committed
Port libtcod direct SDL rendering functions.
Allow access to the fancy SDL classes from tcod contexts.
1 parent afdd1d4 commit 8492014

File tree

4 files changed

+87
-2
lines changed

4 files changed

+87
-2
lines changed

tcod/context.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@
5858

5959
import tcod
6060
import tcod.event
61+
import tcod.sdl.render
62+
import tcod.sdl.video
6163
import tcod.tileset
6264
from tcod._internal import _check, _check_warn, pending_deprecate
6365
from tcod.loader import ffi, lib
@@ -351,6 +353,24 @@ def toggle_fullscreen(context: tcod.context.Context) -> None:
351353
''' # noqa: E501
352354
return lib.TCOD_context_get_sdl_window(self._context_p)
353355

356+
@property
357+
def sdl_window(self) -> Optional[tcod.sdl.video.Window]:
358+
"""Return a tcod.sdl.video.Window referencing this contexts SDL window if it exists.
359+
360+
.. versionadded:: 13.4
361+
"""
362+
p = self.sdl_window_p
363+
return tcod.sdl.video.Window(p) if p else None
364+
365+
@property
366+
def sdl_renderer(self) -> Optional[tcod.sdl.render.Renderer]:
367+
"""Return a tcod.sdl.render.Renderer referencing this contexts SDL renderer if it exists.
368+
369+
.. versionadded:: 13.4
370+
"""
371+
p = lib.TCOD_context_get_sdl_renderer(self._context_p)
372+
return tcod.sdl.render.Renderer(p) if p else None
373+
354374
def __reduce__(self) -> NoReturn:
355375
"""Contexts can not be pickled, so this class will raise
356376
:class:`pickle.PicklingError`.

tcod/render.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
from __future__ import annotations
2+
3+
from typing import Optional
4+
5+
import tcod.console
6+
import tcod.sdl.render
7+
import tcod.tileset
8+
from tcod._internal import _check, _check_p
9+
from tcod.loader import ffi, lib
10+
11+
12+
class SDLTilesetAtlas:
13+
"""Prepares a tileset for rendering using SDL."""
14+
15+
def __init__(self, renderer: tcod.sdl.render.Renderer, tileset: tcod.tileset.Tileset) -> None:
16+
self._renderer = renderer
17+
self.tileset = tileset
18+
self.p = ffi.gc(_check_p(lib.TCOD_sdl2_atlas_new(renderer.p, tileset._tileset_p)), lib.TCOD_sdl2_atlas_delete)
19+
20+
21+
class SDLConsoleRender:
22+
"""Holds an internal cache console and texture which are used to optimized console rendering."""
23+
24+
def __init__(self, atlas: SDLTilesetAtlas) -> None:
25+
self._atlas = atlas
26+
self._renderer = atlas._renderer
27+
self._cache_console: Optional[tcod.console.Console] = None
28+
self._texture: Optional[tcod.sdl.render.Texture] = None
29+
30+
def render(self, console: tcod.console.Console) -> tcod.sdl.render.Texture:
31+
"""Render a console to a cached Texture and then return the Texture.
32+
33+
You should not draw onto the returned Texture as only changed parts of it will be updated on the next call.
34+
35+
This function requires the SDL renderer to have target texture support.
36+
It will also change the SDL target texture for the duration of the call.
37+
"""
38+
if self._cache_console and (
39+
self._cache_console.width != console.width or self._cache_console.height != console.height
40+
):
41+
self._cache_console = None
42+
self._texture = None
43+
if self._cache_console is None or self._texture is None:
44+
self._cache_console = tcod.console.Console(console.width, console.height)
45+
self._texture = self._renderer.new_texture(
46+
self._atlas.tileset.tile_width * console.width,
47+
self._atlas.tileset.tile_height * console.height,
48+
format=int(lib.SDL_PIXELFORMAT_RGBA32),
49+
access=int(lib.SDL_TEXTUREACCESS_TARGET),
50+
)
51+
_check(
52+
lib.TCOD_sdl2_render_texture(
53+
self._atlas.p, console.console_c, self._cache_console.console_c, self._texture.p
54+
)
55+
)
56+
return self._texture

tcod/sdl/render.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ def upload_texture(
116116
elif pixels.shape[2] == 3:
117117
format = int(lib.SDL_PIXELFORMAT_RGB32)
118118
else:
119-
assert False
119+
raise TypeError(f"Can't determine the format required for an array of shape {pixels.shape}.")
120120

121121
texture = self.new_texture(pixels.shape[1], pixels.shape[0], format=format, access=access)
122122
if not pixels[0].flags["C_CONTIGUOUS"]:

tcod/sdl/video.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,17 @@ def size(self, xy: Tuple[int, int]) -> None:
114114
x, y = xy
115115
lib.SDL_SetWindowSize(self.p, x, y)
116116

117+
@property
118+
def title(self) -> str:
119+
"""The title of the window. You may set this attribute to change it."""
120+
return str(ffi.string(lib.SDL_GetWindowtitle(self.p)), encoding="utf-8")
121+
122+
@title.setter
123+
def title(self, value: str) -> None:
124+
lib.SDL_SetWindowtitle(self.p, value.encode("utf-8"))
125+
117126

118-
def get_active_window() -> Window:
127+
def _get_active_window() -> Window:
119128
"""Return the SDL2 window current managed by libtcod.
120129
121130
Will raise an error if libtcod does not currently have a window.

0 commit comments

Comments
 (0)