spinning tetrahedron :3
This commit is contained in:
parent
69ceed6c28
commit
ec63b97756
52
kglobe.py
52
kglobe.py
@ -1,42 +1,26 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
from kitty import draw_to_terminal
|
from kitty import draw_to_terminal, get_position, set_position, hide_cursor, show_cursor #, draw_animation
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
import numpy as np
|
import pyvista as pv
|
||||||
import trimesh
|
|
||||||
import pyrender
|
|
||||||
|
|
||||||
|
sphere = pv.Tetrahedron()# Sphere()
|
||||||
|
pl=pv.Plotter(off_screen=True)
|
||||||
|
pl.add_mesh(sphere, color='tan', show_edges=False)
|
||||||
|
|
||||||
sphere = trimesh.creation.icosphere(subdivisions=3, radius=1.0)
|
hide_cursor()
|
||||||
# create mesh
|
y, x = get_position()
|
||||||
mesh = pyrender.Mesh.from_trimesh(sphere, smooth=True, wireframe=True)
|
print('\n' * 25, end='')
|
||||||
|
|
||||||
# Create a scene and add the mesh
|
frames = []
|
||||||
scene = pyrender.Scene(bg_color = [0, 0, 0, 0])
|
try:
|
||||||
scene.add(mesh)
|
while True:
|
||||||
|
pl.camera.Azimuth(1)
|
||||||
# Add a directional light to illuminate the sphere
|
image = pl.screenshot(transparent_background=True, window_size=(512, 512))
|
||||||
light = pyrender.DirectionalLight(color=np.ones(3), intensity=3.0)
|
frames.append(Image.fromarray(image))
|
||||||
light_pose = np.eye(4)
|
set_position(y-25, x)
|
||||||
light_pose[:3, 3] = [0, 2, 2] # light from above and in front
|
draw_to_terminal(Image.fromarray(image))
|
||||||
scene.add(light, pose=light_pose)
|
finally:
|
||||||
|
show_cursor()
|
||||||
# Add a camera
|
|
||||||
camera = pyrender.PerspectiveCamera(yfov=np.pi / 3.0)
|
|
||||||
camera_pose = np.array([
|
|
||||||
[1.0, 0.0, 0.0, 0.0],
|
|
||||||
[0.0, 1.0, 0.0, 0.0],
|
|
||||||
[0.0, 0.0, 1.0, 3.0], # Pull camera back
|
|
||||||
[0.0, 0.0, 0.0, 1.0]
|
|
||||||
])
|
|
||||||
scene.add(camera, pose=camera_pose)
|
|
||||||
|
|
||||||
r = pyrender.OffscreenRenderer(512, 512)
|
|
||||||
flags = pyrender.RenderFlags.RGBA
|
|
||||||
color, depth = r.render(scene, flags=flags)
|
|
||||||
#
|
|
||||||
im = Image.fromarray((color)) # .new("RGBA", (512, 512), (0, 0, 0, 0) )
|
|
||||||
|
|
||||||
draw_to_terminal(im)
|
|
||||||
|
64
kitty.py
64
kitty.py
@ -1,5 +1,8 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import termios
|
||||||
|
import tty
|
||||||
from base64 import standard_b64encode
|
from base64 import standard_b64encode
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
@ -8,7 +11,7 @@ from PIL import Image, ImageDraw
|
|||||||
def draw_to_terminal(img: Image.Image) -> None:
|
def draw_to_terminal(img: Image.Image) -> None:
|
||||||
buffer: BytesIO = BytesIO()
|
buffer: BytesIO = BytesIO()
|
||||||
img.save(buffer, format='PNG')
|
img.save(buffer, format='PNG')
|
||||||
write_chunked(a='T', f=100, data=buffer.getvalue())
|
write_chunked(a='T', i=1, f=100, q=2, data=buffer.getvalue())
|
||||||
|
|
||||||
def serialize_gr_command(**cmd):
|
def serialize_gr_command(**cmd):
|
||||||
payload = cmd.pop('payload', None)
|
payload = cmd.pop('payload', None)
|
||||||
@ -32,6 +35,65 @@ def write_chunked(**cmd):
|
|||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
cmd.clear()
|
cmd.clear()
|
||||||
|
|
||||||
|
def hide_cursor():
|
||||||
|
sys.stdout.write("\x1b[?25l")
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
def show_cursor():
|
||||||
|
sys.stdout.write("\x1b[?25h")
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
def set_position(y, x):
|
||||||
|
sys.stdout.write(f"\x1b[{y};{x}H")
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
def get_position():
|
||||||
|
# Save the current terminal settings
|
||||||
|
fd = sys.stdin.fileno()
|
||||||
|
old_settings = termios.tcgetattr(fd)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Set terminal to raw mode
|
||||||
|
tty.setraw(fd)
|
||||||
|
|
||||||
|
# Send the ESC[6n command to request cursor position
|
||||||
|
sys.stdout.write("\x1b[6n")
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
# Read the response: ESC [ row ; col R
|
||||||
|
response = ''
|
||||||
|
while True:
|
||||||
|
ch = sys.stdin.read(1)
|
||||||
|
response += ch
|
||||||
|
if ch == 'R':
|
||||||
|
break
|
||||||
|
|
||||||
|
finally:
|
||||||
|
# Restore the terminal settings
|
||||||
|
termios.tcsetattr(fd, termios.TCSANOW, old_settings)
|
||||||
|
|
||||||
|
# Parse the response using regex
|
||||||
|
match = re.search(r'\[(\d+);(\d+)R', response)
|
||||||
|
if match:
|
||||||
|
y, x = map(int, match.groups())
|
||||||
|
return y, x
|
||||||
|
else:
|
||||||
|
raise ValueError("Failed to parse cursor position response")
|
||||||
|
|
||||||
|
|
||||||
|
# sys.stdout.write("\x1b[6n")
|
||||||
|
# sys.stdout.flush()
|
||||||
|
# response = ''
|
||||||
|
# while True:
|
||||||
|
# ch = sys.stdin.read(1)
|
||||||
|
# response += ch
|
||||||
|
# if ch == 'R':
|
||||||
|
# break
|
||||||
|
# match = re.search(r'\[(\d+);(\d+)R', response)
|
||||||
|
# if match:
|
||||||
|
# y, x = map(int, match.groups())
|
||||||
|
# return y, x
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
i = Image.new("RGB", (100, 100), (0, 0, 0))
|
i = Image.new("RGB", (100, 100), (0, 0, 0))
|
||||||
d = ImageDraw.Draw(i)
|
d = ImageDraw.Draw(i)
|
||||||
|
11
pyproject.toml
Normal file
11
pyproject.toml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[project]
|
||||||
|
name = "kglobe"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Add your description here"
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.13"
|
||||||
|
dependencies = [
|
||||||
|
"numpy<2",
|
||||||
|
"pyrender>=0.1.45",
|
||||||
|
"pyvista>=0.45.3",
|
||||||
|
]
|
Loading…
Reference in New Issue
Block a user