bevy_egui icon indicating copy to clipboard operation
bevy_egui copied to clipboard

Support drawing images from TextureAtlases

Open mystal opened this issue 4 years ago β€’ 3 comments

set_egui_texture only supports rendering Textures. It'd be great if I could draw a subsection of a TextureAtlas. Maybe by calling something like:

set_egui_texture_atlas(id: u64, texture_atlas: Handle<TextureAtlas>, texture_index: u32)

The specific use case I'm trying to support is previewing animated sprites in egui.

By the way, bevy_egui has been amazing to use so far! Thanks so much for making it :)

mystal avatar Jan 30 '21 23:01 mystal

Hi! Thanks for the kind words. :)

This feature sounds useful indeed. Though I'm not sure what's the best way to design it in terms of bevy_egui API. The suggestion also assumes that we'll have a widget that will be able to accept Bevy's texture index and render a corresponding Rect of an image.

So that the widget's API would be:

impl TextureAtlasImage {
  pub fn new(texture_atlas_id: egui::TextureId, sprite: bevy::sprite::TextureAtlasSprite)
}

Unfortunately, that seems impossible to achieve without passing TextureAtlas asset as a dependency, to retrieve a corresponding sprite Rect.

But it's possible to render a texture sprite already, using a bit of boilerplate:

// ...
// some init system, basically a body of `set_egui_texture_atlas`
let texture_atlas = texture_atlas_assets.get(texture_atlas_handle).unwrap();
egui_ctx.set_egui_texture(ID, texture_atlas.texture.clone_weak());

// ...
// a system rendering widgets
let texture_atlas = texture_atlas_assets.get(texture_atlas_handle).unwrap();
let rect: egui::Rect = texture_atlas.textures[sprite_index].into(); // somehow convert Bevy's `Rect` to Egui's one
let uv: egui::Rect = egui::Rect::from_min_max(
  egui::math::pos2(rect.min.x / texture_atlas.size.x, rect.min.y / texture_atlas.size.y),
  egui::math::pos2(rect.max.x / texture_atlas.size.x, rect.max.y / texture_atlas.size.y),
);
// ...
// drawing the widget within the UI context
ui.add(egui::Image::new(texture_id, rect.size()).uv(uv));

You can see that even set_egui_texture_atlas would require a loaded TextureAtlas instance. Though I'm not sure whether it makes sense to add such a helper that would do just egui_ctx.set_egui_texture(ID, texture_atlas.texture.clone_weak());. And we need a spite index inside a system rendering widgets, so I guess the actual solution won't have texture_index as a set_egui_texture_atlas parameter, but we'll rather pass it to the TextureAtlasImage constructor.

So the biggest thing bevy_egui can afford is basically introduce a helper (widget) for calculating uv coordinates based on a texture atlas and a sprite index. Probably, that's something that an application can do itself. But I'm still open to introducing this feature if users might find it useful.

Let me know what you think!

vladbat00 avatar Feb 01 '21 09:02 vladbat00

Hi! I wanted to follow up since it's been a while--been very busy, apologies ^^;

I'm planning to try out your suggestion, which seems like it should work for my use case! Once I do I'll report back :)

mystal avatar Feb 24 '21 04:02 mystal

I tried out your suggestion and it works wonderfully! I think a convenience function would be great since I can imagine others might want to visualize animations or individual textures from an atlas.

Thanks!

mystal avatar Feb 25 '21 05:02 mystal