A (forked) rust crate for using Ratatui in a Bevy application.
at main 99 lines 3.1 kB view raw
1use bevy::{ 2 asset::RenderAssetUsages, 3 prelude::*, 4 render::render_resource::{Extent3d, TextureDimension, TextureFormat}, 5 window::WindowResized, 6}; 7 8use crate::RatatuiContext; 9 10/// A plugin that, rather than drawing to a terminal buffer, uses software rendering to build a 2D 11/// texture from the ratatui buffer, and displays the result in a window. 12pub struct WindowedPlugin; 13 14impl Plugin for WindowedPlugin { 15 fn build(&self, app: &mut App) { 16 app.add_systems(PostStartup, terminal_render_setup) 17 .add_systems(PreUpdate, handle_resize_messages) 18 .add_systems(Update, render_terminal_to_handle); 19 } 20} 21 22#[derive(Resource)] 23struct TerminalRender(Handle<Image>); 24 25/// A startup system that sets up the terminal 26pub fn terminal_render_setup( 27 mut commands: Commands, 28 softatui: ResMut<RatatuiContext>, 29 mut images: ResMut<Assets<Image>>, 30) -> Result { 31 commands.spawn(Camera2d); 32 // Create an image that we are going to draw into 33 let width = softatui.backend().get_pixmap_width() as u32; 34 let height = softatui.backend().get_pixmap_height() as u32; 35 let data = softatui.backend().get_pixmap_data_as_rgba(); 36 37 let image = Image::new( 38 Extent3d { 39 width, 40 height, 41 depth_or_array_layers: 1, 42 }, 43 TextureDimension::D2, 44 data, 45 TextureFormat::Rgba8UnormSrgb, 46 RenderAssetUsages::RENDER_WORLD | RenderAssetUsages::MAIN_WORLD, 47 ); 48 let handle = images.add(image); 49 commands.spawn(( 50 ImageNode::new(handle.clone()), 51 Node { 52 justify_self: JustifySelf::Center, 53 align_self: AlignSelf::Center, 54 ..default() 55 }, 56 )); 57 58 commands.insert_resource(TerminalRender(handle)); 59 60 Ok(()) 61} 62 63/// System that updates the terminal texture each frame 64fn render_terminal_to_handle( 65 softatui: ResMut<RatatuiContext>, 66 mut images: ResMut<Assets<Image>>, 67 my_handle: Res<TerminalRender>, 68) { 69 let width = softatui.backend().get_pixmap_width() as u32; 70 let height = softatui.backend().get_pixmap_height() as u32; 71 let data = softatui.backend().get_pixmap_data_as_rgba(); 72 73 let image = images.get_mut(&my_handle.0).expect("Image not found"); 74 *image = Image::new( 75 Extent3d { 76 width, 77 height, 78 depth_or_array_layers: 1, 79 }, 80 TextureDimension::D2, 81 data, 82 TextureFormat::Rgba8UnormSrgb, 83 RenderAssetUsages::RENDER_WORLD | RenderAssetUsages::MAIN_WORLD, 84 ); 85} 86 87/// System that reacts to window resize 88fn handle_resize_messages( 89 mut resize_reader: MessageReader<WindowResized>, 90 mut softatui: ResMut<RatatuiContext>, 91) { 92 for message in resize_reader.read() { 93 let cur_pix_width = softatui.backend().char_width; 94 let cur_pix_height = softatui.backend().char_height; 95 let av_wid = (message.width / cur_pix_width as f32) as u16; 96 let av_hei = (message.height / cur_pix_height as f32) as u16; 97 softatui.backend_mut().resize(av_wid, av_hei); 98 } 99}