Skip to content

Commit

Permalink
feature: Let's start scaling when display tweaks is active (#118)
Browse files Browse the repository at this point in the history
We now sneak a peek at the DisplayTweaks settings if we can find them,
and adjust our sizes to account for any scaling or upscaling done
behind Imgui's back.

If the window is downscaled, we include that in the layout's global
scaling when flattening. If it's being upscaled afterward, we
downscale twice to stay at a reasonable size. I do not think upscaling
looks good, but at least everything is in the right place now.

Anchors specified via x & y coordinates are not affected by this
scaling.
  • Loading branch information
ceejbot authored Jan 19, 2024
1 parent 073915c commit 503f80b
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 70 deletions.
81 changes: 80 additions & 1 deletion src/controller/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! validation and some translation from older versions, but this file is
//! otherwise all fairly predictable.
use std::sync::Mutex;
use std::{path::Path, sync::Mutex};

use eyre::Result;
use ini::Ini;
Expand Down Expand Up @@ -131,6 +131,9 @@ pub struct UserSettings {
equip_sets_unequip: bool,
/// The identifier for the mod in SKSE cosaves. Defaults to SOLS.
skse_identifier: String,

/// Settings we need from DisplayTweaks, if it exists
display_tweaks: DisplayTweaks,
}

impl Default for UserSettings {
Expand Down Expand Up @@ -172,6 +175,7 @@ impl Default for UserSettings {
colorize_icons: true,
equip_sets_unequip: true,
skse_identifier: "SOLS".to_string(),
display_tweaks: DisplayTweaks::default(),
}
}
}
Expand Down Expand Up @@ -286,6 +290,8 @@ impl UserSettings {
self.equip_sets_unequip =
read_from_ini(self.equip_sets_unequip, "bEquipSetsUnequip", options);

self.display_tweaks.read_ini();

Ok(())
}

Expand Down Expand Up @@ -470,6 +476,14 @@ impl UserSettings {
.expect("You must provide exactly four characters as the mod identifier string.");
u32::from_le_bytes(slice)
}

pub fn is_upscaling(&self) -> bool {
self.display_tweaks.upscaling()
}

pub fn resolution_scale(&self) -> f64 {
self.display_tweaks.scale()
}
}

/// Generic for reading a typed value from the ini structure.
Expand Down Expand Up @@ -607,6 +621,17 @@ impl FromIniStr for f32 {
}
}
}

impl FromIniStr for f64 {
fn from_ini(value: &str) -> Option<Self> {
if let Ok(v) = value.parse::<f64>() {
Some(v)
} else {
None
}
}
}

impl FromIniStr for String {
fn from_ini(value: &str) -> Option<Self> {
Some(value.to_string())
Expand Down Expand Up @@ -719,6 +744,60 @@ impl std::fmt::Display for UserSettings {
}
}

#[derive(Debug, Clone)]
struct DisplayTweaks {
scale: f64,
upscaling: bool,
}

impl DisplayTweaks {
/// Get the resolution scale, DisplayTweaks-aware.
pub fn scale(&self) -> f64 {
self.scale
}

pub fn upscaling(&self) -> bool {
self.upscaling
}

/// Pluck scaling settings from the display tweaks ini.
pub fn read_ini(&mut self) {
let fpath = std::path::Path::new("Data/SKSE/Plugins/SSEDisplayTweaks.ini");
self.update_from_ini(&fpath);
let fpath = std::path::Path::new("Data/SKSE/Plugins/SSEDisplayTweaks_Custom.ini");
self.update_from_ini(&fpath);

log::trace!(
"display tweaks scaling: {}; scale={};",
self.upscaling,
self.scale
);
}

fn update_from_ini(&mut self, fpath: &Path) {
if !fpath.exists() {
return;
}
let Ok(conf) = Ini::load_from_file(fpath) else {
return;
};
let Some(section) = conf.section(Some("Render")) else {
return;
};
self.upscaling = read_from_ini(self.upscaling, "BorderlessUpscale", section);
self.scale = read_from_ini(self.scale, "ResolutionScale", section);
}
}

impl Default for DisplayTweaks {
fn default() -> Self {
Self {
scale: 1.0,
upscaling: false,
}
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
52 changes: 30 additions & 22 deletions src/layouts/layout_v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::layouts::shared::NamedAnchor;
use crate::plugin::{
Align, Color, HudElement, LayoutFlattened, MeterKind, Point, SlotFlattened, TextFlattened,
};
use crate::settings::settings;

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct HudLayout1 {
Expand Down Expand Up @@ -144,53 +145,48 @@ impl HudLayout1 {
}

fn flatten(&self, slot: &SlotLayout) -> SlotFlattened {
let factor = self.scale_for_display();
let anchor = self.anchor_point();
let center = anchor.translate(&slot.offset.scale(self.global_scale));
let center = anchor.translate(&slot.offset.scale(factor));

let mut text = Vec::new();
if slot.name_color.a > 0 {
text.push(TextFlattened {
anchor: slot.name_offset.scale(self.global_scale).translate(&center),
anchor: slot.name_offset.scale(factor).translate(&center),
color: slot.name_color.clone(),
alignment: slot.align_text,
contents: "{name}".to_string(),
font_size: slot.name_font_size * self.global_scale,
font_size: slot.name_font_size * factor,
wrap_width: slot.name_wrap_width,
});
}
if slot.count_color.a > 0 {
text.push(TextFlattened {
anchor: slot
.count_offset
.scale(self.global_scale)
.translate(&center),
anchor: slot.count_offset.scale(factor).translate(&center),
color: slot.count_color.clone(),
alignment: slot.align_text,
contents: "{count}".to_string(),
font_size: slot.count_font_size * self.global_scale,
font_size: slot.count_font_size * factor,
wrap_width: slot.count_wrap_width,
});
}

SlotFlattened {
element: slot.element,
center: center.clone(),
bg_size: slot.size.scale(self.global_scale),
bg_size: slot.size.scale(factor),
bg_color: slot.bg_color.clone(),
bg_image: "slot_bg.svg".to_string(),

icon_size: slot.icon_size.scale(self.global_scale),
icon_center: slot.icon_offset.scale(self.global_scale).translate(&center),
icon_size: slot.icon_size.scale(factor),
icon_center: slot.icon_offset.scale(factor).translate(&center),
icon_color: slot.icon_color.clone(),

hotkey_size: slot.hotkey_size.scale(self.global_scale),
hotkey_center: slot
.hotkey_offset
.scale(self.global_scale)
.translate(&center),
hotkey_size: slot.hotkey_size.scale(factor),
hotkey_center: slot.hotkey_offset.scale(factor).translate(&center),
hotkey_color: slot.hotkey_color.clone(),

hotkey_bg_size: slot.hotkey_size.scale(self.global_scale),
hotkey_bg_size: slot.hotkey_size.scale(factor),
hotkey_bg_color: slot.hotkey_bg_color.clone(),
hotkey_bg_image: "key_bg.svg".to_string(),

Expand All @@ -214,26 +210,38 @@ impl HudLayout1 {
text,
}
}

fn scale_for_display(&self) -> f32 {
let config = settings();
let reso = config.resolution_scale();
let display_scale = if config.is_upscaling() {
(reso * reso) as f32
} else {
reso as f32
};
self.global_scale * display_scale
}
}

impl From<&HudLayout1> for LayoutFlattened {
fn from(v: &HudLayout1) -> Self {
let slots = v.layouts.iter().map(|xs| v.flatten(xs)).collect();
let factor = v.scale_for_display();

LayoutFlattened {
global_scale: v.global_scale,
global_scale: factor,
anchor: v.anchor_point(),
size: v.size.scale(v.global_scale),
size: v.size.scale(factor),
bg_size: Point {
x: v.size.x * v.global_scale,
y: v.size.y * v.global_scale,
x: v.size.x * factor,
y: v.size.y * factor,
},
bg_color: v.bg_color.clone(),
bg_image: "hud_bg.svg".to_string(),
hide_ammo_when_irrelevant: v.hide_ammo_when_irrelevant,
hide_left_when_irrelevant: v.hide_left_when_irrelevant,
font: v.font.clone(),
font_size: v.font_size * v.global_scale,
font_size: v.font_size * factor,
// glyphs requested
chinese_full_glyphs: v.chinese_full_glyphs,
simplified_chinese_glyphs: v.simplified_chinese_glyphs,
Expand Down
54 changes: 35 additions & 19 deletions src/layouts/layout_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use super::shared::*;
use crate::plugin::{
Align, Color, HudElement, LayoutFlattened, MeterKind, Point, SlotFlattened, TextFlattened,
};
use crate::settings::settings;

/// Where to arrange the HUD elements and what color to draw them in.
///
Expand Down Expand Up @@ -109,20 +110,22 @@ impl HudLayout2 {

pub fn anchor_point(&self) -> Point {
super::anchor_point(
self.global_scale,
self.scale_for_display(),
&self.size,
&self.anchor_name,
self.anchor.as_ref(),
)
}

fn flatten_slot(&self, slot: &SlotElement, element: HudElement) -> SlotFlattened {
let scale = self.scale_for_display();

let bg = slot.background.clone().unwrap_or_default();
let hotkey = slot.hotkey.clone().unwrap_or_default();
let hkbg = hotkey.background.unwrap_or_default();

let anchor = self.anchor_point();
let center = anchor.translate(&slot.offset.scale(self.global_scale));
let center = anchor.translate(&slot.offset.scale(scale));
let text = slot
.text
.iter()
Expand All @@ -131,9 +134,9 @@ impl HudLayout2 {

let poison = slot.poison.clone().unwrap_or_default();
let poison_image = poison.indicator.svg;
let poison_size = poison.indicator.size.scale(self.global_scale);
let poison_size = poison.indicator.size.scale(scale);
let poison_color = poison.indicator.color;
let poison_center = center.translate(&poison.offset.scale(self.global_scale));
let poison_center = center.translate(&poison.offset.scale(scale));

let meter = slot.meter.clone().unwrap_or_default();
let (
Expand All @@ -148,21 +151,21 @@ impl HudLayout2 {
meter_start_angle,
meter_end_angle,
meter_arc_width,
) = meter.tuple_for_flattening(&center, self.global_scale);
) = meter.tuple_for_flattening(&center, scale);

SlotFlattened {
element,
center: center.clone(),
bg_size: bg.size.scale(self.global_scale),
bg_size: bg.size.scale(scale),
bg_color: bg.color,
bg_image: bg.svg,
icon_size: slot.icon.size.scale(self.global_scale),
icon_center: slot.icon.offset.scale(self.global_scale).translate(&center),
icon_size: slot.icon.size.scale(scale),
icon_center: slot.icon.offset.scale(scale).translate(&center),
icon_color: slot.icon.color.clone(),
hotkey_size: hotkey.size.scale(self.global_scale),
hotkey_center: hotkey.offset.scale(self.global_scale).translate(&center),
hotkey_size: hotkey.size.scale(scale),
hotkey_center: hotkey.offset.scale(scale).translate(&center),
hotkey_color: hotkey.color,
hotkey_bg_size: hkbg.size.scale(self.global_scale),
hotkey_bg_size: hkbg.size.scale(scale),
hotkey_bg_color: hkbg.color,
hotkey_bg_image: hkbg.svg,
poison_size,
Expand All @@ -185,15 +188,27 @@ impl HudLayout2 {
}

fn flatten_text(&self, text: &TextElement, center: &Point) -> TextFlattened {
let scale = self.scale_for_display();
TextFlattened {
anchor: center.translate(&text.offset.scale(self.global_scale)),
anchor: center.translate(&text.offset.scale(scale)),
color: text.color.clone(),
alignment: text.alignment,
contents: text.contents.clone(),
font_size: text.font_size * self.global_scale,
font_size: text.font_size * scale,
wrap_width: text.wrap_width,
}
}

fn scale_for_display(&self) -> f32 {
let config = settings();
let reso = config.resolution_scale();
let display_scale = if config.is_upscaling() {
(reso * reso) as f32
} else {
reso as f32
};
self.global_scale * display_scale
}
}

#[derive(Deserialize, Serialize, Debug, Clone, PartialEq)]
Expand Down Expand Up @@ -480,18 +495,19 @@ impl From<&HudLayout2> for LayoutFlattened {
slots.push(v.flatten_slot(equipset, HudElement::EquipSet));
}
let bg = v.background.clone().unwrap_or_default();
let scale = v.scale_for_display();

LayoutFlattened {
global_scale: v.global_scale,
global_scale: scale,
anchor: v.anchor_point(),
size: v.size.scale(v.global_scale),
bg_size: bg.size.scale(v.global_scale),
size: v.size.scale(scale),
bg_size: bg.size.scale(scale),
bg_color: bg.color.clone(),
bg_image: bg.svg.clone(),
hide_ammo_when_irrelevant: v.hide_ammo_when_irrelevant,
hide_left_when_irrelevant: v.hide_left_when_irrelevant,
font: v.font.clone(),
font_size: v.font_size * v.global_scale,
font_size: v.font_size * scale,
chinese_full_glyphs: v.chinese_full_glyphs,
simplified_chinese_glyphs: v.simplified_chinese_glyphs,
cyrillic_glyphs: v.cyrillic_glyphs,
Expand All @@ -507,7 +523,7 @@ impl From<&HudLayout2> for LayoutFlattened {
#[cfg(test)]
mod tests {
use super::*;
use crate::layouts::{resolutionHeight, Layout};
use crate::layouts::{displayHeight, Layout};

#[test]
fn default_layout_valid() {
Expand Down Expand Up @@ -746,7 +762,7 @@ mod tests {
anchor,
Point {
x: 190.0,
y: resolutionHeight() - layout.size.y
y: displayHeight() - layout.size.y
}
);

Expand Down
Loading

0 comments on commit 503f80b

Please sign in to comment.