From 92f25cf15981c6585417e5880c694b45962d1f54 Mon Sep 17 00:00:00 2001 From: Tobias Berger Date: Tue, 6 Sep 2022 12:08:05 +0200 Subject: [PATCH] Add temperature cfe7401c7aeedec7faea59e8b6dfa0075545b484 --- save/src/lib.rs | 2 +- save/src/world.rs | 59 ++++++++++++++-- save/src/world_manager.rs | 79 ++++++++++++++++----- src/main.rs | 145 ++++++++++++++++++++++++++++---------- 4 files changed, 225 insertions(+), 60 deletions(-) diff --git a/save/src/lib.rs b/save/src/lib.rs index 14edc5e..0786700 100644 --- a/save/src/lib.rs +++ b/save/src/lib.rs @@ -6,7 +6,7 @@ #![warn(macro_use_extern_crate)] #![warn(meta_variable_misuse)] #![warn(missing_abi)] -#![warn(missing_copy_implementations)] +// #![warn(missing_copy_implementations)] #![warn(missing_debug_implementations)] // #![warn(missing_docs)] #![warn(non_ascii_idents)] diff --git a/save/src/world.rs b/save/src/world.rs index 458304e..4b31c3c 100644 --- a/save/src/world.rs +++ b/save/src/world.rs @@ -71,17 +71,19 @@ impl Debug for World { } } -#[derive(Debug, Copy, Clone, Default)] +#[derive(Debug, Clone, Default)] pub struct Biome { pub altitude: f32, pub rainfall: f32, pub temperature: f32, } -#[derive(Debug, Copy, Clone, Default)] +#[derive(Debug, Clone, Default)] pub struct TerrainCell { pub altitude: f32, pub rainfall: f32, + pub temperature: f32, + pub rain_accumulated: f32, pub previous_rain_accumulated: f32, } @@ -118,11 +120,16 @@ impl World { pub const TERRAIN_NOISE_FACTOR_2: f32 = 0.15; pub const TERRAIN_NOISE_FACTOR_3: f32 = 0.1; - pub const MIN_RAINFALL: f32 = -10.0; + pub const MIN_RAINFALL: f32 = -20.0; pub const MAX_RAINFALL: f32 = 100.0; pub const RAINFALL_SPAN: f32 = Self::MAX_RAINFALL - Self::MIN_RAINFALL; pub const RAINFALL_ALTITUDE_FACTOR: f32 = 1.0; + pub const MIN_TEMPERATURE: f32 = -100.0; + pub const MAX_TEMPERATURE: f32 = 100.0; + pub const TEMPERATURE_SPAN: f32 = Self::MAX_TEMPERATURE - Self::MIN_RAINFALL; + pub const TEMPERATURE_ALTITUDE_FACTOR: f32 = 1.0; + pub fn generate(&mut self) -> Result<(), WorldGenError> { if let Err(err) = self.generate_altitude() { return Err(WorldGenError::CartesianError(err)); @@ -130,6 +137,9 @@ impl World { if let Err(err) = self.generate_rainfall() { return Err(WorldGenError::CartesianError(err)); } + if let Err(err) = self.generate_temperature() { + return Err(WorldGenError::CartesianError(err)); + } Ok(()) } @@ -357,12 +367,12 @@ impl World { for x in 0..self.terrain[y].len() { let beta = (x as f32 / self.width as f32) * TAU; - let value = + let random_noise = 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 base_rainfall = Self::calculate_rainfall(random_noise); let altitude_factor = f32::clamp( (cell.altitude / Self::MAX_ALTITUDE) * Self::RAINFALL_ALTITUDE_FACTOR, 0.0, @@ -383,4 +393,43 @@ impl World { Self::MAX_RAINFALL, ) } + + fn generate_temperature(&mut self) -> Result<(), CartesianError> { + let offset = Self::random_offset_vector(); + const RADIUS: f32 = 2.0; + + 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 beta = (x as f32 / self.width as f32) * TAU; + + let random_noise = + self.random_noise_from_polar_coordinates(alpha, beta, RADIUS, offset)?; + + let cell = &mut self.terrain[y][x]; + + let altitude_factor = 1.0 + - f32::clamp( + (cell.altitude / Self::MAX_ALTITUDE) * Self::TEMPERATURE_ALTITUDE_FACTOR, + 0.0, + 1.0, + ); + + let latitude_modifer = (alpha * 0.8) + (random_noise * 0.2 * PI); + let base_temperature = Self::calculate_temperature(f32::sin(latitude_modifer)); + + cell.temperature = base_temperature * altitude_factor; + } + } + + Ok(()) + } + + fn calculate_temperature(raw_temperature: f32) -> f32 { + f32::clamp( + (raw_temperature * Self::TEMPERATURE_SPAN) + Self::MIN_TEMPERATURE, + 0.0, + Self::MAX_TEMPERATURE, + ) + } } diff --git a/save/src/world_manager.rs b/save/src/world_manager.rs index 3cb3831..9a84604 100644 --- a/save/src/world_manager.rs +++ b/save/src/world_manager.rs @@ -16,6 +16,8 @@ pub struct WorldManager { world: Option, #[cfg(feature = "render")] rainfall_visible: bool, + #[cfg(feature = "render")] + temperature_visible: bool, } impl WorldManager { @@ -25,6 +27,7 @@ impl WorldManager { image_handle_id: HandleId::default::(), world: None, rainfall_visible: false, + temperature_visible: false, } } @@ -34,11 +37,20 @@ impl WorldManager { debug!("Turning rainfall off"); } else { debug!("Turning rainfall on"); - debug!("World: {:#?}", self.world); } self.rainfall_visible = !self.rainfall_visible; } + #[cfg(feature = "render")] + pub fn toggle_temperature(&mut self) { + if self.temperature_visible { + debug!("Turning temperature off"); + } else { + debug!("Turning temperature on"); + } + self.temperature_visible = !self.temperature_visible; + } + pub fn get_world(&self) -> Option<&World> { self.world.as_ref() } @@ -52,24 +64,46 @@ impl WorldManager { } #[cfg(feature = "render")] - fn generate_color(cell: &TerrainCell, show_rainfall: bool) -> Color { - let altitude_color = Self::altitude_contour_color(cell.altitude); - let rainfall_color = if show_rainfall { - Self::rainfall_color(cell.rainfall) - } else { - Color::BLACK - }; + fn generate_color(&self, cell: &TerrainCell) -> Color { + let mut final_color = Self::altitude_color(cell.altitude); - let normalized_rainfall = Self::normalize_rainfall(cell.rainfall); + if self.rainfall_visible { + let rainfall_color = Self::rainfall_color(cell.rainfall); + let normalized_rainfall = Self::normalize_rainfall(cell.rainfall); - let r = (altitude_color.r() * (1.0 - normalized_rainfall)) - + (rainfall_color.r() * normalized_rainfall); - let g = (altitude_color.g() * (1.0 - normalized_rainfall)) - + (rainfall_color.g() * normalized_rainfall); - let b = (altitude_color.b() * (1.0 - normalized_rainfall)) - + (rainfall_color.b() * normalized_rainfall); + _ = final_color.set_r( + (final_color.r() * (1.0 - normalized_rainfall)) + + (rainfall_color.r() * normalized_rainfall), + ); + _ = final_color.set_g( + (final_color.g() * (1.0 - normalized_rainfall)) + + (rainfall_color.g() * normalized_rainfall), + ); + _ = final_color.set_b( + (final_color.b() * (1.0 - normalized_rainfall)) + + (rainfall_color.b() * normalized_rainfall), + ); + } - Color::rgb_linear(r, g, b) + if self.temperature_visible { + let temperature_color = Self::temperature_color(cell.temperature); + let normalized_temperature = Self::normalize_temperature(cell.temperature); + + _ = final_color.set_r( + (final_color.r() * (1.0 - normalized_temperature)) + + (temperature_color.r() * normalized_temperature), + ); + _ = final_color.set_g( + (final_color.g() * (1.0 - normalized_temperature)) + + (temperature_color.g() * normalized_temperature), + ); + _ = final_color.set_b( + (final_color.b() * (1.0 - normalized_temperature)) + + (temperature_color.b() * normalized_temperature), + ); + } + + final_color } /* @@ -114,6 +148,17 @@ impl WorldManager { } } + #[cfg(feature = "render")] + fn temperature_color(temperature: f32) -> Color { + let normalized_temperature = Self::normalize_temperature(temperature); + Color::rgb(normalized_temperature, 1.0 - normalized_temperature, 0.0) + } + + #[cfg(feature = "render")] + fn normalize_temperature(temperature: f32) -> f32 { + (temperature - World::MIN_TEMPERATURE) / World::TEMPERATURE_SPAN + } + #[cfg(feature = "render")] pub fn world_colors(&self) -> Vec { match self.get_world() { @@ -123,7 +168,7 @@ impl WorldManager { terrain_cells .iter() - .map(|cell| Self::generate_color(cell, self.rainfall_visible)) + .map(|cell| self.generate_color(cell)) .collect() } } diff --git a/src/main.rs b/src/main.rs index 53a8695..aa7a882 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,7 @@ #![warn(macro_use_extern_crate)] #![warn(meta_variable_misuse)] #![warn(missing_abi)] -#![warn(missing_copy_implementations)] +// #![warn(missing_copy_implementations)] #![warn(missing_debug_implementations)] // #![warn(missing_docs)] #![warn(non_ascii_idents)] @@ -45,6 +45,7 @@ use bevy::{ core_pipeline::core_2d::Camera2dBundle, ecs::{ change_detection::ResMut, + component::Component, query::{Changed, With}, system::{Commands, Query, Res}, }, @@ -55,12 +56,12 @@ use bevy::{ Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages, }, texture::{Image, ImageSettings}, - view::Visibility, }, ui::{ - entity::{ButtonBundle, ImageBundle, TextBundle}, + entity::{ButtonBundle, ImageBundle, NodeBundle, TextBundle}, widget::Button, - AlignItems, Interaction, JustifyContent, Size, Style, UiColor, UiImage, UiRect, Val, + AlignItems, FocusPolicy, Interaction, JustifyContent, Size, Style, UiColor, UiImage, + UiRect, Val, }, utils::default, window::{CursorIcon, WindowDescriptor, Windows}, @@ -76,25 +77,30 @@ fn refresh_world_texture(images: &mut Assets, world_manager: &WorldManage images.get_mut(&image_handle).unwrap().data = world_manager.world_color_bytes(); } +#[cfg(feature = "render")] +#[derive(Component, Default)] +struct RainfallButton; + +#[cfg(feature = "render")] +#[derive(Component, Default)] +struct TemperatureButton; + 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( +fn handle_rainfall_button( mut interaction_query: Query< '_, '_, - (&Interaction, &mut UiColor /*, &Children*/), - (Changed, With