137 lines
3.5 KiB
Python
137 lines
3.5 KiB
Python
|
# Alexander Bass
|
||
|
# Created 4/10/24
|
||
|
# Last Edited 4/13/24
|
||
|
import time
|
||
|
from math import pi, cos, sin, sqrt # noqa: F401
|
||
|
from point import Point, Rotator
|
||
|
from grass_donut import DonutEntity
|
||
|
from real_donut import RealDonutEntity
|
||
|
from entity import Entity, PointBlobEntity
|
||
|
from util import to_rad
|
||
|
|
||
|
WIDTH = 150
|
||
|
HEIGHT = 100
|
||
|
DEPTH = WIDTH
|
||
|
HALF_WIDTH = WIDTH / 2
|
||
|
HALF_HEIGHT = HEIGHT // 2
|
||
|
HALF_DEPTH = DEPTH // 2
|
||
|
|
||
|
NEGATIVE_DEPTH = -DEPTH
|
||
|
|
||
|
|
||
|
def world_to_screen(p_x, p_y, p_z):
|
||
|
s_x = round(p_x + HALF_WIDTH)
|
||
|
s_y = round(p_y + HALF_HEIGHT)
|
||
|
s_z = (p_z + HALF_DEPTH) / DEPTH
|
||
|
return s_x, s_y, s_z
|
||
|
|
||
|
|
||
|
def format_grid(entities, screen):
|
||
|
for x in range(WIDTH):
|
||
|
for y in range(HEIGHT):
|
||
|
screen[y][x] = None
|
||
|
|
||
|
for entity in entities:
|
||
|
for p in entity.get_points():
|
||
|
p_x, p_y, p_z = p.get_xyz()
|
||
|
s_x, s_y, s_z = world_to_screen(p_x, p_y, p_z)
|
||
|
if s_x in range(WIDTH) and s_y in range(HEIGHT):
|
||
|
val = screen[s_y][s_x]
|
||
|
if val is None:
|
||
|
red, green, blue = p.get_rgb()
|
||
|
screen[s_y][s_x] = (red, green, blue, s_z)
|
||
|
elif val[3] < s_z:
|
||
|
red, green, blue = p.get_rgb()
|
||
|
screen[s_y][s_x] = (red, green, blue, s_z)
|
||
|
|
||
|
s = ""
|
||
|
last_color = (0, 0, 0)
|
||
|
for y in range(HEIGHT):
|
||
|
for x in range(WIDTH):
|
||
|
cell = screen[y][x]
|
||
|
if cell is None or 0 > cell[3] > 255:
|
||
|
s += " "
|
||
|
continue
|
||
|
|
||
|
red, green, blue, depth = cell
|
||
|
scale = depth
|
||
|
red *= scale
|
||
|
green *= scale
|
||
|
blue *= scale
|
||
|
if (red, green, blue) != last_color:
|
||
|
s += f"\033[38;2;{round(red)};{round(green)};{round(blue)}m"
|
||
|
last_color = (red, green, blue)
|
||
|
s += "██"
|
||
|
s += "\n"
|
||
|
return s
|
||
|
|
||
|
|
||
|
def update_entities(entities, t):
|
||
|
for e in entities:
|
||
|
e.update(t)
|
||
|
|
||
|
|
||
|
class AxisEntity(PointBlobEntity):
|
||
|
def __init__(self):
|
||
|
self.points = []
|
||
|
for x in range(WIDTH // 2 + 1):
|
||
|
tx = x - WIDTH / 4
|
||
|
for y in range(WIDTH // 2 + 1):
|
||
|
ty = y - WIDTH / 4
|
||
|
self.add_point(Point().set_xyz(0, tx, ty).set_color(1, 1, 0))
|
||
|
|
||
|
r = (
|
||
|
Rotator()
|
||
|
.rotate_z(to_rad(80))
|
||
|
.rotate_y(to_rad(30))
|
||
|
.rotate_x(to_rad(30))
|
||
|
.build()
|
||
|
)
|
||
|
|
||
|
self.rotate(r)
|
||
|
|
||
|
self.rotor = Rotator().rotate_z(to_rad(0.6)).rotate_y(to_rad(0.06)).build()
|
||
|
|
||
|
def update(self, t):
|
||
|
t = t + 6 * 30
|
||
|
|
||
|
self.rotate(self.rotor)
|
||
|
for p in self.points:
|
||
|
x, y, z = p.get_xyz()
|
||
|
x, y = abs(x), abs(y)
|
||
|
p.set_color(255 * abs(sin(x * t / 99)), 255 * abs(sin(y * t / 100)), 0)
|
||
|
|
||
|
|
||
|
class Origin(PointBlobEntity):
|
||
|
def __init__(self):
|
||
|
super().__init__()
|
||
|
self.points = [Point().set_xyz(0, 0, 0).set_color(255, 0, 0)]
|
||
|
|
||
|
|
||
|
def main():
|
||
|
entities = []
|
||
|
# entities.append(AxisEntity())
|
||
|
# entities.append(Origin())
|
||
|
entities.append(RealDonutEntity())
|
||
|
entities.append(DonutEntity())
|
||
|
t = 1
|
||
|
last_time = time.time()
|
||
|
dt = 0
|
||
|
|
||
|
grid = [[None for x in range(WIDTH)] for y in range(HEIGHT)]
|
||
|
while True:
|
||
|
print("\033c", end="")
|
||
|
print(format_grid(entities, grid))
|
||
|
|
||
|
update_entities(entities, t)
|
||
|
current_time = time.time()
|
||
|
dt = current_time - last_time
|
||
|
wait = 1 / 45 - dt
|
||
|
last_time = current_time
|
||
|
time.sleep(max(wait, 0))
|
||
|
|
||
|
t += 1 + 1 / 45 - dt
|
||
|
|
||
|
|
||
|
main()
|