Skip to content

Commit

Permalink
Implement paint callbacks for rendering to a texture
Browse files Browse the repository at this point in the history
  • Loading branch information
mvlabat committed Aug 18, 2024
1 parent 34d3fb9 commit c4f61da
Show file tree
Hide file tree
Showing 6 changed files with 383 additions and 149 deletions.
66 changes: 64 additions & 2 deletions examples/paint_callback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,19 @@ use bevy::{
};
use bevy_egui::{
egui_node::{EguiBevyPaintCallback, EguiBevyPaintCallbackImpl, EguiPipelineKey},
EguiContexts, EguiPlugin,
EguiContexts, EguiPlugin, EguiRenderToTextureHandle,
};
use std::path::Path;
use wgpu_types::{Extent3d, TextureUsages};

fn main() {
App::new()
.add_plugins((DefaultPlugins, EguiPlugin, CustomPipelinePlugin))
.add_systems(Update, ui_example_system)
.add_systems(Startup, setup_worldspace)
.add_systems(
Update,
(ui_example_system, ui_render_to_texture_example_system),
)
.run();
}

Expand Down Expand Up @@ -170,3 +175,60 @@ fn ui_example_system(mut ctx: EguiContexts) {
});
}
}

fn setup_worldspace(
mut images: ResMut<Assets<Image>>,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
mut commands: Commands,
) {
let output_texture = images.add({
let size = Extent3d {
width: 256,
height: 256,
depth_or_array_layers: 1,
};
let mut output_texture = Image {
// You should use `0` so that the pixels are transparent.
data: vec![0; (size.width * size.height * 4) as usize],
..default()
};
output_texture.texture_descriptor.usage |= TextureUsages::RENDER_ATTACHMENT;
output_texture.texture_descriptor.size = size;
output_texture
});

commands.spawn(PbrBundle {
mesh: meshes.add(Cuboid::new(1.0, 1.0, 1.0).mesh()),
material: materials.add(StandardMaterial {
base_color: Color::WHITE,
base_color_texture: Some(Handle::clone(&output_texture)),
alpha_mode: AlphaMode::Blend,
// Remove this if you want it to use the world's lighting.
unlit: true,
..default()
}),
..default()
});
commands.spawn(EguiRenderToTextureHandle(output_texture));
commands.spawn(Camera3dBundle {
transform: Transform::from_xyz(1.5, 1.5, 1.5).looking_at(Vec3::new(0., 0., 0.), Vec3::Y),
..default()
});
}

fn ui_render_to_texture_example_system(
mut contexts: Query<&mut bevy_egui::EguiContext, With<EguiRenderToTextureHandle>>,
) {
for mut ctx in contexts.iter_mut() {
egui::Window::new("Worldspace UI").show(ctx.get_mut(), |ui| {
let (resp, painter) =
ui.allocate_painter(egui::Vec2 { x: 200., y: 200. }, egui::Sense::hover());

painter.add(EguiBevyPaintCallback::new_paint_callback(
resp.rect,
CustomPaintCallback,
));
});
}
}
23 changes: 17 additions & 6 deletions src/egui_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{
render_systems::{
EguiPipelines, EguiTextureBindGroups, EguiTextureId, EguiTransform, EguiTransforms,
},
EguiRenderOutput, EguiSettings, WindowSize,
EguiRenderOutput, EguiSettings, RenderTargetSize,
};
use bevy::{
ecs::world::{FromWorld, World},
Expand All @@ -22,7 +22,10 @@ use bevy::{
VertexBufferLayout, VertexFormat, VertexState, VertexStepMode,
},
renderer::{RenderContext, RenderDevice, RenderQueue},
texture::{Image, ImageAddressMode, ImageFilterMode, ImageSampler, ImageSamplerDescriptor},
texture::{
GpuImage, Image, ImageAddressMode, ImageFilterMode, ImageSampler,
ImageSamplerDescriptor,
},
view::{ExtractedWindow, ExtractedWindows},
},
};
Expand Down Expand Up @@ -96,12 +99,19 @@ pub struct EguiPipelineKey {
}

impl EguiPipelineKey {
/// Extracts target texture format in egui renderpass
/// Constructs a pipeline key from a window.
pub fn from_extracted_window(window: &ExtractedWindow) -> Option<Self> {
Some(Self {
texture_format: window.swap_chain_texture_format?.add_srgb_suffix(),
})
}

/// Constructs a pipeline key from a gpu image.
pub fn from_gpu_image(image: &GpuImage) -> Self {
EguiPipelineKey {
texture_format: image.texture_format.add_srgb_suffix(),
}
}
}

impl SpecializedRenderPipeline for EguiPipeline {
Expand Down Expand Up @@ -222,9 +232,10 @@ impl Node for EguiNode {
return;
};

let mut window_sizes = world.query::<(&WindowSize, &mut EguiRenderOutput)>();
let mut render_target_size = world.query::<(&RenderTargetSize, &mut EguiRenderOutput)>();

let Ok((window_size, mut render_output)) = window_sizes.get_mut(world, self.window_entity)
let Ok((window_size, mut render_output)) =
render_target_size.get_mut(world, self.window_entity)
else {
return;
};
Expand Down Expand Up @@ -644,7 +655,7 @@ impl EguiBevyPaintCallback {
}
}

fn cb(&self) -> &dyn EguiBevyPaintCallbackImpl {
pub(crate) fn cb(&self) -> &dyn EguiBevyPaintCallbackImpl {
self.0.as_ref()
}
}
Expand Down
Loading

0 comments on commit c4f61da

Please sign in to comment.