use cgmath::Point2;
use egui::{pos2, vec2, ClippedPrimitive, FontDefinitions, TexturesDelta};
use egui_wgpu::ScreenDescriptor;
use winit::keyboard::KeyCode;
use crate::{component_app::EngineComponent, inputs::Inputs, render::render_engine::RenderEngine};
pub mod helpers;
pub struct EguiEngine {
context: egui::Context,
renderer: egui_wgpu::Renderer,
raw_input: egui::RawInput,
info: EguiRenderInfo
}
struct EguiRenderInfo {
desc: ScreenDescriptor,
tdelta: TexturesDelta,
paint_jobs: Vec<ClippedPrimitive>
}
impl EguiEngine {
pub fn context(&self) -> &egui::Context { &self.context }
pub fn context_mut(&mut self) -> &mut egui::Context { &mut self.context }
}
impl EngineComponent<(&mut RenderEngine, &mut Inputs)> for EguiEngine {
fn create(engine: &mut RenderEngine) -> Self {
let renderer = egui_wgpu::Renderer::new(&engine.device, wgpu::TextureFormat::Bgra8UnormSrgb, None, 1);
let context = egui::Context::default();
context.set_fonts(FontDefinitions::default());
context.set_style(egui::Style::default());
let raw_input = egui::RawInput {
screen_rect: Some(egui::Rect::from_min_size(
egui::Pos2::default(),
egui::vec2(
engine.size.width as f32,
engine.size.height as f32,
),
)),
..Default::default()
};
let info = EguiRenderInfo {
desc: ScreenDescriptor {
size_in_pixels: [engine.size.width, engine.size.height],
pixels_per_point: 1.0,
},
tdelta: TexturesDelta::default(),
paint_jobs: Vec::new()
};
Self { renderer, context, raw_input, info }
}
fn start(&mut self, _: (&mut RenderEngine, &mut Inputs)) {
self.context.begin_frame(self.raw_input.take());
}
fn update(&mut self, (engine, inputs): (&mut RenderEngine, &mut Inputs)) {
let output = self.context.end_frame();
if let Some(cursor_icon) = helpers::egui_to_winit_cursor_icon(output.platform_output.cursor_icon)
{
engine.window.set_cursor_visible(true);
if inputs.mouse_position().is_some() {
engine.window.set_cursor_icon(cursor_icon);
}
} else {
engine.window.set_cursor_visible(false);
}
let position = inputs.mouse_position().unwrap_or(&Point2 { x: 0.0, y: 0.0 });
self.raw_input.events.push(egui::Event::PointerMoved(pos2(position.x, position.y)));
inputs.mouse_buttons_pressed().iter().for_each(|button| {
let button = match button {
winit::event::MouseButton::Left => Some(egui::PointerButton::Primary),
winit::event::MouseButton::Right => Some(egui::PointerButton::Secondary),
winit::event::MouseButton::Middle => Some(egui::PointerButton::Middle),
winit::event::MouseButton::Back => Some(egui::PointerButton::Extra1),
winit::event::MouseButton::Forward => Some(egui::PointerButton::Extra2),
winit::event::MouseButton::Other(_) => None,
};
let button = if button.is_some() { button.unwrap() } else { return };
self.raw_input.events.push(egui::Event::PointerButton {
pos: pos2(position.x, position.y),
button,
pressed: true,
modifiers: self.raw_input.modifiers
});
});
inputs.mouse_buttons_just_released().iter().for_each(|button| {
let button = match button {
winit::event::MouseButton::Left => Some(egui::PointerButton::Primary),
winit::event::MouseButton::Right => Some(egui::PointerButton::Secondary),
winit::event::MouseButton::Middle => Some(egui::PointerButton::Middle),
winit::event::MouseButton::Back => Some(egui::PointerButton::Extra1),
winit::event::MouseButton::Forward => Some(egui::PointerButton::Extra2),
winit::event::MouseButton::Other(_) => None,
};
let button = if button.is_some() { button.unwrap() } else { return };
self.raw_input.events.push(egui::Event::PointerButton {
pos: pos2(position.x, position.y),
button,
pressed: false,
modifiers: self.raw_input.modifiers
});
});
self.raw_input.events.push(egui::Event::MouseWheel {
unit: egui::MouseWheelUnit::Point,
delta: vec2(inputs.mouse_scroll_delta().x, inputs.mouse_scroll_delta().y),
modifiers: self.raw_input.modifiers
});
inputs.keys_just_pressed().iter().for_each(|key_code| {
let key = helpers::key_from_key_code(*key_code);
let key = if key.is_some() { key.unwrap() } else { return };
self.raw_input.events.push(egui::Event::Key { key, physical_key: helpers::key_from_key_code(*key_code), pressed: true, repeat: false, modifiers: self.raw_input.modifiers });
});
inputs.keys_just_released().iter().for_each(|key_code| {
let key = helpers::key_from_key_code(*key_code);
let key = if key.is_some() { key.unwrap() } else { return };
self.raw_input.events.push(egui::Event::Key { key, physical_key: helpers::key_from_key_code(*key_code), pressed: false, repeat: false, modifiers: self.raw_input.modifiers });
let text = helpers::key_code_to_text(key_code);
if text.is_some() {
let text = text.unwrap();
let text = if inputs.is_key_down(&KeyCode::ShiftLeft) || inputs.is_key_down(&KeyCode::ShiftRight) { text.to_uppercase() } else { text.to_lowercase() };
self.raw_input.events.push(egui::Event::Text(text.to_string()));
}
});
let paint_jobs = self.context.tessellate(output.shapes, 1.0);
let screen_descriptor = egui_wgpu::ScreenDescriptor {
size_in_pixels: [engine.size.width, engine.size.height],
pixels_per_point: 1.0,
};
self.info = EguiRenderInfo { desc: screen_descriptor, tdelta: output.textures_delta, paint_jobs };
self.context.begin_frame(self.raw_input.take());
}
fn render<'rpass>(&'rpass mut self, engine: &'rpass RenderEngine, pass: &mut wgpu::RenderPass<'rpass>) {
let mut encoder = engine.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("encoder"),
});
self.info.tdelta.set.iter().for_each(|(id, delta)| {
self.renderer.update_texture(&engine.device, &engine.queue, *id, delta);
});
self.renderer.update_buffers(&engine.device, &engine.queue, &mut encoder, &self.info.paint_jobs, &self.info.desc);
self.renderer.render(pass, &self.info.paint_jobs, &self.info.desc);
engine.queue.submit(std::iter::once(encoder.finish()));
}
fn exit(&mut self, _: (&mut RenderEngine, &mut Inputs)) {}
}