commit 3845538d92d5b14fea83543c6770db9883b2e423 Author: Elias Stepanik Date: Sat Feb 8 18:03:00 2025 +0100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..e668ad0 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "voxel-engine" +version = "0.1.0" +edition = "2021" + +[dependencies] +bevy = { version = "0.15.1", features = ["jpeg", "trace_tracy", "trace_tracy_memory"] } +bevy_egui = "0.31.1" +bevy_asset = "0.15.0" +bevy-inspector-egui = "0.28.0" +bevy_reflect = "0.15.0" +bevy_render = "0.15.0" +bevy_window = "0.15.0" +egui_dock = "0.14.0" \ No newline at end of file diff --git a/assets/fonts/minecraft_font.ttf b/assets/fonts/minecraft_font.ttf new file mode 100644 index 0000000..61b4610 Binary files /dev/null and b/assets/fonts/minecraft_font.ttf differ diff --git a/combine.sh b/combine.sh new file mode 100644 index 0000000..3b5094b --- /dev/null +++ b/combine.sh @@ -0,0 +1 @@ +find src/ -type f -exec cat {} + > target/combined.txt diff --git a/src/app.rs b/src/app.rs new file mode 100644 index 0000000..ee36acc --- /dev/null +++ b/src/app.rs @@ -0,0 +1,82 @@ +use bevy::prelude::*; +use bevy_egui::EguiSet; +use crate::helper::debug_gizmos::debug_gizmos; +use crate::helper::egui_dock::{reset_camera_viewport, set_camera_viewport, set_gizmo_mode, show_ui_system, UiState}; +use crate::helper::large_transform::DoubleTransform; + +pub struct AppPlugin; + + +#[derive(Resource, Debug)] +pub struct InspectorVisible(pub bool); + +impl Default for InspectorVisible { + fn default() -> Self { + InspectorVisible(false) + } +} +impl Plugin for AppPlugin { + fn build(&self, app: &mut App) { + app.insert_resource(UiState::new()); + app.insert_resource(InspectorVisible(true)); + + + + app.add_plugins(crate::plugins::camera_plugin::CameraPlugin); + app.add_plugins(crate::plugins::ui_plugin::UiPlugin); + + app.add_plugins(crate::plugins::environment_plugin::EnvironmentPlugin); + app.add_plugins(crate::plugins::large_transform_plugin::LargeTransformPlugin); + + + + + + + + + + + app.add_systems(Update, (debug_gizmos, toggle_ui_system)); + app.add_systems( + PostUpdate, + show_ui_system + .before(EguiSet::ProcessOutput) + .before(bevy_egui::systems::end_pass_system) + .before(TransformSystem::TransformPropagate) + .run_if(should_display_inspector), + ); + app.add_systems(PostUpdate, (set_camera_viewport.after(show_ui_system).run_if(should_display_inspector), reset_camera_viewport.run_if(should_not_display_inspector).after(set_camera_viewport))); + app.add_systems(Update, set_gizmo_mode); + app.register_type::>>(); + app.register_type::(); + app.register_type::(); + } + + +} + + + +fn toggle_ui_system( + + keyboard_input: Res>, + mut inspector_visible: ResMut, +){ + // ======================= + // 6) Hide Inspector + // ======================= + if keyboard_input.just_pressed(KeyCode::F1) { + inspector_visible.0 = !inspector_visible.0 + } + +} + + +fn should_display_inspector(inspector_visible: Res) -> bool { + inspector_visible.0 +} + +fn should_not_display_inspector(inspector_visible: Res) -> bool { + !inspector_visible.0 +} diff --git a/src/helper/debug_gizmos.rs b/src/helper/debug_gizmos.rs new file mode 100644 index 0000000..c0e48d3 --- /dev/null +++ b/src/helper/debug_gizmos.rs @@ -0,0 +1,21 @@ +use bevy::color::palettes::css::{BLUE, GREEN, RED}; +use bevy::prelude::*; + +pub fn debug_gizmos(mut gizmos: Gizmos) { + + + /* // Draw a line + gizmos.line( + Vec3::ZERO, + Vec3::new(1.0, 1.0, 1.0), + RED, + ); + + // Draw a sphere + gizmos.sphere(Vec3::new(2.0, 2.0, 2.0), 0.5, BLUE); + + // Draw a wireframe cube + gizmos.rect(Isometry3d::IDENTITY, Vec2::ONE, GREEN);*/ + +} + diff --git a/src/helper/egui_dock.rs b/src/helper/egui_dock.rs new file mode 100644 index 0000000..540c5c0 --- /dev/null +++ b/src/helper/egui_dock.rs @@ -0,0 +1,343 @@ +use bevy::prelude::*; +use bevy_asset::{ReflectAsset, UntypedAssetId}; +use bevy_egui::{egui, EguiContext}; +use bevy_inspector_egui::bevy_inspector::hierarchy::{hierarchy_ui, SelectedEntities}; +use bevy_inspector_egui::bevy_inspector::{ + self, ui_for_entities_shared_components, ui_for_entity_with_children, +}; +use std::any::TypeId; +use bevy_reflect::TypeRegistry; +use bevy_render::camera::{CameraProjection, Viewport}; +use bevy_window::{PrimaryWindow, Window}; +use egui_dock::{DockArea, DockState, NodeIndex, Style}; + +#[cfg(egui_dock_gizmo)] +use transform_gizmo_egui::GizmoMode; + +/// Placeholder type if gizmo is disabled. +#[cfg(not(egui_dock_gizmo))] +#[derive(Clone, Copy)] +pub struct GizmoMode; + + +#[derive(Component)] +pub struct MainCamera; + +pub fn show_ui_system(world: &mut World) { + let Ok(egui_context) = world + .query_filtered::<&mut EguiContext, With>() + .get_single(world) + else { + return; + }; + let mut egui_context = egui_context.clone(); + + world.resource_scope::(|world, mut ui_state| { + ui_state.ui(world, egui_context.get_mut()) + }); +} + +// make camera only render to view not obpub structed by UI +pub fn set_camera_viewport( + ui_state: Res, + primary_window: Query<&mut Window, With>, + egui_settings: Query<&bevy_egui::EguiSettings>, + mut cameras: Query<&mut Camera, With>, +) { + let mut cam = cameras.single_mut(); + + let Ok(window) = primary_window.get_single() else { + return; + }; + + let scale_factor = window.scale_factor() * egui_settings.single().scale_factor; + + let viewport_pos = ui_state.viewport_rect.left_top().to_vec2() * scale_factor; + let viewport_size = ui_state.viewport_rect.size() * scale_factor; + + let physical_position = UVec2::new(viewport_pos.x as u32, viewport_pos.y as u32); + let physical_size = UVec2::new(viewport_size.x as u32, viewport_size.y as u32); + + // The desired viewport rectangle at its offset in "physical pixel space" + let rect = physical_position + physical_size; + + let window_size = window.physical_size(); + // wgpu will panic if trying to set a viewport rect which has coordinates extending + // past the size of the render target, i.e. the physical window in our case. + // Typically this shouldn't happen- but during init and resizing etc. edge cases might occur. + // Simply do nothing in those cases. + if rect.x <= window_size.x && rect.y <= window_size.y { + cam.viewport = Some(Viewport { + physical_position, + physical_size, + depth: 0.0..1.0, + }); + } +} + +pub fn reset_camera_viewport(mut cameras: Query<&mut Camera, With>) { + if let Ok(mut cam) = cameras.get_single_mut() { + cam.viewport = None; // Reset the viewport to its default state + } +} +pub fn set_gizmo_mode(input: Res>, mut ui_state: ResMut) { + #[cfg(egui_dock_gizmo)] + let keybinds = [ + (KeyCode::KeyR, GizmoMode::Rotate), + (KeyCode::KeyT, GizmoMode::Translate), + (KeyCode::KeyS, GizmoMode::Scale), + ]; + #[cfg(not(egui_dock_gizmo))] + let keybinds = []; + for (key, mode) in keybinds { + if input.just_pressed(key) { + ui_state.gizmo_mode = mode; + } + } +} + +#[derive(Eq, PartialEq)] +pub enum InspectorSelection { + Entities, + Resource(TypeId, String), + Asset(TypeId, String, UntypedAssetId), +} + +#[derive(Resource)] +pub struct UiState { + state: DockState, + viewport_rect: egui::Rect, + selected_entities: SelectedEntities, + selection: InspectorSelection, + gizmo_mode: GizmoMode, +} + +impl UiState { + pub fn new() -> Self { + let mut state = DockState::new(vec![EguiWindow::GameView]); + let tree = state.main_surface_mut(); + let [game, _inspector] = + tree.split_right(NodeIndex::root(), 0.75, vec![EguiWindow::Inspector]); + let [game, _hierarchy] = tree.split_left(game, 0.2, vec![EguiWindow::Hierarchy]); + let [_game, _bottom] = + tree.split_below(game, 0.8, vec![EguiWindow::Resources, EguiWindow::Assets]); + + Self { + state, + selected_entities: SelectedEntities::default(), + selection: InspectorSelection::Entities, + viewport_rect: egui::Rect::NOTHING, + #[cfg(egui_dock_gizmo)] + gizmo_mode: GizmoMode::Translate, + #[cfg(not(egui_dock_gizmo))] + gizmo_mode: GizmoMode, + } + } + + pub fn ui(&mut self, world: &mut World, ctx: &mut egui::Context) { + let mut tab_viewer = TabViewer { + world, + viewport_rect: &mut self.viewport_rect, + selected_entities: &mut self.selected_entities, + selection: &mut self.selection, + gizmo_mode: self.gizmo_mode, + }; + DockArea::new(&mut self.state) + .style(Style::from_egui(ctx.style().as_ref())) + .show(ctx, &mut tab_viewer); + } +} + +#[derive(Debug)] +pub enum EguiWindow { + GameView, + Hierarchy, + Resources, + Assets, + Inspector, +} + +pub struct TabViewer<'a> { + world: &'a mut World, + selected_entities: &'a mut SelectedEntities, + selection: &'a mut InspectorSelection, + viewport_rect: &'a mut egui::Rect, + gizmo_mode: GizmoMode, +} + +impl egui_dock::TabViewer for TabViewer<'_> { + type Tab = EguiWindow; + + fn ui(&mut self, ui: &mut egui_dock::egui::Ui, window: &mut Self::Tab) { + let type_registry = self.world.resource::().0.clone(); + let type_registry = type_registry.read(); + + match window { + EguiWindow::GameView => { + *self.viewport_rect = ui.clip_rect(); + + draw_gizmo(ui, self.world, self.selected_entities, self.gizmo_mode); + } + EguiWindow::Hierarchy => { + let selected = hierarchy_ui(self.world, ui, self.selected_entities); + if selected { + *self.selection = InspectorSelection::Entities; + } + } + EguiWindow::Resources => select_resource(ui, &type_registry, self.selection), + EguiWindow::Assets => select_asset(ui, &type_registry, self.world, self.selection), + EguiWindow::Inspector => match *self.selection { + InspectorSelection::Entities => match self.selected_entities.as_slice() { + &[entity] => ui_for_entity_with_children(self.world, entity, ui), + entities => ui_for_entities_shared_components(self.world, entities, ui), + }, + InspectorSelection::Resource(type_id, ref name) => { + ui.label(name); + bevy_inspector::by_type_id::ui_for_resource( + self.world, + type_id, + ui, + name, + &type_registry, + ) + } + InspectorSelection::Asset(type_id, ref name, handle) => { + ui.label(name); + bevy_inspector::by_type_id::ui_for_asset( + self.world, + type_id, + handle, + ui, + &type_registry, + ); + } + }, + } + } + + fn title(&mut self, window: &mut Self::Tab) -> egui_dock::egui::WidgetText { + format!("{window:?}").into() + } + + fn clear_background(&self, window: &Self::Tab) -> bool { + !matches!(window, EguiWindow::GameView) + } +} + +#[allow(unused)] +pub fn draw_gizmo( + ui: &mut egui::Ui, + world: &mut World, + selected_entities: &SelectedEntities, + gizmo_mode: GizmoMode, +) { + let (cam_transform, projection) = world + .query_filtered::<(&GlobalTransform, &Projection), With>() + .single(world); + let view_matrix = Mat4::from(cam_transform.affine().inverse()); + let projection_matrix = projection.get_clip_from_view(); + + if selected_entities.len() != 1 { + #[allow(clippy::needless_return)] + return; + } + + /*for selected in selected_entities.iter() { + let Some(transform) = world.get::(selected) else { + continue; + }; + let model_matrix = transform.compute_matrix(); + + let mut gizmo = Gizmo::new(GizmoConfig { + view_matrix: view_matrix.into(), + projection_matrix: projection_matrix.into(), + orientation: GizmoOrientation::Local, + modes: EnumSet::from(gizmo_mode), + ..Default::default() + }); + let Some([result]) = gizmo + .interact(ui, model_matrix.into()) + .map(|(_, res)| res.as_slice()) + else { + continue; + }; + + let mut transform = world.get_mut::(selected).unwrap(); + transform = Transform { + translation: Vec3::from(<[f64; 3]>::from(result.translation)), + rotation: Quat::from_array(<[f64; 4]>::from(result.rotation)), + scale: Vec3::from(<[f64; 3]>::from(result.scale)), + }; + }*/ +} + +pub fn select_resource( + ui: &mut egui::Ui, + type_registry: &TypeRegistry, + selection: &mut InspectorSelection, +) { + let mut resources: Vec<_> = type_registry + .iter() + .filter(|registration| registration.data::().is_some()) + .map(|registration| { + ( + registration.type_info().type_path_table().short_path(), + registration.type_id(), + ) + }) + .collect(); + resources.sort_by(|(name_a, _), (name_b, _)| name_a.cmp(name_b)); + + for (resource_name, type_id) in resources { + let selected = match *selection { + InspectorSelection::Resource(selected, _) => selected == type_id, + _ => false, + }; + + if ui.selectable_label(selected, resource_name).clicked() { + *selection = InspectorSelection::Resource(type_id, resource_name.to_string()); + } + debug!("{}", resource_name); + } +} + +pub fn select_asset( + ui: &mut egui::Ui, + type_registry: &TypeRegistry, + world: &World, + selection: &mut InspectorSelection, +) { + let mut assets: Vec<_> = type_registry + .iter() + .filter_map(|registration| { + let reflect_asset = registration.data::()?; + Some(( + registration.type_info().type_path_table().short_path(), + registration.type_id(), + reflect_asset, + )) + }) + .collect(); + assets.sort_by(|(name_a, ..), (name_b, ..)| name_a.cmp(name_b)); + + for (asset_name, asset_type_id, reflect_asset) in assets { + let handles: Vec<_> = reflect_asset.ids(world).collect(); + + ui.collapsing(format!("{asset_name} ({})", handles.len()), |ui| { + for handle in handles { + let selected = match *selection { + InspectorSelection::Asset(_, _, selected_id) => selected_id == handle, + _ => false, + }; + + if ui + .selectable_label(selected, format!("{:?}", handle)) + .clicked() + { + *selection = + InspectorSelection::Asset(asset_type_id, asset_name.to_string(), handle); + } + } + }); + } +} diff --git a/src/helper/large_transform.rs b/src/helper/large_transform.rs new file mode 100644 index 0000000..40adb81 --- /dev/null +++ b/src/helper/large_transform.rs @@ -0,0 +1,103 @@ +use bevy::math::{DQuat, DVec3}; +use bevy::prelude::{Commands, Component, GlobalTransform, Query, Reflect, Res, ResMut, Resource, Transform, With, Without}; +use bevy_render::prelude::Camera; + + +#[derive(Resource, Reflect,Default)] +pub struct WorldOffset(pub DVec3); + +#[derive(Component, Default,Reflect)] +pub struct DoubleTransform { + pub translation: DVec3, + pub rotation: DQuat, + pub scale: DVec3, +} + +impl DoubleTransform { + pub fn new(translation: DVec3, rotation: DQuat, scale: DVec3) -> Self { + Self { + translation, + rotation, + scale, + } + } + + /// Returns a unit vector pointing "forward" (negative-Z) based on the rotation + pub fn forward(&self) -> DVec3 { + self.rotation * DVec3::new(0.0, 0.0, -1.0) + } + + /// Returns a unit vector pointing "right" (positive-X) + pub fn right(&self) -> DVec3 { + self.rotation * DVec3::new(1.0, 0.0, 0.0) + } + + /// Returns a unit vector pointing "up" (positive-Y) + pub fn up(&self) -> DVec3 { + self.rotation * DVec3::new(0.0, 1.0, 0.0) + } + pub fn down(&self) -> DVec3 { + self.rotation * DVec3::new(0.0, -1.0, 0.0) + } + +} + +pub(crate) fn get_true_world_position( + offset: &WorldOffset, + transform: &DoubleTransform, +) -> DVec3 { + transform.translation + offset.0 +} + +pub fn setup(mut commands: Commands) { + commands + .spawn(( + DoubleTransform { + translation: DVec3::new(100_000.0, 0.0, 0.0), + rotation: DQuat::IDENTITY, + scale: DVec3::ONE, + }, + // The standard Bevy Transform (will be updated each frame) + Transform::default(), + GlobalTransform::default(), + // Add your mesh/visibility components, etc. + )); + +} + + +pub fn update_render_transform_system( + camera_query: Query<&DoubleTransform, With>, + mut query: Query<(&DoubleTransform, &mut Transform), Without>, +) { + let camera_double_tf = camera_query.single(); + // The camera offset in double-precision + let camera_pos = camera_double_tf.translation; + + for (double_tf, mut transform) in query.iter_mut() { + // relative position (double precision) + let relative_pos = double_tf.translation - camera_pos; + transform.translation = relative_pos.as_vec3(); // convert f64 -> f32 + transform.rotation = double_tf.rotation.as_quat(); // f64 -> f32 + transform.scale = double_tf.scale.as_vec3(); // f64 -> f32 + } +} + +pub fn floating_origin_system( + mut query: Query<&mut DoubleTransform, Without>, + mut camera_query: Query<&mut DoubleTransform, With>, + mut offset: ResMut, +) { + let mut camera_tf = camera_query.single_mut(); + let camera_pos = camera_tf.translation; + + // If the camera moves any distance, recenter it + if camera_pos.length() > 0.001 { + offset.0 += camera_pos; + // Shift everything so camera ends up back at zero + for mut dtf in query.iter_mut() { + dtf.translation -= camera_pos; + } + camera_tf.translation = DVec3::ZERO; + } +} \ No newline at end of file diff --git a/src/helper/mod.rs b/src/helper/mod.rs new file mode 100644 index 0000000..66818b0 --- /dev/null +++ b/src/helper/mod.rs @@ -0,0 +1,3 @@ +pub mod egui_dock; +pub mod debug_gizmos; +pub mod large_transform; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..dda3402 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,89 @@ +mod systems; +mod plugins; +mod app; +mod helper; +use bevy::DefaultPlugins; +use bevy::gizmos::{AppGizmoBuilder, GizmoPlugin}; +use bevy::log::info; +use bevy::prelude::{default, App, GizmoConfigGroup, PluginGroup, Reflect, Res, Resource}; +use bevy::render::RenderPlugin; +use bevy::render::settings::{Backends, RenderCreation, WgpuSettings}; +use bevy_egui::{EguiPlugin}; +use bevy_inspector_egui::DefaultInspectorConfigPlugin; +use bevy_window::{PresentMode, Window, WindowPlugin}; +use crate::app::AppPlugin; + +const TITLE: &str = "Fluid Simulation"; +const RESOLUTION: (f32,f32) = (1920f32, 1080f32); +const RESIZABLE: bool = true; +const DECORATIONS: bool = true; +const TRANSPARENT: bool = true; +const PRESENT_MODE: PresentMode = PresentMode::AutoVsync; + + + +fn main() { + let mut app = App::new(); + register_platform_plugins(&mut app); + + app.add_plugins(AppPlugin); + app.add_plugins(EguiPlugin); + app.add_plugins(DefaultInspectorConfigPlugin); + /*app.add_plugins(GizmoPlugin);*/ + + app.run(); +} + + + +#[derive(Resource)] +pub struct InspectorVisible(bool); +fn register_platform_plugins(app: &mut App) { + #[cfg(target_os = "windows")] + { + // Register Windows-specific plugins + info!("Adding Windows-specific plugins"); + app.add_plugins(DefaultPlugins + .set(RenderPlugin { + render_creation: RenderCreation::Automatic(WgpuSettings { + backends: Some(Backends::VULKAN), + ..default() + }), + ..default() + }) + .set(WindowPlugin { + primary_window: Some(Window { + title: TITLE.to_string(), // Window title + resolution: RESOLUTION.into(), // Initial resolution (width x height) + resizable: RESIZABLE, // Allow resizing + decorations: DECORATIONS, // Enable window decorations + transparent: TRANSPARENT, // Opaque background + present_mode: PRESENT_MODE, // VSync mode + ..default() + }), + ..default() + }) + ); + } + + #[cfg(target_os = "macos")] + { + info!("Adding macOS-specific plugins"); + app.add_plugins(DefaultPlugins) + .set(WindowPlugin { + primary_window: Some(Window { + title: crate::TITLE.to_string(), // Window title + resolution: crate::RESOLUTION.into(), // Initial resolution (width x height) + resizable: crate::RESIZABLE, // Allow resizing + decorations: crate::DECORATIONS, // Enable window decorations + transparent: crate::TRANSPARENT, // Opaque background + present_mode: crate::PRESENT_MODE, // VSync mode + ..default() + }), + ..default() + }); + } +} +fn should_display_inspector(inspector_visible: Res) -> bool { + inspector_visible.0 +} \ No newline at end of file diff --git a/src/plugins/camera_plugin.rs b/src/plugins/camera_plugin.rs new file mode 100644 index 0000000..5d10d8c --- /dev/null +++ b/src/plugins/camera_plugin.rs @@ -0,0 +1,12 @@ +use bevy::a11y::AccessibilitySystem::Update; +use bevy::app::{App, Plugin, PreUpdate, Startup}; + +pub struct CameraPlugin; +impl Plugin for CameraPlugin { + fn build(&self, app: &mut App) { + app.add_systems(Startup, (crate::systems::camera_system::setup)); + app.add_systems(PreUpdate, (crate::systems::camera_system::camera_controller_system)); + } + + +} diff --git a/src/plugins/environment_plugin.rs b/src/plugins/environment_plugin.rs new file mode 100644 index 0000000..ad8c4cc --- /dev/null +++ b/src/plugins/environment_plugin.rs @@ -0,0 +1,37 @@ +use std::fs::create_dir; +use bevy::app::{App, Plugin, PreUpdate, Startup}; +use bevy::color::palettes::css::{GRAY, RED}; +use bevy::prelude::{default, Color, Commands, GlobalTransform, IntoSystemConfigs, Query, Res, Update}; +use bevy_render::prelude::ClearColor; +use crate::app::InspectorVisible; +use crate::systems::environment_system::*; +use crate::systems::voxels::structure::{ChunkEntities, SparseVoxelOctree, Voxel}; + +pub struct EnvironmentPlugin; +impl Plugin for EnvironmentPlugin { + fn build(&self, app: &mut App) { + /*app.insert_resource(ClearColor(Color::from(GRAY)));*/ + app.init_resource::(); + app.add_systems(Startup, (setup).chain()); + app.add_systems(Update, (crate::systems::voxels::rendering::render,crate::systems::voxels::debug::visualize_octree.run_if(should_visualize_octree), crate::systems::voxels::debug::draw_grid.run_if(should_draw_grid), crate::systems::voxels::debug::debug_draw_chunks_system.run_if(should_visualize_chunks)).chain()); + + app.register_type::(); + app.register_type::(); + + } + + + +} + +fn should_visualize_octree(octree_query: Query<&SparseVoxelOctree>,) -> bool { + octree_query.single().show_wireframe +} + +fn should_draw_grid(octree_query: Query<&SparseVoxelOctree>,) -> bool { + octree_query.single().show_world_grid +} + +fn should_visualize_chunks(octree_query: Query<&SparseVoxelOctree>,) -> bool { + octree_query.single().show_chunks +} \ No newline at end of file diff --git a/src/plugins/large_transform_plugin.rs b/src/plugins/large_transform_plugin.rs new file mode 100644 index 0000000..cbeb99d --- /dev/null +++ b/src/plugins/large_transform_plugin.rs @@ -0,0 +1,17 @@ + +use bevy::app::{App, Plugin, PreUpdate, Startup, Update}; +use bevy::prelude::IntoSystemConfigs; +use crate::helper::large_transform::*; + +pub struct LargeTransformPlugin; +impl Plugin for LargeTransformPlugin { + fn build(&self, app: &mut App) { + + app.insert_resource(WorldOffset::default()); + app.add_systems(Startup, setup); + app.add_systems(Update, floating_origin_system.after(crate::systems::camera_system::camera_controller_system)); + app.add_systems(Update, update_render_transform_system.after(floating_origin_system)); + } + + +} diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs new file mode 100644 index 0000000..6f23a92 --- /dev/null +++ b/src/plugins/mod.rs @@ -0,0 +1,5 @@ + +pub mod large_transform_plugin; +pub mod camera_plugin; +pub mod ui_plugin; +pub mod environment_plugin; \ No newline at end of file diff --git a/src/plugins/ui_plugin.rs b/src/plugins/ui_plugin.rs new file mode 100644 index 0000000..e19baca --- /dev/null +++ b/src/plugins/ui_plugin.rs @@ -0,0 +1,15 @@ + + +use bevy::app::{App, FixedUpdate, Plugin, PreUpdate, Startup}; +use bevy::prelude::IntoSystemConfigs; +use crate::systems::ui_system::*; + +pub struct UiPlugin; +impl Plugin for UiPlugin { + fn build(&self, app: &mut App) { + app.add_systems(Startup, setup); + app.add_systems(FixedUpdate, update); + } + + +} diff --git a/src/systems/camera_system.rs b/src/systems/camera_system.rs new file mode 100644 index 0000000..6c9c872 --- /dev/null +++ b/src/systems/camera_system.rs @@ -0,0 +1,318 @@ +use bevy::color::palettes::basic::{BLUE, GREEN}; +use bevy::input::mouse::{MouseMotion, MouseWheel}; +use bevy::math::{DQuat, DVec3, Vec3}; +use bevy::prelude::*; +use bevy_render::camera::{OrthographicProjection, Projection, ScalingMode}; +use bevy_window::CursorGrabMode; +use crate::helper::egui_dock::MainCamera; +use crate::helper::large_transform::{DoubleTransform, WorldOffset}; +use crate::InspectorVisible; +use crate::systems::voxels::structure::{Ray, SparseVoxelOctree, Voxel}; + +#[derive(Component)] +pub struct CameraController { + pub yaw: f32, + pub pitch: f32, + pub speed: f32, + pub sensitivity: f32, +} + +impl Default for CameraController { + fn default() -> Self { + Self { + yaw: 0.0, + pitch: 0.0, + speed: 10.0, + sensitivity: 0.1, + } + } +} + +pub fn setup(mut commands: Commands,){ + + + + commands.spawn(( + DoubleTransform { + translation: DVec3::new(0.0, 0.0, 10.0), + rotation: DQuat::IDENTITY, + scale: DVec3::ONE, + }, + Transform::from_xyz(0.0, 5.0, 10.0), // initial f32 + GlobalTransform::default(), + Camera3d::default(), + Projection::from(PerspectiveProjection{ + near: 0.0001, + ..default() + }), + MainCamera, + CameraController::default() + + )); + + +} + +/// Example system to control a camera using double-precision for position. +pub fn camera_controller_system( + time: Res