From 93d7c67cdccee9e7611d77f47433ac19b361610c Mon Sep 17 00:00:00 2001 From: Monty Marz Date: Thu, 6 Feb 2020 17:34:32 +0000 Subject: [PATCH] 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. --- CHANGELOG.md | 3 + .../buttons/button_mmap_closed_hover.vox | 4 +- .../buttons/button_mmap_closed_press.vox | 4 +- .../element/buttons/button_mmap_open.vox | 4 +- .../buttons/button_mmap_open_hover.vox | 4 +- .../buttons/button_mmap_open_press.vox | 4 +- .../element/buttons/indicator_mmap_small.vox | 3 + .../voxygen/element/buttons/map_indicator.vox | 3 - .../buttons/min_plus/mmap_button-min.vox | 4 +- .../min_plus/mmap_button-min_hover.vox | 4 +- .../min_plus/mmap_button-min_press.vox | 4 +- .../buttons/min_plus/mmap_button-plus.vox | 4 +- .../min_plus/mmap_button-plus_hover.vox | 4 +- .../min_plus/mmap_button-plus_press.vox | 4 +- assets/voxygen/element/frames/mmap.vox | 4 +- assets/voxygen/shaders/ui-frag.glsl | 3 +- assets/voxygen/shaders/ui-vert.glsl | 19 +- voxygen/src/hud/img_ids.rs | 10 +- voxygen/src/hud/map.rs | 59 +++-- voxygen/src/hud/minimap.rs | 186 +++++++++------ voxygen/src/hud/mod.rs | 21 +- voxygen/src/render/pipelines/ui.rs | 23 ++ voxygen/src/scene/camera.rs | 2 +- voxygen/src/ui/graphic/mod.rs | 215 ++++++++++-------- voxygen/src/ui/img_ids.rs | 2 + voxygen/src/ui/mod.rs | 118 +++++++--- world/src/sim/map.rs | 24 +- world/src/sim/mod.rs | 10 +- 28 files changed, 465 insertions(+), 284 deletions(-) create mode 100644 assets/voxygen/element/buttons/indicator_mmap_small.vox delete mode 100644 assets/voxygen/element/buttons/map_indicator.vox diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bc81b6ee7..e17f69506e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/assets/voxygen/element/buttons/button_mmap_closed_hover.vox b/assets/voxygen/element/buttons/button_mmap_closed_hover.vox index dbddd3ee5e..67c7ff173a 100644 --- a/assets/voxygen/element/buttons/button_mmap_closed_hover.vox +++ b/assets/voxygen/element/buttons/button_mmap_closed_hover.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:94485c82707685beb41300d559f20b1653fc8d12bb8557d86083def88a463ddb -size 45263 +oid sha256:50320cab07079b0af941b8b72ab48d60dfb7b62bc4939c6186ff2915cf27617c +size 56639 diff --git a/assets/voxygen/element/buttons/button_mmap_closed_press.vox b/assets/voxygen/element/buttons/button_mmap_closed_press.vox index b5ffeb35ce..ec5d0def60 100644 --- a/assets/voxygen/element/buttons/button_mmap_closed_press.vox +++ b/assets/voxygen/element/buttons/button_mmap_closed_press.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:407ddfbcd7a4c010f1b34e36fb7c28def185a884a778d8d968f8fbd21ca50bc8 -size 45263 +oid sha256:aefe32fb5d1828435d5e01e1fad7ad55655bf06c45c8c3a3797a73e270d3c637 +size 56639 diff --git a/assets/voxygen/element/buttons/button_mmap_open.vox b/assets/voxygen/element/buttons/button_mmap_open.vox index 2de622cade..f3fce68eae 100644 --- a/assets/voxygen/element/buttons/button_mmap_open.vox +++ b/assets/voxygen/element/buttons/button_mmap_open.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:efe5f34512ed66265a246e7dc25ccd84415fcb9fc5ed6b5d28d9341f4141c787 -size 45263 +oid sha256:30edd32396c41aa161534d25331f8e66c9d3960ac7865b8847b4b089c0854d28 +size 56639 diff --git a/assets/voxygen/element/buttons/button_mmap_open_hover.vox b/assets/voxygen/element/buttons/button_mmap_open_hover.vox index 7a05ce9521..502b754f66 100644 --- a/assets/voxygen/element/buttons/button_mmap_open_hover.vox +++ b/assets/voxygen/element/buttons/button_mmap_open_hover.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:94c4a087445c0cc8aed09fe1e239cba3bb1a7c6814893efb85a78215b064a72e -size 45263 +oid sha256:c5e0e535124dfea41c5fa3cbdb37e0b944bc09c4270357b276bced575342137e +size 56639 diff --git a/assets/voxygen/element/buttons/button_mmap_open_press.vox b/assets/voxygen/element/buttons/button_mmap_open_press.vox index 25d8bd1bcd..ad745adb8e 100644 --- a/assets/voxygen/element/buttons/button_mmap_open_press.vox +++ b/assets/voxygen/element/buttons/button_mmap_open_press.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0af6e7b11bb9cb7ebc6ae900beabee054221bcabf8dbde0d83f1a0b55d77bf12 -size 45263 +oid sha256:cf079403a3062a5fa66fe31eaa651a65de88255c4778dc3f66c580051bcd27c7 +size 56639 diff --git a/assets/voxygen/element/buttons/indicator_mmap_small.vox b/assets/voxygen/element/buttons/indicator_mmap_small.vox new file mode 100644 index 0000000000..0079616acd --- /dev/null +++ b/assets/voxygen/element/buttons/indicator_mmap_small.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:693433aa99787746d40b02be5996748f346434bbaf2fdab194e71be7d9cb5633 +size 60583 diff --git a/assets/voxygen/element/buttons/map_indicator.vox b/assets/voxygen/element/buttons/map_indicator.vox deleted file mode 100644 index d6a7a7f865..0000000000 --- a/assets/voxygen/element/buttons/map_indicator.vox +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ad653e9c283144719a9748b7f5b454cb257f3718ed9a381e0535789e01199b13 -size 56760 diff --git a/assets/voxygen/element/buttons/min_plus/mmap_button-min.vox b/assets/voxygen/element/buttons/min_plus/mmap_button-min.vox index 2d357a2041..4846fc04d0 100644 --- a/assets/voxygen/element/buttons/min_plus/mmap_button-min.vox +++ b/assets/voxygen/element/buttons/min_plus/mmap_button-min.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1c333365527174d741c93b2b76718f36b93d9c095a4069d86fb6709f977ab0a0 -size 1640 +oid sha256:b32bf65b8f205ae1ece1a365cc115080954f81b4606c0ecdadc5348fcdc1a05e +size 58044 diff --git a/assets/voxygen/element/buttons/min_plus/mmap_button-min_hover.vox b/assets/voxygen/element/buttons/min_plus/mmap_button-min_hover.vox index 7aa3bfb619..2d4e5db864 100644 --- a/assets/voxygen/element/buttons/min_plus/mmap_button-min_hover.vox +++ b/assets/voxygen/element/buttons/min_plus/mmap_button-min_hover.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3b7dba6b97ae900053f4b65c82964bf9097af87ef1860ae773e12b6008f6808a -size 1640 +oid sha256:15d0cf0a74d08e6654d7afcbc9626089bafc83c499c75d77693867e5f3761835 +size 58044 diff --git a/assets/voxygen/element/buttons/min_plus/mmap_button-min_press.vox b/assets/voxygen/element/buttons/min_plus/mmap_button-min_press.vox index 2da392109a..7c2d8b6e52 100644 --- a/assets/voxygen/element/buttons/min_plus/mmap_button-min_press.vox +++ b/assets/voxygen/element/buttons/min_plus/mmap_button-min_press.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5c4e5b2f0c0a612025fdfc85c968a090ab635e7c51b56ec464c3c2855ccd25d3 -size 1624 +oid sha256:8f15fefed88aa5e069da1d496c92730cd3531ee81907450e301f81bc2ed03a7e +size 3560 diff --git a/assets/voxygen/element/buttons/min_plus/mmap_button-plus.vox b/assets/voxygen/element/buttons/min_plus/mmap_button-plus.vox index 85ba1d2f1a..9503ce5391 100644 --- a/assets/voxygen/element/buttons/min_plus/mmap_button-plus.vox +++ b/assets/voxygen/element/buttons/min_plus/mmap_button-plus.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f1c9f4927664cc47d6b28d6962c15c5414ff87dcc4734cb04a4f824d69253d41 -size 1656 +oid sha256:d6e5b5a9f78f8733a9e32f5b97a7d8f205ea157e91a2188eb47ccc8e0384aaa5 +size 58092 diff --git a/assets/voxygen/element/buttons/min_plus/mmap_button-plus_hover.vox b/assets/voxygen/element/buttons/min_plus/mmap_button-plus_hover.vox index 05db19fa1a..4003eb833c 100644 --- a/assets/voxygen/element/buttons/min_plus/mmap_button-plus_hover.vox +++ b/assets/voxygen/element/buttons/min_plus/mmap_button-plus_hover.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ea0a6a621d1c9d1b44aaddb16a21a1711ba4f5e9283f3bb8f66055d414e6b641 -size 1656 +oid sha256:b7fcb6c6f2c6299fffec7569bbcb166b97078a185bd66f466754142c93b9d2b1 +size 58092 diff --git a/assets/voxygen/element/buttons/min_plus/mmap_button-plus_press.vox b/assets/voxygen/element/buttons/min_plus/mmap_button-plus_press.vox index c61033c8a7..4ed8343da5 100644 --- a/assets/voxygen/element/buttons/min_plus/mmap_button-plus_press.vox +++ b/assets/voxygen/element/buttons/min_plus/mmap_button-plus_press.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:15f28c6f1b7ae17aaf6766ec036f9cc837c74715ea4beeb242b7d69efb92edae -size 1608 +oid sha256:68463cf14fa559d584fcd49ebde24c9af724fb25724541e73b13d796382aea01 +size 58092 diff --git a/assets/voxygen/element/frames/mmap.vox b/assets/voxygen/element/frames/mmap.vox index 6b69ee72f1..2ad34e875c 100644 --- a/assets/voxygen/element/frames/mmap.vox +++ b/assets/voxygen/element/frames/mmap.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cd889ad0b5c2fc8244de776e8d87988a0b19f94c8b9475063379c8adf64dc8ae -size 176060 +oid sha256:2146289fd08e72685f2607c7e759077f1efa35245f9fbe389557b19cf32e7b6b +size 176344 diff --git a/assets/voxygen/shaders/ui-frag.glsl b/assets/voxygen/shaders/ui-frag.glsl index 2d77dd3ef7..a0c7e99904 100644 --- a/assets/voxygen/shaders/ui-frag.glsl +++ b/assets/voxygen/shaders/ui-frag.glsl @@ -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)) { diff --git a/assets/voxygen/shaders/ui-vert.glsl b/assets/voxygen/shaders/ui-vert.glsl index d583e30220..57d7230d6b 100644 --- a/assets/voxygen/shaders/ui-vert.glsl +++ b/assets/voxygen/shaders/ui-vert.glsl @@ -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; diff --git a/voxygen/src/hud/img_ids.rs b/voxygen/src/hud/img_ids.rs index 84a9610ed1..40720c90dc 100644 --- a/voxygen/src/hud/img_ids.rs +++ b/voxygen/src/hud/img_ids.rs @@ -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", + +////////////////////////////////////////////////////////////////////////////////////////////////////// + + + + // 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", diff --git a/voxygen/src/hud/map.rs b/voxygen/src/hud/map.rs index 662d004ccc..0ce7691198 100644 --- a/voxygen/src/hud/map.rs +++ b/voxygen/src/hud/map.rs @@ -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), + world_map: &'a (img_ids::Rotations, Vec2), 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), + rot_imgs: &'a ImgsRot, + world_map: &'a (img_ids::Rotations, Vec2), 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 } diff --git a/voxygen/src/hud/minimap.rs b/voxygen/src/hud/minimap.rs index fc196c6e5b..259325f178 100644 --- a/voxygen/src/hud/minimap.rs +++ b/voxygen/src/hud/minimap.rs @@ -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), + rot_imgs: &'a ImgsRot, + world_map: &'a (img_ids::Rotations, Vec2), 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), + rot_imgs: &'a ImgsRot, + world_map: &'a (img_ids::Rotations, Vec2), 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, 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::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), diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 1a16e2c2d8..2c9f442e1d 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -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), + world_map: (/* Id */ Rotations, Vec2), imgs: Imgs, item_imgs: ItemImgs, fonts: Fonts, @@ -446,7 +445,6 @@ pub struct Hud { force_chat_input: Option, force_chat_cursor: Option, 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, diff --git a/voxygen/src/render/pipelines/ui.rs b/voxygen/src/render/pipelines/ui.rs index 6f3ab102ea..35ba91bb86 100644 --- a/voxygen/src/render/pipelines/ui.rs +++ b/voxygen/src/render/pipelines/ui.rs @@ -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, mode: Mode, ) -> Quad { + 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, mode: Mode, ) -> Tri { + 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, }; diff --git a/voxygen/src/scene/camera.rs b/voxygen/src/scene/camera.rs index d35a4c240b..a0d0d59e54 100644 --- a/voxygen/src/scene/camera.rs +++ b/voxygen/src/scene/camera.rs @@ -190,7 +190,7 @@ impl Camera { } /// Get the focus position of the camera. - pub fn get_focus_pos(&self) -> Vec3 { self.tgt_focus } + pub fn get_focus_pos(&self) -> Vec3 { self.focus } /// Set the focus position of the camera. pub fn set_focus_pos(&mut self, focus: Vec3) { self.tgt_focus = focus; } diff --git a/voxygen/src/ui/graphic/mod.rs b/voxygen/src/ui/graphic/mod.rs index 3fc704b30a..f1431aff08 100644 --- a/voxygen/src/ui/graphic/mod.rs +++ b/voxygen/src/ui/graphic/mod.rs @@ -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, Aabr); +type Parameters = (Id, Vec2); type GraphicMap = HashMap; 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, source: Aabr, rotation: Rotation, - ) -> Option<(Aabr, TexId)> { + ) -> Option<(Aabr, 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::::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::::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))) } } diff --git a/voxygen/src/ui/img_ids.rs b/voxygen/src/ui/img_ids.rs index bf18a99ed8..f3cfc0f65f 100644 --- a/voxygen/src/ui/img_ids.rs +++ b/voxygen/src/ui/img_ids.rs @@ -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 diff --git a/voxygen/src/ui/mod.rs b/voxygen/src/ui/mod.rs index 598040080d..a384c77078 100644 --- a/voxygen/src/ui/mod.rs +++ b/voxygen/src/ui/mod.rs @@ -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, diff --git a/world/src/sim/map.rs b/world/src/sim/map.rs index 5737c8370c..0707abd0d6 100644 --- a/world/src/sim/map.rs +++ b/world/src/sim/map.rs @@ -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, ), }; diff --git a/world/src/sim/mod.rs b/world/src/sim/mod.rs index 594e158696..ea945ae27a 100644 --- a/world/src/sim/mod.rs +++ b/world/src/sim/mod.rs @@ -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, pub(crate) locations: Vec, @@ -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 { 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