mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 01:58:19 +00:00
Improve text line spacing and console text selection
Consider line spacing to belong to the previous line when calculating and rendering text selection. Instead of handling spacing between entries separately in the console, also include line spacing for the last line in the height calculation. Pixel align the line spacing in addition to the font size, as previously some gaps between the entries were larger than others due to missing pixel alignment. This allows rendering the text selection in the console smoothly without any gaps between the console entries/lines. Closes #7617.
This commit is contained in:
parent
c9b2872459
commit
4c223a0002
|
@ -1268,7 +1268,9 @@ public:
|
||||||
pCursor->m_GlyphCount = 0;
|
pCursor->m_GlyphCount = 0;
|
||||||
pCursor->m_CharCount = 0;
|
pCursor->m_CharCount = 0;
|
||||||
pCursor->m_MaxLines = 0;
|
pCursor->m_MaxLines = 0;
|
||||||
|
|
||||||
pCursor->m_LineSpacing = 0;
|
pCursor->m_LineSpacing = 0;
|
||||||
|
pCursor->m_AlignedLineSpacing = 0;
|
||||||
|
|
||||||
pCursor->m_StartX = x;
|
pCursor->m_StartX = x;
|
||||||
pCursor->m_StartY = y;
|
pCursor->m_StartY = y;
|
||||||
|
@ -1481,7 +1483,7 @@ public:
|
||||||
const float CursorY = round_to_int(pCursor->m_Y * FakeToScreen.y) / FakeToScreen.y;
|
const float CursorY = round_to_int(pCursor->m_Y * FakeToScreen.y) / FakeToScreen.y;
|
||||||
const int ActualSize = round_truncate(pCursor->m_FontSize * FakeToScreen.y);
|
const int ActualSize = round_truncate(pCursor->m_FontSize * FakeToScreen.y);
|
||||||
pCursor->m_AlignedFontSize = ActualSize / FakeToScreen.y;
|
pCursor->m_AlignedFontSize = ActualSize / FakeToScreen.y;
|
||||||
const float LineSpacing = pCursor->m_LineSpacing;
|
pCursor->m_AlignedLineSpacing = round_truncate(pCursor->m_LineSpacing * FakeToScreen.y) / FakeToScreen.y;
|
||||||
|
|
||||||
// string length
|
// string length
|
||||||
if(Length < 0)
|
if(Length < 0)
|
||||||
|
@ -1539,38 +1541,34 @@ public:
|
||||||
const auto &&CheckInsideChar = [&](bool CheckOuter, vec2 CursorPos, float LastCharX, float LastCharWidth, float CharX, float CharWidth, float CharY) -> bool {
|
const auto &&CheckInsideChar = [&](bool CheckOuter, vec2 CursorPos, float LastCharX, float LastCharWidth, float CharX, float CharWidth, float CharY) -> bool {
|
||||||
return (LastCharX - LastCharWidth / 2 <= CursorPos.x &&
|
return (LastCharX - LastCharWidth / 2 <= CursorPos.x &&
|
||||||
CharX + CharWidth / 2 > CursorPos.x &&
|
CharX + CharWidth / 2 > CursorPos.x &&
|
||||||
CharY - pCursor->m_AlignedFontSize - LineSpacing <= CursorPos.y &&
|
CursorPos.y >= CharY - pCursor->m_AlignedFontSize &&
|
||||||
CharY + LineSpacing > CursorPos.y) ||
|
CursorPos.y < CharY + pCursor->m_AlignedLineSpacing) ||
|
||||||
(CheckOuter &&
|
(CheckOuter &&
|
||||||
CharY - pCursor->m_AlignedFontSize + LineSpacing > CursorPos.y);
|
CursorPos.y <= CharY - pCursor->m_AlignedFontSize);
|
||||||
};
|
};
|
||||||
const auto &&CheckSelectionStart = [&](bool CheckOuter, vec2 CursorPos, int &SelectionChar, bool &SelectionUsedCase, float LastCharX, float LastCharWidth, float CharX, float CharWidth, float CharY) {
|
const auto &&CheckSelectionStart = [&](bool CheckOuter, vec2 CursorPos, int &SelectionChar, bool &SelectionUsedCase, float LastCharX, float LastCharWidth, float CharX, float CharWidth, float CharY) {
|
||||||
if(!SelectionStarted && !SelectionUsedCase)
|
if(!SelectionStarted && !SelectionUsedCase &&
|
||||||
|
CheckInsideChar(CheckOuter, CursorPos, LastCharX, LastCharWidth, CharX, CharWidth, CharY))
|
||||||
{
|
{
|
||||||
if(CheckInsideChar(CheckOuter, CursorPos, LastCharX, LastCharWidth, CharX, CharWidth, CharY))
|
SelectionChar = pCursor->m_GlyphCount;
|
||||||
{
|
SelectionStarted = !SelectionStarted;
|
||||||
SelectionChar = pCursor->m_GlyphCount;
|
SelectionUsedCase = true;
|
||||||
SelectionStarted = !SelectionStarted;
|
|
||||||
SelectionUsedCase = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const auto &&CheckOutsideChar = [&](bool CheckOuter, vec2 CursorPos, float CharX, float CharWidth, float CharY) -> bool {
|
const auto &&CheckOutsideChar = [&](bool CheckOuter, vec2 CursorPos, float CharX, float CharWidth, float CharY) -> bool {
|
||||||
return (CharX + CharWidth / 2 > CursorPos.x &&
|
return (CharX + CharWidth / 2 > CursorPos.x &&
|
||||||
CharY - pCursor->m_AlignedFontSize - LineSpacing <= CursorPos.y &&
|
CursorPos.y >= CharY - pCursor->m_AlignedFontSize &&
|
||||||
CharY + LineSpacing > CursorPos.y) ||
|
CursorPos.y < CharY + pCursor->m_AlignedLineSpacing) ||
|
||||||
(CheckOuter &&
|
(CheckOuter &&
|
||||||
CharY - LineSpacing <= CursorPos.y);
|
CursorPos.y >= CharY + pCursor->m_AlignedLineSpacing);
|
||||||
};
|
};
|
||||||
const auto &&CheckSelectionEnd = [&](bool CheckOuter, vec2 CursorPos, int &SelectionChar, bool &SelectionUsedCase, float CharX, float CharWidth, float CharY) {
|
const auto &&CheckSelectionEnd = [&](bool CheckOuter, vec2 CursorPos, int &SelectionChar, bool &SelectionUsedCase, float CharX, float CharWidth, float CharY) {
|
||||||
if(SelectionStarted && !SelectionUsedCase)
|
if(SelectionStarted && !SelectionUsedCase &&
|
||||||
|
CheckOutsideChar(CheckOuter, CursorPos, CharX, CharWidth, CharY))
|
||||||
{
|
{
|
||||||
if(CheckOutsideChar(CheckOuter, CursorPos, CharX, CharWidth, CharY))
|
SelectionChar = pCursor->m_GlyphCount;
|
||||||
{
|
SelectionStarted = !SelectionStarted;
|
||||||
SelectionChar = pCursor->m_GlyphCount;
|
SelectionUsedCase = true;
|
||||||
SelectionStarted = !SelectionStarted;
|
|
||||||
SelectionUsedCase = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1585,7 +1583,7 @@ public:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
DrawX = pCursor->m_StartX;
|
DrawX = pCursor->m_StartX;
|
||||||
DrawY += pCursor->m_AlignedFontSize + pCursor->m_LineSpacing;
|
DrawY += pCursor->m_AlignedFontSize + pCursor->m_AlignedLineSpacing;
|
||||||
if((RenderFlags & TEXT_RENDER_FLAG_NO_PIXEL_ALIGMENT) == 0)
|
if((RenderFlags & TEXT_RENDER_FLAG_NO_PIXEL_ALIGMENT) == 0)
|
||||||
{
|
{
|
||||||
DrawX = round_to_int(DrawX * FakeToScreen.x) / FakeToScreen.x; // realign
|
DrawX = round_to_int(DrawX * FakeToScreen.x) / FakeToScreen.x; // realign
|
||||||
|
@ -1868,7 +1866,8 @@ public:
|
||||||
|
|
||||||
if(SelectionStarted && IsRendered)
|
if(SelectionStarted && IsRendered)
|
||||||
{
|
{
|
||||||
vSelectionQuads.emplace_back(SelX, DrawY + (1.0f - pCursor->m_SelectionHeightFactor) * pCursor->m_AlignedFontSize, SelWidth, pCursor->m_SelectionHeightFactor * pCursor->m_AlignedFontSize);
|
const float SelectionHeight = pCursor->m_AlignedFontSize + pCursor->m_AlignedLineSpacing;
|
||||||
|
vSelectionQuads.emplace_back(SelX, DrawY + (1.0f - pCursor->m_SelectionHeightFactor) * SelectionHeight, SelWidth, pCursor->m_SelectionHeightFactor * SelectionHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
LastSelX = SelX;
|
LastSelX = SelX;
|
||||||
|
@ -1957,9 +1956,9 @@ public:
|
||||||
if(TextContainer.m_StringInfo.m_SelectionQuadContainerIndex == -1)
|
if(TextContainer.m_StringInfo.m_SelectionQuadContainerIndex == -1)
|
||||||
TextContainer.m_StringInfo.m_SelectionQuadContainerIndex = Graphics()->CreateQuadContainer(false);
|
TextContainer.m_StringInfo.m_SelectionQuadContainerIndex = Graphics()->CreateQuadContainer(false);
|
||||||
if(HasCursor)
|
if(HasCursor)
|
||||||
Graphics()->QuadContainerAddQuads(TextContainer.m_StringInfo.m_SelectionQuadContainerIndex, aCursorQuads, 2);
|
Graphics()->QuadContainerAddQuads(TextContainer.m_StringInfo.m_SelectionQuadContainerIndex, aCursorQuads, std::size(aCursorQuads));
|
||||||
if(HasSelection)
|
if(HasSelection)
|
||||||
Graphics()->QuadContainerAddQuads(TextContainer.m_StringInfo.m_SelectionQuadContainerIndex, vSelectionQuads.data(), (int)vSelectionQuads.size());
|
Graphics()->QuadContainerAddQuads(TextContainer.m_StringInfo.m_SelectionQuadContainerIndex, vSelectionQuads.data(), vSelectionQuads.size());
|
||||||
Graphics()->QuadContainerUpload(TextContainer.m_StringInfo.m_SelectionQuadContainerIndex);
|
Graphics()->QuadContainerUpload(TextContainer.m_StringInfo.m_SelectionQuadContainerIndex);
|
||||||
|
|
||||||
TextContainer.m_HasCursor = HasCursor;
|
TextContainer.m_HasCursor = HasCursor;
|
||||||
|
|
|
@ -212,6 +212,7 @@ public:
|
||||||
float m_FontSize;
|
float m_FontSize;
|
||||||
float m_AlignedFontSize;
|
float m_AlignedFontSize;
|
||||||
float m_LineSpacing;
|
float m_LineSpacing;
|
||||||
|
float m_AlignedLineSpacing;
|
||||||
|
|
||||||
ETextCursorSelectionMode m_CalculateSelectionMode;
|
ETextCursorSelectionMode m_CalculateSelectionMode;
|
||||||
float m_SelectionHeightFactor;
|
float m_SelectionHeightFactor;
|
||||||
|
@ -237,7 +238,7 @@ public:
|
||||||
|
|
||||||
float Height() const
|
float Height() const
|
||||||
{
|
{
|
||||||
return m_LineCount * m_AlignedFontSize + std::max(0, m_LineCount - 1) * m_LineSpacing;
|
return m_LineCount * (m_AlignedFontSize + m_AlignedLineSpacing);
|
||||||
}
|
}
|
||||||
|
|
||||||
STextBoundingBox BoundingBox() const
|
STextBoundingBox BoundingBox() const
|
||||||
|
|
|
@ -575,7 +575,7 @@ void CGameConsole::CInstance::UpdateEntryTextAttributes(CBacklogEntry *pEntry) c
|
||||||
Cursor.m_MaxLines = 10;
|
Cursor.m_MaxLines = 10;
|
||||||
Cursor.m_LineSpacing = LINE_SPACING;
|
Cursor.m_LineSpacing = LINE_SPACING;
|
||||||
m_pGameConsole->TextRender()->TextEx(&Cursor, pEntry->m_aText, -1);
|
m_pGameConsole->TextRender()->TextEx(&Cursor, pEntry->m_aText, -1);
|
||||||
pEntry->m_YOffset = Cursor.Height() + LINE_SPACING;
|
pEntry->m_YOffset = Cursor.Height();
|
||||||
pEntry->m_LineCount = Cursor.m_LineCount;
|
pEntry->m_LineCount = Cursor.m_LineCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -909,9 +909,9 @@ void CGameConsole::OnRender()
|
||||||
|
|
||||||
{
|
{
|
||||||
// Get height of 1 line
|
// Get height of 1 line
|
||||||
float LineHeight = TextRender()->TextBoundingBox(FONT_SIZE, " ", -1, -1, LINE_SPACING).m_H + LINE_SPACING;
|
float LineHeight = TextRender()->TextBoundingBox(FONT_SIZE, " ", -1, -1, LINE_SPACING).m_H;
|
||||||
|
|
||||||
float RowHeight = FONT_SIZE * 1.25f;
|
float RowHeight = FONT_SIZE * 1.5f;
|
||||||
float x = 3;
|
float x = 3;
|
||||||
float y = ConsoleHeight - RowHeight - 5.0f;
|
float y = ConsoleHeight - RowHeight - 5.0f;
|
||||||
|
|
||||||
|
@ -1104,8 +1104,7 @@ void CGameConsole::OnRender()
|
||||||
|
|
||||||
if(First)
|
if(First)
|
||||||
{
|
{
|
||||||
int Diff = pConsole->m_BacklogLastActiveLine - SkippedLines;
|
OffsetY -= (pConsole->m_BacklogLastActiveLine - SkippedLines) * LineHeight;
|
||||||
OffsetY -= Diff * LineHeight - LINE_SPACING;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float LocalOffsetY = OffsetY + pEntry->m_YOffset / (float)pEntry->m_LineCount;
|
float LocalOffsetY = OffsetY + pEntry->m_YOffset / (float)pEntry->m_LineCount;
|
||||||
|
|
Loading…
Reference in a new issue