Skip to content

Commit

Permalink
Improve shadow rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
alabuzhev committed Aug 31, 2024
1 parent 0acedcc commit 05c4950
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 100 deletions.
5 changes: 5 additions & 0 deletions far/changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
--------------------------------------------------------------------------------
drkns 2024-08-31 13:02:11+01:00 - build 6366

1. Improve shadow rendering.

--------------------------------------------------------------------------------
drkns 2024-08-30 22:15:07+01:00 - build 6365

Expand Down
10 changes: 5 additions & 5 deletions far/interf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1149,15 +1149,15 @@ void SetScreen(rectangle const Where, wchar_t Ch, const FarColor& Color)
Global->ScrBuf->FillRect(Where, { Ch, {}, {}, Color });
}

void MakeShadow(rectangle const Where, bool const IsLegacy)
void MakeShadow(rectangle const Where)
{
Global->ScrBuf->ApplyShadow(Where, IsLegacy);
Global->ScrBuf->ApplyShadow(Where);
}

void DropShadow(rectangle const Where, bool const IsLegacy)
void DropShadow(rectangle const Where)
{
MakeShadow({ Where.left + 2, Where.bottom + 1, Where.right + 2, Where.bottom + 1 }, IsLegacy);
MakeShadow({ Where.right + 1, Where.top + 1, Where.right + 2, Where.bottom }, IsLegacy);
MakeShadow({ Where.left + 2, Where.bottom + 1, Where.right + 2, Where.bottom + 1 });
MakeShadow({ Where.right + 1, Where.top + 1, Where.right + 2, Where.bottom });
}

void SetColor(int Color)
Expand Down
4 changes: 2 additions & 2 deletions far/interf.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,8 @@ void PutText(rectangle Where, const FAR_CHAR_INFO* Src);
void GetText(rectangle Where, matrix<FAR_CHAR_INFO>& Dest);

void SetScreen(rectangle Where, wchar_t Ch,const FarColor& Color);
void MakeShadow(rectangle Where, bool IsLegacy = false);
void DropShadow(rectangle Where, bool IsLegacy = false);
void MakeShadow(rectangle Where);
void DropShadow(rectangle Where);
void SetColor(int Color);
void SetColor(PaletteColors Color);
void SetColor(const FarColor& Color);
Expand Down
2 changes: 1 addition & 1 deletion far/message.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ static message_result MessageImpl(
if (!(Flags & MSG_KEEPBACKGROUND))
{
SetScreen(Position, L' ', colors::PaletteColorToFarColor((Flags & MSG_WARNING)? COL_WARNDIALOGTEXT : COL_DIALOGTEXT));
DropShadow(Position, true);
DropShadow(Position);
Box({ Position.left + 3, Position.top + 1, Position.right - 3, Position.bottom - 1 }, colors::PaletteColorToFarColor((Flags & MSG_WARNING)? COL_WARNDIALOGBOX : COL_DIALOGBOX), DOUBLE_BOX);
}

Expand Down
130 changes: 58 additions & 72 deletions far/scrbuf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,9 @@ static bool apply_index_shadow(FarColor& Color, COLORREF FarColor::* ColorAccess
if (!Is256ColorAvailable)
return false;

// This is ultimately dead code in the current ecosystem:
// Windows added support for 256 and TrueColor at the same time, so it's either everything or nothing.
// But just in case.
if (Index <= cube_last)
{
const auto CubeIndex = Index - cube_first;
Expand Down Expand Up @@ -284,92 +287,70 @@ static void apply_shadow(FarColor& Color, COLORREF FarColor::* ColorAccessor, co
Color = colors::merge(Color, TrueShadow);
}

void ScreenBuf::ApplyShadow(rectangle Where, bool const IsLegacy)
{
if (!is_visible(Where))
return;

SCOPED_ACTION(std::scoped_lock)(CS);

fix_coordinates(Where);
static constexpr FarColor
TrueShadowFull{ FCF_INHERIT_STYLE, { 0x80'000000 }, { 0x80'000000 }, { 0x80'000000 } },
TrueShadowFore{ FCF_INHERIT_STYLE, { 0x80'000000 }, { 0x00'000000 }, { 0x00'000000 } },
TrueShadowBack{ FCF_INHERIT_STYLE, { 0x00'000000 }, { 0x80'000000 }, { 0x00'000000 } },
TrueShadowUndl{ FCF_INHERIT_STYLE, { 0x00'000000 }, { 0x00'000000 }, { 0x80'000000 } };

const auto CharWidthEnabled = char_width::is_enabled();
static void bake_shadows(matrix<FAR_CHAR_INFO>& Buffer, std::span<rectangle const> const WriteRegions)
{
const auto IsTrueColorAvailable = console.IsVtActive() || console.ExternalRendererLoaded();
const auto Is256ColorAvailable = IsTrueColorAvailable;

static constexpr FarColor
TrueShadowFull{ FCF_INHERIT_STYLE, { 0x80'000000 }, { 0x80'000000 }, { 0x80'000000 } },
TrueShadowFore{ FCF_INHERIT_STYLE, { 0x80'000000 }, { 0x00'000000 }, { 0x00'000000 } },
TrueShadowBack{ FCF_INHERIT_STYLE, { 0x00'000000 }, { 0x80'000000 }, { 0x00'000000 } },
TrueShadowUndl{ FCF_INHERIT_STYLE, { 0x00'000000 }, { 0x00'000000 }, { 0x80'000000 } };

for_submatrix(Buf, Where, [&](FAR_CHAR_INFO& Element, point const Point)
for (const auto& i: WriteRegions)
{
if (IsLegacy)
for_submatrix(Buffer, i, [&](FAR_CHAR_INFO& Cell)
{
// This piece is for usage with repeated Message() calls.
// It generates a stable shadow that does not fade to black when reapplied over and over.
// We really, really should ditch the Message pattern.
Element.Attributes.IsBgIndex()?
colors::set_index_value(Element.Attributes.BackgroundColor, F_BLACK) :
colors::set_color_value(Element.Attributes.BackgroundColor, 0);

const auto apply_shadow = [](COLORREF& ColorRef, bool const IsIndex)
if (IsTrueColorAvailable)
{
if (IsIndex)
{
auto Color = colors::index_value(ColorRef);
if (Cell.Reserved0 != 1)
return;

if (Color <= colors::index::nt_last)
{
if (Color == F_LIGHTGRAY)
Color = F_DARKGRAY;
else if (const auto Mask = FOREGROUND_INTENSITY; Color != Mask)
Color &= ~Mask;
}
else if (Color <= colors::index::cube_last)
{
colors::rgb6 rgb(Color);
// We have TrueColor, so just fill whatever is there with half-transparent black.
Cell.Attributes = colors::merge(Cell.Attributes, TrueShadowFull);
}
else
{
if (Cell.Reserved0 != 1)
return;

rgb.r = std::min<uint8_t>(rgb.r, 2);
rgb.g = std::min<uint8_t>(rgb.g, 2);
rgb.b = std::min<uint8_t>(rgb.b, 2);
apply_shadow(Cell.Attributes, &FarColor::ForegroundColor, FCF_FG_INDEX, TrueShadowFore, Is256ColorAvailable);
apply_shadow(Cell.Attributes, &FarColor::BackgroundColor, FCF_BG_INDEX, TrueShadowBack, Is256ColorAvailable);
apply_shadow(Cell.Attributes, &FarColor::UnderlineColor, FCF_FG_UNDERLINE_INDEX, TrueShadowUndl, Is256ColorAvailable);
}
});
}
}

Color = rgb;
}
else
{
Color = std::min<uint8_t>(Color, colors::index::grey_first + colors::index::grey_count / 2);
}
static void reset_shadows(matrix<FAR_CHAR_INFO>& Buffer, matrix<FAR_CHAR_INFO> const& Backup, std::span<rectangle const> const WriteRegions)
{
for (const auto& Rect: WriteRegions)
{
for (auto i = Rect.top; i <= Rect.bottom; ++i)
{
for (auto j = Rect.left; j <= Rect.right; ++j)
{
Buffer[i][j].Attributes = Backup[i][j].Attributes;
}
}
}
}

colors::set_index_value(ColorRef, Color);
}
else
{
const auto Mask = 0x808080;
auto Color = colors::color_value(ColorRef);
void ScreenBuf::ApplyShadow(rectangle Where)
{
if (!is_visible(Where))
return;

if (Color != Mask)
Color &= ~Mask;
SCOPED_ACTION(std::scoped_lock)(CS);

colors::set_color_value(ColorRef, Color);
}
};
fix_coordinates(Where);

apply_shadow(Element.Attributes.ForegroundColor, Element.Attributes.IsFgIndex());
apply_shadow(Element.Attributes.UnderlineColor, Element.Attributes.IsUnderlineIndex());
}
else if (IsTrueColorAvailable)
{
// We have TrueColor, so just fill whatever is there with half-transparent black.
Element.Attributes = colors::merge(Element.Attributes, TrueShadowFull);
}
else
{
apply_shadow(Element.Attributes, &FarColor::ForegroundColor, FCF_FG_INDEX, TrueShadowFore, Is256ColorAvailable);
apply_shadow(Element.Attributes, &FarColor::BackgroundColor, FCF_BG_INDEX, TrueShadowBack, Is256ColorAvailable);
apply_shadow(Element.Attributes, &FarColor::UnderlineColor, FCF_FG_UNDERLINE_INDEX, TrueShadowUndl, Is256ColorAvailable);
}
const auto CharWidthEnabled = char_width::is_enabled();

for_submatrix(Buf, Where, [&](FAR_CHAR_INFO& Element, point const Point)
{
Element.Reserved0 = 1;

if (CharWidthEnabled)
invalidate_broken_pairs_in_cache(Buf, Shadow, Where, Point);
Expand Down Expand Up @@ -688,7 +669,12 @@ void ScreenBuf::Flush(flush_type FlushType)

Shadow = Buf;

bake_shadows(Shadow, WriteList);

console.WriteOutputGather(Shadow, WriteList);

reset_shadows(Shadow, Buf, WriteList);

console.Commit();
}

Expand Down
2 changes: 1 addition & 1 deletion far/scrbuf.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ class ScreenBuf: noncopyable
void RestoreMacroChar();
void RestoreElevationChar();

void ApplyShadow(rectangle Where, bool IsLegacy);
void ApplyShadow(rectangle Where);
void ApplyColor(rectangle Where, const FarColor& Color);
void FillRect(rectangle Where, const FAR_CHAR_INFO& Info);

Expand Down
29 changes: 11 additions & 18 deletions far/scrobj.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,24 +181,17 @@ void ScreenObjectWithShadow::Hide()

void ScreenObjectWithShadow::Shadow(bool Full)
{
if (m_Flags.Check(FSCROBJ_VISIBLE))
if (!m_Flags.Check(FSCROBJ_VISIBLE) || ShadowSaveScr)
return;

if(Full)
{
ShadowSaveScr = std::make_unique<SaveScreen>(rectangle{ 0, 0, ScrX, ScrY });
MakeShadow({ 0, 0, ScrX, ScrY });
}
else
{
if(Full)
{
if (!ShadowSaveScr)
{
ShadowSaveScr = std::make_unique<SaveScreen>(rectangle{ 0, 0, ScrX, ScrY });
MakeShadow({ 0, 0, ScrX, ScrY });
DropShadow(m_Where);
}
}
else
{
if (!ShadowSaveScr)
{
ShadowSaveScr = std::make_unique<SaveScreen>(rectangle{ m_Where.left, m_Where.top, m_Where.right + 2, m_Where.bottom + 1 });
DropShadow(m_Where, m_Flags.Check(FSCROBJ_SPECIAL));
}
}
ShadowSaveScr = std::make_unique<SaveScreen>(rectangle{ m_Where.left, m_Where.top, m_Where.right + 2, m_Where.bottom + 1 });
DropShadow(m_Where);
}
}
2 changes: 1 addition & 1 deletion far/vbuild.m4
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6365
6366

0 comments on commit 05c4950

Please sign in to comment.