else { m_staticCache.Lookup(staticPos, colors, text, rawAlignment, maxPixelWidth, scrolling, XbmcThreads::SystemClockMillis(), dirtyCache) = *static_cast<CGUIFontCacheStaticValue *>(&tempVertices); /* Append the new vertices to the set collected since the first Begin() call */ m_vertex.insert(m_vertex.end(), tempVertices->begin(), tempVertices->end()); } } else { if (hardwareClipping) m_vertexTrans.push_back(CTranslatedVertices(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertexBuffer, g_graphicsContext.GetClipRegion())); else /* Append the vertices from the cache to the set collected since the first Begin() call */ m_vertex.insert(m_vertex.end(), vertices->begin(), vertices->end()); } End(); } // this routine assumes a single line (i.e. it was called from GUITextLayout) float CGUIFontTTFBase::GetTextWidthInternal(vecText::const_iterator start, vecText::const_iterator end) { float width = 0; while (start != end) { Character *c = GetCharacter(*start++);
void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors, const vecText &text, uint32_t alignment, float maxPixelWidth, bool scrolling) { Begin(); uint32_t rawAlignment = alignment; bool dirtyCache(false); bool hardwareClipping = g_Windowing.ScissorsCanEffectClipping(); CGUIFontCacheStaticPosition staticPos(x, y); CGUIFontCacheDynamicPosition dynamicPos; if (hardwareClipping) { dynamicPos = CGUIFontCacheDynamicPosition(g_graphicsContext.ScaleFinalXCoord(x, y), g_graphicsContext.ScaleFinalYCoord(x, y), g_graphicsContext.ScaleFinalZCoord(x, y)); } CVertexBuffer unusedVertexBuffer; CVertexBuffer &vertexBuffer = hardwareClipping ? m_dynamicCache.Lookup(dynamicPos, colors, text, alignment, maxPixelWidth, scrolling, XbmcThreads::SystemClockMillis(), dirtyCache) : unusedVertexBuffer; std::shared_ptr<std::vector<SVertex> > tempVertices = std::make_shared<std::vector<SVertex> >(); std::shared_ptr<std::vector<SVertex> > &vertices = hardwareClipping ? tempVertices : static_cast<std::shared_ptr<std::vector<SVertex> >&>(m_staticCache.Lookup(staticPos, colors, text, alignment, maxPixelWidth, scrolling, XbmcThreads::SystemClockMillis(), dirtyCache)); if (dirtyCache) { // save the origin, which is scaled separately m_originX = x; m_originY = y; // Check if we will really need to truncate or justify the text if ( alignment & XBFONT_TRUNCATED ) { if ( maxPixelWidth <= 0.0f || GetTextWidthInternal(text.begin(), text.end()) <= maxPixelWidth) alignment &= ~XBFONT_TRUNCATED; } else if ( alignment & XBFONT_JUSTIFIED ) { if ( maxPixelWidth <= 0.0f ) alignment &= ~XBFONT_JUSTIFIED; } // calculate sizing information float startX = 0; float startY = (alignment & XBFONT_CENTER_Y) ? -0.5f*m_cellHeight : 0; // vertical centering if ( alignment & (XBFONT_RIGHT | XBFONT_CENTER_X) ) { // Get the extent of this line float w = GetTextWidthInternal( text.begin(), text.end() ); if ( alignment & XBFONT_TRUNCATED && w > maxPixelWidth + 0.5f ) // + 0.5f due to rounding issues w = maxPixelWidth; if ( alignment & XBFONT_CENTER_X) w *= 0.5f; // Offset this line's starting position startX -= w; } float spacePerSpaceCharacter = 0; // for justification effects if ( alignment & XBFONT_JUSTIFIED ) { // first compute the size of the text to render in both characters and pixels unsigned int numSpaces = 0; float linePixels = 0; for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos) { Character *ch = GetCharacter(*pos); if (ch) { if ((*pos & 0xffff) == L' ') numSpaces += 1; linePixels += ch->advance; } } if (numSpaces > 0) spacePerSpaceCharacter = (maxPixelWidth - linePixels) / numSpaces; } float cursorX = 0; // current position along the line // Collect all the Character info in a first pass, in case any of them // are not currently cached and cause the texture to be enlarged, which // would invalidate the texture coordinates. std::queue<Character> characters; if (alignment & XBFONT_TRUNCATED) GetCharacter(L'.'); for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos) { Character *ch = GetCharacter(*pos); if (!ch) { Character null = { 0 }; characters.push(null); continue; } characters.push(*ch); if (maxPixelWidth > 0 && cursorX + ((alignment & XBFONT_TRUNCATED) ? ch->advance + 3 * m_ellipsesWidth : 0) > maxPixelWidth) break; cursorX += ch->advance; } cursorX = 0; for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos) { // If starting text on a new line, determine justification effects // Get the current letter in the CStdString color_t color = (*pos & 0xff0000) >> 16; if (color >= colors.size()) color = 0; color = colors[color]; // grab the next character Character *ch = &characters.front(); if (ch->letterAndStyle == 0) { characters.pop(); continue; } if ( alignment & XBFONT_TRUNCATED ) { // Check if we will be exceeded the max allowed width if ( cursorX + ch->advance + 3 * m_ellipsesWidth > maxPixelWidth ) { // Yup. Let's draw the ellipses, then bail // Perhaps we should really bail to the next line in this case?? Character *period = GetCharacter(L'.'); if (!period) break; for (int i = 0; i < 3; i++) { RenderCharacter(startX + cursorX, startY, period, color, !scrolling, *tempVertices); cursorX += period->advance; } break; } } else if (maxPixelWidth > 0 && cursorX > maxPixelWidth) break; // exceeded max allowed width - stop rendering RenderCharacter(startX + cursorX, startY, ch, color, !scrolling, *tempVertices); if ( alignment & XBFONT_JUSTIFIED ) { if ((*pos & 0xffff) == L' ') cursorX += ch->advance + spacePerSpaceCharacter; else cursorX += ch->advance; } else cursorX += ch->advance; characters.pop(); } if (hardwareClipping) { CVertexBuffer &vertexBuffer = m_dynamicCache.Lookup(dynamicPos, colors, text, rawAlignment, maxPixelWidth, scrolling, XbmcThreads::SystemClockMillis(), dirtyCache); CVertexBuffer newVertexBuffer = CreateVertexBuffer(*tempVertices); vertexBuffer = newVertexBuffer; m_vertexTrans.push_back(CTranslatedVertices(0, 0, 0, &vertexBuffer, g_graphicsContext.GetClipRegion())); } else { m_staticCache.Lookup(staticPos, colors, text, rawAlignment, maxPixelWidth, scrolling, XbmcThreads::SystemClockMillis(), dirtyCache) = *static_cast<CGUIFontCacheStaticValue *>(&tempVertices); /* Append the new vertices to the set collected since the first Begin() call */ m_vertex.insert(m_vertex.end(), tempVertices->begin(), tempVertices->end()); } } else { if (hardwareClipping)
else { m_staticCache.Lookup(staticPos, colors, text, rawAlignment, maxPixelWidth, scrolling, XbmcThreads::SystemClockMillis(), dirtyCache) = *static_cast<CGUIFontCacheStaticValue *>(&tempVertices); /* Append the new vertices to the set collected since the first Begin() call */ m_vertex.insert(m_vertex.end(), tempVertices->begin(), tempVertices->end()); } } else { if (hardwareClipping) m_vertexTrans.push_back(CTranslatedVertices(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertexBuffer, CServiceBroker::GetWinSystem()->GetGfxContext().GetClipRegion())); else /* Append the vertices from the cache to the set collected since the first Begin() call */ m_vertex.insert(m_vertex.end(), vertices->begin(), vertices->end()); } End(); } // this routine assumes a single line (i.e. it was called from GUITextLayout) float CGUIFontTTFBase::GetTextWidthInternal(vecText::const_iterator start, vecText::const_iterator end) { float width = 0; while (start != end) { Character *c = GetCharacter(*start++);