[drape] texture coord generation for stipple lines

This commit is contained in:
ExMix 2015-01-13 15:23:46 +03:00 committed by Alex Zolotarev
parent 5f09ba278b
commit d81394156a

View file

@ -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);