Update Biome colors
0ebf1dfc012a07325fc6c0bd28d1917bdeb4834e
This commit is contained in:
parent
234579f553
commit
e7d73755e2
5 changed files with 102 additions and 103 deletions
|
@ -185,8 +185,16 @@ impl<'de> Deserialize<'de> for World {
|
||||||
let width = width.ok_or_else(|| Error::missing_field("width"))?;
|
let width = width.ok_or_else(|| Error::missing_field("width"))?;
|
||||||
let height = height.ok_or_else(|| Error::missing_field("height"))?;
|
let height = height.ok_or_else(|| Error::missing_field("height"))?;
|
||||||
let seed = seed.ok_or_else(|| Error::missing_field("seed"))?;
|
let seed = seed.ok_or_else(|| Error::missing_field("seed"))?;
|
||||||
let terrain: Vec<Vec<TerrainCell>> =
|
let mut terrain: Vec<Vec<TerrainCell>> =
|
||||||
terrain.ok_or_else(|| Error::missing_field("terrain"))?;
|
terrain.ok_or_else(|| Error::missing_field("terrain"))?;
|
||||||
|
|
||||||
|
for x in 0..width as usize {
|
||||||
|
for y in 0..height as usize {
|
||||||
|
terrain[y][x].x = x;
|
||||||
|
terrain[y][x].y = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let continent_offsets =
|
let continent_offsets =
|
||||||
continent_offsets.ok_or_else(|| Error::missing_field("continent_offsets"))?;
|
continent_offsets.ok_or_else(|| Error::missing_field("continent_offsets"))?;
|
||||||
let continent_widths =
|
let continent_widths =
|
||||||
|
|
|
@ -97,11 +97,16 @@ pub struct TerrainCell {
|
||||||
pub rainfall: f32,
|
pub rainfall: f32,
|
||||||
pub temperature: f32,
|
pub temperature: f32,
|
||||||
|
|
||||||
|
#[serde(skip)]
|
||||||
|
pub x: usize,
|
||||||
|
#[serde(skip)]
|
||||||
|
pub y: usize,
|
||||||
|
|
||||||
pub biome_presences: Vec<(BiomeType, f32)>,
|
pub biome_presences: Vec<(BiomeType, f32)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl World {
|
impl World {
|
||||||
const ALTITUDE_SPAN: f32 = World::MAX_ALTITUDE - World::MIN_ALTITUDE;
|
pub(crate) const ALTITUDE_SPAN: f32 = World::MAX_ALTITUDE - World::MIN_ALTITUDE;
|
||||||
const CONTINENT_MAX_SIZE_FACTOR: f32 = 6.0;
|
const CONTINENT_MAX_SIZE_FACTOR: f32 = 6.0;
|
||||||
const CONTINENT_MIN_SIZE_FACTOR: f32 = 2.5;
|
const CONTINENT_MIN_SIZE_FACTOR: f32 = 2.5;
|
||||||
pub(crate) const MAX_ALTITUDE: f32 = 15000.0;
|
pub(crate) const MAX_ALTITUDE: f32 = 15000.0;
|
||||||
|
@ -300,6 +305,9 @@ impl World {
|
||||||
if altitude < self.min_altitude {
|
if altitude < self.min_altitude {
|
||||||
self.min_altitude = altitude;
|
self.min_altitude = altitude;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.terrain[y][x].x = x;
|
||||||
|
self.terrain[y][x].y = y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
info!("Done generating altitude");
|
info!("Done generating altitude");
|
||||||
|
@ -547,90 +555,79 @@ impl World {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn cell_neighbors(&self, x: usize, y: usize) -> HashMap<CompassDirection, (usize, usize)> {
|
pub fn cell_neighbors(&self, x: usize, y: usize) -> HashMap<CompassDirection, &TerrainCell> {
|
||||||
let mut neighbors = HashMap::new();
|
let mut neighbors = HashMap::new();
|
||||||
|
|
||||||
let height = self.height as usize;
|
let height = self.height as usize;
|
||||||
let width = self.width as usize;
|
let width = self.width as usize;
|
||||||
|
|
||||||
|
let west_x = (width + x - 1) % width;
|
||||||
|
let east_x = (x + 1) % width;
|
||||||
|
|
||||||
let north_edge = y >= height - 1;
|
let north_edge = y >= height - 1;
|
||||||
let east_edge = x >= width - 1;
|
|
||||||
let south_edge = y == 0;
|
let south_edge = y == 0;
|
||||||
let west_edge = x == 0;
|
|
||||||
|
|
||||||
if !north_edge {
|
if !north_edge {
|
||||||
_ = neighbors.insert_unique_unchecked(CompassDirection::North, (y + 1, x));
|
_ = neighbors
|
||||||
}
|
.insert_unique_unchecked(CompassDirection::NorthWest, &self.terrain[y + 1][west_x]);
|
||||||
if !north_edge && !east_edge {
|
_ = neighbors.insert_unique_unchecked(CompassDirection::North, &self.terrain[y + 1][x]);
|
||||||
_ = neighbors.insert_unique_unchecked(CompassDirection::NorthEast, (y + 1, x + 1));
|
_ = neighbors
|
||||||
}
|
.insert_unique_unchecked(CompassDirection::NorthEast, &self.terrain[y + 1][east_x]);
|
||||||
if !east_edge {
|
|
||||||
_ = neighbors.insert_unique_unchecked(CompassDirection::East, (y, x + 1));
|
|
||||||
}
|
|
||||||
if !south_edge && !east_edge {
|
|
||||||
_ = neighbors.insert_unique_unchecked(CompassDirection::SouthEast, (y - 1, x + 1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ = neighbors.insert_unique_unchecked(CompassDirection::West, &self.terrain[y][east_x]);
|
||||||
|
_ = neighbors.insert_unique_unchecked(CompassDirection::East, &self.terrain[y][west_x]);
|
||||||
|
|
||||||
if !south_edge {
|
if !south_edge {
|
||||||
_ = neighbors.insert_unique_unchecked(CompassDirection::South, (y - 1, x));
|
_ = neighbors
|
||||||
|
.insert_unique_unchecked(CompassDirection::SouthWest, &self.terrain[y - 1][west_x]);
|
||||||
|
_ = neighbors.insert_unique_unchecked(CompassDirection::South, &self.terrain[y - 1][x]);
|
||||||
|
_ = neighbors
|
||||||
|
.insert_unique_unchecked(CompassDirection::SouthEast, &self.terrain[y - 1][east_x]);
|
||||||
}
|
}
|
||||||
if !south_edge && !west_edge {
|
|
||||||
_ = neighbors.insert_unique_unchecked(CompassDirection::SouthWest, (y - 1, x - 1));
|
|
||||||
}
|
|
||||||
if !west_edge {
|
|
||||||
_ = neighbors.insert_unique_unchecked(CompassDirection::West, (y, x - 1));
|
|
||||||
};
|
|
||||||
if !north_edge && !west_edge {
|
|
||||||
_ = neighbors.insert_unique_unchecked(CompassDirection::NorthWest, (y + 1, x - 1));
|
|
||||||
};
|
|
||||||
|
|
||||||
neighbors
|
neighbors
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_slant(&self, x: usize, y: usize) -> f32 {
|
pub fn get_slant(&self, cell: &TerrainCell) -> f32 {
|
||||||
let neighbors = self.cell_neighbors(x, y);
|
let neighbors = self.cell_neighbors(cell.x, cell.y);
|
||||||
let terrain = &self.terrain;
|
|
||||||
|
|
||||||
let mut west_altitude = f32::MIN;
|
let mut west_altitude = 0.0;
|
||||||
if let Some(neighbor_coords) = neighbors.get(&CompassDirection::North) {
|
let mut neighbor_count = 0u8;
|
||||||
west_altitude = f32::max(
|
|
||||||
west_altitude,
|
if let Some(neighbor) = neighbors.get(&CompassDirection::North) {
|
||||||
terrain[neighbor_coords.0][neighbor_coords.1].altitude,
|
west_altitude = f32::max(west_altitude, neighbor.altitude);
|
||||||
);
|
neighbor_count += 1;
|
||||||
}
|
}
|
||||||
if let Some(neighbor_coords) = neighbors.get(&CompassDirection::NorthWest) {
|
if let Some(neighbor) = neighbors.get(&CompassDirection::NorthWest) {
|
||||||
west_altitude = f32::max(
|
west_altitude = f32::max(west_altitude, neighbor.altitude);
|
||||||
west_altitude,
|
neighbor_count += 1;
|
||||||
terrain[neighbor_coords.0][neighbor_coords.1].altitude,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if let Some(neighbor_coords) = neighbors.get(&CompassDirection::West) {
|
if let Some(neighbor) = neighbors.get(&CompassDirection::West) {
|
||||||
west_altitude = f32::max(
|
west_altitude = f32::max(west_altitude, neighbor.altitude);
|
||||||
west_altitude,
|
neighbor_count += 1;
|
||||||
terrain[neighbor_coords.0][neighbor_coords.1].altitude,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
west_altitude /= f32::from(neighbor_count);
|
||||||
|
neighbor_count = 0;
|
||||||
|
|
||||||
let mut east_altitude = f32::MIN;
|
let mut east_altitude = f32::MIN;
|
||||||
if let Some(neighbor_coords) = neighbors.get(&CompassDirection::North) {
|
if let Some(neighbor) = neighbors.get(&CompassDirection::North) {
|
||||||
east_altitude = f32::max(
|
east_altitude = f32::max(east_altitude, neighbor.altitude);
|
||||||
east_altitude,
|
neighbor_count += 1;
|
||||||
terrain[neighbor_coords.0][neighbor_coords.1].altitude,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if let Some(neighbor_coords) = neighbors.get(&CompassDirection::NorthWest) {
|
if let Some(neighbor) = neighbors.get(&CompassDirection::NorthWest) {
|
||||||
east_altitude = f32::max(
|
east_altitude = f32::max(east_altitude, neighbor.altitude);
|
||||||
east_altitude,
|
neighbor_count += 1;
|
||||||
terrain[neighbor_coords.0][neighbor_coords.1].altitude,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if let Some(neighbor_coords) = neighbors.get(&CompassDirection::West) {
|
if let Some(neighbor) = neighbors.get(&CompassDirection::West) {
|
||||||
east_altitude = f32::max(
|
east_altitude = f32::max(east_altitude, neighbor.altitude);
|
||||||
east_altitude,
|
neighbor_count += 1;
|
||||||
terrain[neighbor_coords.0][neighbor_coords.1].altitude,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
east_altitude /= f32::from(neighbor_count);
|
||||||
|
|
||||||
west_altitude - east_altitude
|
west_altitude - east_altitude
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -175,31 +175,19 @@ impl WorldManager {
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn generate_color(&self, cell: &TerrainCell, render_settings: &WorldRenderSettings) -> Color {
|
fn generate_color(&self, cell: &TerrainCell, render_settings: &WorldRenderSettings) -> Color {
|
||||||
if render_settings.view == WorldView::Biomes {
|
let base_color = match render_settings.view {
|
||||||
return WorldManager::biome_color(cell);
|
WorldView::Biomes => self.biome_color(cell),
|
||||||
}
|
WorldView::Topography => WorldManager::altitude_contour_color(cell.altitude),
|
||||||
|
};
|
||||||
|
let mut normalizer = 1.0;
|
||||||
|
|
||||||
let altitude_color = WorldManager::altitude_contour_color(cell.altitude);
|
let mut red = base_color.r();
|
||||||
// let altitude_color = if self.contours {
|
let mut green = base_color.g();
|
||||||
// WorldManager::altitude_contour_color(cell.altitude)
|
let mut blue = base_color.b();
|
||||||
// } else {
|
|
||||||
// WorldManager::altitude_color(cell.altitude)
|
|
||||||
// };
|
|
||||||
|
|
||||||
let mut layer_count = 1.0;
|
|
||||||
|
|
||||||
let mut red = altitude_color.r();
|
|
||||||
let mut green = altitude_color.g();
|
|
||||||
let mut blue = altitude_color.b();
|
|
||||||
|
|
||||||
if render_settings.overlay_visible(&WorldOverlay::Rainfall) {
|
if render_settings.overlay_visible(&WorldOverlay::Rainfall) {
|
||||||
layer_count += 1.0;
|
normalizer += 1.0;
|
||||||
let rainfall_color = self.rainfall_contour_color(cell.rainfall);
|
let rainfall_color = self.rainfall_contour_color(cell.rainfall);
|
||||||
// if self.contours {
|
|
||||||
// self.rainfall_contour_color(cell.rainfall)
|
|
||||||
// } else {
|
|
||||||
// WorldManager::rainfall_color(cell.rainfall)
|
|
||||||
// };
|
|
||||||
|
|
||||||
red += rainfall_color.r();
|
red += rainfall_color.r();
|
||||||
green += rainfall_color.g();
|
green += rainfall_color.g();
|
||||||
|
@ -207,20 +195,15 @@ impl WorldManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
if render_settings.overlay_visible(&WorldOverlay::Temperature) {
|
if render_settings.overlay_visible(&WorldOverlay::Temperature) {
|
||||||
layer_count += 1.0;
|
normalizer += 1.0;
|
||||||
let temperature_color = self.temperature_contour_color(cell.temperature);
|
let temperature_color = self.temperature_contour_color(cell.temperature);
|
||||||
// if self.contours {
|
|
||||||
// self.temperature_contour_color(cell.temperature)
|
|
||||||
// } else {
|
|
||||||
// WorldManager::temperature_color(cell.temperature)
|
|
||||||
// };
|
|
||||||
|
|
||||||
red += temperature_color.r();
|
red += temperature_color.r();
|
||||||
green += temperature_color.g();
|
green += temperature_color.g();
|
||||||
blue += temperature_color.b();
|
blue += temperature_color.b();
|
||||||
}
|
}
|
||||||
|
|
||||||
Color::rgb(red / layer_count, green / layer_count, blue / layer_count)
|
Color::rgb(red / normalizer, green / normalizer, blue / normalizer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[cfg(feature = "render")]
|
// #[cfg(feature = "render")]
|
||||||
|
@ -280,19 +263,28 @@ impl WorldManager {
|
||||||
|
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn biome_color(cell: &TerrainCell) -> Color {
|
fn biome_color(&self, cell: &TerrainCell) -> Color {
|
||||||
cell.biome_presences
|
let slant = self.world().get_slant(cell);
|
||||||
.iter()
|
|
||||||
.fold(Color::BLACK, |color, (biome_type, presence)| {
|
|
||||||
let biome: BiomeStats = (*biome_type).into();
|
|
||||||
let biome_color = biome.color;
|
|
||||||
|
|
||||||
Color::rgb(
|
let slant_factor = f32::min(1.0, (4.0 + (10.0 * slant / World::ALTITUDE_SPAN)) / 5.0);
|
||||||
color.r() + (biome_color.r() * presence),
|
let altitude_factor = f32::min(
|
||||||
color.g() + (biome_color.g() * presence),
|
1.0,
|
||||||
color.b() + (biome_color.b() * presence),
|
(0.5 + (cell.altitude - World::MIN_ALTITUDE) / World::ALTITUDE_SPAN) / 1.5,
|
||||||
)
|
);
|
||||||
})
|
|
||||||
|
let mut red = 0.0;
|
||||||
|
let mut green = 0.0;
|
||||||
|
let mut blue = 0.0;
|
||||||
|
|
||||||
|
for (biome, presence) in cell.biome_presences.iter() {
|
||||||
|
red += BiomeStats::from(biome).color.r() * presence;
|
||||||
|
green += BiomeStats::from(biome).color.g() * presence;
|
||||||
|
blue += BiomeStats::from(biome).color.b() * presence;
|
||||||
|
}
|
||||||
|
red *= slant_factor * altitude_factor;
|
||||||
|
green *= slant_factor * altitude_factor;
|
||||||
|
blue *= slant_factor * altitude_factor;
|
||||||
|
Color::rgb(red, green, blue)
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[cfg(feature = "render")]
|
// #[cfg(feature = "render")]
|
||||||
|
|
|
@ -5,4 +5,4 @@ pub(crate) use world_view_selection::WorldViewSelection;
|
||||||
mod world_overlay_selection;
|
mod world_overlay_selection;
|
||||||
pub(crate) use world_overlay_selection::WorldOverlaySelection;
|
pub(crate) use world_overlay_selection::WorldOverlaySelection;
|
||||||
mod save_load;
|
mod save_load;
|
||||||
pub(crate) use save_load::SaveLoad;
|
pub(crate) use save_load::SaveLoad;
|
||||||
|
|
|
@ -24,9 +24,6 @@ impl WindowSystem for TileInfo<'_, '_> {
|
||||||
let cursor_position = world.resource::<CursorMapPosition>();
|
let cursor_position = world.resource::<CursorMapPosition>();
|
||||||
let cursor_y = cursor_position.y;
|
let cursor_y = cursor_position.y;
|
||||||
let cursor_x = cursor_position.x;
|
let cursor_x = cursor_position.x;
|
||||||
_ = ui.label("Coordinates");
|
|
||||||
_ = ui.label(cursor_position.to_string());
|
|
||||||
ui.end_row();
|
|
||||||
|
|
||||||
let world_manager = world.resource::<WorldManager>();
|
let world_manager = world.resource::<WorldManager>();
|
||||||
if cursor_x >= 0
|
if cursor_x >= 0
|
||||||
|
@ -39,8 +36,13 @@ impl WindowSystem for TileInfo<'_, '_> {
|
||||||
rainfall,
|
rainfall,
|
||||||
temperature,
|
temperature,
|
||||||
biome_presences,
|
biome_presences,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
} = &world_manager.world().terrain[cursor_y as usize][cursor_x as usize];
|
} = &world_manager.world().terrain[cursor_y as usize][cursor_x as usize];
|
||||||
|
|
||||||
|
_ = ui.label("Coordinates");
|
||||||
|
_ = ui.label(format!("{x}:{y}"));
|
||||||
|
ui.end_row();
|
||||||
_ = ui.label("Altitude");
|
_ = ui.label("Altitude");
|
||||||
_ = ui.label(format!("{altitude:.2}"));
|
_ = ui.label(format!("{altitude:.2}"));
|
||||||
ui.end_row();
|
ui.end_row();
|
||||||
|
|
Loading…
Reference in a new issue