forked from organicmaps/organicmaps
added support for text colors. refactored text_renderer.
This commit is contained in:
parent
ae2358e9cf
commit
a0d22c5a8f
16 changed files with 638 additions and 562 deletions
|
@ -572,6 +572,7 @@ namespace drule {
|
|||
virtual void Write(FileWriterStream & ar) const { write_rules(ar, this); }
|
||||
|
||||
virtual double GetTextHeight() const { return m_params.get<5>().m_v; }
|
||||
virtual int GetColor() const { return m_params.get<6>().m_v; }
|
||||
|
||||
static string arrKeys[9];
|
||||
};
|
||||
|
@ -637,6 +638,7 @@ namespace drule {
|
|||
virtual void Write(FileWriterStream & ar) const { write_rules(ar, this); }
|
||||
|
||||
virtual double GetTextHeight() const { return m_params.get<6>().m_v; }
|
||||
virtual int GetColor() const {return m_params.get<7>().m_v;}
|
||||
|
||||
static string arrKeys[10];
|
||||
};
|
||||
|
|
|
@ -149,7 +149,7 @@ void DrawerYG::drawArea(vector<m2::PointD> const & pts, rule_ptr_t pRule, int de
|
|||
|
||||
namespace
|
||||
{
|
||||
double const min_text_height = 7.99; // 8
|
||||
double const min_text_height = 12; // 8
|
||||
// double const min_text_height_mask = 9.99; // 10
|
||||
}
|
||||
|
||||
|
@ -167,16 +167,39 @@ uint8_t DrawerYG::get_pathtext_font_size(rule_ptr_t pRule) const
|
|||
|
||||
void DrawerYG::drawText(m2::PointD const & pt, string const & name, rule_ptr_t pRule, int depth)
|
||||
{
|
||||
m_pScreen->drawText(pt, 0.0, get_text_font_size(pRule), name, depth);
|
||||
yg::Color textColor(pRule->GetColor() == -1 ? yg::Color(0, 0, 0, 0) : yg::Color::fromXRGB(pRule->GetColor(), pRule->GetAlpha()));
|
||||
if (textColor == yg::Color(255, 255, 255, 255))
|
||||
textColor = yg::Color(0, 0, 0, 0);
|
||||
|
||||
m_pScreen->drawText(
|
||||
pt,
|
||||
0.0,
|
||||
get_text_font_size(pRule),
|
||||
textColor,
|
||||
name,
|
||||
true, //pRule->GetOutlineColor() != -1,
|
||||
yg::Color(255, 255, 255, 255), //yg::Color::fromXRGB(pRule->GetOutlineColor(), pRule->GetAlpha()),
|
||||
depth,
|
||||
false,
|
||||
true);
|
||||
}
|
||||
|
||||
bool DrawerYG::drawPathText(di::PathInfo const & info, string const & name, uint8_t fontSize, int /*depth*/)
|
||||
{
|
||||
// bool const isMasked = (double(fontSize) / m_visualScale >= min_text_height);
|
||||
|
||||
return m_pScreen->drawPathText( &info.m_path[0], info.m_path.size(), fontSize, name,
|
||||
info.GetLength(), info.GetOffset(),
|
||||
yg::gl::Screen::middle_line, true, yg::maxDepth);
|
||||
return m_pScreen->drawPathText( &info.m_path[0],
|
||||
info.m_path.size(),
|
||||
fontSize,
|
||||
yg::Color(0, 0, 0, 0),
|
||||
name,
|
||||
info.GetLength(),
|
||||
info.GetOffset(),
|
||||
yg::gl::Screen::middle_line,
|
||||
true,
|
||||
yg::Color(255, 255, 255, 255),
|
||||
yg::maxDepth,
|
||||
false);
|
||||
}
|
||||
|
||||
shared_ptr<yg::gl::Screen> DrawerYG::screen() const
|
||||
|
|
|
@ -249,7 +249,10 @@ void InformationDisplay::drawRuler(DrawerYG * pDrawer)
|
|||
pDrawer->screen()->drawText(scalerPts[1] + m2::PointD(7, -7),
|
||||
0,
|
||||
10,
|
||||
yg::Color(0, 0, 0, 0),
|
||||
scalerText.c_str(),
|
||||
true,
|
||||
yg::Color(255, 255, 255, 255),
|
||||
yg::maxDepth,
|
||||
true,
|
||||
false);
|
||||
|
@ -289,7 +292,10 @@ void InformationDisplay::drawCenter(DrawerYG * drawer)
|
|||
drawer->screen()->drawText(
|
||||
m2::PointD(m_displayRect.minX(), m_displayRect.minY()) + m2::PointD(10, m_isDebugInfoEnabled ? 40 : 20),
|
||||
0, 10,
|
||||
yg::Color(0, 0, 0, 0),
|
||||
out.str().c_str(),
|
||||
true,
|
||||
yg::Color(255, 255, 255, 255),
|
||||
yg::maxDepth,
|
||||
true,
|
||||
false);
|
||||
|
@ -317,7 +323,10 @@ void InformationDisplay::drawDebugInfo(DrawerYG * drawer)
|
|||
|
||||
drawer->screen()->drawText(m2::PointD(m_displayRect.minX(), m_displayRect.minY()) + m2::PointD(10, 20),
|
||||
0, 10,
|
||||
yg::Color(0, 0, 0, 0),
|
||||
out.str().c_str(),
|
||||
true,
|
||||
yg::Color(255, 255, 255, 255),
|
||||
yg::maxDepth,
|
||||
true,
|
||||
false);
|
||||
|
@ -347,7 +356,10 @@ void InformationDisplay::drawMemoryWarning(DrawerYG * drawer)
|
|||
|
||||
drawer->screen()->drawText(pos,
|
||||
0, 10,
|
||||
yg::Color(0, 0, 0, 0),
|
||||
out.str().c_str(),
|
||||
true,
|
||||
yg::Color(255, 255, 255, 255),
|
||||
yg::maxDepth,
|
||||
true,
|
||||
false);
|
||||
|
|
|
@ -218,7 +218,6 @@ void RenderQueueRoutine::Do()
|
|||
|
||||
params.m_resourceManager = m_resourceManager;
|
||||
params.m_isMultiSampled = m_isMultiSampled;
|
||||
params.m_useTextLayer = true;
|
||||
params.m_frameBuffer = m_frameBuffer;
|
||||
params.m_renderState = m_renderState;
|
||||
params.m_doPeriodicalUpdate = m_doPeriodicalUpdate;
|
||||
|
|
|
@ -62,4 +62,9 @@ namespace yg
|
|||
{
|
||||
return (l.r != r.r) || (l.g != r.g) || (l.b != r.b) || (l.a != r.a);
|
||||
}
|
||||
|
||||
bool operator == (Color const & l, Color const & r)
|
||||
{
|
||||
return !(l != r);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ namespace yg
|
|||
|
||||
bool operator < (Color const & l, Color const & r);
|
||||
bool operator !=(Color const & l, Color const & r);
|
||||
bool operator ==(Color const & l, Color const & r);
|
||||
|
||||
inline int redFromARGB(uint32_t c) {return (c >> 16) & 0xFF;};
|
||||
inline int greenFromARGB(uint32_t c) {return (c >> 8) & 0xFF;};
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
#include "../coding/strutil.hpp"
|
||||
|
||||
#include "../geometry/angles.hpp"
|
||||
#include "../geometry/rect2d.hpp"
|
||||
|
||||
#include "../base/assert.hpp"
|
||||
|
@ -23,8 +22,6 @@
|
|||
#include "../std/algorithm.hpp"
|
||||
#include "../std/bind.hpp"
|
||||
|
||||
#include "../3party/fribidi/lib/fribidi-deprecated.h"
|
||||
|
||||
#include "../base/start_mem_debug.hpp"
|
||||
|
||||
namespace yg
|
||||
|
@ -133,15 +130,6 @@ namespace yg
|
|||
base_t::endFrame();
|
||||
}
|
||||
|
||||
wstring GeometryBatcher::Log2Vis(wstring const & str)
|
||||
{
|
||||
size_t const count = str.size();
|
||||
wstring res;
|
||||
res.resize(count);
|
||||
FriBidiParType dir = FRIBIDI_PAR_LTR; // requested base direction
|
||||
fribidi_log2vis(str.c_str(), count, &dir, &res[0], 0, 0, 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
bool GeometryBatcher::hasRoom(size_t verticesCount, size_t indicesCount, int pageID) const
|
||||
{
|
||||
|
@ -251,155 +239,6 @@ namespace yg
|
|||
style->m_pageID);
|
||||
}
|
||||
|
||||
void GeometryBatcher::drawPath(m2::PointD const * points, size_t pointsCount, uint32_t styleID, double depth)
|
||||
{
|
||||
#ifdef PROFILER_YG
|
||||
prof::block<prof::yg_draw_path> draw_path_block;
|
||||
#endif
|
||||
|
||||
//#ifdef DEBUG_DRAW_PATH
|
||||
// LineStyle const * lineStyle = reinterpret_cast<LineStyle const*>(styleID);
|
||||
//#else
|
||||
|
||||
ASSERT_GREATER_OR_EQUAL(pointsCount, 2, ());
|
||||
ResourceStyle const * style(m_skin->fromID(styleID));
|
||||
|
||||
ASSERT(style->m_cat == ResourceStyle::ELineStyle, ());
|
||||
LineStyle const * lineStyle = static_cast<LineStyle const *>(style);
|
||||
//#endif
|
||||
|
||||
float rawTileStartLen = 0;
|
||||
|
||||
for (size_t i = 0; i < pointsCount - 1; ++i)
|
||||
{
|
||||
m2::PointD dir = points[i + 1] - points[i];
|
||||
dir *= 1.0 / dir.Length(m2::PointD(0, 0));
|
||||
m2::PointD norm(-dir.y, dir.x);
|
||||
|
||||
/// The length of the current segment.
|
||||
float segLen = points[i + 1].Length(points[i]);
|
||||
/// The remaining length of the segment
|
||||
float segLenRemain = segLen;
|
||||
|
||||
/// Geometry width. It's 1px wider than the pattern width.
|
||||
int geomWidth = lineStyle->m_isSolid ? lineStyle->m_penInfo.m_w : lineStyle->m_penInfo.m_w + 4 - 2 * m_aaShift;
|
||||
float geomHalfWidth = geomWidth / 2.0;
|
||||
|
||||
/// Starting point of the tiles on this segment
|
||||
m2::PointF rawTileStartPt = points[i];
|
||||
|
||||
/// Tiling procedes as following :
|
||||
/// The leftmost tile goes antialiased at left and non-antialiased at right.
|
||||
/// The inner tiles goes non-antialiased at both sides.
|
||||
/// The rightmost tile goes non-antialised at left and antialiased at right side.
|
||||
|
||||
/// Length of the actual pattern data being tiling(without antialiasing zones).
|
||||
float rawTileLen = 0;
|
||||
while (segLenRemain > 0)
|
||||
{
|
||||
rawTileLen = (lineStyle->m_isWrapped || lineStyle->m_isSolid)
|
||||
? segLen
|
||||
: std::min(((float)lineStyle->rawTileLen() - rawTileStartLen), segLenRemain);
|
||||
|
||||
float texMaxY = lineStyle->m_isSolid ? lineStyle->m_texRect.minY() + 1 : lineStyle->m_texRect.maxY() - m_aaShift;
|
||||
float texMinY = lineStyle->m_isSolid ? lineStyle->m_texRect.minY() + 1 : lineStyle->m_texRect.minY() + m_aaShift;
|
||||
|
||||
float texMinX = lineStyle->m_isSolid ? lineStyle->m_texRect.minX() + 1 : lineStyle->m_isWrapped ? 0 : lineStyle->m_texRect.minX() + 2 + rawTileStartLen;
|
||||
float texMaxX = lineStyle->m_isSolid ? lineStyle->m_texRect.minX() + 1 : texMinX + rawTileLen;
|
||||
|
||||
rawTileStartLen += rawTileLen;
|
||||
if (rawTileStartLen >= lineStyle->rawTileLen())
|
||||
rawTileStartLen -= lineStyle->rawTileLen();
|
||||
ASSERT(rawTileStartLen < lineStyle->rawTileLen(), ());
|
||||
|
||||
m2::PointF rawTileEndPt(rawTileStartPt.x + dir.x * rawTileLen, rawTileStartPt.y + dir.y * rawTileLen);
|
||||
|
||||
m2::PointF const fNorm = norm * geomHalfWidth; // enough to calc it once
|
||||
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)
|
||||
};
|
||||
|
||||
shared_ptr<BaseTexture> texture = m_skin->pages()[lineStyle->m_pageID]->texture();
|
||||
|
||||
m2::PointF texCoords[4] =
|
||||
{
|
||||
texture->mapPixel(m2::PointF(texMinX, texMinY)),
|
||||
texture->mapPixel(m2::PointF(texMinX, texMaxY)),
|
||||
texture->mapPixel(m2::PointF(texMaxX, texMaxY)),
|
||||
texture->mapPixel(m2::PointF(texMaxX, texMinY))
|
||||
};
|
||||
|
||||
addTexturedFan(coords, texCoords, 4, depth, lineStyle->m_pageID);
|
||||
|
||||
segLenRemain -= rawTileLen;
|
||||
|
||||
rawTileStartPt = rawTileEndPt;
|
||||
}
|
||||
|
||||
bool isColorJoin = lineStyle->m_isSolid ? true : lineStyle->m_penInfo.atDashOffset(rawTileLen);
|
||||
|
||||
/// Adding geometry for a line join between previous and current segment.
|
||||
if ((i != pointsCount - 2) && (isColorJoin))
|
||||
{
|
||||
m2::PointD nextDir = points[i + 2] - points[i + 1];
|
||||
nextDir *= 1.0 / nextDir.Length(m2::PointD(0, 0));
|
||||
m2::PointD nextNorm(-nextDir.y, nextDir.x);
|
||||
|
||||
/// Computing the sin of angle between directions.
|
||||
double alphaSin = dir.x * nextDir.y - dir.y * nextDir.x;
|
||||
double alphaCos = dir.x * nextDir.x + dir.y * nextDir.y;
|
||||
double alpha = atan2(alphaSin, alphaCos);
|
||||
int angleSegCount = int(ceil(fabs(alpha) / (math::pi / 6)));
|
||||
double angleStep = alpha / angleSegCount;
|
||||
|
||||
m2::PointD startVec;
|
||||
|
||||
if (alpha > 0)
|
||||
{
|
||||
/// The outer site is on the prevNorm direction.
|
||||
startVec = -norm;
|
||||
}
|
||||
else
|
||||
{
|
||||
/// The outer site is on the -prevNorm direction
|
||||
startVec = norm;
|
||||
}
|
||||
|
||||
shared_ptr<BaseTexture> texture = m_skin->pages()[lineStyle->m_pageID]->texture();
|
||||
|
||||
m2::PointF joinSegTex[3] =
|
||||
{
|
||||
texture->mapPixel(lineStyle->m_centerColorPixel),
|
||||
texture->mapPixel(lineStyle->m_borderColorPixel),
|
||||
texture->mapPixel(lineStyle->m_borderColorPixel)
|
||||
};
|
||||
|
||||
m2::PointD prevStartVec = startVec;
|
||||
for (int j = 0; j < angleSegCount; ++j)
|
||||
{
|
||||
/// Rotate start vector to find another point on a join.
|
||||
startVec.Rotate(angleStep);
|
||||
|
||||
/// Computing three points of a join segment.
|
||||
m2::PointF joinSeg[3] =
|
||||
{
|
||||
m2::PointF(points[i + 1]),
|
||||
m2::PointF(points[i + 1] + startVec * geomHalfWidth),
|
||||
m2::PointF(points[i + 1] + prevStartVec * geomHalfWidth)
|
||||
};
|
||||
|
||||
addTexturedFan(joinSeg, joinSegTex, 3, depth, lineStyle->m_pageID);
|
||||
|
||||
prevStartVec = startVec;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GeometryBatcher::drawTrianglesList(m2::PointD const * points, size_t pointsCount, uint32_t styleID, double depth)
|
||||
{
|
||||
|
@ -582,230 +421,6 @@ namespace yg
|
|||
m_pipelines[pageID].m_currentIndex += (size - 2) * 3;
|
||||
}
|
||||
|
||||
|
||||
void GeometryBatcher::drawGlyph(m2::PointD const & ptOrg, m2::PointD const & ptGlyph, float angle, float blOffset, CharStyle const * p, double depth)
|
||||
{
|
||||
float x0 = ptGlyph.x + (p->m_xOffset - 1);
|
||||
float y1 = ptGlyph.y - (p->m_yOffset - 1) - blOffset;
|
||||
float y0 = y1 - (p->m_texRect.SizeY() - 2);
|
||||
float x1 = x0 + (p->m_texRect.SizeX() - 2);
|
||||
|
||||
|
||||
drawTexturedPolygon(ptOrg, angle,
|
||||
p->m_texRect.minX() + 1,
|
||||
p->m_texRect.minY() + 1,
|
||||
p->m_texRect.maxX() - 1,
|
||||
p->m_texRect.maxY() - 1,
|
||||
x0, y0, x1, y1,
|
||||
depth,
|
||||
p->m_pageID);
|
||||
}
|
||||
|
||||
template <class ToDo>
|
||||
void GeometryBatcher::ForEachGlyph(uint8_t fontSize, wstring const & text, bool isMask, bool isFixedFont, ToDo toDo)
|
||||
{
|
||||
m2::PointD currPt(0, 0);
|
||||
for (size_t i = 0; i < text.size(); ++i)
|
||||
{
|
||||
uint32_t glyphID = m_skin->mapGlyph(GlyphKey(text[i], fontSize, isMask), isFixedFont);
|
||||
CharStyle const * p = static_cast<CharStyle const *>(m_skin->fromID(glyphID));
|
||||
if (p)
|
||||
{
|
||||
toDo(currPt, p);
|
||||
currPt += m2::PointD(p->m_xAdvance, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GeometryBatcher::drawText(m2::PointD const & pt, float angle, uint8_t fontSize, string const & utf8Text, double depth, bool isFixedFont, bool log2vis)
|
||||
{
|
||||
wstring text = FromUtf8(utf8Text);
|
||||
|
||||
if (log2vis)
|
||||
text = Log2Vis(text);
|
||||
|
||||
ForEachGlyph(fontSize, text, true, isFixedFont, bind(&GeometryBatcher::drawGlyph, this, cref(pt), _1, angle, 0, _2, depth));
|
||||
ForEachGlyph(fontSize, text, false, isFixedFont, bind(&GeometryBatcher::drawGlyph, this, cref(pt), _1, angle, 0, _2, depth));
|
||||
}
|
||||
|
||||
m2::RectD const GeometryBatcher::textRect(string const & utf8Text, uint8_t fontSize, bool fixedFont, bool log2vis)
|
||||
{
|
||||
m2::RectD rect;
|
||||
m2::PointD pt(0, 0);
|
||||
|
||||
wstring text = FromUtf8(utf8Text);
|
||||
if (log2vis)
|
||||
text = Log2Vis(text);
|
||||
|
||||
for (size_t i = 0; i < text.size(); ++i)
|
||||
{
|
||||
if (fixedFont)
|
||||
{
|
||||
uint32_t glyphID = m_skin->mapGlyph(GlyphKey(text[i], fontSize, false), fixedFont);
|
||||
CharStyle const * p = static_cast<CharStyle const *>(m_skin->fromID(glyphID));
|
||||
rect.Add(pt);
|
||||
rect.Add(pt + m2::PointD(p->m_xOffset + p->m_texRect.SizeX() - 4, -p->m_yOffset - (int)p->m_texRect.SizeY() + 4));
|
||||
pt += m2::PointD(p->m_xAdvance, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
GlyphMetrics const m = resourceManager()->getGlyphMetrics(GlyphKey(text[i], fontSize, false));
|
||||
|
||||
rect.Add(pt);
|
||||
rect.Add(pt + m2::PointD(m.m_xOffset + m.m_width, - m.m_yOffset - m.m_height));
|
||||
pt += m2::PointD(m.m_xAdvance, 0);
|
||||
}
|
||||
}
|
||||
|
||||
rect.Inflate(2, 2);
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
/// Encapsulate array of points in readable getting direction.
|
||||
class pts_array
|
||||
{
|
||||
m2::PointD const * m_arr;
|
||||
size_t m_size;
|
||||
bool m_reverse;
|
||||
|
||||
public:
|
||||
pts_array(m2::PointD const * arr, size_t sz, double fullLength, double & pathOffset)
|
||||
: m_arr(arr), m_size(sz), m_reverse(false)
|
||||
{
|
||||
ASSERT ( m_size > 1, () );
|
||||
|
||||
/* assume, that readable text in path should be ('o' - start draw point):
|
||||
* / o
|
||||
* / \
|
||||
* / or \
|
||||
* o \
|
||||
*/
|
||||
|
||||
double const a = ang::AngleTo(m_arr[0], m_arr[m_size-1]);
|
||||
if (fabs(a) > math::pi / 2.0)
|
||||
{
|
||||
// if we swap direction, we need to recalculate path offset from the end
|
||||
double len = 0.0;
|
||||
for (size_t i = 1; i < m_size; ++i)
|
||||
len += m_arr[i-1].Length(m_arr[i]);
|
||||
|
||||
pathOffset = fullLength - pathOffset - len;
|
||||
ASSERT ( pathOffset >= -1.0E-6, () );
|
||||
if (pathOffset < 0.0) pathOffset = 0.0;
|
||||
|
||||
m_reverse = true;
|
||||
}
|
||||
}
|
||||
|
||||
size_t size() const { return m_size; }
|
||||
|
||||
m2::PointD get(size_t i) const
|
||||
{
|
||||
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); }
|
||||
};
|
||||
|
||||
double const angle_not_inited = -100.0;
|
||||
|
||||
bool CalcPointAndAngle(pts_array const & arr, double offset, size_t & ind, m2::PointD & pt, double & angle)
|
||||
{
|
||||
size_t const oldInd = ind;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (ind + 1 == arr.size())
|
||||
return false;
|
||||
|
||||
double const l = arr[ind + 1].Length(pt);
|
||||
if (offset < l)
|
||||
break;
|
||||
|
||||
offset -= l;
|
||||
pt = arr[++ind];
|
||||
}
|
||||
|
||||
if (oldInd != ind || angle == angle_not_inited)
|
||||
angle = ang::AngleTo(pt, arr[ind + 1]);
|
||||
pt = pt.Move(offset, angle);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GeometryBatcher::drawPathText(
|
||||
m2::PointD const * path, size_t s, uint8_t fontSize, string const & utf8Text,
|
||||
double fullLength, double pathOffset, TextPos pos, bool isMasked, double depth, bool isFixedFont)
|
||||
{
|
||||
if (isMasked)
|
||||
{
|
||||
if (!drawPathTextImpl(path, s, fontSize, utf8Text, fullLength, pathOffset, pos, true, depth, isFixedFont))
|
||||
return false;
|
||||
}
|
||||
return drawPathTextImpl(path, s, fontSize, utf8Text, fullLength, pathOffset, pos, false, depth, isFixedFont);
|
||||
}
|
||||
|
||||
bool GeometryBatcher::drawPathTextImpl(
|
||||
m2::PointD const * path, size_t s, uint8_t fontSize, string const & utf8Text,
|
||||
double fullLength, double pathOffset, TextPos pos, bool fromMask, double depth, bool isFixedFont)
|
||||
{
|
||||
pts_array arrPath(path, s, fullLength, pathOffset);
|
||||
|
||||
wstring const text = Log2Vis(FromUtf8(utf8Text));
|
||||
|
||||
// calculate base line offset
|
||||
float blOffset = 2;
|
||||
switch (pos)
|
||||
{
|
||||
case under_line: blOffset -= fontSize; break;
|
||||
case middle_line: blOffset -= fontSize / 2; break;
|
||||
case above_line: blOffset -= 0; break;
|
||||
}
|
||||
|
||||
size_t const count = text.size();
|
||||
|
||||
vector<GlyphMetrics> glyphs(count);
|
||||
|
||||
// get vector of glyphs and calculate string length
|
||||
double strLength = 0.0;
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
glyphs[i] = resourceManager()->getGlyphMetrics(GlyphKey(text[i], fontSize, fromMask));
|
||||
strLength += glyphs[i].m_xAdvance;
|
||||
}
|
||||
|
||||
// offset of the text from path's start
|
||||
double offset = (fullLength - strLength) / 2.0;
|
||||
if (offset < 0.0) return false;
|
||||
offset -= pathOffset;
|
||||
if (-offset >= strLength) return false;
|
||||
|
||||
// find first visible glyph
|
||||
size_t i = 0;
|
||||
while (offset < 0 && i < count)
|
||||
offset += glyphs[i++].m_xAdvance;
|
||||
|
||||
size_t ind = 0;
|
||||
m2::PointD ptOrg = arrPath[0];
|
||||
double angle = angle_not_inited;
|
||||
|
||||
// draw visible glyphs
|
||||
for (; i < count; ++i)
|
||||
{
|
||||
if (!CalcPointAndAngle(arrPath, offset, ind, ptOrg, angle))
|
||||
break;
|
||||
|
||||
uint32_t const glyphID = m_skin->mapGlyph(GlyphKey(text[i], fontSize, fromMask), isFixedFont);
|
||||
CharStyle const * charStyle = static_cast<CharStyle const *>(m_skin->fromID(glyphID));
|
||||
|
||||
drawGlyph(ptOrg, m2::PointD(0.0, 0.0), angle, blOffset, charStyle, depth);
|
||||
|
||||
offset = glyphs[i].m_xAdvance;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GeometryBatcher::enableClipRect(bool flag)
|
||||
{
|
||||
flush(-1);
|
||||
|
|
|
@ -48,12 +48,8 @@ namespace yg
|
|||
|
||||
typedef function<void()> onFlushFinishedFn;
|
||||
|
||||
enum TextPos { under_line, middle_line, above_line };
|
||||
|
||||
private:
|
||||
|
||||
static wstring Log2Vis(wstring const & str);
|
||||
|
||||
typedef RenderStateUpdater base_t;
|
||||
|
||||
shared_ptr<yg::Skin> m_skin;
|
||||
|
@ -94,16 +90,6 @@ namespace yg
|
|||
|
||||
int m_aaShift;
|
||||
|
||||
bool drawPathTextImpl(m2::PointD const * path,
|
||||
size_t s,
|
||||
uint8_t fontSize,
|
||||
string const & utf8Text,
|
||||
double fullLength,
|
||||
double pathOffset,
|
||||
TextPos pos,
|
||||
bool fromMask,
|
||||
double depth,
|
||||
bool isFixedFont);
|
||||
|
||||
public:
|
||||
|
||||
|
@ -138,36 +124,8 @@ namespace yg
|
|||
uint32_t styleID,
|
||||
double depth);
|
||||
|
||||
private:
|
||||
template <class ToDo>
|
||||
void ForEachGlyph(uint8_t fontSize, wstring const & text, bool isMask, bool isFixedFont, ToDo toDo);
|
||||
|
||||
public:
|
||||
/// Drawing text from point rotated by the angle.
|
||||
void drawText(m2::PointD const & pt,
|
||||
float angle,
|
||||
uint8_t fontSize,
|
||||
string const & utf8Text,
|
||||
double depth,
|
||||
bool fixedFont = false,
|
||||
bool log2vis = true);
|
||||
|
||||
m2::RectD const textRect(string const & utf8Text,
|
||||
uint8_t fontSize,
|
||||
bool fixedFont = false,
|
||||
bool log2vis = true);
|
||||
|
||||
/// Drawing text in the middle of the path.
|
||||
bool drawPathText(m2::PointD const * path,
|
||||
size_t s,
|
||||
uint8_t fontSize,
|
||||
string const & utf8Text,
|
||||
double fullLength,
|
||||
double pathOffset,
|
||||
TextPos pos,
|
||||
bool isMasked,
|
||||
double depth,
|
||||
bool isFixedFont = false);
|
||||
|
||||
/// This functions hide the base_t functions with the same name and signature
|
||||
/// to flush(-1) upon calling them
|
||||
|
@ -195,15 +153,6 @@ namespace yg
|
|||
|
||||
int aaShift() const;
|
||||
|
||||
private:
|
||||
|
||||
void drawGlyph(m2::PointD const & ptOrg,
|
||||
m2::PointD const & ptGlyph,
|
||||
float angle,
|
||||
float blOffset,
|
||||
CharStyle const * p,
|
||||
double depth);
|
||||
|
||||
/// drawing textured polygon with antialiasing
|
||||
/// we assume that the (tx0, ty0, tx1, ty1) area on texture is surrounded by (0, 0, 0, 0) pixels,
|
||||
/// and the 1px interior area is also (0, 0, 0, 0).
|
||||
|
|
|
@ -15,8 +15,8 @@ namespace gil = boost::gil;
|
|||
|
||||
namespace yg
|
||||
{
|
||||
GlyphKey::GlyphKey(int id, int fontSize, bool isMask)
|
||||
: m_id(id), m_fontSize(fontSize), m_isMask(isMask)
|
||||
GlyphKey::GlyphKey(int id, int fontSize, bool isMask, yg::Color const & color)
|
||||
: m_id(id), m_fontSize(fontSize), m_isMask(isMask), m_color(color)
|
||||
{}
|
||||
|
||||
uint32_t GlyphKey::toUInt32() const
|
||||
|
@ -32,7 +32,9 @@ namespace yg
|
|||
return l.m_id < r.m_id;
|
||||
if (l.m_fontSize != r.m_fontSize)
|
||||
return l.m_fontSize < r.m_fontSize;
|
||||
return l.m_isMask < r.m_isMask;
|
||||
if (l.m_isMask != r.m_isMask)
|
||||
return l.m_isMask < r.m_isMask;
|
||||
return l.m_color < r.m_color;
|
||||
}
|
||||
|
||||
GlyphCache::Params::Params(char const * blocksFile, char const * whiteListFile, char const * blackListFile, size_t maxSize)
|
||||
|
@ -169,11 +171,6 @@ namespace yg
|
|||
0
|
||||
));
|
||||
|
||||
/// glyph could appear in cache from getGlyphMetrics method,
|
||||
/// so we should explicitly check this situation
|
||||
// if (glyph.format == FT_GLYPH_FORMAT_OUTLINE)
|
||||
// FTCHECK(FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1));
|
||||
|
||||
FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
|
||||
|
||||
shared_ptr<GlyphInfo> info(new GlyphInfo());
|
||||
|
@ -184,7 +181,7 @@ namespace yg
|
|||
info->m_metrics.m_yOffset = bitmapGlyph ? bitmapGlyph->top - info->m_metrics.m_height : 0;
|
||||
info->m_metrics.m_xAdvance = bitmapGlyph ? int(bitmapGlyph->root.advance.x >> 16) : 0;
|
||||
info->m_metrics.m_yAdvance = bitmapGlyph ? int(bitmapGlyph->root.advance.y >> 16) : 0;
|
||||
info->m_color = key.m_isMask ? yg::Color(255, 255, 255, 0) : yg::Color(0, 0, 0, 0);
|
||||
info->m_color = key.m_color;
|
||||
|
||||
if ((info->m_metrics.m_width != 0) && (info->m_metrics.m_height != 0))
|
||||
{
|
||||
|
@ -206,10 +203,10 @@ namespace yg
|
|||
|
||||
DATA_TRAITS::pixel_t c;
|
||||
|
||||
gil::get_color(c, gil::red_t()) = key.m_isMask ? DATA_TRAITS::maxChannelVal : 0;
|
||||
gil::get_color(c, gil::green_t()) = key.m_isMask ? DATA_TRAITS::maxChannelVal : 0;
|
||||
gil::get_color(c, gil::blue_t()) = key.m_isMask ? DATA_TRAITS::maxChannelVal : 0;
|
||||
gil::get_color(c, gil::alpha_t()) = 0;
|
||||
gil::get_color(c, gil::red_t()) = key.m_color.r / DATA_TRAITS::channelScaleFactor;
|
||||
gil::get_color(c, gil::green_t()) = key.m_color.g / DATA_TRAITS::channelScaleFactor;
|
||||
gil::get_color(c, gil::blue_t()) = key.m_color.b / DATA_TRAITS::channelScaleFactor;
|
||||
gil::get_color(c, gil::alpha_t()) = key.m_color.a / DATA_TRAITS::channelScaleFactor;
|
||||
|
||||
for (size_t y = 0; y < srcView.height(); ++y)
|
||||
for (size_t x = 0; x < srcView.width(); ++x)
|
||||
|
|
|
@ -32,8 +32,10 @@ namespace yg
|
|||
int m_id;
|
||||
int m_fontSize;
|
||||
bool m_isMask;
|
||||
yg::Color m_color;
|
||||
/// as it's used for fixed fonts only, the color doesn't matter
|
||||
uint32_t toUInt32() const;
|
||||
GlyphKey(int id, int fontSize, bool isMask);
|
||||
GlyphKey(int id, int fontSize, bool isMask, yg::Color const & color);
|
||||
};
|
||||
|
||||
struct Font;
|
||||
|
|
|
@ -14,69 +14,222 @@ namespace yg
|
|||
|
||||
void PathRenderer::drawPath(m2::PointD const * points, size_t pointsCount, uint32_t styleID, double depth)
|
||||
{
|
||||
#ifdef PROFILER_YG
|
||||
prof::block<prof::yg_draw_path> draw_path_block;
|
||||
#endif
|
||||
|
||||
//#ifdef DEBUG_DRAW_PATH
|
||||
// LineStyle const * lineStyle = reinterpret_cast<LineStyle const*>(styleID);
|
||||
//#else
|
||||
|
||||
ASSERT_GREATER_OR_EQUAL(pointsCount, 2, ());
|
||||
ResourceStyle const * style(skin()->fromID(styleID));
|
||||
|
||||
ASSERT(style->m_cat == ResourceStyle::ELineStyle, ());
|
||||
LineStyle const * lineStyle = static_cast<LineStyle const *>(style);
|
||||
//#endif
|
||||
|
||||
if (lineStyle->m_isSolid)
|
||||
{
|
||||
drawSolidPath(points, pointsCount, styleID, depth);
|
||||
return;
|
||||
}
|
||||
|
||||
float rawTileStartLen = 0;
|
||||
|
||||
for (size_t i = 0; i < pointsCount - 1; ++i)
|
||||
{
|
||||
m2::PointD dir = points[i + 1] - points[i];
|
||||
dir *= 1.0 / dir.Length(m2::PointD(0, 0));
|
||||
m2::PointD norm(-dir.y, dir.x);
|
||||
|
||||
/// The length of the current segment.
|
||||
float segLen = points[i + 1].Length(points[i]);
|
||||
/// The remaining length of the segment
|
||||
float segLenRemain = segLen;
|
||||
|
||||
/// Geometry width. It's 1px wider than the pattern width.
|
||||
int geomWidth = lineStyle->m_isSolid ? lineStyle->m_penInfo.m_w : lineStyle->m_penInfo.m_w + 4 - 2 * aaShift();
|
||||
float geomHalfWidth = geomWidth / 2.0;
|
||||
|
||||
/// Starting point of the tiles on this segment
|
||||
m2::PointF rawTileStartPt = points[i];
|
||||
|
||||
/// Tiling procedes as following :
|
||||
/// The leftmost tile goes antialiased at left and non-antialiased at right.
|
||||
/// The inner tiles goes non-antialiased at both sides.
|
||||
/// The rightmost tile goes non-antialised at left and antialiased at right side.
|
||||
|
||||
/// Length of the actual pattern data being tiling(without antialiasing zones).
|
||||
float rawTileLen = 0;
|
||||
while (segLenRemain > 0)
|
||||
{
|
||||
rawTileLen = (lineStyle->m_isWrapped || lineStyle->m_isSolid)
|
||||
? segLen
|
||||
: std::min(((float)lineStyle->rawTileLen() - rawTileStartLen), segLenRemain);
|
||||
|
||||
float texMaxY = lineStyle->m_isSolid ? lineStyle->m_texRect.minY() + 1 : lineStyle->m_texRect.maxY() - aaShift();
|
||||
float texMinY = lineStyle->m_isSolid ? lineStyle->m_texRect.minY() + 1 : lineStyle->m_texRect.minY() + aaShift();
|
||||
|
||||
float texMinX = lineStyle->m_isSolid ? lineStyle->m_texRect.minX() + 1 : lineStyle->m_isWrapped ? 0 : lineStyle->m_texRect.minX() + 2 + rawTileStartLen;
|
||||
float texMaxX = lineStyle->m_isSolid ? lineStyle->m_texRect.minX() + 1 : texMinX + rawTileLen;
|
||||
|
||||
rawTileStartLen += rawTileLen;
|
||||
if (rawTileStartLen >= lineStyle->rawTileLen())
|
||||
rawTileStartLen -= lineStyle->rawTileLen();
|
||||
ASSERT(rawTileStartLen < lineStyle->rawTileLen(), ());
|
||||
|
||||
m2::PointF rawTileEndPt(rawTileStartPt.x + dir.x * rawTileLen, rawTileStartPt.y + dir.y * rawTileLen);
|
||||
|
||||
m2::PointF const fNorm = norm * geomHalfWidth; // enough to calc it once
|
||||
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)
|
||||
};
|
||||
|
||||
shared_ptr<BaseTexture> texture = skin()->pages()[lineStyle->m_pageID]->texture();
|
||||
|
||||
m2::PointF texCoords[4] =
|
||||
{
|
||||
texture->mapPixel(m2::PointF(texMinX, texMinY)),
|
||||
texture->mapPixel(m2::PointF(texMinX, texMaxY)),
|
||||
texture->mapPixel(m2::PointF(texMaxX, texMaxY)),
|
||||
texture->mapPixel(m2::PointF(texMaxX, texMinY))
|
||||
};
|
||||
|
||||
addTexturedFan(coords, texCoords, 4, depth, lineStyle->m_pageID);
|
||||
|
||||
segLenRemain -= rawTileLen;
|
||||
|
||||
rawTileStartPt = rawTileEndPt;
|
||||
}
|
||||
|
||||
bool isColorJoin = lineStyle->m_isSolid ? true : lineStyle->m_penInfo.atDashOffset(rawTileLen);
|
||||
|
||||
/// Adding geometry for a line join between previous and current segment.
|
||||
if ((i != pointsCount - 2) && (isColorJoin))
|
||||
{
|
||||
m2::PointD nextDir = points[i + 2] - points[i + 1];
|
||||
nextDir *= 1.0 / nextDir.Length(m2::PointD(0, 0));
|
||||
m2::PointD nextNorm(-nextDir.y, nextDir.x);
|
||||
|
||||
/// Computing the sin of angle between directions.
|
||||
double alphaSin = dir.x * nextDir.y - dir.y * nextDir.x;
|
||||
double alphaCos = dir.x * nextDir.x + dir.y * nextDir.y;
|
||||
double alpha = atan2(alphaSin, alphaCos);
|
||||
int angleSegCount = int(ceil(fabs(alpha) / (math::pi / 6)));
|
||||
double angleStep = alpha / angleSegCount;
|
||||
|
||||
m2::PointD startVec;
|
||||
|
||||
if (alpha > 0)
|
||||
{
|
||||
/// The outer site is on the prevNorm direction.
|
||||
startVec = -norm;
|
||||
}
|
||||
else
|
||||
{
|
||||
/// The outer site is on the -prevNorm direction
|
||||
startVec = norm;
|
||||
}
|
||||
|
||||
shared_ptr<BaseTexture> texture = skin()->pages()[lineStyle->m_pageID]->texture();
|
||||
|
||||
m2::PointF joinSegTex[3] =
|
||||
{
|
||||
texture->mapPixel(lineStyle->m_centerColorPixel),
|
||||
texture->mapPixel(lineStyle->m_borderColorPixel),
|
||||
texture->mapPixel(lineStyle->m_borderColorPixel)
|
||||
};
|
||||
|
||||
m2::PointD prevStartVec = startVec;
|
||||
for (int j = 0; j < angleSegCount; ++j)
|
||||
{
|
||||
/// Rotate start vector to find another point on a join.
|
||||
startVec.Rotate(angleStep);
|
||||
|
||||
/// Computing three points of a join segment.
|
||||
m2::PointF joinSeg[3] =
|
||||
{
|
||||
m2::PointF(points[i + 1]),
|
||||
m2::PointF(points[i + 1] + startVec * geomHalfWidth),
|
||||
m2::PointF(points[i + 1] + prevStartVec * geomHalfWidth)
|
||||
};
|
||||
|
||||
addTexturedFan(joinSeg, joinSegTex, 3, depth, lineStyle->m_pageID);
|
||||
|
||||
prevStartVec = startVec;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PathRenderer::drawSolidPath(m2::PointD const * points, size_t pointsCount, uint32_t styleID, double depth)
|
||||
{
|
||||
ASSERT_GREATER_OR_EQUAL(pointsCount, 2, ());
|
||||
ResourceStyle const * style(skin()->fromID(styleID));
|
||||
|
||||
ASSERT(style->m_cat == ResourceStyle::ELineStyle, ());
|
||||
LineStyle const * lineStyle = static_cast<LineStyle const *>(style);
|
||||
|
||||
if (lineStyle->m_isSolid)
|
||||
ASSERT(lineStyle->m_isSolid, ());
|
||||
|
||||
for (size_t i = 0; i < pointsCount - 1; ++i)
|
||||
{
|
||||
for (size_t i = 0; i < pointsCount - 1; ++i)
|
||||
m2::PointD dir = points[i + 1] - points[i];
|
||||
double len = dir.Length(m2::PointD(0, 0));
|
||||
dir *= 1.0 / len;
|
||||
m2::PointD norm(-dir.y, dir.x);
|
||||
m2::PointD const & nextPt = points[i + 1];
|
||||
|
||||
float geomHalfWidth = (lineStyle->m_penInfo.m_w + 4 - aaShift() * 2) / 2.0;
|
||||
|
||||
float texMinX = lineStyle->m_texRect.minX() + 1;
|
||||
float texMaxX = lineStyle->m_texRect.maxX() - 1;
|
||||
|
||||
float texMinY = lineStyle->m_texRect.maxY() - aaShift();
|
||||
float texMaxY = lineStyle->m_texRect.minY() + aaShift();
|
||||
|
||||
float texCenterX = (texMinX + texMaxX) / 2;
|
||||
|
||||
m2::PointF const fNorm = norm * geomHalfWidth; // enough to calc it once
|
||||
m2::PointF const fDir(fNorm.y, -fNorm.x);
|
||||
|
||||
m2::PointF coords[8] =
|
||||
{
|
||||
m2::PointD dir = points[i + 1] - points[i];
|
||||
double len = dir.Length(m2::PointD(0, 0));
|
||||
dir *= 1.0 / len;
|
||||
m2::PointD norm(-dir.y, dir.x);
|
||||
m2::PointD const & nextPt = points[i + 1];
|
||||
/// left round cap
|
||||
points[i] - fDir + fNorm,
|
||||
points[i] - fDir - fNorm,
|
||||
points[i] + fNorm,
|
||||
/// inner part
|
||||
points[i] - fNorm,
|
||||
nextPt + fNorm,
|
||||
nextPt - fNorm,
|
||||
/// right round cap
|
||||
nextPt + fDir + fNorm,
|
||||
nextPt + fDir - fNorm
|
||||
};
|
||||
|
||||
float geomHalfWidth = (lineStyle->m_penInfo.m_w + 4 - aaShift() * 2) / 2.0;
|
||||
shared_ptr<BaseTexture> texture = skin()->pages()[lineStyle->m_pageID]->texture();
|
||||
|
||||
float texMinX = lineStyle->m_texRect.minX() + 1;
|
||||
float texMaxX = lineStyle->m_texRect.maxX() - 1;
|
||||
m2::PointF texCoords[8] =
|
||||
{
|
||||
texture->mapPixel(m2::PointF(texMinX, texMinY)),
|
||||
texture->mapPixel(m2::PointF(texMinX, texMaxY)),
|
||||
texture->mapPixel(m2::PointF(texCenterX, texMinY)),
|
||||
texture->mapPixel(m2::PointF(texCenterX, texMaxY)),
|
||||
texture->mapPixel(m2::PointF(texCenterX, texMinY)),
|
||||
texture->mapPixel(m2::PointF(texCenterX, texMaxY)),
|
||||
texture->mapPixel(m2::PointF(texMaxX, texMinY)),
|
||||
texture->mapPixel(m2::PointF(texMaxX, texMaxY))
|
||||
};
|
||||
|
||||
float texMinY = lineStyle->m_texRect.maxY() - aaShift();
|
||||
float texMaxY = lineStyle->m_texRect.minY() + aaShift();
|
||||
|
||||
float texCenterX = (texMinX + texMaxX) / 2;
|
||||
|
||||
m2::PointF const fNorm = norm * geomHalfWidth; // enough to calc it once
|
||||
m2::PointF const fDir(fNorm.y, -fNorm.x);
|
||||
|
||||
m2::PointF coords[8] =
|
||||
{
|
||||
/// left round cap
|
||||
points[i] - fDir + fNorm,
|
||||
points[i] - fDir - fNorm,
|
||||
points[i] + fNorm,
|
||||
/// inner part
|
||||
points[i] - fNorm,
|
||||
nextPt + fNorm,
|
||||
nextPt - fNorm,
|
||||
/// right round cap
|
||||
nextPt + fDir + fNorm,
|
||||
nextPt + fDir - fNorm
|
||||
};
|
||||
|
||||
shared_ptr<BaseTexture> texture = skin()->pages()[lineStyle->m_pageID]->texture();
|
||||
|
||||
m2::PointF texCoords[8] =
|
||||
{
|
||||
texture->mapPixel(m2::PointF(texMinX, texMinY)),
|
||||
texture->mapPixel(m2::PointF(texMinX, texMaxY)),
|
||||
texture->mapPixel(m2::PointF(texCenterX, texMinY)),
|
||||
texture->mapPixel(m2::PointF(texCenterX, texMaxY)),
|
||||
texture->mapPixel(m2::PointF(texCenterX, texMinY)),
|
||||
texture->mapPixel(m2::PointF(texCenterX, texMaxY)),
|
||||
texture->mapPixel(m2::PointF(texMaxX, texMinY)),
|
||||
texture->mapPixel(m2::PointF(texMaxX, texMaxY))
|
||||
};
|
||||
|
||||
addTexturedStrip(coords, texCoords, 8, depth, lineStyle->m_pageID);
|
||||
}
|
||||
addTexturedStrip(coords, texCoords, 8, depth, lineStyle->m_pageID);
|
||||
}
|
||||
else
|
||||
base_t::drawPath(points, pointsCount, styleID, depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,9 @@ namespace yg
|
|||
class PathRenderer : public GeometryBatcher
|
||||
{
|
||||
private:
|
||||
|
||||
void drawSolidPath(m2::PointD const * points, size_t pointsCount, uint32_t styleID, double depth);
|
||||
|
||||
public:
|
||||
|
||||
typedef GeometryBatcher base_t;
|
||||
|
|
|
@ -9,8 +9,12 @@
|
|||
|
||||
#include "../coding/strutil.hpp"
|
||||
|
||||
#include "../geometry/angles.hpp"
|
||||
|
||||
#include "../std/bind.hpp"
|
||||
|
||||
#include "../3party/fribidi/lib/fribidi-deprecated.h"
|
||||
|
||||
#include "../base/start_mem_debug.hpp"
|
||||
|
||||
|
||||
|
@ -18,37 +22,36 @@ namespace yg
|
|||
{
|
||||
namespace gl
|
||||
{
|
||||
TextRenderer::Params::Params() : m_useTextLayer(false)
|
||||
{
|
||||
}
|
||||
|
||||
TextRenderer::TextRenderer(Params const & params)
|
||||
: base_t(params), m_useTextLayer(params.m_useTextLayer)
|
||||
TextRenderer::TextRenderer(base_t::Params const & params)
|
||||
: base_t(params)
|
||||
{}
|
||||
|
||||
void TextRenderer::TextObj::Draw(GeometryBatcher * pBatcher) const
|
||||
void TextRenderer::TextObj::Draw(TextRenderer * pTextRenderer) const
|
||||
{
|
||||
pBatcher->drawText(m_pt, 0.0, m_size, m_utf8Text, yg::maxDepth, m_isFixedFont, m_log2vis);
|
||||
pTextRenderer->drawTextImpl(m_pt, 0.0, m_size, m_color, m_utf8Text, m_isMasked, m_maskColor, yg::maxDepth, m_isFixedFont, m_log2vis);
|
||||
}
|
||||
|
||||
m2::RectD const TextRenderer::TextObj::GetLimitRect(GeometryBatcher * pBatcher) const
|
||||
m2::RectD const TextRenderer::TextObj::GetLimitRect(TextRenderer* pTextRenderer) const
|
||||
{
|
||||
return m2::Offset(pBatcher->textRect(m_utf8Text, m_size, false, m_log2vis), m_pt);
|
||||
return m2::Offset(pTextRenderer->textRect(m_utf8Text, m_size, false, m_log2vis), m_pt);
|
||||
}
|
||||
|
||||
void TextRenderer::drawText(m2::PointD const & pt,
|
||||
float angle,
|
||||
uint8_t fontSize,
|
||||
yg::Color const & color,
|
||||
string const & utf8Text,
|
||||
bool isMasked,
|
||||
yg::Color const & maskColor,
|
||||
double depth,
|
||||
bool isFixedFont,
|
||||
bool log2vis)
|
||||
{
|
||||
if (isFixedFont)
|
||||
base_t::drawText(pt, angle, fontSize, utf8Text, depth, isFixedFont, log2vis);
|
||||
drawTextImpl(pt, angle, fontSize, color, utf8Text, isMasked, maskColor, depth, isFixedFont, log2vis);
|
||||
else
|
||||
{
|
||||
TextObj obj(pt, utf8Text, fontSize, depth, isFixedFont, log2vis);
|
||||
TextObj obj(pt, utf8Text, fontSize, color, isMasked, maskColor, depth, isFixedFont, log2vis);
|
||||
m2::RectD r = obj.GetLimitRect(this);
|
||||
/*
|
||||
m2::PointD pts[5] =
|
||||
|
@ -81,5 +84,238 @@ namespace yg
|
|||
|
||||
base_t::endFrame();
|
||||
}
|
||||
|
||||
template <class ToDo>
|
||||
void TextRenderer::ForEachGlyph(uint8_t fontSize, yg::Color const & color, wstring const & text, bool isMasked, bool isFixedFont, ToDo toDo)
|
||||
{
|
||||
m2::PointD currPt(0, 0);
|
||||
for (size_t i = 0; i < text.size(); ++i)
|
||||
{
|
||||
uint32_t glyphID = skin()->mapGlyph(GlyphKey(text[i], fontSize, isMasked, color), isFixedFont);
|
||||
CharStyle const * p = static_cast<CharStyle const *>(skin()->fromID(glyphID));
|
||||
if (p)
|
||||
{
|
||||
toDo(currPt, p);
|
||||
currPt += m2::PointD(p->m_xAdvance, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wstring TextRenderer::Log2Vis(wstring const & str)
|
||||
{
|
||||
size_t const count = str.size();
|
||||
wstring res;
|
||||
res.resize(count);
|
||||
FriBidiParType dir = FRIBIDI_PAR_LTR; // requested base direction
|
||||
fribidi_log2vis(str.c_str(), count, &dir, &res[0], 0, 0, 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
void TextRenderer::drawTextImpl(m2::PointD const & pt, float angle, uint8_t fontSize, yg::Color const & color, string const & utf8Text, bool isMasked, yg::Color const & maskColor, double depth, bool isFixedFont, bool log2vis)
|
||||
{
|
||||
wstring text = FromUtf8(utf8Text);
|
||||
|
||||
if (log2vis)
|
||||
text = Log2Vis(text);
|
||||
|
||||
if (isMasked)
|
||||
ForEachGlyph(fontSize, maskColor, text, true, isFixedFont, bind(&TextRenderer::drawGlyph, this, cref(pt), _1, angle, 0, _2, depth));
|
||||
ForEachGlyph(fontSize, color, text, false, isFixedFont, bind(&TextRenderer::drawGlyph, this, cref(pt), _1, angle, 0, _2, depth));
|
||||
}
|
||||
|
||||
m2::RectD const TextRenderer::textRect(string const & utf8Text, uint8_t fontSize, bool fixedFont, bool log2vis)
|
||||
{
|
||||
m2::RectD rect;
|
||||
m2::PointD pt(0, 0);
|
||||
|
||||
wstring text = FromUtf8(utf8Text);
|
||||
if (log2vis)
|
||||
text = Log2Vis(text);
|
||||
|
||||
for (size_t i = 0; i < text.size(); ++i)
|
||||
{
|
||||
if (fixedFont)
|
||||
{
|
||||
uint32_t glyphID = skin()->mapGlyph(GlyphKey(text[i], fontSize, false, yg::Color(0, 0, 0, 0)), fixedFont);
|
||||
CharStyle const * p = static_cast<CharStyle const *>(skin()->fromID(glyphID));
|
||||
rect.Add(pt);
|
||||
rect.Add(pt + m2::PointD(p->m_xOffset + p->m_texRect.SizeX() - 4, -p->m_yOffset - (int)p->m_texRect.SizeY() + 4));
|
||||
pt += m2::PointD(p->m_xAdvance, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
GlyphMetrics const m = resourceManager()->getGlyphMetrics(GlyphKey(text[i], fontSize, false, yg::Color(0, 0, 0, 0)));
|
||||
|
||||
rect.Add(pt);
|
||||
rect.Add(pt + m2::PointD(m.m_xOffset + m.m_width, - m.m_yOffset - m.m_height));
|
||||
pt += m2::PointD(m.m_xAdvance, 0);
|
||||
}
|
||||
}
|
||||
|
||||
rect.Inflate(2, 2);
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
/// Encapsulate array of points in readable getting direction.
|
||||
class pts_array
|
||||
{
|
||||
m2::PointD const * m_arr;
|
||||
size_t m_size;
|
||||
bool m_reverse;
|
||||
|
||||
public:
|
||||
pts_array(m2::PointD const * arr, size_t sz, double fullLength, double & pathOffset)
|
||||
: m_arr(arr), m_size(sz), m_reverse(false)
|
||||
{
|
||||
ASSERT ( m_size > 1, () );
|
||||
|
||||
/* assume, that readable text in path should be ('o' - start draw point):
|
||||
* / o
|
||||
* / \
|
||||
* / or \
|
||||
* o \
|
||||
*/
|
||||
|
||||
double const a = ang::AngleTo(m_arr[0], m_arr[m_size-1]);
|
||||
if (fabs(a) > math::pi / 2.0)
|
||||
{
|
||||
// if we swap direction, we need to recalculate path offset from the end
|
||||
double len = 0.0;
|
||||
for (size_t i = 1; i < m_size; ++i)
|
||||
len += m_arr[i-1].Length(m_arr[i]);
|
||||
|
||||
pathOffset = fullLength - pathOffset - len;
|
||||
ASSERT ( pathOffset >= -1.0E-6, () );
|
||||
if (pathOffset < 0.0) pathOffset = 0.0;
|
||||
|
||||
m_reverse = true;
|
||||
}
|
||||
}
|
||||
|
||||
size_t size() const { return m_size; }
|
||||
|
||||
m2::PointD get(size_t i) const
|
||||
{
|
||||
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); }
|
||||
};
|
||||
|
||||
double const angle_not_inited = -100.0;
|
||||
|
||||
bool CalcPointAndAngle(pts_array const & arr, double offset, size_t & ind, m2::PointD & pt, double & angle)
|
||||
{
|
||||
size_t const oldInd = ind;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (ind + 1 == arr.size())
|
||||
return false;
|
||||
|
||||
double const l = arr[ind + 1].Length(pt);
|
||||
if (offset < l)
|
||||
break;
|
||||
|
||||
offset -= l;
|
||||
pt = arr[++ind];
|
||||
}
|
||||
|
||||
if (oldInd != ind || angle == angle_not_inited)
|
||||
angle = ang::AngleTo(pt, arr[ind + 1]);
|
||||
pt = pt.Move(offset, angle);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TextRenderer::drawPathText(
|
||||
m2::PointD const * path, size_t s, uint8_t fontSize, yg::Color const & color, string const & utf8Text,
|
||||
double fullLength, double pathOffset, TextPos pos, bool isMasked, yg::Color const & maskColor, double depth, bool isFixedFont)
|
||||
{
|
||||
if (isMasked)
|
||||
if (!drawPathTextImpl(path, s, fontSize, maskColor, utf8Text, fullLength, pathOffset, pos, true, depth, isFixedFont))
|
||||
return false;
|
||||
return drawPathTextImpl(path, s, fontSize, color, utf8Text, fullLength, pathOffset, pos, false, depth, isFixedFont);
|
||||
}
|
||||
|
||||
bool TextRenderer::drawPathTextImpl(
|
||||
m2::PointD const * path, size_t s, uint8_t fontSize, yg::Color const & color, string const & utf8Text,
|
||||
double fullLength, double pathOffset, TextPos pos, bool isMasked, double depth, bool isFixedFont)
|
||||
{
|
||||
pts_array arrPath(path, s, fullLength, pathOffset);
|
||||
|
||||
wstring const text = Log2Vis(FromUtf8(utf8Text));
|
||||
|
||||
// calculate base line offset
|
||||
float blOffset = 2;
|
||||
switch (pos)
|
||||
{
|
||||
case under_line: blOffset -= fontSize; break;
|
||||
case middle_line: blOffset -= fontSize / 2; break;
|
||||
case above_line: blOffset -= 0; break;
|
||||
}
|
||||
|
||||
size_t const count = text.size();
|
||||
|
||||
vector<GlyphMetrics> glyphs(count);
|
||||
|
||||
// get vector of glyphs and calculate string length
|
||||
double strLength = 0.0;
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
glyphs[i] = resourceManager()->getGlyphMetrics(GlyphKey(text[i], fontSize, isMasked, yg::Color(0, 0, 0, 0)));
|
||||
strLength += glyphs[i].m_xAdvance;
|
||||
}
|
||||
|
||||
// offset of the text from path's start
|
||||
double offset = (fullLength - strLength) / 2.0;
|
||||
if (offset < 0.0) return false;
|
||||
offset -= pathOffset;
|
||||
if (-offset >= strLength) return false;
|
||||
|
||||
// find first visible glyph
|
||||
size_t i = 0;
|
||||
while (offset < 0 && i < count)
|
||||
offset += glyphs[i++].m_xAdvance;
|
||||
|
||||
size_t ind = 0;
|
||||
m2::PointD ptOrg = arrPath[0];
|
||||
double angle = angle_not_inited;
|
||||
|
||||
// draw visible glyphs
|
||||
for (; i < count; ++i)
|
||||
{
|
||||
if (!CalcPointAndAngle(arrPath, offset, ind, ptOrg, angle))
|
||||
break;
|
||||
|
||||
uint32_t const glyphID = skin()->mapGlyph(GlyphKey(text[i], fontSize, isMasked, color), isFixedFont);
|
||||
CharStyle const * charStyle = static_cast<CharStyle const *>(skin()->fromID(glyphID));
|
||||
|
||||
drawGlyph(ptOrg, m2::PointD(0.0, 0.0), angle, blOffset, charStyle, depth);
|
||||
|
||||
offset = glyphs[i].m_xAdvance;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TextRenderer::drawGlyph(m2::PointD const & ptOrg, m2::PointD const & ptGlyph, float angle, float blOffset, CharStyle const * p, double depth)
|
||||
{
|
||||
float x0 = ptGlyph.x + (p->m_xOffset - 1);
|
||||
float y1 = ptGlyph.y - (p->m_yOffset - 1) - blOffset;
|
||||
float y0 = y1 - (p->m_texRect.SizeY() - 2);
|
||||
float x1 = x0 + (p->m_texRect.SizeX() - 2);
|
||||
|
||||
|
||||
drawTexturedPolygon(ptOrg, angle,
|
||||
p->m_texRect.minX() + 1,
|
||||
p->m_texRect.minY() + 1,
|
||||
p->m_texRect.maxX() - 1,
|
||||
p->m_texRect.maxY() - 1,
|
||||
x0, y0, x1, y1,
|
||||
depth,
|
||||
p->m_pageID);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,23 +15,32 @@ namespace yg
|
|||
|
||||
class TextRenderer : public PathRenderer
|
||||
{
|
||||
public:
|
||||
|
||||
enum TextPos { under_line, middle_line, above_line };
|
||||
|
||||
private:
|
||||
|
||||
class TextObj
|
||||
{
|
||||
m2::PointD m_pt;
|
||||
uint8_t m_size;
|
||||
string m_utf8Text;
|
||||
bool m_isMasked;
|
||||
double m_depth;
|
||||
bool m_isFixedFont;
|
||||
bool m_log2vis;
|
||||
yg::Color m_color;
|
||||
yg::Color m_maskColor;
|
||||
|
||||
public:
|
||||
TextObj(m2::PointD const & pt, string const & txt, uint8_t sz, double d, bool isFixedFont, bool log2vis)
|
||||
: m_pt(pt), m_size(sz), m_utf8Text(txt), m_depth(d), m_isFixedFont(isFixedFont), m_log2vis(log2vis)
|
||||
TextObj(m2::PointD const & pt, string const & txt, uint8_t sz, yg::Color const & c, bool isMasked, yg::Color const & maskColor, double d, bool isFixedFont, bool log2vis)
|
||||
: m_pt(pt), m_size(sz), m_utf8Text(txt), m_isMasked(isMasked), m_depth(d), m_isFixedFont(isFixedFont), m_log2vis(log2vis), m_color(c), m_maskColor(maskColor)
|
||||
{
|
||||
}
|
||||
|
||||
void Draw(GeometryBatcher * pBatcher) const;
|
||||
m2::RectD const GetLimitRect(GeometryBatcher * pBatcher) const;
|
||||
void Draw(TextRenderer * pTextRenderer) const;
|
||||
m2::RectD const GetLimitRect(TextRenderer * pTextRenderer) const;
|
||||
|
||||
struct better_depth
|
||||
{
|
||||
|
@ -44,26 +53,81 @@ namespace yg
|
|||
|
||||
m4::Tree<TextObj> m_tree;
|
||||
|
||||
bool m_useTextLayer;
|
||||
static wstring Log2Vis(wstring const & str);
|
||||
|
||||
template <class ToDo>
|
||||
void ForEachGlyph(uint8_t fontSize, yg::Color const & color, wstring const & text, bool isMask, bool isFixedFont, ToDo toDo);
|
||||
|
||||
void drawGlyph(m2::PointD const & ptOrg,
|
||||
m2::PointD const & ptGlyph,
|
||||
float angle,
|
||||
float blOffset,
|
||||
CharStyle const * p,
|
||||
double depth);
|
||||
|
||||
|
||||
bool drawPathTextImpl(m2::PointD const * path,
|
||||
size_t s,
|
||||
uint8_t fontSize,
|
||||
yg::Color const & color,
|
||||
string const & utf8Text,
|
||||
double fullLength,
|
||||
double pathOffset,
|
||||
TextPos pos,
|
||||
bool isMasked,
|
||||
double depth,
|
||||
bool isFixedFont);
|
||||
|
||||
/// Drawing text from point rotated by the angle.
|
||||
void drawTextImpl(m2::PointD const & pt,
|
||||
float angle,
|
||||
uint8_t fontSize,
|
||||
yg::Color const & color,
|
||||
string const & utf8Text,
|
||||
bool isMasked,
|
||||
yg::Color const & maskColor,
|
||||
double depth,
|
||||
bool fixedFont,
|
||||
bool log2vis);
|
||||
|
||||
|
||||
public:
|
||||
|
||||
typedef PathRenderer base_t;
|
||||
struct Params : base_t::Params
|
||||
{
|
||||
bool m_useTextLayer;
|
||||
Params();
|
||||
};
|
||||
|
||||
TextRenderer(Params const & params);
|
||||
TextRenderer(base_t::Params const & params);
|
||||
|
||||
/// Drawing text from point rotated by the angle.
|
||||
void drawText(m2::PointD const & pt,
|
||||
float angle,
|
||||
uint8_t fontSize,
|
||||
string const & utf8Text,
|
||||
double depth,
|
||||
bool isFixedFont = false,
|
||||
bool log2vis = false);
|
||||
float angle,
|
||||
uint8_t fontSize,
|
||||
yg::Color const & color,
|
||||
string const & utf8Text,
|
||||
bool isMasked,
|
||||
yg::Color const & maskColor,
|
||||
double depth,
|
||||
bool fixedFont,
|
||||
bool log2vis);
|
||||
|
||||
m2::RectD const textRect(string const & utf8Text,
|
||||
uint8_t fontSize,
|
||||
bool fixedFont,
|
||||
bool log2vis);
|
||||
|
||||
/// Drawing text in the middle of the path.
|
||||
bool drawPathText(m2::PointD const * path,
|
||||
size_t s,
|
||||
uint8_t fontSize,
|
||||
yg::Color const & color,
|
||||
string const & utf8Text,
|
||||
double fullLength,
|
||||
double pathOffset,
|
||||
TextPos pos,
|
||||
bool isMasked,
|
||||
yg::Color const & maskColor,
|
||||
double depth,
|
||||
bool isFixedFont = false);
|
||||
|
||||
|
||||
void setClipRect(m2::RectI const & rect);
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@ UNIT_TEST(GlyphCacheTest_Main)
|
|||
{
|
||||
yg::GlyphCache cache(yg::GlyphCache::Params("", "", "", 200000));
|
||||
cache.addFont(GetPlatform().ReadPathForFile("dejavusans.ttf").c_str());
|
||||
shared_ptr<yg::GlyphInfo> g1 = cache.getGlyph(yg::GlyphKey('#', 40, true));
|
||||
shared_ptr<yg::GlyphInfo> g1 = cache.getGlyph(yg::GlyphKey('#', 40, true, yg::Color(255, 255, 255, 255)));
|
||||
// g1->dump(GetPlatform().WritablePathForFile("#_mask.png").c_str());
|
||||
shared_ptr<yg::GlyphInfo> g2 = cache.getGlyph(yg::GlyphKey('#', 40, false));
|
||||
shared_ptr<yg::GlyphInfo> g2 = cache.getGlyph(yg::GlyphKey('#', 40, false, yg::Color(0, 0, 0, 0)));
|
||||
// g2->dump(GetPlatform().WritablePathForFile("#.png").c_str());
|
||||
}
|
||||
|
|
|
@ -520,12 +520,12 @@ namespace
|
|||
double pat[2] = {2, 2};
|
||||
p->drawPath(path, sizeof(path) / sizeof(m2::PointD), p->skin()->mapPenInfo(yg::PenInfo(yg::Color(0, 0, 0, 0xFF), 2, pat, 2, 0)), 0);
|
||||
|
||||
p->drawText(m2::PointD(200, 200), 0 , 20, "0", 0);
|
||||
p->drawText(m2::PointD(240, 200), math::pi / 2 , 20, "0", 0);
|
||||
p->drawText(m2::PointD(280, 200), math::pi , 20, "0", 0);
|
||||
p->drawText(m2::PointD(320, 200), math::pi * 3 / 2 , 20, "0", 0);
|
||||
p->drawText(m2::PointD(360, 200), math::pi / 18, 20, "0", 0);
|
||||
p->drawText(m2::PointD(40, 50), math::pi / 18, 20, "Simplicity is the ultimate sophistication", 0);
|
||||
p->drawText(m2::PointD(200, 200), 0 , 20, yg::Color(0, 0, 0, 0), "0", true, yg::Color(255, 255, 255, 255), 0, false, true);
|
||||
p->drawText(m2::PointD(240, 200), math::pi / 2 , 20, yg::Color(0, 0, 0, 0), "0", true, yg::Color(255, 255, 255, 255), 0, false, true);
|
||||
p->drawText(m2::PointD(280, 200), math::pi , 20, yg::Color(0, 0, 0, 0), "0", true, yg::Color(255, 255, 255, 255), 0, false, true);
|
||||
p->drawText(m2::PointD(320, 200), math::pi * 3 / 2 , 20, yg::Color(0, 0, 0, 0), "0", true, yg::Color(255, 255, 255, 255), 0, false, true);
|
||||
p->drawText(m2::PointD(360, 200), math::pi / 18, 20, yg::Color(0, 0, 0, 0), "0", true, yg::Color(255, 255, 255, 255), 0, false, true);
|
||||
p->drawText(m2::PointD(40, 50), math::pi / 18, 20, yg::Color(0, 0, 0, 0), "Simplicity is the ultimate sophistication", true, yg::Color(255, 255, 255, 255), 0, false, true);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -533,7 +533,7 @@ namespace
|
|||
{
|
||||
void DoDraw(shared_ptr<yg::gl::Screen> p)
|
||||
{
|
||||
p->drawText(m2::PointD(40, 50), 0, 20, "X", 1);
|
||||
p->drawText(m2::PointD(40, 50), 0, 20, yg::Color(0, 0, 0, 0), "X", true, yg::Color(255, 255, 255, 255), 1, false, true);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -541,7 +541,7 @@ namespace
|
|||
{
|
||||
void DoDraw(shared_ptr<yg::gl::Screen> p)
|
||||
{
|
||||
p->drawText(m2::PointD(40, 50), 0, 20, " ", 1);
|
||||
p->drawText(m2::PointD(40, 50), 0, 20, yg::Color(0, 0, 0, 0), " ", true, yg::Color(255, 255, 255, 255), 1, false, true);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -554,7 +554,7 @@ namespace
|
|||
|
||||
for (size_t i = 0; i < maxTimes; ++i)
|
||||
for (size_t j = 1; j <= i+1; ++j)
|
||||
p->drawText(m2::PointD(40, 10 + yStep * i), math::pi / 6, 20, "Simplicity is the ultimate sophistication", 0);
|
||||
p->drawText(m2::PointD(40, 10 + yStep * i), math::pi / 6, 20, yg::Color(0, 0, 0, 0), "Simplicity is the ultimate sophistication", true, yg::Color(255, 255, 255, 255), 0, false, true);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -570,7 +570,7 @@ namespace
|
|||
yg::PenInfo penInfo = yg::PenInfo(yg::Color(0, 0, 0, 0xFF), 2, &pat[0], ARRAY_SIZE(pat), 0);
|
||||
yg::PenInfo solidPenInfo = yg::PenInfo(yg::Color(0xFF, 0, 0, 0xFF), 4, 0, 0, 0);
|
||||
|
||||
p->drawText(m2::PointD(40, 50), 0, 20, "S", 0);
|
||||
p->drawText(m2::PointD(40, 50), 0, 20, yg::Color(0, 0, 0, 0), "S", true, yg::Color(255, 255, 255, 255), 0, false, true);
|
||||
p->drawPath(&path[0], path.size(), p->skin()->mapPenInfo(solidPenInfo), 0);
|
||||
|
||||
}
|
||||
|
@ -580,7 +580,7 @@ namespace
|
|||
{
|
||||
void DoDraw(shared_ptr<yg::gl::Screen> p)
|
||||
{
|
||||
p->drawText(m2::PointD(40, 50), 0/*, math::pi / 18*/, 20, "Simplicity is the ultimate sophistication", 0);
|
||||
p->drawText(m2::PointD(40, 50), 0/*, math::pi / 18*/, 20, yg::Color(0, 0, 0, 0), "Simplicity is the ultimate sophistication", true, yg::Color(255, 255, 255, 255), 0, false, true);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -588,16 +588,25 @@ namespace
|
|||
{
|
||||
void DoDraw(shared_ptr<yg::gl::Screen> p)
|
||||
{
|
||||
p->drawText(m2::PointD(40, 50), 0/*, math::pi / 18*/, 12, "Simplicity is the ultimate sophistication", 0, true);
|
||||
p->drawText(m2::PointD(40, 50), 0/*, math::pi / 18*/, 12, yg::Color(0, 0, 0, 0), "Simplicity is the ultimate sophistication", true, yg::Color(255, 255, 255, 255), 0, true, true);
|
||||
}
|
||||
};
|
||||
|
||||
struct TestDrawStringWithColor
|
||||
{
|
||||
void DoDraw(shared_ptr<yg::gl::Screen> p)
|
||||
{
|
||||
p->drawText(m2::PointD(40, 50), 0/*, math::pi / 18*/, 25, yg::Color(0, 0, 255, 255), "Simplicity is the ultimate sophistication", true, yg::Color(255, 255, 255, 255), 0, false, true);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct TestDrawUnicodeSymbols
|
||||
{
|
||||
void DoDraw(shared_ptr<yg::gl::Screen> p)
|
||||
{
|
||||
p->drawText(m2::PointD(40, 50), 0, 12, "Latin Symbol : A", 0);
|
||||
p->drawText(m2::PointD(40, 80), 0, 12, "Cyrillic Symbol : Ы", 0);
|
||||
p->drawText(m2::PointD(40, 50), 0, 12, yg::Color(0, 0, 0, 0), "Latin Symbol : A", true, yg::Color(255, 255, 255, 255), 0, false, true);
|
||||
p->drawText(m2::PointD(40, 80), 0, 12, yg::Color(0, 0, 0, 0), "Cyrillic Symbol : Ы", true, yg::Color(255, 255, 255, 255), 0, false, true);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -655,7 +664,7 @@ namespace
|
|||
void DoDraw(shared_ptr<yg::gl::Screen> p)
|
||||
{
|
||||
p->drawPath(&m_path[0], m_path.size(), p->skin()->mapPenInfo(m_penInfo), 0);
|
||||
p->drawPathText(&m_path[0], m_path.size(), 10, m_text, calc_length(m_path), 0.0, yg::gl::Screen::middle_line, true, 0);
|
||||
p->drawPathText(&m_path[0], m_path.size(), 10, yg::Color(0, 0, 0, 0), m_text, calc_length(m_path), 0.0, yg::gl::Screen::middle_line, true, yg::Color(255, 255, 255, 255), 0, false);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -666,8 +675,8 @@ namespace
|
|||
p->drawPath(&m_path[0], m_path.size(), p->skin()->mapPenInfo(m_penInfo), 0);
|
||||
|
||||
double const len = calc_length(m_path);
|
||||
p->drawPathText(&m_path[0], m_path.size(), 10, m_text, len, 0.0, yg::gl::Screen::above_line, true, 0);
|
||||
p->drawPathText(&m_path[0], m_path.size(), 10, m_text, len, 0.0, yg::gl::Screen::under_line, true, 0);
|
||||
p->drawPathText(&m_path[0], m_path.size(), 10, yg::Color(0, 0, 0, 0), m_text, len, 0.0, yg::gl::Screen::above_line, true, yg::Color(255, 255, 255, 255), 0, false);
|
||||
p->drawPathText(&m_path[0], m_path.size(), 10, yg::Color(0, 0, 0, 0), m_text, len, 0.0, yg::gl::Screen::under_line, true, yg::Color(255, 255, 255, 255), 0, false);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -681,7 +690,7 @@ namespace
|
|||
int startY = 30;
|
||||
for (size_t i = 0; i < sizesCount; ++i)
|
||||
{
|
||||
p->drawText(m2::PointD(10, startY), 0, startSize + i, "Simplicity is the ultimate sophistication. Leonardo Da Vinci", 0);
|
||||
p->drawText(m2::PointD(10, startY), 0, startSize + i, yg::Color(0, 0, 0, 0), "Simplicity is the ultimate sophistication. Leonardo Da Vinci", true, yg::Color(255, 255, 255, 255), 0, false, true);
|
||||
startY += startSize + i;
|
||||
}
|
||||
}
|
||||
|
@ -697,8 +706,8 @@ namespace
|
|||
int startY = 30;
|
||||
for (size_t i = 0; i < sizesCount; ++i)
|
||||
{
|
||||
p->drawText(m2::PointD(10, startY), 0, startSize/* + i*/, "Simplicity is the ultimate sophistication. Leonardo Da Vinci", 100);
|
||||
p->drawText(m2::PointD(5, startY + (startSize + i) / 2), 0, startSize/* + i*/, "This text should be filtered", 100);
|
||||
p->drawText(m2::PointD(10, startY), 0, startSize/* + i*/, yg::Color(0, 0, 0, 0), "Simplicity is the ultimate sophistication. Leonardo Da Vinci", true, yg::Color(255, 255, 255, 255), 100, false, true);
|
||||
p->drawText(m2::PointD(5, startY + (startSize + i) / 2), 0, startSize/* + i*/, yg::Color(0, 0, 0, 0), "This text should be filtered", true, yg::Color(255, 255, 255, 255), 100, false, true);
|
||||
startY += startSize + i;
|
||||
}
|
||||
}
|
||||
|
@ -720,8 +729,13 @@ namespace
|
|||
m2::PointD(rand() % 500, rand() % 500),
|
||||
0,
|
||||
rand() % (endSize - startSize) + startSize,
|
||||
yg::Color(rand() % 255, rand() % 255, rand() % 255, 255),
|
||||
texts[rand() % (sizeof(texts) / sizeof(char*))],
|
||||
rand() % 10);
|
||||
true,
|
||||
yg::Color(255, 255, 255, 255),
|
||||
rand() % 10,
|
||||
false,
|
||||
true);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -910,14 +924,15 @@ namespace
|
|||
// UNIT_TEST_GL(TestDrawSingleSymbolAndSolidPath);
|
||||
// UNIT_TEST_GL(TestDrawString);
|
||||
// UNIT_TEST_GL(TestDrawStringWithFixedFont);
|
||||
UNIT_TEST_GL(TestDrawUnicodeSymbols);
|
||||
UNIT_TEST_GL(TestDrawTextRectWithFixedFont);
|
||||
UNIT_TEST_GL(TestDrawStringWithColor);
|
||||
// UNIT_TEST_GL(TestDrawUnicodeSymbols);
|
||||
// UNIT_TEST_GL(TestDrawTextRectWithFixedFont);
|
||||
// UNIT_TEST_GL(TestDrawStringOnString);
|
||||
// UNIT_TEST_GL(TestDrawTextOnPath);
|
||||
// UNIT_TEST_GL(TestDrawTextOnPathWithOffset);
|
||||
// UNIT_TEST_GL(TestDrawTextOverflow);
|
||||
// UNIT_TEST_GL(TestDrawTextFiltering);
|
||||
// UNIT_TEST_GL(TestDrawRandomTextFiltering);
|
||||
UNIT_TEST_GL(TestDrawRandomTextFiltering);
|
||||
// UNIT_TEST_GL(TestDrawSGIConvex);
|
||||
// UNIT_TEST_GL(TestDrawPoly);
|
||||
// UNIT_TEST_GL(TestDrawSolidRect);
|
||||
|
|
Loading…
Add table
Reference in a new issue