diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index b4a9fb5edf..c7cf9ecca6 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -440,7 +440,6 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) case Message::Type::FlushSubroute: { - if (m_apiVersion == dp::ApiVersion::Metal) return; // TODO(@darina, @rokuz): TEMPORARY ref_ptr msg = message; auto subrouteData = msg->AcceptRenderData(); @@ -482,7 +481,6 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) case Message::Type::FlushSubrouteArrows: { - if (m_apiVersion == dp::ApiVersion::Metal) return; // TODO(@darina, @rokuz): TEMPORARY ref_ptr msg = message; drape_ptr routeArrowsData = msg->AcceptRenderData(); if (CheckRouteRecaching(make_ref(routeArrowsData))) @@ -496,7 +494,6 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) case Message::Type::FlushSubrouteMarkers: { - if (m_apiVersion == dp::ApiVersion::Metal) return; // TODO(@darina, @rokuz): TEMPORARY ref_ptr msg = message; drape_ptr markersData = msg->AcceptRenderData(); if (markersData->m_recacheId < 0) @@ -513,7 +510,6 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) case Message::Type::RemoveSubroute: { - if (m_apiVersion == dp::ApiVersion::Metal) return; // TODO(@darina, @rokuz): TEMPORARY ref_ptr msg = message; if (msg->NeedDeactivateFollowing()) { @@ -563,7 +559,6 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) case Message::Type::AddRoutePreviewSegment: { - if (m_apiVersion == dp::ApiVersion::Metal) return; // TODO(@darina, @rokuz): TEMPORARY ref_ptr const msg = message; RouteRenderer::PreviewInfo info; info.m_startPoint = msg->GetStartPoint(); @@ -574,7 +569,6 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) case Message::Type::RemoveRoutePreviewSegment: { - if (m_apiVersion == dp::ApiVersion::Metal) return; // TODO(@darina, @rokuz): TEMPORARY ref_ptr const msg = message; if (msg->NeedRemoveAll()) m_routeRenderer->RemoveAllPreviewSegments(); @@ -585,7 +579,6 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) case Message::Type::SetSubrouteVisibility: { - if (m_apiVersion == dp::ApiVersion::Metal) return; // TODO(@darina, @rokuz): TEMPORARY ref_ptr const msg = message; m_routeRenderer->SetSubrouteVisibility(msg->GetSubrouteId(), msg->IsVisible()); break; @@ -683,7 +676,6 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) case Message::Type::FlushCirclesPack: { - if (m_apiVersion == dp::ApiVersion::Metal) return; // TODO(@darina, @rokuz): TEMPORARY ref_ptr msg = message; CHECK(m_context != nullptr, ()); switch (msg->GetDestination()) diff --git a/shaders/Metal/map.metal b/shaders/Metal/map.metal new file mode 100644 index 0000000000..98ecb5c77b --- /dev/null +++ b/shaders/Metal/map.metal @@ -0,0 +1,60 @@ +#include +#include +#include "shaders_lib.h" +using namespace metal; + +typedef struct +{ + float4x4 u_modelView; + float4x4 u_projection; + float4x4 u_pivotTransform; + float u_opacity; + float u_zScale; + float u_interpolation; + float u_isOutlinePass; + packed_float2 u_contrastGamma; +} Uniforms_T; + +// CirclePoint + +typedef struct +{ + float3 a_normal [[attribute(0)]]; + float3 a_position [[attribute(1)]]; + float4 a_color [[attribute(2)]]; +} CirclePointVertex_T; + +typedef struct +{ + float4 position [[position]]; + float3 radius; + float4 color; +} CirclePointFragment_T; + +vertex CirclePointFragment_T vsCirclePoint(const CirclePointVertex_T in [[stage_in]], + constant Uniforms_T & uniforms [[buffer(2)]]) +{ + CirclePointFragment_T out; + + float3 radius = in.a_normal * in.a_position.z; + float4 pos = float4(in.a_position.xy, 0.0, 1.0) * uniforms.u_modelView; + float4 shiftedPos = float4(radius.xy, 0.0, 0.0) + pos; + out.position = ApplyPivotTransform(shiftedPos * uniforms.u_projection, uniforms.u_pivotTransform, 0.0); + out.radius = radius; + out.color = in.a_color; + + return out; +} + +fragment float4 fsCirclePoint(const CirclePointFragment_T in [[stage_in]], + constant Uniforms_T & uniforms [[buffer(0)]]) +{ + constexpr float kAntialiasingScalar = 0.9; + + float d = dot(in.radius.xy, in.radius.xy); + float4 color = in.color; + float aaRadius = in.radius.z * kAntialiasingScalar; + float stepValue = 1.0 - smoothstep(aaRadius * aaRadius, in.radius.z * in.radius.z, d); + color.a *= (uniforms.u_opacity * stepValue); + return color; +} diff --git a/shaders/Metal/route.metal b/shaders/Metal/route.metal new file mode 100644 index 0000000000..e9957ecaae --- /dev/null +++ b/shaders/Metal/route.metal @@ -0,0 +1,224 @@ +#include +#include +#include "shaders_lib.h" +using namespace metal; + +typedef struct +{ + float4x4 u_modelView; + float4x4 u_projection; + float4x4 u_pivotTransform; + float4 u_routeParams; + float4 u_color; + float4 u_maskColor; + float4 u_outlineColor; + packed_float2 u_pattern; + packed_float2 u_angleCosSin; + float u_arrowHalfWidth; + float u_opacity; +} Uniforms_T; + +// Route/RouteDash + +typedef struct +{ + float3 a_position [[attribute(0)]]; + float2 a_normal [[attribute(1)]]; + float3 a_length [[attribute(2)]]; + float4 a_color [[attribute(3)]]; +} RouteVertex_T; + +typedef struct +{ + float4 position [[position]]; + float3 lengthParams; + float4 color; +} RouteFragment_T; + +vertex RouteFragment_T vsRoute(const RouteVertex_T in [[stage_in]], + constant Uniforms_T & uniforms [[buffer(1)]]) +{ + RouteFragment_T out; + + float2 transformedAxisPos = (float4(in.a_position.xy, 0.0, 1.0) * uniforms.u_modelView).xy; + float2 len = float2(in.a_length.x, in.a_length.z); + if (dot(in.a_normal, in.a_normal) != 0.0) + { + float2 norm = in.a_normal * uniforms.u_routeParams.x; + transformedAxisPos = CalcLineTransformedAxisPos(transformedAxisPos, in.a_position.xy + norm, + uniforms.u_modelView, length(norm)); + if (uniforms.u_routeParams.y != 0.0) + len = float2(in.a_length.x + in.a_length.y * uniforms.u_routeParams.y, in.a_length.z); + } + + out.lengthParams = float3(len, uniforms.u_routeParams.z); + out.color = in.a_color; + float4 pos = float4(transformedAxisPos, in.a_position.z, 1.0) * uniforms.u_projection; + out.position = ApplyPivotTransform(pos, uniforms.u_pivotTransform, 0.0); + + return out; +} + +fragment float4 fsRoute(const RouteFragment_T in [[stage_in]], + constant Uniforms_T & uniforms [[buffer(1)]]) +{ + if (in.lengthParams.x < in.lengthParams.z) + discard_fragment(); + + constexpr float kAntialiasingThreshold = 0.92; + constexpr float kOutlineThreshold1 = 0.81; + constexpr float kOutlineThreshold2 = 0.71; + + float4 color = mix(mix(uniforms.u_color, float4(in.color.rgb, 1.0), in.color.a), uniforms.u_color, + step(uniforms.u_routeParams.w, 0.0)); + color = mix(color, uniforms.u_outlineColor, step(kOutlineThreshold1, abs(in.lengthParams.y))); + color = mix(color, uniforms.u_outlineColor, + smoothstep(kOutlineThreshold2, kOutlineThreshold1, abs(in.lengthParams.y))); + color.a *= (1.0 - smoothstep(kAntialiasingThreshold, 1.0, abs(in.lengthParams.y))); + color = float4(mix(color.rgb, uniforms.u_maskColor.rgb, uniforms.u_maskColor.a), color.a); + return color; +} + +float AlphaFromPattern(float curLen, float2 dashGapLen) +{ + float len = dashGapLen.x + dashGapLen.y; + float offset = fract(curLen / len) * len; + return step(offset, dashGapLen.x); +} + +fragment float4 fsRouteDash(const RouteFragment_T in [[stage_in]], + constant Uniforms_T & uniforms [[buffer(1)]]) +{ + if (in.lengthParams.x < in.lengthParams.z) + discard_fragment(); + + constexpr float kAntialiasingThreshold = 0.92; + + float4 color = uniforms.u_color + in.color; + float a = 1.0 - smoothstep(kAntialiasingThreshold, 1.0, abs(in.lengthParams.y)); + color.a *= (a * AlphaFromPattern(in.lengthParams.x, uniforms.u_pattern)); + color = float4(mix(color.rgb, uniforms.u_maskColor.rgb, uniforms.u_maskColor.a), color.a); + return color; +} + +// RouteArrow + +typedef struct +{ + float4 a_position [[attribute(0)]]; + float2 a_normal [[attribute(1)]]; + float2 a_texCoords [[attribute(2)]]; +} RouteArrowVertex_T; + +typedef struct +{ + float4 position [[position]]; + float2 texCoords; +} RouteArrowFragment_T; + +typedef struct +{ + float4 color [[color(0)]]; + float depth [[depth(any)]]; +} RouteArrowFragment_Output; + +vertex RouteArrowFragment_T vsRouteArrow(const RouteArrowVertex_T in [[stage_in]], + constant Uniforms_T & uniforms [[buffer(1)]]) +{ + RouteArrowFragment_T out; + + float2 transformedAxisPos = (float4(in.a_position.xy, 0.0, 1.0) * uniforms.u_modelView).xy; + if (dot(in.a_normal, in.a_normal) != 0.0) + { + float2 norm = in.a_normal * uniforms.u_arrowHalfWidth; + transformedAxisPos = CalcLineTransformedAxisPos(transformedAxisPos, in.a_position.xy + norm, + uniforms.u_modelView, length(norm)); + } + + out.texCoords = in.a_texCoords; + float4 pos = float4(transformedAxisPos, in.a_position.z, 1.0) * uniforms.u_projection; + out.position = ApplyPivotTransform(pos, uniforms.u_pivotTransform, 0.0); + + return out; +} + +fragment RouteArrowFragment_Output fsRouteArrow(const RouteArrowFragment_T in [[stage_in]], + constant Uniforms_T & uniforms [[buffer(1)]], + texture2d u_colorTex [[texture(0)]], + sampler u_colorTexSampler [[sampler(0)]]) +{ + RouteArrowFragment_Output output; + float4 color = u_colorTex.sample(u_colorTexSampler, in.texCoords); + color.a *= uniforms.u_opacity; + output.depth = in.position.z; + if (color.a < 0.001) + output.depth = 1.0; + output.color = float4(mix(color.rgb, uniforms.u_maskColor.rgb, uniforms.u_maskColor.a), color.a); + return output; +} + +// RouteMarker + +typedef struct +{ + float4 a_position [[attribute(0)]]; + float3 a_normal [[attribute(1)]]; + float4 a_color [[attribute(2)]]; +} RouteMarkerVertex_T; + +typedef struct +{ + float4 position [[position]]; + float4 radius; + float4 color; +} RouteMarkerFragment_T; + +typedef struct +{ + float4 color [[color(0)]]; + float depth [[depth(any)]]; +} RouteMarkerFragment_Output; + +vertex RouteMarkerFragment_T vsRouteMarker(const RouteMarkerVertex_T in [[stage_in]], + constant Uniforms_T & uniforms [[buffer(1)]]) +{ + RouteMarkerFragment_T out; + + float r = uniforms.u_routeParams.x * in.a_normal.z; + float2 cs = uniforms.u_angleCosSin; + float2 normal = float2(in.a_normal.x * cs.x - in.a_normal.y * cs.y, + in.a_normal.x * cs.y + in.a_normal.y * cs.x); + float4 radius = float4(normal * r, r, in.a_position.w); + float4 pos = float4(in.a_position.xy, 0.0, 1.0) * uniforms.u_modelView; + float2 shiftedPos = radius.xy + pos.xy; + pos = float4(shiftedPos, in.a_position.z, 1.0) * uniforms.u_projection; + out.radius = radius; + out.color = in.a_color; + out.position = ApplyPivotTransform(pos, uniforms.u_pivotTransform, 0.0); + + return out; +} + +fragment RouteMarkerFragment_Output fsRouteMarker(const RouteMarkerFragment_T in [[stage_in]], + constant Uniforms_T & uniforms [[buffer(1)]]) +{ + if (uniforms.u_routeParams.y > in.radius.w) + discard_fragment(); + + RouteMarkerFragment_Output output; + + constexpr float kAntialiasingPixelsCount = 2.5; + float4 color = in.color; + + float aaRadius = max(in.radius.z - kAntialiasingPixelsCount, 0.0); + float stepValue = smoothstep(aaRadius * aaRadius, in.radius.z * in.radius.z, + dot(in.radius.xy, in.radius.xy)); + color.a = color.a * uniforms.u_opacity * (1.0 - stepValue); + + output.depth = in.position.z; + if (color.a < 0.001) + output.depth = 1.0; + output.color = float4(mix(color.rgb, uniforms.u_maskColor.rgb, uniforms.u_maskColor.a), color.a); + + return output; +} diff --git a/shaders/Metal/shaders_lib.h b/shaders/Metal/shaders_lib.h index 83c2bd0a31..cccd8f66dd 100644 --- a/shaders/Metal/shaders_lib.h +++ b/shaders/Metal/shaders_lib.h @@ -1,15 +1,9 @@ -#pragma once - #include #include using namespace metal; -float4 ApplyPivotTransform(float4 pivot, float4x4 pivotTransform, float pivotRealZ) -{ - float4 transformedPivot = pivot; - float w = transformedPivot.w; - transformedPivot.xyw = (pivotTransform * float4(transformedPivot.xy, pivotRealZ, w)).xyw; - transformedPivot.z *= transformedPivot.w / w; - return transformedPivot; -} +float4 ApplyPivotTransform(float4 pivot, float4x4 pivotTransform, float pivotRealZ); + +// This function calculates transformed position on an axis for line shaders family. +float2 CalcLineTransformedAxisPos(float2 originalAxisPos, float2 shiftedPos, float4x4 modelView, float halfWidth); diff --git a/shaders/Metal/shaders_lib.metal b/shaders/Metal/shaders_lib.metal new file mode 100644 index 0000000000..ac6c19d8b8 --- /dev/null +++ b/shaders/Metal/shaders_lib.metal @@ -0,0 +1,23 @@ +#include +#include + +using namespace metal; + +float4 ApplyPivotTransform(float4 pivot, float4x4 pivotTransform, float pivotRealZ) +{ + float4 transformedPivot = pivot; + float w = transformedPivot.w; + transformedPivot.xyw = (pivotTransform * float4(transformedPivot.xy, pivotRealZ, w)).xyw; + transformedPivot.z *= transformedPivot.w / w; + return transformedPivot; +} + +float2 CalcLineTransformedAxisPos(float2 originalAxisPos, float2 shiftedPos, float4x4 modelView, float halfWidth) +{ + float2 p = (float4(shiftedPos, 0.0, 1.0) * modelView).xy; + float2 d = p - originalAxisPos; + if (dot(d, d) != 0.0) + return originalAxisPos + normalize(d) * halfWidth; + else + return originalAxisPos; +} diff --git a/shaders/metal_program_pool.mm b/shaders/metal_program_pool.mm index 49c780e6a3..79bbe03d25 100644 --- a/shaders/metal_program_pool.mm +++ b/shaders/metal_program_pool.mm @@ -73,11 +73,11 @@ std::array(Program::ProgramsCount)> const kMeta ProgramInfo("vsMyPosition", "fsMyPosition", {{0, 1}}), // MyPosition ProgramInfo("", "", {}), // Transit ProgramInfo("", "", {}), // TransitMarker - ProgramInfo("", "", {}), // Route - ProgramInfo("", "", {}), // RouteDash - ProgramInfo("", "", {}), // RouteArrow - ProgramInfo("", "", {}), // RouteMarker - ProgramInfo("", "", {}), // CirclePoint + ProgramInfo("vsRoute", "fsRoute", {{0, 3}}), // Route + ProgramInfo("vsRoute", "fsRouteDash", {{0, 3}}), // RouteDash + ProgramInfo("vsRouteArrow", "fsRouteArrow", {{0, 2}}), // RouteArrow + ProgramInfo("vsRouteMarker", "fsRouteMarker", {{0, 2}}), // RouteMarker + ProgramInfo("vsCirclePoint", "fsCirclePoint", {{0, 0}, {1, 2}}), // CirclePoint ProgramInfo("vsDebugRect", "fsDebugRect", {{0, 0}}), // DebugRect ProgramInfo("vsScreenQuad", "fsScreenQuad", {{0, 1}}), // ScreenQuad ProgramInfo("vsArrow3d", "fsArrow3d", {{0, 0}, {1, 1}}), // Arrow3d diff --git a/xcode/shaders/shaders.xcodeproj/project.pbxproj b/xcode/shaders/shaders.xcodeproj/project.pbxproj index 226115e6ae..9eea68b702 100644 --- a/xcode/shaders/shaders.xcodeproj/project.pbxproj +++ b/xcode/shaders/shaders.xcodeproj/project.pbxproj @@ -7,6 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + 451E692D214A53C000764A97 /* route.metal in Sources */ = {isa = PBXBuildFile; fileRef = 451E692C214A53C000764A97 /* route.metal */; }; + 451E692F214A6FA200764A97 /* map.metal in Sources */ = {isa = PBXBuildFile; fileRef = 451E692E214A6FA200764A97 /* map.metal */; }; + 451E6931214A8D4200764A97 /* shaders_lib.metal in Sources */ = {isa = PBXBuildFile; fileRef = 451E6930214A8D4200764A97 /* shaders_lib.metal */; }; 4560F58A213D57D600CC736C /* debug_rect.metal in Sources */ = {isa = PBXBuildFile; fileRef = 45789EDC21342BDE009955CC /* debug_rect.metal */; }; 4560F58B213D57D600CC736C /* screen_quad.metal in Sources */ = {isa = PBXBuildFile; fileRef = 4560F582213D44CE00CC736C /* screen_quad.metal */; }; 4560F5AB2142AC1300CC736C /* gui.metal in Sources */ = {isa = PBXBuildFile; fileRef = 4560F5AA2142AC1300CC736C /* gui.metal */; }; @@ -62,6 +65,9 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 451E692C214A53C000764A97 /* route.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = route.metal; sourceTree = ""; }; + 451E692E214A6FA200764A97 /* map.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = map.metal; sourceTree = ""; }; + 451E6930214A8D4200764A97 /* shaders_lib.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = shaders_lib.metal; sourceTree = ""; }; 4560F582213D44CE00CC736C /* screen_quad.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = screen_quad.metal; sourceTree = ""; }; 4560F5AA2142AC1300CC736C /* gui.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = gui.metal; sourceTree = ""; }; 4561ADF320E378CB0096BC12 /* program_manager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = program_manager.cpp; sourceTree = ""; }; @@ -377,13 +383,16 @@ 45789EDB21342AC4009955CC /* Metal */ = { isa = PBXGroup; children = ( - 45789EDC21342BDE009955CC /* debug_rect.metal */, - 4560F582213D44CE00CC736C /* screen_quad.metal */, - 4560F5AA2142AC1300CC736C /* gui.metal */, - BBF7916F2146D8EC00D27BD8 /* system.metal */, BBF7917221493AFC00D27BD8 /* arrow3d.metal */, - BBF7917421495FF900D27BD8 /* shapes.metal */, + 45789EDC21342BDE009955CC /* debug_rect.metal */, + 4560F5AA2142AC1300CC736C /* gui.metal */, + 451E692E214A6FA200764A97 /* map.metal */, + 451E692C214A53C000764A97 /* route.metal */, + 4560F582213D44CE00CC736C /* screen_quad.metal */, BBF79176214970B600D27BD8 /* shaders_lib.h */, + 451E6930214A8D4200764A97 /* shaders_lib.metal */, + BBF7917421495FF900D27BD8 /* shapes.metal */, + BBF7916F2146D8EC00D27BD8 /* system.metal */, ); path = Metal; sourceTree = ""; @@ -541,9 +550,12 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 451E692F214A6FA200764A97 /* map.metal in Sources */, 4560F5AB2142AC1300CC736C /* gui.metal in Sources */, + 451E692D214A53C000764A97 /* route.metal in Sources */, BBF791702146D8EC00D27BD8 /* system.metal in Sources */, 4560F58A213D57D600CC736C /* debug_rect.metal in Sources */, + 451E6931214A8D4200764A97 /* shaders_lib.metal in Sources */, BBF7917321493AFC00D27BD8 /* arrow3d.metal in Sources */, BBF7917521495FF900D27BD8 /* shapes.metal in Sources */, 4560F58B213D57D600CC736C /* screen_quad.metal in Sources */,