diff --git a/ios/graphics/Model/Line/LineVertex.swift b/ios/graphics/Model/Line/LineVertex.swift index fef25eb9b..5273585b4 100644 --- a/ios/graphics/Model/Line/LineVertex.swift +++ b/ios/graphics/Model/Line/LineVertex.swift @@ -30,24 +30,12 @@ public struct LineVertex: Equatable { vertexDescriptor.attributes[1].offset = offset offset += 3 * MemoryLayout.stride - // Vertex Index + // Metadata vertexDescriptor.attributes[2].bufferIndex = bufferIndex vertexDescriptor.attributes[2].format = .float vertexDescriptor.attributes[2].offset = offset offset += MemoryLayout.stride - // Length Prefix - vertexDescriptor.attributes[3].bufferIndex = bufferIndex - vertexDescriptor.attributes[3].format = .float - vertexDescriptor.attributes[3].offset = offset - offset += MemoryLayout.stride - - // Line Style Info - vertexDescriptor.attributes[4].bufferIndex = bufferIndex - vertexDescriptor.attributes[4].format = .float - vertexDescriptor.attributes[4].offset = offset - offset += MemoryLayout.stride - vertexDescriptor.layouts[0].stride = offset return vertexDescriptor }() @@ -69,24 +57,12 @@ public struct LineVertex: Equatable { vertexDescriptor.attributes[1].offset = offset offset += 2 * MemoryLayout.stride - // Vertex Index + // Metadata vertexDescriptor.attributes[2].bufferIndex = bufferIndex vertexDescriptor.attributes[2].format = .float vertexDescriptor.attributes[2].offset = offset offset += MemoryLayout.stride - // Length Prefix - vertexDescriptor.attributes[3].bufferIndex = bufferIndex - vertexDescriptor.attributes[3].format = .float - vertexDescriptor.attributes[3].offset = offset - offset += MemoryLayout.stride - - // Line Style Info - vertexDescriptor.attributes[4].bufferIndex = bufferIndex - vertexDescriptor.attributes[4].format = .float - vertexDescriptor.attributes[4].offset = offset - offset += MemoryLayout.stride - vertexDescriptor.layouts[0].stride = offset return vertexDescriptor }() diff --git a/ios/graphics/Shader/Metal/LineShader.metal b/ios/graphics/Shader/Metal/LineShader.metal index 48c237325..b3411f34e 100644 --- a/ios/graphics/Shader/Metal/LineShader.metal +++ b/ios/graphics/Shader/Metal/LineShader.metal @@ -26,17 +26,25 @@ using namespace metal; struct LineVertexIn { float2 lineA [[attribute(0)]]; float2 lineB [[attribute(1)]]; - float vertexIndex [[attribute(2)]]; - float lengthPrefix [[attribute(3)]]; - float stylingIndex [[attribute(4)]]; + /* + lineMetadata is packed as a single float but contains multiple pieces of information: + - Bits 0-1 : Vertex Index (0-3) (used for rendering different parts of the quad) + - Bits 2-9 : Line Style Index (0-255) (defines the appearance of the line) + - Bits 10-11 : Segment Type (0 = inner, 1 = start, 2 = end, 3 = single-segment) + */ + float lineMetadata [[attribute(2)]]; }; struct LineVertexUnitSphereIn { float3 lineA [[attribute(0)]]; float3 lineB [[attribute(1)]]; - float vertexIndex [[attribute(2)]]; - float lengthPrefix [[attribute(3)]]; - float stylingIndex [[attribute(4)]]; + /* + lineMetadata is packed as a single float but contains multiple pieces of information: + - Bits 0-1 : Vertex Index (0-3) (used for rendering different parts of the quad) + - Bits 2-9 : Line Style Index (0-255) (defines the appearance of the line) + - Bits 10-11 : Segment Type (0 = inner, 1 = start, 2 = end, 3 = single-segment) + */ + float lineMetadata [[attribute(2)]]; }; struct LineVertexOut { @@ -44,9 +52,9 @@ struct LineVertexOut { float2 uv; float3 lineA; float3 lineB; - int stylingIndex; + int styleOffset; float width; - int segmentType; + uint segmentType; float lengthPrefix; float scalingFactor; float dashingSize; @@ -76,9 +84,9 @@ struct SimpleLineVertexOut { float2 uv; float3 lineA; float3 lineB; - int stylingIndex; + int styleOffset; float width; - int segmentType; + uint segmentType; float scalingFactor; }; @@ -107,8 +115,13 @@ unitSphereSimpleLineGroupVertexShader(const LineVertexUnitSphereIn vertexIn [[st constant float4 &originOffset [[buffer(5)]], constant float4 &tileOrigin [[buffer(6)]]) { - int styleIndex = (int(vertexIn.stylingIndex) & 0xFF) * 8; - constant SimpleLineStyling *style = (constant SimpleLineStyling *)(styling + styleIndex); + const uint packed = as_type(vertexIn.lineMetadata); // Reinterpret float as uint + const uint vertexIndex = packed & 0x3; // Bits 0-1 + const uint styleIndex = (packed >> 2) & 0xFF; // Bits 2-9 + const uint segmentType = (packed >> 10) & 0x3; // Bits 10-11 + const int styleOffset = styleIndex * 8; + + constant SimpleLineStyling *style = (constant SimpleLineStyling *)(styling + styleOffset); // extend position in width direction and in length direction by width / 2.0 float width = style->width / 2.0; @@ -117,15 +130,13 @@ unitSphereSimpleLineGroupVertexShader(const LineVertexUnitSphereIn vertexIn [[st width *= scalingFactor ; } - int index = int(vertexIn.vertexIndex); - const float3 lineA = vertexIn.lineA; const float3 lineB = vertexIn.lineB; float3 position = lineB; - if(index == 0) { + if(vertexIndex == 0) { position = lineA; - } else if(index == 1) { + } else if(vertexIndex == 1) { position = lineA; } @@ -135,14 +146,14 @@ unitSphereSimpleLineGroupVertexShader(const LineVertexUnitSphereIn vertexIn [[st float3 widthNormal = widthNormalIn; - if(index == 0) { + if(vertexIndex == 0) { lengthNormal *= -1.0; widthNormal *= -1.0; - } else if(index == 1) { + } else if(vertexIndex == 1) { lengthNormal *= -1.0; - } else if(index == 2) { + } else if(vertexIndex == 2) { // all fine - } else if(index == 3) { + } else if(vertexIndex == 3) { widthNormal *= -1.0; } @@ -150,14 +161,12 @@ unitSphereSimpleLineGroupVertexShader(const LineVertexUnitSphereIn vertexIn [[st float4((lengthNormal + widthNormal).xyz,0.0) * float4(width, width, width, 0.0); - const int segmentType = int(vertexIn.stylingIndex) >> 8;// / 256.0; - SimpleLineVertexOut out { .position = vpMatrix * extendedPosition, .uv = extendedPosition.xy, .lineA = extendedPosition.xyz - ((vertexIn.lineA + originOffset.xyz)), .lineB = ((vertexIn.lineB + originOffset.xyz)) - ((vertexIn.lineA + originOffset.xyz)), - .stylingIndex = styleIndex, + .styleOffset = styleOffset, .width = width, .segmentType = segmentType, .scalingFactor = scalingFactor, @@ -175,9 +184,14 @@ simpleLineGroupVertexShader(const LineVertexIn vertexIn [[stage_in]], constant float4 &originOffset [[buffer(5)]], constant float4 &tileOrigin [[buffer(6)]]) { - int styleIndex = (int(vertexIn.stylingIndex) & 0xFF) * 8; - constant SimpleLineStyling *style = (constant SimpleLineStyling *)(styling + styleIndex); - + const uint packed = as_type(vertexIn.lineMetadata); // Reinterpret float as uint + const uint vertexIndex = packed & 0x3; // Bits 0-1 + const uint styleIndex = (packed >> 2) & 0xFF; // Bits 2-9 + const uint segmentType = (packed >> 10) & 0x3; // Bits 10-11 + const int styleOffset = styleIndex * 8; + + constant SimpleLineStyling *style = (constant SimpleLineStyling *)(styling + styleOffset); + // extend position in width direction and in length direction by width / 2.0 float width = style->width / 2.0; @@ -188,11 +202,10 @@ simpleLineGroupVertexShader(const LineVertexIn vertexIn [[stage_in]], const float3 lineA = float3(vertexIn.lineA, 0); const float3 lineB = float3(vertexIn.lineB, 0); - int index = int(vertexIn.vertexIndex); float3 position = lineB; - if(index == 0) { + if(vertexIndex == 0) { position = lineA; - } else if(index == 1) { + } else if(vertexIndex == 1) { position = lineA; } @@ -202,14 +215,14 @@ simpleLineGroupVertexShader(const LineVertexIn vertexIn [[stage_in]], float3 widthNormal = widthNormalIn; - if(index == 0) { + if(vertexIndex == 0) { lengthNormal *= -1.0; widthNormal *= -1.0; - } else if(index == 1) { + } else if(vertexIndex == 1) { lengthNormal *= -1.0; - } else if(index == 2) { + } else if(vertexIndex == 2) { // all fine - } else if(index == 3) { + } else if(vertexIndex == 3) { widthNormal *= -1.0; } @@ -217,14 +230,12 @@ simpleLineGroupVertexShader(const LineVertexIn vertexIn [[stage_in]], float4((lengthNormal + widthNormal).xy, 0.0,0.0) * float4(width, width, width, 0.0); - const int segmentType = int(vertexIn.stylingIndex) >> 8;// / 256.0; - SimpleLineVertexOut out { .position = vpMatrix * extendedPosition, .uv = extendedPosition.xy, .lineA = extendedPosition.xyz - ((lineA + originOffset.xyz)), .lineB = ((lineB + originOffset.xyz)) - ((lineA + originOffset.xyz)), - .stylingIndex = styleIndex, + .styleOffset = styleOffset, .width = width, .segmentType = segmentType, .scalingFactor = scalingFactor, @@ -238,7 +249,7 @@ fragment half4 simpleLineGroupFragmentShader(SimpleLineVertexOut in [[stage_in]], constant half *styling [[buffer(1)]]) { - constant SimpleLineStyling *style = (constant SimpleLineStyling *)(styling + in.stylingIndex); + constant SimpleLineStyling *style = (constant SimpleLineStyling *)(styling + in.styleOffset); const half lineLength = length(in.lineB); const half t = dot(in.lineA, normalize(in.lineB) / lineLength); @@ -292,8 +303,15 @@ unitSphereLineGroupVertexShader(const LineVertexUnitSphereIn vertexIn [[stage_in constant float4 &originOffset [[buffer(5)]], constant float4 &tileOrigin [[buffer(6)]]) { - int styleIndex = (int(vertexIn.stylingIndex) & 0xFF) * 23; - constant LineStyling *style = (constant LineStyling *)(styling + styleIndex); + + const uint packed = as_type(vertexIn.lineMetadata); // Reinterpret float as uint + const uint vertexIndex = packed & 0x3; // Bits 0-1 + const uint styleIndex = (packed >> 2) & 0xFF; // Bits 2-9 + const uint segmentType = (packed >> 10) & 0x3; // Bits 10-11 + const float lengthPrefix = float((packed >> 11) & 0x1FFFFF) / 1000.0; // Bits 11-31 + const int styleOffset = styleIndex * 23; + + constant LineStyling *style = (constant LineStyling *)(styling + styleOffset); // extend position in width direction and in length direction by width / 2.0 float width = style->width / 2.0; @@ -307,15 +325,13 @@ unitSphereLineGroupVertexShader(const LineVertexUnitSphereIn vertexIn [[stage_in dashingSize *= dashingScalingFactor; } - int index = int(vertexIn.vertexIndex); - const float3 lineA = vertexIn.lineA; const float3 lineB = vertexIn.lineB; float3 position = lineB; - if(index == 0) { + if(vertexIndex == 0) { position = lineA; - } else if(index == 1) { + } else if(vertexIndex == 1) { position = lineA; } @@ -325,14 +341,14 @@ unitSphereLineGroupVertexShader(const LineVertexUnitSphereIn vertexIn [[stage_in float3 widthNormal = widthNormalIn; - if(index == 0) { + if(vertexIndex == 0) { lengthNormal *= -1.0; widthNormal *= -1.0; - } else if(index == 1) { + } else if(vertexIndex == 1) { lengthNormal *= -1.0; - } else if(index == 2) { + } else if(vertexIndex == 2) { // all fine - } else if(index == 3) { + } else if(vertexIndex == 3) { widthNormal *= -1.0; } @@ -342,17 +358,15 @@ unitSphereLineGroupVertexShader(const LineVertexUnitSphereIn vertexIn [[stage_in float4((lengthNormal + widthNormal).xyz,0.0) * float4(width, width, width, 0.0) + lineOffset; - const int segmentType = int(vertexIn.stylingIndex) >> 8;// / 256.0; - LineVertexOut out { .position = vpMatrix * extendedPosition, .uv = extendedPosition.xy, .lineA = extendedPosition.xyz - ((vertexIn.lineA + originOffset.xyz) + lineOffset.xyz), .lineB = ((vertexIn.lineB + originOffset.xyz) + lineOffset.xyz) - ((vertexIn.lineA + originOffset.xyz) + lineOffset.xyz), - .stylingIndex = styleIndex, + .styleOffset = styleOffset, .width = width, .segmentType = segmentType, - .lengthPrefix = vertexIn.lengthPrefix, + .lengthPrefix = lengthPrefix, .scalingFactor = scalingFactor, .dashingSize = dashingSize, .scaledBlur = blur @@ -370,8 +384,14 @@ lineGroupVertexShader(const LineVertexIn vertexIn [[stage_in]], constant float4 &originOffset [[buffer(5)]], constant float4 &tileOrigin [[buffer(6)]]) { - int styleIndex = (int(vertexIn.stylingIndex) & 0xFF) * 23; - constant LineStyling *style = (constant LineStyling *)(styling + styleIndex); + const uint packed = as_type(vertexIn.lineMetadata); // Reinterpret float as uint + const uint vertexIndex = packed & 0x3; // Bits 0-1 + const uint styleIndex = (packed >> 2) & 0xFF; // Bits 2-9 + const uint segmentType = (packed >> 10) & 0x3; // Bits 10-11 + const float lengthPrefix = float((packed >> 11) & 0x1FFFFF) / 1000.0; // Bits 11-31 + const int styleOffset = styleIndex * 23; + + constant LineStyling *style = (constant LineStyling *)(styling + styleOffset); // extend position in width direction and in length direction by width / 2.0 float width = style->width / 2.0; @@ -388,11 +408,10 @@ lineGroupVertexShader(const LineVertexIn vertexIn [[stage_in]], const float3 lineA = float3(vertexIn.lineA, 0); const float3 lineB = float3(vertexIn.lineB, 0); - int index = int(vertexIn.vertexIndex); float3 position = lineB; - if(index == 0) { + if(vertexIndex == 0) { position = lineA; - } else if(index == 1) { + } else if(vertexIndex == 1) { position = lineA; } @@ -402,14 +421,14 @@ lineGroupVertexShader(const LineVertexIn vertexIn [[stage_in]], float3 widthNormal = widthNormalIn; - if(index == 0) { + if(vertexIndex == 0) { lengthNormal *= -1.0; widthNormal *= -1.0; - } else if(index == 1) { + } else if(vertexIndex == 1) { lengthNormal *= -1.0; - } else if(index == 2) { + } else if(vertexIndex == 2) { // all fine - } else if(index == 3) { + } else if(vertexIndex == 3) { widthNormal *= -1.0; } @@ -419,17 +438,15 @@ lineGroupVertexShader(const LineVertexIn vertexIn [[stage_in]], float4((lengthNormal + widthNormal).xy, 0.0,0.0) * float4(width, width, width, 0.0) + lineOffset; - const int segmentType = int(vertexIn.stylingIndex) >> 8;// / 256.0; - LineVertexOut out { .position = vpMatrix * extendedPosition, .uv = extendedPosition.xy, .lineA = extendedPosition.xyz - ((lineA + originOffset.xyz) + lineOffset.xyz), .lineB = ((lineB + originOffset.xyz) + lineOffset.xyz) - ((lineA + originOffset.xyz) + lineOffset.xyz), - .stylingIndex = styleIndex, + .styleOffset = styleOffset, .width = width, .segmentType = segmentType, - .lengthPrefix = vertexIn.lengthPrefix, + .lengthPrefix = lengthPrefix, .scalingFactor = scalingFactor, .dashingSize = dashingSize, .scaledBlur = blur @@ -444,7 +461,7 @@ lineGroupFragmentShader(LineVertexOut in [[stage_in]], constant half *styling [[buffer(1)]], constant float &time [[buffer(2)]]) { - constant LineStyling *style = (constant LineStyling *)(styling + in.stylingIndex); + constant LineStyling *style = (constant LineStyling *)(styling + in.styleOffset); const float lineLength = length(in.lineB); const float t = dot(in.lineA, normalize(in.lineB) / lineLength); diff --git a/shared/public/LineHelper.h b/shared/public/LineHelper.h index a0ca629b6..6af5b1664 100644 --- a/shared/public/LineHelper.h +++ b/shared/public/LineHelper.h @@ -13,6 +13,7 @@ #include "CoordinateConversionHelperInterface.h" #include "LineInfoInterface.h" #include +#include class LineHelper { public: @@ -72,7 +73,17 @@ class LineHelper { return newPolyline; } + inline static float packLineStyleMetadata(uint8_t vertexIndex, uint8_t lineStyleIndex, uint8_t segmentType, float prefixTotalLineLength) { + uint32_t packed = + (vertexIndex & 0x3) + | ((lineStyleIndex & 0xFF) << 2) + | ((segmentType & 0x3) << 10) + | ((int(prefixTotalLineLength * 1000.0) & 0x1FFFFF) << 11); + float result; + std::memcpy(&result, &packed, sizeof(float)); // Preserve all 32 bits + return result; + } private: static float distanceSquared(const Coord& pt, const Coord &p1, const Coord &p2) diff --git a/shared/src/map/layers/objects/Line2dLayerObject.cpp b/shared/src/map/layers/objects/Line2dLayerObject.cpp index e2ba031e8..89b5cad0f 100644 --- a/shared/src/map/layers/objects/Line2dLayerObject.cpp +++ b/shared/src/map/layers/objects/Line2dLayerObject.cpp @@ -10,6 +10,7 @@ #include "Line2dLayerObject.h" #include "Vec3D.h" +#include "LineHelper.h" #include Line2dLayerObject::Line2dLayerObject(const std::shared_ptr &conversionHelper, @@ -59,12 +60,10 @@ void Line2dLayerObject::setPositions(const std::vector &positions, const double lengthNormalZ = pNext.z - p.z; float lineLength = std::sqrt(lengthNormalX * lengthNormalX + lengthNormalY * lengthNormalY + lengthNormalZ * lengthNormalZ); - // SegmentType (0 inner, 1 start, 2 end, 3 single segment) | lineStyleIndex - // (each one Byte, i.e. up to 256 styles if supported by shader!) - float lineStyleInfo = 0 + (i == 0 && i == iSecondToLast ? (3 << 8) - : (i == 0 ? (float) (1 << 8) - : (i == iSecondToLast ? (float) (2 << 8) - : 0.0))); + // Pack the values into a float-compatible representation + uint8_t segmentType = (i == 0 && i == iSecondToLast) ? 3 : + (i == 0) ? 1 : + (i == iSecondToLast) ? 2 : 0; for (uint8_t vertexIndex = 4; vertexIndex > 0; --vertexIndex) { // Vertex @@ -80,14 +79,7 @@ void Line2dLayerObject::setPositions(const std::vector &positions, const lineAttributes.push_back(pNext.z); } - // Vertex Index - lineAttributes.push_back((float) (vertexIndex - 1)); - - // Segment Start Length Position (length prefix sum) - lineAttributes.push_back(prefixTotalLineLength); - - // Style Info - lineAttributes.push_back(lineStyleInfo); + lineAttributes.push_back(LineHelper::packLineStyleMetadata(vertexIndex, 0, segmentType, prefixTotalLineLength)); } // Vertex indices diff --git a/shared/src/map/layers/objects/LineGroup2dLayerObject.cpp b/shared/src/map/layers/objects/LineGroup2dLayerObject.cpp index d673b6ada..337f2a786 100644 --- a/shared/src/map/layers/objects/LineGroup2dLayerObject.cpp +++ b/shared/src/map/layers/objects/LineGroup2dLayerObject.cpp @@ -12,7 +12,7 @@ #include "RenderLineDescription.h" #include "Logger.h" #include "ShaderLineStyle.h" - +#include "LineHelper.h" #include LineGroup2dLayerObject::LineGroup2dLayerObject(const std::shared_ptr &conversionHelper, @@ -64,12 +64,10 @@ void LineGroup2dLayerObject::setLines(const std::vector 0; --vertexIndex) { // Vertex @@ -85,14 +83,7 @@ void LineGroup2dLayerObject::setLines(const std::vector