diff options
-rw-r--r-- | drape_frontend/line_shape.cpp | 177 |
1 files changed, 147 insertions, 30 deletions
diff --git a/drape_frontend/line_shape.cpp b/drape_frontend/line_shape.cpp index 0b6c8f7868..eb434dcffe 100644 --- a/drape_frontend/line_shape.cpp +++ b/drape_frontend/line_shape.cpp @@ -18,6 +18,70 @@ namespace float const CAP = 1.0f; float const LEFT_WIDTH = 1.0f; float const RIGHT_WIDTH = -1.0f; + size_t const TEX_BEG_IDX = 0; + size_t const TEX_END_IDX = 1; + + struct TexDescription + { + float m_globalLength; + glsl::vec2 m_texCoord; + }; + + class TextureCoordGenerator + { + public: + TextureCoordGenerator(float const baseGtoPScale) + : m_baseGtoPScale(baseGtoPScale) + , m_basePtoGScale(1.0f / baseGtoPScale) + { + } + + void SetRegion(dp::TextureManager::StippleRegion const & region, bool isSolid) + { + m_isSolid = isSolid; + m_region = region; + if (!m_isSolid) + { + m_maskLength = static_cast<float>(m_region.GetMaskPixelLength()); + m_patternLength = static_cast<float>(m_region.GetPatternPixelLength()); + } + } + + bool GetTexCoords(TexDescription & desc) + { + if (m_isSolid) + { + desc.m_texCoord = glsl::ToVec2(m_region.GetTexRect().Center()); + return true; + } + + float const pxLength = desc.m_globalLength * m_baseGtoPScale; + float const maskRest = m_maskLength - m_pxCursor; + + m2::RectF const & texRect = m_region.GetTexRect(); + if (maskRest < pxLength) + { + desc.m_globalLength = maskRest * m_basePtoGScale; + desc.m_texCoord = glsl::vec2(texRect.maxX(), texRect.Center().y); + return false; + } + + float texX = texRect.minX() + ((m_pxCursor + pxLength) / m_maskLength) * texRect.SizeX(); + m_pxCursor = fmodf(m_pxCursor + pxLength, m_patternLength); + + desc.m_texCoord = glsl::vec2(texX, texRect.Center().y); + return true; + } + + private: + float const m_baseGtoPScale; + float const m_basePtoGScale; + dp::TextureManager::StippleRegion m_region; + float m_maskLength = 0.0f; + float m_patternLength = 0.0f; + bool m_isSolid = true; + float m_pxCursor = 0.0f; + }; } LineShape::LineShape(m2::SharedSpline const & spline, @@ -30,6 +94,7 @@ LineShape::LineShape(m2::SharedSpline const & spline, void LineShape::Draw(dp::RefPointer<dp::Batcher> batcher, dp::RefPointer<dp::TextureManager> textures) const { + typedef gpu::LineVertex LV; buffer_vector<gpu::LineVertex, 128> geometry; vector<m2::PointD> const & path = m_spline->GetPath(); @@ -37,19 +102,24 @@ void LineShape::Draw(dp::RefPointer<dp::Batcher> batcher, dp::RefPointer<dp::Tex textures->GetColorRegion(m_params.m_color, colorRegion); glsl::vec2 colorCoord(glsl::ToVec2(colorRegion.GetTexRect().Center())); + TextureCoordGenerator texCoordGen(m_params.m_baseGtoPScale); dp::TextureManager::StippleRegion maskRegion; - textures->GetStippleRegion(dp::TextureManager::TStipplePattern{1}, maskRegion); - glsl::vec2 maskCoord(glsl::ToVec2(maskRegion.GetTexRect().Center())); + if (m_params.m_pattern.empty()) + textures->GetStippleRegion(dp::TextureManager::TStipplePattern{1}, maskRegion); + else + textures->GetStippleRegion(m_params.m_pattern, maskRegion); + texCoordGen.SetRegion(maskRegion, m_params.m_pattern.empty()); float const halfWidth = m_params.m_width / 2.0f; + float const glbHalfWidth = halfWidth / m_params.m_baseGtoPScale; bool generateCap = m_params.m_cap != dp::ButtCap; auto const calcTangentAndNormals = [&halfWidth](glsl::vec2 const & pt0, glsl::vec2 const & pt1, glsl::vec2 & tangent, glsl::vec2 & leftNormal, glsl::vec2 & rightNormal) { - tangent = pt1 - pt0; - leftNormal = halfWidth * glsl::normalize(glsl::vec2(tangent.y, -tangent.x)); + tangent = glsl::normalize(pt1 - pt0); + leftNormal = halfWidth * glsl::vec2(tangent.y, -tangent.x); rightNormal = -leftNormal; }; @@ -58,22 +128,30 @@ void LineShape::Draw(dp::RefPointer<dp::Batcher> batcher, dp::RefPointer<dp::Tex glsl::vec2 leftSegment(SEGMENT, LEFT_WIDTH); glsl::vec2 rightSegment(SEGMENT, RIGHT_WIDTH); + TexDescription texCoords[2]; + if (generateCap) { glsl::vec2 startPoint = glsl::ToVec2(path[0]); glsl::vec2 endPoint = glsl::ToVec2(path[1]); glsl::vec2 tangent, leftNormal, rightNormal; calcTangentAndNormals(startPoint, endPoint, tangent, leftNormal, rightNormal); - tangent = -halfWidth * glsl::normalize(tangent); + tangent = -halfWidth * tangent; glsl::vec3 pivot = glsl::vec3(startPoint, m_params.m_depth); glsl::vec2 leftCap(capType, LEFT_WIDTH); glsl::vec2 rightCap(capType, RIGHT_WIDTH); - geometry.push_back(gpu::LineVertex(pivot, leftNormal + tangent, colorCoord, maskCoord, leftCap)); - geometry.push_back(gpu::LineVertex(pivot, rightNormal + tangent, colorCoord, maskCoord, rightCap)); - geometry.push_back(gpu::LineVertex(pivot, leftNormal, colorCoord, maskCoord, leftSegment)); - geometry.push_back(gpu::LineVertex(pivot, rightNormal, colorCoord, maskCoord, rightSegment)); + texCoords[TEX_BEG_IDX].m_globalLength = 0.0; + texCoords[TEX_END_IDX].m_globalLength = glbHalfWidth; + + VERIFY(texCoordGen.GetTexCoords(texCoords[TEX_BEG_IDX]), ()); + VERIFY(texCoordGen.GetTexCoords(texCoords[TEX_END_IDX]), ()); + + geometry.push_back(LV(pivot, leftNormal + tangent, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, leftCap)); + geometry.push_back(LV(pivot, rightNormal + tangent, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, rightCap)); + geometry.push_back(LV(pivot, leftNormal, colorCoord, texCoords[TEX_END_IDX].m_texCoord, leftSegment)); + geometry.push_back(LV(pivot, rightNormal, colorCoord, texCoords[TEX_END_IDX].m_texCoord, rightSegment)); } glsl::vec2 prevPoint; @@ -108,26 +186,39 @@ void LineShape::Draw(dp::RefPointer<dp::Batcher> batcher, dp::RefPointer<dp::Tex if (m_params.m_join == dp::BevelJoin) { - geometry.push_back(gpu::LineVertex(startPivot, prevForming, colorCoord, maskCoord, leftSegment)); - geometry.push_back(gpu::LineVertex(startPivot, zeroNormal, colorCoord, maskCoord, leftSegment)); - geometry.push_back(gpu::LineVertex(startPivot, nextForming, colorCoord, maskCoord, leftSegment)); - geometry.push_back(gpu::LineVertex(startPivot, nextForming, colorCoord, maskCoord, leftSegment)); + texCoords[TEX_BEG_IDX].m_globalLength = 0.0f; + texCoords[TEX_END_IDX].m_globalLength = glsl::length(nextForming - prevForming) / m_params.m_baseGtoPScale; + VERIFY(texCoordGen.GetTexCoords(texCoords[TEX_BEG_IDX]), ()); + VERIFY(texCoordGen.GetTexCoords(texCoords[TEX_END_IDX]), ()); + + geometry.push_back(LV(startPivot, prevForming, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, leftSegment)); + geometry.push_back(LV(startPivot, zeroNormal, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, leftSegment)); + geometry.push_back(LV(startPivot, nextForming, colorCoord, texCoords[TEX_END_IDX].m_texCoord, leftSegment)); + geometry.push_back(LV(startPivot, nextForming, colorCoord, texCoords[TEX_END_IDX].m_texCoord, leftSegment)); } else { glsl::vec2 middleForming = glsl::normalize(prevForming + nextForming); glsl::vec2 zeroDxDy(0.0, 0.0); + texCoords[TEX_BEG_IDX].m_globalLength = 0.0f; + texCoords[TEX_END_IDX].m_globalLength = glsl::length(nextForming - prevForming) / m_params.m_baseGtoPScale; + TexDescription middle; + middle.m_globalLength = texCoords[TEX_END_IDX].m_globalLength / 2.0f; + VERIFY(texCoordGen.GetTexCoords(texCoords[TEX_BEG_IDX]), ()); + VERIFY(texCoordGen.GetTexCoords(middle), ()); + VERIFY(texCoordGen.GetTexCoords(texCoords[TEX_END_IDX]), ()); + if (m_params.m_join == dp::MiterJoin) { float const b = glsl::length(prevForming - nextForming) / 2.0; float const a = glsl::length(prevForming); middleForming *= static_cast<float>(sqrt(a * a + b * b)); - geometry.push_back(gpu::LineVertex(startPivot, prevForming, colorCoord, maskCoord, zeroDxDy)); - geometry.push_back(gpu::LineVertex(startPivot, zeroNormal, colorCoord, maskCoord, zeroDxDy)); - geometry.push_back(gpu::LineVertex(startPivot, middleForming, colorCoord, maskCoord, zeroDxDy)); - geometry.push_back(gpu::LineVertex(startPivot, nextForming, colorCoord, maskCoord, zeroDxDy)); + geometry.push_back(LV(startPivot, prevForming, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, zeroDxDy)); + geometry.push_back(LV(startPivot, zeroNormal, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, zeroDxDy)); + geometry.push_back(LV(startPivot, middleForming, colorCoord, middle.m_texCoord, zeroDxDy)); + geometry.push_back(LV(startPivot, nextForming, colorCoord, texCoords[TEX_END_IDX].m_texCoord, zeroDxDy)); } else { @@ -136,18 +227,38 @@ void LineShape::Draw(dp::RefPointer<dp::Batcher> batcher, dp::RefPointer<dp::Tex glsl::vec2 dxdyLeft(0.0, -1.0); glsl::vec2 dxdyRight(0.0, -1.0); glsl::vec2 dxdyMiddle(1.0, 1.0); - geometry.push_back(gpu::LineVertex(startPivot, zeroNormal, colorCoord, maskCoord, zeroDxDy)); - geometry.push_back(gpu::LineVertex(startPivot, prevForming, colorCoord, maskCoord, dxdyLeft)); - geometry.push_back(gpu::LineVertex(startPivot, nextForming, colorCoord, maskCoord, dxdyRight)); - geometry.push_back(gpu::LineVertex(startPivot, middleForming, colorCoord, maskCoord, dxdyMiddle)); + geometry.push_back(LV(startPivot, zeroNormal, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, zeroDxDy)); + geometry.push_back(LV(startPivot, prevForming, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, dxdyLeft)); + geometry.push_back(LV(startPivot, nextForming, colorCoord, texCoords[TEX_END_IDX].m_texCoord, dxdyRight)); + geometry.push_back(LV(startPivot, middleForming, colorCoord, middle.m_texCoord, dxdyMiddle)); } } } - geometry.push_back(gpu::LineVertex(startPivot, leftNormal, colorCoord, maskCoord, leftSegment)); - geometry.push_back(gpu::LineVertex(startPivot, rightNormal, colorCoord, maskCoord, rightSegment)); - geometry.push_back(gpu::LineVertex(endPivot, leftNormal, colorCoord, maskCoord, leftSegment)); - geometry.push_back(gpu::LineVertex(endPivot, rightNormal, colorCoord, maskCoord, rightSegment)); + texCoords[TEX_BEG_IDX].m_globalLength = 0.0; + texCoords[TEX_END_IDX].m_globalLength = glsl::length(endPoint - startPoint); + VERIFY(texCoordGen.GetTexCoords(texCoords[TEX_BEG_IDX]), ()); + while (!texCoordGen.GetTexCoords(texCoords[TEX_END_IDX])) + { + glsl::vec2 newEndPoint = startPoint + tangent * texCoords[TEX_END_IDX].m_globalLength; + glsl::vec3 newEndPivot = glsl::vec3(newEndPoint, m_params.m_depth); + + geometry.push_back(LV(startPivot, leftNormal, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, leftSegment)); + geometry.push_back(LV(startPivot, rightNormal, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, rightSegment)); + geometry.push_back(LV(newEndPivot, leftNormal, colorCoord, texCoords[TEX_END_IDX].m_texCoord, leftSegment)); + geometry.push_back(LV(newEndPivot, rightNormal, colorCoord, texCoords[TEX_END_IDX].m_texCoord, rightSegment)); + + startPoint = newEndPoint; + startPivot = newEndPivot; + + VERIFY(texCoordGen.GetTexCoords(texCoords[TEX_BEG_IDX]), ()); + texCoords[TEX_END_IDX].m_globalLength = glsl::length(endPoint - startPoint); + } + + geometry.push_back(LV(startPivot, leftNormal, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, leftSegment)); + geometry.push_back(LV(startPivot, rightNormal, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, rightSegment)); + geometry.push_back(LV(endPivot, leftNormal, colorCoord, texCoords[TEX_END_IDX].m_texCoord, leftSegment)); + geometry.push_back(LV(endPivot, rightNormal, colorCoord, texCoords[TEX_END_IDX].m_texCoord, rightSegment)); prevPoint = startPoint; prevLeftNormal = leftNormal; @@ -161,16 +272,22 @@ void LineShape::Draw(dp::RefPointer<dp::Batcher> batcher, dp::RefPointer<dp::Tex glsl::vec2 endPoint = glsl::ToVec2(path[lastPointIndex]); glsl::vec2 tangent, leftNormal, rightNormal; calcTangentAndNormals(startPoint, endPoint, tangent, leftNormal, rightNormal); - tangent = halfWidth * glsl::normalize(tangent); + tangent = halfWidth * tangent; glsl::vec3 pivot = glsl::vec3(endPoint, m_params.m_depth); glsl::vec2 leftCap(capType, LEFT_WIDTH); glsl::vec2 rightCap(capType, RIGHT_WIDTH); - geometry.push_back(gpu::LineVertex(pivot, leftNormal, colorCoord, maskCoord, leftSegment)); - geometry.push_back(gpu::LineVertex(pivot, rightNormal, colorCoord, maskCoord, rightSegment)); - geometry.push_back(gpu::LineVertex(pivot, leftNormal + tangent, colorCoord, maskCoord, leftCap)); - geometry.push_back(gpu::LineVertex(pivot, rightNormal + tangent, colorCoord, maskCoord, rightCap)); + texCoords[TEX_BEG_IDX].m_globalLength = 0.0; + texCoords[TEX_END_IDX].m_globalLength = glbHalfWidth; + + VERIFY(texCoordGen.GetTexCoords(texCoords[TEX_BEG_IDX]), ()); + VERIFY(texCoordGen.GetTexCoords(texCoords[TEX_END_IDX]), ()); + + geometry.push_back(LV(pivot, leftNormal, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, leftSegment)); + geometry.push_back(LV(pivot, rightNormal, colorCoord, texCoords[TEX_BEG_IDX].m_texCoord, rightSegment)); + geometry.push_back(LV(pivot, leftNormal + tangent, colorCoord, texCoords[TEX_END_IDX].m_texCoord, leftCap)); + geometry.push_back(LV(pivot, rightNormal + tangent, colorCoord, texCoords[TEX_END_IDX].m_texCoord, rightCap)); } dp::GLState state(gpu::LINE_PROGRAM, dp::GLState::GeometryLayer); |