Skip to content

Commit 63a0864

Browse files
committed
added ch, fg, bg attributes to Console's, these will be very powerful when more work is done on them
1 parent c81d341 commit 63a0864

File tree

2 files changed

+178
-26
lines changed

2 files changed

+178
-26
lines changed

dev/benchmark.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,14 @@ def test(self, console):
7272
self.tiles += 1
7373
tdl.flush()
7474

75+
class Benchmark_DrawChar_Ch_Attribute(Benchmark):
76+
77+
def test(self, console):
78+
for x,y in console:
79+
console.ch[x,y] = ord('C')
80+
self.tiles += 1
81+
tdl.flush()
82+
7583

7684
class Benchmark_DrawStr16_DefaultColor(Benchmark):
7785
default_frames = 100
@@ -106,6 +114,7 @@ def run_benchmark():
106114
print_result('In %s mode' % (['release', 'debug'][__debug__]))
107115
print_result('%i characters/frame' % (WIDTH * HEIGHT))
108116
print_result('Opened console in %s mode' % RENDERER)
117+
Benchmark_DrawChar_Ch_Attribute().run(console)
109118
Benchmark_DrawChar_DefaultColor().run(console)
110119
Benchmark_DrawChar_NoColor().run(console)
111120
#Benchmark_DrawStr16_DefaultColor().run(console)

tdl/__init__.py

Lines changed: 169 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,64 @@ class _BaseConsole(object):
190190
@ivar width: The width of this console in tiles. Do not overwrite this.
191191
@ivar height: The height of this console in tiles. Do not overwrite this.
192192
"""
193-
__slots__ = ('width', 'height', 'console', '_cursor', '_fg',
194-
'_bg', '_blend', '__weakref__', '__dict__')
195-
193+
194+
class ConsoleAttribute(object):
195+
def __init__(self, console, range_x, range_y):
196+
self._console = console
197+
self._range_x = range_x
198+
self._range_y = range_y
199+
200+
def _get_slice(self, slice_x, slice_y):
201+
if not isinstance(slice_x, slice):
202+
slice_x = slice(slice_x, slice_x + 1)
203+
if not isinstance(slice_y, slice):
204+
slice_x = slice(slice_y, slice_y + 1)
205+
return self.__class__(self._console, self._range_x[slice_x],
206+
self._range_y[slice_y])
207+
208+
class AttributeCh(ConsoleAttribute):
209+
210+
def __getitem__(self, key):
211+
if isinstance(key[0], slice) or isinstance(key[1], slice):
212+
return self._get_slice(*key)
213+
x = self._range_x[key[0]]
214+
y = self._range_y[key[1]]
215+
return _lib.TCOD_console_get_char(self._console.tcod_console, x, y)
216+
217+
def __setitem__(self, key, ch):
218+
x = self._range_x[key[0]]
219+
y = self._range_y[key[1]]
220+
_lib.TCOD_console_set_char(self._console.tcod_console, x, y, ch)
221+
222+
class AttributeFG(ConsoleAttribute):
223+
224+
def __getitem__(self, key):
225+
if isinstance(key[0], slice) or isinstance(key[1], slice):
226+
return self._get_slice(*key)
227+
x = self._range_x[key[0]]
228+
y = self._range_y[key[1]]
229+
return _lib.TDL_console_get_fg(self._console.tcod_console, x, y)
230+
231+
def __setitem__(self, key, fg):
232+
x = self._range_x[key[0]]
233+
y = self._range_y[key[1]]
234+
_lib.TDL_console_set_fg(self._console.tcod_console, x, y, fg)
235+
236+
class AttributeBG(ConsoleAttribute):
237+
238+
def __getitem__(self, key):
239+
if isinstance(key[0], slice) or isinstance(key[1], slice):
240+
return self._get_slice(*key)
241+
x = self._range_x[key[0]]
242+
y = self._range_y[key[1]]
243+
return _lib.TDL_console_get_bg(self._console.tcod_console, x, y)
244+
245+
def __setitem__(self, key, bg):
246+
x = self._range_x[key[0]]
247+
y = self._range_y[key[1]]
248+
_lib.TDL_console_set_bg(self._console.tcod_console, x, y, fg, 1)
249+
250+
196251
def __init__(self):
197252
self._cursor = (0, 0)
198253
self._scrollMode = 'error'
@@ -205,17 +260,15 @@ def _normalizePoint(self, x, y):
205260
206261
Respects Pythons negative indexes. -1 starts at the bottom right.
207262
Replaces the _drawable function
263+
264+
Mostly depreciated at this point
208265
"""
209266
# cast to int, always faster than type checking
210267
x = int(x)
211268
y = int(y)
212-
213-
assert (-self.width <= x < self.width) and \
214-
(-self.height <= y < self.height), \
215-
('(%i, %i) is an invalid postition on %s' % (x, y, self))
216-
269+
217270
# handle negative indexes
218-
return (x % self.width, y % self.height)
271+
return self._range_x[x], self._range_y[y]
219272

220273
def _normalizeRect(self, x, y, width, height):
221274
"""Check if the rectangle is in bounds and make minor adjustments.
@@ -795,8 +848,6 @@ class Console(_BaseConsole):
795848
garbage collected the tcod_console will be deleted.
796849
"""
797850

798-
__slots__ = ('tcod_console',)
799-
800851
def __init__(self, width, height):
801852
"""Create a new offscreen console.
802853
@@ -812,6 +863,15 @@ def __init__(self, width, height):
812863
self.console = self
813864
self.width = width
814865
self.height = height
866+
867+
# ranges for easy Python style indexing
868+
self._range_x = range(self.width)
869+
self._range_y = range(self.height)
870+
871+
# special attributes for slightly lower level access to ch, fg, bg
872+
self.ch = self.AttributeCh(self, self._range_x, self._range_y)
873+
self.fg = self.AttributeFG(self, self._range_x, self._range_y)
874+
self.bg = self.AttributeBG(self, self._range_x, self._range_y)
815875

816876
@classmethod
817877
def _newConsole(cls, console):
@@ -822,6 +882,12 @@ def _newConsole(cls, console):
822882
self.console = self
823883
self.width = _lib.TCOD_console_get_width(console)
824884
self.height = _lib.TCOD_console_get_height(console)
885+
886+
self._range_x = range(self.width)
887+
self._range_y = range(self.height)
888+
self.ch = self.AttributeCh(self, self._range_x, self._range_y)
889+
self.fg = self.AttributeFG(self, self._range_x, self._range_y)
890+
self.bg = self.AttributeBG(self, self._range_x, self._range_y)
825891
return self
826892

827893
def _root_unhook(self):
@@ -843,6 +909,12 @@ def _root_unhook(self):
843909
_lib.TCOD_console_delete(self.tcod_console)
844910
# this Console object is now a regular console
845911
self.tcod_console = unhooked
912+
913+
# point attributes to new console cdata
914+
self.ch._cdata = unhooked
915+
self.fg._cdata = unhooked
916+
self.bg._cdata = unhooked
917+
846918

847919
def __del__(self):
848920
"""
@@ -930,6 +1002,30 @@ def get_char(self, x, y):
9301002
fg = _lib.TCOD_console_get_char_foreground(self.tcod_console, x, y)
9311003
return char, (fg.r, fg.g, fg.b), (bg.r, bg.g, bg.b)
9321004

1005+
def __getitem__(self, key):
1006+
x, y = key
1007+
if isinstance(x, slice) or isinstance(y, slice):
1008+
if not isinstance(x, slice):
1009+
x = slice(x, x + 1)
1010+
if not isinstance(y, slice):
1011+
y = slice(y, y + 1)
1012+
1013+
window = Window(self, 0, 0, 0, 0)
1014+
window._range_x = range(self.width)[x]
1015+
window._range_y = range(self.height)[y]
1016+
window.ch = window.AttributeCh(self, window._range_x,
1017+
window._range_y)
1018+
window.fg = window.AttributeFG(self, window._range_x,
1019+
window._range_y)
1020+
window.bg = window.AttributeBG(self, window._range_x,
1021+
window._range_y)
1022+
return window
1023+
x = self._range_x[x]
1024+
y = self._range_y[y]
1025+
return (_lib.TCOD_console_get_char(self.tcod_console, x, y),
1026+
_lib.TDL_console_get_fg(self.tcod_console, x, y),
1027+
_lib.TDL_console_get_bg(self.tcod_console, x, y))
1028+
9331029
def __repr__(self):
9341030
return "<Console (Width=%i Height=%i)>" % (self.width, self.height)
9351031

@@ -945,8 +1041,6 @@ class Window(_BaseConsole):
9451041
@undocumented: getChar
9461042
"""
9471043

948-
__slots__ = ('parent', 'x', 'y')
949-
9501044
def __init__(self, console, x, y, width, height):
9511045
"""Isolate part of a L{Console} or L{Window} instance.
9521046
@@ -980,16 +1074,41 @@ def __init__(self, console, x, y, width, height):
9801074
_BaseConsole.__init__(self)
9811075
assert isinstance(console, (Console, Window)), 'console parameter must be a Console or Window instance, got %s' % repr(console)
9821076
self.parent = console
983-
self.x, self.y, self.width, self.height = console._normalizeRect(x, y, width, height)
1077+
1078+
slice_x = slice(x, x + width)
1079+
slice_y = slice(y, y + height)
1080+
self._range_x = console._range_x[slice_x]
1081+
self._range_y = console._range_y[slice_y]
1082+
9841083
if isinstance(console, Console):
9851084
self.console = console
9861085
else:
9871086
self.console = self.parent.console
1087+
1088+
self.ch = self.AttributeCh(self.console, self._range_x, self._range_y)
1089+
self.fg = self.AttributeFG(self.console, self._range_x, self._range_y)
1090+
self.bg = self.AttributeBG(self.console, self._range_x, self._range_y)
9881091

1092+
@property
1093+
def x(self):
1094+
return self._range_x[0]
1095+
1096+
@property
1097+
def y(self):
1098+
return self._range_y[0]
1099+
1100+
@property
1101+
def width(self):
1102+
return len(self._range_x)
1103+
1104+
@property
1105+
def height(self):
1106+
return len(self._range_y)
1107+
9891108
def _translate(self, x, y):
9901109
"""Convertion x and y to their position on the root Console"""
9911110
# we add our position relative to our parent and then call then next parent up
992-
return self.parent._translate((x + self.x), (y + self.y))
1111+
return self.parent._translate(self._range_x[x], self._range_y[y])
9931112

9941113
def clear(self, fg=Ellipsis, bg=Ellipsis):
9951114
# inherit docstring
@@ -1001,24 +1120,24 @@ def clear(self, fg=Ellipsis, bg=Ellipsis):
10011120
self.draw_rect(0, 0, None, None, 0x20, fg, bg)
10021121

10031122
def _set_char(self, x, y, char=None, fg=None, bg=None, bgblend=1):
1004-
self.parent._set_char((x + self.x), (y + self.y), char, fg, bg, bgblend)
1123+
self.parent._set_char(self._range_x[x], self._range_y[y],
1124+
char, fg, bg, bgblend)
10051125

10061126
def _set_batch(self, batch, *args, **kargs):
10071127
# positional values will need to be translated to the parent console
1008-
myX = self.x # remove dots for speed up
1009-
myY = self.y
1010-
self.parent._set_batch((((x + myX, y + myY), ch)
1128+
range_x = self._range_x # remove dots for a slight speed up
1129+
range_y = self._range_y
1130+
self.parent._set_batch((((range_x[x], range_x[y]), ch)
10111131
for ((x, y), ch) in batch), *args, **kargs)
10121132

10131133

10141134
def draw_char(self, x, y, char, fg=Ellipsis, bg=Ellipsis):
10151135
# inherit docstring
1016-
x, y = self._normalizePoint(x, y)
10171136
if fg is Ellipsis:
10181137
fg = self._fg
10191138
if bg is Ellipsis:
10201139
bg = self._bg
1021-
self.parent.draw_char(x + self.x, y + self.y, char, fg, bg)
1140+
self.parent.draw_char(self._range_x[x], self._range_y[y], char, fg, bg)
10221141

10231142
def draw_rect(self, x, y, width, height, string, fg=Ellipsis, bg=Ellipsis):
10241143
# inherit docstring
@@ -1027,7 +1146,7 @@ def draw_rect(self, x, y, width, height, string, fg=Ellipsis, bg=Ellipsis):
10271146
fg = self._fg
10281147
if bg is Ellipsis:
10291148
bg = self._bg
1030-
self.parent.draw_rect(x + self.x, y + self.y, width, height,
1149+
self.parent.draw_rect(self._range_x[x], self._range_y[y], width, height,
10311150
string, fg, bg)
10321151

10331152
def draw_frame(self, x, y, width, height, string, fg=Ellipsis, bg=Ellipsis):
@@ -1037,14 +1156,38 @@ def draw_frame(self, x, y, width, height, string, fg=Ellipsis, bg=Ellipsis):
10371156
fg = self._fg
10381157
if bg is Ellipsis:
10391158
bg = self._bg
1040-
self.parent.draw_frame(x + self.x, y + self.y, width, height,
1159+
self.parent.draw_frame(self._range_x[x], self._range_y[y], width, height,
10411160
string, fg, bg)
10421161

10431162
def get_char(self, x, y):
10441163
# inherit docstring
1045-
x, y = self._normalizePoint(x, y)
1046-
return self.console.get_char(self._translate(x, y))
1047-
1164+
return self.console.get_char(self._range_x[x], self._range_y[y])
1165+
1166+
def __getitem__(self, key):
1167+
x, y = key
1168+
if isinstance(x, slice) or isinstance(y, slice):
1169+
if not isinstance(x, slice):
1170+
x = slice(x, x + 1)
1171+
if not isinstance(y, slice):
1172+
y = slice(y, y + 1)
1173+
1174+
window = Window(self, 0, 0, 0, 0)
1175+
window._range_x = range(self.width)[x]
1176+
window._range_y = range(self.height)[y]
1177+
window.ch = window.AttributeCh(self.console, window._range_x,
1178+
window._range_y)
1179+
window.fg = window.AttributeFG(self.console, window._range_x,
1180+
window._range_y)
1181+
window.bg = window.AttributeBG(self.console, window._range_x,
1182+
window._range_y)
1183+
return window
1184+
x = self._range_x[x]
1185+
y = self._range_y[y]
1186+
return (_lib.TCOD_console_get_char(self.console.tcod_console, x, y),
1187+
_lib.TDL_console_get_fg(self.console.tcod_console, x, y),
1188+
_lib.TDL_console_get_bg(self.console.tcod_console, x, y))
1189+
1190+
10481191
def __repr__(self):
10491192
return "<Window(X=%i Y=%i Width=%i Height=%i)>" % (self.x, self.y,
10501193
self.width,

0 commit comments

Comments
 (0)