#include "drape/texture_manager.hpp" #include "drape/symbols_texture.hpp" #include "drape/font_texture.hpp" #include "drape/stipple_pen_resource.hpp" #include "drape/texture_of_colors.hpp" #include "drape/glfunctions.hpp" #include "platform/platform.hpp" #include "coding/file_name_utils.hpp" #include "base/stl_add.hpp" #include "std/vector.hpp" #include "std/bind.hpp" namespace dp { uint32_t const STIPPLE_TEXTURE_SIZE = 1024; uint32_t const COLOR_TEXTURE_SIZE = 1024; bool TextureManager::BaseRegion::IsValid() const { return !m_info.IsNull() && !m_texture.IsNull(); } void TextureManager::BaseRegion::SetResourceInfo(RefPointer info) { m_info = info; } void TextureManager::BaseRegion::SetTexture(RefPointer texture) { m_texture = texture; } m2::PointU TextureManager::BaseRegion::GetPixelSize() const { ASSERT(IsValid(), ()); m2::RectF const & texRect = m_info->GetTexRect(); return m2::PointU(ceil(texRect.SizeX() * m_texture->GetWidth()), ceil(texRect.SizeY() * m_texture->GetHeight())); } uint32_t TextureManager::BaseRegion::GetPixelHeight() const { return ceil(m_info->GetTexRect().SizeY() * m_texture->GetHeight()); } m2::RectF const & TextureManager::BaseRegion::GetTexRect() const { return m_info->GetTexRect(); } TextureManager::GlyphRegion::GlyphRegion() : BaseRegion() { } float TextureManager::GlyphRegion::GetOffsetX() const { ASSERT(m_info->GetType() == Texture::Glyph, ()); GlyphInfo const * info = static_cast(m_info.GetRaw()); return info->GetMetrics().m_xOffset; } float TextureManager::GlyphRegion::GetOffsetY() const { ASSERT(m_info->GetType() == Texture::Glyph, ()); GlyphInfo const * info = static_cast(m_info.GetRaw()); return info->GetMetrics().m_yOffset; } float TextureManager::GlyphRegion::GetAdvanceX() const { ASSERT(m_info->GetType() == Texture::Glyph, ()); GlyphInfo const * info = static_cast(m_info.GetRaw()); return info->GetMetrics().m_xAdvance; } float TextureManager::GlyphRegion::GetAdvanceY() const { ASSERT(m_info->GetType() == Texture::Glyph, ()); GlyphInfo const * info = static_cast(m_info.GetRaw()); return info->GetMetrics().m_yAdvance; } uint32_t TextureManager::StippleRegion::GetMaskPixelLength() const { ASSERT(m_info->GetType() == Texture::StipplePen, ()); return static_cast(m_info.GetRaw())->GetMaskPixelLength(); } uint32_t TextureManager::StippleRegion::GetPatternPixelLength() const { ASSERT(m_info->GetType() == Texture::StipplePen, ()); return static_cast(m_info.GetRaw())->GetPatternPixelLength(); } void TextureManager::UpdateDynamicTextures() { m_colorTexture->UpdateState(); m_stipplePenTexture->UpdateState(); for_each(m_glyphGroups.begin(), m_glyphGroups.end(), [](GlyphGroup & g) { if (!g.m_texture.IsNull()) g.m_texture->UpdateState(); }); for_each(m_hybridGlyphGroups.begin(), m_hybridGlyphGroups.end(), [](MasterPointer texture) { texture->UpdateState(); }); } void TextureManager::AllocateGlyphTexture(TextureManager::GlyphGroup & group) const { group.m_texture.Reset(new FontTexture(m2::PointU(m_maxTextureSize, m_maxTextureSize), m_glyphManager.GetRefPointer())); } void TextureManager::Init(Params const & params) { GLFunctions::glPixelStore(gl_const::GLUnpackAlignment, 1); SymbolsTexture * symbols = new SymbolsTexture(); symbols->Load(my::JoinFoldersToPath(string("resources-") + params.m_resPrefix, "symbols")); m_symbolTexture.Reset(symbols); m_stipplePenTexture.Reset(new StipplePenTexture(m2::PointU(STIPPLE_TEXTURE_SIZE, STIPPLE_TEXTURE_SIZE))); m_colorTexture.Reset(new ColorTexture(m2::PointU(COLOR_TEXTURE_SIZE, COLOR_TEXTURE_SIZE))); m_glyphManager.Reset(new GlyphManager(params.m_glyphMngParams)); m_maxTextureSize = GLFunctions::glGetInteger(gl_const::GLMaxTextureSize); uint32_t const textureSquare = m_maxTextureSize * m_maxTextureSize; uint32_t const baseGlyphHeight = params.m_glyphMngParams.m_baseGlyphHeight; uint32_t const avarageGlyphSquare = baseGlyphHeight * baseGlyphHeight; m_glyphGroups.push_back(GlyphGroup()); uint32_t glyphCount = ceil(0.9 * textureSquare / avarageGlyphSquare); m_glyphManager->ForEachUnicodeBlock([this, glyphCount](strings::UniChar const & start, strings::UniChar const & end) { if (m_glyphGroups.empty()) { m_glyphGroups.push_back(GlyphGroup(start, end)); return; } GlyphGroup & group = m_glyphGroups.back(); ASSERT_LESS_OR_EQUAL(group.m_endChar, start, ()); if (end - group.m_startChar < glyphCount) group.m_endChar = end; else m_glyphGroups.push_back(GlyphGroup(start, end)); }); } void TextureManager::Release() { m_symbolTexture.Destroy(); m_stipplePenTexture.Destroy(); m_colorTexture.Destroy(); DeleteRange(m_glyphGroups, [](GlyphGroup & g) { g.m_texture.Destroy(); }); DeleteRange(m_hybridGlyphGroups, MasterPointerDeleter()); } void TextureManager::GetSymbolRegion(string const & symbolName, SymbolRegion & region) const { region.SetResourceInfo(m_symbolTexture->FindResource(SymbolsTexture::SymbolKey(symbolName))); region.SetTexture(m_symbolTexture.GetRefPointer()); ASSERT(region.IsValid(), ()); } void TextureManager::GetStippleRegion(TStipplePattern const & pen, StippleRegion & region) const { region.SetResourceInfo(m_stipplePenTexture->FindResource(StipplePenKey(pen))); region.SetTexture(m_stipplePenTexture.GetRefPointer()); ASSERT(region.IsValid(), ()); } void TextureManager::GetColorRegion(Color const & color, ColorRegion & region) const { region.SetResourceInfo(m_colorTexture->FindResource(ColorKey(color))); region.SetTexture(m_colorTexture.GetRefPointer()); ASSERT(region.IsValid(), ()); } void TextureManager::GetGlyphRegions(strings::UniString const & text, TGlyphsBuffer & regions) const { size_t const INVALID_GROUP = static_cast(-1); size_t groupIndex = INVALID_GROUP; for (strings::UniChar const & c : text) { auto const iter = lower_bound(m_glyphGroups.begin(), m_glyphGroups.end(), c, [](GlyphGroup const & g, strings::UniChar const & c) { return g.m_endChar < c; }); ASSERT(iter != m_glyphGroups.end(), ()); size_t currentIndex = distance(m_glyphGroups.begin(), iter); if (groupIndex == INVALID_GROUP) groupIndex = currentIndex; else if (groupIndex != currentIndex) { groupIndex = INVALID_GROUP; break; } } regions.reserve(text.size()); if (groupIndex == INVALID_GROUP) { /// TODO some magic with hybrid textures } else { GlyphGroup & group = m_glyphGroups[groupIndex]; if (group.m_texture.IsNull()) AllocateGlyphTexture(group); RefPointer texture = group.m_texture.GetRefPointer(); for (strings::UniChar const & c : text) { GlyphRegion reg; reg.SetResourceInfo(texture->FindResource(GlyphKey(c))); reg.SetTexture(texture); regions.push_back(reg); } } } } // namespace dp