Fix planet_view feature
40c19014c9774cdf8cc4e5003393de5e8363ef17
This commit is contained in:
parent
7662fcda50
commit
b064aa0dd9
10 changed files with 648509 additions and 103 deletions
15
.github/workflows/release.yaml
vendored
15
.github/workflows/release.yaml
vendored
|
@ -11,7 +11,7 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [windows-2022, ubuntu-22.04, macos-12]
|
os: [windows-2022, ubuntu-22.04, macos-12]
|
||||||
features: ["debug,render", render, "debug", ""]
|
features: ["debug,render", "render", "debug,planet_view", "planet_view", "debug", ""]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
|
@ -27,16 +27,23 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
cargo build --release --no-default-features --features=${{ matrix.features }}
|
cargo build --release --no-default-features --features=${{ matrix.features }}
|
||||||
|
|
||||||
- name: Upload full binary
|
- name: Upload debug & render binary
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
if: ${{ matrix.features == 'debug,render' }}
|
if: ${{ matrix.features == 'debug,render' }}
|
||||||
with:
|
with:
|
||||||
name: worlds-rs-${{ matrix.os }}-debug-render
|
name: worlds-rs-${{ matrix.os }}-debug-render
|
||||||
path: target/release/worlds-sim-rust*
|
path: target/release/worlds-sim-rust*
|
||||||
|
|
||||||
- name: Upload partial-feature binary
|
- name: Upload debug & planet_view binary
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
if: ${{ matrix.features != 'debug,render' && matrix.features != '' }}
|
if: ${{ matrix.features == 'debug,planet_view' }}
|
||||||
|
with:
|
||||||
|
name: worlds-rs-${{ matrix.os }}-debug-planet_view
|
||||||
|
path: target/release/worlds-sim-rust*
|
||||||
|
|
||||||
|
- name: Upload non-debug binary
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
if: ${{ !contains(matrix.features, ',') && matrix.features != '' }}
|
||||||
with:
|
with:
|
||||||
name: worlds-rs-${{ matrix.os }}-${{ matrix.features }}
|
name: worlds-rs-${{ matrix.os }}-${{ matrix.features }}
|
||||||
path: target/release/worlds-sim-rust*
|
path: target/release/worlds-sim-rust*
|
||||||
|
|
|
@ -9,7 +9,7 @@ winit = { version = "0.26.1", features=["x11"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
debug = ["planet/debug"]
|
debug = ["planet/debug"]
|
||||||
planet_view = ["render"]
|
planet_view = ["planet/planet_view", "render"]
|
||||||
render = ["bevy/bevy_asset", "bevy/bevy_winit", "bevy/render", "planet/render", "dep:bevy_pancam"]
|
render = ["bevy/bevy_asset", "bevy/bevy_winit", "bevy/render", "planet/render", "dep:bevy_pancam"]
|
||||||
default = ["render", "debug"]
|
default = ["render", "debug"]
|
||||||
|
|
||||||
|
|
648204
planet.ron
648204
planet.ron
File diff suppressed because one or more lines are too long
|
@ -5,8 +5,9 @@ edition = "2021"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
debug = []
|
debug = []
|
||||||
|
planet_view = ["render"]
|
||||||
render = ["bevy/render"]
|
render = ["bevy/render"]
|
||||||
default = ["render", "debug"]
|
default = ["render", "debug", "planet_view"]
|
||||||
|
|
||||||
[dependencies.rand]
|
[dependencies.rand]
|
||||||
version = "0.8.5"
|
version = "0.8.5"
|
||||||
|
|
|
@ -6,7 +6,7 @@ use {
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct Biome {
|
pub struct BiomeStats {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
pub color: Color,
|
pub color: Color,
|
||||||
|
@ -33,10 +33,10 @@ macro_rules! biome_enum {
|
||||||
|
|
||||||
biome_enum!(IceCap, Ocean, Grassland, Forest, Taiga, Tundra, Desert, Rainforest);
|
biome_enum!(IceCap, Ocean, Grassland, Forest, Taiga, Tundra, Desert, Rainforest);
|
||||||
|
|
||||||
impl From<BiomeType> for Biome {
|
impl From<BiomeType> for BiomeStats {
|
||||||
fn from(biome_type: BiomeType) -> Biome {
|
fn from(biome_type: BiomeType) -> BiomeStats {
|
||||||
match biome_type {
|
match biome_type {
|
||||||
BiomeType::IceCap => Biome {
|
BiomeType::IceCap => BiomeStats {
|
||||||
name: "Ice Cap".into(),
|
name: "Ice Cap".into(),
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
color: Color::rgb_u8(253, 244, 235),
|
color: Color::rgb_u8(253, 244, 235),
|
||||||
|
@ -47,7 +47,7 @@ impl From<BiomeType> for Biome {
|
||||||
min_temperature: World::MIN_TEMPERATURE,
|
min_temperature: World::MIN_TEMPERATURE,
|
||||||
max_temperature: -15.0,
|
max_temperature: -15.0,
|
||||||
},
|
},
|
||||||
BiomeType::Ocean => Biome {
|
BiomeType::Ocean => BiomeStats {
|
||||||
name: "Ocean".into(),
|
name: "Ocean".into(),
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
color: Color::rgb_u8(28, 66, 84),
|
color: Color::rgb_u8(28, 66, 84),
|
||||||
|
@ -58,7 +58,7 @@ impl From<BiomeType> for Biome {
|
||||||
min_temperature: -15.0,
|
min_temperature: -15.0,
|
||||||
max_temperature: World::MAX_TEMPERATURE,
|
max_temperature: World::MAX_TEMPERATURE,
|
||||||
},
|
},
|
||||||
BiomeType::Grassland => Biome {
|
BiomeType::Grassland => BiomeStats {
|
||||||
name: "Grassland".into(),
|
name: "Grassland".into(),
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
color: Color::rgb_u8(167, 177, 84),
|
color: Color::rgb_u8(167, 177, 84),
|
||||||
|
@ -69,7 +69,7 @@ impl From<BiomeType> for Biome {
|
||||||
min_temperature: -5.0,
|
min_temperature: -5.0,
|
||||||
max_temperature: World::MAX_TEMPERATURE,
|
max_temperature: World::MAX_TEMPERATURE,
|
||||||
},
|
},
|
||||||
BiomeType::Forest => Biome {
|
BiomeType::Forest => BiomeStats {
|
||||||
name: "Forest".into(),
|
name: "Forest".into(),
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
color: Color::rgb_u8(76, 132, 55),
|
color: Color::rgb_u8(76, 132, 55),
|
||||||
|
@ -80,7 +80,7 @@ impl From<BiomeType> for Biome {
|
||||||
min_temperature: -5.0,
|
min_temperature: -5.0,
|
||||||
max_temperature: World::MAX_TEMPERATURE,
|
max_temperature: World::MAX_TEMPERATURE,
|
||||||
},
|
},
|
||||||
BiomeType::Taiga => Biome {
|
BiomeType::Taiga => BiomeStats {
|
||||||
name: "Taiga".into(),
|
name: "Taiga".into(),
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
color: Color::rgb_u8(43, 63, 40),
|
color: Color::rgb_u8(43, 63, 40),
|
||||||
|
@ -91,7 +91,7 @@ impl From<BiomeType> for Biome {
|
||||||
min_temperature: -15.0,
|
min_temperature: -15.0,
|
||||||
max_temperature: -0.0,
|
max_temperature: -0.0,
|
||||||
},
|
},
|
||||||
BiomeType::Tundra => Biome {
|
BiomeType::Tundra => BiomeStats {
|
||||||
name: "Tundra ".into(),
|
name: "Tundra ".into(),
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
color: Color::rgb_u8(139, 139, 128),
|
color: Color::rgb_u8(139, 139, 128),
|
||||||
|
@ -102,7 +102,7 @@ impl From<BiomeType> for Biome {
|
||||||
min_temperature: -20.0,
|
min_temperature: -20.0,
|
||||||
max_temperature: -0.0,
|
max_temperature: -0.0,
|
||||||
},
|
},
|
||||||
BiomeType::Desert => Biome {
|
BiomeType::Desert => BiomeStats {
|
||||||
name: "Desert ".into(),
|
name: "Desert ".into(),
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
color: Color::rgb_u8(253, 225, 171),
|
color: Color::rgb_u8(253, 225, 171),
|
||||||
|
@ -113,7 +113,7 @@ impl From<BiomeType> for Biome {
|
||||||
min_temperature: -5.0,
|
min_temperature: -5.0,
|
||||||
max_temperature: World::MAX_TEMPERATURE,
|
max_temperature: World::MAX_TEMPERATURE,
|
||||||
},
|
},
|
||||||
BiomeType::Rainforest => Biome {
|
BiomeType::Rainforest => BiomeStats {
|
||||||
name: "Rainforest".into(),
|
name: "Rainforest".into(),
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
color: Color::rgb_u8(59, 103, 43),
|
color: Color::rgb_u8(59, 103, 43),
|
||||||
|
@ -128,8 +128,8 @@ impl From<BiomeType> for Biome {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&BiomeType> for Biome {
|
impl From<&BiomeType> for BiomeStats {
|
||||||
fn from(biome_type: &BiomeType) -> Biome {
|
fn from(biome_type: &BiomeType) -> BiomeStats {
|
||||||
(*biome_type).into()
|
(*biome_type).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ impl<'de> Deserialize<'de> for World {
|
||||||
Seed,
|
Seed,
|
||||||
Terrain,
|
Terrain,
|
||||||
ContinentOffsets,
|
ContinentOffsets,
|
||||||
ContinentWidths,
|
ContinentSizes,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WorldVisitor;
|
struct WorldVisitor;
|
||||||
|
@ -117,7 +117,7 @@ impl<'de> Deserialize<'de> for World {
|
||||||
seed,
|
seed,
|
||||||
terrain,
|
terrain,
|
||||||
continent_offsets,
|
continent_offsets,
|
||||||
continent_widths,
|
continent_sizes: continent_widths,
|
||||||
|
|
||||||
max_altitude: world_attributes.max_altitude,
|
max_altitude: world_attributes.max_altitude,
|
||||||
min_altitude: world_attributes.min_altitude,
|
min_altitude: world_attributes.min_altitude,
|
||||||
|
@ -173,7 +173,7 @@ impl<'de> Deserialize<'de> for World {
|
||||||
}
|
}
|
||||||
continent_offsets = Some(map.next_value()?);
|
continent_offsets = Some(map.next_value()?);
|
||||||
},
|
},
|
||||||
Field::ContinentWidths => {
|
Field::ContinentSizes => {
|
||||||
if continent_widths.is_some() {
|
if continent_widths.is_some() {
|
||||||
return Err(Error::duplicate_field("continent_widths"));
|
return Err(Error::duplicate_field("continent_widths"));
|
||||||
}
|
}
|
||||||
|
@ -227,7 +227,7 @@ impl<'de> Deserialize<'de> for World {
|
||||||
seed,
|
seed,
|
||||||
terrain,
|
terrain,
|
||||||
continent_offsets,
|
continent_offsets,
|
||||||
continent_widths,
|
continent_sizes: continent_widths,
|
||||||
|
|
||||||
max_altitude: world_attributes.max_altitude,
|
max_altitude: world_attributes.max_altitude,
|
||||||
min_altitude: world_attributes.min_altitude,
|
min_altitude: world_attributes.min_altitude,
|
||||||
|
|
|
@ -5,7 +5,7 @@ use {
|
||||||
mix_values,
|
mix_values,
|
||||||
perlin,
|
perlin,
|
||||||
random_point_in_sphere,
|
random_point_in_sphere,
|
||||||
Biome,
|
BiomeStats,
|
||||||
BiomeType,
|
BiomeType,
|
||||||
CartesianError,
|
CartesianError,
|
||||||
RepeatNum,
|
RepeatNum,
|
||||||
|
@ -55,7 +55,7 @@ pub struct World {
|
||||||
|
|
||||||
pub terrain: Vec<Vec<TerrainCell>>,
|
pub terrain: Vec<Vec<TerrainCell>>,
|
||||||
pub continent_offsets: [Vec2; World::NUM_CONTINENTS as usize],
|
pub continent_offsets: [Vec2; World::NUM_CONTINENTS as usize],
|
||||||
pub continent_widths: [f32; World::NUM_CONTINENTS as usize],
|
pub continent_sizes: [Vec2; World::NUM_CONTINENTS as usize],
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub max_altitude: f32,
|
pub max_altitude: f32,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
|
@ -90,7 +90,7 @@ impl World {
|
||||||
pub(crate) const MAX_TEMPERATURE: f32 = 30.0;
|
pub(crate) const MAX_TEMPERATURE: f32 = 30.0;
|
||||||
pub(crate) const MIN_ALTITUDE: f32 = -15000.0;
|
pub(crate) const MIN_ALTITUDE: f32 = -15000.0;
|
||||||
pub(crate) const MIN_RAINFALL: f32 = 0.0;
|
pub(crate) const MIN_RAINFALL: f32 = 0.0;
|
||||||
pub(crate) const MIN_TEMPERATURE: f32 = -60.0;
|
pub(crate) const MIN_TEMPERATURE: f32 = -35.0;
|
||||||
const MOUNTAIN_RANGE_MIX_FACTOR: f32 = 0.075;
|
const MOUNTAIN_RANGE_MIX_FACTOR: f32 = 0.075;
|
||||||
const MOUNTAIN_RANGE_WIDTH_FACTOR: f32 = 25.0;
|
const MOUNTAIN_RANGE_WIDTH_FACTOR: f32 = 25.0;
|
||||||
const NUM_CONTINENTS: u8 = 7;
|
const NUM_CONTINENTS: u8 = 7;
|
||||||
|
@ -114,7 +114,7 @@ impl World {
|
||||||
height.try_into().unwrap()
|
height.try_into().unwrap()
|
||||||
],
|
],
|
||||||
continent_offsets: [default(); World::NUM_CONTINENTS as usize],
|
continent_offsets: [default(); World::NUM_CONTINENTS as usize],
|
||||||
continent_widths: [default(); World::NUM_CONTINENTS as usize],
|
continent_sizes: [default(); World::NUM_CONTINENTS as usize],
|
||||||
max_altitude: World::MIN_ALTITUDE,
|
max_altitude: World::MIN_ALTITUDE,
|
||||||
min_altitude: World::MAX_ALTITUDE,
|
min_altitude: World::MAX_ALTITUDE,
|
||||||
max_rainfall: World::MIN_RAINFALL,
|
max_rainfall: World::MIN_RAINFALL,
|
||||||
|
@ -156,9 +156,14 @@ impl World {
|
||||||
self.continent_offsets[i as usize].y =
|
self.continent_offsets[i as usize].y =
|
||||||
self.rng.gen_range(height * 1.0 / 6.0..height * 5.0 / 6.0);
|
self.rng.gen_range(height * 1.0 / 6.0..height * 5.0 / 6.0);
|
||||||
|
|
||||||
self.continent_widths[i as usize] = self
|
self.continent_sizes[i as usize] = Vec2 {
|
||||||
.rng
|
x: self.rng.gen_range(
|
||||||
.gen_range(World::CONTINENT_MIN_WIDTH_FACTOR..World::CONTINENT_MAX_WIDTH_FACTOR);
|
World::CONTINENT_MIN_WIDTH_FACTOR..World::CONTINENT_MAX_WIDTH_FACTOR,
|
||||||
|
),
|
||||||
|
y: self.rng.gen_range(
|
||||||
|
World::CONTINENT_MIN_WIDTH_FACTOR..World::CONTINENT_MAX_WIDTH_FACTOR,
|
||||||
|
),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
info!("Done generating continents");
|
info!("Done generating continents");
|
||||||
}
|
}
|
||||||
|
@ -175,20 +180,25 @@ impl World {
|
||||||
for i in 0..World::NUM_CONTINENTS {
|
for i in 0..World::NUM_CONTINENTS {
|
||||||
let idx = i as usize;
|
let idx = i as usize;
|
||||||
let Vec2 {
|
let Vec2 {
|
||||||
x: continent_x,
|
x: offset_x,
|
||||||
y: continent_y,
|
y: offset_y,
|
||||||
} = self.continent_offsets[idx];
|
} = self.continent_offsets[idx];
|
||||||
|
let Vec2 {
|
||||||
|
x: continent_width,
|
||||||
|
y: continent_height,
|
||||||
|
} = self.continent_sizes[idx];
|
||||||
|
|
||||||
let distance_x = f32::min(
|
let distance_x = f32::min(
|
||||||
f32::min(f32::abs(continent_x - x), f32::abs(width + continent_x - x)),
|
f32::min(f32::abs(offset_x - x), f32::abs(width + offset_x - x)),
|
||||||
f32::abs(continent_x - x - width),
|
f32::abs(offset_x - x - width),
|
||||||
) * beta_factor;
|
) * beta_factor
|
||||||
|
* continent_width;
|
||||||
|
|
||||||
let distance_y = f32::abs(continent_y - y);
|
let distance_y = f32::abs(offset_y - y) * continent_height;
|
||||||
|
|
||||||
let distance = f32::sqrt((distance_x * distance_x) + (distance_y * distance_y));
|
let distance = f32::sqrt((distance_x * distance_x) + (distance_y * distance_y));
|
||||||
|
|
||||||
let value = f32::max(0.0, 1.0 - self.continent_widths[idx] * distance / width);
|
let value = f32::max(0.0, 1.0 - distance / width);
|
||||||
|
|
||||||
if value > max_value {
|
if value > max_value {
|
||||||
max_value = value;
|
max_value = value;
|
||||||
|
@ -464,7 +474,7 @@ impl World {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn biome_presence(&self, cell: &TerrainCell, biome: &Biome) -> f32 {
|
fn biome_presence(&self, cell: &TerrainCell, biome: &BiomeStats) -> f32 {
|
||||||
let mut presence = 0.0;
|
let mut presence = 0.0;
|
||||||
let altitude_diff = cell.altitude - biome.min_altitude;
|
let altitude_diff = cell.altitude - biome.min_altitude;
|
||||||
if altitude_diff < 0.0 {
|
if altitude_diff < 0.0 {
|
||||||
|
|
|
@ -2,9 +2,11 @@
|
||||||
use bevy::log::debug;
|
use bevy::log::debug;
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
use bevy::utils::default;
|
use bevy::utils::default;
|
||||||
|
#[cfg(all(feature = "render", feature = "planet_view"))]
|
||||||
|
use std::f32::consts::PI;
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
use {
|
use {
|
||||||
crate::{Biome, TerrainCell},
|
crate::{BiomeStats, TerrainCell},
|
||||||
bevy::{
|
bevy::{
|
||||||
asset::{Assets, HandleId},
|
asset::{Assets, HandleId},
|
||||||
render::render_resource::Extent3d,
|
render::render_resource::Extent3d,
|
||||||
|
@ -90,8 +92,14 @@ impl Display for SaveError {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct WorldManager {
|
pub struct WorldManager {
|
||||||
world: Option<World>,
|
world: Option<World>,
|
||||||
|
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
pub image_handle_id: Option<HandleId>,
|
pub map_image_handle_id: Option<HandleId>,
|
||||||
|
#[cfg(all(feature = "render", feature = "planet_view"))]
|
||||||
|
pub planet_image_handle_id: Option<HandleId>,
|
||||||
|
#[cfg(all(feature = "render", feature = "planet_view"))]
|
||||||
|
pub planet_material_handle_id: Option<HandleId>,
|
||||||
|
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
rainfall_visible: bool,
|
rainfall_visible: bool,
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
|
@ -105,17 +113,21 @@ pub struct WorldManager {
|
||||||
impl WorldManager {
|
impl WorldManager {
|
||||||
pub fn new() -> WorldManager {
|
pub fn new() -> WorldManager {
|
||||||
Self {
|
Self {
|
||||||
#[cfg(feature = "render")]
|
|
||||||
image_handle_id: None,
|
|
||||||
world: None,
|
world: None,
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
|
map_image_handle_id: None,
|
||||||
|
#[cfg(all(feature = "render", feature = "planet_view"))]
|
||||||
|
planet_image_handle_id: None,
|
||||||
|
#[cfg(all(feature = "render", feature = "planet_view"))]
|
||||||
|
planet_material_handle_id: None,
|
||||||
|
#[cfg(feature = "render")]
|
||||||
rainfall_visible: false,
|
rainfall_visible: false,
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
temperature_visible: false,
|
temperature_visible: false,
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
biomes_visible: false,
|
biomes_visible: true,
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
contours: true,
|
contours: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,7 +187,7 @@ impl WorldManager {
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
{
|
{
|
||||||
let image_handle = &images.get_handle(
|
let image_handle = &images.get_handle(
|
||||||
self.image_handle_id
|
self.map_image_handle_id
|
||||||
.expect("Missing image handle, even though world is present"),
|
.expect("Missing image handle, even though world is present"),
|
||||||
);
|
);
|
||||||
images
|
images
|
||||||
|
@ -359,7 +371,7 @@ impl WorldManager {
|
||||||
cell.biome_presences
|
cell.biome_presences
|
||||||
.iter()
|
.iter()
|
||||||
.fold(Color::BLACK, |color, (biome_type, presence)| {
|
.fold(Color::BLACK, |color, (biome_type, presence)| {
|
||||||
let biome: Biome = (*biome_type).into();
|
let biome: BiomeStats = (*biome_type).into();
|
||||||
let biome_color = biome.color;
|
let biome_color = biome.color;
|
||||||
|
|
||||||
Color::rgb(
|
Color::rgb(
|
||||||
|
@ -370,24 +382,67 @@ impl WorldManager {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "render")]
|
// #[cfg(feature = "render")]
|
||||||
pub fn world_colors(&self) -> Vec<Color> {
|
// #[must_use]
|
||||||
match self.get_world() {
|
// fn map_colors(&self) -> Vec<Color> {
|
||||||
None => panic!("Called world_colors before generating world"),
|
// self.world()
|
||||||
Some(world) => {
|
// .terrain
|
||||||
let terrain_cells: Vec<_> = world.terrain.iter().rev().flatten().collect();
|
// .iter()
|
||||||
|
// .rev()
|
||||||
|
// .flatten()
|
||||||
|
// .map(|cell| self.generate_color(cell))
|
||||||
|
// .collect()
|
||||||
|
// }
|
||||||
|
|
||||||
terrain_cells
|
#[cfg(feature = "render")]
|
||||||
|
#[must_use]
|
||||||
|
pub fn map_color_bytes(&self) -> Vec<u8> {
|
||||||
|
self.world()
|
||||||
|
.terrain
|
||||||
.iter()
|
.iter()
|
||||||
.map(|cell| self.generate_color(cell))
|
.rev()
|
||||||
|
.flatten()
|
||||||
|
.flat_map(|cell| {
|
||||||
|
self.generate_color(cell)
|
||||||
|
.as_rgba_f32()
|
||||||
|
.iter()
|
||||||
|
.flat_map(|num| num.to_le_bytes())
|
||||||
|
.collect::<Vec<u8>>()
|
||||||
|
})
|
||||||
.collect()
|
.collect()
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "render")]
|
#[cfg(all(feature = "render", feature = "planet_view"))]
|
||||||
pub fn world_color_bytes(&self) -> Vec<u8> {
|
#[must_use]
|
||||||
self.world_colors()
|
fn planet_colors(&self) -> Vec<Color> {
|
||||||
|
let world = self.world();
|
||||||
|
let width = world.width as usize;
|
||||||
|
let height = world.height as usize;
|
||||||
|
|
||||||
|
let mut colors = vec![Color::PINK; height * width];
|
||||||
|
|
||||||
|
for y in 0..world.height as usize * 2 {
|
||||||
|
for x in 0..world.width as usize {
|
||||||
|
let factor_y = (1.0 - f32::cos(PI * y as f32 / (world.height * 2) as f32)) / 2.0;
|
||||||
|
let real_y = f32::floor(world.height as f32 * factor_y) as usize;
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
assert!(
|
||||||
|
real_y < world.height as usize,
|
||||||
|
"Trying to get cell off of planet. {}/{}",
|
||||||
|
real_y,
|
||||||
|
world.height
|
||||||
|
);
|
||||||
|
|
||||||
|
colors[real_y * width + x] = self.generate_color(&world.terrain[real_y][x]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
colors
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "render", feature = "planet_view"))]
|
||||||
|
#[must_use]
|
||||||
|
pub fn planet_color_bytes(&self) -> Vec<u8> {
|
||||||
|
self.planet_colors()
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|color| {
|
.flat_map(|color| {
|
||||||
color
|
color
|
||||||
|
|
|
@ -15,7 +15,7 @@ macro_rules! toolbar_enum {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "render")]
|
#[cfg(all(feature = "render", not(feature = "planet_view")))]
|
||||||
toolbar_enum!(
|
toolbar_enum!(
|
||||||
GenerateWorld,
|
GenerateWorld,
|
||||||
SaveWorld,
|
SaveWorld,
|
||||||
|
@ -25,6 +25,17 @@ toolbar_enum!(
|
||||||
Biomes,
|
Biomes,
|
||||||
Contours,
|
Contours,
|
||||||
);
|
);
|
||||||
|
#[cfg(all(feature = "render", feature = "planet_view"))]
|
||||||
|
toolbar_enum!(
|
||||||
|
GenerateWorld,
|
||||||
|
SaveWorld,
|
||||||
|
LoadWorld,
|
||||||
|
Rainfall,
|
||||||
|
Temperature,
|
||||||
|
Biomes,
|
||||||
|
Contours,
|
||||||
|
PlanetView,
|
||||||
|
);
|
||||||
|
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
impl From<ToolbarButton> for &'static str {
|
impl From<ToolbarButton> for &'static str {
|
||||||
|
@ -37,6 +48,8 @@ impl From<ToolbarButton> for &'static str {
|
||||||
ToolbarButton::GenerateWorld => "Generate new world",
|
ToolbarButton::GenerateWorld => "Generate new world",
|
||||||
ToolbarButton::SaveWorld => "Save",
|
ToolbarButton::SaveWorld => "Save",
|
||||||
ToolbarButton::LoadWorld => "Load",
|
ToolbarButton::LoadWorld => "Load",
|
||||||
|
#[cfg(feature = "planet_view")]
|
||||||
|
ToolbarButton::PlanetView => "Toggle planet view",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
196
src/main.rs
196
src/main.rs
|
@ -37,16 +37,6 @@ mod plugins;
|
||||||
mod resources;
|
mod resources;
|
||||||
mod ui_helpers;
|
mod ui_helpers;
|
||||||
|
|
||||||
#[cfg(all(feature = "render", feature = "planet_view"))]
|
|
||||||
use bevy::{
|
|
||||||
asset::Handle,
|
|
||||||
core_pipeline::core_3d::Camera3dBundle,
|
|
||||||
pbr::{PbrBundle, PointLight, PointLightBundle, StandardMaterial},
|
|
||||||
prelude::Vec3,
|
|
||||||
render::camera::OrthographicProjection,
|
|
||||||
render::mesh::{shape::Icosphere, Mesh},
|
|
||||||
transform::components::Transform,
|
|
||||||
};
|
|
||||||
#[cfg(all(feature = "debug", feature = "render"))]
|
#[cfg(all(feature = "debug", feature = "render"))]
|
||||||
use bevy::{
|
use bevy::{
|
||||||
diagnostic::{Diagnostics, FrameTimeDiagnosticsPlugin},
|
diagnostic::{Diagnostics, FrameTimeDiagnosticsPlugin},
|
||||||
|
@ -100,7 +90,7 @@ use {
|
||||||
markers::{InfoPanel, ToolbarButton},
|
markers::{InfoPanel, ToolbarButton},
|
||||||
third_party::PanCam,
|
third_party::PanCam,
|
||||||
},
|
},
|
||||||
planet::Biome,
|
planet::BiomeStats,
|
||||||
resources::CursorMapPosition,
|
resources::CursorMapPosition,
|
||||||
ui_helpers::{toolbar_button, toolbar_button_text},
|
ui_helpers::{toolbar_button, toolbar_button_text},
|
||||||
};
|
};
|
||||||
|
@ -113,24 +103,72 @@ use {
|
||||||
planet::WorldManager,
|
planet::WorldManager,
|
||||||
plugins::WorldPlugins,
|
plugins::WorldPlugins,
|
||||||
};
|
};
|
||||||
|
#[cfg(all(feature = "render", feature = "planet_view"))]
|
||||||
|
use {
|
||||||
|
bevy::{
|
||||||
|
asset::Handle,
|
||||||
|
core_pipeline::core_3d::{Camera3d, Camera3dBundle},
|
||||||
|
ecs::query::Without,
|
||||||
|
pbr::{PbrBundle, PointLight, PointLightBundle, StandardMaterial},
|
||||||
|
prelude::{Quat, Vec3},
|
||||||
|
render::camera::OrthographicProjection,
|
||||||
|
render::mesh::{shape::UVSphere, Mesh},
|
||||||
|
transform::components::Transform,
|
||||||
|
},
|
||||||
|
std::f32::consts::FRAC_PI_2,
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
fn refresh_world_texture(images: &mut Assets<Image>, world_manager: &WorldManager) {
|
fn refresh_map_texture(
|
||||||
|
images: &mut Assets<Image>,
|
||||||
|
#[cfg(feature = "planet_view")] materials: &mut Assets<StandardMaterial>,
|
||||||
|
world_manager: &WorldManager,
|
||||||
|
) {
|
||||||
|
let world = world_manager.world();
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
debug!("refreshing world texture");
|
debug!("refreshing world texture");
|
||||||
let image_handle = images.get_handle(world_manager.image_handle_id.expect("No image handle"));
|
let map_image_handle = images.get_handle(
|
||||||
let world_image = images
|
world_manager
|
||||||
.get_mut(&image_handle)
|
.map_image_handle_id
|
||||||
.expect("Image handle pointing to non-existing texture");
|
.expect("No map image handle"),
|
||||||
world_image.resize(Extent3d {
|
);
|
||||||
width: world_manager.world().width,
|
let map_image = images
|
||||||
height: world_manager.world().height,
|
.get_mut(&map_image_handle)
|
||||||
|
.expect("Map image handle pointing to non-existing image");
|
||||||
|
map_image.resize(Extent3d {
|
||||||
|
width: world.width,
|
||||||
|
height: world.height,
|
||||||
depth_or_array_layers: 1,
|
depth_or_array_layers: 1,
|
||||||
});
|
});
|
||||||
world_image.data = world_manager.world_color_bytes();
|
map_image.data = world_manager.map_color_bytes();
|
||||||
|
|
||||||
// TODO: Update Icosphere material. Try to find out why it doesn't
|
#[cfg(feature = "planet_view")]
|
||||||
// automatically
|
{
|
||||||
|
let planet_image_handle = images.get_handle(
|
||||||
|
world_manager
|
||||||
|
.planet_image_handle_id
|
||||||
|
.expect("No planet image handle"),
|
||||||
|
);
|
||||||
|
let planet_image = images
|
||||||
|
.get_mut(&planet_image_handle)
|
||||||
|
.expect("Planet image handle pointing to non-existing image");
|
||||||
|
planet_image.resize(Extent3d {
|
||||||
|
width: world.width,
|
||||||
|
height: world.height,
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
});
|
||||||
|
planet_image.data = world_manager.planet_color_bytes();
|
||||||
|
|
||||||
|
let planet_material_handle = materials.get_handle(
|
||||||
|
world_manager
|
||||||
|
.planet_material_handle_id
|
||||||
|
.expect("No planet material handle"),
|
||||||
|
);
|
||||||
|
let planet_material = materials
|
||||||
|
.get_mut(&planet_material_handle)
|
||||||
|
.expect("Planet material handle pointing to non-existing material");
|
||||||
|
planet_material.base_color_texture = Some(planet_image_handle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
|
@ -150,6 +188,19 @@ fn handle_toolbar_button(
|
||||||
mut windows: ResMut<'_, Windows>,
|
mut windows: ResMut<'_, Windows>,
|
||||||
mut images: ResMut<'_, Assets<Image>>,
|
mut images: ResMut<'_, Assets<Image>>,
|
||||||
mut world_manager: ResMut<'_, WorldManager>,
|
mut world_manager: ResMut<'_, WorldManager>,
|
||||||
|
#[cfg(feature = "planet_view")] mut camera_3d_query: Query<
|
||||||
|
'_,
|
||||||
|
'_,
|
||||||
|
&mut Camera,
|
||||||
|
(With<Camera3d>, Without<Camera2d>),
|
||||||
|
>,
|
||||||
|
#[cfg(feature = "planet_view")] mut camera_2d_query: Query<
|
||||||
|
'_,
|
||||||
|
'_,
|
||||||
|
&mut Camera,
|
||||||
|
(With<Camera2d>, Without<Camera3d>),
|
||||||
|
>,
|
||||||
|
#[cfg(feature = "planet_view")] mut materials: ResMut<'_, Assets<StandardMaterial>>,
|
||||||
) {
|
) {
|
||||||
for (interaction, mut color, toolbar_button) in &mut interaction_query {
|
for (interaction, mut color, toolbar_button) in &mut interaction_query {
|
||||||
match *interaction {
|
match *interaction {
|
||||||
|
@ -161,25 +212,45 @@ fn handle_toolbar_button(
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
debug!("Toggling rainfall");
|
debug!("Toggling rainfall");
|
||||||
world_manager.toggle_rainfall();
|
world_manager.toggle_rainfall();
|
||||||
refresh_world_texture(&mut images, &world_manager);
|
refresh_map_texture(
|
||||||
|
&mut images,
|
||||||
|
#[cfg(feature = "planet_view")]
|
||||||
|
&mut materials,
|
||||||
|
&world_manager,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
ToolbarButton::Temperature => {
|
ToolbarButton::Temperature => {
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
debug!("Toggling temperature");
|
debug!("Toggling temperature");
|
||||||
world_manager.toggle_temperature();
|
world_manager.toggle_temperature();
|
||||||
refresh_world_texture(&mut images, &world_manager);
|
refresh_map_texture(
|
||||||
|
&mut images,
|
||||||
|
#[cfg(feature = "planet_view")]
|
||||||
|
&mut materials,
|
||||||
|
&world_manager,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
ToolbarButton::Biomes => {
|
ToolbarButton::Biomes => {
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
debug!("Toggling biomes");
|
debug!("Toggling biomes");
|
||||||
world_manager.toggle_biomes();
|
world_manager.toggle_biomes();
|
||||||
refresh_world_texture(&mut images, &world_manager);
|
refresh_map_texture(
|
||||||
|
&mut images,
|
||||||
|
#[cfg(feature = "planet_view")]
|
||||||
|
&mut materials,
|
||||||
|
&world_manager,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
ToolbarButton::Contours => {
|
ToolbarButton::Contours => {
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
debug!("Toggling contours");
|
debug!("Toggling contours");
|
||||||
world_manager.toggle_contours();
|
world_manager.toggle_contours();
|
||||||
refresh_world_texture(&mut images, &world_manager);
|
refresh_map_texture(
|
||||||
|
&mut images,
|
||||||
|
#[cfg(feature = "planet_view")]
|
||||||
|
&mut materials,
|
||||||
|
&world_manager,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
ToolbarButton::GenerateWorld => {
|
ToolbarButton::GenerateWorld => {
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
|
@ -187,7 +258,12 @@ fn handle_toolbar_button(
|
||||||
_ = world_manager
|
_ = world_manager
|
||||||
.new_world()
|
.new_world()
|
||||||
.expect("Failed to generate new world");
|
.expect("Failed to generate new world");
|
||||||
refresh_world_texture(&mut images, &world_manager);
|
refresh_map_texture(
|
||||||
|
&mut images,
|
||||||
|
#[cfg(feature = "planet_view")]
|
||||||
|
&mut materials,
|
||||||
|
&world_manager,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
ToolbarButton::SaveWorld => {
|
ToolbarButton::SaveWorld => {
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
|
@ -198,7 +274,21 @@ fn handle_toolbar_button(
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
debug!("Loading world");
|
debug!("Loading world");
|
||||||
_ = world_manager.load_world("planet.ron", &mut images);
|
_ = world_manager.load_world("planet.ron", &mut images);
|
||||||
refresh_world_texture(&mut images, &world_manager);
|
refresh_map_texture(
|
||||||
|
&mut images,
|
||||||
|
#[cfg(feature = "planet_view")]
|
||||||
|
&mut materials,
|
||||||
|
&world_manager,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
#[cfg(feature = "planet_view")]
|
||||||
|
ToolbarButton::PlanetView => {
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
debug!("Toggling planet view");
|
||||||
|
let mut camera_3d = camera_3d_query.single_mut();
|
||||||
|
camera_3d.is_active = !camera_3d.is_active;
|
||||||
|
let mut camera_2d = camera_2d_query.single_mut();
|
||||||
|
camera_2d.is_active = !camera_2d.is_active;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -285,7 +375,7 @@ fn update_info_panel(
|
||||||
.map(|(biome_type, presence)| {
|
.map(|(biome_type, presence)| {
|
||||||
format!(
|
format!(
|
||||||
"Biome: {} ({:.2}%)",
|
"Biome: {} ({:.2}%)",
|
||||||
(<Biome>::from(biome_type).name),
|
(<BiomeStats>::from(biome_type).name),
|
||||||
presence * 100.0
|
presence * 100.0
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -307,7 +397,7 @@ fn update_info_panel(
|
||||||
.map(|(biome_type, presence)| {
|
.map(|(biome_type, presence)| {
|
||||||
format!(
|
format!(
|
||||||
"Biome: {} ({:.2}%)",
|
"Biome: {} ({:.2}%)",
|
||||||
(<Biome>::from(biome_type).name),
|
(<BiomeStats>::from(biome_type).name),
|
||||||
presence * 100.0
|
presence * 100.0
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -354,8 +444,8 @@ fn generate_graphics(
|
||||||
y: (WORLD_SCALE * world.height as i32) as f32,
|
y: (WORLD_SCALE * world.height as i32) as f32,
|
||||||
};
|
};
|
||||||
|
|
||||||
let image_handle = images.add(Image {
|
let map_image_handle = images.add(Image {
|
||||||
data: world_manager.world_color_bytes(),
|
data: world_manager.map_color_bytes(),
|
||||||
texture_descriptor: TextureDescriptor {
|
texture_descriptor: TextureDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
size: Extent3d {
|
size: Extent3d {
|
||||||
|
@ -371,10 +461,30 @@ fn generate_graphics(
|
||||||
},
|
},
|
||||||
..default()
|
..default()
|
||||||
});
|
});
|
||||||
world_manager.image_handle_id = Some(image_handle.id);
|
world_manager.map_image_handle_id = Some(map_image_handle.id);
|
||||||
|
|
||||||
#[cfg(feature = "planet_view")]
|
#[cfg(feature = "planet_view")]
|
||||||
{
|
{
|
||||||
|
let world = world_manager.world();
|
||||||
|
let planet_image_handle = images.add(Image {
|
||||||
|
data: world_manager.planet_color_bytes(),
|
||||||
|
texture_descriptor: TextureDescriptor {
|
||||||
|
label: None,
|
||||||
|
size: Extent3d {
|
||||||
|
width: world.width,
|
||||||
|
height: world.height,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
dimension: TextureDimension::D2,
|
||||||
|
format: TextureFormat::Rgba32Float,
|
||||||
|
mip_level_count: 1,
|
||||||
|
sample_count: 1,
|
||||||
|
usage: TextureUsages::COPY_DST | TextureUsages::TEXTURE_BINDING,
|
||||||
|
},
|
||||||
|
..default()
|
||||||
|
});
|
||||||
|
world_manager.planet_image_handle_id = Some(planet_image_handle.id);
|
||||||
|
|
||||||
_ = commands.spawn_bundle(Camera3dBundle {
|
_ = commands.spawn_bundle(Camera3dBundle {
|
||||||
camera: Camera {
|
camera: Camera {
|
||||||
is_active: false,
|
is_active: false,
|
||||||
|
@ -388,17 +498,25 @@ fn generate_graphics(
|
||||||
.into(),
|
.into(),
|
||||||
..default()
|
..default()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let planet_material_handle = materials.add(
|
||||||
|
images
|
||||||
|
.get_handle(world_manager.planet_image_handle_id.unwrap())
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
|
world_manager.planet_material_handle_id = Some(planet_material_handle.id);
|
||||||
|
|
||||||
_ = commands.spawn_bundle(PbrBundle {
|
_ = commands.spawn_bundle(PbrBundle {
|
||||||
mesh: meshes.add(Mesh::from(Icosphere {
|
mesh: meshes.add(Mesh::from(UVSphere {
|
||||||
radius: 2.0,
|
radius: 2.0,
|
||||||
subdivisions: 9,
|
..default()
|
||||||
})),
|
})),
|
||||||
material: materials.add(images.get_handle(world_manager.image_handle_id).into()),
|
material: planet_material_handle,
|
||||||
transform: Transform::from_translation(default()),
|
transform: Transform::from_rotation(Quat::from_rotation_x(FRAC_PI_2)),
|
||||||
..default()
|
..default()
|
||||||
});
|
});
|
||||||
_ = commands.spawn_bundle(PointLightBundle {
|
_ = commands.spawn_bundle(PointLightBundle {
|
||||||
transform: Transform::from_xyz(-20.0, 20.0, 50.0),
|
transform: Transform::from_xyz(-20.0, 0.0, 50.0),
|
||||||
point_light: PointLight {
|
point_light: PointLight {
|
||||||
intensity: 600000.,
|
intensity: 600000.,
|
||||||
range: 100.,
|
range: 100.,
|
||||||
|
@ -415,7 +533,7 @@ fn generate_graphics(
|
||||||
..default()
|
..default()
|
||||||
});
|
});
|
||||||
_ = commands.spawn_bundle(SpriteBundle {
|
_ = commands.spawn_bundle(SpriteBundle {
|
||||||
texture: images.get_handle(world_manager.image_handle_id.unwrap()),
|
texture: images.get_handle(world_manager.map_image_handle_id.unwrap()),
|
||||||
sprite: Sprite {
|
sprite: Sprite {
|
||||||
custom_size: Some(custom_sprite_size),
|
custom_size: Some(custom_sprite_size),
|
||||||
..default()
|
..default()
|
||||||
|
|
Loading…
Reference in a new issue