refactored text-on-string layout code.

This commit is contained in:
rachytski 2011-05-07 00:55:13 +03:00 committed by Alex Zolotarev
parent c11e497fc6
commit 0e8efdd557
3 changed files with 161 additions and 41 deletions

View file

@ -8,6 +8,25 @@
namespace yg
{
struct PathPoint
{
int m_i;
m2::PointD m_pt;
PathPoint(int i = -1,
m2::PointD const & pt = m2::PointD())
: m_i(i),
m_pt(pt)
{}
};
struct PivotPoint
{
double m_angle;
PathPoint m_pp;
PivotPoint(double angle = 0, PathPoint const & pp = PathPoint())
{}
};
class pts_array
{
m2::PointD const * m_arr;
@ -50,7 +69,77 @@ namespace yg
ASSERT ( i < m_size, ("Index out of range") );
return m_arr[m_reverse ? m_size - i - 1 : i];
}
m2::PointD operator[](size_t i) const { return get(i); }
PathPoint const offsetPoint(PathPoint const & pp, double offset)
{
PathPoint res = pp;
if (res.m_i == -1)
return res;
for (size_t i = res.m_i; i < size() - 1; ++i)
{
double l = res.m_pt.Length(get(i + 1));
if (offset < l)
{
res.m_pt = res.m_pt.Move(offset, ang::AngleTo(get(i), get(i + 1)));
res.m_i = i;
break;
}
else
{
offset -= l;
res.m_pt = get(i + 1);
}
}
return res;
}
PivotPoint findPivotPoint(PathPoint const & pp, GlyphMetrics const & sym)
{
PivotPoint res;
res.m_pp.m_i = -1;
m2::PointD pt1 = pp.m_pt;
double angle = 0;
double advance = sym.m_xOffset + sym.m_width / 2.0;
int j = pp.m_i;
while (advance > 0)
{
if (j + 1 == size())
return res;
double l = get(j + 1).Length(pt1);
angle += ang::AngleTo(get(j), get(j + 1));
if (l < advance)
{
advance -= l;
pt1 = get(j + 1);
++j;
}
else
{
res.m_pp.m_i = j;
res.m_pp.m_pt = pt1.Move(advance, ang::AngleTo(get(j), get(j + 1)));
advance = 0;
angle /= (res.m_pp.m_i - pp.m_i + 1);
res.m_pp.m_pt = pt1;
res.m_angle = angle;
break;
}
}
return res;
}
};
GlyphLayout::GlyphLayout(shared_ptr<ResourceManager> const & resourceManager,
@ -92,50 +181,33 @@ namespace yg
while (offset < 0 && symPos < count)
offset += m_entries[symPos++].m_metrics.m_xAdvance;
m_firstVisible = symPos;
m_lastVisible = count;
PathPoint startPt = arrPath.offsetPoint(PathPoint(0, arrPath.get(0)), offset);
size_t ptPos = 0;
bool doInitAngle = true;
m_firstVisible = symPos;
for (; symPos < count; ++symPos)
{
if (symPos > 0)
{
m_entries[symPos].m_pt = m_entries[symPos - 1].m_pt;
m_entries[symPos].m_angle = m_entries[symPos - 1].m_angle;
}
else
{
m_entries[symPos].m_pt = arrPath[0];
m_entries[symPos].m_angle = 0; //< will be initialized later
}
GlyphMetrics const & metrics = m_entries[symPos].m_metrics;
size_t const oldPtPos = ptPos;
if (startPt.m_i == -1)
return;
while (true)
if (metrics.m_width != 0)
{
if (ptPos + 1 == arrPath.size())
{
m_firstVisible = m_lastVisible = 0;
PivotPoint pivotPt = arrPath.findPivotPoint(startPt, metrics);
if (pivotPt.m_pp.m_i == -1)
return;
}
double const l = arrPath[ptPos + 1].Length(m_entries[symPos].m_pt);
if (offset < l)
break;
offset -= l;
m_entries[symPos].m_pt = arrPath[++ptPos];
m_entries[symPos].m_angle = pivotPt.m_angle;
double centerOffset = metrics.m_xOffset + metrics.m_width / 2.0;
//m_entries[symPos].m_pt = pivotPt.m_pp.m_pt.Move(-centerOffset, pivotPt.m_angle);
m_entries[symPos].m_pt = startPt.m_pt;
}
if ((oldPtPos != ptPos) || (doInitAngle))
{
m_entries[symPos].m_angle = ang::AngleTo(m_entries[symPos].m_pt, arrPath[ptPos + 1]);
doInitAngle = false;
}
startPt = arrPath.offsetPoint(startPt, metrics.m_xAdvance);
m_entries[symPos].m_pt = m_entries[symPos].m_pt.Move(offset, m_entries[symPos].m_angle);
offset = m_entries[symPos].m_metrics.m_xAdvance;
m_lastVisible = symPos + 1;
}
}

View file

@ -367,6 +367,9 @@ namespace yg
vector<GlyphLayoutElem> const & glyphs = layout.entries();
if (layout.lastVisible() != text.size())
return false;
for (size_t i = layout.firstVisible(); i < layout.lastVisible(); ++i)
{
uint32_t const glyphID = skin()->mapGlyph(GlyphKey(text[i], fontDesc.m_size, fontDesc.m_isMasked, fontDesc.m_isMasked ? fontDesc.m_maskColor : fontDesc.m_color), fontDesc.m_isStatic);

View file

@ -729,6 +729,33 @@ namespace
return ret;
}
struct TestDrawTextOnPathBigSymbols
{
vector<m2::PointD> m_path;
string m_text;
yg::PenInfo m_penInfo;
void Init()
{
m_path.push_back(m2::PointD(40, 200));
m_path.push_back(m2::PointD(90, 200));
m_path.push_back(m2::PointD(190, 230));
m_text = "Sim";
double pat[2] = {2, 2};
m_penInfo = yg::PenInfo(yg::Color(0xFF, 0xFF, 0xFF, 0xFF), 2, &pat[0], ARRAY_SIZE(pat), 0);
}
void DoDraw(shared_ptr<yg::gl::Screen> p)
{
p->drawPath(&m_path[0], m_path.size(), 0, p->skin()->mapPenInfo(m_penInfo), 1);
yg::FontDesc fontDesc(false, 40);
p->drawPathText(fontDesc, &m_path[0], m_path.size(), m_text, calc_length(m_path), 0.0, yg::EPosCenter, 0);
}
};
struct TestDrawTextOnPath
{
std::vector<m2::PointD> m_path;
@ -739,7 +766,7 @@ namespace
{
m_path.push_back(m2::PointD(40, 200));
m_path.push_back(m2::PointD(100, 100));
m_path.push_back(m2::PointD(300, 100));
m_path.push_back(m2::PointD(600, 100));
m_path.push_back(m2::PointD(400, 300));
m_text = "Simplicity is the ultimate sophistication. Leonardo Da Vinci.";
@ -750,7 +777,7 @@ namespace
void DoDraw(shared_ptr<yg::gl::Screen> p)
{
p->drawPath(&m_path[0], m_path.size(), 0, p->skin()->mapPenInfo(m_penInfo), 0);
yg::FontDesc fontDesc(false, 10);
yg::FontDesc fontDesc(false, 20);
p->drawPathText(fontDesc, &m_path[0], m_path.size(), m_text, calc_length(m_path), 0.0, yg::EPosCenter, 0);
}
};
@ -789,15 +816,32 @@ namespace
struct TestDrawTextOnPathWithOffset : TestDrawTextOnPath
{
vector<m2::PointD> m_pathUnder;
vector<m2::PointD> m_pathAbove;
TestDrawTextOnPathWithOffset()
{
copy(m_path.begin(), m_path.end(), back_inserter(m_pathUnder));
for (size_t i = 0; i < m_pathUnder.size(); ++i)
m_pathUnder[i].y -= 50;
std::copy(m_path.begin(), m_path.end(), back_inserter(m_pathAbove));
for (size_t i = 0; i < m_pathUnder.size(); ++i)
m_pathAbove[i].y += 50;
}
void DoDraw(shared_ptr<yg::gl::Screen> p)
{
p->drawPath(&m_path[0], m_path.size(), 0, p->skin()->mapPenInfo(m_penInfo), 0);
TestDrawTextOnPath::DoDraw(p);
p->drawPath(&m_pathAbove[0], m_pathAbove.size(), 0, p->skin()->mapPenInfo(m_penInfo), 0);
p->drawPath(&m_pathUnder[0], m_pathUnder.size(), 0, p->skin()->mapPenInfo(m_penInfo), 0);
double const len = calc_length(m_path);
yg::FontDesc fontDesc(false, 10);
yg::FontDesc fontDesc(false, 20);
p->drawPathText(fontDesc, &m_path[0], m_path.size(), m_text, len, 0.0, yg::EPosAbove, 0);
p->drawPathText(fontDesc, &m_path[0], m_path.size(), m_text, len, 0.0, yg::EPosUnder, 0);
p->drawPathText(fontDesc, &m_pathAbove[0], m_pathAbove.size(), m_text, len, 0.0, yg::EPosAbove, 0);
p->drawPathText(fontDesc, &m_pathUnder[0], m_pathUnder.size(), m_text, len, 0.0, yg::EPosUnder, 0);
}
};
@ -1072,9 +1116,10 @@ namespace
// UNIT_TEST_GL(TestDrawUnicodeSymbols);
// UNIT_TEST_GL(TestDrawTextRectWithFixedFont);
// UNIT_TEST_GL(TestDrawStringOnString);
// UNIT_TEST_GL(TestDrawTextOnPath);
UNIT_TEST_GL(TestDrawTextOnPathZigZag);
// UNIT_TEST_GL(TestDrawTextOnPathWithOffset);
// UNIT_TEST_GL(TestDrawTextOnPathBigSymbols);
UNIT_TEST_GL(TestDrawTextOnPath);
UNIT_TEST_GL(TestDrawTextOnPathZigZag);
UNIT_TEST_GL(TestDrawTextOnPathWithOffset);
// UNIT_TEST_GL(TestDrawTextOverflow);
// UNIT_TEST_GL(TestDrawTextFiltering);
// UNIT_TEST_GL(TestDrawRandomTextFiltering);