3434from .__tcod import _lib , _Color , _unpackfile
3535
3636_IS_PYTHON3 = (sys .version_info [0 ] == 3 )
37- _USE_FILL = False
38- 'Set to True to use the libtcod fill optimization. This is actually slower than the normal mode.'
3937
40- def _format_string (string ): # still used for filepaths, and that's about it
38+ def _encodeString (string ): # still used for filepaths, and that's about it
4139 "changes string into bytes if running in python 3, for sending to ctypes"
4240 if _IS_PYTHON3 and isinstance (string , str ):
4341 return string .encode ()
4442 return string
4543
46- #def _encodeString (string):
44+ #def _formatString (string):
4745# pass
4846
4947def _formatChar (char ):
@@ -93,14 +91,13 @@ def _iscolor(color):
9391 if isinstance (color , int ) or not _IS_PYTHON3 and isinstance (color , long ):
9492 return True
9593 return False
96-
94+
9795def _formatColor (color ):
9896 """Format the color to ctypes
9997 """
10098 if color is None :
10199 return None
102- # avoid isinstance, checking __class__ gives a small speed increase
103- if color .__class__ is _Color :
100+ if isinstance (color , _Color ):
104101 return color
105102 if isinstance (color , int ) or not _IS_PYTHON3 and isinstance (color , long ):
106103 # format a web style color with the format 0xRRGGBB
@@ -172,14 +169,23 @@ def drawStr(self, x, y, string, fgcolor=(255, 255, 255), bgcolor=(0, 0, 0)):
172169 assert _verify_colors (fgcolor , bgcolor )
173170 fgcolor , bgcolor = _formatColor (fgcolor ), _formatColor (bgcolor )
174171 width , height = self .getSize ()
175- for char in string :
176- if y == height :
177- raise TDLError ('End of console reached.' )
178- self ._setChar (x , y , _formatChar (char ), fgcolor , bgcolor )
179- x += 1 # advance cursor
180- if x == width : # line break
181- x = 0
182- y += 1
172+ batch = [] # prepare a batch operation
173+ def _drawStrGen (x = x , y = y , string = string , width = width , height = height ):
174+ """Generator for drawStr
175+
176+ Iterates over ((x, y), ch) data for _setCharBatch, raising an
177+ error if the end of the console is reached.
178+ """
179+ for char in string :
180+ if y == height :
181+ raise TDLError ('End of console reached.' )
182+ #batch.append(((x, y), _formatChar(char))) # ((x, y), ch)
183+ yield ((x , y ), _formatChar (char ))
184+ x += 1 # advance cursor
185+ if x == width : # line break
186+ x = 0
187+ y += 1
188+ self ._setCharBatch (_drawStrGen (), fgcolor , bgcolor )
183189
184190 def drawRect (self , x , y , width , height , string , fgcolor = (255 , 255 , 255 ), bgcolor = (0 , 0 , 0 )):
185191 """Draws a rectangle starting from x and y and extending to width and
@@ -198,9 +204,13 @@ def drawRect(self, x, y, width, height, string, fgcolor=(255, 255, 255), bgcolor
198204 assert _verify_colors (fgcolor , bgcolor )
199205 fgcolor , bgcolor = _formatColor (fgcolor ), _formatColor (bgcolor )
200206 char = _formatChar (string )
201- for cellY in range (y , y + height ):
202- for cellX in range (x , x + width ):
203- self ._setChar (cellX , cellY , char , fgcolor , bgcolor )
207+ # use itertools to make an x,y grid
208+ # using ctypes here reduces type converstions later
209+ grid = itertools .product ((ctypes .c_int (x ) for x in range (x , x + width )),
210+ (ctypes .c_int (y ) for y in range (y , y + height )))
211+ # zip the single character in a batch variable
212+ batch = zip (grid , itertools .repeat (char , width * height ))
213+ self ._setCharBatch (batch , fgcolor , bgcolor )
204214
205215 def drawFrame (self , x , y , width , height , string , fgcolor = (255 , 255 , 255 ), bgcolor = (0 , 0 , 0 )):
206216 """Similar to drawRect but only draws the outline of the rectangle.
@@ -442,7 +452,6 @@ def __init__(self, width, height):
442452 self ._as_parameter_ = _lib .TCOD_console_new (width , height )
443453 self .width = width
444454 self .height = height
445- self ._initArrays ()
446455 #self.clear()
447456
448457 @classmethod
@@ -452,23 +461,9 @@ def _newConsole(cls, console):
452461 self ._as_parameter_ = console
453462 self .width = _lib .TCOD_console_get_width (self )
454463 self .height = _lib .TCOD_console_get_height (self )
455- self ._initArrays ()
456464 #self.clear()
457465 return self
458466
459- def _initArrays (self ):
460- if not _USE_FILL :
461- return
462- # used for the libtcod fill optimization
463- IntArray = ctypes .c_int * (self .width * self .height )
464- self .chArray = IntArray ()
465- self .fgArrays = (IntArray (),
466- IntArray (),
467- IntArray ())
468- self .bgArrays = (IntArray (),
469- IntArray (),
470- IntArray ())
471-
472467 def __del__ (self ):
473468 """
474469 If the main console is garbage collected then the window will be closed as well
@@ -517,35 +512,50 @@ def clear(self, fgcolor=(255, 255, 255), bgcolor=(0, 0, 0)):
517512 _lib .TCOD_console_set_default_foreground (self , _formatColor (fgcolor ))
518513 _lib .TCOD_console_clear (self )
519514
520- def _setCharFill (self , x , y , char , fgcolor = None , bgcolor = None ):
521- """An optimized version using the fill wrappers that didn't work out to be any faster"""
522- index = x + y * self .width
523- self .chArray [index ] = char
524- for channel , color in zip (itertools .chain (self .fgArrays , self .bgArrays ),
525- itertools .chain (fgcolor , bgcolor )):
526- channel [index ] = color
527-
528- def _setCharCall (self , x , y , char , fgcolor = None , bgcolor = None , bgblend = 1 ):
515+ def _setChar (self , x , y , char , fgcolor = None , bgcolor = None , bgblend = 1 ):
529516 """
530517 Sets a character.
531518 This is called often and is designed to be as fast as possible.
532519
533520 Because of the need for speed this function will do NO TYPE CHECKING
534521 AT ALL, it's up to the drawing functions to use the functions:
535522 _formatChar and _formatColor before passing to this."""
523+ # buffer values as ctypes objects
524+ console = self ._as_parameter_
525+ x = ctypes .c_int (x )
526+ y = ctypes .c_int (y )
527+
536528 if char is not None and fgcolor is not None and bgcolor is not None :
537- return _setcharEX (self , x , y , char , fgcolor , bgcolor )
529+ _setcharEX (console , x , y , char , fgcolor , bgcolor )
530+ return
538531 if char is not None :
539- _setchar (self , x , y , char )
532+ _setchar (console , x , y , char )
540533 if fgcolor is not None :
541- _setfore (self , x , y , fgcolor )
534+ _setfore (console , x , y , fgcolor )
542535 if bgcolor is not None :
543- _setback (self , x , y , bgcolor , bgblend )
536+ _setback (console , x , y , bgcolor , bgblend )
544537
545- if _USE_FILL :
546- _setChar = _setCharFill
547- else :
548- _setChar = _setCharCall
538+ def _setCharBatch (self , batch , fgcolor , bgcolor , bgblend = 1 ):
539+ """
540+ Try to perform a batch operation otherwise fall back to _setChar.
541+ If fgcolor and bgcolor are defined then this is faster but not by very
542+ much.
543+
544+ batch is a iterable of [(x, y), ch] items
545+ """
546+ if fgcolor and bgcolor :
547+ # buffer values as ctypes objects
548+ console = self ._as_parameter_
549+ bgblend = ctypes .c_int (bgblend )
550+
551+ _lib .TCOD_console_set_default_background (console , bgcolor )
552+ _lib .TCOD_console_set_default_foreground (console , fgcolor )
553+ _putChar = _lib .TCOD_console_put_char # remove dots
554+ for (x , y ), char in batch :
555+ _putChar (console , x , y , char , bgblend )
556+ else :
557+ for (x , y ), char in batch :
558+ self ._setChar (x , y , char , fgcolor , bgcolor , bgblend )
549559
550560 def getChar (self , x , y ):
551561 """Return the character and colors of a cell as
@@ -556,7 +566,7 @@ def getChar(self, x, y):
556566
557567 @rtype: (int, 3-item tuple, 3-item tuple)
558568 """
559- self ._drawable (x , y )
569+ assert self ._drawable (x , y )
560570 char = _lib .TCOD_console_get_char (self , x , y )
561571 bgcolor = _lib .TCOD_console_get_char_background_wrapper (self , x , y )
562572 fgcolor = _lib .TCOD_console_get_char_foreground_wrapper (self , x , y )
@@ -604,6 +614,12 @@ def clear(self, fgcolor=(255, 255, 255), bgcolor=(0, 0, 0)):
604614 def _setChar (self , x , y , char = None , fgcolor = None , bgcolor = None , bgblend = 1 ):
605615 self .parent ._setChar ((x + self .x ), (y + self .y ), char , fgcolor , bgcolor , bgblend )
606616
617+ def _setCharBatch (self , batch , fgcolor , bgcolor , bgblend = 1 ):
618+ myX = self .x # remove dots for speed up
619+ myY = self .y
620+ self .parent ._setCharBatch ((((x + myX , y + myY ), ch ) for ((x , y ), ch ) in batch ),
621+ fgcolor , bgcolor , bgblend )
622+
607623 def getChar (self , x , y ):
608624 """Return the character and colors of a cell as (ch, fg, bg)
609625
@@ -667,7 +683,7 @@ def init(width, height, title='python-tdl', fullscreen=False, renderer='OPENGL')
667683 oldroot ._replace (rootreplacement )
668684 del rootreplacement
669685
670- _lib .TCOD_console_init_root (width , height , _format_string (title ), fullscreen , renderer )
686+ _lib .TCOD_console_init_root (width , height , _encodeString (title ), fullscreen , renderer )
671687
672688 #event.get() # flush the libtcod event queue to fix some issues
673689 # issues may be fixed already
@@ -690,12 +706,6 @@ def flush():
690706 if not _rootinitialized :
691707 raise TDLError ('Cannot flush without first initializing with tdl.init' )
692708
693- if _USE_FILL :
694- console = _rootconsole ()
695- _lib .TCOD_console_fill_background (console , * console .bgArrays )
696- _lib .TCOD_console_fill_foreground (console , * console .fgArrays )
697- _lib .TCOD_console_fill_char (console , console .chArray )
698-
699709 _lib .TCOD_console_flush ()
700710
701711def setFont (path , tileWidth , tileHeight , colomn = False ,
@@ -757,7 +767,7 @@ def setFont(path, tileWidth, tileHeight, colomn=False,
757767 flags |= FONT_TYPE_GREYSCALE
758768 if not os .path .exists (path ):
759769 raise TDLError ('no file exists at: "%s"' % path )
760- _lib .TCOD_console_set_custom_font (_format_string (path ), flags , tileWidth , tileHeight )
770+ _lib .TCOD_console_set_custom_font (_encodeString (path ), flags , tileWidth , tileHeight )
761771
762772def getFullscreen ():
763773 """Returns True if program is fullscreen.
@@ -786,7 +796,7 @@ def setTitle(title):
786796 """
787797 if not _rootinitialized :
788798 raise TDLError ('Not initilized. Set title with tdl.init' )
789- _lib .TCOD_console_set_window_title (_format_string (title ))
799+ _lib .TCOD_console_set_window_title (_encodeString (title ))
790800
791801def screenshot (path = None ):
792802 """Capture the screen and save it as a png file
@@ -801,10 +811,10 @@ def screenshot(path=None):
801811 if not _rootinitialized :
802812 raise TDLError ('Initialize first with tdl.init' )
803813 if isinstance (fileobj , str ):
804- _lib .TCOD_sys_save_screenshot (_format_string (fileobj ))
814+ _lib .TCOD_sys_save_screenshot (_encodeString (fileobj ))
805815 elif isinstance (fileobj , file ): # save to temp file and copy to file-like obj
806816 tmpname = os .tempnam ()
807- _lib .TCOD_sys_save_screenshot (_format_string (tmpname ))
817+ _lib .TCOD_sys_save_screenshot (_encodeString (tmpname ))
808818 with tmpname as tmpfile :
809819 fileobj .write (tmpfile .read ())
810820 os .remove (tmpname )
@@ -815,7 +825,7 @@ def screenshot(path=None):
815825 while filename in filelist :
816826 n += 1
817827 filename = 'screenshot%.4i.png' % n
818- _lib .TCOD_sys_save_screenshot (_format_string (filename ))
828+ _lib .TCOD_sys_save_screenshot (_encodeString (filename ))
819829 else :
820830 raise TypeError ('fileobj is an invalid type: %s' % type (fileobj ))
821831
0 commit comments