Rename planet_view to globe view; Use macros slightly better; PlanetView

f45efb28f1be9e8e39b84196b97d121b64fff607
This commit is contained in:
Tobias Berger 2022-09-20 15:14:16 +02:00
parent 8190666f97
commit afd2495e43
Signed by: toby
GPG key ID: 2D05EFAB764D6A88
12 changed files with 289 additions and 148 deletions

View file

@ -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,planet_view", "planet_view", "debug", ""] features: ["debug,render", "render", "debug,globe_view", "globe_view", "debug", ""]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout - name: Checkout
@ -34,11 +34,11 @@ jobs:
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 debug & planet_view binary - name: Upload debug & globe_view binary
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
if: ${{ matrix.features == 'debug,planet_view' }} if: ${{ matrix.features == 'debug,globe_view' }}
with: with:
name: worlds-rs-${{ matrix.os }}-debug-planet_view name: worlds-rs-${{ matrix.os }}-debug-globe_view
path: target/release/worlds-sim-rust* path: target/release/worlds-sim-rust*
- name: Upload non-debug binary - name: Upload non-debug binary

View file

@ -9,7 +9,7 @@ winit = { version = "0.26.1", features=["x11"] }
[features] [features]
debug = ["planet/debug"] debug = ["planet/debug"]
planet_view = ["planet/planet_view", "render"] globe_view = ["planet/globe_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"]

View file

@ -5,9 +5,9 @@ edition = "2021"
[features] [features]
debug = [] debug = []
planet_view = ["render"] globe_view = ["render"]
render = ["bevy/render"] render = ["bevy/render"]
default = ["render", "debug", "planet_view"] default = ["render", "debug", "globe_view"]
[dependencies.rand] [dependencies.rand]
version = "0.8.5" version = "0.8.5"

View file

@ -1,9 +1,6 @@
use crate::{macros::iterable_enum, World};
#[cfg(feature = "render")] #[cfg(feature = "render")]
use bevy::render::color::Color; use bevy::render::color::Color;
use {
crate::World,
serde::{Deserialize, Serialize},
};
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct BiomeStats { pub struct BiomeStats {
@ -18,20 +15,16 @@ pub struct BiomeStats {
pub max_temperature: f32, pub max_temperature: f32,
} }
macro_rules! biome_enum { iterable_enum!(BiomeType {
($($Variant:ident),*$(,)?) => IceCap,
{ Ocean,
#[derive(Debug, Copy, Clone, Deserialize, Serialize)] Grassland,
pub enum BiomeType { Forest,
$($Variant),*, Taiga,
} Tundra,
impl BiomeType { Desert,
pub const BIOMES: &'static [BiomeType] = &[$(BiomeType::$Variant),*]; Rainforest
} });
}
}
biome_enum!(IceCap, Ocean, Grassland, Forest, Taiga, Tundra, Desert, Rainforest);
impl From<BiomeType> for BiomeStats { impl From<BiomeType> for BiomeStats {
fn from(biome_type: BiomeType) -> BiomeStats { fn from(biome_type: BiomeType) -> BiomeStats {

View file

@ -37,8 +37,8 @@ pub use world::*;
pub mod biome; pub mod biome;
pub use biome::*; pub use biome::*;
pub mod world_manager; pub mod world_manager;
pub use world_manager::*; pub use world_manager::WorldManager;
pub(crate) mod macros;
pub mod math_util; pub mod math_util;
pub use math_util::*;
pub mod perlin; pub mod perlin;
pub mod saving; pub mod saving;

18
planet/src/macros.rs Normal file
View file

@ -0,0 +1,18 @@
macro_rules! iterable_enum {
($Name:ident { $($Variant:ident),*$(,)? }) =>
{
#[derive(Debug, Copy, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
pub enum $Name {
$($Variant),*,
}
impl $Name {
pub const ITEMS: &'static [$Name] = &[$($Name::$Variant),*];
pub const ITEM_COUNT: usize = $Name::ITEMS.len();
pub fn iterator() -> core::slice::Iter<'static, $Name> {
$Name::ITEMS.iter()
}
}
}
}
pub(crate) use iterable_enum;

View file

@ -1,16 +1,23 @@
// TODO: Logging doesn't seem to work here? Figure out why and fix // TODO: Logging doesn't seem to work here? Figure out why and fix
use { use {
crate::{ crate::{
cartesian_coordinates, math_util::{
mix_values, cartesian_coordinates,
mix_values,
random_point_in_sphere,
CartesianError,
RepeatNum,
},
perlin, perlin,
random_point_in_sphere,
BiomeStats, BiomeStats,
BiomeType, BiomeType,
CartesianError,
RepeatNum,
}, },
bevy::{log::info, math::Vec3A, prelude::Vec2, utils::default}, bevy::{
log::info,
math::Vec3A,
prelude::Vec2,
utils::{default, HashMap},
},
rand::{rngs::StdRng, Rng, SeedableRng}, rand::{rngs::StdRng, Rng, SeedableRng},
serde::{Deserialize, Serialize}, serde::{Deserialize, Serialize},
std::{ std::{
@ -47,6 +54,18 @@ impl Display for WorldGenError {
} }
} }
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum CompassDirection {
North,
NorthEast,
East,
SouthEast,
South,
SouthWest,
West,
NorthWest,
}
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub struct World { pub struct World {
pub width: u32, pub width: u32,
@ -456,7 +475,7 @@ impl World {
let mut total_presence = 0.0; let mut total_presence = 0.0;
let mut biome_presences = vec![]; let mut biome_presences = vec![];
for biome_type in BiomeType::BIOMES { for biome_type in BiomeType::iterator() {
let presence = self.biome_presence(cell, &biome_type.into()); let presence = self.biome_presence(cell, &biome_type.into());
if presence <= 0.0 { if presence <= 0.0 {
@ -526,4 +545,92 @@ impl World {
presence presence
} }
#[must_use]
pub fn cell_neighbors(&self, x: usize, y: usize) -> HashMap<CompassDirection, (usize, usize)> {
let mut neighbors = HashMap::new();
let height = self.height as usize;
let width = self.width as usize;
let north_edge = y >= height - 1;
let east_edge = x >= width - 1;
let south_edge = y == 0;
let west_edge = x == 0;
if !north_edge {
_ = neighbors.insert_unique_unchecked(CompassDirection::North, (y + 1, x));
}
if !north_edge && !east_edge {
_ = neighbors.insert_unique_unchecked(CompassDirection::NorthEast, (y + 1, x + 1));
}
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));
}
if !south_edge {
_ = neighbors.insert_unique_unchecked(CompassDirection::South, (y - 1, 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
}
#[must_use]
pub fn get_slant(&self, x: usize, y: usize) -> f32 {
let neighbors = self.cell_neighbors(x, y);
let terrain = &self.terrain;
let mut west_altitude = f32::MIN;
if let Some(neighbor_coords) = neighbors.get(&CompassDirection::North) {
west_altitude = f32::max(
west_altitude,
terrain[neighbor_coords.0][neighbor_coords.1].altitude,
);
}
if let Some(neighbor_coords) = neighbors.get(&CompassDirection::NorthWest) {
west_altitude = f32::max(
west_altitude,
terrain[neighbor_coords.0][neighbor_coords.1].altitude,
);
}
if let Some(neighbor_coords) = neighbors.get(&CompassDirection::West) {
west_altitude = f32::max(
west_altitude,
terrain[neighbor_coords.0][neighbor_coords.1].altitude,
);
}
let mut east_altitude = f32::MIN;
if let Some(neighbor_coords) = neighbors.get(&CompassDirection::North) {
east_altitude = f32::max(
east_altitude,
terrain[neighbor_coords.0][neighbor_coords.1].altitude,
);
}
if let Some(neighbor_coords) = neighbors.get(&CompassDirection::NorthWest) {
east_altitude = f32::max(
east_altitude,
terrain[neighbor_coords.0][neighbor_coords.1].altitude,
);
}
if let Some(neighbor_coords) = neighbors.get(&CompassDirection::West) {
east_altitude = f32::max(
east_altitude,
terrain[neighbor_coords.0][neighbor_coords.1].altitude,
);
}
west_altitude - east_altitude
}
} }

View file

@ -2,19 +2,10 @@
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"))] #[cfg(all(feature = "render", feature = "globe_view"))]
use std::f32::consts::PI; use std::f32::consts::PI;
#[cfg(feature = "render")]
use { use {
crate::{BiomeStats, TerrainCell}, crate::{macros::iterable_enum, World, WorldGenError},
bevy::{
asset::{Assets, HandleId},
render::render_resource::Extent3d,
render::{color::Color, texture::Image},
},
};
use {
crate::{World, WorldGenError},
bevy::log::warn, bevy::log::warn,
rand::random, rand::random,
std::{ std::{
@ -25,6 +16,15 @@ use {
path::Path, path::Path,
}, },
}; };
#[cfg(feature = "render")]
use {
crate::{BiomeStats, TerrainCell},
bevy::{
asset::{Assets, HandleId},
render::render_resource::Extent3d,
render::{color::Color, texture::Image},
},
};
#[derive(Debug)] #[derive(Debug)]
pub enum LoadError { pub enum LoadError {
@ -89,43 +89,46 @@ impl Display for SaveError {
} }
} }
iterable_enum!(PlanetView { Biomes, Altitude });
#[derive(Debug)] #[derive(Debug)]
pub struct WorldManager { pub struct WorldManager {
world: Option<World>, world: Option<World>,
#[cfg(feature = "render")] #[cfg(feature = "render")]
pub map_image_handle_id: Option<HandleId>, pub map_image_handle_id: Option<HandleId>,
#[cfg(all(feature = "render", feature = "planet_view"))] #[cfg(all(feature = "render", feature = "globe_view"))]
pub planet_image_handle_id: Option<HandleId>, pub globe_image_handle_id: Option<HandleId>,
#[cfg(all(feature = "render", feature = "planet_view"))] #[cfg(all(feature = "render", feature = "globe_view"))]
pub planet_material_handle_id: Option<HandleId>, pub globe_material_handle_id: Option<HandleId>,
#[cfg(feature = "render")] #[cfg(feature = "render")]
rainfall_visible: bool, rainfall_visible: bool,
#[cfg(feature = "render")] #[cfg(feature = "render")]
temperature_visible: bool, temperature_visible: bool,
#[cfg(feature = "render")] #[cfg(feature = "render")]
biomes_visible: bool,
#[cfg(feature = "render")]
contours: bool, contours: bool,
#[cfg(feature = "render")]
view: PlanetView,
} }
impl WorldManager { impl WorldManager {
#[must_use]
pub fn new() -> WorldManager { pub fn new() -> WorldManager {
Self { Self {
world: None, world: None,
#[cfg(feature = "render")] #[cfg(feature = "render")]
map_image_handle_id: None, map_image_handle_id: None,
#[cfg(all(feature = "render", feature = "planet_view"))] #[cfg(all(feature = "render", feature = "globe_view"))]
planet_image_handle_id: None, globe_image_handle_id: None,
#[cfg(all(feature = "render", feature = "planet_view"))] #[cfg(all(feature = "render", feature = "globe_view"))]
planet_material_handle_id: None, globe_material_handle_id: None,
#[cfg(feature = "render")] #[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: true, view: PlanetView::Biomes,
#[cfg(feature = "render")] #[cfg(feature = "render")]
contours: false, contours: false,
} }
@ -228,14 +231,19 @@ impl WorldManager {
} }
#[cfg(feature = "render")] #[cfg(feature = "render")]
pub fn toggle_biomes(&mut self) { pub fn cycle_view(&mut self) {
let idx = (PlanetView::iterator()
.position(|view| *view == self.view)
.unwrap()
+ 1)
% PlanetView::ITEM_COUNT;
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
if self.temperature_visible { debug!(
debug!("Turning biomes off"); "Cycling view from {:#?} to {:#?}",
} else { self.view,
debug!("Turning biomes on"); PlanetView::ITEMS[idx]
} );
self.biomes_visible = !self.biomes_visible; self.view = PlanetView::ITEMS[idx];
} }
#[cfg(feature = "render")] #[cfg(feature = "render")]
@ -249,6 +257,7 @@ impl WorldManager {
self.contours = !self.contours; self.contours = !self.contours;
} }
#[must_use]
pub fn get_world(&self) -> Option<&World> { pub fn get_world(&self) -> Option<&World> {
self.world.as_ref() self.world.as_ref()
} }
@ -267,8 +276,9 @@ impl WorldManager {
} }
#[cfg(feature = "render")] #[cfg(feature = "render")]
#[must_use]
fn generate_color(&self, cell: &TerrainCell) -> Color { fn generate_color(&self, cell: &TerrainCell) -> Color {
if self.biomes_visible { if self.view == PlanetView::Biomes {
return WorldManager::biome_color(cell); return WorldManager::biome_color(cell);
} }
@ -316,6 +326,7 @@ impl WorldManager {
} }
#[cfg(feature = "render")] #[cfg(feature = "render")]
#[must_use]
fn altitude_color(altitude: f32) -> Color { fn altitude_color(altitude: f32) -> Color {
if altitude < 0.0 { if altitude < 0.0 {
Color::rgb(0.0, 0.0, (2.0 - altitude / World::MIN_ALTITUDE) / 2.0) Color::rgb(0.0, 0.0, (2.0 - altitude / World::MIN_ALTITUDE) / 2.0)
@ -327,6 +338,7 @@ impl WorldManager {
} }
#[cfg(feature = "render")] #[cfg(feature = "render")]
#[must_use]
fn altitude_contour_color(altitude: f32) -> Color { fn altitude_contour_color(altitude: f32) -> Color {
if altitude < 0.0 { if altitude < 0.0 {
Color::rgb(0.0, 0.0, (2.0 - altitude / World::MIN_ALTITUDE) / 2.0) Color::rgb(0.0, 0.0, (2.0 - altitude / World::MIN_ALTITUDE) / 2.0)
@ -342,6 +354,7 @@ impl WorldManager {
} }
#[cfg(feature = "render")] #[cfg(feature = "render")]
#[must_use]
fn rainfall_contour_color(&self, rainfall: f32) -> Color { fn rainfall_contour_color(&self, rainfall: f32) -> Color {
let mut shade_value = 1.0; let mut shade_value = 1.0;
let value = rainfall / self.world().max_rainfall; let value = rainfall / self.world().max_rainfall;
@ -354,6 +367,7 @@ impl WorldManager {
} }
#[cfg(feature = "render")] #[cfg(feature = "render")]
#[must_use]
fn temperature_contour_color(&self, temperature: f32) -> Color { fn temperature_contour_color(&self, temperature: f32) -> Color {
let mut shade_value = 1.0; let mut shade_value = 1.0;
let value = (temperature - self.world().min_temperature) let value = (temperature - self.world().min_temperature)
@ -367,6 +381,7 @@ impl WorldManager {
} }
#[cfg(feature = "render")] #[cfg(feature = "render")]
#[must_use]
fn biome_color(cell: &TerrainCell) -> Color { fn biome_color(cell: &TerrainCell) -> Color {
cell.biome_presences cell.biome_presences
.iter() .iter()
@ -412,9 +427,9 @@ impl WorldManager {
.collect() .collect()
} }
#[cfg(all(feature = "render", feature = "planet_view"))] #[cfg(all(feature = "render", feature = "globe_view"))]
#[must_use] #[must_use]
fn planet_colors(&self) -> Vec<Color> { fn globe_colors(&self) -> Vec<Color> {
let world = self.world(); let world = self.world();
let width = world.width as usize; let width = world.width as usize;
let height = world.height as usize; let height = world.height as usize;
@ -439,10 +454,10 @@ impl WorldManager {
colors colors
} }
#[cfg(all(feature = "render", feature = "planet_view"))] #[cfg(all(feature = "render", feature = "globe_view"))]
#[must_use] #[must_use]
pub fn planet_color_bytes(&self) -> Vec<u8> { pub fn globe_color_bytes(&self) -> Vec<u8> {
self.planet_colors() self.globe_colors()
.iter() .iter()
.flat_map(|color| { .flat_map(|color| {
color color

View file

@ -1,41 +1,27 @@
#[cfg(feature = "render")] #[cfg(feature = "render")]
use bevy::ecs::component::Component; use {crate::macros::iterable_enum, bevy::ecs::component::Component};
#[cfg(feature = "render")] #[cfg(all(feature = "render", not(feature = "globe_view")))]
macro_rules! toolbar_enum { iterable_enum!(ToolbarButton {
($($Variant:ident),*$(,)?) =>
{
#[derive(Debug, Component, Copy, Clone)]
pub enum ToolbarButton {
$($Variant),*,
}
impl ToolbarButton {
pub const BUTTONS: &'static [ToolbarButton] = &[$(ToolbarButton::$Variant),*];
}
}
}
#[cfg(all(feature = "render", not(feature = "planet_view")))]
toolbar_enum!(
GenerateWorld, GenerateWorld,
SaveWorld, SaveWorld,
LoadWorld, LoadWorld,
Rainfall, Rainfall,
Temperature, Temperature,
Biomes,
Contours,
);
#[cfg(all(feature = "render", feature = "planet_view"))]
toolbar_enum!(
GenerateWorld,
SaveWorld,
LoadWorld,
Rainfall,
Temperature,
Biomes,
Contours,
PlanetView, PlanetView,
); Contours,
});
#[cfg(all(feature = "render", feature = "globe_view"))]
iterable_enum!(ToolbarButton {
GenerateWorld,
SaveWorld,
LoadWorld,
Rainfall,
Temperature,
PlanetView,
Contours,
GlobeView,
});
#[cfg(feature = "render")] #[cfg(feature = "render")]
impl From<ToolbarButton> for &'static str { impl From<ToolbarButton> for &'static str {
@ -44,12 +30,12 @@ impl From<ToolbarButton> for &'static str {
ToolbarButton::Rainfall => "Toggle rainfall", ToolbarButton::Rainfall => "Toggle rainfall",
ToolbarButton::Temperature => "Toggle temperature", ToolbarButton::Temperature => "Toggle temperature",
ToolbarButton::Contours => "Toggle contours", ToolbarButton::Contours => "Toggle contours",
ToolbarButton::Biomes => "Toggle biomes", ToolbarButton::PlanetView => "Cycle view",
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")] #[cfg(feature = "globe_view")]
ToolbarButton::PlanetView => "Toggle planet view", ToolbarButton::GlobeView => "Toggle globe",
} }
} }
} }

19
src/macros.rs Normal file
View file

@ -0,0 +1,19 @@
#[cfg(feature = "render")]
macro_rules! iterable_enum {
($Name:ident { $($Variant:ident),*$(,)? }) =>
{
#[derive(Debug, Copy, Clone, Eq, PartialEq, Component)]
pub enum $Name {
$($Variant),*,
}
impl $Name {
const ITEMS: &'static [$Name] = &[$($Name::$Variant),*];
pub fn iterator() -> core::slice::Iter<'static, $Name> {
$Name::ITEMS.iter()
}
}
}
}
#[cfg(feature = "render")]
pub(crate) use iterable_enum;

View file

@ -32,10 +32,11 @@
#![warn(unused_results)] #![warn(unused_results)]
#![warn(variant_size_differences)] #![warn(variant_size_differences)]
mod components; pub(crate) mod components;
mod plugins; pub(crate) mod macros;
mod resources; pub(crate) mod plugins;
mod ui_helpers; pub(crate) mod resources;
pub(crate) mod ui_helpers;
#[cfg(all(feature = "debug", feature = "render"))] #[cfg(all(feature = "debug", feature = "render"))]
use bevy::{ use bevy::{
@ -103,7 +104,7 @@ use {
planet::WorldManager, planet::WorldManager,
plugins::WorldPlugins, plugins::WorldPlugins,
}; };
#[cfg(all(feature = "render", feature = "planet_view"))] #[cfg(all(feature = "render", feature = "globe_view"))]
use { use {
bevy::{ bevy::{
asset::Handle, asset::Handle,
@ -121,7 +122,7 @@ use {
#[cfg(feature = "render")] #[cfg(feature = "render")]
fn refresh_map_texture( fn refresh_map_texture(
images: &mut Assets<Image>, images: &mut Assets<Image>,
#[cfg(feature = "planet_view")] materials: &mut Assets<StandardMaterial>, #[cfg(feature = "globe_view")] materials: &mut Assets<StandardMaterial>,
world_manager: &WorldManager, world_manager: &WorldManager,
) { ) {
let world = world_manager.world(); let world = world_manager.world();
@ -142,11 +143,11 @@ fn refresh_map_texture(
}); });
map_image.data = world_manager.map_color_bytes(); map_image.data = world_manager.map_color_bytes();
#[cfg(feature = "planet_view")] #[cfg(feature = "globe_view")]
{ {
let planet_image_handle = images.get_handle( let planet_image_handle = images.get_handle(
world_manager world_manager
.planet_image_handle_id .globe_image_handle_id
.expect("No planet image handle"), .expect("No planet image handle"),
); );
let planet_image = images let planet_image = images
@ -157,11 +158,11 @@ fn refresh_map_texture(
height: world.height, height: world.height,
depth_or_array_layers: 1, depth_or_array_layers: 1,
}); });
planet_image.data = world_manager.planet_color_bytes(); planet_image.data = world_manager.globe_color_bytes();
let planet_material_handle = materials.get_handle( let planet_material_handle = materials.get_handle(
world_manager world_manager
.planet_material_handle_id .globe_material_handle_id
.expect("No planet material handle"), .expect("No planet material handle"),
); );
let planet_material = materials let planet_material = materials
@ -188,19 +189,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< #[cfg(feature = "globe_view")] mut camera_3d_query: Query<
'_, '_,
'_, '_,
&mut Camera, &mut Camera,
(With<Camera3d>, Without<Camera2d>), (With<Camera3d>, Without<Camera2d>),
>, >,
#[cfg(feature = "planet_view")] mut camera_2d_query: Query< #[cfg(feature = "globe_view")] mut camera_2d_query: Query<
'_, '_,
'_, '_,
&mut Camera, (&mut Camera, &mut PanCam),
(With<Camera2d>, Without<Camera3d>), (With<Camera2d>, Without<Camera3d>),
>, >,
#[cfg(feature = "planet_view")] mut materials: ResMut<'_, Assets<StandardMaterial>>, #[cfg(feature = "globe_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 {
@ -214,7 +215,7 @@ fn handle_toolbar_button(
world_manager.toggle_rainfall(); world_manager.toggle_rainfall();
refresh_map_texture( refresh_map_texture(
&mut images, &mut images,
#[cfg(feature = "planet_view")] #[cfg(feature = "globe_view")]
&mut materials, &mut materials,
&world_manager, &world_manager,
); );
@ -225,18 +226,18 @@ fn handle_toolbar_button(
world_manager.toggle_temperature(); world_manager.toggle_temperature();
refresh_map_texture( refresh_map_texture(
&mut images, &mut images,
#[cfg(feature = "planet_view")] #[cfg(feature = "globe_view")]
&mut materials, &mut materials,
&world_manager, &world_manager,
); );
}, },
ToolbarButton::Biomes => { ToolbarButton::PlanetView => {
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
debug!("Toggling biomes"); debug!("Cycling planet view");
world_manager.toggle_biomes(); world_manager.cycle_view();
refresh_map_texture( refresh_map_texture(
&mut images, &mut images,
#[cfg(feature = "planet_view")] #[cfg(feature = "globe_view")]
&mut materials, &mut materials,
&world_manager, &world_manager,
); );
@ -247,7 +248,7 @@ fn handle_toolbar_button(
world_manager.toggle_contours(); world_manager.toggle_contours();
refresh_map_texture( refresh_map_texture(
&mut images, &mut images,
#[cfg(feature = "planet_view")] #[cfg(feature = "globe_view")]
&mut materials, &mut materials,
&world_manager, &world_manager,
); );
@ -260,7 +261,7 @@ fn handle_toolbar_button(
.expect("Failed to generate new world"); .expect("Failed to generate new world");
refresh_map_texture( refresh_map_texture(
&mut images, &mut images,
#[cfg(feature = "planet_view")] #[cfg(feature = "globe_view")]
&mut materials, &mut materials,
&world_manager, &world_manager,
); );
@ -276,19 +277,20 @@ fn handle_toolbar_button(
_ = world_manager.load_world("planet.ron", &mut images); _ = world_manager.load_world("planet.ron", &mut images);
refresh_map_texture( refresh_map_texture(
&mut images, &mut images,
#[cfg(feature = "planet_view")] #[cfg(feature = "globe_view")]
&mut materials, &mut materials,
&world_manager, &world_manager,
); );
}, },
#[cfg(feature = "planet_view")] #[cfg(feature = "globe_view")]
ToolbarButton::PlanetView => { ToolbarButton::GlobeView => {
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
debug!("Toggling planet view"); debug!("Toggling globe view");
let mut camera_3d = camera_3d_query.single_mut(); let mut camera_3d = camera_3d_query.single_mut();
camera_3d.is_active = !camera_3d.is_active; camera_3d.is_active = !camera_3d.is_active;
let mut camera_2d = camera_2d_query.single_mut(); let (mut camera_2d, mut pancam) = camera_2d_query.single_mut();
camera_2d.is_active = !camera_2d.is_active; camera_2d.is_active = !camera_2d.is_active;
pancam.enabled = camera_2d.is_active;
}, },
} }
}, },
@ -336,11 +338,11 @@ fn update_cursor_map_position(
} }
} }
#[cfg(all(feature = "render", feature = "planet_view"))] #[cfg(all(feature = "render", feature = "globe_view"))]
const ROTATION_SPEED: f32 = 0.002; const ROTATION_SPEED: f32 = 0.002;
#[cfg(all(feature = "render", feature = "planet_view"))] #[cfg(all(feature = "render", feature = "globe_view"))]
fn rotate_planet(mut planet_transform: Query<'_, '_, &mut Transform, With<Handle<Mesh>>>) { fn rotate_globe(mut globe_transform: Query<'_, '_, &mut Transform, With<Handle<Mesh>>>) {
planet_transform.single_mut().rotate_y(ROTATION_SPEED); globe_transform.single_mut().rotate_y(ROTATION_SPEED);
} }
#[cfg(feature = "render")] #[cfg(feature = "render")]
@ -431,8 +433,8 @@ fn generate_graphics(
mut world_manager: ResMut<'_, WorldManager>, mut world_manager: ResMut<'_, WorldManager>,
mut images: ResMut<'_, Assets<Image>>, mut images: ResMut<'_, Assets<Image>>,
mut fonts: ResMut<'_, Assets<Font>>, mut fonts: ResMut<'_, Assets<Font>>,
#[cfg(feature = "planet_view")] mut materials: ResMut<'_, Assets<StandardMaterial>>, #[cfg(feature = "globe_view")] mut materials: ResMut<'_, Assets<StandardMaterial>>,
#[cfg(feature = "planet_view")] mut meshes: ResMut<'_, Assets<Mesh>>, #[cfg(feature = "globe_view")] mut meshes: ResMut<'_, Assets<Mesh>>,
) { ) {
let julia_mono_handle = fonts.add( let julia_mono_handle = fonts.add(
Font::try_from_bytes(include_bytes!("../assets/JuliaMono.ttf").to_vec()) Font::try_from_bytes(include_bytes!("../assets/JuliaMono.ttf").to_vec())
@ -463,11 +465,11 @@ fn generate_graphics(
}); });
world_manager.map_image_handle_id = Some(map_image_handle.id); world_manager.map_image_handle_id = Some(map_image_handle.id);
#[cfg(feature = "planet_view")] #[cfg(feature = "globe_view")]
{ {
let world = world_manager.world(); let world = world_manager.world();
let planet_image_handle = images.add(Image { let globe_image_handle = images.add(Image {
data: world_manager.planet_color_bytes(), data: world_manager.globe_color_bytes(),
texture_descriptor: TextureDescriptor { texture_descriptor: TextureDescriptor {
label: None, label: None,
size: Extent3d { size: Extent3d {
@ -483,7 +485,7 @@ fn generate_graphics(
}, },
..default() ..default()
}); });
world_manager.planet_image_handle_id = Some(planet_image_handle.id); world_manager.globe_image_handle_id = Some(globe_image_handle.id);
_ = commands.spawn_bundle(Camera3dBundle { _ = commands.spawn_bundle(Camera3dBundle {
camera: Camera { camera: Camera {
@ -499,19 +501,20 @@ fn generate_graphics(
..default() ..default()
}); });
let planet_material_handle = materials.add( let globe_material_handle = materials.add(
images images
.get_handle(world_manager.planet_image_handle_id.unwrap()) .get_handle(world_manager.globe_image_handle_id.unwrap())
.into(), .into(),
); );
world_manager.planet_material_handle_id = Some(planet_material_handle.id); world_manager.globe_material_handle_id = Some(globe_material_handle.id);
// TODO: Globe texture is mirrored east-to-west.
_ = commands.spawn_bundle(PbrBundle { _ = commands.spawn_bundle(PbrBundle {
mesh: meshes.add(Mesh::from(UVSphere { mesh: meshes.add(Mesh::from(UVSphere {
radius: 2.0, radius: 2.0,
..default() ..default()
})), })),
material: planet_material_handle, material: globe_material_handle,
transform: Transform::from_rotation(Quat::from_rotation_x(FRAC_PI_2)), transform: Transform::from_rotation(Quat::from_rotation_x(FRAC_PI_2)),
..default() ..default()
}); });
@ -591,7 +594,7 @@ fn generate_graphics(
..default() ..default()
}) })
.with_children(|button_box| { .with_children(|button_box| {
ToolbarButton::BUTTONS.iter().for_each(|&button_type| { ToolbarButton::iterator().for_each(|&button_type| {
_ = button_box _ = button_box
.spawn_bundle(toolbar_button()) .spawn_bundle(toolbar_button())
.with_children(|button| { .with_children(|button| {
@ -630,9 +633,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.add_system(handle_toolbar_button) .add_system(handle_toolbar_button)
.add_system(update_cursor_map_position) .add_system(update_cursor_map_position)
.add_system(update_info_panel); .add_system(update_info_panel);
#[cfg(all(feature = "render", feature = "planet_view"))] #[cfg(all(feature = "render", feature = "globe_view"))]
{ {
_ = app.add_system(rotate_planet); _ = app.add_system(rotate_globe);
} }
} }
#[cfg(not(feature = "render"))] #[cfg(not(feature = "render"))]

View file

@ -48,7 +48,7 @@ impl PluginGroup for WorldPlugins {
.add(TextPlugin::default()) .add(TextPlugin::default())
.add(UiPlugin::default()) .add(UiPlugin::default())
.add(PanCamPlugin::default()); .add(PanCamPlugin::default());
#[cfg(feature = "planet_view")] #[cfg(feature = "globe_view")]
{ {
use bevy::pbr::PbrPlugin; use bevy::pbr::PbrPlugin;
_ = group.add(PbrPlugin::default()) _ = group.add(PbrPlugin::default())