mirror of
https://github.com/emilk/egui.git
synced 2026-09-01 22:30:03 -04:00
Move all crates into a crates directory (#1940)
This commit is contained in:
177
crates/egui_demo_app/src/apps/custom3d_wgpu.rs
Normal file
177
crates/egui_demo_app/src/apps/custom3d_wgpu.rs
Normal file
@@ -0,0 +1,177 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use eframe::{
|
||||
egui_wgpu::{self, wgpu},
|
||||
wgpu::util::DeviceExt,
|
||||
};
|
||||
|
||||
pub struct Custom3d {
|
||||
angle: f32,
|
||||
}
|
||||
|
||||
impl Custom3d {
|
||||
pub fn new<'a>(cc: &'a eframe::CreationContext<'a>) -> Self {
|
||||
// Get the WGPU render state from the eframe creation context. This can also be retrieved
|
||||
// from `eframe::Frame` when you don't have a `CreationContext` available.
|
||||
let wgpu_render_state = cc.wgpu_render_state.as_ref().expect("WGPU enabled");
|
||||
|
||||
let device = &wgpu_render_state.device;
|
||||
|
||||
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: None,
|
||||
source: wgpu::ShaderSource::Wgsl(include_str!("./custom3d_wgpu_shader.wgsl").into()),
|
||||
});
|
||||
|
||||
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
label: None,
|
||||
entries: &[wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStages::VERTEX,
|
||||
ty: wgpu::BindingType::Buffer {
|
||||
ty: wgpu::BufferBindingType::Uniform,
|
||||
has_dynamic_offset: false,
|
||||
min_binding_size: None,
|
||||
},
|
||||
count: None,
|
||||
}],
|
||||
});
|
||||
|
||||
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: None,
|
||||
bind_group_layouts: &[&bind_group_layout],
|
||||
push_constant_ranges: &[],
|
||||
});
|
||||
|
||||
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: None,
|
||||
layout: Some(&pipeline_layout),
|
||||
vertex: wgpu::VertexState {
|
||||
module: &shader,
|
||||
entry_point: "vs_main",
|
||||
buffers: &[],
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &shader,
|
||||
entry_point: "fs_main",
|
||||
targets: &[Some(wgpu_render_state.target_format.into())],
|
||||
}),
|
||||
primitive: wgpu::PrimitiveState::default(),
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
});
|
||||
|
||||
let uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: None,
|
||||
contents: bytemuck::cast_slice(&[0.0]),
|
||||
usage: wgpu::BufferUsages::COPY_DST
|
||||
| wgpu::BufferUsages::MAP_WRITE
|
||||
| wgpu::BufferUsages::UNIFORM,
|
||||
});
|
||||
|
||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
label: None,
|
||||
layout: &bind_group_layout,
|
||||
entries: &[wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: uniform_buffer.as_entire_binding(),
|
||||
}],
|
||||
});
|
||||
|
||||
// Because the graphics pipeline must have the same lifetime as the egui render pass,
|
||||
// instead of storing the pipeline in our `Custom3D` struct, we insert it into the
|
||||
// `paint_callback_resources` type map, which is stored alongside the render pass.
|
||||
wgpu_render_state
|
||||
.egui_rpass
|
||||
.write()
|
||||
.paint_callback_resources
|
||||
.insert(TriangleRenderResources {
|
||||
pipeline,
|
||||
bind_group,
|
||||
uniform_buffer,
|
||||
});
|
||||
|
||||
Self { angle: 0.0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl eframe::App for Custom3d {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
egui::ScrollArea::both()
|
||||
.auto_shrink([false; 2])
|
||||
.show(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.spacing_mut().item_spacing.x = 0.0;
|
||||
ui.label("The triangle is being painted using ");
|
||||
ui.hyperlink_to("WGPU", "https://wgpu.rs");
|
||||
ui.label(" (Portable Rust graphics API awesomeness)");
|
||||
});
|
||||
ui.label("It's not a very impressive demo, but it shows you can embed 3D inside of egui.");
|
||||
|
||||
egui::Frame::canvas(ui.style()).show(ui, |ui| {
|
||||
self.custom_painting(ui);
|
||||
});
|
||||
ui.label("Drag to rotate!");
|
||||
ui.add(egui_demo_lib::egui_github_link_file!());
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Custom3d {
|
||||
fn custom_painting(&mut self, ui: &mut egui::Ui) {
|
||||
let (rect, response) =
|
||||
ui.allocate_exact_size(egui::Vec2::splat(300.0), egui::Sense::drag());
|
||||
|
||||
self.angle += response.drag_delta().x * 0.01;
|
||||
|
||||
// Clone locals so we can move them into the paint callback:
|
||||
let angle = self.angle;
|
||||
|
||||
// The callback function for WGPU is in two stages: prepare, and paint.
|
||||
//
|
||||
// The prepare callback is called every frame before paint and is given access to the wgpu
|
||||
// Device and Queue, which can be used, for instance, to update buffers and uniforms before
|
||||
// rendering.
|
||||
//
|
||||
// The paint callback is called after prepare and is given access to the render pass, which
|
||||
// can be used to issue draw commands.
|
||||
let cb = egui_wgpu::CallbackFn::new()
|
||||
.prepare(move |device, queue, paint_callback_resources| {
|
||||
let resources: &TriangleRenderResources = paint_callback_resources.get().unwrap();
|
||||
resources.prepare(device, queue, angle);
|
||||
})
|
||||
.paint(move |_info, rpass, paint_callback_resources| {
|
||||
let resources: &TriangleRenderResources = paint_callback_resources.get().unwrap();
|
||||
resources.paint(rpass);
|
||||
});
|
||||
|
||||
let callback = egui::PaintCallback {
|
||||
rect,
|
||||
callback: Arc::new(cb),
|
||||
};
|
||||
|
||||
ui.painter().add(callback);
|
||||
}
|
||||
}
|
||||
|
||||
struct TriangleRenderResources {
|
||||
pipeline: wgpu::RenderPipeline,
|
||||
bind_group: wgpu::BindGroup,
|
||||
uniform_buffer: wgpu::Buffer,
|
||||
}
|
||||
|
||||
impl TriangleRenderResources {
|
||||
fn prepare(&self, _device: &wgpu::Device, queue: &wgpu::Queue, angle: f32) {
|
||||
// Update our uniform buffer with the angle from the UI
|
||||
queue.write_buffer(&self.uniform_buffer, 0, bytemuck::cast_slice(&[angle]));
|
||||
}
|
||||
|
||||
fn paint<'rpass>(&'rpass self, rpass: &mut wgpu::RenderPass<'rpass>) {
|
||||
// Draw our triangle!
|
||||
rpass.set_pipeline(&self.pipeline);
|
||||
rpass.set_bind_group(0, &self.bind_group, &[]);
|
||||
rpass.draw(0..3, 0..1);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user