Fix planet_view feature

40c19014c9774cdf8cc4e5003393de5e8363ef17
This commit is contained in:
Tobias Berger 2022-09-20 12:25:31 +02:00
parent 7662fcda50
commit b064aa0dd9
Signed by: toby
GPG key ID: 2D05EFAB764D6A88
10 changed files with 648509 additions and 103 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", ""] 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*

View file

@ -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

File diff suppressed because one or more lines are too long

View file

@ -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"

View file

@ -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()
} }
} }

View file

@ -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,

View file

@ -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 {

View file

@ -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

View file

@ -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",
} }
} }
} }

View file

@ -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()