From 2ab06f38c7743dd93e9ad050fab169e7d04d6bdb Mon Sep 17 00:00:00 2001 From: ExMix Date: Thu, 5 Mar 2015 15:10:04 +0300 Subject: [PATCH] [drape] Rule and Ruler text. Global callbacks for gui subsystem --- drape/batcher.cpp | 4 +- drape/batcher.hpp | 6 +- drape/drape.pro | 3 +- drape/shaders/ruler_vertex_shader.vsh | 14 ++ drape/shaders/shader_index.txt | 1 + drape/shaders/text_fragment_shader.fsh | 9 +- drape_frontend/backend_renderer.cpp | 2 +- drape_frontend/drape_engine.cpp | 13 ++ drape_gui/compass.cpp | 24 +-- drape_gui/drape_gui.cpp | 40 ++++ drape_gui/drape_gui.hpp | 30 +++ drape_gui/drape_gui.pro | 14 +- drape_gui/drape_gui_tests/skin_tests.cpp | 4 +- drape_gui/gui_text.cpp | 200 ++++++++++++++++++ drape_gui/gui_text.hpp | 67 ++++++ drape_gui/layer_render.cpp | 36 +++- drape_gui/layer_render.hpp | 9 +- drape_gui/ruler.cpp | 140 ++++++++++++ drape_gui/ruler.hpp | 16 ++ drape_gui/ruler_helper.cpp | 257 +++++++++++++++++++++++ drape_gui/ruler_helper.hpp | 37 ++++ drape_gui/ruler_text.cpp | 120 +++++++++++ drape_gui/ruler_text.hpp | 23 ++ drape_gui/shape.cpp | 30 ++- drape_gui/shape.hpp | 12 +- drape_gui/skin.cpp | 6 +- drape_gui/skin.hpp | 3 +- drape_head/testing_engine.cpp | 88 +++++++- std/iterator.hpp | 2 + 29 files changed, 1142 insertions(+), 68 deletions(-) create mode 100644 drape/shaders/ruler_vertex_shader.vsh create mode 100644 drape_gui/drape_gui.cpp create mode 100644 drape_gui/drape_gui.hpp create mode 100644 drape_gui/gui_text.cpp create mode 100644 drape_gui/gui_text.hpp create mode 100644 drape_gui/ruler.cpp create mode 100644 drape_gui/ruler.hpp create mode 100644 drape_gui/ruler_helper.cpp create mode 100644 drape_gui/ruler_helper.hpp create mode 100644 drape_gui/ruler_text.cpp create mode 100644 drape_gui/ruler_text.hpp diff --git a/drape/batcher.cpp b/drape/batcher.cpp index 48726f2403..4e7d8dd9f2 100644 --- a/drape/batcher.cpp +++ b/drape/batcher.cpp @@ -139,7 +139,7 @@ void Batcher::InsertListOfStrip(GLState const & state, RefPointer(state, params, handle, vertexStride); } -void Batcher::StartSession(flush_fn const & flusher) +void Batcher::StartSession(TFlushFn const & flusher) { m_flushInterface = flusher; } @@ -147,7 +147,7 @@ void Batcher::StartSession(flush_fn const & flusher) void Batcher::EndSession() { Flush(); - m_flushInterface = flush_fn(); + m_flushInterface = TFlushFn(); } void Batcher::ChangeBuffer(RefPointer wrapper, bool checkFilledBuffer) diff --git a/drape/batcher.hpp b/drape/batcher.hpp index 9afcabe681..ede182b9ba 100644 --- a/drape/batcher.hpp +++ b/drape/batcher.hpp @@ -44,8 +44,8 @@ public: TransferPointer handle, uint8_t vertexStride); - typedef function )> flush_fn; - void StartSession(flush_fn const & flusher); + typedef function )> TFlushFn; + void StartSession(TFlushFn const & flusher); void EndSession(); private: @@ -64,7 +64,7 @@ private: void Flush(); private: - flush_fn m_flushInterface; + TFlushFn m_flushInterface; private: typedef map > buckets_t; diff --git a/drape/drape.pro b/drape/drape.pro index ccd0c63d4e..d6b5dbf6bb 100644 --- a/drape/drape.pro +++ b/drape/drape.pro @@ -19,4 +19,5 @@ OTHER_FILES += \ shaders/line_fragment_shader.fsh \ shaders/text_fragment_shader.fsh \ shaders/text_vertex_shader.vsh \ - shaders/compass_vertex_shader.vsh + shaders/compass_vertex_shader.vsh \ + shaders/ruler_vertex_shader.vsh diff --git a/drape/shaders/ruler_vertex_shader.vsh b/drape/shaders/ruler_vertex_shader.vsh new file mode 100644 index 0000000000..3bb107ed1c --- /dev/null +++ b/drape/shaders/ruler_vertex_shader.vsh @@ -0,0 +1,14 @@ +attribute vec2 a_position; +attribute vec2 a_normal; +attribute vec2 a_colorTexCoords; + +uniform float u_length; +uniform mat4 projection; + +varying vec2 v_colorTexCoords; + +void main(void) +{ + gl_Position = vec4(a_position + u_length * a_normal, 0, 1) * projection; + v_colorTexCoords = a_colorTexCoords; +} diff --git a/drape/shaders/shader_index.txt b/drape/shaders/shader_index.txt index d10a51cf2c..f350d6cd03 100644 --- a/drape/shaders/shader_index.txt +++ b/drape/shaders/shader_index.txt @@ -2,3 +2,4 @@ TEXTURING_PROGRAM texturing_vertex_shader.vsh texturing_fragment_shader.fsh LINE_PROGRAM line_vertex_shader.vsh line_fragment_shader.fsh TEXT_PROGRAM text_vertex_shader.vsh text_fragment_shader.fsh COMPASS_PROGRAM compass_vertex_shader.vsh texturing_fragment_shader.fsh +RULER_PROGRAM ruler_vertex_shader.vsh texturing_fragment_shader.fsh diff --git a/drape/shaders/text_fragment_shader.fsh b/drape/shaders/text_fragment_shader.fsh index 48e021f400..fe1d2f3de4 100755 --- a/drape/shaders/text_fragment_shader.fsh +++ b/drape/shaders/text_fragment_shader.fsh @@ -1,3 +1,4 @@ + varying vec2 v_colorTexCoord; varying vec2 v_outlineColorTexCoord; varying vec2 v_maskTexCoord; @@ -37,8 +38,8 @@ vec4 without_outline(vec4 base, float alpha) { if (alpha > GLYPH_MIN_VALUE) { - float oFactor = smoothstep(GLYPH_MIN_VALUE, GLYPH_MAX_VALUE, alpha ); - return mix(base, vec4(1, 1, 1, 0), oFactor); + float oFactor = smoothstep(GLYPH_MIN_VALUE, GLYPH_MAX_VALUE, alpha); + return mix(base, vec4(0, 0, 0, 0), oFactor); } return base; } @@ -51,9 +52,9 @@ void main (void) vec4 finalColor; if (outline.a > 0.1) - finalColor = colorize(base, outline, 1.0 - base.a * alpha); + finalColor = colorize(base, outline, 1.0 - alpha); else - finalColor = without_outline(base, 1.0 - base.a * alpha); + finalColor = without_outline(base, 1.0 - alpha); gl_FragColor = finalColor; } diff --git a/drape_frontend/backend_renderer.cpp b/drape_frontend/backend_renderer.cpp index d3b11514ae..5f891124b0 100644 --- a/drape_frontend/backend_renderer.cpp +++ b/drape_frontend/backend_renderer.cpp @@ -27,7 +27,7 @@ BackendRenderer::BackendRenderer(dp::RefPointer commutator, : m_model(model) , m_engineContext(commutator) , m_texturesManager(textureManager) - , m_guiCacher("default", df::VisualParams::Instance().GetVisualScale()) + , m_guiCacher("default") , m_commutator(commutator) , m_contextFactory(oglcontextfactory) { diff --git a/drape_frontend/drape_engine.cpp b/drape_frontend/drape_engine.cpp index 15b2296bf6..a7cf5f99a5 100644 --- a/drape_frontend/drape_engine.cpp +++ b/drape_frontend/drape_engine.cpp @@ -3,6 +3,8 @@ #include "drape_frontend/message_subclasses.hpp" #include "drape_frontend/visual_params.hpp" +#include "drape_gui/drape_gui.hpp" + #include "drape/texture_manager.hpp" #include "std/bind.hpp" @@ -18,6 +20,17 @@ DrapeEngine::DrapeEngine(dp::RefPointer contextfactory, { VisualParams::Init(vs, df::CalculateTileSize(m_viewport.GetWidth(), m_viewport.GetHeight())); + gui::DrapeGui::TScaleFactorFn scaleFn = [] + { + return VisualParams::Instance().GetVisualScale(); + }; + gui::DrapeGui::TGeneralizationLevelFn gnLvlFn = [](ScreenBase const & screen) + { + return GetDrawTileScale(screen); + }; + + gui::DrapeGui::Instance().Init(scaleFn, gnLvlFn); + m_textureManager = dp::MasterPointer(new dp::TextureManager()); m_threadCommutator = dp::MasterPointer(new ThreadsCommutator()); dp::RefPointer commutatorRef = m_threadCommutator.GetRefPointer(); diff --git a/drape_gui/compass.cpp b/drape_gui/compass.cpp index 7a9636fe6c..2289de0c33 100644 --- a/drape_gui/compass.cpp +++ b/drape_gui/compass.cpp @@ -24,9 +24,8 @@ namespace class CompassHandle : public Handle { public: - CompassHandle(glsl::vec2 const & pivot) - : Handle(FeatureID(), dp::Center, 0.0) - , m_pivot(pivot) + CompassHandle(m2::PointF const & pivot) + : Handle(dp::Center, pivot) { } @@ -44,22 +43,6 @@ namespace m_uniforms.SetMatrix4x4Value("modelView", glsl::value_ptr(m)); } } - - virtual bool IndexesRequired() const override { return false; } - - virtual m2::RectD GetPixelRect(ScreenBase const & screen) const override - { - return m2::RectD(); - } - - virtual void GetPixelShape(ScreenBase const & screen, Rects & rects) const override - { - UNUSED_VALUE(screen); - UNUSED_VALUE(rects); - } - - private: - glsl::vec2 m_pivot; }; } @@ -80,7 +63,6 @@ void Compass::Draw(dp::RefPointer batcher, dp::RefPointer batcher, dp::RefPointer(&vertexes)); batcher->InsertTriangleStrip(state, dp::MakeStackRefPointer(&provider), - dp::MovePointer(new CompassHandle(glsl::ToVec2(m_position.m_pixelPivot)))); + dp::MovePointer(new CompassHandle(m_position.m_pixelPivot))); } uint16_t Compass::GetVertexCount() const diff --git a/drape_gui/drape_gui.cpp b/drape_gui/drape_gui.cpp new file mode 100644 index 0000000000..1794dcb160 --- /dev/null +++ b/drape_gui/drape_gui.cpp @@ -0,0 +1,40 @@ +#include "drape_gui.hpp" + +#include "../base/assert.hpp" + +namespace gui +{ + +struct DrapeGui::Impl +{ + DrapeGui::TScaleFactorFn m_scaleFn; + DrapeGui::TGeneralizationLevelFn m_gnLvlFn; +}; + +DrapeGui & DrapeGui::Instance() +{ + static DrapeGui s_gui; + return s_gui; +} + +void DrapeGui::Init(TScaleFactorFn const & scaleFn, TGeneralizationLevelFn const & gnLvlFn) +{ + ASSERT(m_impl == nullptr, ()); + m_impl.reset(new DrapeGui::Impl()); + m_impl->m_scaleFn = scaleFn; + m_impl->m_gnLvlFn = gnLvlFn; +} + +double DrapeGui::GetScaleFactor() +{ + ASSERT(m_impl != nullptr, ()); + return m_impl->m_scaleFn(); +} + +int DrapeGui::GetGeneralization(ScreenBase const & screen) +{ + ASSERT(m_impl != nullptr, ()); + return m_impl->m_gnLvlFn(screen); +} + +} diff --git a/drape_gui/drape_gui.hpp b/drape_gui/drape_gui.hpp new file mode 100644 index 0000000000..1d7a56fa3e --- /dev/null +++ b/drape_gui/drape_gui.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "../std/function.hpp" +#include "../std/unique_ptr.hpp" + +class ScreenBase; + +namespace gui +{ + +class DrapeGui +{ +public: + + typedef function TScaleFactorFn; + typedef function TGeneralizationLevelFn; + + static DrapeGui & Instance(); + + void Init(TScaleFactorFn const & scaleFn, TGeneralizationLevelFn const & gnLvlFn); + double GetScaleFactor(); + int GetGeneralization(ScreenBase const & screen); + +private: + struct Impl; + unique_ptr m_impl; + +}; + +} diff --git a/drape_gui/drape_gui.pro b/drape_gui/drape_gui.pro index bc08aec758..c7281be1a9 100644 --- a/drape_gui/drape_gui.pro +++ b/drape_gui/drape_gui.pro @@ -12,11 +12,21 @@ HEADERS += \ skin.hpp \ compass.hpp \ shape.hpp \ - layer_render.hpp + layer_render.hpp \ + ruler.hpp \ + ruler_helper.hpp \ + drape_gui.hpp \ + gui_text.hpp \ + ruler_text.hpp SOURCES += \ skin.cpp \ compass.cpp \ shape.cpp \ - layer_render.cpp + layer_render.cpp \ + ruler.cpp \ + ruler_helper.cpp \ + drape_gui.cpp \ + gui_text.cpp \ + ruler_text.cpp diff --git a/drape_gui/drape_gui_tests/skin_tests.cpp b/drape_gui/drape_gui_tests/skin_tests.cpp index fefc0b398f..e089ffcdbd 100644 --- a/drape_gui/drape_gui_tests/skin_tests.cpp +++ b/drape_gui/drape_gui_tests/skin_tests.cpp @@ -2,10 +2,12 @@ #include "../../testing/testing.hpp" #include "../skin.hpp" +#include "../drape_gui.hpp" UNIT_TEST(ParseDefaultSkinTest) { - gui::Skin skin(gui::ResolveGuiSkinFile("default"), 2.0); + gui::DrapeGui::Instance().Init([]{ return 2.0; }, [] (ScreenBase const &) { return 6.0f; }); + gui::Skin skin(gui::ResolveGuiSkinFile("default")); float width = 600.0f; float height = 800.0f; skin.Resize(width, height); diff --git a/drape_gui/gui_text.cpp b/drape_gui/gui_text.cpp new file mode 100644 index 0000000000..503264056d --- /dev/null +++ b/drape_gui/gui_text.cpp @@ -0,0 +1,200 @@ +#include "gui_text.hpp" +#include "drape_gui.hpp" + +#include "../base/string_utils.hpp" +#include "../base/stl_add.hpp" + +#include "../drape/fribidi.hpp" + +#include "../std/unique_ptr.hpp" +#include "../std/algorithm.hpp" + +namespace gui +{ + +dp::BindingInfo const & GuiText::StaticVertex::GetBindingInfo() +{ + static unique_ptr info; + + if (info == nullptr) + { + info.reset(new dp::BindingInfo(3)); + + dp::BindingDecl & posDecl = info->GetBindingDecl(0); + posDecl.m_attributeName = "a_position"; + posDecl.m_componentCount = 3; + posDecl.m_componentType = gl_const::GLFloatType; + posDecl.m_offset = 0; + posDecl.m_stride = sizeof(StaticVertex); + + dp::BindingDecl & colorDecl = info->GetBindingDecl(1); + colorDecl.m_attributeName = "a_colorTexCoord"; + colorDecl.m_componentCount = 2; + colorDecl.m_componentType = gl_const::GLFloatType; + colorDecl.m_offset = sizeof(glsl::vec3); + colorDecl.m_stride = posDecl.m_stride; + + dp::BindingDecl & outlineDecl = info->GetBindingDecl(2); + outlineDecl.m_attributeName = "a_outlineColorTexCoord"; + outlineDecl.m_componentCount = 2; + outlineDecl.m_componentType = gl_const::GLFloatType; + outlineDecl.m_offset = colorDecl.m_offset + sizeof(glsl::vec2); + outlineDecl.m_stride = posDecl.m_stride; + } + + return *info.get(); +} + +dp::BindingInfo const & GuiText::DynamicVertex::GetBindingInfo() +{ + static unique_ptr info; + + if (info == nullptr) + { + info.reset(new dp::BindingInfo(2, 1)); + + dp::BindingDecl & normalDecl = info->GetBindingDecl(0); + normalDecl.m_attributeName = "a_normal"; + normalDecl.m_componentCount = 2; + normalDecl.m_componentType = gl_const::GLFloatType; + normalDecl.m_offset = 0; + normalDecl.m_stride = sizeof(DynamicVertex); + + dp::BindingDecl & maskDecl = info->GetBindingDecl(1); + maskDecl.m_attributeName = "a_maskTexCoord"; + maskDecl.m_componentCount = 2; + maskDecl.m_componentType = gl_const::GLFloatType; + maskDecl.m_offset = sizeof(glsl::vec2); + maskDecl.m_stride = normalDecl.m_stride; + } + + return *info.get(); +} + +GuiText::GuiText(dp::Anchor anchor) + : m_anchor(anchor) +{ +} + +void GuiText::SetMaxLength(uint16_t maxLength) +{ + m_maxLength = maxLength; +} + +dp::RefPointer GuiText::SetAlphabet(string const & alphabet, dp::RefPointer mng) +{ + strings::UniString str = strings::MakeUniString(alphabet + "."); + strings::UniString::iterator it = unique(str.begin(), str.end()); + str.resize(distance(str.begin(), it)); + + dp::TextureManager::TGlyphsBuffer buffer; + mng->GetGlyphRegions(str, buffer); + m_alphabet.reserve(buffer.size()); + + ASSERT_EQUAL(str.size(), buffer.size(), ()); + m_alphabet.resize(str.size()); + transform(str.begin(), str.end(), buffer.begin(), m_alphabet.begin(), + [this](strings::UniChar const & c, dp::TextureManager::GlyphRegion const & r) + { + return make_pair(c, r); + }); + + sort(m_alphabet.begin(), m_alphabet.end(), [](TAlphabetNode const & n1, TAlphabetNode const & n2) + { + return n1.first < n2.first; + }); + + return m_alphabet[0].second.GetTexture(); +} + +dp::RefPointer GuiText::Precache(buffer_vector & buffer, dp::FontDecl const & font, + dp::RefPointer mng) +{ + float const baseHeight = 20.0f; + m_textRatio = font.m_size * DrapeGui::Instance().GetScaleFactor() / baseHeight; + + dp::TextureManager::ColorRegion color; + dp::TextureManager::ColorRegion outlineColor; + + mng->GetColorRegion(font.m_color, color); + mng->GetColorRegion(font.m_outlineColor, outlineColor); + + glsl::vec2 colorTex = glsl::ToVec2(color.GetTexRect().Center()); + glsl::vec2 outlineTex = glsl::ToVec2(outlineColor.GetTexRect().Center()); + float depth = 0.0f; + + for (size_t i = 0; i < m_maxLength; ++i) + { + buffer.push_back(StaticVertex(glsl::vec3(0.0, 0.0, depth), colorTex, outlineTex)); + buffer.push_back(StaticVertex(glsl::vec3(0.0, 0.0, depth), colorTex, outlineTex)); + buffer.push_back(StaticVertex(glsl::vec3(0.0, 0.0, depth), colorTex, outlineTex)); + buffer.push_back(StaticVertex(glsl::vec3(0.0, 0.0, depth), colorTex, outlineTex)); + depth += 10.0f; + } + + return color.GetTexture(); +} + +void GuiText::SetText(buffer_vector & buffer, string text) const +{ + if (text.size() > m_maxLength) + text = text.erase(m_maxLength - 3) + "..."; + + strings::UniString uniText = fribidi::log2vis(strings::MakeUniString(text)); + + float maxHeight = 0.0f; + float length = 0.0f; + glsl::vec2 offset = glsl::vec2(0.0, 0.0); + + for (size_t i = 0; i < uniText.size(); ++i) + { + strings::UniChar c = uniText[i]; + TAlphabet::const_iterator it = find_if(m_alphabet.begin(), m_alphabet.end(), [&c](TAlphabetNode const & n) + { + return n.first == c; + }); + + ASSERT(it != m_alphabet.end(), ()); + if (it != m_alphabet.end()) + { + dp::TextureManager::GlyphRegion const & glyph = it->second; + m2::PointF pixelSize = m2::PointF(glyph.GetPixelSize()) * m_textRatio; + m2::RectF const & r = glyph.GetTexRect(); + + float xOffset = glyph.GetOffsetX() * m_textRatio; + float yOffset = glyph.GetOffsetY() * m_textRatio; + + float const upVector = -static_cast(pixelSize.y) - yOffset; + float const bottomVector = -yOffset; + + buffer.push_back(DynamicVertex(offset + glsl::vec2(xOffset, bottomVector), glsl::ToVec2(r.LeftTop()))); + buffer.push_back(DynamicVertex(offset + glsl::vec2(xOffset, upVector), glsl::ToVec2(r.LeftBottom()))); + buffer.push_back(DynamicVertex(offset + glsl::vec2(pixelSize.x + xOffset, bottomVector), glsl::ToVec2(r.RightTop()))); + buffer.push_back(DynamicVertex(offset + glsl::vec2(pixelSize.x + xOffset, upVector), glsl::ToVec2(r.RightBottom()))); + + float const advance = glyph.GetAdvanceX() * m_textRatio; + length += advance + xOffset; + offset += glsl::vec2(advance, glyph.GetAdvanceY() * m_textRatio); + maxHeight = max(maxHeight, (glyph.GetPixelHeight() + glyph.GetOffsetY()) * m_textRatio); + } + } + + glsl::vec2 anchorModifyer = glsl::vec2(-length / 2.0f, maxHeight / 2.0f); + if (m_anchor & dp::Right) + anchorModifyer.x = -length; + else if (m_anchor & dp::Left) + anchorModifyer.x = 0; + + if (m_anchor & dp::Top) + anchorModifyer.y = maxHeight; + else if (m_anchor & dp::Bottom) + anchorModifyer.y = 0; + + for (DynamicVertex & v : buffer) + v.m_normal += anchorModifyer; + + for (size_t i = buffer.size(); i < 4 * m_maxLength; ++i) + buffer.push_back(DynamicVertex(glsl::vec2(0.0, 0.0), glsl::vec2(0.0, 0.0))); +} + +} diff --git a/drape_gui/gui_text.hpp b/drape_gui/gui_text.hpp new file mode 100644 index 0000000000..07e70506f7 --- /dev/null +++ b/drape_gui/gui_text.hpp @@ -0,0 +1,67 @@ +#pragma once + +#include "../drape/drape_global.hpp" +#include "../drape/binding_info.hpp" +#include "../drape/texture_manager.hpp" +#include "../drape/glsl_types.hpp" + +#include "../std/utility.hpp" +#include "../std/stdint.hpp" + +namespace gui +{ + +class GuiText +{ +public: + struct StaticVertex + { + StaticVertex() = default; + StaticVertex(glsl::vec3 const & position, glsl::vec2 const & color, glsl::vec2 const & outlineColor) + : m_position(position) + , m_color(color) + , m_outline(outlineColor) + { + } + + static dp::BindingInfo const & GetBindingInfo(); + + glsl::vec3 m_position; + glsl::vec2 m_color; + glsl::vec2 m_outline; + }; + + struct DynamicVertex + { + DynamicVertex() = default; + DynamicVertex(glsl::vec2 const & normal, glsl::vec2 const & mask) + : m_normal(normal) + , m_maskTexCoord(mask) + { + } + + static dp::BindingInfo const & GetBindingInfo(); + + glsl::vec2 m_normal; + glsl::vec2 m_maskTexCoord; + }; + + GuiText(dp::Anchor anchor); + + void SetMaxLength(uint16_t maxLength); + dp::RefPointer SetAlphabet(string const & alphabet, dp::RefPointer mng); + dp::RefPointer Precache(buffer_vector & buffer, dp::FontDecl const & font, + dp::RefPointer mng); + void SetText(buffer_vector & buffer, string text) const; + +private: + dp::Anchor m_anchor; + uint16_t m_maxLength = 0; + float m_textRatio = 0.0f; + + typedef pair TAlphabetNode; + typedef vector TAlphabet; + TAlphabet m_alphabet; +}; + +} diff --git a/drape_gui/layer_render.cpp b/drape_gui/layer_render.cpp index 72236e60a2..e2632b3f0a 100644 --- a/drape_gui/layer_render.cpp +++ b/drape_gui/layer_render.cpp @@ -1,5 +1,8 @@ #include "layer_render.hpp" #include "compass.hpp" +#include "ruler.hpp" +#include "ruler_text.hpp" +#include "ruler_helper.hpp" #include "../drape/batcher.hpp" #include "../drape/render_bucket.hpp" @@ -9,9 +12,9 @@ namespace gui { -LayerCacher::LayerCacher(string const & deviceType, double vs) +LayerCacher::LayerCacher(string const & deviceType) { - m_skin.reset(new Skin(ResolveGuiSkinFile(deviceType), vs)); + m_skin.reset(new Skin(ResolveGuiSkinFile(deviceType))); } void LayerCacher::Resize(int w, int h) @@ -22,11 +25,7 @@ void LayerCacher::Resize(int w, int h) dp::TransferPointer LayerCacher::Recache(dp::RefPointer textures) { LayerRenderer * renderer = new LayerRenderer(); - - Compass compass; - compass.SetPosition(m_skin->ResolvePosition(Skin::ElementName::Compass)); - - auto flushFn = [&renderer, this](dp::GLState const & state, dp::TransferPointer bucket) + dp::Batcher::TFlushFn flushFn = [&renderer, this](dp::GLState const & state, dp::TransferPointer bucket) { dp::MasterPointer b(bucket); ASSERT(b->GetOverlayHandlesCount() == 1, ()); @@ -40,14 +39,28 @@ dp::TransferPointer LayerCacher::Recache(dp::RefPointerAddShapeRenderer(new ShapeRenderer(state, buffer, handle.Move())); }; - dp::Batcher batcher(compass.GetIndexCount(), compass.GetVertexCount()); - batcher.StartSession(flushFn); - compass.Draw(dp::MakeStackRefPointer(&batcher), textures); - batcher.EndSession(); + dp::Batcher batcher; + dp::RefPointer pBatcher = dp::MakeStackRefPointer(&batcher); + + CacheShape(flushFn, pBatcher, textures, Compass(), Skin::ElementName::Compass); + CacheShape(flushFn, pBatcher, textures, Ruler(), Skin::ElementName::Ruler); + CacheShape(flushFn, pBatcher, textures, RulerText(), Skin::ElementName::Ruler); return dp::MovePointer(renderer); } +void LayerCacher::CacheShape(dp::Batcher::TFlushFn const & flushFn, dp::RefPointer batcher, + dp::RefPointer mng, Shape && shape, Skin::ElementName element) +{ + shape.SetPosition(m_skin->ResolvePosition(element)); + + batcher->SetVertexBufferSize(shape.GetVertexCount()); + batcher->SetIndexBufferSize(shape.GetIndexCount()); + batcher->StartSession(flushFn); + shape.Draw(batcher, mng); + batcher->EndSession(); +} + ////////////////////////////////////////////////////////////////////////////////////////// LayerRenderer::~LayerRenderer() @@ -65,6 +78,7 @@ void LayerRenderer::Build(dp::RefPointer mng) void LayerRenderer::Render(dp::RefPointer mng, ScreenBase const & screen) { + RulerHelper::Instance().Update(screen); for_each(m_renderers.begin(), m_renderers.end(), [&screen, mng](ShapeRenderer * r) { r->Render(screen, mng); diff --git a/drape_gui/layer_render.hpp b/drape_gui/layer_render.hpp index a498d7a605..da98d51f05 100644 --- a/drape_gui/layer_render.hpp +++ b/drape_gui/layer_render.hpp @@ -3,10 +3,11 @@ #include "skin.hpp" #include "shape.hpp" -#include "../geometry/screenbase.hpp" #include "../drape/texture_manager.hpp" #include "../drape/gpu_program_manager.hpp" +#include "../geometry/screenbase.hpp" + #include "../std/unique_ptr.hpp" namespace gui @@ -40,11 +41,15 @@ private: class LayerCacher { public: - LayerCacher(string const & deviceType, double vs); + LayerCacher(string const & deviceType); void Resize(int w, int h); dp::TransferPointer Recache(dp::RefPointer textures); +private: + void CacheShape(dp::Batcher::TFlushFn const & flushFn, dp::RefPointer batcher, + dp::RefPointer mng, Shape && shape, Skin::ElementName element); + private: unique_ptr m_skin; }; diff --git a/drape_gui/ruler.cpp b/drape_gui/ruler.cpp new file mode 100644 index 0000000000..cabc6484d7 --- /dev/null +++ b/drape_gui/ruler.cpp @@ -0,0 +1,140 @@ +#include "ruler.hpp" +#include "ruler_helper.hpp" + +#include "../drape/shader_def.hpp" + +namespace gui +{ + +namespace +{ + +struct RulerVertex +{ + RulerVertex() = default; + RulerVertex(glsl::vec2 const & pos, glsl::vec2 const & normal, glsl::vec2 const & texCoord) + : m_position(pos) + , m_normal(normal) + , m_texCoord(texCoord) + { + } + + glsl::vec2 m_position; + glsl::vec2 m_normal; + glsl::vec2 m_texCoord; +}; + +dp::BindingInfo GetBindingInfo() +{ + dp::BindingInfo info(3); + dp::BindingDecl & posDecl = info.GetBindingDecl(0); + posDecl.m_attributeName = "a_position"; + posDecl.m_componentCount = 2; + posDecl.m_componentType = gl_const::GLFloatType; + posDecl.m_offset = 0; + posDecl.m_stride = sizeof(RulerVertex); + + dp::BindingDecl & normalDecl = info.GetBindingDecl(1); + normalDecl.m_attributeName = "a_normal"; + normalDecl.m_componentCount = 2; + normalDecl.m_componentType = gl_const::GLFloatType; + normalDecl.m_offset = sizeof(glsl::vec2); + normalDecl.m_stride = posDecl.m_stride; + + dp::BindingDecl & texDecl = info.GetBindingDecl(2); + texDecl.m_attributeName = "a_colorTexCoords"; + texDecl.m_componentCount = 2; + texDecl.m_componentType = gl_const::GLFloatType; + texDecl.m_offset = 2 * sizeof(glsl::vec2); + texDecl.m_stride = posDecl.m_stride; + + return info; +} + +class RulerHandle : public Handle +{ +public: + RulerHandle(dp::Anchor anchor) + : Handle(anchor, m2::PointF(0.0f, 0.0f)) + { + SetIsVisible(true); + } + + virtual void Update(ScreenBase const & screen) override + { + RulerHelper & helper = RulerHelper::Instance(); + SetIsVisible(helper.IsVisible(screen)); + if (IsVisible()) + m_uniforms.SetFloatValue("u_length", helper.GetRulerPixelLength()); + } + + virtual bool IndexesRequired() const override { return false; } + + virtual m2::RectD GetPixelRect(ScreenBase const & screen) const override + { + return m2::RectD(); + } + + virtual void GetPixelShape(ScreenBase const & screen, Rects & rects) const override + { + UNUSED_VALUE(screen); + UNUSED_VALUE(rects); + } +}; + +} + +void Ruler::Draw(dp::RefPointer batcher, dp::RefPointer tex) const +{ + buffer_vector data; + + dp::TextureManager::ColorRegion reg; + tex->GetColorRegion(dp::Color(0x4D, 0x4D, 0x4D, 0xCC), reg); + + glsl::vec2 pivot = glsl::ToVec2(m_position.m_pixelPivot); + glsl::vec2 texCoord = glsl::ToVec2(reg.GetTexRect().Center()); + float h = RulerHelper::Instance().GetRulerHalfHeight(); + + dp::Anchor anchor = m_position.m_anchor; + if (anchor & dp::Left) + { + data.push_back(RulerVertex(pivot + glsl::vec2(0.0, h), glsl::vec2(0.0, 0.0), texCoord)); + data.push_back(RulerVertex(pivot + glsl::vec2(0.0, -h), glsl::vec2(0.0, 0.0), texCoord)); + data.push_back(RulerVertex(pivot + glsl::vec2(0.0, h), glsl::vec2(1.0, 0.0), texCoord)); + data.push_back(RulerVertex(pivot + glsl::vec2(0.0, -h), glsl::vec2(1.0, 0.0), texCoord)); + } + else if (anchor & dp::Right) + { + data.push_back(RulerVertex(pivot + glsl::vec2(0.0, h), glsl::vec2(-1.0, 0.0), texCoord)); + data.push_back(RulerVertex(pivot + glsl::vec2(0.0, -h), glsl::vec2(-1.0, 0.0), texCoord)); + data.push_back(RulerVertex(pivot + glsl::vec2(0.0, h), glsl::vec2(0.0, 0.0), texCoord)); + data.push_back(RulerVertex(pivot + glsl::vec2(0.0, -h), glsl::vec2(0.0, 0.0), texCoord)); + } + else + { + data.push_back(RulerVertex(pivot + glsl::vec2(0.0, h), glsl::vec2(-1.0, 0.0), texCoord)); + data.push_back(RulerVertex(pivot + glsl::vec2(0.0, -h), glsl::vec2(-1.0, 0.0), texCoord)); + data.push_back(RulerVertex(pivot + glsl::vec2(0.0, h), glsl::vec2(1.0, 0.0), texCoord)); + data.push_back(RulerVertex(pivot + glsl::vec2(0.0, -h), glsl::vec2(1.0, 0.0), texCoord)); + } + + dp::GLState state(gpu::RULER_PROGRAM, dp::GLState::UserMarkLayer); + state.SetColorTexture(reg.GetTexture()); + + dp::AttributeProvider provider(1, 4); + provider.InitStream(0, GetBindingInfo(), dp::MakeStackRefPointer(data.data())); + batcher->InsertTriangleStrip(state, dp::MakeStackRefPointer(&provider), + dp::MovePointer(new RulerHandle(m_position.m_anchor))); +} + +uint16_t Ruler::GetVertexCount() const +{ + return 4; +} + +uint16_t Ruler::GetIndexCount() const +{ + return 6; +} + +} diff --git a/drape_gui/ruler.hpp b/drape_gui/ruler.hpp new file mode 100644 index 0000000000..9c2057997d --- /dev/null +++ b/drape_gui/ruler.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "shape.hpp" + +namespace gui +{ + +class Ruler : public Shape +{ +public: + virtual void Draw(dp::RefPointer batcher, dp::RefPointer tex) const; + virtual uint16_t GetVertexCount() const; + virtual uint16_t GetIndexCount() const; +}; + +} diff --git a/drape_gui/ruler_helper.cpp b/drape_gui/ruler_helper.cpp new file mode 100644 index 0000000000..264c0e5e5b --- /dev/null +++ b/drape_gui/ruler_helper.cpp @@ -0,0 +1,257 @@ +#include "ruler_helper.hpp" +#include "drape_gui.hpp" + +#include "../platform/settings.hpp" +#include "../indexer/mercator.hpp" +#include "../indexer/measurement_utils.hpp" +#include "../geometry/screenbase.hpp" + +#include "../base/macros.hpp" + +#include "../std/algorithm.hpp" +#include "../std/numeric.hpp" +#include "../std/iterator.hpp" + +namespace gui +{ + +namespace +{ + +static int const MinPixelWidth = 60; +static int const MinMetersWidth = 10; +static int const MaxMetersWidth = 1000000; + +static int const MinUnitValue = -1; +static int const MaxUnitValue = numeric_limits::max() - 1; +static int const InvalidUnitValue = MaxUnitValue + 1; + +struct UnitValue +{ + char const * m_s; + int m_i; +}; + +UnitValue g_arrFeets[] = { + { "10 ft", 10 }, + { "20 ft", 20 }, + { "50 ft", 50 }, + { "100 ft", 100 }, + { "200 ft", 200 }, + { "0.1 mi", 528 }, + { "0.2 mi", 528 * 2 }, + { "0.5 mi", 528 * 5 }, + { "1 mi", 5280 }, + { "2 mi", 2 * 5280 }, + { "5 mi", 5 * 5280 }, + { "10 mi", 10 * 5280 }, + { "20 mi", 20 * 5280 }, + { "50 mi", 50 * 5280 }, + { "100 mi", 100 * 5280 }, + { "200 mi", 200 * 5280 }, + { "500 mi", 500 * 5280 } +}; + +UnitValue g_arrYards[] = { + { "50 yd", 50 }, + { "100 yd", 100 }, + { "200 yd", 200 }, + { "500 yd", 500 }, + { "0.5 mi", 1760 / 2 }, + { "1 mi", 1760 }, + { "2 mi", 2 * 1760 }, + { "5 mi", 5 * 1760 }, + { "10 mi", 10 * 1760 }, + { "20 mi", 20 * 1760 }, + { "50 mi", 50 * 1760 }, + { "100 mi", 100 * 1760 }, + { "200 mi", 200 * 1760 }, + { "500 mi", 500 * 1760 } +}; + +UnitValue g_arrMetres[] = { + { "1 m", 1 }, + { "2 m", 2 }, + { "5 m", 5 }, + { "10 m", 10 }, + { "20 m", 20 }, + { "50 m", 50 }, + { "100 m", 100 }, + { "200 m", 200 }, + { "500 m", 500 }, + { "1 km", 1000 }, + { "2 km", 2000 }, + { "5 km", 5000 }, + { "10 km", 10000 }, + { "20 km", 20000 }, + { "50 km", 50000 }, + { "100 km", 100000 }, + { "200 km", 200000 }, + { "500 km", 500000 }, + { "1000 km", 1000000 } +}; + +double identity(double val) +{ + return val; +} + +} + +RulerHelper::RulerHelper() + : m_pixelLength(0.0) + , m_rangeIndex(InvalidUnitValue) + , m_isTextDirty(false) +{ +} + +RulerHelper & RulerHelper::Instance() +{ + static RulerHelper s_helper; + return s_helper; +} + +void RulerHelper::Update(ScreenBase const & screen) +{ + m2::PointD pivot = screen.PixelRect().Center(); + int const minPxWidth = my::rounds(MinPixelWidth * DrapeGui::Instance().GetScaleFactor()); + m2::PointD pt1 = screen.PtoG(pivot); + m2::PointD pt0 = screen.PtoG(pivot - m2::PointD(minPxWidth, 0)); + + double const distanceInMetres = MercatorBounds::DistanceOnEarth(pt0, pt1); + + // convert metres to units for calculating m_metresDiff + double metersDiff = CalcMetresDiff(distanceInMetres); + + bool const higherThanMax = metersDiff > MaxMetersWidth; + bool const lessThanMin = metersDiff < MinMetersWidth; + m_pixelLength = minPxWidth; + + if (higherThanMax) + m_pixelLength = minPxWidth * 3 / 2; + else if (!lessThanMin) + { + double const a = ang::AngleTo(pt1, pt0); + pt0 = MercatorBounds::GetSmPoint(pt1, cos(a) * metersDiff, sin(a) * metersDiff); + + m_pixelLength = my::rounds(pivot.Length(screen.GtoP(pt0))); + } +} + +bool RulerHelper::IsVisible(const ScreenBase & screen) const +{ + return DrapeGui::Instance().GetGeneralization(screen) > 4; +} + +float RulerHelper::GetRulerHalfHeight() const +{ + return 2 * DrapeGui::Instance().GetScaleFactor(); +} + +float RulerHelper::GetRulerPixelLength() const +{ + return m_pixelLength; +} + +int RulerHelper::GetVerticalTextOffset() const +{ + return -5 * DrapeGui::Instance().GetScaleFactor(); +} + +bool RulerHelper::IsTextDirty() const +{ + return m_isTextDirty; +} + +string const & RulerHelper::GetRulerText() const +{ + m_isTextDirty = false; + return m_rulerText; +} + +void RulerHelper::GetTextInitInfo(string & alphabet, size_t & size) const +{ + set symbols; + size_t result = 0; + auto const functor = [&result, &symbols](UnitValue const & v) + { + size_t stringSize = strlen(v.m_s); + result = max(result, stringSize); + for (int i = 0; i < stringSize; ++i) + symbols.insert(v.m_s[i]); + }; + + for_each(begin(g_arrFeets), end(g_arrFeets), functor); + for_each(begin(g_arrMetres), end(g_arrMetres), functor); + for_each(begin(g_arrYards), end(g_arrYards), functor); + + for_each(begin(symbols), end(symbols), [&alphabet](char c) + { + alphabet.push_back(c); + }); + alphabet.append("<>"); + + size = result + 2; // add 2 char for symbols "< " and "> " +} + +double RulerHelper::CalcMetresDiff(double value) +{ + UnitValue * arrU = g_arrMetres; + int count = ARRAY_SIZE(g_arrMetres); + + typedef double (*ConversionFn)(double); + ConversionFn conversionFn = &identity; + + Settings::Units units = Settings::Metric; + Settings::Get("Units", units); + + switch (units) + { + case Settings::Foot: + arrU = g_arrFeets; + count = ARRAY_SIZE(g_arrFeets); + conversionFn = &MeasurementUtils::MetersToFeet; + break; + + case Settings::Yard: + arrU = g_arrYards; + count = ARRAY_SIZE(g_arrYards); + conversionFn = &MeasurementUtils::MetersToYards; + break; + default: + break; + } + + int prevUnitRange = m_rangeIndex; + double result = 0.0; + double v = conversionFn(value); + if (arrU[0].m_i > v) + { + m_rangeIndex = MinUnitValue; + m_rulerText = string("< ") + arrU[0].m_s; + result = MinMetersWidth - 1.0; + } + else if (arrU[count-1].m_i <= v) + { + m_rangeIndex = MaxUnitValue; + m_rulerText = string("> ") + arrU[count-1].m_s; + result = MaxMetersWidth + 1.0; + } + else + for (int i = 0; i < count; ++i) + { + if (arrU[i].m_i > v) + { + m_rangeIndex = i; + result = arrU[i].m_i / conversionFn(1.0); + m_rulerText = arrU[i].m_s; + break; + } + } + + if (m_rangeIndex != prevUnitRange) + m_isTextDirty = true; + return result; +} + +} diff --git a/drape_gui/ruler_helper.hpp b/drape_gui/ruler_helper.hpp new file mode 100644 index 0000000000..2933a44245 --- /dev/null +++ b/drape_gui/ruler_helper.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include "../std/string.hpp" + +class ScreenBase; + +namespace gui +{ + +class RulerHelper +{ +public: + static RulerHelper & Instance(); + + void Update(ScreenBase const & screen); + bool IsVisible(ScreenBase const & screen) const; + + float GetRulerHalfHeight() const; + float GetRulerPixelLength() const; + int GetVerticalTextOffset() const; + bool IsTextDirty() const; + string const & GetRulerText() const; + void GetTextInitInfo(string & alphabet, size_t & size) const; + +private: + RulerHelper(); + + double CalcMetresDiff(double value); + +private: + float m_pixelLength; + int m_rangeIndex; + string m_rulerText; + mutable bool m_isTextDirty; +}; + +} diff --git a/drape_gui/ruler_text.cpp b/drape_gui/ruler_text.cpp new file mode 100644 index 0000000000..56b295692b --- /dev/null +++ b/drape_gui/ruler_text.cpp @@ -0,0 +1,120 @@ +#include "ruler_text.hpp" +#include "ruler_helper.hpp" +#include "drape_gui.hpp" + +#include "../drape/glsl_func.hpp" +#include "../drape/attribute_provider.hpp" +#include "../drape/shader_def.hpp" + +namespace gui +{ + +static size_t const FontSize = 7; +static dp::Color const FontColor = dp::Color(0x4D, 0x4D, 0x4D, 0xCC); + +namespace +{ + class RulerTextHandle : public Handle + { + public: + RulerTextHandle(dp::Anchor anchor, m2::PointF const & pivot) + : Handle(anchor, pivot) + { + SetIsVisible(true); + m_textView.Reset(new GuiText(anchor)); + } + + ~RulerTextHandle() + { + m_textView.Destroy(); + } + + virtual void Update(ScreenBase const & screen) override + { + UNUSED_VALUE(screen); + + SetIsVisible(RulerHelper::Instance().IsVisible(screen)); + + if (!IsVisible()) + return; + + glsl::mat4 m = glsl::transpose(glsl::translate(glsl::mat4(), glsl::vec3(m_pivot, 0.0))); + m_uniforms.SetMatrix4x4Value("modelView", glsl::value_ptr(m)); + } + + virtual void GetAttributeMutation(dp::RefPointer mutator, ScreenBase const & screen) const override + { + UNUSED_VALUE(screen); + + RulerHelper const & helper = RulerHelper::Instance(); + if (!helper.IsTextDirty()) + return; + + buffer_vector buffer; + m_textView->SetText(buffer, helper.GetRulerText()); + + size_t byteCount = buffer.size() * sizeof(GuiText::DynamicVertex); + void * dataPointer = mutator->AllocateMutationBuffer(byteCount); + memcpy(dataPointer, buffer.data(), byteCount); + + dp::OverlayHandle::TOffsetNode offsetNode = GetOffsetNode(GuiText::DynamicVertex::GetBindingInfo().GetID()); + + dp::MutateNode mutateNode; + mutateNode.m_data = dp::MakeStackRefPointer(dataPointer); + mutateNode.m_region = offsetNode.second; + mutator->AddMutation(offsetNode.first, mutateNode); + } + + dp::RefPointer GetTextView() + { + return m_textView.GetRefPointer(); + } + + private: + dp::MasterPointer m_textView; + }; +} + +RulerText::RulerText() +{ + RulerHelper::Instance().GetTextInitInfo(m_alphabet, m_maxLength); +} + +void RulerText::Draw(dp::RefPointer batcher, dp::RefPointer tex) const +{ + m2::PointF rulerTextPivot = m_position.m_pixelPivot + m2::PointF(0.0, RulerHelper::Instance().GetVerticalTextOffset()); + dp::Anchor anchor = static_cast((m_position.m_anchor & (dp::Right | dp::Left)) | dp::Bottom); + RulerTextHandle * handle = new RulerTextHandle(anchor, rulerTextPivot); + dp::RefPointer textView = handle->GetTextView(); + dp::RefPointer maskTexture = textView->SetAlphabet(m_alphabet, tex); + textView->SetMaxLength(m_maxLength); + + buffer_vector statData; + buffer_vector dynData; + dp::RefPointer colorTexture = textView->Precache(statData, dp::FontDecl(FontColor, FontSize * DrapeGui::Instance().GetScaleFactor()), tex); + + ASSERT_EQUAL(GetVertexCount(), statData.size(), ()); + dynData.resize(statData.size()); + + dp::AttributeProvider provider(2, statData.size()); + provider.InitStream(0, GuiText::StaticVertex::GetBindingInfo(), dp::MakeStackRefPointer(statData.data())); + provider.InitStream(1, GuiText::DynamicVertex::GetBindingInfo(), dp::MakeStackRefPointer(dynData.data())); + + dp::GLState state(gpu::TEXT_PROGRAM, dp::GLState::UserMarkLayer); + state.SetColorTexture(colorTexture); + state.SetMaskTexture(maskTexture); + + batcher->InsertListOfStrip(state, dp::MakeStackRefPointer(&provider), dp::MovePointer(handle), 4); +} + +uint16_t RulerText::GetVertexCount() const +{ + return 4 * m_maxLength; +} + +uint16_t RulerText::GetIndexCount() const +{ + return 6 * m_maxLength; +} + +} diff --git a/drape_gui/ruler_text.hpp b/drape_gui/ruler_text.hpp new file mode 100644 index 0000000000..a085a32570 --- /dev/null +++ b/drape_gui/ruler_text.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include "shape.hpp" +#include "gui_text.hpp" + +namespace gui +{ + +class RulerText : public Shape +{ +public: + RulerText(); + + virtual void Draw(dp::RefPointer batcher, dp::RefPointer tex) const; + virtual uint16_t GetVertexCount() const; + virtual uint16_t GetIndexCount() const; + +private: + string m_alphabet; + size_t m_maxLength; +}; + +} diff --git a/drape_gui/shape.cpp b/drape_gui/shape.cpp index 796a50f77c..4af6825a35 100644 --- a/drape_gui/shape.cpp +++ b/drape_gui/shape.cpp @@ -10,6 +10,29 @@ void Shape::SetPosition(gui::Position const & position) m_position = position; } +void Handle::SetProjection(int w, int h) +{ + array m; + dp::MakeProjection(m, 0.0f, w, h, 0.0f); + m_uniforms.SetMatrix4x4Value("projection", m.data()); +} + +bool Handle::IndexesRequired() const +{ + return false; +} + +m2::RectD Handle::GetPixelRect(const ScreenBase & screen) const +{ + return m2::RectD(); +} + +void Handle::GetPixelShape(const ScreenBase & screen, dp::OverlayHandle::Rects & rects) const +{ + UNUSED_VALUE(screen); + UNUSED_VALUE(rects); +} + ShapeRenderer::ShapeRenderer(dp::GLState const & state, dp::TransferPointer buffer, dp::TransferPointer implHandle) @@ -53,11 +76,4 @@ void ShapeRenderer::Render(ScreenBase const & screen, dp::RefPointerRender(); } -void Handle::SetProjection(int w, int h) -{ - array m; - dp::MakeProjection(m, 0.0f, w, h, 0.0f); - m_uniforms.SetMatrix4x4Value("projection", m.data()); -} - } diff --git a/drape_gui/shape.hpp b/drape_gui/shape.hpp index 6f04f75827..99b21e90b2 100644 --- a/drape_gui/shape.hpp +++ b/drape_gui/shape.hpp @@ -29,13 +29,23 @@ protected: class Handle : public dp::OverlayHandle { public: - Handle(FeatureID const & id, dp::Anchor anchor, double p) : dp::OverlayHandle(id, anchor, p) {} + Handle(dp::Anchor anchor, m2::PointF const & pivot) + : dp::OverlayHandle(FeatureID(), anchor, 0.0) + , m_pivot(glsl::ToVec2(pivot)) + { + } + dp::UniformValuesStorage const & GetUniforms() const { return m_uniforms; } void SetProjection(int w, int h); + virtual bool IndexesRequired() const override; + virtual m2::RectD GetPixelRect(ScreenBase const & screen) const override; + virtual void GetPixelShape(ScreenBase const & screen, Rects & rects) const override; + protected: dp::UniformValuesStorage m_uniforms; + glsl::vec2 const m_pivot; }; class ShapeRenderer diff --git a/drape_gui/skin.cpp b/drape_gui/skin.cpp index d12d759313..677fe2b4b3 100644 --- a/drape_gui/skin.cpp +++ b/drape_gui/skin.cpp @@ -1,4 +1,5 @@ #include "skin.hpp" +#include "drape_gui.hpp" #include "../platform/platform.hpp" #include "../coding/parse_xml.hpp" @@ -246,8 +247,7 @@ void PositionResolver::SetOffsetY(float y) m_offset.y = y; } -Skin::Skin(ReaderPtr const & reader, double visualScale) - : m_vs(visualScale) +Skin::Skin(ReaderPtr const & reader) { SkinLoader loader(m_resolvers); ReaderSource > source(reader); @@ -259,7 +259,7 @@ Position Skin::ResolvePosition(ElementName name) { TResolversPair const & resolvers = m_resolvers[name]; PositionResolver const & resolver = (m_displayWidth < m_displayHeight) ? resolvers.first : resolvers.second; - return resolver.Resolve(m_displayWidth, m_displayHeight, m_vs); + return resolver.Resolve(m_displayWidth, m_displayHeight, DrapeGui::Instance().GetScaleFactor()); } void Skin::Resize(int w, int h) diff --git a/drape_gui/skin.hpp b/drape_gui/skin.hpp index a72c1da35f..89fe04e3c6 100644 --- a/drape_gui/skin.hpp +++ b/drape_gui/skin.hpp @@ -46,7 +46,7 @@ public: Copyright }; - Skin(ReaderPtr const & reader, double visualScale); + explicit Skin(ReaderPtr const & reader); Position ResolvePosition(ElementName name); void Resize(int w, int h); @@ -61,7 +61,6 @@ private: int m_displayWidth; int m_displayHeight; - double m_vs; }; ReaderPtr ResolveGuiSkinFile(string const & deviceType); diff --git a/drape_head/testing_engine.cpp b/drape_head/testing_engine.cpp index 79991168e2..403046d14f 100644 --- a/drape_head/testing_engine.cpp +++ b/drape_head/testing_engine.cpp @@ -12,6 +12,9 @@ #include "drape_frontend/circle_shape.hpp" #include "drape_frontend/poi_symbol_shape.hpp" +#include "drape_gui/drape_gui.hpp" +#include "drape_gui/gui_text.hpp" + #include "drape/utils/vertex_decl.hpp" #include "drape/glsl_types.hpp" #include "drape/vertex_array_buffer.hpp" @@ -34,6 +37,48 @@ namespace df { +class DummyGuiText +{ +public: + DummyGuiText(m2::PointF const & base, string const & text) + : m_base(base) + , m_text(text) + { + } + + void Draw(dp::RefPointer batcher, dp::RefPointer textures) const + { + gui::GuiText textCacher(dp::LeftBottom); + textCacher.SetMaxLength(10); + dp::RefPointer maskTexture = textCacher.SetAlphabet(m_text, textures); + + dp::FontDecl font(dp::Color(0, 0, 0, 255), 14); + buffer_vector statData; + dp::RefPointer colorTexure = textCacher.Precache(statData, font, textures); + + glsl::vec2 offset = glsl::ToVec2(m_base); + for (gui::GuiText::StaticVertex & v : statData) + v.m_position = glsl::vec3(v.m_position.xy() + offset, v.m_position.z); + + buffer_vector dynData; + textCacher.SetText(dynData, m_text); + ASSERT_EQUAL(statData.size(), dynData.size(), ()); + + dp::AttributeProvider provider(2, dynData.size()); + provider.InitStream(0, gui::GuiText::StaticVertex::GetBindingInfo(), dp::MakeStackRefPointer(statData.data())); + provider.InitStream(1, gui::GuiText::DynamicVertex::GetBindingInfo(), dp::MakeStackRefPointer(dynData.data())); + + dp::GLState state(gpu::TEXT_PROGRAM, dp::GLState::OverlayLayer); + state.SetColorTexture(colorTexure); + state.SetMaskTexture(maskTexture); + batcher->InsertListOfStrip(state, dp::MakeStackRefPointer(&provider), 4); + } + +private: + m2::PointF m_base; + string m_text; +}; + class DummyStippleElement : public MapShape { public: @@ -74,7 +119,6 @@ public: dp::GLState state(gpu::TEXTURING_PROGRAM, dp::GLState::GeometryLayer); state.SetColorTexture(region.GetTexture()); - state.SetBlending(dp::Blending(true)); batcher->InsertTriangleStrip(state, dp::MakeStackRefPointer(&provider)); } @@ -111,7 +155,6 @@ public: dp::GLState state(gpu::TEXTURING_PROGRAM, dp::GLState::GeometryLayer); state.SetColorTexture(region.GetTexture()); - state.SetBlending(dp::Blending(true)); batcher->InsertTriangleStrip(state, dp::MakeStackRefPointer(&provider)); } @@ -258,6 +301,19 @@ TestingEngine::TestingEngine(dp::RefPointer oglcontextfac { m_contextFactory->getDrawContext()->makeCurrent(); df::VisualParams::Init(vs, df::CalculateTileSize(viewport.GetWidth(), viewport.GetHeight())); + + gui::DrapeGui::TScaleFactorFn scaleFn = []() + { + return df::VisualParams::Instance().GetVisualScale(); + }; + + gui::DrapeGui::TGeneralizationLevelFn genLvlFn = [](ScreenBase const & screen) + { + return df::GetDrawTileScale(screen); + }; + + gui::DrapeGui::Instance().Init(scaleFn, genLvlFn); + GLFunctions::Init(); dp::TextureManager::Params params; @@ -294,9 +350,7 @@ void TestingEngine::Draw() static bool isInitialized = false; if (!isInitialized) { - m_batcher->StartSession(bind(&df::TestingEngine::OnFlushData, this, _1, _2)); DrawImpl(); - m_batcher->EndSession(); m_batcher->StartSession(bind(&df::TestingEngine::OnFlushData, this, _1, _2)); DrawRects(); m_batcher->EndSession(); @@ -359,11 +413,12 @@ void TestingEngine::timerEvent(QTimerEvent * e) void TestingEngine::DrawImpl() { - FontDecl fd; + m_batcher->StartSession(bind(&df::TestingEngine::OnFlushData, this, _1, _2)); + dp::FontDecl fd; fd.m_color = dp::Color::Black(); fd.m_outlineColor = dp::Color::White(); fd.m_size = 32.0f; - FontDecl auxFd; + dp::FontDecl auxFd; auxFd.m_color = dp::Color(0, 80, 240, 255); auxFd.m_outlineColor = dp::Color::Transparent(); auxFd.m_size = 20.0f; @@ -389,7 +444,7 @@ void TestingEngine::DrawImpl() ptvp.m_baseGtoPScale = 1.0f / m_modelView.GetScale(); ptvp.m_depth = 100.0f; ptvp.m_text = "Some text"; - ptvp.m_textFont = FontDecl(dp::Color::Black(), 40, dp::Color::Red()); + ptvp.m_textFont = dp::FontDecl(dp::Color::Black(), 40, dp::Color::Red()); PathTextShape(spline, ptvp).Draw(m_batcher.GetRefPointer(), m_textures.GetRefPointer()); LineViewParams lvp; @@ -451,6 +506,25 @@ void TestingEngine::DrawImpl() p.m_depth = 0.0f; AreaShape(move(trg), p).Draw(m_batcher.GetRefPointer(), m_textures.GetRefPointer()); } + m_batcher->EndSession(); + + m_batcher->StartSession(bind(&df::TestingEngine::OnFlushData, this, _1, _2)); + { + vector path; + path.push_back(m2::PointD(120.0f, 30.0f)); + path.push_back(m2::PointD(125.0f, 30.0f)); + m2::SharedSpline spl(path); + + LineViewParams lvpl = lvp; + lvpl.m_pattern.clear(); + lvpl.m_depth = -10.0f; + lvpl.m_width = 2.0f; + LineShape(spl, lvpl).Draw(m_batcher.GetRefPointer(), m_textures.GetRefPointer()); + + DummyGuiText tt(m2::PointF(120.0f, 30.0f), "200 km"); + tt.Draw(m_batcher.GetRefPointer(), m_textures.GetRefPointer()); + } + m_batcher->EndSession(); } void TestingEngine::DrawRects() diff --git a/std/iterator.hpp b/std/iterator.hpp index 0e820b66e1..6fb9c08133 100644 --- a/std/iterator.hpp +++ b/std/iterator.hpp @@ -15,6 +15,8 @@ using std::insert_iterator; using std::istream_iterator; using std::iterator_traits; using std::reverse_iterator; +using std::begin; +using std::end; #ifdef DEBUG_NEW #define new DEBUG_NEW