diff --git a/Cargo.toml b/Cargo.toml index 0ceca43..2b84644 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [features] debug = ["save/debug"] render = ["bevy/bevy_asset", "bevy/bevy_winit", "bevy/render", "save/render"] -default = ["render"] +default = ["render", "debug"] [dependencies.save] path = "save" diff --git a/assets/JuliaMono.ttf b/assets/JuliaMono.ttf new file mode 100644 index 0000000..f37efba Binary files /dev/null and b/assets/JuliaMono.ttf differ diff --git a/save/src/world.rs b/save/src/world.rs index 12fd343..458304e 100644 --- a/save/src/world.rs +++ b/save/src/world.rs @@ -71,6 +71,13 @@ impl Debug for World { } } +#[derive(Debug, Copy, Clone, Default)] +pub struct Biome { + pub altitude: f32, + pub rainfall: f32, + pub temperature: f32, +} + #[derive(Debug, Copy, Clone, Default)] pub struct TerrainCell { pub altitude: f32, @@ -120,7 +127,7 @@ impl World { if let Err(err) = self.generate_altitude() { return Err(WorldGenError::CartesianError(err)); } - if let Err(err) = self.generate_rainfall_alt() { + if let Err(err) = self.generate_rainfall() { return Err(WorldGenError::CartesianError(err)); } @@ -280,6 +287,7 @@ impl World { Self::MIN_ALTITUDE + (raw_altitude * Self::ALTITUDE_SPAN) } + /* fn generate_rainfall_alt(&mut self) -> Result<(), CartesianError> { let max_cycles = self.width / 5; @@ -289,13 +297,12 @@ impl World { for _ in 0..max_cycles { for x in 0..self.width { - let mut prev_x = (x - 1 + self.width) % self.width; - for y in 0..self.height { + let mut prev_x = (x - 1 + self.width) % self.width; let prev_y = if y < self.height / 4 { - prev_x = (x + 1) % self.width; y + 1 } else if y < self.height / 2 { + prev_x = (x + 1) % self.width; y - 1 } else if y < (self.height * 3) / 4 { prev_x = (x + 1) % self.width; @@ -304,15 +311,12 @@ impl World { y - 1 }; - let width_factor = f32::sin(PI * y as f32 / self.height as f32); - let mut cell = self.terrain[y as usize][x as usize]; cell.previous_rain_accumulated = cell.rain_accumulated; cell.rain_accumulated = 0.0; if cell.altitude <= 0.0 { - cell.rain_accumulated += - width_factor * ACCUMULATED_RAIN_FACTOR * Self::MAX_RAINFALL; + cell.rain_accumulated += ACCUMULATED_RAIN_FACTOR * Self::MAX_RAINFALL; } let prev_cell = self.terrain[prev_y as usize][prev_x as usize]; @@ -342,8 +346,8 @@ impl World { Ok(()) } + */ - /* fn generate_rainfall(&mut self) -> Result<(), CartesianError> { let offset = Self::random_offset_vector(); const RADIUS: f32 = 2.0; @@ -351,14 +355,16 @@ impl World { for y in 0..self.terrain.len() { let alpha = (y as f32 / self.height as f32) * PI; for x in 0..self.terrain[y].len() { - let mut cell = self.terrain[y][x]; let beta = (x as f32 / self.width as f32) * TAU; - let base_rainfall = Self::calculate_rainfall( - self.random_noise_from_polar_coordinates(alpha, beta, RADIUS, offset)?, - ); + let value = + self.random_noise_from_polar_coordinates(alpha, beta, RADIUS, offset)?; + + let mut cell = &mut self.terrain[y][x]; + + let base_rainfall = Self::calculate_rainfall(value); let altitude_factor = f32::clamp( - cell.altitude / Self::MAX_ALTITUDE * Self::RAINFALL_ALTITUDE_FACTOR, + (cell.altitude / Self::MAX_ALTITUDE) * Self::RAINFALL_ALTITUDE_FACTOR, 0.0, 1.0, ); @@ -371,8 +377,10 @@ impl World { } fn calculate_rainfall(raw_rainfall: f32) -> f32 { - ((raw_rainfall * Self::RAINFALL_ALTITUDE_FACTOR) + Self::MIN_RAINFALL) - .clamp(0.0, Self::MAX_RAINFALL) + f32::clamp( + (raw_rainfall * Self::RAINFALL_SPAN) + Self::MIN_RAINFALL, + 0.0, + Self::MAX_RAINFALL, + ) } - */ } diff --git a/save/src/world_manager.rs b/save/src/world_manager.rs index 0d09992..3cb3831 100644 --- a/save/src/world_manager.rs +++ b/save/src/world_manager.rs @@ -1,17 +1,42 @@ #[cfg(feature = "render")] use crate::TerrainCell; use crate::{World, WorldGenError}; +use bevy::log::debug; #[cfg(feature = "render")] -use bevy::render::color::Color; +use bevy::{ + asset::HandleId, + render::{color::Color, texture::Image}, +}; use rand::random; #[derive(Debug)] pub struct WorldManager { + #[cfg(feature = "render")] + pub image_handle_id: HandleId, world: Option, + #[cfg(feature = "render")] + rainfall_visible: bool, } + impl WorldManager { pub fn new() -> WorldManager { - WorldManager { world: None } + Self { + #[cfg(feature = "render")] + image_handle_id: HandleId::default::(), + world: None, + rainfall_visible: false, + } + } + + #[cfg(feature = "render")] + pub fn toggle_rainfall(&mut self) { + if self.rainfall_visible { + debug!("Turning rainfall off"); + } else { + debug!("Turning rainfall on"); + debug!("World: {:#?}", self.world); + } + self.rainfall_visible = !self.rainfall_visible; } pub fn get_world(&self) -> Option<&World> { @@ -27,9 +52,13 @@ impl WorldManager { } #[cfg(feature = "render")] - fn generate_color(cell: &TerrainCell) -> Color { + fn generate_color(cell: &TerrainCell, show_rainfall: bool) -> Color { let altitude_color = Self::altitude_contour_color(cell.altitude); - let rainfall_color = Self::rainfall_color(cell.rainfall); + let rainfall_color = if show_rainfall { + Self::rainfall_color(cell.rainfall) + } else { + Color::BLACK + }; let normalized_rainfall = Self::normalize_rainfall(cell.rainfall); @@ -73,20 +102,15 @@ impl WorldManager { #[cfg(feature = "render")] fn rainfall_color(rainfall: f32) -> Color { - if rainfall <= 0.0 { - Color::BLACK - } else { - let mult = rainfall / World::MAX_RAINFALL; - Color::rgb(0.0, mult, 0.0) - } + Color::rgb(0.0, Self::normalize_rainfall(rainfall), 0.0) } #[cfg(feature = "render")] fn normalize_rainfall(rainfall: f32) -> f32 { if rainfall <= 0.0 { - rainfall + 0.0 } else { - rainfall / World::MAX_ALTITUDE + rainfall / World::MAX_RAINFALL } } @@ -99,7 +123,7 @@ impl WorldManager { terrain_cells .iter() - .map(|cell| Self::generate_color(cell)) + .map(|cell| Self::generate_color(cell, self.rainfall_visible)) .collect() } } diff --git a/src/main.rs b/src/main.rs index 4ee0334..53a8695 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,34 +34,93 @@ mod plugins; -use bevy::app::App; +use bevy::{ + app::App, + log::{debug, LogSettings}, + utils::tracing::Level, +}; #[cfg(feature = "render")] use bevy::{ - asset::Assets, + asset::{AssetServer, Assets}, core_pipeline::core_2d::Camera2dBundle, ecs::{ change_detection::ResMut, - system::{Commands, Res}, + query::{Changed, With}, + system::{Commands, Query, Res}, }, + hierarchy::BuildChildren, render::{ + color::Color, render_resource::{ Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages, }, texture::{Image, ImageSettings}, + view::Visibility, + }, + ui::{ + entity::{ButtonBundle, ImageBundle, TextBundle}, + widget::Button, + AlignItems, Interaction, JustifyContent, Size, Style, UiColor, UiImage, UiRect, Val, }, - ui::{entity::ImageBundle, Size, Style, UiImage, Val}, utils::default, - window::WindowDescriptor, + window::{CursorIcon, WindowDescriptor, Windows}, winit::WinitSettings, }; use plugins::WorldPlugins; use save::*; #[cfg(feature = "render")] -fn generate_texture( +fn refresh_world_texture(images: &mut Assets, world_manager: &WorldManager) { + debug!("refreshing world texture"); + let image_handle = images.get_handle(world_manager.image_handle_id); + images.get_mut(&image_handle).unwrap().data = world_manager.world_color_bytes(); +} + +const NORMAL_BUTTON: Color = Color::rgb(0.15, 0.15, 0.15); +const HOVERED_BUTTON: Color = Color::rgb(0.25, 0.25, 0.25); +const PRESSED_BUTTON: Color = Color::rgb(0.35, 0.60, 0.35); +#[cfg(feature = "render")] +fn handle_button_interaction( + mut interaction_query: Query< + '_, + '_, + (&Interaction, &mut UiColor /*, &Children*/), + (Changed, With