From e3d585ec907a4aa333d669956fc6eb06c7ba6c4c Mon Sep 17 00:00:00 2001 From: gered Date: Fri, 7 Apr 2023 14:21:27 -0400 Subject: [PATCH] initial commit of ggdt_imgui library fairly basic at this stage, but working --- Cargo.toml | 1 + ggdt_imgui/Cargo.toml | 13 +++ ggdt_imgui/src/lib.rs | 2 + ggdt_imgui/src/platform.rs | 200 +++++++++++++++++++++++++++++++++++++ ggdt_imgui/src/renderer.rs | 102 +++++++++++++++++++ 5 files changed, 318 insertions(+) create mode 100644 ggdt_imgui/Cargo.toml create mode 100644 ggdt_imgui/src/lib.rs create mode 100644 ggdt_imgui/src/platform.rs create mode 100644 ggdt_imgui/src/renderer.rs diff --git a/Cargo.toml b/Cargo.toml index ce9b7fd..50ed23b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = [ "ggdt", + "ggdt_imgui", "examples/*", ] diff --git a/ggdt_imgui/Cargo.toml b/ggdt_imgui/Cargo.toml new file mode 100644 index 0000000..c4af066 --- /dev/null +++ b/ggdt_imgui/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "ggdt_imgui" +description = "ImGui backend for ggdt." +version = "0.1.0" +authors = ["Gered King "] +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +ggdt = { path = "../ggdt" } +imgui = "0.11.0" +thiserror = "=1.0.30" diff --git a/ggdt_imgui/src/lib.rs b/ggdt_imgui/src/lib.rs new file mode 100644 index 0000000..0766373 --- /dev/null +++ b/ggdt_imgui/src/lib.rs @@ -0,0 +1,2 @@ +pub mod platform; +pub mod renderer; diff --git a/ggdt_imgui/src/platform.rs b/ggdt_imgui/src/platform.rs new file mode 100644 index 0000000..fdaffa8 --- /dev/null +++ b/ggdt_imgui/src/platform.rs @@ -0,0 +1,200 @@ +use ggdt::system::event::{KeyModifiers, KeyboardEvent, MouseEvent, SystemEvent}; +use ggdt::system::input_devices::keyboard::scancodes::Scancode; +use ggdt::system::input_devices::mouse::buttons::MouseButton; +use ggdt::system::res::standard::Standard; +use ggdt::system::res::SystemResources; +use ggdt::system::System; +use std::time::Instant; + +fn handle_key(io: &mut imgui::Io, key: Scancode, down: bool) { + let key = match key { + Scancode::A => imgui::Key::A, + Scancode::B => imgui::Key::B, + Scancode::C => imgui::Key::C, + Scancode::D => imgui::Key::D, + Scancode::E => imgui::Key::E, + Scancode::F => imgui::Key::F, + Scancode::G => imgui::Key::G, + Scancode::H => imgui::Key::H, + Scancode::I => imgui::Key::I, + Scancode::J => imgui::Key::J, + Scancode::K => imgui::Key::K, + Scancode::L => imgui::Key::L, + Scancode::M => imgui::Key::M, + Scancode::N => imgui::Key::N, + Scancode::O => imgui::Key::O, + Scancode::P => imgui::Key::P, + Scancode::Q => imgui::Key::Q, + Scancode::R => imgui::Key::R, + Scancode::S => imgui::Key::S, + Scancode::T => imgui::Key::T, + Scancode::U => imgui::Key::U, + Scancode::V => imgui::Key::V, + Scancode::W => imgui::Key::W, + Scancode::X => imgui::Key::X, + Scancode::Y => imgui::Key::Y, + Scancode::Z => imgui::Key::Z, + Scancode::Num1 => imgui::Key::Keypad1, + Scancode::Num2 => imgui::Key::Keypad2, + Scancode::Num3 => imgui::Key::Keypad3, + Scancode::Num4 => imgui::Key::Keypad4, + Scancode::Num5 => imgui::Key::Keypad5, + Scancode::Num6 => imgui::Key::Keypad6, + Scancode::Num7 => imgui::Key::Keypad7, + Scancode::Num8 => imgui::Key::Keypad8, + Scancode::Num9 => imgui::Key::Keypad9, + Scancode::Num0 => imgui::Key::Keypad0, + Scancode::Return => imgui::Key::Enter, + Scancode::Escape => imgui::Key::Escape, + Scancode::Backspace => imgui::Key::Backspace, + Scancode::Tab => imgui::Key::Tab, + Scancode::Space => imgui::Key::Space, + Scancode::Minus => imgui::Key::Minus, + Scancode::Equals => imgui::Key::Equal, + Scancode::LeftBracket => imgui::Key::LeftBracket, + Scancode::RightBracket => imgui::Key::RightBracket, + Scancode::Backslash => imgui::Key::Backslash, + Scancode::Semicolon => imgui::Key::Semicolon, + Scancode::Apostrophe => imgui::Key::Apostrophe, + Scancode::Grave => imgui::Key::GraveAccent, + Scancode::Comma => imgui::Key::Comma, + Scancode::Period => imgui::Key::Period, + Scancode::Slash => imgui::Key::Slash, + Scancode::CapsLock => imgui::Key::CapsLock, + Scancode::F1 => imgui::Key::F1, + Scancode::F2 => imgui::Key::F2, + Scancode::F3 => imgui::Key::F3, + Scancode::F4 => imgui::Key::F4, + Scancode::F5 => imgui::Key::F5, + Scancode::F6 => imgui::Key::F6, + Scancode::F7 => imgui::Key::F7, + Scancode::F8 => imgui::Key::F8, + Scancode::F9 => imgui::Key::F9, + Scancode::F10 => imgui::Key::F10, + Scancode::F11 => imgui::Key::F11, + Scancode::F12 => imgui::Key::F12, + Scancode::PrintScreen => imgui::Key::PrintScreen, + Scancode::ScrollLock => imgui::Key::ScrollLock, + Scancode::Pause => imgui::Key::Pause, + Scancode::Insert => imgui::Key::Insert, + Scancode::Home => imgui::Key::Home, + Scancode::PageUp => imgui::Key::PageUp, + Scancode::Delete => imgui::Key::Delete, + Scancode::End => imgui::Key::End, + Scancode::PageDown => imgui::Key::PageDown, + Scancode::Right => imgui::Key::RightArrow, + Scancode::Left => imgui::Key::LeftArrow, + Scancode::Down => imgui::Key::DownArrow, + Scancode::Up => imgui::Key::UpArrow, + Scancode::KpDivide => imgui::Key::KeypadDivide, + Scancode::KpMultiply => imgui::Key::KeypadMultiply, + Scancode::KpMinus => imgui::Key::KeypadSubtract, + Scancode::KpPlus => imgui::Key::KeypadAdd, + Scancode::KpEnter => imgui::Key::KeypadEnter, + Scancode::Kp1 => imgui::Key::Keypad1, + Scancode::Kp2 => imgui::Key::Keypad2, + Scancode::Kp3 => imgui::Key::Keypad3, + Scancode::Kp4 => imgui::Key::Keypad4, + Scancode::Kp5 => imgui::Key::Keypad5, + Scancode::Kp6 => imgui::Key::Keypad6, + Scancode::Kp7 => imgui::Key::Keypad7, + Scancode::Kp8 => imgui::Key::Keypad8, + Scancode::Kp9 => imgui::Key::Keypad9, + Scancode::Kp0 => imgui::Key::Keypad0, + Scancode::KpPeriod => imgui::Key::KeypadDecimal, + Scancode::Application => imgui::Key::Menu, + Scancode::KpEquals => imgui::Key::KeypadEqual, + Scancode::Menu => imgui::Key::Menu, + Scancode::LCtrl => imgui::Key::LeftCtrl, + Scancode::LShift => imgui::Key::LeftShift, + Scancode::LAlt => imgui::Key::LeftAlt, + Scancode::LGui => imgui::Key::LeftSuper, + Scancode::RCtrl => imgui::Key::RightCtrl, + Scancode::RShift => imgui::Key::RightShift, + Scancode::RAlt => imgui::Key::RightAlt, + Scancode::RGui => imgui::Key::RightSuper, + _ => return, + }; + io.add_key_event(key, down); +} + +fn handle_key_modifier(io: &mut imgui::Io, keymod: KeyModifiers) { + io.add_key_event(imgui::Key::ModShift, keymod.intersects(KeyModifiers::LSHIFTMOD | KeyModifiers::RSHIFTMOD)); + io.add_key_event(imgui::Key::ModCtrl, keymod.intersects(KeyModifiers::LCTRLMOD | KeyModifiers::RCTRLMOD)); + io.add_key_event(imgui::Key::ModAlt, keymod.intersects(KeyModifiers::LALTMOD | KeyModifiers::RALTMOD)); + io.add_key_event(imgui::Key::ModSuper, keymod.intersects(KeyModifiers::LGUIMOD | KeyModifiers::RGUIMOD)); +} + +fn handle_mouse_button_event(io: &mut imgui::Io, button: MouseButton, down: bool) { + match button { + MouseButton::Left => io.add_mouse_button_event(imgui::MouseButton::Left, down), + MouseButton::Right => io.add_mouse_button_event(imgui::MouseButton::Right, down), + MouseButton::Middle => io.add_mouse_button_event(imgui::MouseButton::Middle, down), + MouseButton::X1 => io.add_mouse_button_event(imgui::MouseButton::Extra1, down), + MouseButton::X2 => io.add_mouse_button_event(imgui::MouseButton::Extra2, down), + _ => {} + } +} + +pub struct Platform { + last_frame: Instant, +} + +impl Platform { + pub fn new(imgui: &mut imgui::Context) -> Self { + imgui.set_ini_filename(None); + imgui.set_platform_name(Some(String::from("ggdt"))); + + imgui.style_mut().anti_aliased_lines = false; + imgui.style_mut().anti_aliased_lines_use_tex = false; + + Platform { last_frame: Instant::now() } + } + + pub fn handle_event(&mut self, context: &mut imgui::Context, event: &SystemEvent) -> bool { + let io = context.io_mut(); + + match *event { + SystemEvent::Mouse(MouseEvent::MouseMotion { x, y, .. }) => { + io.add_mouse_pos_event([x as f32, y as f32]); + true + } + SystemEvent::Mouse(MouseEvent::MouseButtonUp { button, .. }) => { + handle_mouse_button_event(io, button, false); + true + } + SystemEvent::Mouse(MouseEvent::MouseButtonDown { button, .. }) => { + handle_mouse_button_event(io, button, true); + true + } + SystemEvent::Keyboard(KeyboardEvent::KeyUp { scancode: Some(scancode), keymod, .. }) => { + handle_key_modifier(io, keymod); + handle_key(io, scancode, false); + true + } + SystemEvent::Keyboard(KeyboardEvent::KeyDown { scancode: Some(scancode), keymod, .. }) => { + handle_key_modifier(io, keymod); + handle_key(io, scancode, true); + true + } + SystemEvent::Keyboard(KeyboardEvent::TextInput { ref text }) => { + for ch in text.chars() { + io.add_input_character(ch); + } + true + } + _ => false, + } + } + + pub fn prepare_frame(&mut self, context: &mut imgui::Context, system: &System) { + let io = context.io_mut(); + + let now = Instant::now(); + io.update_delta_time(now.duration_since(self.last_frame)); + self.last_frame = now; + + io.display_size = [system.res.width() as f32, system.res.height() as f32]; + io.display_framebuffer_scale = [1.0, 1.0]; + } +} diff --git a/ggdt_imgui/src/renderer.rs b/ggdt_imgui/src/renderer.rs new file mode 100644 index 0000000..84f48f3 --- /dev/null +++ b/ggdt_imgui/src/renderer.rs @@ -0,0 +1,102 @@ +use ggdt::graphics::bitmap::rgb::triangles::RgbaTriangle2d; +use ggdt::graphics::bitmap::rgb::{RgbaBitmap, RgbaPixelFormat}; +use ggdt::graphics::color::{to_argb32, BlendFunction}; +use ggdt::math::rect::Rect; +use ggdt::math::vector2::Vector2; +use imgui::internal::RawWrapper; + +pub struct Renderer { + pub texture_map: imgui::Textures, +} + +impl Renderer { + pub fn new(context: &mut imgui::Context) -> Self { + let mut texture_map = imgui::Textures::new(); + + // set up a bitmap with the imgui font atlas texture pixels and register a bitmap->texture mapping for it + // with imgui + let mut font = context.fonts(); + let mut font_atlas_texture = font.build_rgba32_texture(); + font.tex_id = texture_map.insert( + RgbaBitmap::from_bytes( + font_atlas_texture.width, + font_atlas_texture.height, + RgbaPixelFormat::RGBA, + &mut font_atlas_texture.data, + ) + .unwrap(), + ); + + Renderer { texture_map } + } + + pub fn render(&mut self, draw_data: &imgui::DrawData, dest: &mut RgbaBitmap) { + let original_clip_rect = *dest.clip_region(); + + for draw_list in draw_data.draw_lists() { + for command in draw_list.commands() { + match command { + imgui::DrawCmd::Elements { count, cmd_params } => { + let clip_rect = Rect::from_coords( + (cmd_params.clip_rect[0] - draw_data.display_pos[0]) as i32, + (cmd_params.clip_rect[1] - draw_data.display_pos[1]) as i32, + (cmd_params.clip_rect[2] - draw_data.display_pos[0]) as i32, + (cmd_params.clip_rect[3] - draw_data.display_pos[1]) as i32, + ); + if clip_rect.x > dest.right() as i32 + || clip_rect.y > dest.bottom() as i32 + || clip_rect.right() < 0 || clip_rect.bottom() < 0 + { + continue; + } + + dest.set_clip_region(&clip_rect); + let bitmap = self.texture_map.get(cmd_params.texture_id).unwrap(); + + let idx_buffer = draw_list.idx_buffer(); + let vtx_buffer = draw_list.vtx_buffer(); + let mut idx = 0; + while idx < count { + let v1 = vtx_buffer[idx_buffer[cmd_params.idx_offset + idx] as usize]; + let v2 = vtx_buffer[idx_buffer[cmd_params.idx_offset + idx + 1] as usize]; + let v3 = vtx_buffer[idx_buffer[cmd_params.idx_offset + idx + 2] as usize]; + + let triangle = RgbaTriangle2d::SolidTexturedMultiColoredBlended { + position: [ + Vector2::new(v2.pos[0], v2.pos[1]), + Vector2::new(v1.pos[0], v1.pos[1]), + Vector2::new(v3.pos[0], v3.pos[1]), + ], + texcoord: [ + Vector2::new(v2.uv[0], v2.uv[1]), + Vector2::new(v1.uv[0], v1.uv[1]), + Vector2::new(v3.uv[0], v3.uv[1]), + ], + color: [ + to_argb32(v2.col[3], v2.col[0], v2.col[1], v2.col[2]), + to_argb32(v1.col[3], v1.col[0], v1.col[1], v1.col[2]), + to_argb32(v3.col[3], v3.col[0], v3.col[1], v3.col[2]), + ], + bitmap, + blend: BlendFunction::Blend, + }; + dest.triangle_2d(&triangle); + + idx += 3; + } + } + imgui::DrawCmd::RawCallback { callback, raw_cmd } => { + //dbg!("DrawCmd::RawCallback"); + unsafe { callback(draw_list.raw(), raw_cmd) } + } + imgui::DrawCmd::ResetRenderState => { + // todo + //dbg!("DrawCmd::ResetRenderState"); + dest.set_clip_region(&original_clip_rect); + } + } + } + } + dest.set_clip_region(&original_clip_rect); + } +}