diff --git a/far/changelog b/far/changelog index ecfeea0c6f..f3e7b907ca 100644 --- a/far/changelog +++ b/far/changelog @@ -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 diff --git a/far/interf.cpp b/far/interf.cpp index 0dff800f98..7d8d0e1bc4 100644 --- a/far/interf.cpp +++ b/far/interf.cpp @@ -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) diff --git a/far/interf.hpp b/far/interf.hpp index a485799e2e..e63d5e397f 100644 --- a/far/interf.hpp +++ b/far/interf.hpp @@ -200,8 +200,8 @@ void PutText(rectangle Where, const FAR_CHAR_INFO* Src); void GetText(rectangle Where, matrix& 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); diff --git a/far/message.cpp b/far/message.cpp index 1070f62cbc..b8e36425a9 100644 --- a/far/message.cpp +++ b/far/message.cpp @@ -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); } diff --git a/far/scrbuf.cpp b/far/scrbuf.cpp index 79e5016586..c3275bbc88 100644 --- a/far/scrbuf.cpp +++ b/far/scrbuf.cpp @@ -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; @@ -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& Buffer, std::span 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(rgb.r, 2); - rgb.g = std::min(rgb.g, 2); - rgb.b = std::min(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(Color, colors::index::grey_first + colors::index::grey_count / 2); - } +static void reset_shadows(matrix& Buffer, matrix const& Backup, std::span 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); @@ -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(); } diff --git a/far/scrbuf.hpp b/far/scrbuf.hpp index 4a52279381..379102d71c 100644 --- a/far/scrbuf.hpp +++ b/far/scrbuf.hpp @@ -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); diff --git a/far/scrobj.cpp b/far/scrobj.cpp index 8456ef6b05..cca09dd562 100644 --- a/far/scrobj.cpp +++ b/far/scrobj.cpp @@ -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(rectangle{ 0, 0, ScrX, ScrY }); + MakeShadow({ 0, 0, ScrX, ScrY }); + } + else { - if(Full) - { - if (!ShadowSaveScr) - { - ShadowSaveScr = std::make_unique(rectangle{ 0, 0, ScrX, ScrY }); - MakeShadow({ 0, 0, ScrX, ScrY }); - DropShadow(m_Where); - } - } - else - { - if (!ShadowSaveScr) - { - ShadowSaveScr = std::make_unique(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(rectangle{ m_Where.left, m_Where.top, m_Where.right + 2, m_Where.bottom + 1 }); + DropShadow(m_Where); } } diff --git a/far/vbuild.m4 b/far/vbuild.m4 index 7c115f7f9d..e691ab6a48 100644 --- a/far/vbuild.m4 +++ b/far/vbuild.m4 @@ -1 +1 @@ -6365 +6366