path_renderer: butt caps, square caps, bevel linejoins

This commit is contained in:
Darafei Praliaskouski 2013-01-11 18:36:55 +03:00 committed by Alex Zolotarev
parent 3bdcacf169
commit 12852f1d21
3 changed files with 145 additions and 53 deletions

View file

@ -87,12 +87,15 @@ namespace
double width = 2,
double depth = 0,
double pathOffset = 0,
double penOffset = 0)
double penOffset = 0,
graphics::Pen::Info::ELineCap lineCap = graphics::Pen::Info::ERoundCap,
graphics::Pen::Info::ELineJoin lineJoin = graphics::Pen::Info::ERoundJoin
)
{
m_pathes.push_back(points);
m_pathOffsets.push_back(pathOffset);
//m_patterns.push_back(pattern);
m_penInfos.push_back(graphics::Pen::Info(color, width, pattern.empty() ? 0 : &pattern[0], pattern.size(), penOffset));
m_penInfos.push_back(graphics::Pen::Info(color, width, pattern.empty() ? 0 : &pattern[0], pattern.size(), penOffset, 0, 0, lineJoin, lineCap));
m_depthes.push_back(depth);
}
@ -539,29 +542,78 @@ namespace
void Init()
{
base_t::Init();
m_drawAxis = true;
std::vector<m2::PointD> testPoints;
std::vector<double> testPattern;
double dx = 0, dy = 0, width = 30;
for (int i = 0; i < 2; ++i)
{
// testPoints.push_back(m2::PointD(120, 200));
// testPoints.push_back(m2::PointD(180, 140));
testPoints.push_back(m2::PointD(220, 269));
testPoints.push_back(m2::PointD(320, 270));
testPoints.clear();
testPoints.push_back(m2::PointD(dx + 20, dy + 100));
testPoints.push_back(m2::PointD(dx + 80, dy + 40));
testPoints.push_back(m2::PointD(dx + 120, dy + 169));
testPoints.push_back(m2::PointD(dx + 220, dy + 170));
AddTest(testPoints, testPattern, graphics::Color(0, 255, 0, 255), width, 0, 0, 0, graphics::Pen::Info::EButtCap, graphics::Pen::Info::ERoundJoin);
AddTest(testPoints, testPattern, graphics::Color(255, 0, 0, 255), 40);
testPattern.push_back(20);
testPattern.push_back(20);
testPattern.push_back(20);
testPattern.push_back(20);
dy += 130;
testPoints.clear();
testPoints.push_back(m2::PointD(420, 300));
testPoints.push_back(m2::PointD(480, 240));
testPoints.push_back(m2::PointD(520, 369));
testPoints.push_back(m2::PointD(620, 370));
testPoints.clear();
testPoints.push_back(m2::PointD(dx + 20, dy + 100));
testPoints.push_back(m2::PointD(dx + 80, dy + 40));
testPoints.push_back(m2::PointD(dx + 120, dy + 169));
testPoints.push_back(m2::PointD(dx + 220, dy + 170));
AddTest(testPoints, testPattern, graphics::Color(0, 255, 0, 255), width, 0, 0, 0, graphics::Pen::Info::ESquareCap, graphics::Pen::Info::ERoundJoin);
AddTest(testPoints, testPattern, graphics::Color(0, 255, 0, 255), 40);
dy += 130;
testPoints.clear();
testPoints.push_back(m2::PointD(dx + 20, dy + 100));
testPoints.push_back(m2::PointD(dx + 80, dy + 40));
testPoints.push_back(m2::PointD(dx + 120, dy + 169));
testPoints.push_back(m2::PointD(dx + 220, dy + 170));
AddTest(testPoints, testPattern, graphics::Color(0, 255, 0, 255), width, 0, 0, 0, graphics::Pen::Info::ERoundCap, graphics::Pen::Info::ERoundJoin);
dy = 0;
dx += 200;
testPoints.clear();
testPoints.push_back(m2::PointD(dx + 20, dy + 100));
testPoints.push_back(m2::PointD(dx + 80, dy + 40));
testPoints.push_back(m2::PointD(dx + 120, dy + 169));
testPoints.push_back(m2::PointD(dx + 220, dy + 170));
AddTest(testPoints, testPattern, graphics::Color(0, 255, 0, 255), width, 0, 0, 0, graphics::Pen::Info::EButtCap, graphics::Pen::Info::EBevelJoin);
dy += 130;
testPoints.clear();
testPoints.push_back(m2::PointD(dx + 20, dy + 100));
testPoints.push_back(m2::PointD(dx + 80, dy + 40));
testPoints.push_back(m2::PointD(dx + 120, dy + 169));
testPoints.push_back(m2::PointD(dx + 220, dy + 170));
AddTest(testPoints, testPattern, graphics::Color(0, 255, 0, 255), width, 0, 0, 0, graphics::Pen::Info::ESquareCap, graphics::Pen::Info::EBevelJoin);
dy += 130;
testPoints.clear();
testPoints.push_back(m2::PointD(dx + 20, dy + 100));
testPoints.push_back(m2::PointD(dx + 80, dy + 40));
testPoints.push_back(m2::PointD(dx + 120, dy + 169));
testPoints.push_back(m2::PointD(dx + 220, dy + 170));
AddTest(testPoints, testPattern, graphics::Color(0, 255, 0, 255), width, 0, 0, 0, graphics::Pen::Info::ERoundCap, graphics::Pen::Info::EBevelJoin);
testPattern.push_back(20);
testPattern.push_back(20);
testPattern.push_back(20);
testPattern.push_back(20);
dx += 200;
dy = 0;
}
}
};
@ -1410,9 +1462,9 @@ namespace
UNIT_TEST_GL(TestDrawPathWithOffset);
UNIT_TEST_GL(TestDrawPathJoin);
UNIT_TEST_GL(TestDrawPathSolid1PX);
UNIT_TEST_GL(TestDrawPathSolid2PX);
UNIT_TEST_GL(TestDrawPathSolid2PX);*/
UNIT_TEST_GL(TestDrawPathSolid);
UNIT_TEST_GL(TestDrawOverlappedSymbolWithText);
/*UNIT_TEST_GL(TestDrawOverlappedSymbolWithText);
UNIT_TEST_GL(TestDrawAnyRect);
UNIT_TEST_GL(TestDrawSector);
UNIT_TEST_GL(TestDrawPathSolidDiffWidth);
@ -1422,6 +1474,6 @@ namespace
UNIT_TEST_GL(TestDrawUtilsRect);
UNIT_TEST_GL(TestDrawUtilsRectFilledTexture);
UNIT_TEST_GL(TestDrawSymbolFiltering);
UNIT_TEST_GL(TestDrawCircle);*/
UNIT_TEST_GL(TestDrawImage);
UNIT_TEST_GL(TestDrawCircle);
UNIT_TEST_GL(TestDrawImage);*/
}

View file

@ -140,11 +140,10 @@ namespace graphics
m2::PointF coords[4] =
{
// vng: i think this "rawTileStartPt + fNorm" reading better, isn't it?
m2::PointF(rawTileStartPt.x + fNorm.x, rawTileStartPt.y + fNorm.y),
m2::PointF(rawTileStartPt.x - fNorm.x, rawTileStartPt.y - fNorm.y),
m2::PointF(rawTileEndPt.x - fNorm.x, rawTileEndPt.y - fNorm.y),
m2::PointF(rawTileEndPt.x + fNorm.x, rawTileEndPt.y + fNorm.y)
rawTileStartPt + fNorm,
rawTileStartPt - fNorm,
rawTileEndPt - fNorm,
rawTileEndPt + fNorm
};
m2::PointF texCoords[4] =
@ -255,10 +254,17 @@ namespace graphics
}
}
void PathRenderer::drawSolidPath(m2::PointD const * points, size_t pointsCount, double offset, Pen const * pen, double depth)
{
ASSERT(pen->m_isSolid, ());
bool const hasRoundCap = (pen->m_info.m_cap == pen->m_info.ERoundCap);
bool const hasSquareCap = (pen->m_info.m_cap == pen->m_info.ESquareCap);
bool const hasRoundJoin = (pen->m_info.m_join == pen->m_info.ERoundJoin);
bool const hasBevelJoin = (pen->m_info.m_join == pen->m_info.EBevelJoin);
for (size_t i = 0; i < pointsCount - 1; ++i)
{
m2::PointD dir = points[i + 1] - points[i];
@ -281,27 +287,46 @@ namespace graphics
m2::PointF const fDir(fNorm.y, -fNorm.x);
int numPoints = 4;
bool const hasLeftRoundCap = (pen->m_info.m_cap == pen->m_info.ERoundCap) || (i != 0);
bool const hasRightRoundCap = (pen->m_info.m_cap == pen->m_info.ERoundCap) || (i != (pointsCount - 2));
if (hasLeftRoundCap) {numPoints += 2;};
if (hasRightRoundCap) {numPoints += 2;};
int j = 0;
bool const leftIsCap = i == 0;
bool const rightIsCap = i == (pointsCount - 2);
if (leftIsCap && (hasRoundCap || hasSquareCap))
numPoints += 2;
if ((rightIsCap && (hasRoundCap || hasSquareCap)) || (!rightIsCap && (hasRoundJoin || hasBevelJoin)))
numPoints += 2;
int cur = 0;
m2::PointF coords[numPoints];
if (hasLeftRoundCap)
if (leftIsCap && (hasRoundCap || hasSquareCap))
{
coords[j] = points[i] - fDir + fNorm; j++;
coords[j] = points[i] - fDir - fNorm; j++;
coords[cur++] = points[i] - fDir + fNorm;
coords[cur++] = points[i] - fDir - fNorm;
}
coords[j] = points[i] + fNorm; j++;
coords[j] = points[i] - fNorm; j++;
coords[j] = nextPt + fNorm; j++;
coords[j] = nextPt - fNorm; j++;
if (hasRightRoundCap)
coords[cur++] = points[i] + fNorm;
coords[cur++] = points[i] - fNorm;
coords[cur++] = nextPt + fNorm;
coords[cur++] = nextPt - fNorm;
if ((rightIsCap && (hasRoundCap || hasSquareCap)) || (!rightIsCap && hasRoundJoin))
{
coords[j] = nextPt + fDir + fNorm; j++;
coords[j] = nextPt + fDir - fNorm; j++;
coords[cur++] = nextPt + fDir + fNorm;
coords[cur++] = nextPt + fDir - fNorm;
}
else if (!rightIsCap && hasBevelJoin)
{
m2::PointD dirNextSeg = points[i + 2] - points[i + 1];
double lenNextSeg = dirNextSeg.Length(m2::PointD(0, 0));
dirNextSeg *= 1.0 / lenNextSeg;
m2::PointD normNextSeg(-dirNextSeg.y, dirNextSeg.x);
m2::PointF const fNormNextSeg = normNextSeg * geomHalfWidth;
coords[cur++] = points[i + 1] + fNormNextSeg;
coords[cur++] = points[i + 1] - fNormNextSeg;
}
GeometryPipeline & p = pipeline(pen->m_pipelineID);
@ -314,22 +339,36 @@ namespace graphics
return;
}
j = 0;
m2::PointF texCoords[numPoints];
if (hasLeftRoundCap)
cur = 0;
if ((leftIsCap && hasRoundCap))// || (!leftIsCap && hasRoundJoin))
{
texCoords[j] = texture->mapPixel(m2::PointF(texMinX, texMinY)); j++;
texCoords[j] = texture->mapPixel(m2::PointF(texMinX, texMaxY)); j++;
texCoords[cur++] = texture->mapPixel(m2::PointF(texMinX, texMinY));
texCoords[cur++] = texture->mapPixel(m2::PointF(texMinX, texMaxY));
}
texCoords[j] = texture->mapPixel(m2::PointF(texCenterX, texMinY)); j++;
texCoords[j] = texture->mapPixel(m2::PointF(texCenterX, texMaxY)); j++;
texCoords[j] = texture->mapPixel(m2::PointF(texCenterX, texMinY)); j++;
texCoords[j] = texture->mapPixel(m2::PointF(texCenterX, texMaxY)); j++;
if (hasRightRoundCap)
else if (leftIsCap && hasSquareCap)
{
texCoords[j] = texture->mapPixel(m2::PointF(texMaxX, texMinY)); j++;
texCoords[j] = texture->mapPixel(m2::PointF(texMaxX, texMaxY)); j++;
texCoords[cur++] = texture->mapPixel(m2::PointF(texCenterX, texMinY));
texCoords[cur++] = texture->mapPixel(m2::PointF(texCenterX, texMaxY));
}
texCoords[cur++] = texture->mapPixel(m2::PointF(texCenterX, texMinY));
texCoords[cur++] = texture->mapPixel(m2::PointF(texCenterX, texMaxY));
texCoords[cur++] = texture->mapPixel(m2::PointF(texCenterX, texMinY));
texCoords[cur++] = texture->mapPixel(m2::PointF(texCenterX, texMaxY));
if ((rightIsCap && hasRoundCap) || (!rightIsCap && hasRoundJoin))
{
texCoords[cur++] = texture->mapPixel(m2::PointF(texMaxX, texMinY));
texCoords[cur++] = texture->mapPixel(m2::PointF(texMaxX, texMaxY));
}
else if ((rightIsCap && hasSquareCap) || (!rightIsCap && hasBevelJoin))
{
texCoords[cur++] = texture->mapPixel(m2::PointF(texCenterX, texMinY));
texCoords[cur++] = texture->mapPixel(m2::PointF(texCenterX, texMaxY));
}
m2::PointF normal(0, 0);
addTexturedStripStrided(coords, sizeof(m2::PointF),

View file

@ -24,7 +24,8 @@ namespace graphics
enum ELineCap
{
ERoundCap,
EButtCap
EButtCap,
ESquareCap
};
typedef buffer_vector<double, 16> TPattern;