Cache rendered maps
Plus some small tweaks
This commit is contained in:
parent
6cc04b48fd
commit
7d3e97da5a
4 changed files with 78 additions and 18 deletions
|
@ -32,7 +32,7 @@ impl From<BiomeType> for BiomeStats {
|
||||||
BiomeType::IceCap => BiomeStats {
|
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::WHITE,
|
||||||
min_altitude: World::MIN_ALTITUDE,
|
min_altitude: World::MIN_ALTITUDE,
|
||||||
max_altitude: World::MAX_ALTITUDE,
|
max_altitude: World::MAX_ALTITUDE,
|
||||||
min_rainfall: World::MIN_RAINFALL,
|
min_rainfall: World::MIN_RAINFALL,
|
||||||
|
|
|
@ -35,6 +35,7 @@ impl Display for CartesianError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn cartesian_coordinates(
|
pub fn cartesian_coordinates(
|
||||||
alpha: f32,
|
alpha: f32,
|
||||||
mut beta: f32,
|
mut beta: f32,
|
||||||
|
@ -61,6 +62,7 @@ pub fn cartesian_coordinates(
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn random_point_in_sphere(rng: &mut StdRng, radius: f32) -> Vec3A {
|
pub fn random_point_in_sphere(rng: &mut StdRng, radius: f32) -> Vec3A {
|
||||||
// https://karthikkaranth.me/blog/generating-random-points-in-a-sphere/#better-choice-of-spherical-coordinates
|
// https://karthikkaranth.me/blog/generating-random-points-in-a-sphere/#better-choice-of-spherical-coordinates
|
||||||
|
|
||||||
|
@ -85,14 +87,19 @@ pub fn random_point_in_sphere(rng: &mut StdRng, radius: f32) -> Vec3A {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub fn mix_values(a: f32, b: f32, weight_b: f32) -> f32 {
|
pub fn mix_values(a: f32, b: f32, weight_b: f32) -> f32 {
|
||||||
(b * weight_b) + (a * (1.0 - weight_b))
|
(b * weight_b) + (a * (1.0 - weight_b))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait RepeatNum {
|
pub trait RepeatNum {
|
||||||
|
#[must_use]
|
||||||
fn repeat(self, length: Self) -> Self;
|
fn repeat(self, length: Self) -> Self;
|
||||||
}
|
}
|
||||||
impl RepeatNum for f32 {
|
impl RepeatNum for f32 {
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
fn repeat(self, length: f32) -> f32 {
|
fn repeat(self, length: f32) -> f32 {
|
||||||
f32::clamp(self - (self / length).floor() * length, 0.0, length)
|
f32::clamp(self - (self / length).floor() * length, 0.0, length)
|
||||||
}
|
}
|
||||||
|
|
|
@ -233,6 +233,7 @@ fn update_gui(world: &mut World) {
|
||||||
fn redraw_map(
|
fn redraw_map(
|
||||||
mut should_redraw: ResMut<ShouldRedraw>,
|
mut should_redraw: ResMut<ShouldRedraw>,
|
||||||
world_manager: Res<WorldManager>,
|
world_manager: Res<WorldManager>,
|
||||||
|
mut world_renderer: ResMut<WorldRenderer>,
|
||||||
render_settings: Res<WorldRenderSettings>,
|
render_settings: Res<WorldRenderSettings>,
|
||||||
mut images: ResMut<Assets<Image>>,
|
mut images: ResMut<Assets<Image>>,
|
||||||
mut map_sprite: Query<&mut Sprite>,
|
mut map_sprite: Query<&mut Sprite>,
|
||||||
|
@ -267,7 +268,7 @@ fn redraw_map(
|
||||||
height: world.height,
|
height: world.height,
|
||||||
..default()
|
..default()
|
||||||
});
|
});
|
||||||
map_image.data = world_manager.map_color_bytes(render_settings);
|
map_image.data = world_renderer.map_color_bytes(world_manager, render_settings);
|
||||||
map_sprite.single_mut().custom_size = Some(Vec2 {
|
map_sprite.single_mut().custom_size = Some(Vec2 {
|
||||||
x: (world.width * WORLD_SCALE as u32) as f32,
|
x: (world.width * WORLD_SCALE as u32) as f32,
|
||||||
y: (world.height * WORLD_SCALE as u32) as f32,
|
y: (world.height * WORLD_SCALE as u32) as f32,
|
||||||
|
@ -297,6 +298,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
.insert_resource(OpenedWindows::default())
|
.insert_resource(OpenedWindows::default())
|
||||||
.insert_resource(WorldRenderSettings::default())
|
.insert_resource(WorldRenderSettings::default())
|
||||||
.insert_resource(ShouldRedraw::default())
|
.insert_resource(ShouldRedraw::default())
|
||||||
|
.insert_resource(WorldRenderer::default())
|
||||||
.add_startup_system(generate_graphics)
|
.add_startup_system(generate_graphics)
|
||||||
.add_system(update_gui)
|
.add_system(update_gui)
|
||||||
.add_system(update_cursor_map_position)
|
.add_system(update_cursor_map_position)
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::macros::iterable_enum_stringify,
|
crate::macros::iterable_enum_stringify,
|
||||||
bevy::{
|
bevy::{asset::HandleId, prelude::*, utils::HashSet},
|
||||||
asset::HandleId,
|
|
||||||
prelude::{Color, Resource},
|
|
||||||
utils::HashSet,
|
|
||||||
},
|
|
||||||
planet::{BiomeStats, TerrainCell, World, WorldManager},
|
planet::{BiomeStats, TerrainCell, World, WorldManager},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -166,34 +162,89 @@ fn coastline_color(world: &World, cell: &TerrainCell) -> Color {
|
||||||
COASTLINE_PALETTE[0]
|
COASTLINE_PALETTE[0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub trait WorldRenderer {
|
|
||||||
fn map_color_bytes(&self, render_settings: &WorldRenderSettings) -> Vec<u8>;
|
const CACHE_SIZE: usize =
|
||||||
fn generate_color(&self, cell: &TerrainCell, render_settings: &WorldRenderSettings) -> Color;
|
WorldOverlay::ITEM_COUNT * WorldOverlay::ITEM_COUNT * WorldView::ITEM_COUNT;
|
||||||
|
|
||||||
|
#[derive(Default, Resource)]
|
||||||
|
pub struct WorldRenderer {
|
||||||
|
cached_world_seed: u32,
|
||||||
|
cache: [Option<Vec<u8>>; CACHE_SIZE],
|
||||||
}
|
}
|
||||||
impl WorldRenderer for WorldManager {
|
|
||||||
|
impl WorldRenderer {
|
||||||
|
fn cache_index(render_settings: &WorldRenderSettings) -> usize {
|
||||||
|
let view_num = match render_settings.view {
|
||||||
|
WorldView::Biomes => 0,
|
||||||
|
WorldView::Topography => 1,
|
||||||
|
WorldView::Coastlines => 2,
|
||||||
|
};
|
||||||
|
let mut overlay_num = 0;
|
||||||
|
for overlay in render_settings.visible_overlays.iter() {
|
||||||
|
overlay_num |= match overlay {
|
||||||
|
WorldOverlay::Temperature => 1,
|
||||||
|
WorldOverlay::Rainfall => 2,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#[cfg(feature = "logging")]
|
||||||
|
debug!(overlay_num, view_num);
|
||||||
|
(view_num << WorldOverlay::ITEM_COUNT) | overlay_num
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn map_color_bytes(&self, render_settings: &WorldRenderSettings) -> Vec<u8> {
|
pub fn map_color_bytes(
|
||||||
let Some(world) = self.get_world() else {
|
&mut self,
|
||||||
|
world_manager: &WorldManager,
|
||||||
|
render_settings: &WorldRenderSettings,
|
||||||
|
) -> Vec<u8> {
|
||||||
|
let Some(world) = world_manager.get_world() else {
|
||||||
return vec![];
|
return vec![];
|
||||||
};
|
};
|
||||||
world
|
|
||||||
|
let cache_index = WorldRenderer::cache_index(render_settings);
|
||||||
|
#[cfg(feature = "logging")]
|
||||||
|
debug!(cache_index);
|
||||||
|
assert!(
|
||||||
|
cache_index < CACHE_SIZE,
|
||||||
|
"Generated cache index too large for render cache"
|
||||||
|
);
|
||||||
|
if world.seed != self.cached_world_seed {
|
||||||
|
self.cache = default();
|
||||||
|
self.cached_world_seed = world.seed;
|
||||||
|
}
|
||||||
|
if let Some(cached) = &self.cache[cache_index] {
|
||||||
|
return cached.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
let bytes: Vec<_> = world
|
||||||
.terrain
|
.terrain
|
||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.flatten()
|
.flatten()
|
||||||
.flat_map(|cell| {
|
.flat_map(|cell| {
|
||||||
self.generate_color(cell, render_settings)
|
self.generate_color(world_manager, cell, render_settings)
|
||||||
.as_rgba_f32()
|
.as_rgba_f32()
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|num| num.to_le_bytes())
|
.flat_map(|num| num.to_le_bytes())
|
||||||
.collect::<Vec<u8>>()
|
.collect::<Vec<u8>>()
|
||||||
})
|
})
|
||||||
.collect()
|
.collect();
|
||||||
|
let result = bytes.clone();
|
||||||
|
self.cache[cache_index] = Some(bytes);
|
||||||
|
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn generate_color(&self, cell: &TerrainCell, render_settings: &WorldRenderSettings) -> Color {
|
pub fn generate_color(
|
||||||
let world = self.get_world().expect("No world in generate_color");
|
&self,
|
||||||
|
world_manager: &WorldManager,
|
||||||
|
cell: &TerrainCell,
|
||||||
|
render_settings: &WorldRenderSettings,
|
||||||
|
) -> Color {
|
||||||
|
let world = world_manager
|
||||||
|
.get_world()
|
||||||
|
.expect("No world in generate_color");
|
||||||
let base_color = match render_settings.view {
|
let base_color = match render_settings.view {
|
||||||
WorldView::Biomes => biome_color(world, cell),
|
WorldView::Biomes => biome_color(world, cell),
|
||||||
WorldView::Topography => altitude_contour_color(world, cell.altitude),
|
WorldView::Topography => altitude_contour_color(world, cell.altitude),
|
||||||
|
|
Loading…
Reference in a new issue