Add a minimap overlay based on voxel data.

This commit is contained in:
Avi Weinstock 2021-05-10 23:09:14 -04:00
parent 81bba1393a
commit d1d7147aa6
4 changed files with 145 additions and 5 deletions

11
Cargo.lock generated
View File

@ -2415,6 +2415,15 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "inline_tweak"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7033e97b20277cc0d043226d1940fa7719ff08d2305d1fc7421e53066d00eb4b"
dependencies = [
"lazy_static",
]
[[package]] [[package]]
name = "inotify" name = "inotify"
version = "0.7.1" version = "0.7.1"
@ -5644,7 +5653,6 @@ dependencies = [
name = "veloren-i18n" name = "veloren-i18n"
version = "0.9.0" version = "0.9.0"
dependencies = [ dependencies = [
"clap",
"deunicode", "deunicode",
"git2", "git2",
"hashbrown", "hashbrown",
@ -5826,6 +5834,7 @@ dependencies = [
"iced_native", "iced_native",
"iced_winit", "iced_winit",
"image", "image",
"inline_tweak",
"itertools 0.10.0", "itertools 0.10.0",
"keyboard-keynames", "keyboard-keynames",
"lazy_static", "lazy_static",

View File

@ -104,7 +104,7 @@ treeculler = "0.2"
tokio = { version = "1", default-features = false, features = ["rt-multi-thread"] } tokio = { version = "1", default-features = false, features = ["rt-multi-thread"] }
num_cpus = "1.0" num_cpus = "1.0"
# vec_map = { version = "0.8.2" } # vec_map = { version = "0.8.2" }
# inline_tweak = "1.0.2" inline_tweak = "1.0.2"
itertools = "0.10.0" itertools = "0.10.0"
# Tracy # Tracy

View File

@ -4,22 +4,113 @@ use super::{
TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN, TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
}; };
use crate::{ use crate::{
hud::{Graphic, Ui},
session::settings_change::{Interface as InterfaceChange, Interface::*}, session::settings_change::{Interface as InterfaceChange, Interface::*},
ui::{fonts::Fonts, img_ids}, ui::{fonts::Fonts, img_ids},
GlobalState, GlobalState,
}; };
use client::{self, Client}; use client::{self, Client};
use common::{comp, comp::group::Role, terrain::TerrainChunkSize, vol::RectVolSize}; use common::{
comp,
comp::group::Role,
grid::Grid,
terrain::TerrainChunkSize,
vol::{ReadVol, RectVolSize},
};
use common_net::msg::world_msg::SiteKind; use common_net::msg::world_msg::SiteKind;
use conrod_core::{ use conrod_core::{
color, position, color, position,
widget::{self, Button, Image, Rectangle, Text}, widget::{self, Button, Image, Rectangle, Text},
widget_ids, Color, Colorable, Positionable, Sizeable, Widget, WidgetCommon, widget_ids, Color, Colorable, Positionable, Sizeable, Widget, WidgetCommon,
}; };
use hashbrown::HashMap;
use image::{DynamicImage, RgbaImage};
use specs::{saveload::MarkerAllocator, WorldExt}; use specs::{saveload::MarkerAllocator, WorldExt};
use std::sync::Arc;
use vek::*; use vek::*;
pub struct VoxelMinimap {
chunk_minimaps: HashMap<Vec2<i32>, HashMap<i32, Grid<[u8; 4]>>>,
composited: RgbaImage,
image_id: img_ids::Rotations,
}
impl VoxelMinimap {
pub fn new(ui: &mut Ui) -> Self {
let mut composited = RgbaImage::new(96, 96);
for x in 0..96 {
for y in 0..96 {
composited.put_pixel(
x,
y,
image::Rgba([255 - 2 * x as u8, 255 - 2 * y as u8, 0, 64]),
);
}
}
Self {
chunk_minimaps: HashMap::new(),
image_id: ui.add_graphic_with_rotations(Graphic::Image(
Arc::new(DynamicImage::ImageRgba8(composited.clone())),
Some(Rgba::from([0.0, 0.0, 0.0, 0.0])),
)),
composited,
}
}
pub fn maintain(&mut self, client: &Client, ui: &mut Ui) {
let terrain = client.state().terrain();
for (key, chunk) in terrain.iter() {
if !self.chunk_minimaps.contains_key(&key) {
let mut layers = HashMap::new();
for z in chunk.get_min_z()..chunk.get_max_z() {
let grid = Grid::populate_from(Vec2::new(32, 32), |v| {
chunk
.get(Vec3::new(v.x, v.y, z))
.ok()
.and_then(|block| block.get_color())
.map(|rgb| [rgb.r, rgb.g, rgb.b, 128])
.unwrap_or([0, 0, 0, 0])
});
layers.insert(z, grid);
}
self.chunk_minimaps.insert(key, layers);
}
}
let player = client.entity();
if let Some(pos) = client.state().ecs().read_storage::<comp::Pos>().get(player) {
let pos = pos.0;
let cpos: Vec2<i32> = (pos.xy() / 32.0).as_();
for i in -1..=1 {
for j in -1..=1 {
let coff = Vec2::new(i, j);
if let Some(grid) = self
.chunk_minimaps
.get(&(cpos + coff))
.and_then(|l| l.get(&(pos.z as i32)))
{
for x in 0..32 {
for y in 0..32 {
self.composited.put_pixel(
(i + 1) as u32 * 32 + x,
(j + 1) as u32 * 32 + y,
grid.get(Vec2::new(x, y).as_())
.map(|c| image::Rgba(*c))
.unwrap_or(image::Rgba([0, 0, 0, 0])),
);
}
}
}
}
}
// TODO: don't leak memory, replace
self.image_id = ui.add_graphic_with_rotations(Graphic::Image(
Arc::new(DynamicImage::ImageRgba8(self.composited.clone())),
Some(Rgba::from([0.0, 0.0, 0.0, 0.0])),
));
}
}
}
widget_ids! { widget_ids! {
struct Ids { struct Ids {
mmap_frame, mmap_frame,
@ -40,6 +131,7 @@ widget_ids! {
mmap_site_icons[], mmap_site_icons[],
member_indicators[], member_indicators[],
location_marker, location_marker,
voxel_minimap,
} }
} }
@ -56,6 +148,7 @@ pub struct MiniMap<'a> {
ori: Vec3<f32>, ori: Vec3<f32>,
global_state: &'a GlobalState, global_state: &'a GlobalState,
location_marker: Option<Vec2<f32>>, location_marker: Option<Vec2<f32>>,
voxel_minimap: &'a VoxelMinimap,
} }
impl<'a> MiniMap<'a> { impl<'a> MiniMap<'a> {
@ -69,6 +162,7 @@ impl<'a> MiniMap<'a> {
ori: Vec3<f32>, ori: Vec3<f32>,
global_state: &'a GlobalState, global_state: &'a GlobalState,
location_marker: Option<Vec2<f32>>, location_marker: Option<Vec2<f32>>,
voxel_minimap: &'a VoxelMinimap,
) -> Self { ) -> Self {
Self { Self {
show, show,
@ -81,6 +175,7 @@ impl<'a> MiniMap<'a> {
ori, ori,
global_state, global_state,
location_marker, location_marker,
voxel_minimap,
} }
} }
} }
@ -116,6 +211,8 @@ impl<'a> Widget for MiniMap<'a> {
let show_minimap = self.global_state.settings.interface.minimap_show; let show_minimap = self.global_state.settings.interface.minimap_show;
let is_facing_north = self.global_state.settings.interface.minimap_face_north; let is_facing_north = self.global_state.settings.interface.minimap_face_north;
let show_topo_map = self.global_state.settings.interface.map_show_topo_map; let show_topo_map = self.global_state.settings.interface.map_show_topo_map;
//let show_voxel_map = self.global_state.settings.interface.map_show_voxel_map;
let show_voxel_map = true;
let orientation = if is_facing_north { let orientation = if is_facing_north {
Vec3::new(0.0, 1.0, 0.0) Vec3::new(0.0, 1.0, 0.0)
} else { } else {
@ -277,6 +374,36 @@ impl<'a> Widget for MiniMap<'a> {
.set(state.ids.map_layers[index], ui); .set(state.ids.map_layers[index], ui);
} }
} }
if show_voxel_map {
let voxelmap_rotation = if is_facing_north {
self.voxel_minimap.image_id.none
} else {
self.voxel_minimap.image_id.source_north
};
use inline_tweak::tweak;
/*let rect_src = position::Rect::from_xy_dim(
[
player_pos.x as f64 / TerrainChunkSize::RECT_SIZE.x as f64 + tweak!(0.0),
worldsize.y as f64 -
(player_pos.y as f64 / TerrainChunkSize::RECT_SIZE.y as f64) + tweak!(0.0),
],
[w_src / tweak!(32768.0), h_src / tweak!(32768.0)],
);*/
let rect_src = position::Rect::from_xy_dim([tweak!(48.0), tweak!(48.0)], [
tweak!(96.0),
tweak!(96.0),
]);
Image::new(voxelmap_rotation)
.middle_of(state.ids.mmap_frame_bg)
.w_h(
map_size.x * 3.0 * (zoom / max_zoom),
map_size.y * 3.0 * zoom / max_zoom,
)
.parent(state.ids.mmap_frame_bg)
.source_rectangle(rect_src)
.graphics_for(state.ids.map_layers[0])
.set(state.ids.voxel_minimap, ui);
}
// Map icons // Map icons
if state.ids.mmap_site_icons.len() < self.client.sites().len() { if state.ids.mmap_site_icons.len() < self.client.sites().len() {

View File

@ -39,7 +39,7 @@ use group::Group;
use img_ids::Imgs; use img_ids::Imgs;
use item_imgs::ItemImgs; use item_imgs::ItemImgs;
use map::Map; use map::Map;
use minimap::MiniMap; use minimap::{MiniMap, VoxelMinimap};
use popup::Popup; use popup::Popup;
use prompt_dialog::PromptDialog; use prompt_dialog::PromptDialog;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -785,6 +785,7 @@ pub struct Hud {
events: Vec<Event>, events: Vec<Event>,
crosshair_opacity: f32, crosshair_opacity: f32,
floaters: Floaters, floaters: Floaters,
voxel_minimap: VoxelMinimap,
} }
impl Hud { impl Hud {
@ -841,6 +842,7 @@ impl Hud {
); );
Self { Self {
voxel_minimap: VoxelMinimap::new(&mut ui),
ui, ui,
imgs, imgs,
world_map, world_map,
@ -928,6 +930,7 @@ impl Hud {
) -> Vec<Event> { ) -> Vec<Event> {
span!(_guard, "update_layout", "Hud::update_layout"); span!(_guard, "update_layout", "Hud::update_layout");
let mut events = std::mem::replace(&mut self.events, Vec::new()); let mut events = std::mem::replace(&mut self.events, Vec::new());
self.voxel_minimap.maintain(&client, &mut self.ui);
let (ref mut ui_widgets, ref mut item_tooltip_manager, ref mut tooltip_manager) = let (ref mut ui_widgets, ref mut item_tooltip_manager, ref mut tooltip_manager) =
&mut self.ui.set_widgets(); &mut self.ui.set_widgets();
// self.ui.set_item_widgets(); pulse time for pulsating elements // self.ui.set_item_widgets(); pulse time for pulsating elements
@ -2316,6 +2319,7 @@ impl Hud {
camera.get_orientation(), camera.get_orientation(),
&global_state, &global_state,
self.show.location_marker, self.show.location_marker,
&self.voxel_minimap,
) )
.set(self.ids.minimap, ui_widgets) .set(self.ids.minimap, ui_widgets)
{ {