feat(themes): add ThemeAbgrCacheLerp pure-helper for crossfade
Per-slot ABGR byte-lerp between two cache value-records, stack-allocated output, t clamped. Pattern anchor: imgui.cpp ImAlphaBlendColors.
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
namespace HellionChat.Themes;
|
||||
|
||||
// Per-slot ABGR byte-lerp between two ThemeAbgrCache value-records.
|
||||
// Pattern anchor: imgui.cpp:2820-2828 ImAlphaBlendColors -- decompose
|
||||
// each byte, lerp via Math.Round, recompose. Stack-allocated output
|
||||
// (readonly record struct), no heap pressure inside the crossfade
|
||||
// window. t is clamped to [0, 1] so float drift cannot overshoot.
|
||||
internal static class ThemeAbgrCacheLerp
|
||||
{
|
||||
public static ThemeAbgrCache Lerp(ThemeAbgrCache from, ThemeAbgrCache to, float t)
|
||||
{
|
||||
t = Math.Clamp(t, 0f, 1f);
|
||||
|
||||
return new ThemeAbgrCache(
|
||||
PrimaryDark: LerpAbgr(from.PrimaryDark, to.PrimaryDark, t),
|
||||
Primary: LerpAbgr(from.Primary, to.Primary, t),
|
||||
PrimaryLight: LerpAbgr(from.PrimaryLight, to.PrimaryLight, t),
|
||||
PrimaryGlow: LerpAbgr(from.PrimaryGlow, to.PrimaryGlow, t),
|
||||
AccentDark: LerpAbgr(from.AccentDark, to.AccentDark, t),
|
||||
Accent: LerpAbgr(from.Accent, to.Accent, t),
|
||||
AccentLight: LerpAbgr(from.AccentLight, to.AccentLight, t),
|
||||
Identity: LerpAbgr(from.Identity, to.Identity, t),
|
||||
WindowBg: LerpAbgr(from.WindowBg, to.WindowBg, t),
|
||||
ChildBg: LerpAbgr(from.ChildBg, to.ChildBg, t),
|
||||
FrameBg: LerpAbgr(from.FrameBg, to.FrameBg, t),
|
||||
Surface: LerpAbgr(from.Surface, to.Surface, t),
|
||||
SurfaceHover: LerpAbgr(from.SurfaceHover, to.SurfaceHover, t),
|
||||
Border: LerpAbgr(from.Border, to.Border, t),
|
||||
TextPrimary: LerpAbgr(from.TextPrimary, to.TextPrimary, t),
|
||||
TextMuted: LerpAbgr(from.TextMuted, to.TextMuted, t),
|
||||
TextDim: LerpAbgr(from.TextDim, to.TextDim, t),
|
||||
StatusSuccess: LerpAbgr(from.StatusSuccess, to.StatusSuccess, t),
|
||||
StatusDanger: LerpAbgr(from.StatusDanger, to.StatusDanger, t),
|
||||
StatusWarning: LerpAbgr(from.StatusWarning, to.StatusWarning, t),
|
||||
StatusInfo: LerpAbgr(from.StatusInfo, to.StatusInfo, t)
|
||||
);
|
||||
}
|
||||
|
||||
private static uint LerpAbgr(uint from, uint to, float t)
|
||||
{
|
||||
var ra = (byte)(from & 0xFFu);
|
||||
var ga = (byte)((from >> 8) & 0xFFu);
|
||||
var ba = (byte)((from >> 16) & 0xFFu);
|
||||
var aa = (byte)((from >> 24) & 0xFFu);
|
||||
|
||||
var rb = (byte)(to & 0xFFu);
|
||||
var gb = (byte)((to >> 8) & 0xFFu);
|
||||
var bb = (byte)((to >> 16) & 0xFFu);
|
||||
var ab = (byte)((to >> 24) & 0xFFu);
|
||||
|
||||
// Math.Round (default ToEven) matches ColourUtil.ApplyAlpha so a
|
||||
// crossfade-into-hover transition does not produce a one-byte
|
||||
// jump at the midpoint between the two paths.
|
||||
var r = (byte)Math.Round(ra + (rb - ra) * t);
|
||||
var g = (byte)Math.Round(ga + (gb - ga) * t);
|
||||
var b = (byte)Math.Round(ba + (bb - ba) * t);
|
||||
var a = (byte)Math.Round(aa + (ab - aa) * t);
|
||||
|
||||
return ((uint)a << 24) | ((uint)b << 16) | ((uint)g << 8) | r;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user