Hack to finally fix #738

Text rendering is now done in window coordinates corresponding to window
pixels to avoid floating-point rounding errors that show up as rendering
artifacts
dev-time-step
Piotr Dziwinski 2016-04-06 22:21:41 +12:00
parent c94ebb45e7
commit 71a77c77f6
4 changed files with 127 additions and 47 deletions

View File

@ -3789,9 +3789,7 @@ void CEngine::DrawInterface()
m_device->SetRenderState(RENDER_STATE_LIGHTING, false); m_device->SetRenderState(RENDER_STATE_LIGHTING, false);
m_device->SetRenderState(RENDER_STATE_FOG, false); m_device->SetRenderState(RENDER_STATE_FOG, false);
m_device->SetTransform(TRANSFORM_VIEW, m_matViewInterface); SetInterfaceCoordinates();
m_device->SetTransform(TRANSFORM_PROJECTION, m_matProjInterface);
m_device->SetTransform(TRANSFORM_WORLD, m_matWorldInterface);
// Force new state to disable lighting // Force new state to disable lighting
m_interfaceMode = true; m_interfaceMode = true;
@ -3890,9 +3888,7 @@ void CEngine::DrawInterface()
m_device->SetRenderMode(RENDER_MODE_INTERFACE); m_device->SetRenderMode(RENDER_MODE_INTERFACE);
m_device->SetTransform(TRANSFORM_VIEW, m_matViewInterface); SetInterfaceCoordinates();
m_device->SetTransform(TRANSFORM_PROJECTION, m_matProjInterface);
m_device->SetTransform(TRANSFORM_WORLD, m_matWorldInterface);
} }
// Draw foreground color // Draw foreground color
@ -5184,4 +5180,27 @@ void CEngine::SetDebugGotoBitmap(std::unique_ptr<CImage> debugImage)
UpdateGroundSpotTextures(); UpdateGroundSpotTextures();
} }
void CEngine::SetInterfaceCoordinates()
{
m_device->SetTransform(TRANSFORM_VIEW, m_matViewInterface);
m_device->SetTransform(TRANSFORM_PROJECTION, m_matProjInterface);
m_device->SetTransform(TRANSFORM_WORLD, m_matWorldInterface);
}
void CEngine::SetWindowCoordinates()
{
Math::Matrix matWorldWindow;
matWorldWindow.LoadIdentity();
Math::Matrix matViewWindow;
matViewWindow.LoadIdentity();
Math::Matrix matProjWindow;
Math::LoadOrthoProjectionMatrix(matProjWindow, 0.0f, m_size.x, m_size.y, 0.0f, -1.0f, 1.0f);
m_device->SetTransform(TRANSFORM_VIEW, matViewWindow);
m_device->SetTransform(TRANSFORM_PROJECTION, matProjWindow);
m_device->SetTransform(TRANSFORM_WORLD, matWorldWindow);
}
} // namespace Gfx } // namespace Gfx

View File

@ -1196,6 +1196,9 @@ public:
void AddDebugGotoLine(std::vector<Gfx::VertexCol> line); void AddDebugGotoLine(std::vector<Gfx::VertexCol> line);
void SetDebugGotoBitmap(std::unique_ptr<CImage> debugImage); void SetDebugGotoBitmap(std::unique_ptr<CImage> debugImage);
void SetWindowCoordinates();
void SetInterfaceCoordinates();
protected: protected:
//! Resets some states and flushes textures after device was changed (e.g. resoulution changed) //! Resets some states and flushes textures after device was changed (e.g. resoulution changed)
/** Instead of calling this directly, send EVENT_RESOLUTION_CHANGED event **/ /** Instead of calling this directly, send EVENT_RESOLUTION_CHANGED event **/

View File

@ -214,7 +214,9 @@ void CText::DrawText(const std::string &text, std::vector<FontMetaChar>::iterato
pos.x -= sw; pos.x -= sw;
} }
DrawString(text, format, end, size, pos, width, eol, color); Math::IntPoint intPos = m_engine->InterfaceToWindowCoords(pos);
int intWidth = width * m_engine->GetWindowSize().x;
DrawString(text, format, end, size, intPos, intWidth, eol, color);
} }
void CText::DrawText(const std::string &text, FontType font, void CText::DrawText(const std::string &text, FontType font,
@ -236,7 +238,9 @@ void CText::DrawText(const std::string &text, FontType font,
pos.x -= sw; pos.x -= sw;
} }
DrawString(text, font, size, pos, width, eol, color); Math::IntPoint intPos = m_engine->InterfaceToWindowCoords(pos);
int intWidth = width * m_engine->GetWindowSize().x;
DrawString(text, font, size, intPos, intWidth, eol, color);
} }
void CText::SizeText(const std::string &text, std::vector<FontMetaChar>::iterator format, void CText::SizeText(const std::string &text, std::vector<FontMetaChar>::iterator format,
@ -322,6 +326,14 @@ float CText::GetHeight(FontType font, float size)
return ifSize.y; return ifSize.y;
} }
int CText::GetHeightInt(FontType font, float size)
{
assert(font != FONT_BUTTON);
CachedFont* cf = GetOrOpenFont(font, size);
assert(cf != nullptr);
return TTF_FontHeight(cf->font);
}
float CText::GetStringWidth(const std::string &text, float CText::GetStringWidth(const std::string &text,
std::vector<FontMetaChar>::iterator format, std::vector<FontMetaChar>::iterator format,
@ -416,6 +428,46 @@ float CText::GetCharWidth(UTF8Char ch, FontType font, float size, float offset)
return charSize.x * width; return charSize.x * width;
} }
int CText::GetCharWidthInt(UTF8Char ch, FontType font, float size, float offset)
{
if (font == FONT_BUTTON)
{
Math::IntPoint windowSize = m_engine->GetWindowSize();
int height = GetHeightInt(FONT_COLOBOT, size);
int width = height*(static_cast<float>(windowSize.y)/windowSize.x);
return width;
}
int width = 1;
if (ch.c1 < 32 && ch.c1 >= 0)
{
if (ch.c1 == '\t')
width = m_tabSize;
// TODO: tab sizing at intervals?
ch.c1 = ':';
}
CachedFont* cf = GetOrOpenFont(font, size);
assert(cf != nullptr);
Math::IntPoint charSize;
auto it = cf->cache.find(ch);
if (it != cf->cache.end())
{
charSize = (*it).second.charSize;
}
else
{
std::string text;
text.append({ch.c1, ch.c2, ch.c3});
TTF_SizeUTF8(cf->font, text.c_str(), &charSize.x, &charSize.y);
}
return charSize.x * width;
}
int CText::Justify(const std::string &text, std::vector<FontMetaChar>::iterator format, int CText::Justify(const std::string &text, std::vector<FontMetaChar>::iterator format,
std::vector<FontMetaChar>::iterator end, std::vector<FontMetaChar>::iterator end,
@ -636,11 +688,11 @@ UTF8Char CText::TranslateSpecialChar(int specialChar)
void CText::DrawString(const std::string &text, std::vector<FontMetaChar>::iterator format, void CText::DrawString(const std::string &text, std::vector<FontMetaChar>::iterator format,
std::vector<FontMetaChar>::iterator end, std::vector<FontMetaChar>::iterator end,
float size, Math::Point pos, float width, int eol, Color color) float size, Math::IntPoint pos, int width, int eol, Color color)
{ {
m_engine->SetState(ENG_RSTATE_TEXT); m_engine->SetState(ENG_RSTATE_TEXT);
float start = pos.x; int start = pos.x;
unsigned int fmtIndex = 0; unsigned int fmtIndex = 0;
@ -654,12 +706,12 @@ void CText::DrawString(const std::string &text, std::vector<FontMetaChar>::itera
UTF8Char ch = *it; UTF8Char ch = *it;
float offset = pos.x - start; int offset = pos.x - start;
float cw = GetCharWidth(ch, font, size, offset); int cw = GetCharWidthInt(ch, font, size, offset);
if (offset + cw > width) // exceeds the maximum width? if (offset + cw > width) // exceeds the maximum width?
{ {
ch = TranslateSpecialChar(CHAR_SKIP_RIGHT); ch = TranslateSpecialChar(CHAR_SKIP_RIGHT);
cw = GetCharWidth(ch, font, size, offset); cw = GetCharWidthInt(ch, font, size, offset);
pos.x = start + width - cw; pos.x = start + width - cw;
color = Color(1.0f, 0.0f, 0.0f); color = Color(1.0f, 0.0f, 0.0f);
DrawCharAndAdjustPos(ch, font, size, pos, color); DrawCharAndAdjustPos(ch, font, size, pos, color);
@ -700,9 +752,9 @@ void CText::DrawString(const std::string &text, std::vector<FontMetaChar>::itera
} }
else else
{ {
Math::Point charSize; Math::IntPoint charSize;
charSize.x = GetCharWidth(ch, font, size, offset); charSize.x = GetCharWidthInt(ch, font, size, offset);
charSize.y = GetHeight(font, size); charSize.y = GetHeightInt(font, size);
DrawHighlight(hl, pos, charSize); DrawHighlight(hl, pos, charSize);
} }
} }
@ -788,7 +840,7 @@ void CText::StringToUTFCharList(const std::string &text, std::vector<UTF8Char> &
} }
void CText::DrawString(const std::string &text, FontType font, void CText::DrawString(const std::string &text, FontType font,
float size, Math::Point pos, float width, int eol, Color color) float size, Math::IntPoint pos, int width, int eol, Color color)
{ {
assert(font != FONT_BUTTON); assert(font != FONT_BUTTON);
@ -802,7 +854,7 @@ void CText::DrawString(const std::string &text, FontType font,
} }
} }
void CText::DrawHighlight(FontHighlight hl, Math::Point pos, Math::Point size) void CText::DrawHighlight(FontHighlight hl, Math::IntPoint pos, Math::IntPoint size)
{ {
// Gradient colors // Gradient colors
Color grad[4]; Color grad[4];
@ -827,9 +879,9 @@ void CText::DrawHighlight(FontHighlight hl, Math::Point pos, Math::Point size)
Math::IntPoint vsize = m_engine->GetWindowSize(); Math::IntPoint vsize = m_engine->GetWindowSize();
float h = 0.0f; float h = 0.0f;
if (vsize.y <= 768.0f) // 1024x768 or less? if (vsize.y <= 768.0f) // 1024x768 or less?
h = 1.01f / vsize.y; // 1 pixel h = 1.01f; // 1 pixel
else // more than 1024x768? else // more than 1024x768?
h = 2.0f / vsize.y; // 2 pixels h = 2.0f; // 2 pixels
Math::Point p1, p2; Math::Point p1, p2;
p1.x = pos.x; p1.x = pos.x;
@ -856,22 +908,24 @@ void CText::DrawHighlight(FontHighlight hl, Math::Point pos, Math::Point size)
VertexCol(Math::Vector(p2.x, p2.y, 0.0f), grad[1]) VertexCol(Math::Vector(p2.x, p2.y, 0.0f), grad[1])
}; };
m_engine->SetWindowCoordinates();
m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, quad, 4); m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, quad, 4);
m_engine->SetInterfaceCoordinates();
m_engine->AddStatisticTriangle(2); m_engine->AddStatisticTriangle(2);
m_device->SetTextureEnabled(0, true); m_device->SetTextureEnabled(0, true);
} }
void CText::DrawCharAndAdjustPos(UTF8Char ch, FontType font, float size, Math::Point &pos, Color color) void CText::DrawCharAndAdjustPos(UTF8Char ch, FontType font, float size, Math::IntPoint &pos, Color color)
{ {
if(font == FONT_BUTTON) if (font == FONT_BUTTON)
{ {
Math::IntPoint windowSize = m_engine->GetWindowSize(); Math::IntPoint windowSize = m_engine->GetWindowSize();
float height = GetHeight(FONT_COLOBOT, size); int height = GetHeightInt(FONT_COLOBOT, size);
float width = height*(static_cast<float>(windowSize.y)/windowSize.x); int width = height * (static_cast<float>(windowSize.y)/windowSize.x);
Math::Point p1(pos.x, pos.y); Math::IntPoint p1(pos.x, pos.y - height);
Math::Point p2(pos.x + width, pos.y + height); Math::IntPoint p2(pos.x + width, pos.y);
Math::Vector n(0.0f, 0.0f, -1.0f); // normal Math::Vector n(0.0f, 0.0f, -1.0f); // normal
@ -909,13 +963,15 @@ void CText::DrawCharAndAdjustPos(UTF8Char ch, FontType font, float size, Math::P
Vertex quad[4] = Vertex quad[4] =
{ {
Vertex(Math::Vector(p1.x, p1.y, 0.0f), n, Math::Point(uv1.x, uv2.y)), Vertex(Math::Vector(p1.x, p2.y, 0.0f), n, Math::Point(uv1.x, uv2.y)),
Vertex(Math::Vector(p1.x, p2.y, 0.0f), n, Math::Point(uv1.x, uv1.y)), Vertex(Math::Vector(p1.x, p1.y, 0.0f), n, Math::Point(uv1.x, uv1.y)),
Vertex(Math::Vector(p2.x, p1.y, 0.0f), n, Math::Point(uv2.x, uv2.y)), Vertex(Math::Vector(p2.x, p2.y, 0.0f), n, Math::Point(uv2.x, uv2.y)),
Vertex(Math::Vector(p2.x, p2.y, 0.0f), n, Math::Point(uv2.x, uv1.y)) Vertex(Math::Vector(p2.x, p1.y, 0.0f), n, Math::Point(uv2.x, uv1.y))
}; };
m_engine->SetWindowCoordinates();
m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, quad, 4, color); m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, quad, 4, color);
m_engine->SetInterfaceCoordinates();
m_engine->AddStatisticTriangle(2); m_engine->AddStatisticTriangle(2);
pos.x += width; pos.x += width;
@ -939,31 +995,31 @@ void CText::DrawCharAndAdjustPos(UTF8Char ch, FontType font, float size, Math::P
CharTexture tex = GetCharTexture(ch, font, size); CharTexture tex = GetCharTexture(ch, font, size);
Math::Point charInterfaceSize = m_engine->WindowToInterfaceSize(tex.charSize); Math::Point p1(pos.x, pos.y - tex.charSize.y);
Math::Point p2(pos.x + tex.charSize.x, pos.y);
Math::Point p1(pos.x, pos.y);
Math::Point p2(pos.x + charInterfaceSize.x, pos.y + charInterfaceSize.y);
const float halfPixelMargin = 0.5f; const float halfPixelMargin = 0.5f;
Math::Point texCoord1(static_cast<float>(tex.charPos.x + halfPixelMargin) / FONT_TEXTURE_SIZE.x, Math::Point texCoord1(static_cast<float>(tex.charPos.x + halfPixelMargin) / FONT_TEXTURE_SIZE.x,
static_cast<float>(tex.charPos.y + halfPixelMargin) / FONT_TEXTURE_SIZE.y); static_cast<float>(tex.charPos.y + halfPixelMargin) / FONT_TEXTURE_SIZE.y);
Math::Point texCoord2(static_cast<float>(tex.charPos.x + tex.charSize.x + halfPixelMargin) / FONT_TEXTURE_SIZE.x, Math::Point texCoord2(static_cast<float>(tex.charPos.x + tex.charSize.x - halfPixelMargin) / FONT_TEXTURE_SIZE.x,
static_cast<float>(tex.charPos.y + tex.charSize.y + halfPixelMargin) / FONT_TEXTURE_SIZE.y); static_cast<float>(tex.charPos.y + tex.charSize.y - halfPixelMargin) / FONT_TEXTURE_SIZE.y);
Math::Vector n(0.0f, 0.0f, -1.0f); // normal Math::Vector n(0.0f, 0.0f, -1.0f); // normal
Vertex quad[4] = Vertex quad[4] =
{ {
Vertex(Math::Vector(p1.x, p1.y, 0.0f), n, Math::Point(texCoord1.x, texCoord2.y)), Vertex(Math::Vector(p1.x, p2.y, 0.0f), n, Math::Point(texCoord1.x, texCoord2.y)),
Vertex(Math::Vector(p1.x, p2.y, 0.0f), n, Math::Point(texCoord1.x, texCoord1.y)), Vertex(Math::Vector(p1.x, p1.y, 0.0f), n, Math::Point(texCoord1.x, texCoord1.y)),
Vertex(Math::Vector(p2.x, p1.y, 0.0f), n, Math::Point(texCoord2.x, texCoord2.y)), Vertex(Math::Vector(p2.x, p2.y, 0.0f), n, Math::Point(texCoord2.x, texCoord2.y)),
Vertex(Math::Vector(p2.x, p2.y, 0.0f), n, Math::Point(texCoord2.x, texCoord1.y)) Vertex(Math::Vector(p2.x, p1.y, 0.0f), n, Math::Point(texCoord2.x, texCoord1.y))
}; };
m_device->SetTexture(0, tex.id); m_device->SetTexture(0, tex.id);
m_engine->SetWindowCoordinates();
m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, quad, 4, color); m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, quad, 4, color);
m_engine->SetInterfaceCoordinates();
m_engine->AddStatisticTriangle(2); m_engine->AddStatisticTriangle(2);
pos.x += charInterfaceSize.x * width; pos.x += tex.charSize.x * width;
} }
} }
@ -1063,8 +1119,8 @@ CharTexture CText::CreateCharTexture(UTF8Char ch, CachedFont* font)
} }
const int pixelMargin = 1; const int pixelMargin = 1;
Math::IntPoint tileSize(Math::NextPowerOfTwo(textSurface->w) + pixelMargin, Math::IntPoint tileSize(Math::Max(16, Math::NextPowerOfTwo(textSurface->w)) + pixelMargin,
Math::NextPowerOfTwo(textSurface->h) + pixelMargin); Math::Max(16, Math::NextPowerOfTwo(textSurface->h)) + pixelMargin);
FontTexture* fontTexture = GetOrCreateFontTexture(tileSize); FontTexture* fontTexture = GetOrCreateFontTexture(tileSize);

View File

@ -281,6 +281,7 @@ public:
float GetDescent(FontType font, float size); float GetDescent(FontType font, float size);
//! Returns the height font metric //! Returns the height font metric
float GetHeight(FontType font, float size); float GetHeight(FontType font, float size);
int GetHeightInt(FontType font, float size);
//! Returns width of string (multi-format) //! Returns width of string (multi-format)
TEST_VIRTUAL float GetStringWidth(const std::string& text, TEST_VIRTUAL float GetStringWidth(const std::string& text,
@ -290,6 +291,7 @@ public:
TEST_VIRTUAL float GetStringWidth(std::string text, FontType font, float size); TEST_VIRTUAL float GetStringWidth(std::string text, FontType font, float size);
//! Returns width of single character //! Returns width of single character
TEST_VIRTUAL float GetCharWidth(UTF8Char ch, FontType font, float size, float offset); TEST_VIRTUAL float GetCharWidth(UTF8Char ch, FontType font, float size, float offset);
int GetCharWidthInt(UTF8Char ch, FontType font, float size, float offset);
//! Justifies a line of text (multi-format) //! Justifies a line of text (multi-format)
int Justify(const std::string &text, std::vector<FontMetaChar>::iterator format, int Justify(const std::string &text, std::vector<FontMetaChar>::iterator format,
@ -319,11 +321,11 @@ protected:
void DrawString(const std::string &text, std::vector<FontMetaChar>::iterator format, void DrawString(const std::string &text, std::vector<FontMetaChar>::iterator format,
std::vector<FontMetaChar>::iterator end, std::vector<FontMetaChar>::iterator end,
float size, Math::Point pos, float width, int eol, Color color); float size, Math::IntPoint pos, int width, int eol, Color color);
void DrawString(const std::string &text, FontType font, void DrawString(const std::string &text, FontType font,
float size, Math::Point pos, float width, int eol, Color color); float size, Math::IntPoint pos, int width, int eol, Color color);
void DrawHighlight(FontHighlight hl, Math::Point pos, Math::Point size); void DrawHighlight(FontHighlight hl, Math::IntPoint pos, Math::IntPoint size);
void DrawCharAndAdjustPos(UTF8Char ch, FontType font, float size, Math::Point &pos, Color color); void DrawCharAndAdjustPos(UTF8Char ch, FontType font, float size, Math::IntPoint &pos, Color color);
void StringToUTFCharList(const std::string &text, std::vector<UTF8Char> &chars); void StringToUTFCharList(const std::string &text, std::vector<UTF8Char> &chars);
void StringToUTFCharList(const std::string &text, std::vector<UTF8Char> &chars, std::vector<FontMetaChar>::iterator format, std::vector<FontMetaChar>::iterator end); void StringToUTFCharList(const std::string &text, std::vector<UTF8Char> &chars, std::vector<FontMetaChar>::iterator format, std::vector<FontMetaChar>::iterator end);