bool CText::Create() { if (TTF_Init() != 0) { m_error = std::string("TTF_Init error: ") + std::string(TTF_GetError()); return false; } m_fonts[FONT_COLOBOT] = new MultisizeFont("fonts/dvu_sans.ttf"); m_fonts[FONT_COLOBOT_BOLD] = new MultisizeFont("fonts/dvu_sans_bold.ttf"); m_fonts[FONT_COLOBOT_ITALIC] = new MultisizeFont("fonts/dvu_sans_italic.ttf"); m_fonts[FONT_COURIER] = new MultisizeFont("fonts/dvu_sans_mono.ttf"); m_fonts[FONT_COURIER_BOLD] = new MultisizeFont("fonts/dvu_sans_mono_bold.ttf"); for (auto it = m_fonts.begin(); it != m_fonts.end(); ++it) { FontType type = (*it).first; CachedFont* cf = GetOrOpenFont(type, m_defaultSize); if (cf == nullptr || cf->font == nullptr) return false; } return true; }
void CText::DrawCharAndAdjustPos(UTF8Char ch, FontType font, float size, Math::Point &pos, Color color) { // TODO: if (font == FONT_BUTTON) if (font == FONT_BUTTON) return; // TODO: special chars? CachedFont* cf = GetOrOpenFont(font, size); if (cf == nullptr) return; int width = 1; if (ch.c1 > 0 && ch.c1 < 32) { // FIXME add support for chars with code 9 10 23 if (ch.c1 == '\t') { ch.c1 = ':'; width = 4; } else { ch.c1 = ' '; } ch.c2 = 0; ch.c3 = 0; } auto it = cf->cache.find(ch); CharTexture tex; if (it != cf->cache.end()) { tex = (*it).second; } else { tex = CreateCharTexture(ch, cf); if (tex.id == 0) // invalid return; cf->cache[ch] = tex; } Math::Point p1(pos.x, pos.y + tex.charSize.y - tex.texSize.y); Math::Point p2(pos.x + tex.texSize.x, pos.y + tex.charSize.y); Math::Vector n(0.0f, 0.0f, -1.0f); // normal Vertex quad[4] = { Vertex(Math::Vector(p1.x, p1.y, 0.0f), n, Math::Point(0.0f, 1.0f)), Vertex(Math::Vector(p1.x, p2.y, 0.0f), n, Math::Point(0.0f, 0.0f)), Vertex(Math::Vector(p2.x, p1.y, 0.0f), n, Math::Point(1.0f, 1.0f)), Vertex(Math::Vector(p2.x, p2.y, 0.0f), n, Math::Point(1.0f, 0.0f)) }; m_device->SetTexture(0, tex.id); m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, quad, 4, color); m_engine->AddStatisticTriangle(2); pos.x += tex.charSize.x * width; }
float CText::GetHeight(FontType font, float size) { assert(font != FONT_BUTTON); CachedFont* cf = GetOrOpenFont(font, size); assert(cf != nullptr); Math::IntPoint wndSize; wndSize.y = TTF_FontHeight(cf->font); Math::Point ifSize = m_engine->WindowToInterfaceSize(wndSize); return ifSize.y; }
float CText::GetStringWidth(const std::string &text, FontType font, float size) { assert(font != FONT_BUTTON); // TODO: special chars? CachedFont* cf = GetOrOpenFont(font, size); assert(cf != nullptr); Math::IntPoint wndSize; TTF_SizeUTF8(cf->font, text.c_str(), &wndSize.x, &wndSize.y); Math::Point ifSize = m_engine->WindowToInterfaceSize(wndSize); return ifSize.x; }
float CText::GetStringWidth(std::string text, FontType font, float size) { assert(font != FONT_BUTTON); // Skip special chars for (char& c : text) { if (c < 32 && c >= 0) c = ':'; } CachedFont* cf = GetOrOpenFont(font, size); assert(cf != nullptr); Math::IntPoint wndSize; TTF_SizeUTF8(cf->font, text.c_str(), &wndSize.x, &wndSize.y); Math::Point ifSize = m_engine->WindowToInterfaceSize(wndSize); return ifSize.x; }
float CText::GetCharWidth(UTF8Char ch, FontType font, float size, float offset) { // TODO: if (font == FONT_BUTTON) if (font == FONT_BUTTON) return 0.0f; // TODO: special chars? // TODO: tab sizing CachedFont* cf = GetOrOpenFont(font, size); assert(cf != nullptr); CharTexture tex; auto it = cf->cache.find(ch); if (it != cf->cache.end()) tex = (*it).second; else tex = CreateCharTexture(ch, cf); return tex.charSize.x; }
float CText::GetCharWidth(UTF8Char ch, FontType font, float size, float offset) { if (font == FONT_BUTTON) { Math::IntPoint windowSize = m_engine->GetWindowSize(); float height = GetHeight(FONT_COLOBOT, size); float 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::Point charSize; auto it = cf->cache.find(ch); if (it != cf->cache.end()) { charSize = (*it).second.charSize; } else { Math::IntPoint wndSize; std::string text; text.append({ch.c1, ch.c2, ch.c3}); TTF_SizeUTF8(cf->font, text.c_str(), &wndSize.x, &wndSize.y); charSize = m_engine->WindowToInterfaceSize(wndSize); } return charSize.x * width; }
void CText::DrawCharAndAdjustPos(UTF8Char ch, FontType font, float size, Math::Point &pos, Color color) { if(font == FONT_BUTTON) { Math::IntPoint windowSize = m_engine->GetWindowSize(); float height = GetHeight(FONT_COLOBOT, size); float width = height*(static_cast<float>(windowSize.y)/windowSize.x); Math::Point p1(pos.x, pos.y); Math::Point p2(pos.x + width, pos.y + height); Math::Vector n(0.0f, 0.0f, -1.0f); // normal // For whatever reason ch.c1 is a SIGNED char, we need to fix that unsigned char icon = static_cast<unsigned char>(ch.c1); if ( icon >= 192 ) { icon -= 192; m_engine->SetTexture("textures/interface/text.png"); m_engine->SetState(ENG_RSTATE_TTEXTURE_WHITE); } else if ( icon >= 128 ) { icon -= 128; m_engine->SetTexture("textures/interface/button3.png"); m_engine->SetState(ENG_RSTATE_TTEXTURE_WHITE); } else if ( icon >= 64 ) { icon -= 64; m_engine->SetTexture("textures/interface/button2.png"); m_engine->SetState(ENG_RSTATE_TTEXTURE_WHITE); } else { m_engine->SetTexture("textures/interface/button1.png"); m_engine->SetState(ENG_RSTATE_TTEXTURE_WHITE); } Math::Point uv1, uv2; uv1.x = (32.0f / 256.0f) * (icon%8); uv1.y = (32.0f / 256.0f) * (icon/8); uv2.x = (32.0f / 256.0f) + uv1.x; uv2.y = (32.0f / 256.0f) + uv1.y; float dp = 0.5f / 256.0f; uv1.x += dp; uv1.y += dp; uv2.x -= dp; uv2.y -= dp; 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, 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, uv1.y)) }; m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, quad, 4, color); m_engine->AddStatisticTriangle(2); pos.x += width; // Don't forget to restore the state! m_engine->SetState(ENG_RSTATE_TEXT); } else { CachedFont* cf = GetOrOpenFont(font, size); if (cf == nullptr) return; int width = 1; if (ch.c1 > 0 && ch.c1 < 32) { if (ch.c1 == '\t') width = m_tabSize; ch = TranslateSpecialChar(ch.c1); } auto it = cf->cache.find(ch); CharTexture tex; if (it != cf->cache.end()) { tex = (*it).second; } else { tex = CreateCharTexture(ch, cf); if (tex.id == 0) // invalid return; cf->cache[ch] = tex; } Math::Point p1(pos.x, pos.y + tex.charSize.y - tex.texSize.y); Math::Point p2(pos.x + tex.texSize.x, pos.y + tex.charSize.y); Math::Vector n(0.0f, 0.0f, -1.0f); // normal Vertex quad[4] = { Vertex(Math::Vector(p1.x, p1.y, 0.0f), n, Math::Point(0.0f, 1.0f)), Vertex(Math::Vector(p1.x, p2.y, 0.0f), n, Math::Point(0.0f, 0.0f)), Vertex(Math::Vector(p2.x, p1.y, 0.0f), n, Math::Point(1.0f, 1.0f)), Vertex(Math::Vector(p2.x, p2.y, 0.0f), n, Math::Point(1.0f, 0.0f)) }; m_device->SetTexture(0, tex.id); m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, quad, 4, color); m_engine->AddStatisticTriangle(2); pos.x += tex.charSize.x * width; } }