diff --git a/indexer/drawing_rules.cpp b/indexer/drawing_rules.cpp index 0286f3a24d..ba8ff044c6 100644 --- a/indexer/drawing_rules.cpp +++ b/indexer/drawing_rules.cpp @@ -607,6 +607,10 @@ namespace drule { virtual void Read(FileReaderStream & ar) { read_rules(ar, this); } virtual void Write(FileWriterStream & ar) const { write_rules(ar, this); } + virtual double GetRadius() const {return m_params.get<0>().m_v;} + virtual int GetStrokeColor() const {return m_params.get<3>().m_v;} + virtual int GetColor() const {return m_params.get<1>().m_v;} + static string arrKeys[6]; }; string CircleRule::arrKeys[] = { diff --git a/indexer/drawing_rules.hpp b/indexer/drawing_rules.hpp index 6a6a190f52..2d91505df5 100644 --- a/indexer/drawing_rules.hpp +++ b/indexer/drawing_rules.hpp @@ -58,6 +58,9 @@ namespace drule virtual double GetWidth() const { return -1; } virtual void GetPattern(vector &, double &) const {} virtual void GetSymbol(string &) const {} + + virtual double GetRadius() const {return -1;} + virtual int GetStrokeColor() const {return -1;} }; class RulesHolder diff --git a/map/drawer_yg.cpp b/map/drawer_yg.cpp index 8422893531..74f4e9c69a 100644 --- a/map/drawer_yg.cpp +++ b/map/drawer_yg.cpp @@ -85,6 +85,29 @@ void DrawerYG::drawSymbol(m2::PointD const & pt, string const & symbolName, yg:: m_pScreen->drawSymbol(pt, m_pSkin->mapSymbol(symbolName.c_str()), pos, depth); } +void DrawerYG::drawCircle(m2::PointD const & pt, rule_ptr_t pRule, int depth) +{ + uint32_t id = pRule->GetID(); + if (id == drule::BaseRule::empty_id) + { + yg::CircleInfo info(pRule->GetRadius(), + yg::Color::fromXRGB(pRule->GetColor(), pRule->GetAlpha()), + true); + + id = m_pSkin->mapCircleInfo(info); + + if (id != drule::BaseRule::empty_id) + pRule->SetID(id); + else + { + //ASSERT ( false, ("Can't find symbol by id = ", (name)) ); + return; + } + } + + m_pScreen->drawCircle(pt, id, depth); +} + void DrawerYG::drawSymbol(m2::PointD const & pt, rule_ptr_t pRule, yg::EPosition pos, int depth) { // Use BaseRule::m_id to cache for point draw rule. @@ -290,6 +313,8 @@ void DrawerYG::Draw(di::DrawInfo const * pInfo, rule_ptr_t * rules, int * depthV bool const isArea = !pInfo->m_areas.empty(); bool const isName = !pInfo->m_name.empty(); + bool const isCircle = (pRule->GetRadius() != -1); + if (!isCaption) { /// path is drawn separately in the code above @@ -313,6 +338,8 @@ void DrawerYG::Draw(di::DrawInfo const * pInfo, rule_ptr_t * rules, int * depthV drawArea(i->m_path, pRule, depth); else if (isSym) drawSymbol(i->GetCenter(), pRule, yg::EPosLeft, depth); + if (isCircle) + drawCircle(i->GetCenter(), pRule, depth); } } @@ -330,7 +357,11 @@ void DrawerYG::Draw(di::DrawInfo const * pInfo, rule_ptr_t * rules, int * depthV 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); + if (isCircle) + drawCircle(i->GetCenter(), pRule, depth); + } } // draw way name @@ -363,6 +394,10 @@ void DrawerYG::Draw(di::DrawInfo const * pInfo, rule_ptr_t * rules, int * depthV isN = ((pRule->GetType() & drule::node) != 0); if (!isPath && !isArea && isN) drawText(pInfo->m_point, pInfo->m_name, pRule, depth); + + if (isCircle) + drawCircle(pInfo->m_point, pRule, depth); + } } } diff --git a/map/drawer_yg.hpp b/map/drawer_yg.hpp index 51d462defd..dd50e1a97a 100644 --- a/map/drawer_yg.hpp +++ b/map/drawer_yg.hpp @@ -63,6 +63,7 @@ private: protected: void drawSymbol(m2::PointD const & pt, rule_ptr_t pRule, yg::EPosition pos, int depth); + void drawCircle(m2::PointD const & pt, rule_ptr_t pRule, 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); diff --git a/yg/circle_info.cpp b/yg/circle_info.cpp index 167b31539b..0536325754 100644 --- a/yg/circle_info.cpp +++ b/yg/circle_info.cpp @@ -4,7 +4,7 @@ namespace yg { - CircleInfo::CircleInfo(double radius, + CircleInfo::CircleInfo(unsigned radius, Color const & color, bool isOutlined, Color const & outlineColor) @@ -13,4 +13,18 @@ namespace yg m_isOutlined(isOutlined), m_outlineColor(outlineColor) {} + + CircleInfo::CircleInfo() + {} + + bool operator< (CircleInfo const & l, CircleInfo const & r) + { + if (l.m_radius != r.m_radius) + return l.m_radius < r.m_radius; + if (l.m_color != r.m_color) + return l.m_color < r.m_color; + if (l.m_isOutlined != r.m_isOutlined) + return l.m_isOutlined < r.m_isOutlined; + return l.m_outlineColor < r.m_outlineColor; + } } diff --git a/yg/circle_info.hpp b/yg/circle_info.hpp index 55e0c40249..7a53259d9f 100644 --- a/yg/circle_info.hpp +++ b/yg/circle_info.hpp @@ -6,15 +6,18 @@ namespace yg { struct CircleInfo { - double m_radius; + unsigned m_radius; Color m_color; bool m_isOutlined; Color m_outlineColor; + CircleInfo(); CircleInfo( - double radius, + unsigned radius, Color const & color = Color(0, 0, 0, 255), - bool isOutlined = true, + bool isOutlined = false, Color const & outlineColor = Color(255, 255, 255, 255)); }; + + bool operator< (CircleInfo const & l, CircleInfo const & r); } diff --git a/yg/color.cpp b/yg/color.cpp index e8fc73837c..dd2f7564f1 100644 --- a/yg/color.cpp +++ b/yg/color.cpp @@ -49,6 +49,16 @@ namespace yg alphaFromARGB(_c)); } + Color const & Color::operator /= (unsigned k) + { + r /= k; + g /= k; + b /= k; + a /= k; + + return *this; + } + bool operator < (Color const & l, Color const & r) { if (l.r != r.r) return l.r < r.r; diff --git a/yg/color.hpp b/yg/color.hpp index 850ce29262..fe8cdef071 100644 --- a/yg/color.hpp +++ b/yg/color.hpp @@ -18,6 +18,8 @@ namespace yg static Color const fromARGB(uint32_t _c); static Color const fromXRGB(uint32_t _c, unsigned char _a = 0); + + Color const & operator /= (unsigned k); }; bool operator < (Color const & l, Color const & r); diff --git a/yg/shape_renderer.cpp b/yg/shape_renderer.cpp index 498150f8ed..48ba2709ba 100644 --- a/yg/shape_renderer.cpp +++ b/yg/shape_renderer.cpp @@ -64,5 +64,24 @@ namespace yg drawTrianglesList(§orPts[0], sectorPts.size(), skin()->mapColor(c), depth); } + + void ShapeRenderer::drawCircle(m2::PointD const & center, uint32_t styleID, double depth) + { + ResourceStyle const * style(skin()->fromID(styleID)); + + m2::RectU texRect(style->m_texRect); + texRect.Inflate(-1, -1); + + m2::PointD pt(center - m2::PointD(texRect.SizeX() / 2, texRect.SizeY() / 2)); + pt.x = ceil(pt.x); + pt.y = ceil(pt.y); + + + drawTexturedPolygon(m2::PointD(0, 0), 0, + texRect.minX(), texRect.minY(), texRect.maxX(), texRect.maxY(), + pt.x, pt.y, pt.x + texRect.SizeX(), pt.y + texRect.SizeY(), + depth, + style->m_pageID); + } } } diff --git a/yg/shape_renderer.hpp b/yg/shape_renderer.hpp index c82ad99802..4a00493d26 100644 --- a/yg/shape_renderer.hpp +++ b/yg/shape_renderer.hpp @@ -19,7 +19,7 @@ namespace yg 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); + void drawCircle(m2::PointD const & center, uint32_t styleID, double depth); }; } } diff --git a/yg/skin.cpp b/yg/skin.cpp index 20dc77a70e..130b2db812 100644 --- a/yg/skin.cpp +++ b/yg/skin.cpp @@ -131,6 +131,22 @@ namespace yg return packID(m_currentDynamicPage, m_pages[m_currentDynamicPage]->mapPenInfo(penInfo)); } + uint32_t Skin::mapCircleInfo(CircleInfo const & circleInfo) + { + uint32_t res = invalidPageHandle(); + for (uint8_t i = 0; i < m_pages.size(); ++i) + { + res = m_pages[i]->findCircleInfo(circleInfo); + if (res != invalidPageHandle()) + return packID(i, res); + } + + if (!m_pages[m_currentDynamicPage]->hasRoom(circleInfo)) + changeCurrentDynamicPage(); + + return packID(m_currentDynamicPage, m_pages[m_currentDynamicPage]->mapCircleInfo(circleInfo)); + } + bool Skin::mapPenInfo(PenInfo const * penInfos, uint32_t * styleIDS, size_t count) { uint8_t savedDynamicPage = m_currentDynamicPage; diff --git a/yg/skin_page.cpp b/yg/skin_page.cpp index 46c9a12ed5..24097aba9f 100644 --- a/yg/skin_page.cpp +++ b/yg/skin_page.cpp @@ -62,6 +62,12 @@ namespace yg : m_penInfo(penInfo), m_rect(rect){} + CircleUploadCmd::CircleUploadCmd(){} + CircleUploadCmd::CircleUploadCmd(yg::CircleInfo const & circleInfo, + m2::RectU const & rect) + : m_circleInfo(circleInfo), + m_rect(rect){} + ResourceStyle * FontInfo::fromID(uint32_t id, bool isMask) const { TChars::const_iterator it = m_chars.find(id); @@ -120,6 +126,7 @@ namespace yg clearPenInfoHandles(); clearColorHandles(); clearFontHandles(); + clearCircleInfoHandles(); m_packer.reset(); } @@ -140,6 +147,14 @@ namespace yg m_penInfoMap.clear(); } + void SkinPage::clearCircleInfoHandles() + { + for (TCircleInfoMap::const_iterator it = m_circleInfoMap.begin(); it != m_circleInfoMap.end(); ++it) + m_styles.erase(it->second); + + m_circleInfoMap.clear(); + } + void SkinPage::clearFontHandles() { for (TGlyphMap::const_iterator it = m_glyphMap.begin(); it != m_glyphMap.end(); ++it) @@ -261,6 +276,43 @@ namespace yg return m_packer.hasRoom(gi->m_metrics.m_width + 4, gi->m_metrics.m_height + 4); } + uint32_t SkinPage::findCircleInfo(CircleInfo const & circleInfo) const + { + TCircleInfoMap::const_iterator it = m_circleInfoMap.find(circleInfo); + if (it == m_circleInfoMap.end()) + return m_packer.invalidHandle(); + else + return it->second; + } + + uint32_t SkinPage::mapCircleInfo(CircleInfo const & circleInfo) + { + uint32_t foundHandle = findCircleInfo(circleInfo); + + if (foundHandle != m_packer.invalidHandle()) + return foundHandle; + + unsigned r = circleInfo.m_isOutlined ? circleInfo.m_radius + 1 : circleInfo.m_radius; + + m2::Packer::handle_t handle = m_packer.pack( + r * 2 + 4, + r * 2 + 4); + + m2::RectU texRect = m_packer.find(handle).second; + m_circleUploadCommands.push_back(CircleUploadCmd(circleInfo, texRect)); + m_circleInfoMap[circleInfo] = handle; + + m_styles[handle] = shared_ptr(new GenericStyle(texRect, m_pageID) ); + + return m_circleInfoMap[circleInfo]; + } + + bool SkinPage::hasRoom(CircleInfo const & circleInfo) const + { + unsigned r = circleInfo.m_isOutlined ? circleInfo.m_radius + 1 : circleInfo.m_radius; + return m_packer.hasRoom(r * 2 + 4, + r * 2 + 4); + } uint32_t SkinPage::findPenInfo(PenInfo const & penInfo) const { @@ -397,17 +449,21 @@ namespace yg penInfo.m_color.b, penInfo.m_color.a)); - /// making alpha channel opaque +/* /// in non-transparent areas - premultiply color value with alpha and make it opaque for (size_t x = 2; x < v.width() - 2; ++x) for (size_t y = 2; y < v.height() - 2; ++y) { unsigned char alpha = gil::get_color(v(x, y), gil::alpha_t()); - if (alpha != 0) - { - v(x, y) = penColor; -// gil::get_color(v(x, y), gil::alpha_t()) = alpha; - } - } + float fAlpha = alpha / (float)TDynamicTexture::maxChannelVal; +// if (alpha != 0) +// { + gil::get_color(v(x, y), gil::red_t()) *= fAlpha; + gil::get_color(v(x, y), gil::green_t()) *= fAlpha; + gil::get_color(v(x, y), gil::blue_t()) *= fAlpha; + +// gil::get_color(v(x, y), gil::alpha_t()) = TDynamicTexture::maxChannelVal; +// } + }*/ } else { @@ -478,6 +534,150 @@ namespace yg m_penUploadCommands.clear(); } + void SkinPage::uploadCircleInfo() + { + for (size_t i = 0; i < m_circleUploadCommands.size(); ++i) + { + yg::CircleInfo & circleInfo = m_circleUploadCommands[i].m_circleInfo; + m2::RectU const & rect = m_circleUploadCommands[i].m_rect; + + TDynamicTexture * dynTexture = static_cast(m_texture.get()); + + TDynamicTexture::view_t v = dynTexture->view(rect.SizeX(), rect.SizeY()); + + agg::rgba8 aggColor(circleInfo.m_color.r, + circleInfo.m_color.g, + circleInfo.m_color.b, + circleInfo.m_color.a); + + agg::rgba8 aggOutlineColor(circleInfo.m_outlineColor.r, + circleInfo.m_outlineColor.g, + circleInfo.m_outlineColor.b, + circleInfo.m_outlineColor.a); + + circleInfo.m_color /= TDynamicTexture::channelScaleFactor; + + TDynamicTexture::pixel_t gilColorTranslucent; + + gil::get_color(gilColorTranslucent, gil::red_t()) = circleInfo.m_color.r; + gil::get_color(gilColorTranslucent, gil::green_t()) = circleInfo.m_color.g; + gil::get_color(gilColorTranslucent, gil::blue_t()) = circleInfo.m_color.b; + gil::get_color(gilColorTranslucent, gil::alpha_t()) = 0; + + circleInfo.m_outlineColor /= TDynamicTexture::channelScaleFactor; + + TDynamicTexture::pixel_t gilOutlineColorTranslucent; + + gil::get_color(gilOutlineColorTranslucent, gil::red_t()) = circleInfo.m_outlineColor.r; + gil::get_color(gilOutlineColorTranslucent, gil::green_t()) = circleInfo.m_outlineColor.g; + gil::get_color(gilOutlineColorTranslucent, gil::blue_t()) = circleInfo.m_outlineColor.b; + gil::get_color(gilOutlineColorTranslucent, gil::alpha_t()) = 0; + + TDynamicTexture::pixel_t gilColor = gilColorTranslucent; + gil::get_color(gilColor, gil::alpha_t()) = circleInfo.m_color.a; + + TDynamicTexture::pixel_t gilOutlineColor = gilOutlineColorTranslucent; + gil::get_color(gilOutlineColor, gil::alpha_t()) = circleInfo.m_outlineColor.a; + + /// draw circle + agg::rendering_buffer buf( + (unsigned char *)&v(0, 0), + rect.SizeX(), + rect.SizeY(), + rect.SizeX() * sizeof(TDynamicTexture::pixel_t) + ); + + typedef AggTraits::pixfmt_t agg_pixfmt_t; + + agg_pixfmt_t pixfmt(buf); + agg::renderer_base rbase(pixfmt); + + if (circleInfo.m_isOutlined) + gil::fill_pixels(v, gilOutlineColorTranslucent); + else + gil::fill_pixels(v, gilColorTranslucent); + + m2::PointD center(circleInfo.m_radius + 2, circleInfo.m_radius + 2); + + if (circleInfo.m_isOutlined) + center += m2::PointD(1, 1); + + agg::scanline_u8 s; + agg::rasterizer_scanline_aa<> rasterizer; + + agg::ellipse ell; + + ell.init(center.x, + center.y, + circleInfo.m_isOutlined ? circleInfo.m_radius + 1 : circleInfo.m_radius, + circleInfo.m_isOutlined ? circleInfo.m_radius + 1 : circleInfo.m_radius, + 100); + + rasterizer.add_path(ell); + + agg::render_scanlines_aa_solid(rasterizer, + s, + rbase, + circleInfo.m_isOutlined ? aggOutlineColor : aggColor); + + TDynamicTexture::pixel_t px = circleInfo.m_isOutlined ? gilOutlineColor : gilColor; + + /// making alpha channel opaque +/* for (size_t x = 2; x < v.width() - 2; ++x) + for (size_t y = 2; y < v.height() - 2; ++y) + { + unsigned char alpha = gil::get_color(v(x, y), gil::alpha_t()); + + float fAlpha = alpha / (float)TDynamicTexture::maxChannelVal; + + if (alpha != 0) + { + gil::get_color(v(x, y), gil::red_t()) *= fAlpha; + gil::get_color(v(x, y), gil::green_t()) *= fAlpha; + gil::get_color(v(x, y), gil::blue_t()) *= fAlpha; + + gil::get_color(v(x, y), gil::alpha_t()) = TDynamicTexture::maxChannelVal; + } + } + */ + if (circleInfo.m_isOutlined) + { + /// drawing inner circle + ell.init(center.x, + center.y, + circleInfo.m_radius, + circleInfo.m_radius, + 100); + + rasterizer.reset(); + rasterizer.add_path(ell); + + agg::render_scanlines_aa_solid(rasterizer, + s, + rbase, + aggColor); +/* for (size_t x = 2; x < v.width() - 2; ++x) + for (size_t y = 2; y < v.height() - 2; ++y) + { + unsigned char alpha = gil::get_color(v(x, y), gil::alpha_t()); + float fAlpha = alpha / (float)TDynamicTexture::maxChannelVal; +// if (alpha != 0) +// { + gil::get_color(v(x, y), gil::red_t()) *= fAlpha; + gil::get_color(v(x, y), gil::green_t()) *= fAlpha; + gil::get_color(v(x, y), gil::blue_t()) *= fAlpha; + +// gil::get_color(v(x, y), gil::alpha_t()) = TDynamicTexture::maxChannelVal; +// } + }*/ + } + + dynTexture->upload(&v(0, 0), rect); + } + + m_circleUploadCommands.clear(); + } + void SkinPage::uploadGlyphs() { for (size_t i = 0; i < m_glyphUploadCommands.size(); ++i) @@ -566,6 +766,7 @@ namespace yg uploadColors(); uploadPenInfo(); uploadGlyphs(); + uploadCircleInfo(); static_cast(m_texture.get())->unlock(); } } diff --git a/yg/skin_page.hpp b/yg/skin_page.hpp index 760a4d0886..4378e4d88c 100644 --- a/yg/skin_page.hpp +++ b/yg/skin_page.hpp @@ -9,6 +9,7 @@ #include "../geometry/rect2d.hpp" #include "pen_info.hpp" +#include "circle_info.hpp" #include "color.hpp" #include "glyph_cache.hpp" @@ -47,6 +48,14 @@ namespace yg PenUploadCmd(); }; + struct CircleUploadCmd + { + yg::CircleInfo m_circleInfo; + m2::RectU m_rect; + CircleUploadCmd(yg::CircleInfo const & circleInfo, m2::RectU const & rect); + CircleUploadCmd(); + }; + struct FontInfo { int8_t m_fontSize; @@ -67,17 +76,18 @@ namespace yg private: -// typedef unordered_map > TStyles; typedef map > TStyles; TStyles m_styles; -// typedef unordered_map TPointNameMap; typedef map TPointNameMap; TPointNameMap m_pointNameMap; typedef map TPenInfoMap; TPenInfoMap m_penInfoMap; + typedef map TCircleInfoMap; + TCircleInfoMap m_circleInfoMap; + typedef map TColorMap; TColorMap m_colorMap; @@ -91,10 +101,12 @@ namespace yg vector m_colorUploadCommands; vector m_penUploadCommands; vector m_glyphUploadCommands; + vector m_circleUploadCommands; void uploadPenInfo(); void uploadColors(); void uploadGlyphs(); + void uploadCircleInfo(); typedef vector TFonts; TFonts m_fonts; @@ -113,6 +125,7 @@ namespace yg void clearColorHandles(); void clearPenInfoHandles(); void clearFontHandles(); + void clearCircleInfoHandles(); void clearHandles(); @@ -140,6 +153,10 @@ namespace yg uint32_t mapPenInfo(PenInfo const & penInfo); bool hasRoom(PenInfo const & penInfo) const; + uint32_t findCircleInfo(CircleInfo const & circleInfo) const; + uint32_t mapCircleInfo(CircleInfo const & circleInfo); + bool hasRoom(CircleInfo const & circleInfo) const; + uint32_t findGlyph(GlyphKey const & g, bool isFixedFont) const; uint32_t mapGlyph(GlyphKey const & g); bool hasRoom(GlyphKey const & g) const; diff --git a/yg/yg_tests/screengl_test.cpp b/yg/yg_tests/screengl_test.cpp index 37af0a988d..7d56c6c39a 100644 --- a/yg/yg_tests/screengl_test.cpp +++ b/yg/yg_tests/screengl_test.cpp @@ -926,6 +926,15 @@ namespace } }; + struct TestDrawCircle + { + void DoDraw(shared_ptr const & p) + { + p->drawCircle(m2::PointD(200, 200), p->skin()->mapCircleInfo(yg::CircleInfo(10, yg::Color(255, 0, 0, 255))), 100); + p->drawCircle(m2::PointD(100, 200), p->skin()->mapCircleInfo(yg::CircleInfo(10, yg::Color(255, 0, 0, 255), true, yg::Color(255, 255, 255, 255))), 100); + } + }; + // UNIT_TEST_GL(TestDrawPolyOverflow); // UNIT_TEST_GL(TestDrawText); // UNIT_TEST_GL(TestDrawSingleSymbol); @@ -948,14 +957,15 @@ namespace // UNIT_TEST_GL(TestDrawPathWithSkinPageMiss); // UNIT_TEST_GL(TestDrawPathWithOffset); // UNIT_TEST_GL(TestDrawPathJoin); -// UNIT_TEST_GL(TestDrawPathSolid1PX); -// UNIT_TEST_GL(TestDrawPathSolid2PX); -// UNIT_TEST_GL(TestDrawPathSolid); + UNIT_TEST_GL(TestDrawPathSolid1PX); + UNIT_TEST_GL(TestDrawPathSolid2PX); + UNIT_TEST_GL(TestDrawPathSolid); // UNIT_TEST_GL(TestDrawSector); -// UNIT_TEST_GL(TestDrawPathSolidDiffWidth); + UNIT_TEST_GL(TestDrawPathSolidDiffWidth); // UNIT_TEST_GL(TestDrawPathSolidWithZ); // UNIT_TEST_GL(TestDrawPathSolidWithClipRect); // UNIT_TEST_GL(TestDrawUtilsRect); // UNIT_TEST_GL(TestDrawUtilsRectFilledTexture); - UNIT_TEST_GL(TestDrawSymbolFiltering); +// UNIT_TEST_GL(TestDrawSymbolFiltering); + UNIT_TEST_GL(TestDrawCircle); }