From c90938efbd93b0c800821b864d2cd7612e9eb756 Mon Sep 17 00:00:00 2001 From: Sunpy Date: Wed, 12 Feb 2020 13:11:57 +0100 Subject: [PATCH] A few shader samples --- main.py | 67 ++++--------------------------------------- pixel.py | 9 +++++- shaders/background.py | 8 ++++++ shaders/default.py | 11 +++++++ shaders/eyeblower.py | 40 ++++++++++++++++++++++++++ shaders/ripples.py | 20 +++++++++++++ shaders/wave.py | 53 ++++++++++++++++++++++++++++++++++ 7 files changed, 145 insertions(+), 63 deletions(-) create mode 100644 shaders/background.py create mode 100644 shaders/default.py create mode 100644 shaders/eyeblower.py create mode 100644 shaders/ripples.py create mode 100644 shaders/wave.py diff --git a/main.py b/main.py index fcd6fad..c1a75bb 100644 --- a/main.py +++ b/main.py @@ -2,72 +2,15 @@ import os import math -from pixel import Pixel, Screen +from pixel import Screen -WIDTH, HEIGHT = 100, 30 +from shaders import eyeblower + +WIDTH, HEIGHT = 100, 30 # Set to -1, -1 for dynamic resolution STD_HANDLE = 1 # Would want this to be 0, but it can cause issues -def shad_background(pixel: Pixel, x: int, y: int, time: float): - uv = (x / WIDTH, y / HEIGHT) - - h = math.sin(uv[0] * math.pi + uv[1] * 10.0 + time + math.cos(uv[0] * uv[1] + uv[1] * 7.1823) * math.sin(uv[0] * 14.2)) - pixel.background_color.set(h, h, h) - -def shad_wave(pixel: Pixel, x: int, y: int, time: float): # https://www.shadertoy.com/view/Wd23W3 - uv = (x / WIDTH, y / HEIGHT) - - def hsv2rgb(h, s, v) -> tuple: - r,g,b = 0,0,0 - - i = int(h * 6) - f = h * 6 - i - p = v * (1 - s) - q = v * (1 - f * s) - t = v * (1 - (1 - f) * s) - - o = i % 6 - - if o == 0: - r,g,b = v,t,p - elif o == 1: - r,g,b = q,v,p - elif o == 2: - r,g,b = p,v,t - elif o == 3: - r,g,b = p,q,v - elif o == 4: - r,g,b = t,p,v - else: - r,g,b = v,p,q - - return r, g, b - - def step(edge: float, value: float) -> float: - return 1.0 if value > edge else 0.0 - - def strip(h: float, thickness: float, y: float) -> float: - return step(y + h - thickness, step(1., y + h + thickness)) - - col = [0.0, 0.0, 0.0] - - f = 0.0 - while f < math.pi * 2: - a = strip(.5 + math.cos(uv[0] * 2. + time * 3.) * .15, - .005, - uv[1] + math.cos(uv[0] * 3. + time * 2. + f) * .25) - - _col = hsv2rgb(f / math.pi / 2., 1., 1.) - for i in range(3): - col[i] += a * _col[i] - - f += math.pi / 4. - - pixel.text_color.set(*col) - - screen = Screen(WIDTH, HEIGHT, STD_HANDLE, [ - shad_background - #shad_wave + eyeblower.main ]) screen.mainloop() \ No newline at end of file diff --git a/pixel.py b/pixel.py index 17accde..340085a 100644 --- a/pixel.py +++ b/pixel.py @@ -79,6 +79,8 @@ class Screen: self.time_start = datetime.datetime.now() self.buffer = "" + + self.dynamic = self.height < 0 and self.width < 0 def get_time(self): return (datetime.datetime.now() - self.time_start).total_seconds() @@ -95,6 +97,10 @@ class Screen: while True: width, height = os.get_terminal_size(self.std_handle) + + if self.dynamic: + self.width, self.height = width, height + if width < self.width or height < self.height: Screen.clear() print("Unable to print the screen, a terminal with %dx%d (and above) chars are required to continue" % (self.width, self.height)) @@ -103,10 +109,11 @@ class Screen: time = self.get_time() + resolution = (self.width, self.height) for y in range(self.height): for x in range(self.width): for render_func in self.render_funcs: - render_func(pixel, x, y, time) + render_func(pixel, resolution, (x, y), time) self.write(str(pixel)) pixel.reset() self.write("\x1b[0m\n") # newline diff --git a/shaders/background.py b/shaders/background.py new file mode 100644 index 0000000..e32d814 --- /dev/null +++ b/shaders/background.py @@ -0,0 +1,8 @@ +import math +from pixel import Pixel + +def main(pixel: Pixel, resolution: tuple, frag_coord: tuple, time: float): + uv = (frag_coord[0] / resolution[0], frag_coord[1] / resolution[1]) + + h = math.sin(uv[0] * math.pi + uv[1] * 10.0 + time + math.cos(uv[0] * uv[1] + uv[1] * 7.1823) * math.sin(uv[0] * 14.2)) + pixel.background_color.set(h, h, h) \ No newline at end of file diff --git a/shaders/default.py b/shaders/default.py new file mode 100644 index 0000000..0289551 --- /dev/null +++ b/shaders/default.py @@ -0,0 +1,11 @@ +import math +from pixel import Pixel + +def main(pixel: Pixel, resolution: tuple, frag_coord: tuple, time: float): + uv = (frag_coord[0] / resolution[0], frag_coord[1] / resolution[1]) + + pixel.background_color.set( + 0.5 + 0.5 * math.cos(time + uv[0]), + 0.5 + 0.5 * math.cos(time + uv[1] + 2), + 0.5 + 0.5 * math.cos(time + uv[0] + 4) + ) \ No newline at end of file diff --git a/shaders/eyeblower.py b/shaders/eyeblower.py new file mode 100644 index 0000000..e03aa17 --- /dev/null +++ b/shaders/eyeblower.py @@ -0,0 +1,40 @@ +import math +from pixel import Pixel + +FREQUENCY = 20.0 +COLOR_A = (1.0, 0.5, 0.9) +COLOR_B = (0.5, 0.1, 0.3) + +def distance(a: tuple, b: tuple) -> float: + if len(a) != len(b): + raise TypeError("Mismatching dimentional vector passed") + + dist = 0 + for i in range(len(a)): + d = b[i] - a[i] + dist += d * d + + return dist ** 0.5 + +def sign(v: float) -> float: + return 1.0 if v >= 0 else 0.0 + +def main(pixel: Pixel, resolution: tuple, frag_coord: tuple, time: float): # https://www.shadertoy.com/view/ldX3DN + uv = tuple(-1.0 + 2.0 * x for x in (frag_coord[0] / resolution[0], frag_coord[1] / resolution[1])) + + homo_coords = (uv[0], 2.0 * frag_coord[1] / resolution[0]) + + moving_origin1 = (math.sin(time * 0.7), math.sin(time * 1.7)) + moving_origin2 = (-math.cos(time * 2.0), -math.sin(time * 3.0)) + + wave_point1 = math.sin( distance(moving_origin1, homo_coords) * FREQUENCY ) + wave_point2 = math.sin( distance(moving_origin2, homo_coords) * FREQUENCY ) + + black_or_white1 = sign(wave_point1) + black_or_white2 = sign(wave_point2) + + composite = black_or_white1 * black_or_white2 + + col = tuple(max(COLOR_A[i] * composite, COLOR_B[i]) for i in range(3)) + + pixel.background_color.set( *col ) diff --git a/shaders/ripples.py b/shaders/ripples.py new file mode 100644 index 0000000..6dc6eff --- /dev/null +++ b/shaders/ripples.py @@ -0,0 +1,20 @@ +import math +from pixel import Pixel + +def main(pixel: Pixel, resolution: tuple, frag_coord: tuple, time: float): # https://www.shadertoy.com/view/ldX3zr + invAr = resolution[1] / resolution[0] + + uv = (frag_coord[0] / resolution[0], frag_coord[1] / resolution[1]) + + col = [*uv, 0.5 + 0.5 * math.sin(time)] + + x = 0.5 - uv[0] + y = (0.5 - uv[1]) * invAr + + r = -(x * x + y * y) + z = 1.0 + 0.5 * math.sin((r + time * 0.035) / 0.013) + + for i in range(3): + col[i] *= z + + pixel.background_color.set( *col ) \ No newline at end of file diff --git a/shaders/wave.py b/shaders/wave.py new file mode 100644 index 0000000..852c3fa --- /dev/null +++ b/shaders/wave.py @@ -0,0 +1,53 @@ +import math +from pixel import Pixel + +def main(pixel: Pixel, resolution: tuple, frag_coord: tuple, time: float): + uv = (frag_coord[0] / resolution[0], frag_coord[1] / resolution[1]) + + def hsv2rgb(h, s, v) -> tuple: + r,g,b = 0,0,0 + + i = int(h * 6) + f = h * 6 - i + p = v * (1 - s) + q = v * (1 - f * s) + t = v * (1 - (1 - f) * s) + + o = i % 6 + + if o == 0: + r,g,b = v,t,p + elif o == 1: + r,g,b = q,v,p + elif o == 2: + r,g,b = p,v,t + elif o == 3: + r,g,b = p,q,v + elif o == 4: + r,g,b = t,p,v + else: + r,g,b = v,p,q + + return r, g, b + + def step(edge: float, value: float) -> float: + return 1.0 if value > edge else 0.0 + + def strip(h: float, thickness: float, y: float) -> float: + return step(y + h - thickness, step(1., y + h + thickness)) + + col = [0.0, 0.0, 0.0] + + f = 0.0 + while f < math.pi * 2: + a = strip(.5 + math.cos(uv[0] * 2. + time * 3.) * .15, + .005, + uv[1] + math.cos(uv[0] * 3. + time * 2. + f) * .25) + + _col = hsv2rgb(f / math.pi / 2., 1., 1.) + for i in range(3): + col[i] += a * _col[i] + + f += math.pi / 4. + + pixel.background_color.set(*col) \ No newline at end of file