hook vtk directly
This commit is contained in:
parent
070c1290b9
commit
c074cfce30
@ -146,7 +146,7 @@ async def main():
|
||||
plotter.add_mesh(line, color="red", line_width=2)
|
||||
|
||||
|
||||
#kitty.hide_cursor()
|
||||
kitty.hide_cursor()
|
||||
try:
|
||||
#asyncio.run(plotter.run())
|
||||
await plotter.run()
|
||||
|
@ -5,6 +5,11 @@ import select
|
||||
import sys
|
||||
import termios
|
||||
import tty
|
||||
import vtk
|
||||
from vtk.util import numpy_support
|
||||
import numpy as np
|
||||
from io import BytesIO
|
||||
from PIL import Image
|
||||
|
||||
import pyvista as pv
|
||||
|
||||
@ -17,13 +22,14 @@ class TerminalPlotter(pv.Plotter):
|
||||
self.width = width
|
||||
self.height = height
|
||||
self._running = True
|
||||
self._needs_render = True
|
||||
self._render_complete = False
|
||||
self._rendering = False
|
||||
self._render_pending = True
|
||||
self.w2i_filter = vtk.vtkWindowToImageFilter()
|
||||
self.w2i_filter.SetInputBufferTypeToRGBA()
|
||||
self.w2i_filter.ReadFrontBufferOff()
|
||||
self.w2i_filter.SetInput(self.ren_win)
|
||||
self.set_background([0.0, 0.0, 0.0])
|
||||
self.add_on_render_callback(self._on_render)
|
||||
# if we are too close to the bottom of the terminal, create some space.
|
||||
# transparency
|
||||
self.ren_win.SetAlphaBitPlanes(1)
|
||||
self.ren_win.SetMultiSamples(0)
|
||||
|
||||
async def initialize(self):
|
||||
h_pix, _ = await kitty.get_terminal_cell_size()
|
||||
@ -38,14 +44,15 @@ class TerminalPlotter(pv.Plotter):
|
||||
print("\n" * self.needed_lines, end="")
|
||||
kitty.set_position(self.start_y, self.start_x)
|
||||
|
||||
|
||||
async def render_to_kitty(self):
|
||||
self.render()
|
||||
buf = io.BytesIO()
|
||||
self.screenshot(buf, transparent_background=True, window_size=(self.width, self.height))
|
||||
await kitty.draw_to_terminal(buf)
|
||||
# print("y:", self.start_y, "rows:", self.rows, end="")
|
||||
kitty.set_position(self.start_y, self.start_x)
|
||||
async def _handle_key(self, c):
|
||||
if c == "a":
|
||||
self.camera.Azimuth(10)
|
||||
elif c == "d":
|
||||
self.camera.Azimuth(-10)
|
||||
elif c == "w":
|
||||
self.camera.Elevation(10)
|
||||
elif c == "s":
|
||||
self.camera.Elevation(-10)
|
||||
|
||||
async def _input_loop(self):
|
||||
fd = sys.stdin.fileno()
|
||||
@ -64,60 +71,37 @@ class TerminalPlotter(pv.Plotter):
|
||||
finally:
|
||||
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
||||
|
||||
async def _handle_key(self, c):
|
||||
if c == "a":
|
||||
self.camera.Azimuth(10)
|
||||
elif c == "d":
|
||||
self.camera.Azimuth(-10)
|
||||
elif c == "w":
|
||||
self.camera.Elevation(10)
|
||||
elif c == "s":
|
||||
self.camera.Elevation(-10)
|
||||
self._needs_render = True
|
||||
# await self.render_to_kitty()
|
||||
|
||||
def _on_render(self, *args):
|
||||
"""Callback that runs after each render."""
|
||||
self._rendering = False
|
||||
self._render_complete = True
|
||||
|
||||
async def _display_loop(self):
|
||||
"""Loop that captures the screen and updates the terminal after rendering."""
|
||||
while self._running:
|
||||
if self._render_complete:
|
||||
self._render_complete = False
|
||||
buf = io.BytesIO()
|
||||
# Safe: Screenshot only after render is confirmed complete
|
||||
self.screenshot(buf, transparent_background=True, window_size=(self.width, self.height))
|
||||
await kitty.draw_to_terminal(buf)
|
||||
kitty.set_position(self.start_y, self.start_x)
|
||||
await asyncio.sleep(0.001)
|
||||
|
||||
async def _render_loop(self):
|
||||
while self._running:
|
||||
if self._needs_render and not self._rendering:
|
||||
self._rendering = True
|
||||
self._needs_render = False
|
||||
self.update() # triggers a render and calls _on_render
|
||||
await asyncio.sleep(0.001)
|
||||
# keep renedring the scene
|
||||
self.ren_win.Render()
|
||||
# Update the filter to grab the current buffer
|
||||
self.w2i_filter.Modified()
|
||||
self.w2i_filter.Update()
|
||||
|
||||
async def _display_in_terminal(self, buf):
|
||||
await kitty.draw_to_terminal(buf)
|
||||
kitty.set_position(self.start_y, self.start_x)
|
||||
vtk_image = self.w2i_filter.GetOutput()
|
||||
|
||||
width, height, _ = vtk_image.GetDimensions()
|
||||
vtk_array = vtk_image.GetPointData().GetScalars()
|
||||
arr = numpy_support.vtk_to_numpy(vtk_array)
|
||||
|
||||
# Reshape the array to height x width x channels (probably 3 or 4)
|
||||
arr = arr.reshape(height, width, -1)
|
||||
|
||||
# Flip vertically because VTK's origin is bottom-left
|
||||
arr = np.flip(arr, axis=0)
|
||||
img = Image.fromarray(arr)
|
||||
buffer: BytesIO = BytesIO()
|
||||
img.save(buffer, format="PNG")
|
||||
await kitty.draw_to_terminal(buffer)
|
||||
kitty.set_position(self.start_y, self.start_x)
|
||||
|
||||
async def run(self):
|
||||
await self.initialize()
|
||||
self.iren.initialize()
|
||||
self._needs_render = True
|
||||
tasks = [
|
||||
asyncio.create_task(self._input_loop()),
|
||||
asyncio.create_task(self._render_loop()),
|
||||
asyncio.create_task(self._display_loop()),
|
||||
]
|
||||
await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
|
||||
self._running = False
|
||||
|
||||
|
||||
#await self.render_to_kitty()
|
||||
#await self._input_loop()
|
||||
|
Loading…
Reference in New Issue
Block a user