1 """
2 The documentation for python-tdl. A Pythonic port of
3 U{libtcod<http://doryen.eptalys.net/libtcod/>}.
4
5 Getting Started
6 ===============
7 Once the library is imported you can load the font you want to use with
8 L{tdl.setFont}. This is optional and can be skipped to get a decent
9 default font. After that you call L{tdl.init} to set the size of the
10 window and get the root console in return. This console is the canvas
11 to what will appear on the screen.
12
13 Drawing
14 =======
15 Once you have the root console from L{tdl.init} you can start drawing on
16 it using a method such as L{Console.drawChar}. When using this method
17 you can have the char parameter be an intiger or a single character
18 string. The fgcolor and bgcolor parameters expect a three item list
19 [red, green, blue] with integers in the 0-255 range with [0, 0, 0] being
20 black and [255, 255, 255] being white. Or instead you can use None for
21 any of the three parameters to tell the library to keep what is at that
22 spot instead of overwriting it. After the drawing functions are called
23 a call to L{tdl.flush} will update the screen.
24 """
25
26 import sys
27 import os
28 import ctypes
29 import weakref
30 import array
31 import itertools
32
33 from . import event
34 from .__tcod import _lib, _Color, _unpackfile
35
36 _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.'
41 "changes string into bytes if running in python 3, for sending to ctypes"
42 if _IS_PYTHON3 and isinstance(string, str):
43 return string.encode()
44 return string
45
63
64 _fontinitialized = False
65 _rootinitialized = False
66 _rootconsole = None
67
68 _setchar = _lib.TCOD_console_set_char
69 _setfore = _lib.TCOD_console_set_char_foreground
70 _setback = _lib.TCOD_console_set_char_background
71 _setcharEX = _lib.TCOD_console_put_char_ex
73 """Used internally.
74 Raise an assertion error if the parameters can not be converted into colors.
75 """
76 for color in colors:
77 assert _iscolor(color), 'a color must be a 3 item tuple, web format, or None, received %s' % repr(color)
78 return True
79
81 """Used internally.
82 A debug function to see if an object can be used as a TCOD color struct.
83 None counts as a parameter to keep the current colors instead.
84
85 This function is often part of an inner-loop and can slow a program down.
86 It has been made to work with assert and can be skipped with the -O flag.
87 Still it's called often and must be optimized.
88 """
89 if color is None:
90 return True
91 if isinstance(color, (tuple, list, _Color)):
92 return len(color) == 3
93 if isinstance(color, int) or not _IS_PYTHON3 and isinstance(color, long):
94 return True
95 return False
96
109
111 """
112 The catch all for most TDL specific errors.
113 """
114
382
383 width, height = self.getSize()
384 if abs(x) >= width or abs(y) >= height:
385 return self.clear()
386
387
388 coverX, uncoverX = getCover(x, width)
389 coverY, uncoverY = getCover(y, height)
390
391
392
393
394
395
396
397 x, width, srcx = getSlide(x, width)
398 y, height, srcy = getSlide(y, height)
399 self.blit(self, x, y, width, height, srcx, srcy)
400
401 if uncoverX:
402 self.drawRect(uncoverX[0], coverY[0], uncoverX[1], coverY[1], 0x20)
403 if uncoverY:
404 self.drawRect(coverX[0], uncoverY[0], coverX[1], uncoverY[1], 0x20)
405 if uncoverX and uncoverY:
406 self.drawRect(uncoverX[0], uncoverY[0], uncoverX[1], uncoverY[1], 0x20)
407
413
426
428 """The Console is the main class of the tdl library.
429
430 The console created by the L{tdl.init} function is the root console and is the
431 consle that is rendered to the screen with flush.
432
433 Any console made from Console is an off-screen console that can be drawn
434 on and then L{blit} to the root console.
435 """
436
437 __slots__ = ('_as_parameter_',)
438
446
447
448 @classmethod
450 """Make a Console instance, from a console ctype"""
451 self = cls.__new__(cls)
452 self._as_parameter_ = console
453 self.width = _lib.TCOD_console_get_width(self)
454 self.height = _lib.TCOD_console_get_height(self)
455 self._initArrays()
456
457 return self
458
460 if not _USE_FILL:
461 return
462
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
485
500
502 """Convertion x and y to their position on the root Console for this Window
503
504 Because this is a Console instead of a Window we return the paramaters
505 untouched"""
506 return x, y
507
508 - def clear(self, fgcolor=(255, 255, 255), bgcolor=(0, 0, 0)):
509 """Clears the entire console.
510
511 @type fgcolor: 3-item list
512 @type bgcolor: 3-item list
513 """
514 assert _verify_colors(fgcolor, bgcolor)
515 assert fgcolor and bgcolor, 'Can not use None with clear'
516 _lib.TCOD_console_set_default_background(self, _formatColor(bgcolor))
517 _lib.TCOD_console_set_default_foreground(self, _formatColor(fgcolor))
518 _lib.TCOD_console_clear(self)
519
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):
529 """
530 Sets a character.
531 This is called often and is designed to be as fast as possible.
532
533 Because of the need for speed this function will do NO TYPE CHECKING
534 AT ALL, it's up to the drawing functions to use the functions:
535 _formatChar and _formatColor before passing to this."""
536 if char is not None and fgcolor is not None and bgcolor is not None:
537 return _setcharEX(self, x, y, char, fgcolor, bgcolor)
538 if char is not None:
539 _setchar(self, x, y, char)
540 if fgcolor is not None:
541 _setfore(self, x, y, fgcolor)
542 if bgcolor is not None:
543 _setback(self, x, y, bgcolor, bgblend)
544
545 if _USE_FILL:
546 _setChar = _setCharFill
547 else:
548 _setChar = _setCharCall
549
551 """Return the character and colors of a cell as
552 (char, fgcolor, bgcolor)
553
554 The charecter is returned as a number.
555 Each color is returned as a tuple.
556
557 @rtype: (int, 3-item tuple, 3-item tuple)
558 """
559 self._drawable(x, y)
560 char = _lib.TCOD_console_get_char(self, x, y)
561 bgcolor = _lib.TCOD_console_get_char_background_wrapper(self, x, y)
562 fgcolor = _lib.TCOD_console_get_char_foreground_wrapper(self, x, y)
563 return char, tuple(fgcolor), tuple(bgcolor)
564
566 return "<Console (Width=%i Height=%i)>" % (self.width, self.height)
567
568
569 -class Window(_MetaConsole):
570 """A Window contains a small isolated part of a Console.
571
572 Drawing on the Window draws on the Console.
573
574 Making a Window and setting its width or height to None will extend it to
575 the edge of the console.
576 """
577
578 __slots__ = ('console', 'parent', 'x', 'y')
579
580 - def __init__(self, console, x, y, width, height):
581 assert isinstance(console, (Console, Window)), 'console parameter must be a Console or Window instance, got %s' % repr(console)
582 self.parent = console
583 self.x, self.y, self.width, self.height = console._normalizeRect(x, y, width, height)
584 if isinstance(console, Console):
585 self.console = console
586 else:
587 self.console = self.parent.console
588
590 """Convertion x and y to their position on the root Console"""
591
592 return self.parent._translate((x + self.x), (y + self.y))
593
594 - def clear(self, fgcolor=(255, 255, 255), bgcolor=(0, 0, 0)):
595 """Clears the entire Window.
596
597 @type fgcolor: 3-item list
598 @type bgcolor: 3-item list
599 """
600 assert _verify_colors(fgcolor, bgcolor)
601 assert fgcolor and bgcolor, 'Can not use None with clear'
602 self.draw_rect(0, 0, None, None, 0x20, fgcolor, bgcolor)
603
604 - def _setChar(self, x, y, char=None, fgcolor=None, bgcolor=None, bgblend=1):
605 self.parent._setChar((x + self.x), (y + self.y), char, fgcolor, bgcolor, bgblend)
606
608 """Return the character and colors of a cell as (ch, fg, bg)
609
610 @rtype: (int, 3-item tuple, 3-item tuple)
611 """
612 self._drawable(x, y)
613 return self.console.getChar(self._translate(x, y))
614
616 return "<Window(X=%i Y=%i Width=%i Height=%i)>" % (self.x, self.y,
617 self.width,
618 self.height)
619
620
621 -def init(width, height, title='python-tdl', fullscreen=False, renderer='OPENGL'):
622 """Start the main console with the given width and height and return the
623 root console.
624
625 Call the consoles drawing functions. Then remember to use L{tdl.flush} to
626 make what's drawn visible on the console.
627
628 @type width: int
629 @type height: int
630
631 @type title: string
632
633 @type fullscreen: boolean
634 @param fullscreen: Can be set to True to start in fullscreen mode.
635
636 @type renderer: string
637 @param renderer: Can be one of 'GLSL', 'OPENGL', or 'SDL'.
638
639 Due to way Python works you're unlikely to see much of an
640 improvement by using 'GLSL' or 'OPENGL' as most of the
641 time Python is slow interacting with the console and the
642 rendering itself is pretty fast even on 'SDL'.
643
644 This should be left at default or switched to 'SDL' for
645 better reliability and an instantaneous start up time.
646
647 @rtype: L{Console}
648 @return: The root console. Only what is drawn on the root console is
649 what's visible after a call to L{tdl.flush}.
650 After the root console is garbage collected, the window made by
651 this function will close.
652 """
653 RENDERERS = {'GLSL': 0, 'OPENGL': 1, 'SDL': 2}
654 global _rootinitialized, _rootconsole
655 if not _fontinitialized:
656 setFont(_unpackfile('terminal.png'), 16, 16, colomn=True)
657
658 if renderer.upper() not in RENDERERS:
659 raise TDLError('No such render type "%s", expected one of "%s"' % (renderer, '", "'.join(RENDERERS)))
660 renderer = RENDERERS[renderer.upper()]
661
662
663 if _rootconsole is not None:
664 oldroot = _rootconsole()
665 rootreplacement = Console(oldroot.width, oldroot.height)
666 rootreplacement.blit(oldroot)
667 oldroot._replace(rootreplacement)
668 del rootreplacement
669
670 _lib.TCOD_console_init_root(width, height, _format_string(title), fullscreen, renderer)
671
672
673
674
675 event._eventsflushed = False
676 _rootinitialized = True
677 rootconsole = Console._newConsole(ctypes.c_void_p())
678 _rootconsole = weakref.ref(rootconsole)
679
680 return rootconsole
681
683 """Make all changes visible and update the screen.
684
685 Remember to call this function after drawing operations.
686 Calls to flush will enfore the frame rate limit set by L{tdl.setFPS}.
687
688 This function can only be called after L{tdl.init}
689 """
690 if not _rootinitialized:
691 raise TDLError('Cannot flush without first initializing with tdl.init')
692
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
699 _lib.TCOD_console_flush()
700
701 -def setFont(path, tileWidth, tileHeight, colomn=False,
702 greyscale=False, altLayout=False):
703 """Changes the font to be used for this session.
704 This should be called before L{tdl.init}
705
706 While it's possible you can change the font mid program it can sometimes
707 break in rare circumstances. So use caution when doing this.
708
709 @type path: string
710 @param path: Must be a string filepath where a bmp or png file is found.
711
712 @type tileWidth: int
713 @param tileWidth: The width of an individual tile.
714
715 @type tileHeight: int
716 @param tileHeight: The height of an individual tile.
717
718 @type colomn: boolean
719 @param colomn: Defines if the characer order goes along the rows or
720 colomns.
721 It should be True if the charater codes 0-15 are in the
722 first column. And should be False if the characters 0-15
723 are in the first row.
724
725 @type greyscale: boolean
726 @param greyscale: Creates an anti-aliased font from a greyscale bitmap.
727 Otherwise it uses the alpha channel for anti-aliasing.
728
729 @type altLayout: boolean
730 @param altLayout: An alternative layout with space in the upper left
731 corner. The colomn parameter is ignored if this is
732 True, find examples of this layout in the font/
733 directory included with the python-tdl source.
734
735 @raise TDLError: Will be raised if no file is found at path.
736
737 @note: A png file that's been optimized can fail to load correctly on
738 MAC OS X creating a garbled mess when rendering.
739 Don't use a program like optipng or just use bmp files instead if
740 you want your program to work on macs.
741 """
742
743 FONT_LAYOUT_ASCII_INCOL = 1
744 FONT_LAYOUT_ASCII_INROW = 2
745 FONT_TYPE_GREYSCALE = 4
746 FONT_LAYOUT_TCOD = 8
747 global _fontinitialized
748 _fontinitialized = True
749 flags = 0
750 if altLayout:
751 flags |= FONT_LAYOUT_TCOD
752 elif colomn:
753 flags |= FONT_LAYOUT_ASCII_INCOL
754 else:
755 flags |= FONT_LAYOUT_ASCII_INROW
756 if greyscale:
757 flags |= FONT_TYPE_GREYSCALE
758 if not os.path.exists(path):
759 raise TDLError('no file exists at: "%s"' % path)
760 _lib.TCOD_console_set_custom_font(_format_string(path), flags, tileWidth, tileHeight)
761
763 """Returns True if program is fullscreen.
764
765 @rtype: boolean
766 @return: Returns True if the window is in fullscreen mode.
767 Otherwise returns False.
768 """
769 if not _rootinitialized:
770 raise TDLError('Initialize first with tdl.init')
771 return _lib.TCOD_console_is_fullscreen()
772
774 """Changes the fullscreen state.
775
776 @type fullscreen: boolean
777 """
778 if not _rootinitialized:
779 raise TDLError('Initialize first with tdl.init')
780 _lib.TCOD_console_set_fullscreen(fullscreen)
781
783 """Change the window title.
784
785 @type title: string
786 """
787 if not _rootinitialized:
788 raise TDLError('Not initilized. Set title with tdl.init')
789 _lib.TCOD_console_set_window_title(_format_string(title))
790
792 """Capture the screen and save it as a png file
793
794 @type path: string
795 @param path: The filepath to save the screenshot.
796
797 If path is None then the image will be placed in the current
798 folder with the names:
799 screenshot001.png, screenshot002.png, ...
800 """
801 if not _rootinitialized:
802 raise TDLError('Initialize first with tdl.init')
803 if isinstance(fileobj, str):
804 _lib.TCOD_sys_save_screenshot(_format_string(fileobj))
805 elif isinstance(fileobj, file):
806 tmpname = os.tempnam()
807 _lib.TCOD_sys_save_screenshot(_format_string(tmpname))
808 with tmpname as tmpfile:
809 fileobj.write(tmpfile.read())
810 os.remove(tmpname)
811 elif fileobj is None:
812 filelist = os.listdir('.')
813 n = 1
814 filename = 'screenshot%.3i.png' % n
815 while filename in filelist:
816 n += 1
817 filename = 'screenshot%.4i.png' % n
818 _lib.TCOD_sys_save_screenshot(_format_string(filename))
819 else:
820 raise TypeError('fileobj is an invalid type: %s' % type(fileobj))
821
823 """Set the maximum frame rate.
824
825 @type frameRate: int
826 @param frameRate: Further calls to L{tdl.flush} will limit the speed of
827 the program to run at <frameRate> frames per second. Can
828 also be set to 0 to run without a limit.
829
830 Defaults to None.
831 """
832 if frameRate is None:
833 frameRate = 0
834 assert isinstance(frameRate, int), 'frameRate must be an integer or None, got: %s' % repr(frameRate)
835 _lib.TCOD_sys_set_fps(frameRate)
836
838 """Return the current frames per second of the running program set by
839 L{setFPS}
840
841 @rtype: int
842 @return: Returns the frameRate set by setFPS.
843 If set to no limit, this will return 0.
844 """
845 return _lib.TCOD_sys_get_fps()
846
848 """Change the fullscreen resoulution
849
850 @type width: int
851 @type height: int
852 """
853 _lib.TCOD_sys_force_fullscreen_resolution(width, height)
854
855 __all__ = [_var for _var in locals().keys() if _var[0] != '_' and _var not in ['sys', 'os', 'ctypes', 'array', 'weakref', 'itertools']]
856 __all__ += ['_MetaConsole']
857