oml_game_egui/
egui_wrapper.rs

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				//} else if self.primary_mouse_button_was_pressed {
176				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		// tracing::debug!("{:?}", full_output.shapes);
204		self.shapes = full_output.shapes;
205		self.textures_delta.append(full_output.textures_delta);
206		//tracing::debug!("{:?}", full_output.platform_output.cursor_icon);
207		/*
208				let platform_output = full_output.platform_output;
209				my_integration.set_cursor_icon(platform_output.cursor_icon);
210				if !platform_output.copied_text.is_empty() {
211					my_integration.set_clipboard_text(platform_output.copied_text);
212				}
213		*/
214		Ok(())
215	}
216
217	pub fn render(&mut self, system: &mut System, renderer: &mut Renderer) -> anyhow::Result<()> {
218		self.size = *renderer.viewport_size();
219		//tracing::debug!("Size {:?}", &self.size);
220		self.paint(system, renderer)?;
221		Ok(())
222	}
223	fn gather_input(&mut self) -> RawInput {
224		//tracing::debug!("pixels_per_point {}", self.pixels_per_point);
225		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			//dropped_files: Vec::new(),
231			//hovered_files: Vec::new(),
232			//events: 0,
233			//has_focus: 0,
234			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			//			pixels_per_point: Some(self.pixels_per_point*2.0),
240			events: self.events.drain(..).collect(),
241			..Default::default()
242		};
243		//tracing::debug!("{:?}", ri.events);
244		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				//let mut color = 0xffffffff;
260				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				// update existing texture
281				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.update_canvas();
298					tex.queue_canvas_update();
299				});
300			} else {
301				// create new texture
302				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		//tracing::debug!("{:?}", &clipped_primitives);
327
328		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			//tracing::debug!("ClipRect: {:?}", clip_rect);
337			match primitive {
338				egui::epaint::Primitive::Mesh(mesh) => {
339					//tracing::debug!("Mesh: {:?}", &mesh );
340					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 size = renderer.size();
355		//let aspect_ratio = renderer.aspect_ratio();
356
357		//tracing::debug!("Size: {:?}", &size );
358		//tracing::debug!("Aspect Ratio: {:?}", &aspect_ratio );
359
360		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		// tracing::debug!("Using texture {}", tid);
366		renderer.use_texture_id_in_channel(*tid, 0);
367		//		renderer.render_textured_fullscreen_quad();
368
369		for (i, v) in mesh.vertices.iter().enumerate() {
370			/*
371			gl_Position = vec4(
372			2.0 * a_pos.x / u_screen_size.x - 1.0,
373			1.0 - 2.0 * a_pos.y / u_screen_size.y,
374			0.0,
375			1.0);
376			*/
377			let vertex = Vector2::new( v.pos.x, v.pos.y )
378			.scaled_vector2( &Vector2::new( 1.0, -1.0 ) ) // upside down :(
379			//.scaled( 4.0 )
380			//.add( &Vector2::new( 0.0, 0.0 ) )
381			//.add( &Vector2::new( 5.0*500.0, 4.0*-500.0 ) )
382			;
383
384			//tracing::debug!("TC {}, {}", v.uv.x, v.uv.y);
385			renderer.set_tex_coords(&Vector2::new(v.uv.x, v.uv.y /*/8.0*/));
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			//tracing::debug!("{} -> {}, {:?}", i, vi, v.pos );
399		}
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}