Compare commits

...

1 Commits

Author SHA1 Message Date
Leonard Hecker
8d4f242218 Improve appearance of curly underlines 2024-10-21 21:53:58 +02:00
3 changed files with 11 additions and 20 deletions

View File

@@ -298,13 +298,11 @@ void BackendD3D::_updateFontDependents(const RenderingPayload& p)
{
const int cellHeight = font.cellSize.y;
const int duTop = font.doubleUnderline[0].position;
const int duBottom = font.doubleUnderline[1].position;
const int duHeight = font.doubleUnderline[0].height;
// This gives it the same position and height as our double-underline. There's no particular reason for that, apart from
// it being simple to implement and robust against more peculiar fonts with unusually large/small descenders, etc.
// We still need to ensure though that it doesn't clip out of the cellHeight at the bottom, which is why `position` has a min().
const auto height = std::max(3, duBottom + duHeight - duTop);
// We want 1 period per cell. Calculating the corresponding height is simple.
// The height must be rounded to give the extrema a crisp look. We still need to ensure though
// that it doesn't clip out of the cellHeight at the bottom, which is why `position` has a min().
const auto height = std::max(3, static_cast<int>(lroundf(font.cellSize.x / 3.14159265359f)));
const auto position = std::min(duTop, cellHeight - height);
_curlyLineHalfHeight = height * 0.5f;
@@ -586,7 +584,6 @@ void BackendD3D::_recreateConstBuffer(const RenderingPayload& p) const
DWrite_GetGammaRatios(_gamma, data.gammaRatios);
data.enhancedContrast = p.s->font->antialiasingMode == AntialiasingMode::ClearType ? _cleartypeEnhancedContrast : _grayscaleEnhancedContrast;
data.underlineWidth = p.s->font->underline.height;
data.doubleUnderlineWidth = p.s->font->doubleUnderline[0].height;
data.curlyLineHalfHeight = _curlyLineHalfHeight;
data.shadedGlyphDotSize = std::max(1.0f, std::roundf(std::max(p.s->font->cellSize.x / 16.0f, p.s->font->cellSize.y / 32.0f)));
p.deviceContext->UpdateSubresource(_psConstantBuffer.get(), 0, nullptr, &data, 0, 0);

View File

@@ -42,7 +42,6 @@ namespace Microsoft::Console::Render::Atlas
alignas(sizeof(f32x4)) f32 gammaRatios[4]{};
alignas(sizeof(f32)) f32 enhancedContrast = 0;
alignas(sizeof(f32)) f32 underlineWidth = 0;
alignas(sizeof(f32)) f32 doubleUnderlineWidth = 0;
alignas(sizeof(f32)) f32 curlyLineHalfHeight = 0;
alignas(sizeof(f32)) f32 shadedGlyphDotSize = 0;
#pragma warning(suppress : 4324) // 'PSConstBuffer': structure was padded due to alignment specifier

View File

@@ -12,7 +12,6 @@ cbuffer ConstBuffer : register(b0)
float4 gammaRatios;
float enhancedContrast;
float underlineWidth;
float doubleUnderlineWidth;
float curlyLineHalfHeight;
float shadedGlyphDotSize;
}
@@ -171,19 +170,15 @@ Output main(PSData data) : SV_Target
}
case SHADING_TYPE_CURLY_LINE:
{
// The curly line has the same thickness as a double underline.
// We halve it to make the math a bit easier.
float strokeWidthHalf = doubleUnderlineWidth * data.renditionScale.y * 0.5f;
// The curly line has the same thickness as an underline.
// We halve it to get the stroke width and make the math a bit easier.
float strokeWidthHalf = underlineWidth * data.renditionScale.y * 0.5f;
float center = curlyLineHalfHeight * data.renditionScale.y;
float amplitude = center - strokeWidthHalf;
// We multiply the frequency by pi/2 to get a sine wave which has an integer period.
// This makes every period of the wave look exactly the same.
float frequency = 1.57079632679489661923f / (curlyLineHalfHeight * data.renditionScale.x);
// At very small sizes, like when the wave is just 3px tall and 1px wide, it'll look too fat and/or blurry.
// Because we multiplied our frequency with pi, the extrema of the curve and its intersections with the
// centerline always occur right between two pixels. This causes both to be lit with the same color.
// By adding a small phase shift, we can break this symmetry up. It'll make the wave look a lot more crispy.
float phase = 1.57079632679489661923f;
// This calculates a frequency that results in one 1 period per cell.
float frequency = (4.0f * 1.57079632679489661923f) / (backgroundCellSize.x * data.renditionScale.x);
// This shifts the wave so that the peak is in the middle of the cell.
float phase = 3.0f * 1.57079632679489661923f;
float sine = sin(data.position.x * frequency + phase);
// We use the distance to the sine curve as its alpha value - the closer the more opaque.
// To give it a smooth appearance we don't want to simply calculate the vertical distance to the curve: