tirbofish/dropbear · diff
changed readme.md to update for linux build docs, fixed up the borked .eucp file where it copied to dir.
Signature present but could not be verified.
Unverified
@@ -11,7 +11,20 @@ If you might have not realised, all the crates/projects names are after Australi ## Build -To build, clone the repository, then build it. It will build in debug mode, and use a lot of packages, so if your CPU is not fast enough for building you should brew a cup of coffee during the build time. +To build, ensure build requirements, clone the repository, then build it. It will build in debug mode, and use a lot of packages, so if your CPU is not fast enough for building you should brew a cup of coffee during the build time. + +With Unix systems (macOS not tested), you will have to download a couple dependencies if building locally: +<!-- If you have a macOS system, please create a PR and add your own implementation. I know you need to use brew, but I don't know what dependencies to install. --> + +```bash +# ubuntu, adapt to your own OS +sudo apt install libudev-dev pkg-config libssl-dev clang + +# if on arm devices where russimp cannot compile +sudo apt install assimp-utils +``` + +After downloading the requirements, you are free to build it using cargo. ```bash git clone git@github.com:4tkbytes/dropbear @@ -34,6 +34,9 @@ pub struct Camera { pub speed: f32, pub sensitivity: f32, + + pub view_mat: Matrix4<f32>, + pub proj_mat: Matrix4<f32>, } impl Camera { @@ -117,10 +120,13 @@ impl Camera { self.eye } - fn build_vp(&self) -> Matrix4<f32> { + fn build_vp(&mut self) -> Matrix4<f32> { let view = Matrix4::<f32>::look_at_rh(&self.eye, &self.target, &self.up); let proj = Perspective3::new(self.aspect, self.fov_y.to_radians(), self.znear, self.zfar); - return OPENGL_TO_WGPU_MATRIX * proj.to_homogeneous() * view; + self.view_mat = view.clone(); + self.proj_mat = proj.clone().to_homogeneous(); + let result = OPENGL_TO_WGPU_MATRIX * proj.to_homogeneous() * view; + result } pub fn create_bind_group_layout(&mut self, graphics: &Graphics, camera_buffer: Buffer) { @@ -18,7 +18,7 @@ use crate::{ }; pub struct Graphics<'a> { - pub state: &'a State, + pub state: &'a mut State, pub view: &'a TextureView, pub encoder: &'a mut CommandEncoder, pub screen_size: (f32, f32), @@ -27,15 +27,24 @@ pub struct Graphics<'a> { pub const NO_TEXTURE: &'static [u8] = include_bytes!("no-texture.png"); impl<'a> Graphics<'a> { - pub fn new(state: &'a State, view: &'a TextureView, encoder: &'a mut CommandEncoder) -> Self { + pub fn new(state: &'a mut State, view: &'a TextureView, encoder: &'a mut CommandEncoder) -> Self { + let screen_size = (state.config.width as f32, state.config.height as f32); Self { state, view, encoder, - screen_size: (state.config.width as f32, state.config.height as f32), + screen_size, } } + pub fn resize(&mut self, width: u32, height: u32) { + self.state.resize(width, height); + } + + pub fn texture_bind_group(&mut self) -> &wgpu::BindGroupLayout { + &self.state.texture_bind_layout + } + pub fn create_render_pipline( &mut self, shader: &Shader, @@ -224,7 +224,7 @@ Hardware: label: Some("Render Encoder"), }); - let viewport_view = { &self.viewport_texture.view }; + let viewport_view = { &self.viewport_texture.view.clone() }; self.egui_renderer.begin_frame(&self.window); @@ -14,6 +14,7 @@ use log; use egui_dock_fork::TabViewer; use egui_toast_fork::{Toast, ToastKind}; use serde::{Deserialize, Serialize}; +use transform_gizmo_egui::{Gizmo, GizmoConfig}; use crate::{ APP_INFO, @@ -28,10 +29,13 @@ pub enum EditorTab { Viewport, // middle, } -pub struct EditorTabViewer { +pub struct EditorTabViewer<'a> { pub view: egui::TextureId, pub nodes: Vec<EntityNode>, - // pub world: hecs::World, + pub tex_size: Extent3d, + pub gizmo: &'a mut Gizmo, + pub camera: &'a mut Camera, + pub resize_signal: &'a mut (bool, u32, u32), } pub const SELECTED: LazyLock<Mutex<Option<hecs::Entity>>> = LazyLock::new(|| Mutex::new(None)); @@ -57,7 +61,7 @@ impl Default for INeedABetterNameForThisStruct { impl INeedABetterNameForThisStruct {} -impl TabViewer for EditorTabViewer { +impl<'a> TabViewer for EditorTabViewer<'a> { type Tab = EditorTab; fn title(&mut self, tab: &mut Self::Tab) -> egui::WidgetText { @@ -87,7 +91,28 @@ impl TabViewer for EditorTabViewer { match tab { EditorTab::Viewport => { let size = ui.available_size(); - ui.image((self.view, size)); + let new_tex_width = size.x.max(1.0) as u32; + let new_tex_height = size.y.max(1.0) as u32; + + if self.tex_size.width != new_tex_height || self.tex_size.height != new_tex_height { + // log::debug!("Sending resize signal"); + *self.resize_signal = (true, new_tex_width, new_tex_height); + + self.tex_size.width = new_tex_width; + self.tex_size.height = new_tex_height; + + let new_aspect = new_tex_width as f32 / new_tex_height as f32; + self.camera.aspect = new_aspect; + } + + ui.image((self.view, [self.tex_size.width as f32, self.tex_size.height as f32].into())); + + // self.gizmo.update_config(GizmoConfig { + // view_matrix: self.camera.view_mat.into(), + // projection_matrix: self.camera.proj_mat.into(), + // }); + // TODO: Figure out how to get the guizmos working because this is fucking annoying to deal with + // Note to self: fuck you >:( } EditorTab::ModelEntityList => { ui.label("Model/Entity List"); @@ -15,17 +15,17 @@ impl Keyboard for Editor { match key { // KeyCode::Escape => event_loop.exit(), KeyCode::Escape => { - self.is_cursor_locked = !self.is_cursor_locked; - if !self.is_cursor_locked { - if let Some((surface_idx, node_idx, _)) = - self.dock_state.find_tab(&EditorTab::AssetViewer) - { - self.dock_state - .set_focused_node_and_surface((surface_idx, node_idx)); - } else { - self.dock_state.push_to_focused_leaf(EditorTab::AssetViewer); - } - } + // self.is_cursor_locked = !self.is_cursor_locked; + // if !self.is_cursor_locked { + // if let Some((surface_idx, node_idx, _)) = + // self.dock_state.find_tab(&EditorTab::AssetViewer) + // { + // self.dock_state + // .set_focused_node_and_surface((surface_idx, node_idx)); + // } else { + // self.dock_state.push_to_focused_leaf(EditorTab::AssetViewer); + // } + // } } KeyCode::KeyS => { #[cfg(not(target_os = "macos"))] @@ -11,12 +11,12 @@ use std::{ }; use dropbear_engine::{ - camera::Camera, - scene::SceneCommand, + camera::Camera, scene::SceneCommand, }; -use egui; +use egui::{self, Context}; use hecs::World; use log; +use transform_gizmo_egui::Gizmo; use wgpu::{Color, Extent3d, RenderPipeline}; use winit::{keyboard::KeyCode, window::Window}; use egui_dock_fork::{DockArea, DockState, NodeIndex, Style}; @@ -53,6 +53,10 @@ pub struct Editor { project_name: String, project_path: Option<PathBuf>, pending_scene_switch: bool, + + gizmo: Gizmo, + + resize_signal: (bool, u32, u32), } impl Default for Editor { @@ -90,6 +94,8 @@ impl Editor { project_name: String::new(), project_path: None, pending_scene_switch: false, + gizmo: Gizmo::default(), + resize_signal: (false, 1, 1) } } @@ -109,7 +115,7 @@ impl Editor { Ok(()) } - pub fn show_ui(&mut self, ctx: &egui::Context) { + pub fn show_ui(&mut self, ctx: &Context) { egui::TopBottomPanel::top("menu_bar").show(ctx, |ui| { egui::MenuBar::new().ui(ui, |ui| { ui.menu_button("File", |ui| { @@ -206,7 +212,7 @@ impl Editor { }); }); - egui::CentralPanel::default().show(ctx, |ui| { + egui::CentralPanel::default().show(&ctx, |ui| { DockArea::new(&mut self.dock_state) .style(Style::from_egui(ui.style().as_ref())) .show_inside( @@ -214,6 +220,10 @@ impl Editor { &mut EditorTabViewer { view: self.texture_id.unwrap(), nodes: EntityNode::from_world(&self.world), + gizmo: &mut self.gizmo, + tex_size: self.size, + camera: &mut self.camera, + resize_signal: &mut self.resize_signal, }, ); }); @@ -70,12 +70,13 @@ impl Scene for Editor { 0.125, 0.002, ); + let texture_bind_group = &graphics.texture_bind_group().clone(); let model_layout = graphics.create_model_uniform_bind_group_layout(); let pipeline = graphics.create_render_pipline( &shader, vec![ - &graphics.state.texture_bind_layout, + texture_bind_group, camera.layout(), &model_layout, ], @@ -111,6 +112,10 @@ impl Scene for Editor { } } + let new_size = graphics.state.viewport_texture.size; + let new_aspect = new_size.width as f32 / new_size.height as f32; + self.camera.aspect = new_aspect; + self.camera.update(graphics); if !self.is_cursor_locked { @@ -131,10 +136,15 @@ impl Scene for Editor { a: 1.0, }; self.color = color.clone(); - self.size = graphics.state.viewport_texture.size; - self.texture_id = Some(graphics.state.texture_id); - let ctx = graphics.get_egui_context(); - self.show_ui(ctx); + self.size = graphics.state.viewport_texture.size.clone(); + self.texture_id = Some(graphics.state.texture_id.clone()); + self.show_ui(&graphics.get_egui_context()); + + if self.resize_signal.0.clone() { + // graphics.state.resize(self.resize_signal.1, self.resize_signal.2); + // self.resize_signal.0 = false; + } + self.window = Some(graphics.state.window.clone()); if let Ok(mut toasts) = GLOBAL_TOASTS.lock() { toasts.show(graphics.get_egui_context()); @@ -1,7 +1,5 @@ use std::{ - fs, io, - path::Path, - process::Command, + fs, sync::mpsc::{self, Receiver}, }; @@ -12,7 +10,6 @@ use dropbear_engine::{ }; use log::{self, debug}; use gilrs; -use async_trait::async_trait; use egui::{self, FontId, Frame, RichText}; use egui_toast_fork::{ToastOptions, Toasts}; use git2::Repository; @@ -57,49 +54,6 @@ impl MainMenu { } } - #[allow(dead_code)] - fn setup_poetry_project(project_path: &Path) -> anyhow::Result<()> { - if !Command::new("poetry").args(["--version"]).output().is_ok() { - return Err(anyhow!( - "Poetry is not installed. Please install it using pipx or the official poetry website" - )); - } - - let status = Command::new("poetry") - .args(&["new", "scripts"]) - .current_dir(project_path) - .status() - .expect("Failed to run poetry new"); - if !status.success() { - return Err(anyhow!(io::Error::new( - io::ErrorKind::Other, - "Poetry project creation failed", - ))); - } - - let scripts_path = project_path.join("scripts"); - if scripts_path.exists() && scripts_path.is_dir() { - for entry in fs::read_dir(&scripts_path)? { - let entry = entry?; - let path = entry.path(); - let file_name = path.file_name().unwrap(); - let dest = project_path.join(file_name); - fs::rename(&path, &dest)?; - } - } - - if scripts_path.exists() { - fs::remove_dir_all(&scripts_path)?; - } - - let tests_path = project_path.join("tests"); - if tests_path.exists() { - fs::remove_dir_all(&tests_path)?; - } - - Ok(()) - } - fn start_project_creation(&mut self) { let (tx, rx) = mpsc::channel(); let project_name = self.project_name.clone(); @@ -153,7 +107,6 @@ impl MainMenu { } else if folder == "src2" { if let Some(path) = &project_path { let mut config = ProjectConfig::new(project_name.clone(), &path); - // let _ = config.write_to(&path); let _ = config.write_to_all(); let mut global = PROJECT.write().unwrap(); *global = config; @@ -162,29 +115,6 @@ impl MainMenu { Err(anyhow!("Project path not found")) } } - // else if folder == "scripts" || folder == "deps" { - // if folder == "scripts" { - // Self::setup_poetry_project(path) - // } else { - // let status = Command::new("poetry") - // .args(["add", "3d-to-image"]) - // .current_dir(path) - // .status(); - // match status { - // Ok(_) => Ok(()), - // Err(e) => Err(anyhow!(e)), - // } - // } - // } else if folder == "scripts2" { - // if path.join("src/scripts").exists() { - // fs::write( - // &path.join("src/scripts/convert_model_to_image.py"), - // include_str!("scripts/convert_model_to_image.py"), - // ) - // .map_err(|e| anyhow!(e)) - // } else { - // Err(anyhow!("The src/scripts folder does not exist")) - // } else { if !full_path.exists() { fs::create_dir_all(&full_path) @@ -214,7 +144,6 @@ impl MainMenu { } } -#[async_trait] impl Scene for MainMenu { fn load(&mut self, _graphics: &mut dropbear_engine::graphics::Graphics) {} @@ -36,7 +36,7 @@ pub static SOURCE: Lazy<RwLock<SourceConfig>> = Lazy::new(|| RwLock::new(SourceC #[derive(Debug, Deserialize, Serialize, Default)] pub struct ProjectConfig { pub project_name: String, - pub project_path: String, + pub project_path: PathBuf, pub date_created: String, pub date_last_accessed: String, #[serde(default)] @@ -48,11 +48,10 @@ impl ProjectConfig { /// a new project, with it creating new defaults for everything. pub fn new(project_name: String, project_path: &PathBuf) -> Self { let date_created = format!("{}", Utc::now().format("%Y-%m-%d %H:%M:%S")); - let project_path_str = project_path.to_str().unwrap().to_string(); let date_last_accessed = format!("{}", Utc::now().format("%Y-%m-%d %H:%M:%S")); let mut result = Self { project_name, - project_path: project_path_str, + project_path: project_path.to_path_buf(), date_created, date_last_accessed, dock_layout: None, @@ -74,7 +73,7 @@ impl ProjectConfig { let ron_str = ron::ser::to_string_pretty(&self, PrettyConfig::default()) .map_err(|e| anyhow::anyhow!("RON serialization error: {}", e))?; let config_path = path.join(format!("{}.eucp", self.project_name.clone().to_lowercase())); - self.project_path = path.clone().to_str().unwrap().to_string(); + self.project_path = path.to_path_buf(); fs::write(&config_path, ron_str).map_err(|e| anyhow::anyhow!(e.to_string()))?; Ok(()) @@ -88,11 +87,10 @@ impl ProjectConfig { pub fn read_from(path: &PathBuf) -> anyhow::Result<Self> { let ron_str = fs::read_to_string(path)?; let mut config: ProjectConfig = ron::de::from_str(&ron_str.as_str())?; + config.project_path = path.parent().unwrap().to_path_buf(); log::info!("Loaded project!"); - log::debug!("Loaded config info: {:#?}", config); + log::debug!("Loaded config info: {:?}", config); log::debug!("Updating with new content"); - // config.write_to(&path.parent().unwrap().to_path_buf())?; - // config.assets = Assets::walk(&path.parent().unwrap().to_path_buf()); config.load_config_to_memory()?; config.write_to_all()?; log::debug!("Successfully updated!");