bevy_egui icon indicating copy to clipboard operation
bevy_egui copied to clipboard

SVG loaded via egui_extras is not visible

Open dadepo opened this issue 2 years ago β€’ 1 comments

I am taking this example here which shows how to use egui_extras to show svg, and changing it to use bevy_egui integration instead of eframe that is used in the example.

The svg does not show when using bevy_egui. The main part of the code is reproduced below:

use bevy_egui::{egui, EguiContext, EguiPlugin};
fn run_bevy_intefration() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugin(EguiPlugin)
        .add_system(ui_example_system)
        .run();
}

fn ui_example_system(mut egui_context: ResMut<EguiContext>) {
    egui::Window::new("Hello").show(egui_context.ctx_mut(), |ui| {
        ui.label("Bevy Egui");
        ui.separator();
        let svg_image = egui_extras::RetainedImage::from_svg_bytes(
            "hide.svg",
            include_bytes!("icons/visible.svg"),
        ).unwrap();

        svg_image.show_scaled(ui, 1.0);

        ui.separator();
    });
}

It is worth mentioning that it seems the svg is actually in the layout and not just visible, because click and hovered state can be used. For example, updating the code above with the following line

   if svg_image.show_scaled(ui, 1.0).interact(egui::Sense::click()).hovered() {
            dbg!("123");
        };

Will print out 123 to the console on hover around the area where the svg should have been visible.

Is this an issue with bevy_egui that needs to be fixed? or I am missing out on some configuration I need to apply before this can work?

dadepo avatar Feb 09 '23 14:02 dadepo

You want to load texture only once, then, if you need, only update it. I don't know why, but it's in the "manual", and standard images wouldn't work in your example either... Here how I've done handling svg's, but have in mind that they are fragments of my program, so I could have missed something.

Creating svg (for visualising neural net's in my case)

use simplesvg as svg;

let mut objs: Vec<svg::Fig> = vec![]; // vector with objects
let mut cir = svg::Fig::Circle(x, y, r); // object
let mut att = svg::Attr::default(); // style
cir = cir.styled(att);
objs.push(cir); // push object to vector

let out = svg::Svg{0: objs, 1: 400, 2: 550}.to_string(); // create svg "file"

Rasterize it (crate nsvg)

let svg = nsvg::parse_str(&out, nsvg::Units::Pixel, 96.0).unwrap();
svg.rasterize_to_raw_rgba(scale).unwrap()

Handling it

#[derive(Default, Resource)]
struct ImageData {
    egui_texture_handle: Option<egui::TextureHandle>,
}

fn ui_window(
    mut h_texture: ResMut<ImageData>,
    mut egui_ctx: ResMut<EguiContext>
) {
    let texture = h_texture
        .egui_texture_handle
        .get_or_insert_with(|| {
            let (size_x, size_y, pxs) = <to_raw_rgba from before>;
            let img = ColorImage::from_rgba_unmultiplied([size_x, size_y], &pxs);
            egui_ctx.ctx_mut().load_texture(
                "title",
                img.clone(),
                Default::default(),
            )
        })
        .clone();
egui::Window::new("---").show(egui_ctx.ctx_mut(), |ui|{
        ui.add(egui::widgets::Image::new(
            texture.id(),
            texture.size_vec2(),    
        ));
}

If you want to update it

fn u_img(
    mut h_texture: ResMut<ImageData>,
){    
        let (size_x, size_y, pxs) = <to_raw_rgba from before>;
        let img = ColorImage::from_rgba_unmultiplied([size_x, size_y], &pxs);
        if let Some(x) = h_texture.egui_texture_handle.as_mut(){
            x.set(img, default());
        }
}

I haven't seen anywhere 'tutorial' for that, so here it is.

HVisMyLife avatar Feb 17 '23 11:02 HVisMyLife