Skip to content

Commit

Permalink
AtlasEngine: Implement remaining grid lines
Browse files Browse the repository at this point in the history
  • Loading branch information
lhecker committed Jul 25, 2022
1 parent 2e8949d commit 539618e
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 38 deletions.
25 changes: 17 additions & 8 deletions src/renderer/atlas/AtlasEngine.api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -612,11 +612,24 @@ void AtlasEngine::_resolveFontMetrics(const wchar_t* requestedFaceName, const Fo
const auto descentInPx = static_cast<double>(metrics.descent) * designUnitsPerPx;
const auto lineGapInPx = static_cast<double>(metrics.lineGap) * designUnitsPerPx;
const auto advanceWidthInPx = static_cast<double>(glyphMetrics.advanceWidth) * designUnitsPerPx;
const auto underlineOffsetInPx = static_cast<double>(-metrics.underlinePosition) * designUnitsPerPx;
const auto underlineThicknessInPx = static_cast<double>(metrics.underlineThickness) * designUnitsPerPx;
const auto strikethroughOffsetInPx = static_cast<double>(-metrics.strikethroughPosition) * designUnitsPerPx;
const auto strikethroughThicknessInPx = static_cast<double>(metrics.strikethroughThickness) * designUnitsPerPx;
const auto lineThicknessInPx = std::round(std::max(1.0, std::min(underlineThicknessInPx, strikethroughThicknessInPx)));

const auto halfGapInPx = lineGapInPx / 2.0;
const auto baseline = std::ceil(ascentInPx + halfGapInPx);
const auto underlinePosInPx = std::ceil(baseline + underlineOffsetInPx - lineThicknessInPx / 2.0);
const auto strikethroughPosInPx = std::round(baseline + strikethroughOffsetInPx - lineThicknessInPx / 2.0);
const auto cellHeightViaDescent = std::ceil(baseline + descentInPx + halfGapInPx);
// A double-underline is 3 lines tall due to a 1 line gap between the two lines.
// This logic should be kept in sync with AtlasEngine::_updateConstantBuffer,
// which calculates the offset/position of the lower line.
const auto cellHeightViaUnderlines = underlinePosInPx + 3 * lineThicknessInPx;

const auto cellWidth = gsl::narrow<u16>(std::ceil(advanceWidthInPx));
const auto cellHeight = gsl::narrow<u16>(std::ceil(baseline + descentInPx + halfGapInPx));
const auto cellHeight = gsl::narrow<u16>(std::max(cellHeightViaDescent, cellHeightViaUnderlines));

{
til::size coordSize;
Expand All @@ -637,13 +650,9 @@ void AtlasEngine::_resolveFontMetrics(const wchar_t* requestedFaceName, const Fo

if (fontMetrics)
{
const auto underlineOffsetInPx = static_cast<double>(-metrics.underlinePosition) * designUnitsPerPx;
const auto underlineThicknessInPx = static_cast<double>(metrics.underlineThickness) * designUnitsPerPx;
const auto strikethroughOffsetInPx = static_cast<double>(-metrics.strikethroughPosition) * designUnitsPerPx;
const auto strikethroughThicknessInPx = static_cast<double>(metrics.strikethroughThickness) * designUnitsPerPx;
const auto lineThickness = gsl::narrow<u16>(std::round(std::min(underlineThicknessInPx, strikethroughThicknessInPx)));
const auto underlinePos = gsl::narrow<u16>(std::ceil(baseline + underlineOffsetInPx - lineThickness / 2.0));
const auto strikethroughPos = gsl::narrow<u16>(std::round(baseline + strikethroughOffsetInPx - lineThickness / 2.0));
const auto lineThickness = gsl::narrow<u16>(lineThicknessInPx);
const auto underlinePos = gsl::narrow<u16>(underlinePosInPx);
const auto strikethroughPos = gsl::narrow<u16>(strikethroughPosInPx);

auto fontName = wil::make_process_heap_string(requestedFaceName);
const auto fontWeight = gsl::narrow<u16>(requestedWeight);
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/atlas/AtlasEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,7 @@ try
WI_SetFlagIf(flags, CellFlags::BorderTop, textAttributes.IsTopHorizontalDisplayed());
WI_SetFlagIf(flags, CellFlags::BorderRight, textAttributes.IsRightVerticalDisplayed());
WI_SetFlagIf(flags, CellFlags::BorderBottom, textAttributes.IsBottomHorizontalDisplayed());
WI_SetFlagIf(flags, CellFlags::Underline, textAttributes.IsUnderlined());
WI_SetFlagIf(flags, CellFlags::Underline, textAttributes.IsUnderlined() || textAttributes.IsDoublyUnderlined());
WI_SetFlagIf(flags, CellFlags::UnderlineDotted, hyperlinkId != 0);
WI_SetFlagIf(flags, CellFlags::UnderlineDouble, textAttributes.IsDoublyUnderlined());
WI_SetFlagIf(flags, CellFlags::Strikethrough, textAttributes.IsCrossedOut());
Expand Down Expand Up @@ -1003,7 +1003,7 @@ void AtlasEngine::_recreateFontDependentResources()
{
_r.underlinePos = _api.fontMetrics.underlinePos;
_r.strikethroughPos = _api.fontMetrics.strikethroughPos;
_r.lineThickness = _api.fontMetrics.lineThickness;
_r.lineWidth = _api.fontMetrics.lineThickness;
_r.dpi = _api.dpi;
}
{
Expand Down
8 changes: 5 additions & 3 deletions src/renderer/atlas/AtlasEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -823,8 +823,10 @@ namespace Microsoft::Console::Render
alignas(sizeof(f32)) f32 enhancedContrast = 0;
alignas(sizeof(u32)) u32 cellCountX = 0;
alignas(sizeof(u32x2)) u32x2 cellSize;
alignas(sizeof(u32x2)) u32x2 underlinePos;
alignas(sizeof(u32x2)) u32x2 strikethroughPos;
alignas(sizeof(u32)) u32 underlinePos = 0;
alignas(sizeof(u32)) u32 underlineDoublePos = 0;
alignas(sizeof(u32)) u32 strikethroughPos = 0;
alignas(sizeof(u32)) u32 lineWidth = 0;
alignas(sizeof(u32)) u32 backgroundColor = 0;
alignas(sizeof(u32)) u32 cursorColor = 0;
alignas(sizeof(u32)) u32 selectionColor = 0;
Expand Down Expand Up @@ -947,7 +949,7 @@ namespace Microsoft::Console::Render
u16x2 cellCount; // invalidated by ApiInvalidations::Font|Size, caches _api.cellCount
u16 underlinePos = 0;
u16 strikethroughPos = 0;
u16 lineThickness = 0;
u16 lineWidth = 0;
u16 dpi = USER_DEFAULT_SCREEN_DPI; // invalidated by ApiInvalidations::Font, caches _api.dpi
u16x2 atlasSizeInPixel; // invalidated by ApiInvalidations::Font
TileHashMap glyphs;
Expand Down
10 changes: 6 additions & 4 deletions src/renderer/atlas/AtlasEngine.r.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,12 @@ void AtlasEngine::_updateConstantBuffer() const noexcept
data.cellCountX = _r.cellCount.x;
data.cellSize.x = _r.cellSize.x;
data.cellSize.y = _r.cellSize.y;
data.underlinePos.x = _r.underlinePos;
data.underlinePos.y = _r.underlinePos + _r.lineThickness;
data.strikethroughPos.x = _r.strikethroughPos;
data.strikethroughPos.y = _r.strikethroughPos + _r.lineThickness;
data.underlinePos = _r.underlinePos;
// This logic should be kept in sync with AtlasEngine::_resolveFontMetrics,
// which reserves enough space so that the double underline is fully visible.
data.underlineDoublePos = _r.underlinePos + 2 * _r.lineWidth;
data.strikethroughPos = _r.strikethroughPos;
data.lineWidth = _r.lineWidth;
data.backgroundColor = _r.backgroundColor;
data.cursorColor = _r.cursorOptions.cursorColor;
data.selectionColor = _r.selectionColor;
Expand Down
50 changes: 29 additions & 21 deletions src/renderer/atlas/shader_ps.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,10 @@ cbuffer ConstBuffer : register(b0)
float enhancedContrast;
uint cellCountX;
uint2 cellSize;
uint2 underlinePos;
uint2 strikethroughPos;
uint underlinePos;
uint underlineDoublePos;
uint strikethroughPos;
uint lineWidth;
uint backgroundColor;
uint cursorColor;
uint selectionColor;
Expand Down Expand Up @@ -107,22 +109,7 @@ float4 main(float4 pos: SV_Position): SV_Target
}

// Layer 2:
// Step 1: Underlines
[branch] if (cell.flags & CellFlags_Underline)
{
[flatten] if (cellPos.y >= underlinePos.x && cellPos.y < underlinePos.y)
{
color = alphaBlendPremultiplied(color, fg);
}
}
[branch] if (cell.flags & CellFlags_UnderlineDotted)
{
[flatten] if (cellPos.y >= underlinePos.x && cellPos.y < underlinePos.y && (viewportPos.x / (underlinePos.y - underlinePos.x) & 3) == 0)
{
color = alphaBlendPremultiplied(color, fg);
}
}
// Step 2: The cell's glyph, potentially drawn in the foreground color
// Step 1: The cell's glyph, potentially drawn in the foreground color
{
float4 glyph = glyphs[decodeU16x2(cell.glyphPos) + cellPos];

Expand Down Expand Up @@ -152,10 +139,31 @@ float4 main(float4 pos: SV_Position): SV_Target
}
}
}
// Step 3: Lines, but not "under"lines
[branch] if (cell.flags & CellFlags_Strikethrough)
// Step 2: Lines
{
[flatten] if (cellPos.y >= strikethroughPos.x && cellPos.y < strikethroughPos.y)
// What a nice coincidence that we have exactly 8 flags to handle right now!
bool4x2 flags = {
cell.flags & CellFlags_BorderLeft,
cell.flags & CellFlags_BorderTop,
cell.flags & CellFlags_BorderRight,
cell.flags & CellFlags_BorderBottom,
cell.flags & CellFlags_Underline,
cell.flags & CellFlags_UnderlineDotted,
cell.flags & CellFlags_UnderlineDouble,
cell.flags & CellFlags_Strikethrough,
};
bool4x2 checks = {
cellPos < lineWidth,
(cellSize - cellPos) <= lineWidth,
// The following <lineWidth checks rely on underflow turning the
// uint into a way larger number than any reasonable lineWidth.
// That way we don't need to write `y >= lo && y < hi`.
(cellPos.y - underlinePos) < lineWidth,
(cellPos.y - underlineDoublePos) < lineWidth && (viewportPos.x / lineWidth & 3) == 0,
(cellPos.y - underlineDoublePos) < lineWidth,
(cellPos.y - strikethroughPos) < lineWidth,
};
[flatten] if (any(flags && checks))
{
color = alphaBlendPremultiplied(color, fg);
}
Expand Down

0 comments on commit 539618e

Please sign in to comment.