1use std::collections::HashMap;
2use std::sync::RwLock;
3
4use egui::RawInput;
5use oml_game::math::Matrix32;
6use oml_game::math::Vector2;
7use oml_game::renderer::Color;
8use oml_game::renderer::Renderer;
9use oml_game::renderer::Texture;
10use oml_game::system::System;
11use oml_game::window::WindowUpdateContext;
12
13#[derive(Debug, Default)]
14pub struct EguiWrapper {
15 inner: RwLock<EguiWrapperInner>,
16}
17
18impl EguiWrapper {
19 pub fn setup(&mut self, pixels_per_point: f32) -> anyhow::Result<()> {
20 let mut inner = self.inner.write().unwrap();
21 inner.setup(pixels_per_point)
22 }
23
24 pub fn set_color(&mut self, color: &Color) {
25 let mut inner = self.inner.write().unwrap();
26 inner.set_color(color);
27 }
28
29 pub fn toggle_input(&mut self) -> bool {
30 let mut inner = self.inner.write().unwrap();
31 inner.toggle_input()
32 }
33
34 pub fn enable_input(&mut self) {
35 let mut inner = self.inner.write().unwrap();
36 inner.enable_input();
37 }
38
39 pub fn disable_input(&mut self) {
40 let mut inner = self.inner.write().unwrap();
41 inner.disable_input();
42 }
43
44 pub fn set_input_disabled(&mut self, input_disabled: bool) {
45 let mut inner = self.inner.write().unwrap();
46 inner.set_input_disabled(input_disabled);
47 }
48
49 pub fn input_disabled(&self) -> bool {
50 let mut inner = self.inner.read().unwrap();
51 inner.input_disabled()
52 }
53
54 pub fn set_effect_id(&mut self, effect_id: u16) {
55 let mut inner = self.inner.write().unwrap();
56 inner.set_effect_id(effect_id);
57 }
58 pub fn set_layer_id(&mut self, layer_id: u8) {
59 let mut inner = self.inner.write().unwrap();
60 inner.set_layer_id(layer_id);
61 }
62 pub fn update(&mut self, wuc: &mut WindowUpdateContext) -> anyhow::Result<()> {
63 let mut inner = self.inner.write().unwrap();
64 inner.update(wuc)
65 }
66
67 pub fn run<F>(&self, system: &mut System, mut f: F) -> anyhow::Result<()>
68 where
69 F: FnMut(&egui::Context) -> anyhow::Result<()>,
70 {
71 let mut inner = self.inner.write().unwrap();
72 inner.run(system, f)
73 }
74
75 pub fn render(&mut self, system: &mut System, renderer: &mut Renderer) -> anyhow::Result<()> {
76 let mut inner = self.inner.write().unwrap();
77 inner.render(system, renderer)
78 }
79 fn gather_input(&mut self) -> RawInput {
80 let mut inner = self.inner.write().unwrap();
81 inner.gather_input()
82 }
83
84 fn paint(&mut self, system: &mut System, renderer: &mut Renderer) -> anyhow::Result<()> {
85 let mut inner = self.inner.write().unwrap();
86 inner.paint(system, renderer)
87 }
88
89 fn paint_mesh(&self, renderer: &mut Renderer, mesh: egui::epaint::Mesh) -> anyhow::Result<()> {
90 let mut inner = self.inner.read().unwrap();
91 inner.paint_mesh(renderer, mesh)
92 }
93}
94
95#[derive(Debug, Default)]
96pub struct EguiWrapperInner {
97 egui_ctx: egui::Context,
98 shapes: Vec<egui::epaint::ClippedShape>,
99 textures_delta: egui::TexturesDelta,
100 effect_id: u16,
101 layer_id: u8,
102 texture_ids: HashMap<egui::epaint::TextureId, u16>,
103 size: Vector2,
104 pixels_per_point: f32,
105 events: Vec<egui::Event>,
106 primary_mouse_button_was_pressed: bool,
107 input_disabled: bool,
108 color: Color,
109}
110
111impl EguiWrapperInner {
112 pub fn setup(&mut self, pixels_per_point: f32) -> anyhow::Result<()> {
113 self.pixels_per_point = pixels_per_point;
114 Ok(())
115 }
116
117 pub fn set_color(&mut self, color: &Color) {
118 self.color = *color;
119 }
120
121 pub fn toggle_input(&mut self) -> bool {
122 self.input_disabled = !self.input_disabled;
123
124 self.input_disabled
125 }
126
127 pub fn enable_input(&mut self) {
128 self.input_disabled = false;
129 }
130
131 pub fn disable_input(&mut self) {
132 self.input_disabled = true;
133 }
134
135 pub fn set_input_disabled(&mut self, input_disabled: bool) {
136 self.input_disabled = input_disabled;
137 }
138
139 pub fn input_disabled(&self) -> bool {
140 self.input_disabled
141 }
142
143 pub fn set_effect_id(&mut self, effect_id: u16) {
144 self.effect_id = effect_id;
145 }
146 pub fn set_layer_id(&mut self, layer_id: u8) {
147 self.layer_id = layer_id;
148 }
149 pub fn update(&mut self, wuc: &mut WindowUpdateContext) -> anyhow::Result<()> {
150 if !self.input_disabled {
151 let mut cursor_pos = Vector2::zero();
152
153 cursor_pos.x = 1.0 * (wuc.mouse_pos.x * wuc.window_size.x - 0.5 * wuc.window_size.x);
154 cursor_pos.y = -1.0 * (wuc.mouse_pos.y * wuc.window_size.y - 0.5 * wuc.window_size.y);
155
156 self.events.push(egui::Event::PointerMoved(egui::Pos2 {
157 x: cursor_pos.x,
158 y: cursor_pos.y,
159 }));
160
161 if wuc.was_mouse_button_pressed(0) {
162 tracing::debug!("Primary Mouse Button Pressed @ {:?}", &cursor_pos);
163 wuc.consume_mouse_button_pressed(0);
164 self.events.push(egui::Event::PointerButton {
165 pos: egui::Pos2 {
166 x: cursor_pos.x,
167 y: cursor_pos.y,
168 },
169 button: egui::PointerButton::Primary,
170 pressed: true,
171 modifiers: egui::Modifiers::default(),
172 });
173 self.primary_mouse_button_was_pressed = true;
174 } else if wuc.was_mouse_button_released(0) {
175 self.events.push(egui::Event::PointerButton {
177 pos: egui::Pos2 {
178 x: cursor_pos.x,
179 y: cursor_pos.y,
180 },
181 button: egui::PointerButton::Primary,
182 pressed: false,
183 modifiers: egui::Modifiers::default(),
184 });
185 self.primary_mouse_button_was_pressed = false;
186 }
187 }
188 Ok(())
189 }
190
191 pub fn run<F>(&mut self, _system: &mut System, mut f: F) -> anyhow::Result<()>
192 where
193 F: FnMut(&egui::Context) -> anyhow::Result<()>,
194 {
195 let raw_input: egui::RawInput = self.gather_input();
196
197 self.egui_ctx.begin_frame(raw_input);
198
199 f(&self.egui_ctx).unwrap();
200
201 let full_output = self.egui_ctx.end_frame();
202
203 self.shapes = full_output.shapes;
205 self.textures_delta.append(full_output.textures_delta);
206 Ok(())
215 }
216
217 pub fn render(&mut self, system: &mut System, renderer: &mut Renderer) -> anyhow::Result<()> {
218 self.size = *renderer.viewport_size();
219 self.paint(system, renderer)?;
221 Ok(())
222 }
223 fn gather_input(&mut self) -> RawInput {
224 let screen_size_in_points = egui::Vec2 {
226 x: self.size.x / self.pixels_per_point,
227 y: self.size.y / self.pixels_per_point,
228 };
229 let ri = RawInput {
230 screen_rect: Some(egui::Rect::from_center_size(
235 Default::default(),
236 screen_size_in_points,
237 )),
238 pixels_per_point: Some(self.pixels_per_point),
239 events: self.events.drain(..).collect(),
241 ..Default::default()
242 };
243 ri
245 }
246
247 fn update_texture_from_image(
248 tex: &mut Texture,
249 ox: usize,
250 oy: usize,
251 image: &egui::epaint::image::ImageData,
252 ) {
253 match image {
254 egui::epaint::image::ImageData::Color(color_image) => {
255 todo!();
256 },
257 egui::epaint::image::ImageData::Font(font_image) => {
258 let mut p = Vector2::zero();
259 for y in 0..font_image.size[1] {
261 p.y = (oy + y) as f32;
262 for x in 0..font_image.size[0] {
263 p.x = (ox + x) as f32;
264 let coverage = font_image.pixels[y * font_image.size[0] + x];
265 let coverage = (coverage * 255.0) as u8;
266 let color = (coverage as u32) * 0x01010101;
267 tex.set_texel(&p, color);
268 }
269 }
270 },
271 };
272 }
273
274 fn paint(&mut self, system: &mut System, renderer: &mut Renderer) -> anyhow::Result<()> {
275 let shapes = std::mem::take(&mut self.shapes);
276 let mut textures_delta = std::mem::take(&mut self.textures_delta);
277
278 for (id, image_delta) in &textures_delta.set {
279 if let Some(pos) = &image_delta.pos {
280 let name = match id {
282 egui::epaint::TextureId::Managed(mid) => {
283 format!("egui-{}", mid)
284 },
285 egui::epaint::TextureId::User(_uid) => {
286 todo!();
287 },
288 };
289
290 renderer.find_texture_mut_and_then(&name, |tex| {
291 EguiWrapperInner::update_texture_from_image(
292 tex,
293 pos[0],
294 pos[1],
295 &image_delta.image,
296 );
297 tex.queue_canvas_update();
299 });
300 } else {
301 let size = &image_delta.image.size();
303 let size = if size[0] > size[1] { size[0] } else { size[1] };
304 let name = match id {
305 egui::epaint::TextureId::Managed(mid) => {
306 format!("egui-{}", mid)
307 },
308 egui::epaint::TextureId::User(_uid) => {
309 todo!();
310 },
311 };
312 let mut tex = Texture::create_canvas(&name, size as u32);
313 let sy = image_delta.image.size()[1] as f32 / image_delta.image.size()[0] as f32;
314 let mtx = Matrix32::identity().with_scaling_xy(1.0, sy);
315 tex.set_mtx(&mtx);
316
317 EguiWrapperInner::update_texture_from_image(&mut tex, 0, 0, &image_delta.image);
318
319 tex.update_canvas();
320 let tid = renderer.register_texture(tex);
321 self.texture_ids.insert(*id, tid);
322 }
323 }
324
325 let clipped_primitives = self.egui_ctx.tessellate(shapes);
326 renderer.use_layer(self.layer_id);
329 renderer.use_effect(self.effect_id);
330
331 for egui::ClippedPrimitive {
332 clip_rect: _,
333 primitive,
334 } in clipped_primitives
335 {
336 match primitive {
338 egui::epaint::Primitive::Mesh(mesh) => {
339 self.paint_mesh(renderer, mesh)?;
341 },
342 p => {
343 tracing::warn!("Unsupported primitive {:?}", &p);
344 },
345 };
346 }
347
348 Ok(())
349 }
350
351 fn paint_mesh(&self, renderer: &mut Renderer, mesh: egui::epaint::Mesh) -> anyhow::Result<()> {
352 let mut vertice_map = HashMap::new();
353
354 let texture_id = &mesh.texture_id;
361 let tid = match self.texture_ids.get(texture_id) {
362 Some(tid) => tid,
363 None => return Ok(()),
364 };
365 renderer.use_texture_id_in_channel(*tid, 0);
367 for (i, v) in mesh.vertices.iter().enumerate() {
370 let vertex = Vector2::new( v.pos.x, v.pos.y )
378 .scaled_vector2( &Vector2::new( 1.0, -1.0 ) ) ;
383
384 renderer.set_tex_coords(&Vector2::new(v.uv.x, v.uv.y ));
386 let color = oml_game::renderer::Color::from_rgba(
387 v.color.r() as f32 / 255.0,
388 v.color.g() as f32 / 255.0,
389 v.color.b() as f32 / 255.0,
390 v.color.a() as f32 / 255.0,
391 );
392
393 let color = color * self.color;
394
395 renderer.set_color(&color);
396 let vi = renderer.add_vertex(&vertex);
397 vertice_map.insert(i, vi);
398 }
400
401 for t in mesh.indices.chunks(3) {
402 let tm: Vec<u32> = t
403 .iter()
404 .map(|i| *vertice_map.get(&(*i as usize)).unwrap())
405 .collect();
406 renderer.add_triangle(tm[0], tm[1], tm[2]);
407 }
408 Ok(())
409 }
410}