mvlabat / bevy_egui

This crate provides an Egui integration for the Bevy game engine. 🇺🇦 Please support the Ukrainian army: https://savelife.in.ua/en/
MIT License
897 stars 241 forks source link

SVG loaded via egui_extras is not visible #150

Open dadepo opened 1 year ago

dadepo commented 1 year ago

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?

HVisMyLife commented 1 year ago

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.