Skip to content

Commit

Permalink
Continuation of 5788: proper alpha blending
Browse files Browse the repository at this point in the history
Available in files highlighting and editor selection colour
  • Loading branch information
alabuzhev committed May 18, 2021
1 parent bc97881 commit 1e2b47c
Show file tree
Hide file tree
Showing 11 changed files with 201 additions and 89 deletions.
6 changes: 6 additions & 0 deletions far/changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
--------------------------------------------------------------------------------
drkns 19.05.2021 00:00:00 +0100 - build 5800

1. Continuation of 5788: proper alpha blending.
Available in files highlighting and editor selection colour.

--------------------------------------------------------------------------------
drkns 16.05.2021 15:31:41 +0100 - build 5799

Expand Down
90 changes: 75 additions & 15 deletions far/colormix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,16 @@ enum
ConsoleFgShift=0,
};

static auto to_rgba(COLORREF const Color)
{
return *reinterpret_cast<rgba const*>(&Color);
}

static auto to_color(rgba const Rgba)
{
return *reinterpret_cast<COLORREF const*>(&Rgba);
}

namespace colors
{
COLORREF index_value(COLORREF const Colour)
Expand Down Expand Up @@ -119,13 +129,47 @@ namespace colors
const auto merge_part = [&](COLORREF FarColor::*ColorAccessor, const FARCOLORFLAGS Flag)
{
const auto TopValue = std::invoke(ColorAccessor, Top);

// Nothing to apply
if (is_transparent(TopValue))
return;

// TODO: proper alpha blending?
std::invoke(ColorAccessor, Result) = TopValue;
auto& ResultValue = std::invoke(ColorAccessor, Result);

// Simple case
if (is_opaque(TopValue))
{
ResultValue = TopValue;
flags::copy(Result.Flags, Flag, Top.Flags);
return;
}

flags::copy(Result.Flags, Flag, Top.Flags);
// Alpha blending
const auto BottomValue = std::invoke(ColorAccessor, Bottom);

const auto to_rgba = [](COLORREF const Color, bool const Is4Bit)
{
return ::to_rgba(Is4Bit ? ConsoleIndexToTrueColor(Color) : Color);
};

const auto TopRGBA = to_rgba(TopValue, (Top.Flags & Flag) != 0);
const auto BottomRGBA = to_rgba(BottomValue, (Bottom.Flags & Flag) != 0);

const auto calc_channel = [&](unsigned char rgba::*Accessor)
{
return static_cast<unsigned char>((std::invoke(Accessor, TopRGBA) * TopRGBA.a + (0xFF - TopRGBA.a) * std::invoke(Accessor, BottomRGBA)) / 0xFF);
};

rgba const MergedRGBA
{
calc_channel(&rgba::r),
calc_channel(&rgba::g),
calc_channel(&rgba::b),
static_cast<unsigned char>(BottomRGBA.a | ((0xFF - BottomRGBA.a) * TopRGBA.a / 0xFF))
};

ResultValue = to_color(MergedRGBA);
flags::clear(Result.Flags, Flag);
};

merge_part(&FarColor::BackgroundColor, FCF_BG_4BIT);
Expand Down Expand Up @@ -174,23 +218,17 @@ namespace colors
if (const auto Iterator = Map.find(Color); Iterator != Map.cend())
return Iterator->second;

union color_point
{
const COLORREF Color;
const rgba RGBA;
};

color_point const Point{ Color };
const auto PointRGBA = to_rgba(Color);

const auto distance = [&](COLORREF const PaletteColor)
{
color_point const PalettePoint{ PaletteColor };
const auto PaletteRGBA = to_rgba(PaletteColor);

const auto distance_part = [&](unsigned char rgba::* const Getter)
{
return std::abs(
int{ std::invoke(Getter, Point.RGBA) } -
int{ std::invoke(Getter, PalettePoint.RGBA) }
int{ std::invoke(Getter, PointRGBA) } -
int{ std::invoke(Getter, PaletteRGBA) }
);
};

Expand Down Expand Up @@ -292,9 +330,9 @@ FarColor ConsoleColorToFarColor(WORD Color)
};
}

COLORREF ConsoleIndexToTrueColor(size_t Index)
COLORREF ConsoleIndexToTrueColor(COLORREF const Color)
{
return opaque(console_palette()[Index & ConsoleMask]);
return alpha_value(Color) | console_palette()[Color & ConsoleMask];
}

const FarColor& PaletteColorToFarColor(PaletteColors ColorIndex)
Expand Down Expand Up @@ -402,6 +440,28 @@ TEST_CASE("colors.COLORREF")
}
}

TEST_CASE("colors.merge")
{
static const struct
{
FarColor Bottom, Top, Merged;
}
Tests[]
{
{ { 0, {0x00000000}, {0x00000000} }, { 0, {0x00000000}, {0x00000000} }, { 0, {0x00000000}, {0x00000000} } },
{ { 0, {0xFF123456}, {0xFF654321} }, { 0, {0xFFABCDEF}, {0xFFFEDCBA} }, { 0, {0xFFABCDEF}, {0xFFFEDCBA} } },
{ { 0, {0x80000000}, {0xFF000000} }, { 0, {0x80000000}, {0x01000000} }, { 0, {0xBF000000}, {0xFF000000} } },
{ { 0, {0xFFFFFFFF}, {0xFF000000} }, { 0, {0x80000000}, {0x80FFFFFF} }, { 0, {0xFF7F7F7F}, {0xFF808080} } },
{ { 0, {0xFF00D5FF}, {0xFFBB5B00} }, { 0, {0x800000FF}, {0x80000000} }, { 0, {0xFF006AFF}, {0xFF5D2D00} } },
};

for (const auto& i: Tests)
{
const auto Color = colors::merge(i.Bottom, i.Top);
REQUIRE(Color == i.Merged);
}
}

TEST_CASE("colors.parser")
{
static const struct
Expand Down
2 changes: 1 addition & 1 deletion far/colormix.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ namespace colors
FarColor merge(const FarColor& Bottom, const FarColor& Top);
WORD FarColorToConsoleColor(const FarColor& Color);
FarColor ConsoleColorToFarColor(WORD Color);
COLORREF ConsoleIndexToTrueColor(size_t Index);
COLORREF ConsoleIndexToTrueColor(COLORREF Color);
const FarColor& PaletteColorToFarColor(PaletteColors ColorIndex);
const FarColor* StoreColor(const FarColor& Value);
COLORREF ARGB2ABGR(int Color);
Expand Down
4 changes: 2 additions & 2 deletions far/dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1988,8 +1988,8 @@ void Dialog::ShowDialog(size_t ID)
int startx = m_Where.left + CX1 + (Item.Flags&DIF_NOBRACKETS? 0 : 2);
Global->ScrBuf->ApplyColor(
{ startx, m_Where.top + CY1, startx + 1, m_Where.top + CY1 },
colors::ConsoleColorToFarColor(B_YELLOW | F_LIGHTBLUE),
ScreenBuf::apply_mode::all);
colors::ConsoleColorToFarColor(B_YELLOW | F_LIGHTBLUE)
);
}
break;
}
Expand Down
9 changes: 4 additions & 5 deletions far/edit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ void Edit::FastShow(const ShowInfo* Info)
{
if (m_Flags.Check(FEDITLINE_CLEARFLAG))
{
Global->ScrBuf->ApplyColor(m_Where, GetUnchangedColor(), ScreenBuf::apply_mode::all);
Global->ScrBuf->ApplyColor(m_Where, GetUnchangedColor());
}
}
else
Expand All @@ -358,7 +358,7 @@ void Edit::FastShow(const ShowInfo* Info)

if (m_Flags.Check(FEDITLINE_DROPDOWNBOX))
{
Global->ScrBuf->ApplyColor(m_Where, GetSelectedColor(), ScreenBuf::apply_mode::color);
Global->ScrBuf->ApplyColor(m_Where, GetSelectedColor());
}
else
{
Expand All @@ -369,8 +369,7 @@ void Edit::FastShow(const ShowInfo* Info)
std::min(m_Where.left + TabSelEnd - 1, static_cast<int>(m_Where.right)),
m_Where.top
},
GetSelectedColor(),
ScreenBuf::apply_mode::color
GetSelectedColor()
);
}
}
Expand Down Expand Up @@ -2204,7 +2203,7 @@ void Edit::ApplyColor(const FarColor& SelColor, int XPos, int FocusedLeftPos)
// Раскрашиваем элемент, если есть что раскрашивать
if (End >= Start)
{
Global->ScrBuf->ApplyColor({ m_Where.left + Start, m_Where.top, m_Where.left + End, m_Where.top }, CurItem.GetColor(), ScreenBuf::apply_mode::all);
Global->ScrBuf->ApplyColor({ m_Where.left + Start, m_Where.top, m_Where.left + End, m_Where.top }, CurItem.GetColor());
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion far/editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ void Editor::ShowEditor()
BlockX2=XX2;

if (BlockX1 <= XX2 && BlockX2 >= m_Where.left)
Global->ScrBuf->ApplyColor({ BlockX1, Y, BlockX2, Y }, colors::PaletteColorToFarColor(COL_EDITORSELECTEDTEXT), ScreenBuf::apply_mode::color);
Global->ScrBuf->ApplyColor({ BlockX1, Y, BlockX2, Y }, colors::PaletteColorToFarColor(COL_EDITORSELECTEDTEXT));
}

++CurPtr;
Expand Down
32 changes: 32 additions & 0 deletions far/farlang.templ.m4
Original file line number Diff line number Diff line change
Expand Up @@ -18754,6 +18754,22 @@ MSetColorBackground
"&Фон:"
"&Fonas:"

MSetColorForeAARRGGBB
l:
l:// 8 characters max
"AARRGGBB"
"AARRGGBB"
"AARRGGBB"
"AARRGGBB"
"AARRGGBB"
"AARRGGBB"
"AARRGGBB"
"AARRGGBB"
"AARRGGBB"
"AARRGGBB"
"AARRGGBB"
"AARRGGBB"

MSetColorForeRGB
l:
l:// 3 characters max
Expand All @@ -18770,6 +18786,22 @@ l:// 3 characters max
"&RGB…"
"&RGB…"

MSetColorBackAARRGGBB
l:
l:// 8 characters max
"AARRGGBB"
"AARRGGBB"
"AARRGGBB"
"AARRGGBB"
"AARRGGBB"
"AARRGGBB"
"AARRGGBB"
"AARRGGBB"
"AARRGGBB"
"AARRGGBB"
"AARRGGBB"
"AARRGGBB"

MSetColorBackRGB
l:
l:// 3 characters max
Expand Down
24 changes: 1 addition & 23 deletions far/scrbuf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,31 +206,9 @@ void ScreenBuf::ApplyColor(rectangle Where, const FarColor& Color, apply_mode co

fix_coordinates(Where);

const auto
DoForeground = ApplyMode & apply_mode::foreground && !colors::is_transparent(Color.ForegroundColor),
DoBackground = ApplyMode & apply_mode::background && !colors::is_transparent(Color.BackgroundColor),
DoStyle = ApplyMode & apply_mode::style && !(Color.BackgroundColor & FCF_IGNORE_STYLE);

for_submatrix(Buf, Where, [&](FAR_CHAR_INFO& Element)
{
auto& DstColor = Element.Attributes;

if (DoForeground)
{
DstColor.ForegroundColor = Color.ForegroundColor;
flags::copy(DstColor.Flags, FCF_FG_4BIT, Color.Flags);
}

if (DoBackground)
{
DstColor.BackgroundColor = Color.BackgroundColor;
flags::copy(DstColor.Flags, FCF_BG_4BIT, Color.Flags);
}

if (DoStyle)
{
flags::copy(DstColor.Flags, FCF_STYLEMASK, Color.Flags);
}
Element.Attributes = colors::merge(Element.Attributes, Color);
});

debug_flush();
Expand Down
2 changes: 1 addition & 1 deletion far/scrbuf.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class ScreenBuf: noncopyable
all = color | style
};

void ApplyColor(rectangle Where, const FarColor& Color, apply_mode ApplyMode);
void ApplyColor(rectangle Where, const FarColor& Color, apply_mode ApplyMode = apply_mode::all);
void FillRect(rectangle Where, const FAR_CHAR_INFO& Info);

void Scroll(size_t Count);
Expand Down
Loading

0 comments on commit 1e2b47c

Please sign in to comment.