mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Hack to allow minimap rotation.
Currently it just always rotates towards the camera, but it wouldn't be hard to create a config option that swaps out the rotation of the indicator and the map.
This commit is contained in:
parent
1a61d2f154
commit
7702df5d8d
@ -10,8 +10,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Added
|
||||
|
||||
- Added music system
|
||||
- Added zoomable and rotatable minimap
|
||||
- Added rotating orientation marker to main-map
|
||||
|
||||
### Changed
|
||||
- Brighter / higher contrast main-map
|
||||
|
||||
### Removed
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -20,7 +20,8 @@ void main() {
|
||||
if (f_mode == uint(0)) {
|
||||
tgt_color = f_color * vec4(1.0, 1.0, 1.0, texture(u_tex, f_uv).a);
|
||||
// Image
|
||||
} else if (f_mode == uint(1)) {
|
||||
// HACK: bit 0 is set for both ordinary and north-facing images.
|
||||
} else if ((f_mode & uint(1)) == uint(1)) {
|
||||
tgt_color = f_color * texture(u_tex, f_uv);
|
||||
// 2D Geometry
|
||||
} else if (f_mode == uint(2)) {
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
in vec2 v_pos;
|
||||
in vec2 v_uv;
|
||||
in vec2 v_center;
|
||||
in vec4 v_color;
|
||||
in uint v_mode;
|
||||
|
||||
@ -19,15 +20,31 @@ flat out uint f_mode;
|
||||
out vec4 f_color;
|
||||
|
||||
void main() {
|
||||
f_uv = v_uv;
|
||||
f_color = v_color;
|
||||
|
||||
if (w_pos.w == 1.0) {
|
||||
f_uv = v_uv;
|
||||
// Fixed scale In-game element
|
||||
vec4 projected_pos = proj_mat * view_mat * vec4(w_pos.xyz, 1.0);
|
||||
gl_Position = vec4(projected_pos.xy / projected_pos.w + v_pos, 0.0, 1.0);
|
||||
} else if (v_mode == uint(3)) {
|
||||
// HACK: North facing source rectangle.
|
||||
vec2 look_at_dir = normalize(vec2(-view_mat[0][2], -view_mat[1][2]));
|
||||
mat2 look_at = mat2(look_at_dir.y, look_at_dir.x, -look_at_dir.x, look_at_dir.y);
|
||||
f_uv = v_center + look_at * (v_uv - v_center);
|
||||
gl_Position = vec4(v_pos, 0.0, 1.0);
|
||||
} else if (v_mode == uint(5)) {
|
||||
// HACK: North facing target rectangle.
|
||||
f_uv = v_uv;
|
||||
float aspect_ratio = screen_res.x / screen_res.y;
|
||||
vec2 look_at_dir = normalize(vec2(-view_mat[0][2], -view_mat[1][2]));
|
||||
mat2 look_at = mat2(look_at_dir.y, -look_at_dir.x, look_at_dir.x, look_at_dir.y);
|
||||
vec2 v_len = v_pos - v_center;
|
||||
vec2 v_proj = look_at * vec2(v_len.x, v_len.y / aspect_ratio);
|
||||
gl_Position = vec4(v_center + vec2(v_proj.x, v_proj.y * aspect_ratio), 0.0, 1.0);
|
||||
} else {
|
||||
// Interface element
|
||||
f_uv = v_uv;
|
||||
gl_Position = vec4(v_pos, 0.0, 1.0);
|
||||
}
|
||||
f_mode = v_mode;
|
||||
|
@ -8,6 +8,13 @@ rotation_image_ids! {
|
||||
// Tooltip Test
|
||||
tt_side: "voxygen/element/frames/tt_test_edge",
|
||||
tt_corner: "voxygen/element/frames/tt_test_corner_tr",
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
<VoxelPixArtGraphic>
|
||||
|
||||
// Minimap
|
||||
indicator_mmap_small: "voxygen.element.buttons.indicator_mmap_small",
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,7 +138,6 @@ image_ids! {
|
||||
skull_2: "voxygen.element.icons.skull_2",
|
||||
|
||||
// Map
|
||||
map_indicator: "voxygen.element.buttons.map_indicator",
|
||||
indicator_mmap: "voxygen.element.buttons.indicator_mmap",
|
||||
indicator_mmap_2: "voxygen.element.buttons.indicator_mmap_2",
|
||||
indicator_mmap_3: "voxygen.element.buttons.indicator_mmap_3",
|
||||
@ -169,7 +175,7 @@ image_ids! {
|
||||
mmap_open_press: "voxygen.element.buttons.button_mmap_open_press",
|
||||
mmap_plus: "voxygen.element.buttons.min_plus.mmap_button-plus",
|
||||
mmap_plus_hover: "voxygen.element.buttons.min_plus.mmap_button-plus_hover",
|
||||
mmap_plus_press: "voxygen.element.buttons.min_plus.mmap_button-plus_hover",
|
||||
mmap_plus_press: "voxygen.element.buttons.min_plus.mmap_button-plus_press",
|
||||
mmap_minus: "voxygen.element.buttons.min_plus.mmap_button-min",
|
||||
mmap_minus_hover: "voxygen.element.buttons.min_plus.mmap_button-min_hover",
|
||||
mmap_minus_press: "voxygen.element.buttons.min_plus.mmap_button-min_press",
|
||||
|
@ -1,9 +1,12 @@
|
||||
use super::{img_ids::Imgs, Fonts, Show, TEXT_COLOR};
|
||||
use super::{
|
||||
img_ids::{Imgs, ImgsRot},
|
||||
Fonts, Show, TEXT_COLOR,
|
||||
};
|
||||
use crate::ui::img_ids;
|
||||
use client::{self, Client};
|
||||
use common::{comp, terrain::TerrainChunkSize, vol::RectVolSize};
|
||||
use conrod_core::{
|
||||
color,
|
||||
image::Id,
|
||||
widget::{self, Button, Image, Rectangle, Text},
|
||||
widget_ids, Color, Colorable, Positionable, Sizeable, Widget, WidgetCommon,
|
||||
};
|
||||
@ -30,12 +33,13 @@ widget_ids! {
|
||||
pub struct Map<'a> {
|
||||
_show: &'a Show,
|
||||
client: &'a Client,
|
||||
world_map: (Id, Vec2<u32>),
|
||||
world_map: &'a (img_ids::Rotations, Vec2<u32>),
|
||||
imgs: &'a Imgs,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
fonts: &'a Fonts,
|
||||
#[conrod(common_builder)]
|
||||
common: widget::CommonBuilder,
|
||||
pulse: f32,
|
||||
_pulse: f32,
|
||||
velocity: f32,
|
||||
}
|
||||
impl<'a> Map<'a> {
|
||||
@ -43,7 +47,8 @@ impl<'a> Map<'a> {
|
||||
show: &'a Show,
|
||||
client: &'a Client,
|
||||
imgs: &'a Imgs,
|
||||
world_map: (Id, Vec2<u32>),
|
||||
rot_imgs: &'a ImgsRot,
|
||||
world_map: &'a (img_ids::Rotations, Vec2<u32>),
|
||||
fonts: &'a Fonts,
|
||||
pulse: f32,
|
||||
velocity: f32,
|
||||
@ -51,11 +56,12 @@ impl<'a> Map<'a> {
|
||||
Self {
|
||||
_show: show,
|
||||
imgs,
|
||||
rot_imgs,
|
||||
world_map,
|
||||
client,
|
||||
fonts,
|
||||
common: widget::CommonBuilder::default(),
|
||||
pulse,
|
||||
_pulse: pulse,
|
||||
velocity,
|
||||
}
|
||||
}
|
||||
@ -160,9 +166,9 @@ impl<'a> Widget for Map<'a> {
|
||||
let (world_map, worldsize) = self.world_map;
|
||||
let worldsize = worldsize.map2(TerrainChunkSize::RECT_SIZE, |e, f| e as f64 * f as f64);
|
||||
|
||||
Image::new(world_map)
|
||||
Image::new(world_map.none)
|
||||
.middle_of(state.ids.map_bg)
|
||||
.color(Some(Color::Rgba(1.0, 1.0, 1.0, fade - 0.1)))
|
||||
.color(Some(Color::Rgba(1.0, 1.0, 1.0, fade + 0.5)))
|
||||
.w_h(700.0, 700.0)
|
||||
.parent(state.ids.map_bg)
|
||||
.set(state.ids.grid, ui);
|
||||
@ -177,31 +183,18 @@ impl<'a> Widget for Map<'a> {
|
||||
|
||||
let x = player_pos.x as f64 / worldsize.x * 700.0;
|
||||
let y = player_pos.y as f64 / worldsize.y * 700.0;
|
||||
let indic_ani = (self.pulse * 6.0/*animation speed*/).cos()/*starts at 1.0*/ * 0.5 + 0.50; // changes the animation frame
|
||||
let indic_scale = 1.2;
|
||||
// Indicator
|
||||
Image::new(if indic_ani <= 0.3 {
|
||||
self.imgs.indicator_mmap
|
||||
} else if indic_ani <= 0.6 {
|
||||
self.imgs.indicator_mmap_2
|
||||
} else {
|
||||
self.imgs.indicator_mmap_3
|
||||
})
|
||||
.bottom_left_with_margins_on(state.ids.grid, y, x - (20.0 * 1.2) / 2.0)
|
||||
.w_h(
|
||||
22.0 * 1.2,
|
||||
if indic_ani <= 0.3 {
|
||||
16.0 * indic_scale
|
||||
} else if indic_ani <= 0.6 {
|
||||
23.0 * indic_scale
|
||||
} else {
|
||||
34.0 * indic_scale
|
||||
},
|
||||
)
|
||||
.color(Some(Color::Rgba(1.0, 1.0, 1.0, fade + 0.2)))
|
||||
.floating(true)
|
||||
.parent(ui.window)
|
||||
.set(state.ids.indicator, ui);
|
||||
let indic_scale = 0.6;
|
||||
Image::new(self.rot_imgs.indicator_mmap_small.target_north)
|
||||
.bottom_left_with_margins_on(
|
||||
state.ids.grid,
|
||||
y - 37.0 * indic_scale / 2.0,
|
||||
x - 32.0 * indic_scale / 2.0,
|
||||
)
|
||||
.w_h(32.0 * indic_scale, 37.0 * indic_scale)
|
||||
.color(Some(Color::Rgba(1.0, 1.0, 1.0, 1.0)))
|
||||
.floating(true)
|
||||
.parent(ui.window)
|
||||
.set(state.ids.indicator, ui);
|
||||
|
||||
None
|
||||
}
|
||||
|
@ -1,9 +1,12 @@
|
||||
use super::{img_ids::Imgs, Fonts, Show, HP_COLOR, TEXT_COLOR};
|
||||
use super::{
|
||||
img_ids::{Imgs, ImgsRot},
|
||||
Fonts, Show, HP_COLOR, TEXT_COLOR,
|
||||
};
|
||||
use crate::ui::img_ids;
|
||||
use client::{self, Client};
|
||||
use common::{comp, terrain::TerrainChunkSize, vol::RectVolSize};
|
||||
use conrod_core::{
|
||||
color,
|
||||
image::Id,
|
||||
color, position,
|
||||
widget::{self, Button, Image, Rectangle, Text},
|
||||
widget_ids, Color, Colorable, Positionable, Sizeable, Widget, WidgetCommon,
|
||||
};
|
||||
@ -33,12 +36,11 @@ pub struct MiniMap<'a> {
|
||||
client: &'a Client,
|
||||
|
||||
imgs: &'a Imgs,
|
||||
world_map: (Id, Vec2<u32>),
|
||||
rot_imgs: &'a ImgsRot,
|
||||
world_map: &'a (img_ids::Rotations, Vec2<u32>),
|
||||
fonts: &'a Fonts,
|
||||
#[conrod(common_builder)]
|
||||
common: widget::CommonBuilder,
|
||||
pulse: f32,
|
||||
zoom: f32,
|
||||
}
|
||||
|
||||
impl<'a> MiniMap<'a> {
|
||||
@ -46,20 +48,18 @@ impl<'a> MiniMap<'a> {
|
||||
show: &'a Show,
|
||||
client: &'a Client,
|
||||
imgs: &'a Imgs,
|
||||
world_map: (Id, Vec2<u32>),
|
||||
rot_imgs: &'a ImgsRot,
|
||||
world_map: &'a (img_ids::Rotations, Vec2<u32>),
|
||||
fonts: &'a Fonts,
|
||||
pulse: f32,
|
||||
zoom: f32,
|
||||
) -> Self {
|
||||
Self {
|
||||
show,
|
||||
client,
|
||||
imgs,
|
||||
rot_imgs,
|
||||
world_map,
|
||||
fonts,
|
||||
common: widget::CommonBuilder::default(),
|
||||
pulse,
|
||||
zoom,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -69,6 +69,7 @@ pub struct State {
|
||||
|
||||
last_region_name: Option<String>,
|
||||
last_update: Instant,
|
||||
zoom: f64,
|
||||
}
|
||||
|
||||
pub enum Event {
|
||||
@ -86,6 +87,14 @@ impl<'a> Widget for MiniMap<'a> {
|
||||
|
||||
last_region_name: None,
|
||||
last_update: Instant::now(),
|
||||
zoom: {
|
||||
let min_world_dim = self.world_map.1.reduce_partial_min() as f64;
|
||||
min_world_dim.min(
|
||||
min_world_dim
|
||||
* (TerrainChunkSize::RECT_SIZE.reduce_partial_max() as f64 / 32.0)
|
||||
* (16.0 / 1024.0),
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,53 +102,74 @@ impl<'a> Widget for MiniMap<'a> {
|
||||
|
||||
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
|
||||
let widget::UpdateArgs { state, ui, .. } = args;
|
||||
let zoom = self.zoom as f64;
|
||||
let zoom = state.zoom;
|
||||
if self.show.mini_map {
|
||||
Image::new(self.imgs.mmap_frame)
|
||||
.w_h(100.0 * 4.0 * zoom, 100.0 * 4.0 * zoom)
|
||||
.w_h(100.0 * 3.0, 100.0 * 3.0)
|
||||
.top_right_with_margins_on(ui.window, 5.0, 5.0)
|
||||
.set(state.ids.mmap_frame, ui);
|
||||
|
||||
Rectangle::fill_with([92.0 * 4.0, 82.0 * 4.0], color::TRANSPARENT)
|
||||
.mid_top_with_margin_on(state.ids.mmap_frame, 13.0 * 4.0 + 4.0 * zoom)
|
||||
Rectangle::fill_with([92.0 * 3.0, 82.0 * 3.0], color::TRANSPARENT)
|
||||
.mid_top_with_margin_on(state.ids.mmap_frame, 13.0 * 3.0 + 3.0)
|
||||
.set(state.ids.mmap_frame_bg, ui);
|
||||
// Zoom Buttons
|
||||
// TODO: Add zoomable minimap
|
||||
|
||||
/*if Button::image(self.imgs.mmap_plus)
|
||||
.w_h(100.0 * 0.2 * zoom, 100.0 * 0.2 * zoom)
|
||||
.hover_image(self.imgs.mmap_plus_hover)
|
||||
.press_image(self.imgs.mmap_plus_press)
|
||||
.top_left_with_margins_on(state.ids.mmap_frame, 0.0, 0.0)
|
||||
.set(state.ids.mmap_plus, ui)
|
||||
.was_clicked()
|
||||
{
|
||||
if zoom > 0.0 {
|
||||
zoom = zoom + 1.0
|
||||
} else if zoom == 5.0 {
|
||||
}
|
||||
}
|
||||
if Button::image(self.imgs.mmap_minus)
|
||||
.w_h(100.0 * 0.2 * zoom, 100.0 * 0.2 * zoom)
|
||||
.hover_image(self.imgs.mmap_minus_hover)
|
||||
.press_image(self.imgs.mmap_minus_press)
|
||||
.down_from(state.ids.mmap_plus, 0.0)
|
||||
.set(state.ids.mmap_minus, ui)
|
||||
.was_clicked()
|
||||
{
|
||||
if zoom < 6.0 {
|
||||
zoom = zoom - 1.0
|
||||
} else if zoom == 0.0 {
|
||||
}
|
||||
}*/
|
||||
// Map Image
|
||||
// Map size
|
||||
let (world_map, worldsize) = self.world_map;
|
||||
let worldsize = worldsize.map2(TerrainChunkSize::RECT_SIZE, |e, f| e as f64 * f as f64);
|
||||
Image::new(world_map)
|
||||
.middle_of(state.ids.mmap_frame_bg)
|
||||
.w_h(92.0 * 4.0 * zoom, 82.0 * 4.0 * zoom)
|
||||
.parent(state.ids.mmap_frame_bg)
|
||||
.set(state.ids.grid, ui);
|
||||
|
||||
// Zoom Buttons
|
||||
|
||||
// Pressing + multiplies, and - divides, zoom by ZOOM_FACTOR.
|
||||
const ZOOM_FACTOR: f64 = 2.0;
|
||||
|
||||
// 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_min()/*.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
|
||||
// button clicked, it is also okay to perform the zoom action.
|
||||
// Note that since `Button::image` has side effects, we must perform
|
||||
// the `can_zoom_in` and `can_zoom_out` checks after the `&&` to avoid
|
||||
// undesired early termination.
|
||||
let can_zoom_in = zoom < max_zoom;
|
||||
let can_zoom_out = zoom > min_zoom;
|
||||
|
||||
if Button::image(self.imgs.mmap_minus)
|
||||
.w_h(100.0 * 0.30, 100.0 * 0.30)
|
||||
.hover_image(self.imgs.mmap_minus_hover)
|
||||
.press_image(self.imgs.mmap_minus_press)
|
||||
.top_left_with_margins_on(state.ids.mmap_frame, 0.0, 0.0)
|
||||
.enabled(can_zoom_out)
|
||||
.set(state.ids.mmap_minus, ui)
|
||||
.was_clicked()
|
||||
&& can_zoom_out
|
||||
{
|
||||
// Set the image dimensions here, rather than recomputing each time.
|
||||
let zoom = min_zoom.max(zoom / ZOOM_FACTOR);
|
||||
state.update(|s| s.zoom = zoom);
|
||||
// set_image_dims(zoom);
|
||||
}
|
||||
if Button::image(self.imgs.mmap_plus)
|
||||
.w_h(100.0 * 0.30, 100.0 * 0.30)
|
||||
.hover_image(self.imgs.mmap_plus_hover)
|
||||
.press_image(self.imgs.mmap_plus_press)
|
||||
.right_from(state.ids.mmap_minus, 6.0)
|
||||
.enabled(can_zoom_in)
|
||||
.set(state.ids.mmap_plus, ui)
|
||||
.was_clicked()
|
||||
&& can_zoom_in
|
||||
{
|
||||
let zoom = max_zoom.min(zoom * ZOOM_FACTOR);
|
||||
state.update(|s| s.zoom = zoom);
|
||||
// set_image_dims(zoom);
|
||||
}
|
||||
|
||||
// Reload zoom in case it changed.
|
||||
let zoom = state.zoom;
|
||||
|
||||
// Coordinates
|
||||
let player_pos = self
|
||||
.client
|
||||
@ -149,30 +179,36 @@ impl<'a> Widget for MiniMap<'a> {
|
||||
.get(self.client.entity())
|
||||
.map_or(Vec3::zero(), |pos| pos.0);
|
||||
|
||||
let x = player_pos.x as f64 / worldsize.x * 92.0 * 4.0;
|
||||
let y = player_pos.y as f64 / worldsize.y * 82.0 * 4.0;
|
||||
let indic_ani = (self.pulse * 6.0).cos() * 0.5 + 0.5; //Animation timer
|
||||
let indic_scale = 0.8;
|
||||
// Get map image source rectangle dimensons.
|
||||
let w_src = worldsize.x / TerrainChunkSize::RECT_SIZE.x as f64 / zoom;
|
||||
let h_src = worldsize.y / TerrainChunkSize::RECT_SIZE.y as f64 / zoom;
|
||||
|
||||
// Set map image to be centered around player coordinates.
|
||||
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,
|
||||
],
|
||||
[w_src, h_src],
|
||||
);
|
||||
|
||||
// Map Image
|
||||
Image::new(world_map.source_north)
|
||||
.middle_of(state.ids.mmap_frame_bg)
|
||||
.w_h(92.0 * 3.0, 82.0 * 3.0)
|
||||
.parent(state.ids.mmap_frame_bg)
|
||||
.source_rectangle(rect_src)
|
||||
.set(state.ids.grid, ui);
|
||||
|
||||
// Indicator
|
||||
Image::new(if indic_ani <= 0.5 {
|
||||
self.imgs.indicator_mmap
|
||||
} else {
|
||||
self.imgs.indicator_mmap_2
|
||||
})
|
||||
.bottom_left_with_margins_on(state.ids.grid, y, x - 5.0)
|
||||
.w_h(
|
||||
// Animation frames depening on timer value from 0.0 to 1.0
|
||||
22.0 * 0.8,
|
||||
if indic_ani <= 0.5 {
|
||||
18.0 * indic_scale
|
||||
} else {
|
||||
23.0 * indic_scale
|
||||
},
|
||||
)
|
||||
.color(Some(Color::Rgba(1.0, 1.0, 1.0, 1.0)))
|
||||
.floating(true)
|
||||
.parent(ui.window)
|
||||
.set(state.ids.indicator, ui);
|
||||
let ind_scale = 0.4;
|
||||
Image::new(self.rot_imgs.indicator_mmap_small.none)
|
||||
.middle_of(state.ids.grid)
|
||||
.w_h(32.0 * ind_scale, 37.0 * ind_scale)
|
||||
.color(Some(Color::Rgba(1.0, 1.0, 1.0, 1.0)))
|
||||
.floating(true)
|
||||
.parent(ui.window)
|
||||
.set(state.ids.indicator, ui);
|
||||
} else {
|
||||
Image::new(self.imgs.mmap_frame_closed)
|
||||
.w_h(100.0 * 2.0, 11.0 * 2.0)
|
||||
@ -186,9 +222,9 @@ impl<'a> Widget for MiniMap<'a> {
|
||||
self.imgs.mmap_closed
|
||||
})
|
||||
.wh(if self.show.mini_map {
|
||||
[100.0 * 0.4; 2]
|
||||
[100.0 * 0.3; 2]
|
||||
} else {
|
||||
[100.0 * 0.2 * zoom; 2]
|
||||
[100.0 * 0.2; 2]
|
||||
})
|
||||
.hover_image(if self.show.mini_map {
|
||||
self.imgs.mmap_open_hover
|
||||
@ -267,7 +303,7 @@ impl<'a> Widget for MiniMap<'a> {
|
||||
state.ids.mmap_frame,
|
||||
if self.show.mini_map { 6.0 } else { 0.0 },
|
||||
)
|
||||
.font_size(if self.show.mini_map { 30 } else { 18 })
|
||||
.font_size(if self.show.mini_map { 20 } else { 18 })
|
||||
.font_id(self.fonts.cyri)
|
||||
.color(TEXT_COLOR)
|
||||
.set(state.ids.mmap_location, ui),
|
||||
|
@ -13,7 +13,7 @@ mod skillbar;
|
||||
mod social;
|
||||
mod spell;
|
||||
|
||||
use crate::{ecs::comp::HpFloaterList, hud::img_ids::ImgsRot};
|
||||
use crate::{ecs::comp::HpFloaterList, hud::img_ids::ImgsRot, ui::img_ids::Rotations};
|
||||
pub use settings_window::ScaleChange;
|
||||
use std::time::Duration;
|
||||
|
||||
@ -46,7 +46,6 @@ use crate::{
|
||||
use client::{Client, Event as ClientEvent};
|
||||
use common::{assets::load_expect, comp, terrain::TerrainChunk, vol::RectRasterableVol};
|
||||
use conrod_core::{
|
||||
image::Id,
|
||||
text::cursor::Index,
|
||||
widget::{self, Button, Image, Rectangle, Text},
|
||||
widget_ids, Color, Colorable, Labelable, Positionable, Sizeable, Widget,
|
||||
@ -307,7 +306,7 @@ impl Show {
|
||||
fn map(&mut self, open: bool) {
|
||||
self.map = open;
|
||||
self.bag = false;
|
||||
self.want_grab = !open;
|
||||
self.want_grab = true;
|
||||
}
|
||||
|
||||
fn character_window(&mut self, open: bool) {
|
||||
@ -431,7 +430,7 @@ impl Show {
|
||||
pub struct Hud {
|
||||
ui: Ui,
|
||||
ids: Ids,
|
||||
world_map: (Id, Vec2<u32>),
|
||||
world_map: (/* Id */ Rotations, Vec2<u32>),
|
||||
imgs: Imgs,
|
||||
item_imgs: ItemImgs,
|
||||
fonts: Fonts,
|
||||
@ -446,7 +445,6 @@ pub struct Hud {
|
||||
force_chat_input: Option<String>,
|
||||
force_chat_cursor: Option<Index>,
|
||||
pulse: f32,
|
||||
zoom: f32,
|
||||
velocity: f32,
|
||||
}
|
||||
|
||||
@ -461,7 +459,7 @@ impl Hud {
|
||||
let ids = Ids::new(ui.id_generator());
|
||||
// Load world map
|
||||
let world_map = (
|
||||
ui.add_graphic(Graphic::Image(client.world_map.0.clone())),
|
||||
ui.add_graphic_with_rotations(Graphic::Image(client.world_map.0.clone())),
|
||||
client.world_map.1,
|
||||
);
|
||||
// Load images.
|
||||
@ -497,7 +495,7 @@ impl Hud {
|
||||
quest: false,
|
||||
spell: false,
|
||||
character_window: false,
|
||||
mini_map: false,
|
||||
mini_map: true,
|
||||
settings_tab: SettingsTab::Interface,
|
||||
social_tab: SocialTab::Online,
|
||||
want_grab: true,
|
||||
@ -509,7 +507,6 @@ impl Hud {
|
||||
force_chat_input: None,
|
||||
force_chat_cursor: None,
|
||||
pulse: 0.0,
|
||||
zoom: 1.0,
|
||||
velocity: 0.0,
|
||||
}
|
||||
}
|
||||
@ -1590,10 +1587,9 @@ impl Hud {
|
||||
&self.show,
|
||||
client,
|
||||
&self.imgs,
|
||||
self.world_map,
|
||||
&self.rot_imgs,
|
||||
&self.world_map,
|
||||
&self.fonts,
|
||||
self.pulse,
|
||||
self.zoom,
|
||||
)
|
||||
.set(self.ids.minimap, ui_widgets)
|
||||
{
|
||||
@ -1864,7 +1860,8 @@ impl Hud {
|
||||
&self.show,
|
||||
client,
|
||||
&self.imgs,
|
||||
self.world_map,
|
||||
&self.rot_imgs,
|
||||
&self.world_map,
|
||||
&self.fonts,
|
||||
self.pulse,
|
||||
self.velocity,
|
||||
|
@ -10,6 +10,7 @@ gfx_defines! {
|
||||
pos: [f32; 2] = "v_pos",
|
||||
uv: [f32; 2] = "v_uv",
|
||||
color: [f32; 4] = "v_color",
|
||||
center: [f32; 2] = "v_center",
|
||||
mode: u32 = "v_mode",
|
||||
}
|
||||
|
||||
@ -55,11 +56,23 @@ pub const MODE_TEXT: u32 = 0;
|
||||
pub const MODE_IMAGE: u32 = 1;
|
||||
/// Ignore `tex` and draw simple, colored 2D geometry.
|
||||
pub const MODE_GEOMETRY: u32 = 2;
|
||||
/// Draw an image from the texture at `tex` in the fragment shader, with the
|
||||
/// source rectangle rotated to face north.
|
||||
///
|
||||
/// FIXME: Make more principled.
|
||||
pub const MODE_IMAGE_SOURCE_NORTH: u32 = 3;
|
||||
/// Draw an image from the texture at `tex` in the fragment shader, with the
|
||||
/// target rectangle rotated to face north.
|
||||
///
|
||||
/// FIXME: Make more principled.
|
||||
pub const MODE_IMAGE_TARGET_NORTH: u32 = 5;
|
||||
|
||||
pub enum Mode {
|
||||
Text,
|
||||
Image,
|
||||
Geometry,
|
||||
ImageSourceNorth,
|
||||
ImageTargetNorth,
|
||||
}
|
||||
|
||||
impl Mode {
|
||||
@ -68,6 +81,8 @@ impl Mode {
|
||||
Mode::Text => MODE_TEXT,
|
||||
Mode::Image => MODE_IMAGE,
|
||||
Mode::Geometry => MODE_GEOMETRY,
|
||||
Mode::ImageSourceNorth => MODE_IMAGE_SOURCE_NORTH,
|
||||
Mode::ImageTargetNorth => MODE_IMAGE_TARGET_NORTH,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -78,10 +93,16 @@ pub fn create_quad(
|
||||
color: Rgba<f32>,
|
||||
mode: Mode,
|
||||
) -> Quad<UiPipeline> {
|
||||
let center = if let Mode::ImageSourceNorth = mode {
|
||||
uv_rect.center().into_array()
|
||||
} else {
|
||||
rect.center().into_array()
|
||||
};
|
||||
let mode_val = mode.value();
|
||||
let v = |pos, uv| Vertex {
|
||||
pos,
|
||||
uv,
|
||||
center,
|
||||
color: color.into_array(),
|
||||
mode: mode_val,
|
||||
};
|
||||
@ -118,10 +139,12 @@ pub fn create_tri(
|
||||
color: Rgba<f32>,
|
||||
mode: Mode,
|
||||
) -> Tri<UiPipeline> {
|
||||
let center = [0.0, 0.0];
|
||||
let mode_val = mode.value();
|
||||
let v = |pos, uv| Vertex {
|
||||
pos,
|
||||
uv,
|
||||
center,
|
||||
color: color.into_array(),
|
||||
mode: mode_val,
|
||||
};
|
||||
|
@ -190,7 +190,7 @@ impl Camera {
|
||||
}
|
||||
|
||||
/// Get the focus position of the camera.
|
||||
pub fn get_focus_pos(&self) -> Vec3<f32> { self.tgt_focus }
|
||||
pub fn get_focus_pos(&self) -> Vec3<f32> { self.focus }
|
||||
|
||||
/// Set the focus position of the camera.
|
||||
pub fn set_focus_pos(&mut self, focus: Vec3<f32>) { self.tgt_focus = focus; }
|
||||
|
@ -6,7 +6,7 @@ pub use renderer::{SampleStrat, Transform};
|
||||
use crate::render::{Renderer, Texture};
|
||||
use dot_vox::DotVoxData;
|
||||
use guillotiere::{size2, SimpleAtlasAllocator};
|
||||
use hashbrown::HashMap;
|
||||
use hashbrown::{hash_map::Entry, HashMap};
|
||||
use image::{DynamicImage, RgbaImage};
|
||||
use log::warn;
|
||||
use pixel_art::resize_pixel_art;
|
||||
@ -26,6 +26,14 @@ pub enum Rotation {
|
||||
Cw90,
|
||||
Cw180,
|
||||
Cw270,
|
||||
/// Orientation of source rectangle that always faces true north.
|
||||
/// Simple hack to get around Conrod not having space for proper
|
||||
/// rotation data (though it should be possible to add in other ways).
|
||||
SourceNorth,
|
||||
/// Orientation of target rectangle that always faces true north.
|
||||
/// Simple hack to get around Conrod not having space for proper
|
||||
/// rotation data (though it should be possible to add in other ways).
|
||||
TargetNorth,
|
||||
}
|
||||
|
||||
/// Images larger than this are stored in individual textures
|
||||
@ -41,7 +49,7 @@ pub struct Id(u32);
|
||||
#[derive(PartialEq, Eq, Hash, Copy, Clone)]
|
||||
pub struct TexId(usize);
|
||||
|
||||
type Parameters = (Id, Vec2<u16>, Aabr<u64>);
|
||||
type Parameters = (Id, Vec2<u16>);
|
||||
type GraphicMap = HashMap<Id, Graphic>;
|
||||
|
||||
enum CacheLoc {
|
||||
@ -130,6 +138,8 @@ impl GraphicCache {
|
||||
self.textures = vec![texture];
|
||||
}
|
||||
|
||||
/// Source rectangle should be from 0 to 1, and represents a bounding box
|
||||
/// for the source image of the graphic.
|
||||
pub fn cache_res(
|
||||
&mut self,
|
||||
renderer: &mut Renderer,
|
||||
@ -137,15 +147,18 @@ impl GraphicCache {
|
||||
dims: Vec2<u16>,
|
||||
source: Aabr<f64>,
|
||||
rotation: Rotation,
|
||||
) -> Option<(Aabr<u16>, TexId)> {
|
||||
) -> Option<(Aabr<f64>, TexId)> {
|
||||
let dims = match rotation {
|
||||
Rotation::Cw90 | Rotation::Cw270 => Vec2::new(dims.y, dims.x),
|
||||
Rotation::None | Rotation::Cw180 => dims,
|
||||
Rotation::SourceNorth => dims,
|
||||
Rotation::TargetNorth => dims,
|
||||
};
|
||||
let key = (graphic_id, dims, source.map(|e| e.to_bits())); // TODO: Replace this with rounded representation of source
|
||||
let key = (graphic_id, dims);
|
||||
|
||||
// Rotate aabr according to requested rotation.
|
||||
let rotated_aabr = |Aabr { min, max }| match rotation {
|
||||
Rotation::None => Aabr { min, max },
|
||||
Rotation::None | Rotation::SourceNorth | Rotation::TargetNorth => Aabr { min, max },
|
||||
Rotation::Cw90 => Aabr {
|
||||
min: Vec2::new(min.x, max.y),
|
||||
max: Vec2::new(max.x, min.y),
|
||||
@ -156,101 +169,115 @@ impl GraphicCache {
|
||||
max: Vec2::new(min.x, max.y),
|
||||
},
|
||||
};
|
||||
// Scale aabr according to provided source rectangle.
|
||||
let scaled_aabr = |aabr: Aabr<_>| {
|
||||
let size: Vec2<_> = aabr.size().into();
|
||||
Aabr {
|
||||
min: size.mul_add(source.min, aabr.min),
|
||||
max: size.mul_add(source.max, aabr.min),
|
||||
}
|
||||
};
|
||||
// Apply all transformations.
|
||||
// TODO: Verify rotation is being applied correctly.
|
||||
let transformed_aabr = |aabr| rotated_aabr(scaled_aabr(aabr));
|
||||
|
||||
if let Some(details) = self.cache_map.get(&key) {
|
||||
let (idx, aabr) = match details.location {
|
||||
CacheLoc::Atlas {
|
||||
atlas_idx, aabr, ..
|
||||
} => (self.atlases[atlas_idx].1, aabr),
|
||||
CacheLoc::Texture { index } => {
|
||||
(index, Aabr {
|
||||
min: Vec2::new(0, 0),
|
||||
// Note texture should always match the cached dimensions
|
||||
max: dims,
|
||||
})
|
||||
},
|
||||
};
|
||||
let details = match self.cache_map.entry(key) {
|
||||
Entry::Occupied(details) => {
|
||||
let details = details.get();
|
||||
let (idx, aabr) = match details.location {
|
||||
CacheLoc::Atlas {
|
||||
atlas_idx, aabr, ..
|
||||
} => (self.atlases[atlas_idx].1, aabr),
|
||||
CacheLoc::Texture { index } => {
|
||||
(index, Aabr {
|
||||
min: Vec2::new(0, 0),
|
||||
// Note texture should always match the cached dimensions
|
||||
max: dims,
|
||||
})
|
||||
},
|
||||
};
|
||||
|
||||
// Check if the cached version has been invalidated by replacing the underlying
|
||||
// graphic
|
||||
if !details.valid {
|
||||
// Create image
|
||||
let image = draw_graphic(&self.graphic_map, graphic_id, dims)?;
|
||||
// Transfer to the gpu
|
||||
upload_image(renderer, aabr, &self.textures[idx], &image);
|
||||
// Check if the cached version has been invalidated by replacing the underlying
|
||||
// graphic
|
||||
if !details.valid {
|
||||
// Create image
|
||||
let image = draw_graphic(&self.graphic_map, graphic_id, dims)?;
|
||||
// Transfer to the gpu
|
||||
upload_image(renderer, aabr, &self.textures[idx], &image);
|
||||
}
|
||||
|
||||
return Some((transformed_aabr(aabr.map(|e| e as f64)), TexId(idx)));
|
||||
},
|
||||
Entry::Vacant(details) => details,
|
||||
};
|
||||
|
||||
// Create image
|
||||
let image = draw_graphic(&self.graphic_map, graphic_id, dims)?;
|
||||
|
||||
// Allocate space on the gpu
|
||||
// Check size of graphic
|
||||
// Graphics over a particular size are sent to their own textures
|
||||
let location = if Vec2::<i32>::from(self.atlases[0].0.size().to_tuple())
|
||||
.map(|e| e as u16)
|
||||
.map2(dims, |a, d| a as f32 * ATLAS_CUTTOFF_FRAC >= d as f32)
|
||||
.reduce_and()
|
||||
{
|
||||
// Fit into an atlas
|
||||
let mut loc = None;
|
||||
for (atlas_idx, (ref mut atlas, _)) in self.atlases.iter_mut().enumerate() {
|
||||
if let Some(rectangle) = atlas.allocate(size2(i32::from(dims.x), i32::from(dims.y)))
|
||||
{
|
||||
let aabr = aabr_from_alloc_rect(rectangle);
|
||||
loc = Some(CacheLoc::Atlas { atlas_idx, aabr });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Some((rotated_aabr(aabr), TexId(idx)))
|
||||
} else {
|
||||
// Create image
|
||||
let image = draw_graphic(&self.graphic_map, graphic_id, dims)?;
|
||||
|
||||
// Allocate space on the gpu
|
||||
// Check size of graphic
|
||||
// Graphics over a particular size are sent to their own textures
|
||||
let location = if Vec2::<i32>::from(self.atlases[0].0.size().to_tuple())
|
||||
.map(|e| e as u16)
|
||||
.map2(dims, |a, d| a as f32 * ATLAS_CUTTOFF_FRAC >= d as f32)
|
||||
.reduce_and()
|
||||
{
|
||||
// Fit into an atlas
|
||||
let mut loc = None;
|
||||
for (atlas_idx, (ref mut atlas, _)) in self.atlases.iter_mut().enumerate() {
|
||||
if let Some(rectangle) =
|
||||
atlas.allocate(size2(i32::from(dims.x), i32::from(dims.y)))
|
||||
{
|
||||
let aabr = aabr_from_alloc_rect(rectangle);
|
||||
loc = Some(CacheLoc::Atlas { atlas_idx, aabr });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
match loc {
|
||||
Some(loc) => loc,
|
||||
// Create a new atlas
|
||||
None => {
|
||||
let (mut atlas, texture) = create_atlas_texture(renderer);
|
||||
let aabr = atlas
|
||||
.allocate(size2(i32::from(dims.x), i32::from(dims.y)))
|
||||
.map(aabr_from_alloc_rect)
|
||||
.unwrap();
|
||||
let tex_idx = self.textures.len();
|
||||
let atlas_idx = self.atlases.len();
|
||||
self.textures.push(texture);
|
||||
self.atlases.push((atlas, tex_idx));
|
||||
CacheLoc::Atlas { atlas_idx, aabr }
|
||||
},
|
||||
}
|
||||
} else {
|
||||
// Create a texture just for this
|
||||
let texture = renderer.create_dynamic_texture(dims).unwrap();
|
||||
let index = self.textures.len();
|
||||
self.textures.push(texture);
|
||||
CacheLoc::Texture { index }
|
||||
};
|
||||
|
||||
let (idx, aabr) = match location {
|
||||
CacheLoc::Atlas {
|
||||
atlas_idx, aabr, ..
|
||||
} => (self.atlases[atlas_idx].1, aabr),
|
||||
CacheLoc::Texture { index } => {
|
||||
(index, Aabr {
|
||||
min: Vec2::new(0, 0),
|
||||
// Note texture should always match the cached dimensions
|
||||
max: dims,
|
||||
})
|
||||
match loc {
|
||||
Some(loc) => loc,
|
||||
// Create a new atlas
|
||||
None => {
|
||||
let (mut atlas, texture) = create_atlas_texture(renderer);
|
||||
let aabr = atlas
|
||||
.allocate(size2(i32::from(dims.x), i32::from(dims.y)))
|
||||
.map(aabr_from_alloc_rect)
|
||||
.unwrap();
|
||||
let tex_idx = self.textures.len();
|
||||
let atlas_idx = self.atlases.len();
|
||||
self.textures.push(texture);
|
||||
self.atlases.push((atlas, tex_idx));
|
||||
CacheLoc::Atlas { atlas_idx, aabr }
|
||||
},
|
||||
};
|
||||
// Upload
|
||||
upload_image(renderer, aabr, &self.textures[idx], &image);
|
||||
// Insert into cached map
|
||||
self.cache_map.insert(key, CachedDetails {
|
||||
location,
|
||||
valid: true,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Create a texture just for this
|
||||
let texture = renderer.create_dynamic_texture(dims).unwrap();
|
||||
let index = self.textures.len();
|
||||
self.textures.push(texture);
|
||||
CacheLoc::Texture { index }
|
||||
};
|
||||
|
||||
Some((rotated_aabr(aabr), TexId(idx)))
|
||||
}
|
||||
let (idx, aabr) = match location {
|
||||
CacheLoc::Atlas {
|
||||
atlas_idx, aabr, ..
|
||||
} => (self.atlases[atlas_idx].1, aabr),
|
||||
CacheLoc::Texture { index } => {
|
||||
(index, Aabr {
|
||||
min: Vec2::new(0, 0),
|
||||
// Note texture should always match the cached dimensions
|
||||
max: dims,
|
||||
})
|
||||
},
|
||||
};
|
||||
// Upload
|
||||
upload_image(renderer, aabr, &self.textures[idx], &image);
|
||||
// Insert into cached map
|
||||
details.insert(CachedDetails {
|
||||
location,
|
||||
valid: true,
|
||||
});
|
||||
|
||||
Some((transformed_aabr(aabr.map(|e| e as f64)), TexId(idx)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,6 +106,8 @@ pub struct Rotations {
|
||||
pub cw90: conrod_core::image::Id,
|
||||
pub cw180: conrod_core::image::Id,
|
||||
pub cw270: conrod_core::image::Id,
|
||||
pub source_north: conrod_core::image::Id,
|
||||
pub target_north: conrod_core::image::Id,
|
||||
}
|
||||
|
||||
/// This macro will automatically load all specified assets, get the
|
||||
|
@ -28,6 +28,7 @@ use crate::{
|
||||
window::Window,
|
||||
Error,
|
||||
};
|
||||
use ::image::GenericImageView;
|
||||
use cache::Cache;
|
||||
use common::{assets, util::srgba_to_linear};
|
||||
use conrod_core::{
|
||||
@ -43,6 +44,7 @@ use conrod_core::{
|
||||
use graphic::{Rotation, TexId};
|
||||
use log::{error, warn};
|
||||
use std::{
|
||||
f32, f64,
|
||||
fs::File,
|
||||
io::{BufReader, Read},
|
||||
ops::Range,
|
||||
@ -172,6 +174,16 @@ impl Ui {
|
||||
cw90: self.image_map.insert((graphic_id, Rotation::Cw90)),
|
||||
cw180: self.image_map.insert((graphic_id, Rotation::Cw180)),
|
||||
cw270: self.image_map.insert((graphic_id, Rotation::Cw270)),
|
||||
// Hacky way to make sure a source rectangle always faces north regardless of player
|
||||
// orientation.
|
||||
// This is an easy way to get around Conrod's lack of rotation data for images (for this
|
||||
// specific use case).
|
||||
source_north: self.image_map.insert((graphic_id, Rotation::SourceNorth)),
|
||||
// Hacky way to make sure a target rectangle always faces north regardless of player
|
||||
// orientation.
|
||||
// This is an easy way to get around Conrod's lack of rotation data for images (for this
|
||||
// specific use case).
|
||||
target_north: self.image_map.insert((graphic_id, Rotation::TargetNorth)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -420,46 +432,88 @@ impl Ui {
|
||||
PrimitiveKind::Image {
|
||||
image_id,
|
||||
color,
|
||||
source_rect: _, // TODO: <-- use this
|
||||
source_rect,
|
||||
} => {
|
||||
let (graphic_id, rotation) = self
|
||||
.image_map
|
||||
.get(&image_id)
|
||||
.expect("Image does not exist in image map");
|
||||
let graphic_cache = self.cache.graphic_cache_mut();
|
||||
|
||||
match graphic_cache.get_graphic(*graphic_id) {
|
||||
Some(Graphic::Blank) | None => continue,
|
||||
_ => {},
|
||||
}
|
||||
let gl_aabr = gl_aabr(rect);
|
||||
let (source_aabr, gl_size) = {
|
||||
// Transform the source rectangle into uv coordinate.
|
||||
// TODO: Make sure this is right. Especially the conversions.
|
||||
let ((uv_l, uv_r, uv_b, uv_t), gl_size) =
|
||||
match graphic_cache.get_graphic(*graphic_id) {
|
||||
Some(Graphic::Blank) | None => continue,
|
||||
Some(Graphic::Image(image)) => {
|
||||
source_rect.and_then(|src_rect| {
|
||||
let (image_w, image_h) = image.dimensions();
|
||||
let (source_w, source_h) = src_rect.w_h();
|
||||
let gl_size = gl_aabr.size();
|
||||
if image_w == 0
|
||||
|| image_h == 0
|
||||
|| source_w < 1.0
|
||||
|| source_h < 1.0
|
||||
|| gl_size.reduce_partial_max() < f32::EPSILON
|
||||
{
|
||||
None
|
||||
} else {
|
||||
// Multiply drawn image size by ratio of original image
|
||||
// size to
|
||||
// source rectangle size (since as the proportion of the
|
||||
// image gets
|
||||
// smaller, the drawn size should get bigger), up to the
|
||||
// actual
|
||||
// size of the original image.
|
||||
let ratio_x = (image_w as f64 / source_w).min(
|
||||
(image_w as f64 / (gl_size.w * half_res.x) as f64)
|
||||
.max(1.0),
|
||||
);
|
||||
let ratio_y = (image_h as f64 / source_h).min(
|
||||
(image_h as f64 / (gl_size.h * half_res.y) as f64)
|
||||
.max(1.0),
|
||||
);
|
||||
let (l, r, b, t) = src_rect.l_r_b_t();
|
||||
Some((
|
||||
(
|
||||
l / image_w as f64, /* * ratio_x*/
|
||||
r / image_w as f64, /* * ratio_x*/
|
||||
b / image_h as f64, /* * ratio_y*/
|
||||
t / image_h as f64, /* * ratio_y*/
|
||||
),
|
||||
Extent2::new(
|
||||
(gl_size.w as f64 * ratio_x) as f32,
|
||||
(gl_size.h as f64 * ratio_y) as f32,
|
||||
),
|
||||
))
|
||||
/* ((l / image_w as f64),
|
||||
(r / image_w as f64),
|
||||
(b / image_h as f64),
|
||||
(t / image_h as f64)) */
|
||||
}
|
||||
})
|
||||
},
|
||||
// No easy way to interpret source_rect for voxels...
|
||||
Some(Graphic::Voxel(..)) => None,
|
||||
}
|
||||
.unwrap_or_else(|| ((0.0, 1.0, 0.0, 1.0), gl_aabr.size()));
|
||||
(
|
||||
Aabr {
|
||||
min: Vec2::new(uv_l, uv_b),
|
||||
max: Vec2::new(uv_r, uv_t),
|
||||
},
|
||||
gl_size,
|
||||
)
|
||||
};
|
||||
|
||||
let color =
|
||||
srgba_to_linear(color.unwrap_or(conrod_core::color::WHITE).to_fsa().into());
|
||||
|
||||
let gl_aabr = gl_aabr(rect);
|
||||
let resolution = Vec2::new(
|
||||
(gl_aabr.size().w * half_res.x).round() as u16,
|
||||
(gl_aabr.size().h * half_res.y).round() as u16,
|
||||
(gl_size.w * half_res.x).round() as u16,
|
||||
(gl_size.h * half_res.y).round() as u16,
|
||||
);
|
||||
// Transform the source rectangle into uv coordinate.
|
||||
// TODO: Make sure this is right.
|
||||
let source_aabr = {
|
||||
let (uv_l, uv_r, uv_b, uv_t) = (0.0, 1.0, 0.0, 1.0);
|
||||
/*match source_rect {
|
||||
Some(src_rect) => {
|
||||
let (l, r, b, t) = src_rect.l_r_b_t();
|
||||
((l / image_w) as f32,
|
||||
(r / image_w) as f32,
|
||||
(b / image_h) as f32,
|
||||
(t / image_h) as f32)
|
||||
}
|
||||
None => (0.0, 1.0, 0.0, 1.0),
|
||||
};*/
|
||||
Aabr {
|
||||
min: Vec2::new(uv_l, uv_b),
|
||||
max: Vec2::new(uv_r, uv_t),
|
||||
}
|
||||
};
|
||||
|
||||
// Cache graphic at particular resolution.
|
||||
let (uv_aabr, tex_id) = match graphic_cache.cache_res(
|
||||
@ -500,7 +554,13 @@ impl Ui {
|
||||
State::Image(_) => {},
|
||||
}
|
||||
|
||||
mesh.push_quad(create_ui_quad(gl_aabr, uv_aabr, color, UiMode::Image));
|
||||
mesh.push_quad(create_ui_quad(gl_aabr, uv_aabr, color, match *rotation {
|
||||
Rotation::None | Rotation::Cw90 | Rotation::Cw180 | Rotation::Cw270 => {
|
||||
UiMode::Image
|
||||
},
|
||||
Rotation::SourceNorth => UiMode::ImageSourceNorth,
|
||||
Rotation::TargetNorth => UiMode::ImageTargetNorth,
|
||||
}));
|
||||
},
|
||||
PrimitiveKind::Text {
|
||||
color,
|
||||
|
@ -239,6 +239,9 @@ impl MapConfig {
|
||||
}
|
||||
}
|
||||
|
||||
let water_color_factor = 2.0;
|
||||
let g_water = 32.0 * water_color_factor;
|
||||
let b_water = 64.0 * water_color_factor;
|
||||
let rgba = match (river_kind, (is_water, true_alt >= true_sea_level)) {
|
||||
(_, (false, _)) | (None, (_, true)) => {
|
||||
let (r, g, b) = (
|
||||
@ -251,7 +254,7 @@ impl MapConfig {
|
||||
0.0
|
||||
})
|
||||
.sqrt(),
|
||||
if is_shaded { 0.2 + (alt * 0.8) } else { alt },
|
||||
if is_shaded { 0.4 + (alt * 0.6) } else { alt },
|
||||
(if is_shaded { alt } else { alt }
|
||||
* if is_humidity {
|
||||
humidity as f64
|
||||
@ -272,17 +275,22 @@ impl MapConfig {
|
||||
},
|
||||
(Some(RiverKind::Ocean), _) => (
|
||||
0,
|
||||
((32.0 - water_depth * 32.0) * 1.0) as u8,
|
||||
((64.0 - water_depth * 64.0) * 1.0) as u8,
|
||||
((g_water - water_depth * g_water) * 1.0) as u8,
|
||||
((b_water - water_depth * b_water) * 1.0) as u8,
|
||||
255,
|
||||
),
|
||||
(Some(RiverKind::River { .. }), _) => (
|
||||
0,
|
||||
g_water as u8 + (alt * (127.0 - g_water)) as u8,
|
||||
b_water as u8 + (alt * (255.0 - b_water)) as u8,
|
||||
255,
|
||||
),
|
||||
(Some(RiverKind::River { .. }), _) => {
|
||||
(0, 32 + (alt * 95.0) as u8, 64 + (alt * 191.0) as u8, 255)
|
||||
},
|
||||
(None, _) | (Some(RiverKind::Lake { .. }), _) => (
|
||||
0,
|
||||
(((32.0 + water_alt * 95.0) + (-water_depth * 32.0)) * 1.0) as u8,
|
||||
(((64.0 + water_alt * 191.0) + (-water_depth * 64.0)) * 1.0) as u8,
|
||||
(((g_water + water_alt * (127.0 - 32.0)) + (-water_depth * g_water)) * 1.0)
|
||||
as u8,
|
||||
(((b_water + water_alt * (255.0 - b_water)) + (-water_depth * b_water))
|
||||
* 1.0) as u8,
|
||||
255,
|
||||
),
|
||||
};
|
||||
|
@ -292,6 +292,9 @@ impl WorldFile {
|
||||
|
||||
pub struct WorldSim {
|
||||
pub seed: u32,
|
||||
/// Maximum height above sea level of any chunk in the map (not including
|
||||
/// post-erosion warping, cliffs, and other things like that).
|
||||
pub max_height: f32,
|
||||
pub(crate) chunks: Vec<SimChunk>,
|
||||
pub(crate) locations: Vec<Location>,
|
||||
|
||||
@ -1288,6 +1291,7 @@ impl WorldSim {
|
||||
|
||||
let mut this = Self {
|
||||
seed,
|
||||
max_height: maxh as f32,
|
||||
chunks,
|
||||
locations: Vec::new(),
|
||||
gen_ctx,
|
||||
@ -1306,7 +1310,11 @@ impl WorldSim {
|
||||
pub fn get_map(&self) -> Vec<u32> {
|
||||
let mut v = vec![0u32; WORLD_SIZE.x * WORLD_SIZE.y];
|
||||
// TODO: Parallelize again.
|
||||
MapConfig::default().generate(&self, |pos, (r, g, b, a)| {
|
||||
MapConfig {
|
||||
gain: self.max_height,
|
||||
..MapConfig::default()
|
||||
}
|
||||
.generate(&self, |pos, (r, g, b, a)| {
|
||||
v[pos.y * WORLD_SIZE.x + pos.x] = u32::from_le_bytes([r, g, b, a]);
|
||||
});
|
||||
v
|
||||
|
Loading…
Reference in New Issue
Block a user