diff --git a/example.py b/example.py new file mode 100644 index 0000000..b574066 --- /dev/null +++ b/example.py @@ -0,0 +1,28 @@ +from pytermrender import * +Screen = TermScreen(height=24, width=80, framerate=30) + +#not strictly needed, but useful +def tick(): + Screen.frame_no+=1 + +def setup(): + print("Setup") + print("Clearing") + clearScreen() + pass + + +def teardown(): + print("Teardown") + print("Teardown Complete") + pass + + +def draw(): + clearScreen() + clearAllBuffers() + drawBox(0,0,Screen.width,Screen.height,'#') + printBuffer(1,1,str(Screen.framerate)+'fps '+str(Screen.frame_no)) + + +run() diff --git a/example2.py b/example2.py new file mode 100644 index 0000000..423303d --- /dev/null +++ b/example2.py @@ -0,0 +1,59 @@ +from pytermrender import * +from colorama import Fore, Back, Style + +BPM=112 +BEAT_SUB=16 +FRAMERATE=(BPM*BEAT_SUB/60) + +Screen = TermScreen(height=24, width=64, framerate=FRAMERATE) + +cursorX=1 +cooldown=0 +def tick(): + global cursorX,cooldown + Screen.frame_no+=1 + cursorX=cursorX+1 + if cursorX >= Screen.width-1: + cursorX=0 + if cursorX % 12 == 0: + cooldown=8 + else: + cooldown-=1 + return + + +def setup(): + print("Setup") + print("Clearing") + clearScreen() + return + + +def teardown(): + print("Teardown") + print("Teardown Complete") + return + + +def draw(): + clearScreen() + clearAllBuffers() + for y in range(Screen.height): + for x in range(Screen.width): + if x == 0 or x == Screen.width-1: + Screen.buffer_char[y][x]='#' + if y == 0 or y == Screen.height-1: + Screen.buffer_char[y][x]='#' + printBuffer(0,3,"1234567890123456789012345678901234567890123456789012345678901234") + printBuffer(0,4,"0 1 2 3 4 5 6 ") + #printBuffer(0,4,"2 6 8 6 4 6 8 6 2 6 8 6 4 6 8 6 ") + clearLine(5) + Screen.buffer_char[5][cursorX] = "x" + if cooldown > 0: + Screen.buffer_color[5][cursorX] = Fore.RED + + printBuffer(1,1,Screen.frame_no) + printBuffer(8,1,Screen.framerate) + + +run() diff --git a/pytermrender.py b/pytermrender.py new file mode 100644 index 0000000..1f7ecff --- /dev/null +++ b/pytermrender.py @@ -0,0 +1,161 @@ +import __main__ +import time, math +from colorama import Fore, Back, Style +import functools +#from dataclasses import dataclass +printr = functools.partial(print, end="") + +## Definitions + + +class RenderException(Exception): + pass + + +class TermScreen: + width: int + height: int + framerate: float + frame_no: int = 0 + buffers: list = ["char", "color"] + tickers: dict + def __init__(self, *, width: int = 80, height: int = 24, framerate: float = 30.0): + self.width=width + self.height=height + self.framerate=framerate + self.buffer_char = [[" "]*self.width for i in range(self.height)] + self.buffer_color = [[Style.RESET_ALL]*self.width for i in range(self.height)] + return + + def reset_buffer(self, buffer="char"): + if buffer not in self.buffers: + raise RenderException("Buffer Does not exist") + match buffer: + case "char": + self.buffer_char = [[" "]*self.width for i in range(self.height)] + case "color": + self.buffer_color = [[Style.RESET_ALL]*self.width for i in range(self.height)] + return + + def render(self): + for y in range(self.height): + for x in range(self.width): + printr(self.buffer_color[y][x]) + printr(self.buffer_char[y][x]) + print() #print \n + return + +def framerateMaker(func, perSec): + interval = 1.0 / perSec + while True: + start_time = time.time() + func() + elapsed = time.time() - start_time + if elapsed < interval: + time.sleep(interval-elapsed) + return + +def renderLoop(): + global Screen + pro_tick() + pro_draw() + Screen.render() + return +################ + +## Library Functions + +def clearScreen(): + printr('\033[2J') + +def clearBuffer(buf="char"): + global Screen + Screen.reset_buffer(buf) + return + +def clearAllBuffers(): + global Screen + for buf in Screen.buffers: + Screen.reset_buffer(buf) + return + +def printBuffer(x, y, val): + global Screen + string=str(val) + if len(string) > Screen.width-x: + raise RenderException("Too Long to fit in screen") + for i, char in enumerate(string): + Screen.buffer_char[y][x+i]=char + +def clearLine(y): + global Screen + Screen.buffer_char[y]=[" "]*Screen.width + +def drawBox(x,y,width,height,char): + global Screen + if x+width > Screen.width or y+height > Screen.height: + raise RenderException("Box too BIG") + for w_x in range(width): + for w_y in range(height): + if (w_x==0 or w_x==width-1) or (w_y==0 or w_y==height-1): + Screen.buffer_char[y+w_y][x+w_x] = char + +#################### + + + +def tick(): + global Screen + Screen.frame_no+=1 + +def setup(): + print("Setup") + clearScreen() + clearAllBuffers() + return + + +def teardown(): + print("Default Teardown") + return + + +def draw(): + return + +def run(): + global Screen + global pro_tick, pro_draw + + if hasattr(__main__, "Screen"): + Screen = __main__.Screen + else: + raise RenderException("Screen Not defined") + + if hasattr(__main__, "setup"): + pro_setup = __main__.setup + else: + pro_setup = setup + + if hasattr(__main__, "teardown"): + pro_teardown = __main__.teardown + else: + pro_teardown = teardown + + if hasattr(__main__, "tick"): + pro_tick = __main__.tick + else: + pro_tick = tick + + if hasattr(__main__, "draw"): + pro_draw = __main__.draw + else: + pro_draw = draw + + pro_setup() + try: + framerateMaker(renderLoop, Screen.framerate) + except KeyboardInterrupt: + pass + pro_teardown() +