Python RGB Matrix games and animations https://www.xythobuz.de/ledmatrix_v2.html
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. #!/usr/bin/env python3
  2. from bdfparser import Font
  3. from PIL import Image
  4. import os
  5. import time
  6. class DrawText:
  7. def __init__(self, g):
  8. self.gui = g
  9. scriptDir = os.path.dirname(os.path.realpath(__file__))
  10. fontDir = os.path.join(scriptDir, "fonts")
  11. self.fonts = []
  12. for f in os.listdir(os.fsencode(fontDir)):
  13. filename = os.fsdecode(f)
  14. if not filename.lower().endswith(".bdf"):
  15. continue
  16. font = Font(os.path.join(fontDir, filename))
  17. #print(f"{filename} global size is "
  18. # f"{font.headers['fbbx']} x {font.headers['fbby']} (pixel), "
  19. # f"it contains {len(font)} glyphs.")
  20. # TODO hard-coded per-font offsets
  21. offset = 0
  22. if filename == "iv18x16u.bdf":
  23. offset = 6
  24. data = (font, offset, {})
  25. self.fonts.append(data)
  26. def getGlyph(self, c):
  27. f, o, cache = self.fonts[0] # TODO selection of fonts
  28. # only render glyphs once, cache resulting image data
  29. if not c in cache:
  30. g = f.glyph(c).draw()
  31. # invert color
  32. g = g.replace(1, 2).replace(0, 1).replace(2, 0)
  33. # render to pixel data
  34. img = Image.frombytes('RGBA',
  35. (g.width(), g.height()),
  36. g.tobytes('RGBA'))
  37. cache[c] = img
  38. return (cache[c], o)
  39. def drawGlyph(self, g, xOff, yOff):
  40. if xOff >= self.gui.width:
  41. return
  42. for x in range(0, g.width):
  43. for y in range(0, g.height):
  44. xTarget = xOff + x
  45. if (xTarget < 0) or (xTarget >= self.gui.width):
  46. continue
  47. p = g.getpixel((x, y))
  48. self.gui.set_pixel(xTarget, yOff + y, p)
  49. def text(self, s, offset = 0, earlyAbort = True):
  50. w = 0
  51. for c in s:
  52. xOff = -offset + w
  53. if earlyAbort:
  54. if xOff >= self.gui.width:
  55. break
  56. g, y = self.getGlyph(c)
  57. w += g.width
  58. if xOff >= -10: # some wiggle room so chars dont disappear
  59. self.drawGlyph(g, xOff, y)
  60. return w
  61. class ScrollText:
  62. def __init__(self, g, t, i = 1, s = 100):
  63. self.gui = g
  64. self.drawer = DrawText(self.gui)
  65. self.text = t
  66. self.iterations = i
  67. self.speed = 1.0 / s
  68. self.width = self.drawer.text(self.text, 0, False)
  69. self.restart()
  70. def restart(self):
  71. self.offset = -self.gui.width
  72. self.last = time.time()
  73. self.count = 0
  74. def finished(self):
  75. return (self.count >= self.iterations)
  76. def draw(self):
  77. if (time.time() - self.last) > self.speed:
  78. self.last = time.time()
  79. self.offset = (self.offset + 1)
  80. if self.offset >= self.width:
  81. self.offset = -self.gui.width
  82. self.count += 1
  83. self.drawer.text(self.text, self.offset, True)
  84. if __name__ == "__main__":
  85. import platform
  86. t = None
  87. if platform.machine() == "armv7l":
  88. from pi import PiMatrix
  89. t = PiMatrix()
  90. else:
  91. from test import TestGUI
  92. t = TestGUI()
  93. d = ScrollText(t, "Hello, World!")
  94. t.debug_loop(d.draw)