Python RGB Matrix games and animations https://www.xythobuz.de/ledmatrix_v2.html
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

draw.py 6.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #!/usr/bin/env python3
  2. # Uses the Python BDF format bitmap font parser:
  3. # https://github.com/tomchen/bdfparser
  4. #
  5. # And the pillow Python Imaging Library:
  6. # https://github.com/python-pillow/Pillow
  7. #
  8. # ----------------------------------------------------------------------------
  9. # "THE BEER-WARE LICENSE" (Revision 42):
  10. # <xythobuz@xythobuz.de> wrote this file. As long as you retain this notice
  11. # you can do whatever you want with this stuff. If we meet some day, and you
  12. # think this stuff is worth it, you can buy me a beer in return. Thomas Buck
  13. # ----------------------------------------------------------------------------
  14. from bdfparser import Font
  15. from PIL import Image
  16. import os
  17. import time
  18. class DrawText:
  19. def __init__(self, g, fg = (255, 255, 255), bg = (0, 0, 0), c = (0, 255, 0)):
  20. self.gui = g
  21. self.fg = fg
  22. self.bg = bg
  23. self.color = c
  24. scriptDir = os.path.dirname(os.path.realpath(__file__))
  25. fontDir = os.path.join(scriptDir, "fonts")
  26. self.fonts = {}
  27. for f in os.listdir(os.fsencode(fontDir)):
  28. filename = os.fsdecode(f)
  29. if not filename.lower().endswith(".bdf"):
  30. continue
  31. # TODO hard-coded per-font offsets and spacing adjustment
  32. offset = 0
  33. spacing = 0
  34. if filename == "iv18x16u.bdf":
  35. offset = 6
  36. elif filename == "ib8x8u.bdf":
  37. offset = 10
  38. elif filename == "lemon.bdf":
  39. offset = 8
  40. spacing = -3
  41. elif filename == "antidote.bdf":
  42. offset = 9
  43. spacing = -1
  44. elif filename == "uushi.bdf":
  45. offset = 8
  46. spacing = -2
  47. elif filename == "tom-thumb.bdf":
  48. offset = 12
  49. spacing = 2
  50. font = Font(os.path.join(fontDir, filename))
  51. data = (font, offset, {}, spacing)
  52. self.fonts[filename[:-4]] = data
  53. def getGlyph(self, c, font):
  54. if not isinstance(font, str):
  55. # fall-back to first available font
  56. f, offset, cache, spacing = next(iter(self.fonts))
  57. else:
  58. # users font choice
  59. f, offset, cache, spacing = self.fonts[font]
  60. # only render glyphs once, cache resulting image data
  61. if not c in cache:
  62. g = f.glyph(c).draw()
  63. # invert color
  64. g = g.replace(1, 2).replace(0, 1).replace(2, 0)
  65. # render to pixel data
  66. bytesdict = {
  67. 0: int(self.fg[2] << 16 | self.fg[1] << 8 | self.fg[0]).to_bytes(4, byteorder = "little"),
  68. 1: int(self.bg[2] << 16 | self.bg[1] << 8 | self.bg[0]).to_bytes(4, byteorder = "little"),
  69. 2: int(self.color[2] << 16 | self.color[1] << 8 | self.color[0]).to_bytes(4, byteorder = "little"),
  70. }
  71. img = Image.frombytes('RGBA',
  72. (g.width(), g.height()),
  73. g.tobytes('RGBA', bytesdict))
  74. cache[c] = img
  75. return (cache[c], offset, spacing)
  76. def drawGlyph(self, g, xOff, yOff, spacing):
  77. if xOff >= self.gui.width:
  78. return
  79. for x in range(0, g.width):
  80. for y in range(0, g.height):
  81. xTarget = xOff + x
  82. if (xTarget < 0) or (xTarget >= self.gui.width):
  83. continue
  84. p = g.getpixel((x, y))
  85. self.gui.set_pixel(xTarget, yOff + y, p)
  86. for x in range(0, spacing):
  87. for y in range(0, g.height):
  88. self.gui.set_pixel(xOff + x + g.width, yOff + y, self.bg)
  89. def text(self, s, f, offset = 0, earlyAbort = True, yOff = 0):
  90. w = 0
  91. for c in s:
  92. xOff = -offset + w
  93. if earlyAbort:
  94. if xOff >= self.gui.width:
  95. break
  96. g, y, spacing = self.getGlyph(c, f)
  97. w += g.width + spacing
  98. if xOff >= -16: # some wiggle room so chars dont disappear
  99. self.drawGlyph(g, xOff, y + yOff, spacing)
  100. return w
  101. class ScrollText:
  102. def __init__(self, g, t, f, i = 1, s = 75, fg = (255, 255, 255), bg = (0, 0, 0)):
  103. self.gui = g
  104. self.drawer = DrawText(self.gui, fg, bg)
  105. self.iterations = i
  106. self.speed = 1.0 / s
  107. self.setText(t, f)
  108. self.restart()
  109. def setText(self, t, f):
  110. self.text = t
  111. self.font = f
  112. self.width = self.drawer.text(self.text, self.font, 0, False)
  113. def restart(self):
  114. self.offset = -self.gui.width
  115. self.last = time.time()
  116. self.count = 0
  117. def finished(self):
  118. return (self.count >= self.iterations)
  119. def draw(self):
  120. if (time.time() - self.last) > self.speed:
  121. off = (time.time() - self.last) / self.speed
  122. self.offset += int(off)
  123. self.last = time.time()
  124. if self.offset >= self.width:
  125. self.offset = -self.gui.width
  126. self.count += 1
  127. self.drawer.text(self.text, self.font, self.offset, True)
  128. if __name__ == "__main__":
  129. import util
  130. t = util.getTarget()
  131. from splash import SplashScreen
  132. splash = SplashScreen(t)
  133. t.loop_start()
  134. splash.draw()
  135. t.loop_end()
  136. from manager import Manager
  137. m = Manager(t)
  138. m.add(ScrollText(t, "tom-thumb Abcdefgh tom-thumb", "tom-thumb",
  139. 1, 75, (0, 255, 0), (0, 0, 25)))
  140. m.add(ScrollText(t, "antidote Abcdefgh antidote", "antidote",
  141. 1, 75, (0, 255, 0), (0, 0, 25)))
  142. m.add(ScrollText(t, "uushi Abcdefgh uushi", "uushi",
  143. 1, 75, (0, 255, 0), (0, 0, 25)))
  144. m.add(ScrollText(t, "lemon Abcdefgh lemon", "lemon",
  145. 1, 75, (0, 255, 0), (0, 0, 25)))
  146. m.add(ScrollText(t, "ib8x8u Abcdefgh ib8x8u", "ib8x8u",
  147. 1, 75, (0, 255, 0), (0, 0, 25)))
  148. m.add(ScrollText(t, "iv18x16u Abcdefgh iv18x16u", "iv18x16u",
  149. 1, 75, (0, 255, 0), (0, 0, 25)))
  150. m.restart()
  151. t.debug_loop(m.draw)