Demystify map site icon placement calculations

This commit is contained in:
Imbris 2020-11-22 02:31:11 -05:00 committed by Joshua Barretto
parent e461fbd951
commit 898bba8884
3 changed files with 78 additions and 67 deletions

View File

@ -6,8 +6,8 @@ rustflags = [
[alias]
generate = "run --package tools --"
test-server = "-Zpackage-features run --bin veloren-server-cli --no-default-features"
tracy-server = "-Zunstable-options -Zpackage-features run --bin veloren-server-cli --no-default-features --features tracy --profile dev"
tracy-server = "-Zunstable-options -Zpackage-features run --bin veloren-server-cli --no-default-features --features tracy,simd --profile no_overflow"
test-voxygen = "-Zpackage-features run --bin veloren-voxygen --no-default-features --features gl,simd"
tracy-voxygen = "-Zunstable-options -Zpackage-features run --bin veloren-voxygen --no-default-features --features tracy,gl,simd --profile dev"
tracy-voxygen = "-Zunstable-options -Zpackage-features run --bin veloren-voxygen --no-default-features --features tracy,gl,simd --profile no_overflow"
server = "run --bin veloren-server-cli"

View File

@ -230,7 +230,6 @@ impl<'a> Widget for Map<'a> {
.set(state.ids.grid, ui);
// Map Image
let (world_map, worldsize) = self.world_map;
let worldsize = worldsize.map2(TerrainChunkSize::RECT_SIZE, |e, f| e as f64 * f as f64);
// Coordinates
let player_pos = self
@ -241,8 +240,8 @@ impl<'a> Widget for Map<'a> {
.get(self.client.entity())
.map_or(Vec3::zero(), |pos| pos.0);
let max_zoom = (worldsize / TerrainChunkSize::RECT_SIZE.map(|e| e as f64))
.reduce_partial_max()/*.min(f64::MAX)*/;
let max_zoom = worldsize
.reduce_partial_max() as f64/*.min(f64::MAX)*/;
let map_size = Vec2::new(760.0, 760.0);
@ -256,13 +255,14 @@ impl<'a> Widget for Map<'a> {
.left()
.map(|drag| Vec2::<f64>::from(drag.delta_xy))
.sum();
let drag_new = drag + dragged / zoom;
// Drag represents offset of view from the player_pos in chunk coords
let drag_new = drag + dragged / map_size / zoom * worldsize.map(|e| e as f64);
events.push(Event::MapDrag(drag_new));
let rect_src = position::Rect::from_xy_dim(
[
(player_pos.x as f64 / TerrainChunkSize::RECT_SIZE.x as f64) - drag.x,
((worldsize.y - player_pos.y as f64) / TerrainChunkSize::RECT_SIZE.y as f64)
(worldsize.y as f64 - (player_pos.y as f64 / TerrainChunkSize::RECT_SIZE.y as f64))
+ drag.y,
],
[w_src, h_src],
@ -302,13 +302,13 @@ impl<'a> Widget for Map<'a> {
events.push(Event::MapZoom(new_val as f64));
}*/
// Handle zooming with the mousewheel
let zoom_lvl = self.global_state.settings.gameplay.map_zoom;
let scrolled: f64 = ui
.widget_input(state.ids.grid)
.scrolls()
.map(|scroll| scroll.y)
.sum();
let new_zoom_lvl = (zoom_lvl * (1.0 + scrolled * 0.05 * PLATFORM_FACTOR))
let new_zoom_lvl = (self.global_state.settings.gameplay.map_zoom
* (1.0 + scrolled * 0.05 * PLATFORM_FACTOR))
.clamped(1.22, 20.0 /* max_zoom */);
events.push(Event::MapZoom(new_zoom_lvl as f64));
// Icon settings
@ -471,13 +471,17 @@ impl<'a> Widget for Map<'a> {
});
}
for (i, site) in self.client.sites().iter().enumerate() {
// Site pos in world coordinates relative to the player
let rwpos = site.wpos.map(|e| e as f32) - player_pos;
let rcpos =
rwpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz| e / sz as f32) * zoom as f32 * 3.0
/ 4.0;
let rpos = Vec2::unit_x().rotated_z(0.0) * rcpos.x
+ Vec2::unit_y().rotated_z(0.0) * rcpos.y
+ drag.map(|e| (e * zoom_lvl) as f32 / 1.67);
// Convert to chunk coordinates
let rcpos = rwpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz| e / sz as f32)
// Add map dragging
+ drag.map(|e| e as f32);
// Convert to fractional coordinates relative to the worldsize
let rfpos = rcpos.map2(*worldsize, |e, sz| e / sz as f32);
// Convert to relative pixel coordinates from the center of the map
// Accounting for zooming
let rpos = rfpos.map2(map_size, |e, sz| e * sz as f32 * zoom as f32);
if rpos
.map2(map_size, |e, sz| e.abs() > sz as f32 / 2.0)
@ -639,16 +643,27 @@ impl<'a> Widget for Map<'a> {
(e as f64 / sz).clamped(0.0, 1.0)
});*/
//let xy = rel * 760.0;
let rpos = drag.map(|e| (e * zoom_lvl) as f32 / 2.6);
// Offset from map center due to dragging
let rcpos = drag.map(|e| e as f32);
// Convert to fractional coordinates relative to the worldsize
let rfpos = rcpos.map2(*worldsize, |e, sz| e / sz as f32);
// Convert to relative pixel coordinates from the center of the map
// Accounting for zooming
let rpos = rfpos.map2(map_size, |e, sz| e * sz as f32 * zoom as f32);
// Don't show if outside or near the edge of the map
let arrow_sz = {
let scale = 0.6f64;
Vec2::new(32.0, 37.0) * scale
};
// Hide if icon could go off of the edge of the map
if !rpos
.map2(map_size, |e, sz| e > sz as f32 / 1.67)
.map2(map_size, |e, sz| {
e.abs() + arrow_sz.map(|e| e as f32 / 2.0).magnitude() > sz as f32 / 2.0
})
.reduce_or()
{
let scale = 0.6;
let arrow_sz = Vec2::new(32.0, 37.0) * scale;
if drag.x == 0.0 && drag.y == 0.0 {
Image::new(self.rot_imgs.indicator_mmap_small.target_north)
//.top_left_with_margins_on(state.ids.grid, 407.0 - drag.y * zoom_lvl, 417.0 + drag.x * zoom_lvl)
Image::new(self.rot_imgs.indicator_mmap_small.target_north)
.x_y_position_relative_to(
state.ids.grid,
position::Relative::Scalar(rpos.x as f64),
@ -656,10 +671,7 @@ impl<'a> Widget for Map<'a> {
)
.w_h(arrow_sz.x, arrow_sz.y)
.color(Some(UI_HIGHLIGHT_0))
.floating(true)
//.parent(ui.window)
.set(state.ids.indicator, ui);
}
}
// Info about controls
let icon_size = Vec2::new(tweak!(25.6), tweak!(28.8));
@ -699,7 +711,7 @@ impl<'a> Widget for Map<'a> {
.set(state.ids.recenter_button, ui)
.was_clicked()
{
events.push(Event::MapDrag(drag_new - drag_new));
events.push(Event::MapDrag(Vec2::zero()));
};
Image::new(self.imgs.m_move_ico)

View File

@ -1,7 +1,8 @@
use super::{
img_ids::{Imgs, ImgsRot},
Show, TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN, QUALITY_COMMON, QUALITY_DEBUG, QUALITY_EPIC, QUALITY_HIGH, QUALITY_LOW, QUALITY_MODERATE,
};
Show, QUALITY_COMMON, QUALITY_DEBUG, QUALITY_EPIC, QUALITY_HIGH, QUALITY_LOW, QUALITY_MODERATE,
TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
};
use crate::ui::{fonts::Fonts, img_ids};
use client::{self, Client};
use common::{comp, msg::world_msg::SiteKind, terrain::TerrainChunkSize, vol::RectVolSize};
@ -124,9 +125,8 @@ impl<'a> Widget for MiniMap<'a> {
.mid_top_with_margin_on(state.ids.mmap_frame_2, 18.0 * SCALE)
.set(state.ids.mmap_frame_bg, ui);
// Map size
// Map size in chunk coords
let (world_map, worldsize) = self.world_map;
let worldsize = worldsize.map2(TerrainChunkSize::RECT_SIZE, |e, f| e as f64 * f as f64);
// Zoom Buttons
@ -136,8 +136,8 @@ impl<'a> Widget for MiniMap<'a> {
// TODO: Either prevent zooming all the way in, *or* see if we can interpolate
// somehow if you zoom in too far. Or both.
let min_zoom = 1.0;
let max_zoom = (worldsize / TerrainChunkSize::RECT_SIZE.map(|e| e as f64))
.reduce_partial_max()/*.min(f64::MAX)*/;
let max_zoom = worldsize
.reduce_partial_max() as f64/*.min(f64::MAX)*/;
// NOTE: Not sure if a button can be clicked while disabled, but we still double
// check for both kinds of zoom to make sure that not only was the
@ -200,17 +200,18 @@ impl<'a> Widget for MiniMap<'a> {
let rect_src = position::Rect::from_xy_dim(
[
player_pos.x as f64 / TerrainChunkSize::RECT_SIZE.x as f64,
(worldsize.y - player_pos.y as f64) / TerrainChunkSize::RECT_SIZE.y as f64,
worldsize.y as f64
- (player_pos.y as f64 / TerrainChunkSize::RECT_SIZE.y as f64),
],
[w_src, h_src],
);
let map_size = Vec2::new(170.0, 170.0);
let map_size = Vec2::new(170.0 * SCALE, 170.0 * SCALE);
// Map Image
Image::new(world_map.source_north)
.middle_of(state.ids.mmap_frame_bg)
.w_h(map_size.x * SCALE, map_size.y * SCALE)
.w_h(map_size.x, map_size.y)
.parent(state.ids.mmap_frame_bg)
.source_rectangle(rect_src)
.set(state.ids.grid, ui);
@ -221,8 +222,6 @@ impl<'a> Widget for MiniMap<'a> {
.middle_of(state.ids.grid)
.w_h(32.0 * ind_scale, 37.0 * ind_scale)
.color(Some(UI_HIGHLIGHT_0))
.floating(true)
.parent(ui.window)
.set(state.ids.indicator, ui);
// Map icons
@ -241,19 +240,23 @@ impl<'a> Widget for MiniMap<'a> {
.mmap_site_icons_bgs
.resize(self.client.sites().len(), &mut ui.widget_id_generator())
});
}
for (i, site) in self.client.sites().iter().enumerate() {
}
for (i, site) in self.client.sites().iter().enumerate() {
// Site pos in world coordinates relative to the player
let rwpos = site.wpos.map(|e| e as f32) - player_pos;
let rcpos = rwpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz| e / sz as f32)
* state.zoom as f32
/ 4.0;
let rpos = Vec2::unit_x().rotated_z(self.ori.x) * rcpos.x
+ Vec2::unit_y().rotated_z(self.ori.x) * rcpos.y;
// Convert to chunk coordinates
let rcpos = rwpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz| e / sz as f32);
// Convert to fractional coordinates relative to the worldsize
let rfpos = rcpos.map2(*worldsize, |e, sz| e / sz as f32);
// Convert to unrotated pixel coordinates from the player location on the map
// (the center)
// Accounting for zooming
let rpixpos = rfpos.map2(map_size, |e, sz| e * sz as f32 * zoom as f32);
let rpos = Vec2::unit_x().rotated_z(self.ori.x) * rpixpos.x
+ Vec2::unit_y().rotated_z(self.ori.x) * rpixpos.y;
// TODO: Why does this require the magic constant 0.73? This this related to
// scaling issues?
if rpos
.map2(map_size, |e, sz| e.abs() > sz as f32 / 0.73 / 2.0)
.map2(map_size, |e, sz| e.abs() > sz as f32 / 2.0)
.reduce_or()
{
continue;
@ -270,22 +273,20 @@ impl<'a> Widget for MiniMap<'a> {
position::Relative::Scalar(rpos.y as f64),
)
.w_h(20.0, 20.0)
.color(Some(
match &site.kind {
SiteKind::Town => Color::Rgba(1.0, 1.0, 1.0, 0.0),
SiteKind::Castle => Color::Rgba(1.0, 1.0, 1.0, 0.0),
SiteKind::Dungeon { difficulty } => match difficulty {
0 => QUALITY_LOW,
1 => QUALITY_COMMON,
2 => QUALITY_MODERATE,
3 => QUALITY_HIGH,
4 => QUALITY_EPIC,
5 => QUALITY_DEBUG,
_ => Color::Rgba(1.0, 1.0, 1.0, 0.0),
},
},))
.floating(true)
.parent(ui.window)
.color(Some(match &site.kind {
SiteKind::Town => Color::Rgba(1.0, 1.0, 1.0, 0.0),
SiteKind::Castle => Color::Rgba(1.0, 1.0, 1.0, 0.0),
SiteKind::Dungeon { difficulty } => match difficulty {
0 => QUALITY_LOW,
1 => QUALITY_COMMON,
2 => QUALITY_MODERATE,
3 => QUALITY_HIGH,
4 => QUALITY_EPIC,
5 => QUALITY_DEBUG,
_ => Color::Rgba(1.0, 1.0, 1.0, 0.0),
},
}))
.parent(state.ids.grid)
.set(state.ids.mmap_site_icons_bgs[i], ui);
Image::new(match &site.kind {
SiteKind::Town => self.imgs.mmap_site_town,
@ -295,7 +296,6 @@ impl<'a> Widget for MiniMap<'a> {
.middle_of(state.ids.mmap_site_icons_bgs[i])
.w_h(20.0, 20.0)
.color(Some(UI_HIGHLIGHT_0))
.floating(true)
.set(state.ids.mmap_site_icons[i], ui);
}
@ -309,9 +309,8 @@ impl<'a> Widget for MiniMap<'a> {
for (dir, id, name, bold) in dirs.iter() {
let cardinal_dir = Vec2::unit_x().rotated_z(self.ori.x as f64) * dir.x
+ Vec2::unit_y().rotated_z(self.ori.x as f64) * dir.y;
let clamped = (cardinal_dir * 3.0)
/ (cardinal_dir * 3.0).map(|e| e.abs()).reduce_partial_max();
let pos = clamped * (map_size * 0.73 - 10.0);
let clamped = cardinal_dir / cardinal_dir.map(|e| e.abs()).reduce_partial_max();
let pos = clamped * (map_size / 2.0 - 10.0);
Text::new(name)
.x_y_position_relative_to(
state.ids.grid,