diff --git a/map/compass_arrow.cpp b/map/compass_arrow.cpp new file mode 100644 index 0000000000..d24ec374f1 --- /dev/null +++ b/map/compass_arrow.cpp @@ -0,0 +1,162 @@ +#include "compass_arrow.hpp" +#include "framework.hpp" +#include "rotate_screen_task.hpp" + +#include "../anim/controller.hpp" + +#include "../gui/controller.hpp" + +#include "../geometry/any_rect2d.hpp" +#include "../geometry/transformations.hpp" + +#include "../yg/display_list.hpp" +#include "../yg/screen.hpp" +#include "../yg/skin.hpp" + +CompassArrow::CompassArrow(Params const & p) + : base_t(p), + m_boundRects(1) +{ + m_arrowWidth = p.m_arrowWidth; + m_arrowHeight = p.m_arrowHeight; + m_northColor = p.m_northColor; + m_southColor = p.m_southColor; + m_framework = p.m_framework; + m_angle = 0; +} + +void CompassArrow::setAngle(double angle) +{ + m_angle = angle; + m_drawM = math::Shift(math::Rotate(math::Identity(), m_angle), pivot() * visualScale()); + + setIsDirtyRect(true); +} + +vector const & CompassArrow::boundRects() const +{ + if (isDirtyRect()) + { + double k = visualScale(); + + m2::PointD pv = pivot() * k; + double halfW = m_arrowWidth / 2.0 * k; + double halfH = m_arrowHeight / 2.0 * k; + + m_boundRects[0] = m2::AnyRectD(pv, + -math::pi / 2 + m_angle, + m2::RectD(-halfW, -halfH, halfW, halfH)); + + setIsDirtyRect(false); + } + + return m_boundRects; +} + +void CompassArrow::draw(yg::gl::OverlayRenderer * r, + math::Matrix const & m) const +{ + if (isVisible()) + { + checkDirtyDrawing(); + m_displayList->draw(m_drawM * m); + } +} + +void CompassArrow::cache() +{ + yg::gl::Screen * cacheScreen = m_controller->GetCacheScreen(); + + m_displayList.reset(); + m_displayList.reset(cacheScreen->createDisplayList()); + + cacheScreen->beginFrame(); + cacheScreen->setDisplayList(m_displayList.get()); + + double k = visualScale(); + + double halfW = m_arrowWidth / 2.0 * k; + double halfH = m_arrowHeight / 2.0 * k; + + m2::PointF northPts[3] = { + m2::PointF(-halfW, 0), + m2::PointF(0, -halfH), + m2::PointF(halfW, 0) + }; + + cacheScreen->drawConvexPolygon(northPts, 3, m_northColor, depth()); + + m2::PointF southPts[3] = { + m2::PointF(-halfW, 0), + m2::PointF(halfW, 0), + m2::PointF(0, halfH), + }; + + cacheScreen->drawConvexPolygon(southPts, 3, m_southColor, depth()); + + m2::PointD outlinePts[6] = { + m2::PointD(-halfW, 0), + m2::PointD(0, -halfH), + m2::PointD(halfW, 0), + m2::PointD(0, halfH), + m2::PointD(-halfW, 0), + m2::PointD(halfW, 0) + }; + + yg::PenInfo outlinePenInfo(yg::Color(32, 32, 32, 255), 1, 0, 0, 0); + + cacheScreen->drawPath(outlinePts, sizeof(outlinePts) / sizeof(m2::PointD), 0, cacheScreen->skin()->mapPenInfo(outlinePenInfo), depth()); + + m_drawM = math::Shift(math::Rotate(math::Identity(), m_angle), pivot() * k); + + cacheScreen->setDisplayList(0); + cacheScreen->endFrame(); + + // we should not call cacheScreen->completeCommands + // as the gui::Element::cache is called on the GUI thread. +} + +void CompassArrow::purge() +{ + m_displayList.reset(); +} + +bool CompassArrow::onTapEnded(m2::PointD const & pt) +{ + shared_ptr animController = m_framework->GetRenderPolicy()->GetAnimController(); + animController->Lock(); + + if (m_rotateScreenTask + && !m_rotateScreenTask->IsEnded() + && !m_rotateScreenTask->IsCancelled()) + m_rotateScreenTask->Cancel(); + m_rotateScreenTask.reset(); + + double startAngle = m_framework->GetNavigator().Screen().GetAngle(); + double endAngle = 0; + + double period = 2 * math::pi; + + startAngle -= floor(startAngle / period) * period; + endAngle -= floor(endAngle / period) * period; + + if (fabs(startAngle - endAngle) > math::pi) + startAngle -= 2 * math::pi; + + m_rotateScreenTask.reset(new RotateScreenTask(m_framework, + startAngle, + endAngle, + 1)); + animController->AddTask(m_rotateScreenTask); + + animController->Unlock(); + + m_framework->Invalidate(); + + return true; +} + +bool CompassArrow::hitTest(m2::PointD const & pt) const +{ + return pt.Length(pivot() * visualScale()) < max(m_arrowWidth / 2, m_arrowHeight / 2); +} diff --git a/map/compass_arrow.hpp b/map/compass_arrow.hpp new file mode 100644 index 0000000000..0ffd07531d --- /dev/null +++ b/map/compass_arrow.hpp @@ -0,0 +1,69 @@ +#pragma once + +#include "../gui/element.hpp" + +#include "../yg/color.hpp" + +#include "../geometry/any_rect2d.hpp" + +#include "../std/shared_ptr.hpp" + +namespace yg +{ + namespace gl + { + class DisplayList; + } +} + +class RotateScreenTask; +class Framework; + +/// Compass Arrow, which shows up when the screen is rotated, +/// and rotates screen back to straight orientation when beeing pressed +class CompassArrow : public gui::Element +{ +private: + + typedef gui::Element base_t; + + unsigned m_arrowWidth; + unsigned m_arrowHeight; + yg::Color m_northColor; + yg::Color m_southColor; + double m_angle; + + shared_ptr m_displayList; + shared_ptr m_rotateScreenTask; + + mutable vector m_boundRects; + + math::Matrix m_drawM; + + Framework * m_framework; + + void cache(); + void purge(); + +public: + + struct Params : public base_t::Params + { + unsigned m_arrowWidth; + unsigned m_arrowHeight; + yg::Color m_northColor; + yg::Color m_southColor; + Framework * m_framework; + }; + + CompassArrow(Params const & p); + + void setAngle(double angle); + + vector const & boundRects() const; + void draw(yg::gl::OverlayRenderer * r, math::Matrix const & m) const; + + bool onTapEnded(m2::PointD const & pt); + + bool hitTest(m2::PointD const & pt) const; +}; diff --git a/map/framework.cpp b/map/framework.cpp index 0a8fc52df0..9b00940107 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -571,6 +571,8 @@ void Framework::DrawAdditionalInfo(shared_ptr const & e) m_informationDisplay.setEmptyCountryName(m_renderPolicy->GetCountryName()); m_informationDisplay.enableCountryStatusDisplay(isEmptyModel); + m_informationDisplay.enableCompassArrow(m_navigator.Screen().GetAngle() != 0); + m_informationDisplay.setCompassArrowAngle(m_navigator.Screen().GetAngle()); m_informationDisplay.setScreen(m_navigator.Screen()); diff --git a/map/information_display.cpp b/map/information_display.cpp index af09134407..1b04155d7f 100644 --- a/map/information_display.cpp +++ b/map/information_display.cpp @@ -1,6 +1,7 @@ #include "information_display.hpp" #include "drawer_yg.hpp" #include "country_status_display.hpp" +#include "compass_arrow.hpp" #include "framework.hpp" #include "../indexer/mercator.hpp" @@ -37,6 +38,19 @@ InformationDisplay::InformationDisplay(Framework * framework) m_countryStatusDisplay.reset(new CountryStatusDisplay(p)); + CompassArrow::Params cap; + + cap.m_position = yg::EPosCenter; + cap.m_depth = yg::maxDepth; + cap.m_arrowHeight = 60; + cap.m_arrowWidth = 20; + cap.m_pivot = m2::PointD(10 + cap.m_arrowHeight / 2, 10 + cap.m_arrowHeight / 2); + cap.m_northColor = yg::Color(255, 0, 0, 255); + cap.m_southColor = yg::Color(255, 255, 255, 255); + cap.m_framework = framework; + + m_compassArrow.reset(new CompassArrow(cap)); + location::State::Params lsp; lsp.m_position = yg::EPosCenter; @@ -57,6 +71,7 @@ InformationDisplay::InformationDisplay(Framework * framework) enableMemoryWarning(false); enableBenchmarkInfo(false); enableCountryStatusDisplay(false); + enableCompassArrow(false); for (int i = 0; i < sizeof(m_DebugPts) / sizeof(m2::PointD); ++i) m_DebugPts[i] = m2::PointD(0, 0); @@ -68,6 +83,7 @@ void InformationDisplay::setController(gui::Controller *controller) { m_controller = controller; m_controller->AddElement(m_countryStatusDisplay); + m_controller->AddElement(m_compassArrow); m_controller->AddElement(m_locationState); } @@ -368,6 +384,16 @@ void InformationDisplay::drawLog(DrawerYG * drawer) } */ +void InformationDisplay::enableCompassArrow(bool doEnable) +{ + m_compassArrow->setIsVisible(doEnable); +} + +void InformationDisplay::setCompassArrowAngle(double angle) +{ + m_compassArrow->setAngle(angle); +} + void InformationDisplay::enableCountryStatusDisplay(bool doEnable) { m_countryStatusDisplay->setIsVisible(doEnable); diff --git a/map/information_display.hpp b/map/information_display.hpp index d49888b9b0..665c7af4ed 100644 --- a/map/information_display.hpp +++ b/map/information_display.hpp @@ -24,6 +24,7 @@ namespace gui class Framework; class CountryStatusDisplay; +class CompassArrow; /// Class, which displays additional information on the primary layer. /// like rules, coordinates, GPS position and heading @@ -80,6 +81,7 @@ private: static WindowHandle * s_windowHandle; */ shared_ptr m_countryStatusDisplay; + shared_ptr m_compassArrow; shared_ptr m_locationState; public: @@ -126,6 +128,9 @@ public: void setLogSize(size_t logSize); void drawLog(DrawerYG * pDrawer); + void enableCompassArrow(bool doEnable); + void setCompassArrowAngle(double angle); + shared_ptr const & locationState() const; void enableCountryStatusDisplay(bool doEnable); diff --git a/map/map.pro b/map/map.pro index 97e8d44fb5..2c7eccabe5 100644 --- a/map/map.pro +++ b/map/map.pro @@ -48,7 +48,8 @@ HEADERS += \ tile_set.hpp \ geourl_process.hpp \ country_status_display.hpp \ - rotate_screen_task.hpp + rotate_screen_task.hpp \ + compass_arrow.hpp SOURCES += \ feature_vec_model.cpp \ @@ -88,7 +89,8 @@ SOURCES += \ geourl_process.cpp \ bookmark.cpp \ country_status_display.cpp \ - rotate_screen_task.cpp + rotate_screen_task.cpp \ + compass_arrow.cpp !iphone*:!bada*:!android* { HEADERS += qgl_render_context.hpp @@ -105,3 +107,5 @@ SOURCES += \ + + diff --git a/yg/area_renderer.cpp b/yg/area_renderer.cpp index 48c26e1ffd..d5d27e8db0 100644 --- a/yg/area_renderer.cpp +++ b/yg/area_renderer.cpp @@ -36,10 +36,55 @@ namespace yg base_t::endFrame(); } + void AreaRenderer::drawTrianglesFan(m2::PointF const * points, + size_t pointsCount, + uint32_t styleID, + double depth) + { + ++m_areasCount; + m_trianglesCount += (pointsCount - 2); + + if (!m_drawAreas) + return; + + ResourceStyle const * style = skin()->fromID(styleID); + + if (style == 0) + { + LOG(LINFO, ("drawTrianglesFan: styleID=", styleID, " wasn't found on current skin.")); + return; + } + + ASSERT_GREATER_OR_EQUAL(pointsCount, 2, ()); + + float texX = style->m_texRect.minX() + 1.0f; + float texY = style->m_texRect.minY() + 1.0f; + + shared_ptr texture = skin()->getPage(style->m_pipelineID)->texture(); + + if (!texture) + { + LOG(LDEBUG, ("returning as no texture is reserved")); + return; + } + + texture->mapPixel(texX, texY); + + m2::PointF texCoord(texX, texY); + m2::PointF normal(0, 0); + + addTexturedFanStrided(points, sizeof(m2::PointF), + &normal, 0, + &texCoord, 0, + pointsCount, + depth, + style->m_pipelineID); + } + void AreaRenderer::drawTrianglesList(m2::PointD const * points, size_t pointsCount, uint32_t styleID, double depth) { ++m_areasCount; - m_trianglesCount += pointsCount; + m_trianglesCount += pointsCount / 3; if (!m_drawAreas) return; diff --git a/yg/area_renderer.hpp b/yg/area_renderer.hpp index 707cbb525c..33d13d7b20 100644 --- a/yg/area_renderer.hpp +++ b/yg/area_renderer.hpp @@ -32,6 +32,11 @@ namespace yg uint32_t styleID, double depth); + void drawTrianglesFan(m2::PointF const * points, + size_t pointsCount, + uint32_t styleID, + double depth); + void beginFrame(); void endFrame(); }; diff --git a/yg/overlay_element.cpp b/yg/overlay_element.cpp index 1584a8debf..12a38e1cb4 100644 --- a/yg/overlay_element.cpp +++ b/yg/overlay_element.cpp @@ -19,6 +19,7 @@ namespace yg m_isVisible(true), m_isValid(true), m_isDirtyRect(true), + m_isDirtyDrawing(true), m_isDirtyRoughRect(true) {} diff --git a/yg/overlay_element.hpp b/yg/overlay_element.hpp index 4f1ea2845b..02732c9339 100644 --- a/yg/overlay_element.hpp +++ b/yg/overlay_element.hpp @@ -82,8 +82,8 @@ namespace yg bool isValid() const; void setIsValid(bool flag); - bool hitTest(m2::PointD const & pt) const; - bool roughHitTest(m2::PointD const & pt) const; + virtual bool hitTest(m2::PointD const & pt) const; + virtual bool roughHitTest(m2::PointD const & pt) const; m2::RectD const & roughBoundRect() const; }; diff --git a/yg/shape_renderer.cpp b/yg/shape_renderer.cpp index 266aa4c046..3155733712 100644 --- a/yg/shape_renderer.cpp +++ b/yg/shape_renderer.cpp @@ -17,6 +17,19 @@ namespace yg { } + void ShapeRenderer::drawConvexPolygon(m2::PointF const * pts, size_t ptsCount, yg::Color const & color, double depth) + { + uint32_t styleID = skin()->mapColor(color); + + if (styleID == skin()->invalidHandle()) + { + LOG(LINFO, ("cannot map color")); + return; + } + + drawTrianglesFan(pts, ptsCount, styleID, depth); + } + void ShapeRenderer::drawArc(m2::PointD const & center, double startA, double endA, double r, yg::Color const & c, double depth) { vector pts; diff --git a/yg/shape_renderer.hpp b/yg/shape_renderer.hpp index 2303d2e441..79170fd7f0 100644 --- a/yg/shape_renderer.hpp +++ b/yg/shape_renderer.hpp @@ -16,14 +16,50 @@ namespace yg ShapeRenderer(base_t::Params const & params); - static void approximateArc(m2::PointD const & center, double startA, double endA, double r, vector & pts); - 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 drawConvexPolygon(m2::PointF const * points, + size_t pointsCount, + yg::Color const & color, + double depth); - void drawRectangle(m2::AnyRectD const & r, yg::Color const & c, double depth); - void drawRectangle(m2::RectD const & r, yg::Color const & c, double depth); - void drawRoundedRectangle(m2::RectD const & r, double rad, yg::Color const & c, double depth); + static void approximateArc(m2::PointD const & center, + double startA, + double endA, + double r, + vector & pts); + + 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 drawRectangle(m2::AnyRectD const & r, + yg::Color const & c, + double depth); + + void drawRectangle(m2::RectD const & r, + yg::Color const & c, + double depth); + + void drawRoundedRectangle(m2::RectD const & r, + double rad, + yg::Color const & c, + double depth); }; } }