Color mode and HUD colors UI options

This commit is contained in:
Joshua Barretto 2020-11-24 21:37:21 +00:00
parent 925885cc2b
commit ea77d855ee
11 changed files with 225 additions and 32 deletions

View File

@ -84,7 +84,7 @@
"common.video_settings": "Graphics Settings",
"common.sound_settings": "Sound Settings",
"common.language_settings": "Language Settings",
"common.accessiblity_settings": "Accessiblity Settings",
"common.accessibility_settings": "Accessibility Settings",
// Message when connection to the server is lost
"common.connection_lost": r#"Connection lost!
@ -380,6 +380,16 @@ magically infused items?"#,
"hud.settings.unbound": "None",
"hud.settings.reset_keybinds": "Reset to Defaults",
"hud.settings.color_mode": "Color Mode",
"hud.settings.color_mode.none": "None",
"hud.settings.color_mode.protanopia": "Protanopia",
"hud.settings.color_mode.deuteranopia": "Deuteranopia",
"hud.settings.color_mode.tritanopia": "Tritanopia",
"hud.settings.hud_colors": "HUD Colors",
"hud.settings.hud_colors.none": "None",
"hud.settings.hud_colors.high_contrast": "High Contrast",
"hud.settings.hud_colors.color_deficiency": "Color Deficiency",
"hud.social": "Other Players",
"hud.social.online": "Online:",
"hud.social.friends": "Friends",
@ -419,7 +429,7 @@ magically infused items?"#,
"hud.map.difficulty": "Difficulty",
"hud.map.towns": "Towns",
"hud.map.castles": "Castles",
"hud.map.dungeons": "Dungeons",
"hud.map.dungeons": "Dungeons",
"hud.map.caves": "Caves",
"hud.map.cave": "Cave",
"hud.map.town": "Town",

View File

@ -191,28 +191,26 @@ vec3 correct(vec3 rgb, vec3 dlms) {
return rgb + correction;
}
#define COLOR_NONE 0
#define COLOR_PROTANOPIA 1
#define COLOR_DEUTERANOPIA 2
#define COLOR_TRITANOPIA 3
#define COLOR_CORRECTION COLOR_NONE
#define COLOR_MODE_NONE 0
#define COLOR_MODE_PROTANOPIA 1
#define COLOR_MODE_DEUTERANOPIA 2
#define COLOR_MODE_TRITANOPIA 3
vec3 color_correction(vec3 rgb) {
vec3 lms = lms_color(rgb);
#if (COLOR_CORRECTION == COLOR_PROTANOPIA)
#if (COLOR_MODE == COLOR_MODE_PROTANOPIA)
vec3 rgb_new = correct(rgb, vec3(
0.0 * lms.r + 2.02344 * lms.g + -2.52581 * lms.b,
0.0 * lms.r + 1.0 * lms.g + 0.0 * lms.b,
0.0 * lms.r + 0.0 * lms.g + 1.0 * lms.b
));
#elif (COLOR_CORRECTION == COLOR_DEUTERANOPIA)
#elif (COLOR_MODE == COLOR_MODE_DEUTERANOPIA)
vec3 rgb_new = correct(rgb, vec3(
1.0 * lms.r + 0.0 * lms.g + 0.0 * lms.b,
0.494207 * lms.r + 0.0 * lms.g + 1.24827 * lms.b,
0.0 * lms.r + 0.0 * lms.g + 1.0 * lms.b
));
#elif (COLOR_CORRECTION == COLOR_TRITANOPIA)
#elif (COLOR_MODE == COLOR_MODE_TRITANOPIA)
vec3 rgb_new = correct(rgb, vec3(
1.0 * lms.r + 0.0 * lms.g + 0.0 * lms.b,
0.0 * lms.r + 1.0 * lms.g + 0.0 * lms.b,

View File

@ -1,7 +1,7 @@
use super::{
img_ids::{Imgs, ImgsRot},
Show, BLACK, BUFF_COLOR, DEBUFF_COLOR, ERROR_COLOR, GROUP_COLOR, HP_COLOR, KILL_COLOR,
LOW_HP_COLOR, STAMINA_COLOR, TEXT_COLOR, TEXT_COLOR_GREY, UI_HIGHLIGHT_0, UI_MAIN,
Show, BLACK, BUFF_COLOR, DEBUFF_COLOR, ERROR_COLOR, GROUP_COLOR, KILL_COLOR, LOW_HP_COLOR,
STAMINA_COLOR, TEXT_COLOR, TEXT_COLOR_GREY, UI_HIGHLIGHT_0, UI_MAIN,
};
use crate::{
@ -362,7 +362,7 @@ impl<'a> Widget for Group<'a> {
let health_col = match (health_perc * 100.0) as u8 {
0..=20 => crit_hp_color,
21..=40 => LOW_HP_COLOR,
_ => HP_COLOR,
_ => self.settings.accessibility.hud_colors.health_color(),
};
// Don't show panel for the player!
// Panel BG

View File

@ -49,6 +49,7 @@ use crate::{
i18n::{i18n_asset_key, LanguageMetadata, Localization},
render::{Consts, Globals, RenderMode, Renderer},
scene::camera::{self, Camera},
settings::HudColors,
ui::{fonts::Fonts, img_ids::Rotations, slot, Graphic, Ingameable, ScaleMode, Ui},
window::{Event as WinEvent, FullScreenSettings, GameInput},
GlobalState,
@ -93,7 +94,7 @@ const TEXT_COLOR_3: Color = Color::Rgba(1.0, 1.0, 1.0, 0.1);
const TEXT_BIND_CONFLICT_COLOR: Color = Color::Rgba(1.0, 0.0, 0.0, 1.0);
const BLACK: Color = Color::Rgba(0.0, 0.0, 0.0, 1.0);
//const BG_COLOR: Color = Color::Rgba(1.0, 1.0, 1.0, 0.8);
const HP_COLOR: Color = Color::Rgba(0.33, 0.63, 0.0, 1.0);
//const HP_COLOR: Color = Color::Rgba(0.33, 0.63, 0.0, 1.0);
const LOW_HP_COLOR: Color = Color::Rgba(0.93, 0.59, 0.03, 1.0);
const CRITICAL_HP_COLOR: Color = Color::Rgba(0.79, 0.19, 0.17, 1.0);
const STAMINA_COLOR: Color = Color::Rgba(0.29, 0.62, 0.75, 0.9);
@ -163,6 +164,16 @@ const NAMETAG_DMG_RANGE: f32 = 120.0;
/// Range to display speech-bubbles at
const SPEECH_BUBBLE_RANGE: f32 = NAMETAG_RANGE;
impl HudColors {
pub fn health_color(&self) -> Color {
match self {
HudColors::Default => Color::Rgba(0.33, 0.63, 0.0, 1.0),
HudColors::HighContrast => Color::Rgba(1.0, 1.0, 1.0, 1.0),
HudColors::ColorDeficiency => Color::Rgba(0.0, 0.3, 1.0, 1.0),
}
}
}
widget_ids! {
struct Ids {
// Crosshair
@ -365,6 +376,7 @@ pub enum Event {
ChangeRenderMode(Box<RenderMode>),
ChangeAutoWalkBehavior(PressBehavior),
ChangeStopAutoWalkOnInput(bool),
ChangeHudColors(HudColors),
CraftRecipe(String),
InviteMember(common::sync::Uid),
AcceptInvite,
@ -1261,6 +1273,7 @@ impl Hud {
// Speech bubble, name, level, and hp bars
overhead::Overhead::new(
&global_state,
info,
bubble,
own_level,
@ -2193,6 +2206,9 @@ impl Hud {
settings_window::Event::ChangeStopAutoWalkOnInput(state) => {
events.push(Event::ChangeStopAutoWalkOnInput(state));
},
settings_window::Event::ChangeHudColors(hud_colors) => {
events.push(Event::ChangeHudColors(hud_colors));
},
}
}
}

View File

@ -1,5 +1,5 @@
use super::{
img_ids::Imgs, DEFAULT_NPC, FACTION_COLOR, GROUP_COLOR, GROUP_MEMBER, HP_COLOR, LOW_HP_COLOR,
img_ids::Imgs, DEFAULT_NPC, FACTION_COLOR, GROUP_COLOR, GROUP_MEMBER, LOW_HP_COLOR,
REGION_COLOR, SAY_COLOR, STAMINA_COLOR, TELL_COLOR, TEXT_BG, TEXT_COLOR,
};
use crate::{
@ -7,6 +7,7 @@ use crate::{
i18n::Localization,
settings::GameplaySettings,
ui::{fonts::Fonts, Ingameable},
GlobalState,
};
use common::comp::{BuffKind, Buffs, Energy, Health, SpeechBubble, SpeechBubbleType, Stats};
use conrod_core::{
@ -70,6 +71,7 @@ pub fn should_show_healthbar(health: &Health) -> bool { health.current() != heal
/// (Speech bubble, Name, Level, HP/energy bars, etc.)
#[derive(WidgetCommon)]
pub struct Overhead<'a> {
global_state: &'a GlobalState,
info: Option<Info<'a>>,
bubble: Option<&'a SpeechBubble>,
own_level: u32,
@ -87,6 +89,7 @@ pub struct Overhead<'a> {
impl<'a> Overhead<'a> {
#[allow(clippy::too_many_arguments)] // TODO: Pending review in #587
pub fn new(
global_state: &'a GlobalState,
info: Option<Info<'a>>,
bubble: Option<&'a SpeechBubble>,
own_level: u32,
@ -98,6 +101,7 @@ impl<'a> Overhead<'a> {
fonts: &'a Fonts,
) -> Self {
Self {
global_state,
info,
bubble,
own_level,
@ -330,7 +334,11 @@ impl<'a> Widget for Overhead<'a> {
} else if hp_percentage <= 50.0 {
LOW_HP_COLOR
} else {
HP_COLOR
self.global_state
.settings
.accessibility
.hud_colors
.health_color()
}))
.parent(id)
.set(state.ids.health_bar, ui);

View File

@ -1,15 +1,16 @@
use super::{
img_ids::Imgs, BarNumbers, CrosshairType, PressBehavior, ShortcutNumbers, Show,
CRITICAL_HP_COLOR, ERROR_COLOR, HP_COLOR, LOW_HP_COLOR, MENU_BG, STAMINA_COLOR,
TEXT_BIND_CONFLICT_COLOR, TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
CRITICAL_HP_COLOR, ERROR_COLOR, LOW_HP_COLOR, MENU_BG, STAMINA_COLOR, TEXT_BIND_CONFLICT_COLOR,
TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
};
use crate::{
hud::BuffPosition,
i18n::{list_localizations, LanguageMetadata, Localization},
render::{
AaMode, CloudMode, FluidMode, LightingMode, RenderMode, ShadowMapMode, ShadowMode,
UpscaleMode,
AaMode, CloudMode, ColorMode, FluidMode, LightingMode, RenderMode, ShadowMapMode,
ShadowMode, UpscaleMode,
},
settings::HudColors,
ui::{fonts::Fonts, ImageSlider, ScaleMode, ToggleButton},
window::{FullScreenSettings, FullscreenMode, GameInput},
GlobalState,
@ -219,6 +220,11 @@ widget_ids! {
auto_walk_behavior_list,
stop_auto_walk_on_input_button,
stop_auto_walk_on_input_label,
//
color_mode_text,
color_mode_list,
hud_colors_text,
hud_colors_list,
}
}
@ -315,6 +321,7 @@ pub enum Event {
ChangeFreeLookBehavior(PressBehavior),
ChangeAutoWalkBehavior(PressBehavior),
ChangeStopAutoWalkOnInput(bool),
ChangeHudColors(HudColors),
}
pub enum ScaleChange {
@ -393,7 +400,9 @@ impl<'a> Widget for SettingsWindow<'a> {
SettingsTab::Video => self.localized_strings.get("common.video_settings"),
SettingsTab::Sound => self.localized_strings.get("common.sound_settings"),
SettingsTab::Lang => self.localized_strings.get("common.language_settings"),
SettingsTab::Accessibility => self.localized_strings.get("common.accessiblity_settings"),
SettingsTab::Accessibility => {
self.localized_strings.get("common.accessibility_settings")
},
})
.mid_top_with_margin_on(state.ids.frame, 3.0)
.font_id(self.fonts.cyri.conrod_id)
@ -1723,7 +1732,12 @@ impl<'a> Widget for SettingsWindow<'a> {
let fps_col = match self.fps as i32 {
0..=14 => CRITICAL_HP_COLOR,
15..=29 => LOW_HP_COLOR,
30..=50 => HP_COLOR,
30..=50 => self
.global_state
.settings
.accessibility
.hud_colors
.health_color(),
_ => STAMINA_COLOR,
};
Text::new(&format!("FPS: {:.0}", self.fps))
@ -2125,7 +2139,7 @@ impl<'a> Widget for SettingsWindow<'a> {
// Get which upscale factor is currently active
let selected = upscale_factors
.iter()
.position(|factor| (*factor - render_mode.upscale_mode.factor).abs() < 0.001);
.position(|factor| (*factor - render_mode.upscale.factor).abs() < 0.001);
if let Some(clicked) = DropDownList::new(
&upscale_factors
@ -2142,7 +2156,7 @@ impl<'a> Widget for SettingsWindow<'a> {
.set(state.ids.upscale_factor_list, ui)
{
events.push(Event::ChangeRenderMode(Box::new(RenderMode {
upscale_mode: UpscaleMode {
upscale: UpscaleMode {
factor: upscale_factors[clicked],
},
..render_mode.clone()
@ -2852,7 +2866,92 @@ impl<'a> Widget for SettingsWindow<'a> {
}
if let SettingsTab::Accessibility = self.show.settings_tab {
// ADD STUFF HERE
let render_mode = &self.global_state.settings.graphics.render_mode;
// Color mode
Text::new(&self.localized_strings.get("hud.settings.color_mode"))
.top_left_with_margins_on(state.ids.settings_content, 10.0, 10.0)
.font_size(self.fonts.cyri.scale(14))
.font_id(self.fonts.cyri.conrod_id)
.color(TEXT_COLOR)
.set(state.ids.color_mode_text, ui);
let mode_list = [
ColorMode::None,
ColorMode::Protanopia,
ColorMode::Deuteranopia,
ColorMode::Tritanopia,
];
let mode_label_list = [
&self.localized_strings.get("hud.settings.color_mode.none"),
&self
.localized_strings
.get("hud.settings.color_mode.protanopia"),
&self
.localized_strings
.get("hud.settings.color_mode.deuteranopia"),
&self
.localized_strings
.get("hud.settings.color_mode.tritanopia"),
];
// Get which color mode is currently active
let selected = mode_list.iter().position(|x| *x == render_mode.color);
if let Some(clicked) = DropDownList::new(&mode_label_list, selected)
.w_h(400.0, 22.0)
.color(MENU_BG)
.label_color(TEXT_COLOR)
.label_font_id(self.fonts.cyri.conrod_id)
.down_from(state.ids.color_mode_text, 8.0)
.set(state.ids.color_mode_list, ui)
{
events.push(Event::ChangeRenderMode(Box::new(RenderMode {
color: mode_list[clicked],
..render_mode.clone()
})));
}
let accessibility = &self.global_state.settings.accessibility;
// HUD colors
Text::new(&self.localized_strings.get("hud.settings.hud_colors"))
.down_from(state.ids.color_mode_list, 8.0)
.font_size(self.fonts.cyri.scale(14))
.font_id(self.fonts.cyri.conrod_id)
.color(TEXT_COLOR)
.set(state.ids.hud_colors_text, ui);
let mode_list = [
HudColors::Default,
HudColors::HighContrast,
HudColors::ColorDeficiency,
];
let mode_label_list = [
&self.localized_strings.get("hud.settings.hud_colors.none"),
&self
.localized_strings
.get("hud.settings.hud_colors.high_contrast"),
&self
.localized_strings
.get("hud.settings.hud_colors.color_deficiency"),
];
// Get which HUD colors are currently active
let selected = mode_list
.iter()
.position(|x| *x == accessibility.hud_colors);
if let Some(clicked) = DropDownList::new(&mode_label_list, selected)
.w_h(400.0, 22.0)
.color(MENU_BG)
.label_color(TEXT_COLOR)
.label_font_id(self.fonts.cyri.conrod_id)
.down_from(state.ids.hud_colors_text, 8.0)
.set(state.ids.hud_colors_list, ui)
{
events.push(Event::ChangeHudColors(mode_list[clicked]));
}
};
events
}

View File

@ -2,7 +2,7 @@ use super::{
hotbar,
img_ids::{Imgs, ImgsRot},
item_imgs::ItemImgs,
slots, BarNumbers, ShortcutNumbers, Show, BLACK, CRITICAL_HP_COLOR, HP_COLOR, LOW_HP_COLOR,
slots, BarNumbers, ShortcutNumbers, Show, BLACK, CRITICAL_HP_COLOR, LOW_HP_COLOR,
STAMINA_COLOR, TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN, XP_COLOR,
};
use crate::{
@ -378,7 +378,12 @@ impl<'a> Widget for Skillbar<'a> {
let health_col = match hp_percentage as u8 {
0..=20 => crit_hp_color,
21..=40 => LOW_HP_COLOR,
_ => HP_COLOR,
_ => self
.global_state
.settings
.accessibility
.hud_colors
.health_color(),
};
// Content
Image::new(self.imgs.bar_content)

View File

@ -240,6 +240,23 @@ impl ShadowMode {
pub fn is_map(&self) -> bool { matches!(self, Self::Map(_)) }
}
/// Shadow modes
#[derive(PartialEq, Clone, Copy, Debug, Serialize, Deserialize)]
pub enum ColorMode {
/// For people with missing/defective L cone cells (red)
Protanopia,
/// For people with missing/defective M cone cells (green)
Deuteranopia,
/// For people with missing/defective S cone cells (blue)
Tritanopia,
#[serde(other)]
None,
}
impl Default for ColorMode {
fn default() -> Self { ColorMode::None }
}
/// Upscale mode settings.
#[derive(PartialEq, Clone, Copy, Debug, Serialize, Deserialize)]
pub struct UpscaleMode {
@ -260,5 +277,6 @@ pub struct RenderMode {
pub fluid: FluidMode,
pub lighting: LightingMode,
pub shadow: ShadowMode,
pub upscale_mode: UpscaleMode,
pub upscale: UpscaleMode,
pub color: ColorMode,
}

View File

@ -9,8 +9,8 @@ use super::{
ui, GlobalModel, Globals,
},
texture::Texture,
AaMode, CloudMode, FilterMethod, FluidMode, LightingMode, Pipeline, RenderError, RenderMode,
ShadowMapMode, ShadowMode, WrapMode,
AaMode, CloudMode, ColorMode, FilterMethod, FluidMode, LightingMode, Pipeline, RenderError,
RenderMode, ShadowMapMode, ShadowMode, WrapMode,
};
use common::{
assets::{self, watch::ReloadIndicator, Asset},
@ -441,7 +441,7 @@ impl Renderer {
RenderError,
> {
let upscaled = Vec2::from(size)
.map(|e: u16| (e as f32 * mode.upscale_mode.factor) as u16)
.map(|e: u16| (e as f32 * mode.upscale.factor) as u16)
.into_tuple();
let kind = match mode.aa {
AaMode::None | AaMode::Fxaa => {
@ -1821,6 +1821,7 @@ fn create_pipelines(
#define CLOUD_MODE {}
#define LIGHTING_ALGORITHM {}
#define SHADOW_MODE {}
#define COLOR_MODE {}
"#,
constants,
@ -1848,6 +1849,12 @@ fn create_pipelines(
ShadowMode::Map(_) if has_shadow_views => "SHADOW_MODE_MAP",
ShadowMode::Cheap | ShadowMode::Map(_) => "SHADOW_MODE_CHEAP",
},
match mode.color {
ColorMode::None => "COLOR_MODE_NONE",
ColorMode::Protanopia => "COLOR_MODE_PROTANOPIA",
ColorMode::Deuteranopia => "COLOR_MODE_DEUTERANOPIA",
ColorMode::Tritanopia => "COLOR_MODE_TRITANOPIA",
},
);
let anti_alias = Glsl::load_watched(

View File

@ -1053,6 +1053,10 @@ impl PlayState for SessionState {
HudEvent::ChangeStopAutoWalkOnInput(state) => {
global_state.settings.gameplay.stop_auto_walk_on_input = state;
},
HudEvent::ChangeHudColors(hud_colors) => {
global_state.settings.accessibility.hud_colors = hud_colors;
global_state.settings.save_to_file_warn();
},
HudEvent::CraftRecipe(r) => {
self.client.borrow_mut().craft_recipe(&r);
},

View File

@ -715,6 +715,32 @@ impl Default for LanguageSettings {
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub enum HudColors {
HighContrast,
ColorDeficiency,
#[serde(other)]
Default,
}
impl Default for HudColors {
fn default() -> Self { HudColors::Default }
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(default)]
pub struct AccessibilitySettings {
pub hud_colors: HudColors,
}
impl Default for AccessibilitySettings {
fn default() -> Self {
Self {
hud_colors: HudColors::Default,
}
}
}
/// `Settings` contains everything that can be configured in the settings.ron
/// file.
#[derive(Clone, Debug, Serialize, Deserialize)]
@ -733,6 +759,7 @@ pub struct Settings {
pub language: LanguageSettings,
pub screenshots_path: PathBuf,
pub controller: GamepadSettings,
pub accessibility: AccessibilitySettings,
}
impl Default for Settings {
@ -767,6 +794,7 @@ impl Default for Settings {
language: LanguageSettings::default(),
screenshots_path,
controller: GamepadSettings::default(),
accessibility: AccessibilitySettings::default(),
}
}
}