diff --git a/drape/batcher.hpp b/drape/batcher.hpp index 305ec4ed7c..07f0e6e174 100644 --- a/drape/batcher.hpp +++ b/drape/batcher.hpp @@ -22,6 +22,7 @@ class OverlayHandle; class Batcher { public: + static uint32_t const IndexPerTriangle = 3; static uint32_t const IndexPerQuad = 6; static uint32_t const VertexPerQuad = 4; diff --git a/drape/depth_constants.hpp b/drape/depth_constants.hpp new file mode 100644 index 0000000000..e5e8b7dd14 --- /dev/null +++ b/drape/depth_constants.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "utils/projection.hpp" + +namespace dp +{ + +namespace depth +{ + +float const POSITION_ACCURACY = minDepth; +float const MY_POSITION_MARK = maxDepth; + +} // namespace depth + +} // namespace dp diff --git a/drape/drape.pro b/drape/drape.pro index f531ddb472..0129e908c0 100644 --- a/drape/drape.pro +++ b/drape/drape.pro @@ -21,3 +21,5 @@ OTHER_FILES += \ shaders/text_vertex_shader.vsh \ shaders/compass_vertex_shader.vsh \ shaders/ruler_vertex_shader.vsh \ + shaders/position_accuracy_shader.vsh \ + shaders/my_position_shader.vsh diff --git a/drape/drape_common.pri b/drape/drape_common.pri index 3c96a890e2..dd8b06fb1d 100644 --- a/drape/drape_common.pri +++ b/drape/drape_common.pri @@ -98,5 +98,5 @@ HEADERS += \ $$DRAPE_DIR/utils/vertex_decl.hpp \ $$DRAPE_DIR/vertex_array_buffer.hpp \ $$ROOT_DIR/stb_image/stb_image.h \ - $$ROOT_DIR/sdf_image/sdf_image.h \ - + $$ROOT_DIR/sdf_image/sdf_image.h \ + $$PWD/depth_constants.hpp diff --git a/drape/glsl_func.hpp b/drape/glsl_func.hpp index 17e25d3859..0a45cb70da 100644 --- a/drape/glsl_func.hpp +++ b/drape/glsl_func.hpp @@ -5,6 +5,8 @@ #include #include +#include + namespace glsl { diff --git a/drape/shaders/my_position_shader.vsh b/drape/shaders/my_position_shader.vsh new file mode 100644 index 0000000000..e1d40b8c78 --- /dev/null +++ b/drape/shaders/my_position_shader.vsh @@ -0,0 +1,28 @@ +attribute vec2 a_normal; +attribute vec2 a_colorTexCoords; + +uniform vec3 u_position; +uniform float u_azimut; + +uniform mat4 modelView; +uniform mat4 projection; + +varying vec2 v_colorTexCoords; + +void main(void) +{ + float sinV = sin(u_azimut); + float cosV = cos(u_azimut); + + mat4 rotation; + rotation[0] = vec4(cosV, sinV, 0.0, 0.0); + rotation[1] = vec4(-sinV, cosV, 0.0, 0.0); + rotation[2] = vec4(0.0, 0.0, 1.0, 0.0); + rotation[3] = vec4(0.0, 0.0, 0.0, 1.0); + + vec4 normal = vec4(a_normal, 0, 0); + vec4 pos = vec4(u_position, 1.0); + + gl_Position = ((normal * rotation + pos * modelView)) * projection; + v_colorTexCoords = a_colorTexCoords; +} diff --git a/drape/shaders/position_accuracy_shader.vsh b/drape/shaders/position_accuracy_shader.vsh new file mode 100644 index 0000000000..c4fbe1bc24 --- /dev/null +++ b/drape/shaders/position_accuracy_shader.vsh @@ -0,0 +1,18 @@ +attribute vec2 a_normal; +attribute vec2 a_colorTexCoords; + +uniform vec3 u_position; +uniform float u_accuracy; + +uniform mat4 modelView; +uniform mat4 projection; + +varying vec2 v_colorTexCoords; + +void main(void) +{ + vec4 position = vec4(u_position.xy + normalize(a_normal) * u_accuracy, u_position.z, 1); + gl_Position = position * modelView * projection; + + v_colorTexCoords = a_colorTexCoords; +} diff --git a/drape/shaders/shader_index.txt b/drape/shaders/shader_index.txt index f350d6cd03..e52639fc5d 100644 --- a/drape/shaders/shader_index.txt +++ b/drape/shaders/shader_index.txt @@ -3,3 +3,5 @@ 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 +ACCURACY_PROGRAM position_accuracy_shader.vsh texturing_fragment_shader.fsh +MY_POSITION_PROGRAM my_position_shader.vsh texturing_fragment_shader.fsh diff --git a/drape_frontend/backend_renderer.cpp b/drape_frontend/backend_renderer.cpp index ed2e7a11ff..e6170aac10 100644 --- a/drape_frontend/backend_renderer.cpp +++ b/drape_frontend/backend_renderer.cpp @@ -37,7 +37,7 @@ BackendRenderer::BackendRenderer(dp::RefPointer commutator, { m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, dp::MovePointer(new GuiRecacheMessage(elements)), - MessagePriority::Normal); + MessagePriority::High); }); StartThread(); @@ -187,6 +187,11 @@ void BackendRenderer::InitGLDependentResource() GetPlatform().GetFontNames(params.m_glyphMngParams.m_fonts); m_texturesManager->Init(params); + + dp::MasterPointer position(new MyPosition(m_texturesManager)); + m_commutator->PostMessage(ThreadsCommutator::RenderThread, + dp::MovePointer(new MyPositionShapeMessage(position.Move())), + MessagePriority::High); } void BackendRenderer::FlushGeometry(dp::TransferPointer message) diff --git a/drape_frontend/drape_frontend.pro b/drape_frontend/drape_frontend.pro index 8b2cf46705..f5cd2e6530 100644 --- a/drape_frontend/drape_frontend.pro +++ b/drape_frontend/drape_frontend.pro @@ -40,6 +40,7 @@ SOURCES += \ user_marks_provider.cpp \ viewport.cpp \ visual_params.cpp \ + my_position.cpp HEADERS += \ apply_feature_functors.hpp \ @@ -78,3 +79,4 @@ HEADERS += \ user_marks_provider.hpp \ viewport.hpp \ visual_params.hpp \ + my_position.hpp diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index 85a491f9c9..b71badb548 100644 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -164,6 +164,10 @@ void FrontendRenderer::AcceptMessage(dp::RefPointer message) break; } + case Message::MyPositionShape: + m_myPositionMark = CastMessage(message)->AcceptShape(); + break; + case Message::InvalidateRect: { InvalidateRectMessage * m = df::CastMessage(message); @@ -276,7 +280,11 @@ void FrontendRenderer::RenderScene() dp::GLState const & state = group->GetState(); dp::GLState::DepthLayer layer = state.GetDepthLayer(); if (prevLayer != layer && layer == dp::GLState::OverlayLayer) + { GLFunctions::glClearDepth(); + if (!m_myPositionMark.IsNull()) + m_myPositionMark->Render(m_view, m_gpuProgramManager.GetRefPointer(), m_generalUniforms); + } prevLayer = layer; ASSERT_LESS_OR_EQUAL(prevLayer, layer, ()); diff --git a/drape_frontend/frontend_renderer.hpp b/drape_frontend/frontend_renderer.hpp index ae67d1c6af..6827cb3839 100644 --- a/drape_frontend/frontend_renderer.hpp +++ b/drape_frontend/frontend_renderer.hpp @@ -13,6 +13,7 @@ #include "drape_frontend/tile_info.hpp" #include "drape_frontend/backend_renderer.hpp" #include "drape_frontend/render_group.hpp" +#include "drape_frontend/my_position.hpp" #include "drape_gui/layer_render.hpp" @@ -105,6 +106,7 @@ private: vector m_renderGroups; vector m_userMarkRenderGroups; dp::MasterPointer m_guiRenderer; + dp::MasterPointer m_myPositionMark; dp::UniformValuesStorage m_generalUniforms; diff --git a/drape_frontend/message.hpp b/drape_frontend/message.hpp index 706295054b..68c7beb1b4 100644 --- a/drape_frontend/message.hpp +++ b/drape_frontend/message.hpp @@ -22,6 +22,7 @@ public: UpdateUserMarkLayer, GuiLayerRecached, GuiRecache, + MyPositionShape, StopRendering }; diff --git a/drape_frontend/message_subclasses.hpp b/drape_frontend/message_subclasses.hpp index fe41bb3685..ebd96409bb 100644 --- a/drape_frontend/message_subclasses.hpp +++ b/drape_frontend/message_subclasses.hpp @@ -1,5 +1,6 @@ #pragma once +#include "drape_frontend/my_position.hpp" #include "drape_frontend/message.hpp" #include "drape_frontend/viewport.hpp" #include "drape_frontend/tile_key.hpp" @@ -247,6 +248,25 @@ private: gui::Skin::ElementName m_elements; }; +class MyPositionShapeMessage : public Message +{ +public: + MyPositionShapeMessage(dp::TransferPointer shape) + : m_shape(shape) + { + } + + Type GetType() const override { return Message::MyPositionShape; } + + dp::MasterPointer AcceptShape() + { + return dp::MasterPointer(m_shape); + } + +private: + dp::TransferPointer m_shape; +}; + class StopRenderingMessage : public Message { public: diff --git a/drape_frontend/my_position.cpp b/drape_frontend/my_position.cpp new file mode 100644 index 0000000000..a17fe37926 --- /dev/null +++ b/drape_frontend/my_position.cpp @@ -0,0 +1,220 @@ +#include "my_position.hpp" + +#include "../drape/batcher.hpp" +#include "../drape/depth_constants.hpp" +#include "../drape/glsl_func.hpp" +#include "../drape/glsl_types.hpp" +#include "../drape/render_bucket.hpp" +#include "../drape/shader_def.hpp" + +namespace df +{ + +namespace +{ + +struct Vertex +{ + glsl::vec2 m_normal; + glsl::vec2 m_texCoord; +}; + +dp::BindingInfo GetBindingInfo() +{ + dp::BindingInfo info(2); + dp::BindingDecl & normal = info.GetBindingDecl(0); + normal.m_attributeName = "a_normal"; + normal.m_componentCount = 2; + normal.m_componentType = gl_const::GLFloatType; + normal.m_offset = 0; + normal.m_stride = sizeof(Vertex); + + dp::BindingDecl & texCoord = info.GetBindingDecl(1); + texCoord.m_attributeName = "a_colorTexCoords"; + texCoord.m_componentCount = 2; + texCoord.m_componentType = gl_const::GLFloatType; + texCoord.m_offset = sizeof(glsl::vec2); + texCoord.m_stride = sizeof(Vertex); + + return info; +} + +} // namespace + +MyPosition::MyPosition(dp::RefPointer mng) + : m_position(m2::PointF::Zero()) + , m_azimut(0.0f) + , m_accuracy(0.0f) + , m_showAzimut(false) + , m_isVisible(false) +{ + m_parts.resize(3); + CacheAccuracySector(mng); + CachePointPosition(mng); +} + +void MyPosition::SetPosition(m2::PointF const & pt) +{ + m_position = pt; +} + +void MyPosition::SetAzimut(float azimut) +{ + m_azimut = azimut; +} + +void MyPosition::SetAccuracy(float accuracy) +{ + m_accuracy = accuracy; +} + +void MyPosition::SetIsVisible(bool isVisible) +{ + m_isVisible = isVisible; +} + +void MyPosition::Render(ScreenBase const & screen, + dp::RefPointer mng, + dp::UniformValuesStorage const & commonUniforms) +{ + if (!m_isVisible) + return; + + dp::UniformValuesStorage uniforms = commonUniforms; + + { + dp::UniformValuesStorage accuracyUniforms = uniforms; + accuracyUniforms.SetFloatValue("u_position", m_position.x, m_position.y, dp::depth::POSITION_ACCURACY); + accuracyUniforms.SetFloatValue("u_accuracy", m_accuracy); + RenderPart(mng, accuracyUniforms, MY_POSITION_ACCURACY); + } + + { + dp::UniformValuesStorage arrowUniforms = uniforms; + arrowUniforms.SetFloatValue("u_position", m_position.x, m_position.y, dp::depth::MY_POSITION_MARK); + arrowUniforms.SetFloatValue("u_azimut", m_azimut - screen.GetAngle()); + RenderPart(mng, arrowUniforms, (m_showAzimut == true) ? MY_POSITION_ARROW : MY_POSITION_POINT); + } +} + +void MyPosition::CacheAccuracySector(dp::RefPointer mng) +{ + int const TriangleCount = 40; + int const VertexCount = TriangleCount + 2; + float const etalonSector = math::twicePi / static_cast(TriangleCount); + + dp::TextureManager::ColorRegion color; + mng->GetColorRegion(dp::Color(0x51, 0xA3, 0xDC, 0x46), color); + glsl::vec2 colorCoord = glsl::ToVec2(color.GetTexRect().Center()); + + buffer_vector buffer; + buffer.push_back(Vertex{ glsl::vec2(0.0f, 0.0f), colorCoord }); + + glsl::vec2 startNormal(0.0f, 1.0f); + + for (size_t i = 0; i < TriangleCount + 1; ++i) + { + glsl::vec2 rotatedNormal = glsl::rotate(startNormal, -(i * etalonSector)); + buffer.push_back(Vertex{ rotatedNormal, colorCoord }); + } + + dp::GLState state(gpu::ACCURACY_PROGRAM, dp::GLState::OverlayLayer); + state.SetColorTexture(color.GetTexture()); + + { + dp::Batcher batcher(TriangleCount * dp::Batcher::IndexPerTriangle, VertexCount); + dp::SessionGuard guard(batcher, [this](dp::GLState const & state, dp::TransferPointer b) + { + dp::MasterPointer bucket(b); + ASSERT(bucket->GetOverlayHandlesCount() == 0, ()); + + m_nodes.emplace_back(state, bucket->MoveBuffer()); + m_parts[MY_POSITION_ACCURACY].second = m_nodes.size() - 1; + bucket.Destroy(); + }); + + dp::AttributeProvider provider(1 /*stream count*/, VertexCount); + provider.InitStream(0 /*stream index*/, GetBindingInfo(), dp::StackVoidRef(buffer.data())); + + m_parts[MY_POSITION_ACCURACY].first = batcher.InsertTriangleFan(state, dp::MakeStackRefPointer(&provider)); + } +} + +void MyPosition::CachePointPosition(dp::RefPointer mng) +{ + dp::TextureManager::SymbolRegion pointSymbol, arrowSymbol; + mng->GetSymbolRegion("current-position", pointSymbol); + mng->GetSymbolRegion("current-position-compas", arrowSymbol); + + m2::RectF const & pointTexRect = pointSymbol.GetTexRect(); + m2::PointF pointHalfSize = m2::PointF(pointSymbol.GetPixelSize()) * 0.5f; + + Vertex pointData[4]= + { + { glsl::vec2(-pointHalfSize.x, pointHalfSize.y), glsl::ToVec2(pointTexRect.LeftTop()) }, + { glsl::vec2(-pointHalfSize.x, -pointHalfSize.y), glsl::ToVec2(pointTexRect.LeftBottom()) }, + { glsl::vec2( pointHalfSize.x, pointHalfSize.y), glsl::ToVec2(pointTexRect.RightTop()) }, + { glsl::vec2( pointHalfSize.x, -pointHalfSize.y), glsl::ToVec2(pointTexRect.RightBottom())} + }; + + m2::RectF const & arrowTexRect = arrowSymbol.GetTexRect(); + m2::PointF arrowHalfSize = m2::PointF(arrowSymbol.GetPixelSize()) * 0.5f; + + Vertex arrowData[4]= + { + { glsl::vec2(-arrowHalfSize.x, arrowHalfSize.y), glsl::ToVec2(arrowTexRect.LeftTop()) }, + { glsl::vec2(-arrowHalfSize.x, -arrowHalfSize.y), glsl::ToVec2(arrowTexRect.LeftBottom()) }, + { glsl::vec2( arrowHalfSize.x, arrowHalfSize.y), glsl::ToVec2(arrowTexRect.RightTop()) }, + { glsl::vec2( arrowHalfSize.x, -arrowHalfSize.y), glsl::ToVec2(arrowTexRect.RightBottom())} + }; + + ASSERT(pointSymbol.GetTexture() == arrowSymbol.GetTexture(), ()); + dp::GLState state(gpu::MY_POSITION_PROGRAM, dp::GLState::OverlayLayer); + state.SetColorTexture(pointSymbol.GetTexture()); + + { + dp::Batcher batcher(2 * dp::Batcher::IndexPerQuad, 2 * dp::Batcher::VertexPerQuad); + dp::SessionGuard guard(batcher, [this](dp::GLState const & state, dp::TransferPointer b) + { + dp::MasterPointer bucket(b); + ASSERT(bucket->GetOverlayHandlesCount() == 0, ()); + + m_nodes.emplace_back(state, bucket->MoveBuffer()); + bucket.Destroy(); + }); + + dp::AttributeProvider pointProvider(1 /*stream count*/, dp::Batcher::VertexPerQuad); + pointProvider.InitStream(0 /*stream index*/, GetBindingInfo(), dp::StackVoidRef(pointData)); + + dp::AttributeProvider arrowProvider(1 /*stream count*/, dp::Batcher::VertexPerQuad); + arrowProvider.InitStream(0 /*stream index*/, GetBindingInfo(), dp::StackVoidRef(arrowData)); + + m_parts[MY_POSITION_POINT].second = m_nodes.size(); + m_parts[MY_POSITION_ARROW].second = m_nodes.size(); + m_parts[MY_POSITION_POINT].first = batcher.InsertTriangleStrip(state, dp::MakeStackRefPointer(&pointProvider)); + m_parts[MY_POSITION_ARROW].first = batcher.InsertTriangleStrip(state, dp::MakeStackRefPointer(&arrowProvider)); + } +} + +void MyPosition::RenderPart(dp::RefPointer mng, + dp::UniformValuesStorage const & uniforms, + MyPosition::EMyPositionPart part) +{ + TPart const & accuracy = m_parts[part]; + RenderNode & node = m_nodes[accuracy.second]; + + dp::RefPointer prg = mng->GetProgram(node.m_state.GetProgramIndex()); + prg->Bind(); + if (!node.m_isBuilded) + { + node.m_buffer->Build(prg); + node.m_isBuilded = true; + } + + dp::ApplyUniforms(uniforms, prg); + dp::ApplyState(node.m_state, prg); + + node.m_buffer->RenderRange(accuracy.first); +} + +} diff --git a/drape_frontend/my_position.hpp b/drape_frontend/my_position.hpp new file mode 100644 index 0000000000..d73f3f8482 --- /dev/null +++ b/drape_frontend/my_position.hpp @@ -0,0 +1,73 @@ +#pragma once + +#include "../drape/vertex_array_buffer.hpp" +#include "../drape/glstate.hpp" +#include "../drape/gpu_program_manager.hpp" +#include "../drape/texture_manager.hpp" +#include "../drape/uniform_values_storage.hpp" + +#include "../geometry/screenbase.hpp" + +namespace df +{ + +class MyPosition +{ +public: + MyPosition(dp::RefPointer mng); + + ///@param pt = mercator point + void SetPosition(m2::PointF const & pt); + void SetAzimut(float azimut); + void SetAccuracy(float accuracy); + void SetIsVisible(bool isVisible); + + void Render(ScreenBase const & screen, + dp::RefPointer mng, + dp::UniformValuesStorage const & commonUniforms); + +private: + void CacheAccuracySector(dp::RefPointer mng); + void CachePointPosition(dp::RefPointer mng); + +private: + struct RenderNode + { + RenderNode(dp::GLState const & state, dp::TransferPointer buffer) + : m_state(state) + , m_buffer(buffer) + , m_isBuilded(false) + { + } + + dp::GLState m_state; + dp::MasterPointer m_buffer; + bool m_isBuilded; + }; + + enum EMyPositionPart + { + // don't change order and values + MY_POSITION_ACCURACY = 0, + MY_POSITION_ARROW = 1, + MY_POSITION_POINT = 2 + }; + + void RenderPart(dp::RefPointer mng, + dp::UniformValuesStorage const & uniforms, + EMyPositionPart part); + +private: + m2::PointF m_position; + float m_azimut; + float m_accuracy; + bool m_showAzimut; + bool m_isVisible; + + using TPart = pair; + + vector m_parts; + vector m_nodes; +}; + +}