mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Fixed many map problems, re-added surface mist
This commit is contained in:
parent
579bdcf10e
commit
aa59d66a76
@ -9,7 +9,7 @@ vec2 get_cloud_heights(vec2 pos) {
|
||||
const float CLOUD_HALF_WIDTH = 300;
|
||||
const float CLOUD_HEIGHT_VARIATION = 1500.0;
|
||||
float cloud_alt = CLOUD_AVG_ALT + (texture(t_noise, pos.xy * 0.00005).x - 0.5) * CLOUD_HEIGHT_VARIATION;
|
||||
#if (CLOUD_MODE != CLOUD_MODE_MINIMAL)
|
||||
#if (CLOUD_MODE > CLOUD_MODE_MINIMAL)
|
||||
cloud_alt += (texture(t_noise, pos.xy * 0.001).x - 0.5) * 0.1 * CLOUD_HEIGHT_VARIATION;
|
||||
#endif
|
||||
return vec2(cloud_alt, CLOUD_HALF_WIDTH);
|
||||
@ -18,15 +18,19 @@ vec2 get_cloud_heights(vec2 pos) {
|
||||
float emission_strength = clamp((sin(time_of_day.x / (3600 * 24)) - 0.8) / 0.1, 0, 1);
|
||||
|
||||
// Returns vec4(r, g, b, density)
|
||||
vec4 cloud_at(vec3 pos, float dist, out vec3 emission) {
|
||||
vec4 cloud_at(vec3 pos, float dist, bool close_hack, out vec3 emission) {
|
||||
// Natural attenuation of air (air naturally attenuates light that passes through it)
|
||||
// Simulate the atmosphere thinning above 3000 metres down to nothing at 5000 metres
|
||||
float air = 0.0001 * clamp((10000.0 - pos.z) / 7000, 0, 1);
|
||||
float air = 0.00015 * clamp((10000.0 - pos.z) / 7000, 0, 1);
|
||||
|
||||
// Mist sits close to the ground in valleys (TODO: use base_alt to put it closer to water)
|
||||
float MIST_MIN = 300;
|
||||
const float MIST_FADE_HEIGHT = 250;
|
||||
float mist = 0.0003 * pow(clamp(1.0 - (pos.z - MIST_MIN) / MIST_FADE_HEIGHT, 0.0, 1), 2) / (1.0 + pow(1.0 + dist / 20000.0, 2.0));
|
||||
float mist_min_alt = 0.5;
|
||||
#if (CLOUD_MODE > CLOUD_MODE_LOW)
|
||||
mist_min_alt = (texture(t_noise, pos.xy * 0.00015).x - 0.5) * 2 + 0.5;
|
||||
#endif
|
||||
mist_min_alt *= 250;
|
||||
const float MIST_FADE_HEIGHT = 500;
|
||||
float mist = 0.005 * pow(clamp(1.0 - (pos.z - mist_min_alt) / MIST_FADE_HEIGHT, 0.0, 1), 4.0) / (1.0 + pow(1.0 + dist / 20000.0, 2.0));
|
||||
|
||||
vec3 wind_pos = vec3(pos.xy + wind_offset, pos.z);
|
||||
|
||||
@ -34,6 +38,13 @@ vec4 cloud_at(vec3 pos, float dist, out vec3 emission) {
|
||||
float cloud_tendency = cloud_tendency_at(pos.xy);
|
||||
float cloud = 0;
|
||||
|
||||
// The first first sample is taken very close to the ground and does not match other sample distances.
|
||||
// This means that clouds get bizarre sampling. Avoiding sampling the clouds in this sample entirely makes for
|
||||
// better results.
|
||||
if (close_hack) {
|
||||
cloud_tendency = 0.0;
|
||||
}
|
||||
|
||||
vec2 cloud_attr = get_cloud_heights(wind_pos.xy);
|
||||
float cloud_factor = 0.0;
|
||||
float turb_noise = 0.0;
|
||||
@ -51,7 +62,7 @@ vec4 cloud_at(vec3 pos, float dist, out vec3 emission) {
|
||||
#if (CLOUD_MODE >= CLOUD_MODE_HIGH)
|
||||
turb_noise += (noise_3d((wind_pos + turb_offset * 0.3) * 0.01) - 0.5) * 0.125;
|
||||
#endif
|
||||
mist *= (1.0 + turb_noise);
|
||||
mist *= 1.0 + turb_noise;
|
||||
|
||||
cloud_factor = 0.5 * (1.0 - pow(min(abs(pos.z - cloud_attr.x) / (cloud_attr.y * pow(max(cloud_tendency * 20.0, 0), 0.5)), 1.0), 1.0));
|
||||
float cloud_flat = min(cloud_tendency, 0.07) * 0.05;
|
||||
@ -60,7 +71,7 @@ vec4 cloud_at(vec3 pos, float dist, out vec3 emission) {
|
||||
}
|
||||
|
||||
// What proportion of sunlight is *not* being blocked by nearby cloud? (approximation)
|
||||
float sun_access = clamp((pos.z - cloud_attr.x + turb_noise * 250.0) * 0.002 + 0.35 + mist * 10000, 0.0, 1);
|
||||
float sun_access = clamp((pos.z - cloud_attr.x + turb_noise * 250.0) * 0.002 + 0.35 + max(mist * 20000, 0), 0, 1);
|
||||
// Since we're assuming the sun/moon is always above (not always correct) it's the same for the moon
|
||||
float moon_access = sun_access;
|
||||
|
||||
@ -71,16 +82,16 @@ vec4 cloud_at(vec3 pos, float dist, out vec3 emission) {
|
||||
vec3 cloud_norm = vec3(
|
||||
(cloud_tendency - cloud_tendency_x) * 6,
|
||||
(cloud_tendency - cloud_tendency_y) * 6,
|
||||
(pos.z - cloud_attr.x) / 450 + turb_noise
|
||||
) * 0.5;
|
||||
sun_access = mix(max(dot(-sun_dir.xyz, cloud_norm) + 0.5, 0.025), sun_access, 0.25);
|
||||
moon_access = mix(max(dot(-moon_dir.xyz, cloud_norm) + 0.5, 0.025), moon_access, 0.25);
|
||||
(pos.z - cloud_attr.x) / 250 + turb_noise + 0.25
|
||||
);
|
||||
sun_access = mix(max(dot(-sun_dir.xyz, cloud_norm) + 0.0, 0.025), sun_access, 0.25);
|
||||
moon_access = mix(max(dot(-moon_dir.xyz, cloud_norm) + 0.35, 0.025), moon_access, 0.25);
|
||||
#endif
|
||||
|
||||
// Prevent mist (i.e: vapour beneath clouds) being accessible to the sun to avoid visual problems
|
||||
float suppress_mist = clamp((pos.z - cloud_attr.x + cloud_attr.y) / 300, 0, 1);
|
||||
sun_access *= suppress_mist;
|
||||
moon_access *= suppress_mist;
|
||||
//sun_access *= suppress_mist;
|
||||
//moon_access *= suppress_mist;
|
||||
|
||||
// Prevent clouds and mist appearing underground (but fade them out gently)
|
||||
float not_underground = clamp(1.0 - (alt_at(pos.xy - focus_off.xy) - (pos.z - focus_off.z)) / 80.0, 0, 1);
|
||||
@ -149,11 +160,11 @@ vec3 get_cloud_color(vec3 surf_color, vec3 dir, vec3 origin, const float time_of
|
||||
vec3 dir_diff = vec3(0);
|
||||
#if (CLOUD_MODE == CLOUD_MODE_MINIMAL)
|
||||
/* splay += (texture(t_noise, vec2(atan2(dir.x, dir.y) * 2 / PI, dir.z) * 1.5 - time_of_day * 0.000025).x - 0.5) * 0.4 / (1.0 + pow(dir.z, 2) * 10); */
|
||||
dir_diff = vec3(
|
||||
(texture(t_noise, vec2(atan2(dir.x, dir.y) * 2 / PI, dir.z) * 1.0 - time_of_day * 0.00005).x - 0.5) * 0.2 / (1.0 + pow(dir.z, 2) * 10),
|
||||
(texture(t_noise, vec2(atan2(dir.x, dir.y) * 2 / PI, dir.z) * 1.0 - time_of_day * 0.00005).x - 0.5) * 0.2 / (1.0 + pow(dir.z, 2) * 10),
|
||||
(texture(t_noise, vec2(atan2(dir.x, dir.y) * 2 / PI, dir.z) * 1.0 - time_of_day * 0.00005).x - 0.5) * 0.2 / (1.0 + pow(dir.z, 2) * 10)
|
||||
) * 1500;
|
||||
/* dir_diff = vec3( */
|
||||
/* (texture(t_noise, vec2(atan2(dir.x, dir.y) * 2 / PI, dir.z) * 1.0 - time_of_day * 0.00005).x - 0.5) * 0.2 / (1.0 + pow(dir.z, 2) * 10), */
|
||||
/* (texture(t_noise, vec2(atan2(dir.x, dir.y) * 2 / PI, dir.z) * 1.0 - time_of_day * 0.00005).x - 0.5) * 0.2 / (1.0 + pow(dir.z, 2) * 10), */
|
||||
/* (texture(t_noise, vec2(atan2(dir.x, dir.y) * 2 / PI, dir.z) * 1.0 - time_of_day * 0.00005).x - 0.5) * 0.2 / (1.0 + pow(dir.z, 2) * 10) */
|
||||
/* ) * 1500; */
|
||||
splay += (texture(t_noise, vec2(atan2(dir.x, dir.y) * 2 / PI, dir.z) * 5.0 - time_of_day * 0.00005).x - 0.5) * 0.075 / (1.0 + pow(dir.z, 2) * 10);
|
||||
#endif
|
||||
|
||||
@ -164,18 +175,22 @@ vec3 get_cloud_color(vec3 surf_color, vec3 dir, vec3 origin, const float time_of
|
||||
float net_light = get_sun_brightness() + get_moon_brightness();
|
||||
|
||||
float cdist = max_dist;
|
||||
while (cdist > 1) {
|
||||
float ndist = step_to_dist(trunc(dist_to_step(cdist - 0.25)));
|
||||
float ldist = cdist * 1.25;
|
||||
bool close_hack = true;
|
||||
//int i = 0;
|
||||
while (cdist > 4 /*&& i < 1000*/) {
|
||||
//i += 1;
|
||||
vec3 emission;
|
||||
vec4 sample = cloud_at(origin + (dir + dir_diff / ndist) * ndist * splay, ndist, emission);
|
||||
vec4 sample = cloud_at(origin + (dir + dir_diff / cdist) * ldist * splay, ldist, close_hack, emission);
|
||||
close_hack = false;
|
||||
|
||||
vec2 density_integrals = max(sample.zw, vec2(0)) * (cdist - ndist);
|
||||
vec2 density_integrals = max(sample.zw, vec2(0)) * (ldist - cdist);
|
||||
|
||||
float sun_access = sample.x;
|
||||
float moon_access = sample.y;
|
||||
float scatter_factor = 1.0 - 1.0 / (1.0 + density_integrals.x);
|
||||
|
||||
const float RAYLEIGH = 0.5;
|
||||
const float RAYLEIGH = 0.25;
|
||||
|
||||
surf_color =
|
||||
// Attenuate light passing through the clouds
|
||||
@ -191,7 +206,9 @@ vec3 get_cloud_color(vec3 surf_color, vec3 dir, vec3 origin, const float time_of
|
||||
sky_color * sun_access * scatter_factor * get_sun_brightness() +
|
||||
sky_color * moon_access * scatter_factor * get_moon_brightness();
|
||||
|
||||
cdist = ndist;
|
||||
|
||||
ldist = cdist;
|
||||
cdist = step_to_dist(trunc(dist_to_step(cdist - 0.25)));
|
||||
}
|
||||
|
||||
return surf_color;
|
||||
|
@ -39,8 +39,8 @@ widget_ids! {
|
||||
map_settings_align,
|
||||
show_towns_img,
|
||||
show_towns_box,
|
||||
show_towns_text,
|
||||
show_castles_img,
|
||||
show_towns_text,
|
||||
show_castles_img,
|
||||
show_castles_box,
|
||||
show_castles_text,
|
||||
show_dungeons_img,
|
||||
@ -65,7 +65,7 @@ pub struct Map<'a> {
|
||||
localized_strings: &'a Localization,
|
||||
global_state: &'a GlobalState,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
}
|
||||
impl<'a> Map<'a> {
|
||||
#[allow(clippy::too_many_arguments)] // TODO: Pending review in #587
|
||||
@ -79,7 +79,7 @@ impl<'a> Map<'a> {
|
||||
pulse: f32,
|
||||
localized_strings: &'a Localization,
|
||||
global_state: &'a GlobalState,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
) -> Self {
|
||||
Self {
|
||||
show: show,
|
||||
@ -92,7 +92,7 @@ impl<'a> Map<'a> {
|
||||
_pulse: pulse,
|
||||
localized_strings,
|
||||
global_state,
|
||||
tooltip_manager,
|
||||
tooltip_manager,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -191,7 +191,7 @@ impl<'a> Widget for Map<'a> {
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.font_size(self.fonts.cyri.scale(21))
|
||||
.color(TEXT_COLOR)
|
||||
.set(state.ids.qlog_title, ui);
|
||||
.set(state.ids.qlog_title, ui);
|
||||
|
||||
// Location Name
|
||||
/*match self.client.current_chunk() {
|
||||
@ -234,19 +234,19 @@ impl<'a> Widget for Map<'a> {
|
||||
|
||||
let w_src = max_zoom / zoom;
|
||||
let h_src = max_zoom / zoom;
|
||||
// Handle dragging
|
||||
let drag = self.global_state.settings.gameplay.map_drag;
|
||||
// Handle dragging
|
||||
let drag = self.global_state.settings.gameplay.map_drag;
|
||||
let dragged: Vec2::<f64> = ui.widget_input(state.ids.grid).drags().left().map(|drag| Vec2::<f64>::from(drag.delta_xy)).sum();
|
||||
let drag_new = drag + dragged;
|
||||
events.push(Event::MapDrag(drag_new));
|
||||
|
||||
let drag_new = drag + dragged / zoom;
|
||||
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) + drag.y,
|
||||
],
|
||||
[w_src, h_src],
|
||||
);
|
||||
);
|
||||
// X-Button
|
||||
if Button::image(self.imgs.close_button)
|
||||
.w_h(24.0, 25.0)
|
||||
@ -256,8 +256,8 @@ impl<'a> Widget for Map<'a> {
|
||||
.set(state.ids.close, ui)
|
||||
.was_clicked()
|
||||
{
|
||||
events.push(Event::Close);
|
||||
events.push(Event::MapDrag(drag_new - drag_new));
|
||||
events.push(Event::Close);
|
||||
events.push(Event::MapDrag(drag_new - drag_new));
|
||||
}
|
||||
Image::new(world_map.none)
|
||||
.mid_top_with_margin_on(state.ids.map_align, 10.0)
|
||||
@ -281,13 +281,13 @@ impl<'a> Widget for Map<'a> {
|
||||
.set(state.ids.zoom_slider, ui)
|
||||
{
|
||||
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 + scrolled * 0.1).clamped(1.0, max_zoom);
|
||||
events.push(Event::MapZoom(new_zoom_lvl as f64));
|
||||
|
||||
let new_zoom_lvl = (zoom_lvl * (1.0 + scrolled * 0.1)).clamped(1.0, 20.0/*max_zoom*/);
|
||||
events.push(Event::MapZoom(new_zoom_lvl as f64));
|
||||
|
||||
|
||||
// Icon settings
|
||||
// Alignment
|
||||
@ -298,7 +298,7 @@ impl<'a> Widget for Map<'a> {
|
||||
// Show difficulties
|
||||
Image::new(self.imgs.map_dif_5)
|
||||
.top_left_with_margins_on(state.ids.map_settings_align, 5.0, 5.0)
|
||||
.w_h(20.0, 20.0)
|
||||
.w_h(20.0, 20.0)
|
||||
.set(state.ids.show_difficulty_img, ui);
|
||||
if Button::image(if self.show.map_difficulty {
|
||||
self.imgs.checkbox_checked} else {self.imgs.checkbox})
|
||||
@ -323,7 +323,7 @@ impl<'a> Widget for Map<'a> {
|
||||
// Towns
|
||||
Image::new(self.imgs.mmap_site_town)
|
||||
.down_from(state.ids.show_difficulty_img, 10.0)
|
||||
.w_h(20.0, 20.0)
|
||||
.w_h(20.0, 20.0)
|
||||
.set(state.ids.show_towns_img, ui);
|
||||
if Button::image(if self.show.map_towns {
|
||||
self.imgs.checkbox_checked} else {self.imgs.checkbox})
|
||||
@ -348,7 +348,7 @@ impl<'a> Widget for Map<'a> {
|
||||
// Castles
|
||||
Image::new(self.imgs.mmap_site_castle)
|
||||
.down_from(state.ids.show_towns_img, 10.0)
|
||||
.w_h(20.0, 20.0)
|
||||
.w_h(20.0, 20.0)
|
||||
.set(state.ids.show_castles_img, ui);
|
||||
if Button::image(if self.show.map_castles {
|
||||
self.imgs.checkbox_checked} else {self.imgs.checkbox})
|
||||
@ -373,7 +373,7 @@ impl<'a> Widget for Map<'a> {
|
||||
// Dungeons
|
||||
Image::new(self.imgs.mmap_site_dungeon)
|
||||
.down_from(state.ids.show_castles_img, 10.0)
|
||||
.w_h(20.0, 20.0)
|
||||
.w_h(20.0, 20.0)
|
||||
.set(state.ids.show_dungeons_img, ui);
|
||||
if Button::image(if self.show.map_dungeons {
|
||||
self.imgs.checkbox_checked} else {self.imgs.checkbox})
|
||||
@ -417,8 +417,9 @@ Text::new("Dungeons")
|
||||
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;
|
||||
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);
|
||||
|
||||
if rpos
|
||||
.map2(map_size, |e, sz| e.abs() > sz as f32 / 2.0)
|
||||
@ -433,7 +434,7 @@ Text::new("Dungeons")
|
||||
SiteKind::Dungeon => "Dungeon",
|
||||
SiteKind::Castle => "Castle",
|
||||
};
|
||||
let desc = format!("Difficulty: {}", dif);
|
||||
let desc = format!("Difficulty: {}", dif);
|
||||
Button::image(match &site.kind {
|
||||
SiteKind::Town => if self.show.map_towns {self.imgs.mmap_site_town } else {self.imgs.nothing},
|
||||
SiteKind::Dungeon => if self.show.map_dungeons {self.imgs.mmap_site_dungeon} else {self.imgs.nothing},
|
||||
@ -441,15 +442,15 @@ Text::new("Dungeons")
|
||||
})
|
||||
.x_y_position_relative_to(
|
||||
state.ids.grid,
|
||||
position::Relative::Scalar(rpos.x as f64 + drag.x * zoom_lvl),
|
||||
position::Relative::Scalar(rpos.y as f64 + drag.y * zoom_lvl),
|
||||
position::Relative::Scalar(rpos.x as f64),
|
||||
position::Relative::Scalar(rpos.y as f64),
|
||||
)
|
||||
.w_h(20.0 * 1.2, 20.0 * 1.2)
|
||||
.hover_image(match &site.kind {
|
||||
SiteKind::Town => self.imgs.mmap_site_town_hover,
|
||||
SiteKind::Dungeon => self.imgs.mmap_site_dungeon_hover,
|
||||
SiteKind::Castle => self.imgs.mmap_site_castle_hover,
|
||||
})
|
||||
})
|
||||
.image_color(UI_HIGHLIGHT_0)
|
||||
.parent(ui.window)
|
||||
.with_tooltip(self.tooltip_manager, title, &desc, &site_tooltip, match dif {
|
||||
@ -464,7 +465,7 @@ Text::new("Dungeons")
|
||||
.set(state.ids.mmap_site_icons[i], ui);
|
||||
|
||||
// Difficulty from 0-6
|
||||
// 0 = towns and places without a difficulty level
|
||||
// 0 = towns and places without a difficulty level
|
||||
if self.show.map_difficulty {
|
||||
|
||||
let size = 1.8; // Size factor for difficulty indicators
|
||||
@ -481,11 +482,11 @@ Text::new("Dungeons")
|
||||
6 => -12.0 * size,
|
||||
_ => -4.0 * size,
|
||||
})
|
||||
.w(match dif {
|
||||
.w(match dif {
|
||||
6 => 12.0 * size,
|
||||
_ => 4.0 * size * dif as f64,
|
||||
})
|
||||
.h(match dif {
|
||||
.h(match dif {
|
||||
6 => 12.0 * size,
|
||||
_ => 4.0 * size,
|
||||
})
|
||||
@ -504,7 +505,7 @@ Text::new("Dungeons")
|
||||
SiteKind::Town => if self.show.map_towns {dif_img.set(state.ids.site_difs[i], ui) },
|
||||
SiteKind::Dungeon => if self.show.map_dungeons {dif_img.set(state.ids.site_difs[i], ui)},
|
||||
SiteKind::Castle => if self.show.map_castles {dif_img.set(state.ids.site_difs[i], ui)},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -517,16 +518,26 @@ Text::new("Dungeons")
|
||||
(e as f64 / sz).clamped(0.0, 1.0)
|
||||
});*/
|
||||
//let xy = rel * 760.0;
|
||||
let scale = 0.6;
|
||||
let arrow_sz = Vec2::new(32.0, 37.0) * scale;
|
||||
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)
|
||||
.w_h(arrow_sz.x, arrow_sz.y)
|
||||
.color(Some(UI_HIGHLIGHT_0))
|
||||
.floating(true)
|
||||
.parent(ui.window)
|
||||
.set(state.ids.indicator, ui);
|
||||
|
||||
let rpos = drag.map(|e| (e * zoom_lvl) as f32 / 2.0);
|
||||
if !rpos
|
||||
.map2(map_size, |e, sz| e.abs() > sz as f32 / 1.67)
|
||||
.reduce_or()
|
||||
{
|
||||
let scale = 0.6;
|
||||
let arrow_sz = Vec2::new(32.0, 37.0) * scale;
|
||||
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)
|
||||
.x_y_position_relative_to(
|
||||
state.ids.grid,
|
||||
position::Relative::Scalar(rpos.x as f64),
|
||||
position::Relative::Scalar(rpos.y as f64),
|
||||
)
|
||||
.w_h(arrow_sz.x, arrow_sz.y)
|
||||
.color(Some(UI_HIGHLIGHT_0))
|
||||
.floating(true)
|
||||
.parent(ui.window)
|
||||
.set(state.ids.indicator, ui);
|
||||
}
|
||||
|
||||
events
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user