From 38f383a0b2596795613ef429ceeba05af1f809ab Mon Sep 17 00:00:00 2001 From: Bradlee Speice Date: Sun, 23 Feb 2025 18:02:35 -0500 Subject: [PATCH] Start working on a transform editor --- Cargo.lock | 1 + crates/flare-shader/src/lib.rs | 21 +++++--- crates/flare/Cargo.toml | 1 + crates/flare/examples/transform_editor.rs | 60 +++++++++++++++++++++++ crates/flare/src/lib.rs | 1 + crates/flare/src/main.rs | 2 + crates/flare/src/transform_editor.rs | 57 +++++++++++++++++++++ 7 files changed, 137 insertions(+), 6 deletions(-) create mode 100644 crates/flare/examples/transform_editor.rs create mode 100644 crates/flare/src/lib.rs create mode 100644 crates/flare/src/transform_editor.rs diff --git a/Cargo.lock b/Cargo.lock index d152631..90ef64d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1299,6 +1299,7 @@ dependencies = [ "egui", "egui-wgpu", "env_logger", + "epaint", "flare-shader", "futures", "futures-executor", diff --git a/crates/flare-shader/src/lib.rs b/crates/flare-shader/src/lib.rs index 52ee960..5cd80a6 100644 --- a/crates/flare-shader/src/lib.rs +++ b/crates/flare-shader/src/lib.rs @@ -158,15 +158,24 @@ impl ThreadState { #[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] #[repr(C)] pub struct Coefs { - a: f32, - b: f32, - c: f32, - d: f32, - e: f32, - f: f32, + pub a: f32, + pub b: f32, + pub c: f32, + pub d: f32, + pub e: f32, + pub f: f32, } impl Coefs { + pub const IDENTITY: Coefs = Coefs { + a: 1.0, + b: 0.0, + c: 0.0, + d: 0.0, + e: 1.0, + f: 0.0 + }; + pub fn new(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32) -> Self { Self { a, b, c, d, e, f } } diff --git a/crates/flare/Cargo.toml b/crates/flare/Cargo.toml index 75d8d4a..20f0a20 100644 --- a/crates/flare/Cargo.toml +++ b/crates/flare/Cargo.toml @@ -12,6 +12,7 @@ eframe = { version = "0.31", features = ["wgpu"]} egui = "0.31" egui-wgpu = "0.31" env_logger.workspace = true +epaint = "0.31" flare-shader = { path = "../flare-shader" } futures = "0.3" futures-executor.workspace = true diff --git a/crates/flare/examples/transform_editor.rs b/crates/flare/examples/transform_editor.rs new file mode 100644 index 0000000..65f8da9 --- /dev/null +++ b/crates/flare/examples/transform_editor.rs @@ -0,0 +1,60 @@ +use flare::transform_editor::TransformEditor; +use flare_shader::Coefs; + +struct TransformEditorApp { + transform_editor: TransformEditor, +} + +impl TransformEditorApp { + fn new() -> Self { + Self { + transform_editor: TransformEditor::new() + } + } +} + +impl eframe::App for TransformEditorApp { + fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { + egui::TopBottomPanel::top("top_panel").show(ctx, |ui| { + egui::menu::bar(ui, |ui| { + ui.menu_button("File", |ui| { + if ui.button("Quit").clicked() { + ctx.send_viewport_cmd(egui::ViewportCommand::Close); + } + }); + if ui.button("Add Transform").clicked() { + self.transform_editor.add_transform(Coefs::IDENTITY) + } + }) + }); + + egui::TopBottomPanel::bottom("bottom_panel").show(ctx, |ui| { + ui.label(format!("Transforms: {}", self.transform_editor.len())) + }); + + egui::CentralPanel::default().show(ctx, |ui| { + egui::Frame::canvas(ui.style()).show(ui, |ui| { + self.transform_editor.ui(ui) + }) + }); + } +} + +fn main() -> eframe::Result { + env_logger::init(); + + let initial_dimensions = egui::vec2(800., 600.); + let native_options = eframe::NativeOptions { + viewport: egui::ViewportBuilder::default().with_inner_size(initial_dimensions), + renderer: eframe::Renderer::Wgpu, + ..Default::default() + }; + + eframe::run_native( + "transform_editor", + native_options, + Box::new(|cc| { + Ok(Box::new(TransformEditorApp::new())) + }), + ) +} \ No newline at end of file diff --git a/crates/flare/src/lib.rs b/crates/flare/src/lib.rs new file mode 100644 index 0000000..dfb0b30 --- /dev/null +++ b/crates/flare/src/lib.rs @@ -0,0 +1 @@ +pub mod transform_editor; \ No newline at end of file diff --git a/crates/flare/src/main.rs b/crates/flare/src/main.rs index f47b7b6..dd04c62 100644 --- a/crates/flare/src/main.rs +++ b/crates/flare/src/main.rs @@ -15,6 +15,8 @@ use std::fs::File; use wgpu::util::DeviceExt; use wgpu::{CommandBuffer, CommandEncoder, Device, Queue, RenderPass}; +pub mod transform_editor; + struct RenderGroup { device: wgpu::Device, queue: wgpu::Queue, diff --git a/crates/flare/src/transform_editor.rs b/crates/flare/src/transform_editor.rs new file mode 100644 index 0000000..bad915c --- /dev/null +++ b/crates/flare/src/transform_editor.rs @@ -0,0 +1,57 @@ +use egui::{emath, Rect, Sense}; +use epaint::{Color32, Shape, Stroke}; +use flare_shader::Coefs; + +pub struct TransformEditor { + transforms: Vec +} + +fn coef_to_shapes(coef: &Coefs, to_screen: emath::RectTransform) -> Vec { + let origin = to_screen.transform_pos(egui::pos2(coef.c, -coef.f)); + let x = to_screen.transform_pos(egui::pos2(coef.c + coef.a, -(coef.f + coef.b))); + let y = to_screen.transform_pos(egui::pos2(coef.c + coef.d, -(coef.f + coef.e))); + + let stroke = Stroke::new(2.0, Color32::BLUE); + let translucent = Color32::from_rgba_unmultiplied(0, 0, 255, 8); + + let shapes = vec![ + Shape::circle_stroke(origin, 5.0, stroke), + Shape::circle_stroke(x, 5.0, stroke), + Shape::circle_stroke(y, 5.0, stroke), + Shape::convex_polygon(vec![origin, x, y], translucent, stroke), + ]; + + shapes +} + +impl TransformEditor { + pub fn new() -> Self { + let mut editor = Self { transforms: vec![] }; + editor.add_transform(Coefs::IDENTITY); + + editor + } + + pub fn add_transform(&mut self, coefs: Coefs) { + self.transforms.push(coefs); + } + + pub fn len(&self) -> usize { + self.transforms.len() + } + + pub fn ui(&mut self, ui: &mut egui::Ui) -> egui::Response { + let (response, painter) = ui.allocate_painter(ui.available_size(), Sense::hover()); + + let transform_area = Rect::from_min_max(egui::pos2(-2.0, -2.0), egui::pos2(2.0, 2.0)); + let to_screen = emath::RectTransform::from_to(transform_area, response.interact_rect); + + self.transforms.iter().map(|coef| { + coef_to_shapes(coef, to_screen) + }).flat_map(|x| x).for_each(|shape| { + let _ = painter.add(shape); + }); + + response + } +} \ No newline at end of file