use notan::egui::{self, *}; use notan::prelude::*; #[derive(AppState)] struct State { triangle: Triangle, angle: f32, } impl State { pub fn new(gfx: &mut Graphics) -> Self { Self { triangle: Triangle::new(gfx), angle: 0.0, } } } #[notan_main] fn main() -> Result<(), String> { let win = WindowConfig::default() .set_lazy_loop(true) .set_vsync(true) .set_high_dpi(true); notan::init_with(State::new) .add_config(win) .add_config(EguiConfig) .draw(draw) .build() } fn draw(gfx: &mut Graphics, plugins: &mut Plugins, state: &mut State) { let mut output = plugins.egui(|ctx| { egui::CentralPanel::default().show(ctx, |ui| { egui::Frame::canvas(ui.style()).show(ui, |ui| { let (rect, response) = ui.allocate_exact_size(egui::Vec2::splat(300.0), egui::Sense::drag()); state.angle += response.drag_delta().x * 0.01; // Pass as callback the triangle to be draw let triangle = state.triangle.clone(); let angle = state.angle; let cb = EguiCallbackFn::new(move |info, device| { triangle.draw(device, info, angle); }); let callback = egui::PaintCallback { rect, callback: std::sync::Arc::new(cb), }; ui.painter().add(callback); }); ui.label("Drag to rotate!"); }); }); output.clear_color(Color::BLACK); gfx.render(&output); } // --- TRIANGLE //language=glsl const VERT: ShaderSource = notan::vertex_shader! { r#" #version 450 layout(location = 0) in vec2 a_pos; layout(location = 1) in vec3 a_color; layout(location = 0) out vec3 v_color; layout(set = 0, binding = 0) uniform Locals { float u_angle; }; void main() { v_color = a_color; gl_Position = vec4(a_pos, 0.0, 1.0); gl_Position.x *= cos(u_angle); } "# }; //language=glsl const FRAG: ShaderSource = notan::fragment_shader! { r#" #version 450 precision mediump float; layout(location = 0) in vec3 v_color; layout(location = 0) out vec4 color; void main() { color = vec4(v_color, 1.0); } "# }; #[derive(Clone)] struct Triangle { pipeline: Pipeline, vbo: Buffer, ubo: Buffer, } impl Triangle { fn new(gfx: &mut Graphics) -> Self { let vertex_info = VertexInfo::new() .attr(0, VertexFormat::Float32x2) .attr(1, VertexFormat::Float32x3); let pipeline = gfx .create_pipeline() .from(&VERT, &FRAG) .with_vertex_info(&vertex_info) .build() .unwrap(); #[rustfmt::skip] let vertices = [ 0.0, 1.0, 1.0, 0.2, 0.3, -1.0, -1.0, 0.1, 1.0, 0.3, 1.0, -1.0, 0.1, 0.2, 1.0, ]; let vbo = gfx .create_vertex_buffer() .with_info(&vertex_info) .with_data(&vertices) .build() .unwrap(); let ubo = gfx .create_uniform_buffer(0, "Locals") .with_data(&[0.0]) .build() .unwrap(); Self { pipeline, vbo, ubo } } fn draw(&self, device: &mut Device, info: egui::PaintCallbackInfo, angle: f32) { // update angle device.set_buffer_data(&self.ubo, &[angle]); // create a new renderer let mut renderer = device.create_renderer(); // set scissors using the clip_rect passed by egui renderer.set_scissors( info.clip_rect.min.x, info.clip_rect.min.y, info.clip_rect.width(), info.clip_rect.height(), ); // start the pass renderer.begin(None); // set the viewport using the rect passed by egui renderer.set_viewport( info.viewport.min.x, info.viewport.min.y, info.viewport.width(), info.viewport.height(), ); // draw the triangle renderer.set_pipeline(&self.pipeline); renderer.bind_buffer(&self.vbo); renderer.draw(0, 3); renderer.end(); device.render(renderer.commands()); } }