diff --git a/iphone/Maps/Classes/MapViewController.mm b/iphone/Maps/Classes/MapViewController.mm index b045be3a38..8eca7e87da 100644 --- a/iphone/Maps/Classes/MapViewController.mm +++ b/iphone/Maps/Classes/MapViewController.mm @@ -1,6 +1,6 @@ #import "MapViewController.hpp" #import "EAGLView.hpp" -#import "SettingsManager.h" +#import "../Settings/SettingsManager.h" #include "RenderContext.hpp" #include "WindowHandle.hpp" diff --git a/iphone/Maps/Platform/IPhonePlatform.mm b/iphone/Maps/Platform/IPhonePlatform.mm index 5022656cf3..2d6ccbdd62 100644 --- a/iphone/Maps/Platform/IPhonePlatform.mm +++ b/iphone/Maps/Platform/IPhonePlatform.mm @@ -162,7 +162,7 @@ bool IPhonePlatform::IsMultiSampled() const { return m_isMultiSampled; } - + bool IPhonePlatform::DoPeriodicalUpdate() const { return m_doPeriodicalUpdate; @@ -172,9 +172,8 @@ vector IPhonePlatform::GetFontNames() const { vector res; string fontFolder = m_resourcesPath; - GetFilesInDir(fontFolder, ".ttf", res); - for (int i = 0; i < res.size(); ++i) + for (size_t i = 0; i < res.size(); ++i) res[i] = fontFolder + res[i]; /* res.push_back(ReadPathForFile("wqy-microhei.ttf")); diff --git a/map/drawer_yg.cpp b/map/drawer_yg.cpp index 91842fc393..8422893531 100644 --- a/map/drawer_yg.cpp +++ b/map/drawer_yg.cpp @@ -12,6 +12,7 @@ #include "../base/profiler.hpp" #include "../base/logging.hpp" +#include "../base/buffer_vector.hpp" #include "../std/sstream.hpp" @@ -108,32 +109,57 @@ void DrawerYG::drawSymbol(m2::PointD const & pt, rule_ptr_t pRule, yg::EPosition m_pScreen->drawSymbol(pt, id, pos, depth); } -void DrawerYG::drawPath(vector const & pts, rule_ptr_t pRule, int depth) +void DrawerYG::drawPath(vector const & pts, rule_ptr_t * rules, int * depthVec, size_t count) { - // Use BaseRule::m_id to cache for line draw rule. - // This rule type is used for line and area drawing, so leave m_id for line type. + // if any rule needs caching - cache as a whole vector + // check whether we needs caching + bool flag = false; - uint32_t id = pRule->GetID(); - if (id == drule::BaseRule::empty_id) + for (int i = 0; i < count; ++i) { - vector pattern; - double offset; - pRule->GetPattern(pattern, offset); - - for (size_t i = 0; i < pattern.size(); ++i) - pattern[i] *= m_scale * m_visualScale; - - yg::PenInfo rd(yg::Color::fromXRGB(pRule->GetColor(), pRule->GetAlpha()), - max(pRule->GetWidth() * m_scale, 1.0) * m_visualScale, - pattern.empty() ? 0 : &pattern[0], pattern.size(), offset * m_scale); - - id = m_pSkin->mapPenInfo(rd); - - ASSERT ( id != drule::BaseRule::empty_id, () ); - pRule->SetID(id); + if (rules[i]->GetID() == drule::BaseRule::empty_id) + { + flag = true; + break; + } } - m_pScreen->drawPath(&pts[0], pts.size(), id, depth); + buffer_vector penInfos(count); + buffer_vector styleIDs(count); + + if (flag) + { + /// collect yg::PenInfo into array and pack them as a whole + for (int i = 0; i < count; ++i) + { + rule_ptr_t pRule = rules[i]; + vector pattern; + double offset; + pRule->GetPattern(pattern, offset); + + for (size_t j = 0; j < pattern.size(); ++j) + pattern[j] *= m_scale * m_visualScale; + + penInfos[i] = yg::PenInfo (yg::Color::fromXRGB(pRule->GetColor(), pRule->GetAlpha()), + max(pRule->GetWidth() * m_scale, 1.0) * m_visualScale, + pattern.empty() ? 0 : &pattern[0], pattern.size(), offset * m_scale); + styleIDs[i] = m_pSkin->invalidHandle(); + } + + if (m_pSkin->mapPenInfo(&penInfos[0], &styleIDs[0], count)) + for (int i = 0; i < count; ++i) + rules[i]->SetID(styleIDs[i]); + else + LOG(LINFO, ("couldn't successfully pack a sequence of path styles as a whole")); + } + + for (int i = 0; i < count; ++i) + m_pScreen->drawPath(&pts[0], pts.size(), rules[i]->GetID(), depthVec[i]); +} + +void DrawerYG::drawPath(vector const & pts, rule_ptr_t pRule, int depth) +{ + drawPath(pts, &pRule, &depth, 1); } void DrawerYG::drawArea(vector const & pts, rule_ptr_t pRule, int depth) @@ -168,6 +194,8 @@ uint8_t DrawerYG::get_pathtext_font_size(rule_ptr_t pRule) const void DrawerYG::drawText(m2::PointD const & pt, string const & name, rule_ptr_t pRule, int depth) { yg::Color textColor(pRule->GetColor() == -1 ? yg::Color(0, 0, 0, 0) : yg::Color::fromXRGB(pRule->GetColor(), pRule->GetAlpha())); + + /// to prevent white text on white outline if (textColor == yg::Color(255, 255, 255, 255)) textColor = yg::Color(0, 0, 0, 0); @@ -177,8 +205,8 @@ void DrawerYG::drawText(m2::PointD const & pt, string const & name, rule_ptr_t p get_text_font_size(pRule), textColor, name, - true, //pRule->GetOutlineColor() != -1, - yg::Color(255, 255, 255, 255), //yg::Color::fromXRGB(pRule->GetOutlineColor(), pRule->GetAlpha()), + true, + yg::Color(255, 255, 255, 255), depth, false, true); @@ -217,89 +245,125 @@ void DrawerYG::SetScale(int level) m_scale = scales::GetM2PFactor(level); } -void DrawerYG::Draw(di::DrawInfo const * pInfo, rule_ptr_t pRule, int depth) +void DrawerYG::Draw(di::DrawInfo const * pInfo, rule_ptr_t * rules, int * depthVec, size_t count) { - bool const isCaption = pRule->GetTextHeight() >= 0.0; + buffer_vector pathRules; + buffer_vector pathDepthes; - string symbol; - pRule->GetSymbol(symbol); - bool const isSymbol = !symbol.empty(); + /// separating path rules from other - bool const isPath = !pInfo->m_pathes.empty(); - bool const isArea = !pInfo->m_areas.empty(); - bool const isName = !pInfo->m_name.empty(); - - if (!isCaption) + for (unsigned i = 0; i < count; ++i) { - // draw path - if (isPath && !isSymbol && (pRule->GetColor() != -1)) + rule_ptr_t pRule = rules[i]; + string symbol; + pRule->GetSymbol(symbol); + + bool const isSymbol = !symbol.empty(); + bool const isCaption = pRule->GetTextHeight() >= 0.0; + bool const isPath = !pInfo->m_pathes.empty(); + + if (!isCaption && isPath && !isSymbol && (pRule->GetColor() != -1)) { - for (list::const_iterator i = pInfo->m_pathes.begin(); i != pInfo->m_pathes.end(); ++i) - drawPath(i->m_path, pRule, depth); + pathRules.push_back(rules[i]); + pathDepthes.push_back(depthVec[i]); } - - // draw area - if (isArea) - { - bool const isFill = pRule->GetFillColor() != -1; - bool isSym = isSymbol && ((pRule->GetType() & drule::way) != 0); - - for (list::const_iterator i = pInfo->m_areas.begin(); i != pInfo->m_areas.end(); ++i) - { - if (isFill) - drawArea(i->m_path, pRule, depth); - else if (isSym) - drawSymbol(i->GetCenter(), pRule, yg::EPosLeft, depth); - } - } - - // draw point symbol - if (!isPath && !isArea && isSymbol && ((pRule->GetType() & drule::node) != 0)) - drawSymbol(pInfo->m_point, pRule, yg::EPosLeft, depth); } - else + + if (!pathRules.empty()) { - if (isName) + for (list::const_iterator i = pInfo->m_pathes.begin(); i != pInfo->m_pathes.end(); ++i) + drawPath(i->m_path, &pathRules[0], &pathDepthes[0], pathRules.size()); + } + + for (unsigned i = 0; i < count; ++i) + { + rule_ptr_t pRule = rules[i]; + int depth = depthVec[i]; + + bool const isCaption = pRule->GetTextHeight() >= 0.0; + + string symbol; + pRule->GetSymbol(symbol); + bool const isSymbol = !symbol.empty(); + + bool const isPath = !pInfo->m_pathes.empty(); + bool const isArea = !pInfo->m_areas.empty(); + bool const isName = !pInfo->m_name.empty(); + + if (!isCaption) { - bool isN = ((pRule->GetType() & drule::way) != 0); - - // draw area text - if (isArea && isN) - { - for (list::const_iterator i = pInfo->m_areas.begin(); i != pInfo->m_areas.end(); ++i) - drawText(i->GetCenter(), pInfo->m_name, pRule, depth); - } - - // draw way name - if (isPath && !isArea && isN) + /// path is drawn separately in the code above +/* // draw path + if (isPath && !isSymbol && (pRule->GetColor() != -1)) { for (list::const_iterator i = pInfo->m_pathes.begin(); i != pInfo->m_pathes.end(); ++i) + drawPath(i->m_path, pRule, depth); + } + */ + + // draw area + if (isArea) + { + bool const isFill = pRule->GetFillColor() != -1; + bool isSym = isSymbol && ((pRule->GetType() & drule::way) != 0); + + for (list::const_iterator i = pInfo->m_areas.begin(); i != pInfo->m_areas.end(); ++i) { - uint8_t const fontSize = get_pathtext_font_size(pRule); - - list & lst = m_pathsOrg[pInfo->m_name]; - - m2::RectD r = i->GetLimitRect(); - r.Inflate(-r.SizeX() / 4.0, -r.SizeY() / 4.0); - r.Inflate(fontSize, fontSize); - - bool needDraw = true; - for (list::const_iterator j = lst.begin(); j != lst.end(); ++j) - if (r.IsIntersect(*j)) - { - needDraw = false; - break; - } - - if (needDraw && drawPathText(*i, pInfo->m_name, fontSize, depth)) - lst.push_back(r); + if (isFill) + drawArea(i->m_path, pRule, depth); + else if (isSym) + drawSymbol(i->GetCenter(), pRule, yg::EPosLeft, depth); } } - // draw point text - isN = ((pRule->GetType() & drule::node) != 0); - if (!isPath && !isArea && isN) - drawText(pInfo->m_point, pInfo->m_name, pRule, depth); + // draw point symbol + if (!isPath && !isArea && isSymbol && ((pRule->GetType() & drule::node) != 0)) + drawSymbol(pInfo->m_point, pRule, yg::EPosLeft, depth); + } + else + { + if (isName) + { + bool isN = ((pRule->GetType() & drule::way) != 0); + + // draw area text + if (isArea && isN) + { + for (list::const_iterator i = pInfo->m_areas.begin(); i != pInfo->m_areas.end(); ++i) + drawText(i->GetCenter(), pInfo->m_name, pRule, depth); + } + + // draw way name + if (isPath && !isArea && isN) + { + for (list::const_iterator i = pInfo->m_pathes.begin(); i != pInfo->m_pathes.end(); ++i) + { + uint8_t const fontSize = get_pathtext_font_size(pRule); + + list & lst = m_pathsOrg[pInfo->m_name]; + + m2::RectD r = i->GetLimitRect(); + r.Inflate(-r.SizeX() / 4.0, -r.SizeY() / 4.0); + r.Inflate(fontSize, fontSize); + + bool needDraw = true; + for (list::const_iterator j = lst.begin(); j != lst.end(); ++j) + if (r.IsIntersect(*j)) + { + needDraw = false; + break; + } + + if (needDraw && drawPathText(*i, pInfo->m_name, fontSize, depth)) + lst.push_back(r); + } + } + + // draw point text + isN = ((pRule->GetType() & drule::node) != 0); + if (!isPath && !isArea && isN) + drawText(pInfo->m_point, pInfo->m_name, pRule, depth); + } } } } diff --git a/map/drawer_yg.hpp b/map/drawer_yg.hpp index 649970ad16..51d462defd 100644 --- a/map/drawer_yg.hpp +++ b/map/drawer_yg.hpp @@ -14,7 +14,6 @@ class ScreenBase; namespace drule { class BaseRule; } - namespace yg { namespace gl @@ -65,6 +64,7 @@ private: protected: void drawSymbol(m2::PointD const & pt, rule_ptr_t pRule, yg::EPosition pos, int depth); void drawPath(vector const & pts, rule_ptr_t pRule, int depth); + void drawPath(vector const & pts, rule_ptr_t * rules, int * depthVec, size_t count); void drawArea(vector const & pts, rule_ptr_t pRule, int depth); void drawText(m2::PointD const & pt, string const & name, rule_ptr_t pRule, int depth); @@ -100,5 +100,5 @@ public: void SetVisualScale(double visualScale); void SetScale(int level); - void Draw(di::DrawInfo const * pInfo, rule_ptr_t pRule, int depth); + void Draw(di::DrawInfo const * pInfo, rule_ptr_t * rules, int * depthVec, size_t count); }; diff --git a/map/framework.cpp b/map/framework.cpp index 4d2d3bfde3..0ad786c22c 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -87,6 +87,22 @@ namespace fwork m_keys.erase(unique(m_keys.begin(), m_keys.end(), equal_key()), m_keys.end()); } + void DrawProcessor::ConvertKeysToRules(int layer) + { + m_rules.resize(m_keys.size()); + m_depthVec.resize(m_keys.size()); + // push rules to drawing queue + for (size_t i = 0; i < m_keys.size(); ++i) + { + int depth = m_keys[i].m_priority; + if (layer != 0) + depth = (layer * drule::layer_base_priority) + (depth % drule::layer_base_priority); + + m_rules[i] = drule::rules().Find(m_keys[i]); + m_depthVec[i] = depth; + } + } + #define GET_POINTS(functor_t, for_each_fun, assign_fun) \ { \ functor_t fun(m_convertor, m_rect); \ @@ -152,19 +168,14 @@ namespace fwork // remove duplicating identical drawing keys PreProcessKeys(); - // push rules to drawing queue - for (size_t i = 0; i < m_keys.size(); ++i) - { - int depth = m_keys[i].m_priority; - if (layer != 0) - depth = (layer * drule::layer_base_priority) + (depth % drule::layer_base_priority); + // get drawing rules for the m_keys array + ConvertKeysToRules(layer); #ifdef PROFILER_DRAWING - ++m_drawCount; + m_drawCount += m_keys.size(); #endif - pDrawer->Draw(ptr.get(), drule::rules().Find(m_keys[i]), depth); - } + pDrawer->Draw(ptr.get(), &m_rules[0], &m_depthVec[0], m_keys.size()); return true; } diff --git a/map/framework.hpp b/map/framework.hpp index 2b4ba3567e..7549dff413 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -54,6 +54,8 @@ namespace fwork shared_ptr m_paintEvent; vector m_keys; + vector m_rules; + vector m_depthVec; int m_zoom; @@ -64,6 +66,7 @@ namespace fwork inline DrawerYG * GetDrawer() const { return m_paintEvent->drawer().get(); } void PreProcessKeys(); + void ConvertKeysToRules(int layer); public: DrawProcessor(m2::RectD const & r, diff --git a/yg/circle_info.cpp b/yg/circle_info.cpp new file mode 100644 index 0000000000..167b31539b --- /dev/null +++ b/yg/circle_info.cpp @@ -0,0 +1,16 @@ +#include "../base/SRC_FIRST.hpp" + +#include "circle_info.hpp" + +namespace yg +{ + CircleInfo::CircleInfo(double radius, + Color const & color, + bool isOutlined, + Color const & outlineColor) + : m_radius(radius), + m_color(color), + m_isOutlined(isOutlined), + m_outlineColor(outlineColor) + {} +} diff --git a/yg/circle_info.hpp b/yg/circle_info.hpp new file mode 100644 index 0000000000..55e0c40249 --- /dev/null +++ b/yg/circle_info.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include "color.hpp" + +namespace yg +{ + struct CircleInfo + { + double m_radius; + Color m_color; + bool m_isOutlined; + Color m_outlineColor; + + CircleInfo( + double radius, + Color const & color = Color(0, 0, 0, 255), + bool isOutlined = true, + Color const & outlineColor = Color(255, 255, 255, 255)); + }; +} diff --git a/yg/geometry_batcher.cpp b/yg/geometry_batcher.cpp index edca146902..4b6f288a37 100644 --- a/yg/geometry_batcher.cpp +++ b/yg/geometry_batcher.cpp @@ -210,6 +210,13 @@ namespace yg void GeometryBatcher::drawTrianglesList(m2::PointD const * points, size_t pointsCount, uint32_t styleID, double depth) { ResourceStyle const * style = m_skin->fromID(styleID); + + if (style == 0) + { + LOG(LINFO, ("styleID=", styleID, " wasn't found on current skin.")); + return; + } + if (!hasRoom(pointsCount, pointsCount, style->m_pageID)) flush(style->m_pageID); diff --git a/yg/path_renderer.cpp b/yg/path_renderer.cpp index 6a4b9297fa..3e53ae1158 100644 --- a/yg/path_renderer.cpp +++ b/yg/path_renderer.cpp @@ -4,6 +4,8 @@ #include "resource_style.hpp" #include "skin.hpp" +#include "../base/logging.hpp" + namespace yg { namespace gl @@ -25,6 +27,12 @@ namespace yg ASSERT_GREATER_OR_EQUAL(pointsCount, 2, ()); ResourceStyle const * style(skin()->fromID(styleID)); + if (style == 0) + { + LOG(LINFO, ("styleID=", styleID, " wasn't found on current skin")); + return; + } + ASSERT(style->m_cat == ResourceStyle::ELineStyle, ()); LineStyle const * lineStyle = static_cast(style); //#endif diff --git a/yg/pen_info.hpp b/yg/pen_info.hpp index 54bf90d850..0bd73ce1dc 100644 --- a/yg/pen_info.hpp +++ b/yg/pen_info.hpp @@ -1,5 +1,3 @@ -#ifndef RULE_DEFINITION_H -#define RULE_DEFINITION_H #pragma once #include "color.hpp" @@ -34,4 +32,3 @@ namespace yg bool operator < (PenInfo const & l, PenInfo const & r); } -#endif // RULE_DEFINITION_H diff --git a/yg/shape_renderer.hpp b/yg/shape_renderer.hpp index 0e0f8dd6cb..c82ad99802 100644 --- a/yg/shape_renderer.hpp +++ b/yg/shape_renderer.hpp @@ -18,6 +18,8 @@ namespace yg void drawArc(m2::PointD const & center, double startA, double endA, double r, yg::Color const & c, double depth); void drawSector(m2::PointD const & center, double startA, double endA, double r, yg::Color const & c, double depth); void fillSector(m2::PointD const & center, double startA, double endA, double r, yg::Color const & c, double depth); + +// void drawCircle(m2::PointD const & center, uint32_t styleID, double depth); }; } } diff --git a/yg/skin.cpp b/yg/skin.cpp index 837766a863..20dc77a70e 100644 --- a/yg/skin.cpp +++ b/yg/skin.cpp @@ -131,6 +131,39 @@ namespace yg return packID(m_currentDynamicPage, m_pages[m_currentDynamicPage]->mapPenInfo(penInfo)); } + bool Skin::mapPenInfo(PenInfo const * penInfos, uint32_t * styleIDS, size_t count) + { + uint8_t savedDynamicPage = m_currentDynamicPage; + + int i = 0; + + do + { + styleIDS[i] = m_pages[m_currentDynamicPage]->findPenInfo(penInfos[i]); + + if ((styleIDS[i] == invalidPageHandle()) || (unpackID(styleIDS[i]).first != m_currentDynamicPage)) + { + /// try to pack on the currentDynamicPage + while (!m_pages[m_currentDynamicPage]->hasRoom(penInfos[i])) + { + /// no room - switch the page + changeCurrentDynamicPage(); + if (savedDynamicPage == m_currentDynamicPage) + return false; //mapPenInfo(penInfos[i])); + } + + ++i; + } + while (i != count); + + return true; + } + uint32_t Skin::mapGlyph(GlyphKey const & gk, bool isFixedFont) { uint32_t res = invalidPageHandle(); @@ -208,28 +241,26 @@ namespace yg void Skin::changeCurrentDynamicPage() { - /// 1. flush screen(through overflowFns) - callOverflowFns(m_currentDynamicPage); + /// flush screen(through overflowFns) + /// callOverflowFns(m_currentDynamicPage); + /// 1. clear currentDynamicPage + callClearPageFns(m_currentDynamicPage); /// page should be frozen after flushing(activeCommands > 0) - /// 2. forget all fonts packed on previous page - m_pages[m_currentDynamicPage]->clearFontHandles(); - /// 2. choose next dynamic page if (m_currentDynamicPage == m_startDynamicPage + m_dynamicPagesCount - 1) m_currentDynamicPage = m_startDynamicPage; else ++m_currentDynamicPage; - /// 3. clear it if necessary and notify observers about this event(through clearPageFns) + /// 3. clear new currentDynamicPage callClearPageFns(m_currentDynamicPage); } void Skin::changeCurrentTextPage() { - callOverflowFns(m_currentTextPage); - - m_pages[m_currentTextPage]->clearFontHandles(); + //callOverflowFns(m_currentTextPage); + callClearPageFns(m_currentTextPage); if (m_currentTextPage == m_startTextPage + m_textPagesCount - 1) m_currentTextPage = m_startTextPage; diff --git a/yg/skin.hpp b/yg/skin.hpp index 5ced589bab..4888c5d02c 100644 --- a/yg/skin.hpp +++ b/yg/skin.hpp @@ -2,6 +2,7 @@ #include "resource_style.hpp" #include "pen_info.hpp" +#include "circle_info.hpp" #include "skin_page.hpp" #include "../geometry/rect2d.hpp" #include "../std/unordered_map.hpp" @@ -114,6 +115,9 @@ namespace yg /// if found - return id. /// if not - pack and return id. uint32_t mapPenInfo(PenInfo const & penInfo); + /// map an array of PenInfo on the same skin page + /// returns the completion flag + bool mapPenInfo(PenInfo const * penInfos, uint32_t * styleIDS, size_t count); /// find brushDef on the texture. /// if found - return id. /// if not - pack and return id. @@ -122,6 +126,10 @@ namespace yg /// if found - return id /// if not - pack and return id uint32_t mapGlyph(GlyphKey const & gk, bool isFixedFont); + /// find circleStyle on texture + /// if found - return id + /// if not - pack and return id + uint32_t mapCircleInfo(CircleInfo const & circleInfo); void addClearPageFn(clearPageFn fn, int priority); void addOverflowFn(overflowFn, int priority); diff --git a/yg/symbol_renderer.cpp b/yg/symbol_renderer.cpp index 26560ebe0a..ecefdab0c9 100644 --- a/yg/symbol_renderer.cpp +++ b/yg/symbol_renderer.cpp @@ -1,7 +1,9 @@ #include "../base/SRC_FIRST.hpp" #include "symbol_renderer.hpp" #include "skin.hpp" + #include "../std/bind.hpp" +#include "../base/logging.hpp" namespace yg { @@ -75,6 +77,13 @@ namespace yg void SymbolRenderer::drawSymbol(m2::PointD const & pt, uint32_t styleID, EPosition pos, int depth) { + ResourceStyle const * style(skin()->fromID(styleID)); + if (style == 0) + { + LOG(LINFO, ("styleID=", styleID, " wasn't found on the current skin")); + return; + } + SymbolObject obj(pt, styleID, pos, depth); m2::RectD r = obj.GetLimitRect(this); diff --git a/yg/yg.pro b/yg/yg.pro index 85f4b8c0b8..794414f853 100644 --- a/yg/yg.pro +++ b/yg/yg.pro @@ -59,7 +59,8 @@ SOURCES += \ layer_manager.cpp \ path_renderer.cpp \ shape_renderer.cpp \ - symbol_renderer.cpp + symbol_renderer.cpp \ + circle_info.cpp HEADERS += \ internal/opengl.hpp \ @@ -106,7 +107,8 @@ HEADERS += \ defines.hpp \ path_renderer.hpp \ shape_renderer.hpp \ - symbol_renderer.hpp + symbol_renderer.hpp \ + circle_info.hpp !iphonesimulator-g++42 { !iphonedevice-g++42 {