File: plasma.py

package info (click to toggle)
python-asciimatics 1.15.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 4,488 kB
  • sloc: python: 15,713; sh: 8; makefile: 2
file content (77 lines) | stat: -rw-r--r-- 2,507 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
"""
This module implements a plasma effect renderer.
"""

from math import sin, pi, sqrt

from asciimatics.renderers.base import DynamicRenderer
from asciimatics.screen import Screen


class Plasma(DynamicRenderer):
    """
    Renderer to create a "plasma" effect using sinusoidal functions.

    The implementation here uses the same techniques described in
    http://lodev.org/cgtutor/plasma.html
    """

    # The ASCII grey scale from darkest to lightest.
    _greyscale = ' .:;rsA23hHG#9&@'

    # Colours for different environments
    _palette_8 = [
        (Screen.COLOUR_BLUE, Screen.A_NORMAL),
        (Screen.COLOUR_BLUE, Screen.A_NORMAL),
        (Screen.COLOUR_MAGENTA, Screen.A_NORMAL),
        (Screen.COLOUR_MAGENTA, Screen.A_NORMAL),
        (Screen.COLOUR_RED, Screen.A_NORMAL),
        (Screen.COLOUR_RED, Screen.A_BOLD),
    ]
    _palette_256 = [
        (18, 0),
        (19, 0),
        (20, 0),
        (21, 0),
        (57, 0),
        (93, 0),
        (129, 0),
        (201, 0),
        (200, 0),
        (199, 0),
        (198, 0),
        (197, 0),
        (196, 0),
        (196, 0),
        (196, 0),
    ]

    def __init__(self, height, width, colours):
        """
        :param height: Height of the box to contain the plasma.
        :param width: Width of the box to contain the plasma.
        :param colours: Number of colours the screen supports.
        """
        super().__init__(height, width)
        self._palette = self._palette_256 if colours >= 256 else self._palette_8
        self._t = 0

    def _render_now(self):
        # Internal function for creating a sine wave radiating out from a point
        def f(x1, y1, xp, yp, n):
            return sin(sqrt((x1 - self._canvas.width * xp) ** 2 +
                            4 * ((y1 - self._canvas.height * yp) ** 2)) * pi / n)

        self._t += 1
        for y in range(self._canvas.height - 1):
            for x in range(self._canvas.width - 1):
                value = abs(f(x + self._t / 3, y, 1 / 4, 1 / 3, 15) +
                            f(x, y, 1 / 8, 1 / 5, 11) +
                            f(x, y + self._t / 3, 1 / 2, 1 / 5, 13) +
                            f(x, y, 3 / 4, 4 / 5, 13)) / 4.0
                fg, attr = self._palette[
                    int(round(value * (len(self._palette) - 1)))]
                char = self._greyscale[int((len(self._greyscale) - 1) * value)]
                self._write(char, x, y, fg, attr, 0)

        return self._plain_image, self._colour_map