Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drape/attribute_buffer_mutator.cpp16
-rw-r--r--drape/attribute_buffer_mutator.hpp7
-rw-r--r--drape_frontend/apply_feature_functors.cpp2
-rw-r--r--drape_frontend/drape_frontend.pro3
-rw-r--r--drape_frontend/intrusive_vector.hpp54
-rw-r--r--drape_frontend/path_text_shape.cpp490
-rw-r--r--drape_frontend/path_text_shape.hpp47
-rw-r--r--drape_frontend/text_layout.cpp315
-rw-r--r--drape_frontend/text_layout.hpp85
-rw-r--r--drape_frontend/text_shape.cpp321
-rw-r--r--drape_frontend/text_shape.hpp22
11 files changed, 810 insertions, 552 deletions
diff --git a/drape/attribute_buffer_mutator.cpp b/drape/attribute_buffer_mutator.cpp
index 465a25b78a..4554482385 100644
--- a/drape/attribute_buffer_mutator.cpp
+++ b/drape/attribute_buffer_mutator.cpp
@@ -3,9 +3,25 @@
namespace dp
{
+AttributeBufferMutator::~AttributeBufferMutator()
+{
+ SharedBufferManager & mng = SharedBufferManager::instance();
+ for (size_t i = 0; i < m_array.size(); ++i)
+ {
+ TBufferNode & node = m_array[i];
+ mng.freeSharedBuffer(node.second, node.first);
+ }
+}
+
void AttributeBufferMutator::AddMutation(BindingInfo const & info, MutateNode const & node)
{
m_data[info].push_back(node);
}
+void * AttributeBufferMutator::AllocateMutationBuffer(uint32_t byteCount)
+{
+ m_array.push_back(make_pair(SharedBufferManager::instance().reserveSharedBuffer(byteCount), byteCount));
+ return &((*m_array.back().first)[0]);
+}
+
} // namespace dp
diff --git a/drape/attribute_buffer_mutator.hpp b/drape/attribute_buffer_mutator.hpp
index 150defcd64..dfc77359e2 100644
--- a/drape/attribute_buffer_mutator.hpp
+++ b/drape/attribute_buffer_mutator.hpp
@@ -3,6 +3,8 @@
#include "pointers.hpp"
#include "binding_info.hpp"
+#include "../base/shared_buffer_manager.hpp"
+
#include "../std/stdint.hpp"
#include "../std/map.hpp"
@@ -26,10 +28,14 @@ struct MutateNode
class AttributeBufferMutator
{
+ typedef pair<SharedBufferManager::shared_buffer_ptr_t, size_t> TBufferNode;
+ typedef vector<TBufferNode> TBufferArray;
typedef vector<MutateNode> TMutateNodes;
typedef map<BindingInfo, TMutateNodes> TMutateData;
public:
+ ~AttributeBufferMutator();
void AddMutation(BindingInfo const & info, MutateNode const & node);
+ void * AllocateMutationBuffer(uint32_t byteCount);
private:
friend class VertexArrayBuffer;
@@ -37,6 +43,7 @@ private:
private:
TMutateData m_data;
+ TBufferArray m_array;
};
} // namespace dp
diff --git a/drape_frontend/apply_feature_functors.cpp b/drape_frontend/apply_feature_functors.cpp
index 11cb6e3584..90eadde06c 100644
--- a/drape_frontend/apply_feature_functors.cpp
+++ b/drape_frontend/apply_feature_functors.cpp
@@ -312,7 +312,7 @@ void ApplyLineFeature::ProcessRule(Stylist::rule_wrapper_t const & rule)
params.m_text = m_captions.GetPathName();
params.m_textFont = fontDecl;
- m_context.InsertShape(m_tileKey, dp::MovePointer<MapShape>(new PathTextShape(m_spline, params)));
+ m_context.InsertShape(m_tileKey, dp::MovePointer<MapShape>(new PathTextShape(m_spline, params, m_currentScaleGtoP)));
}
if (pLineRule != NULL)
diff --git a/drape_frontend/drape_frontend.pro b/drape_frontend/drape_frontend.pro
index 3c68f6d5a1..2d0b842ef8 100644
--- a/drape_frontend/drape_frontend.pro
+++ b/drape_frontend/drape_frontend.pro
@@ -38,6 +38,7 @@ SOURCES += \
path_text_shape.cpp \
path_symbol_shape.cpp \
common_structures.cpp \
+ text_layout.cpp
HEADERS += \
engine_context.hpp \
@@ -72,3 +73,5 @@ HEADERS += \
path_symbol_shape.hpp \
common_structures.hpp \
fribidi.hpp \
+ text_layout.hpp \
+ intrusive_vector.hpp
diff --git a/drape_frontend/intrusive_vector.hpp b/drape_frontend/intrusive_vector.hpp
new file mode 100644
index 0000000000..30e5fad580
--- /dev/null
+++ b/drape_frontend/intrusive_vector.hpp
@@ -0,0 +1,54 @@
+#pragma once
+
+#include "../base/assert.hpp"
+
+#include "../std/stdint.hpp"
+
+namespace df
+{
+
+enum FillDirection
+{
+ Forward,
+ Backward
+};
+
+template <typename T>
+class IntrusiveVector
+{
+public:
+ IntrusiveVector(void * memoryBuffer, uint32_t byteCount)
+ : m_memory(reinterpret_cast<T *>(memoryBuffer))
+ , m_direction(Forward)
+ {
+ ASSERT(byteCount % sizeof(T) == 0, ());
+ m_capacity = byteCount / sizeof(T);
+ m_size = 0;
+ }
+
+ void SetFillDirection(FillDirection direction)
+ {
+ ASSERT(m_size == 0, ());
+ m_direction = direction;
+ }
+
+ void PushBack(T const & value)
+ {
+ ASSERT(m_size < m_capacity, ());
+ if (m_direction == Forward)
+ m_memory[m_size++] = value;
+ else
+ {
+ m_memory[m_capacity - m_size - 1] = value;
+ m_size++;
+ }
+ }
+
+private:
+ T * m_memory;
+ FillDirection m_direction;
+ uint32_t m_capacity;
+ uint32_t m_size;
+};
+
+}
diff --git a/drape_frontend/path_text_shape.cpp b/drape_frontend/path_text_shape.cpp
index 83ed02bfe3..a3101b2dda 100644
--- a/drape_frontend/path_text_shape.cpp
+++ b/drape_frontend/path_text_shape.cpp
@@ -1,4 +1,7 @@
#include "path_text_shape.hpp"
+#include "text_layout.hpp"
+#include "visual_params.hpp"
+#include "intrusive_vector.hpp"
#include "../drape/shader_def.hpp"
#include "../drape/attribute_provider.hpp"
@@ -18,332 +21,257 @@
#include "../std/algorithm.hpp"
#include "../std/vector.hpp"
-namespace df
-{
-
-using m2::PointF;
using m2::Spline;
using glsl_types::vec2;
-using glsl_types::vec4;
namespace
{
- static float const realFontSize = 28.0f;
-
- struct Buffer
+ struct AccumulateRect
{
- vector<vec2> m_pos;
- vector<vec4> m_uvs;
- vector<vec4> m_baseColor;
- vector<vec4> m_outlineColor;
- vector<LetterInfo> m_info;
- float m_offset;
- float m_maxSize;
-
- void addSizes(float x, float y)
+ ScreenBase const & m_screen;
+ m2::RectD m_pixelRect;
+ AccumulateRect(ScreenBase const & screen)
+ : m_screen(screen)
{
- if (x > m_maxSize)
- m_maxSize = x;
- if (y > m_maxSize)
- m_maxSize = y;
}
- };
-}
-
-PathTextShape::PathTextShape(m2::SharedSpline const & spline, PathTextViewParams const & params)
- : m_spline(spline)
- , m_params(params)
-{
-}
-void PathTextShape::Draw(dp::RefPointer<dp::Batcher> batcher, dp::RefPointer<dp::TextureSetHolder> textures) const
-{
- strings::UniString const text = strings::MakeUniString(m_params.m_text);
- float const fontSize = m_params.m_textFont.m_size;
+ void operator()(m2::PointF const & pt)
+ {
+ m_pixelRect.Add(m_screen.GtoP(pt));
+ }
- // Fill buffers
- int const cnt = text.size();
- vector<Buffer> buffers(1);
- float const needOutline = m_params.m_textFont.m_needOutline;
- float length = 0.0f;
+ };
- int textureSet;
- for (int i = 0; i < cnt; i++)
+ class PathTextHandle : public dp::OverlayHandle
{
- dp::TextureSetHolder::GlyphRegion region;
- textures->GetGlyphRegion(text[i], region);
- float xOffset, yOffset, advance;
- m2::PointU pixelSize;
- region.GetMetrics(xOffset, yOffset, advance);
- region.GetPixelSize(pixelSize);
- float halfWidth = pixelSize.x / 2.0f;
- float halfHeight = pixelSize.y / 2.0f;
- float const aspect = fontSize / realFontSize;
-
- textureSet = region.GetTextureNode().m_textureSet;
- if (buffers.size() < textureSet)
- buffers.resize(textureSet + 1);
-
- Buffer & curBuffer = buffers[textureSet];
-
- yOffset *= aspect;
- xOffset *= aspect;
- halfWidth *= aspect;
- halfHeight *= aspect;
- advance *= aspect;
- length += advance;
-
- curBuffer.addSizes(halfWidth, halfHeight);
+ public:
+ static const uint8_t PathGlyphPositionID = 1;
+
+ PathTextHandle(m2::SharedSpline const & spl,
+ df::SharedTextLayout const & layout,
+ float const mercatorOffset,
+ float const depth)
+ : OverlayHandle(FeatureID(), dp::Center, depth)
+ , m_spline(spl)
+ , m_layout(layout)
+ , m_splineOffset(mercatorOffset)
+ {
+ }
- curBuffer.m_info.push_back(
- LetterInfo(xOffset, yOffset, advance + curBuffer.m_offset, halfWidth, halfHeight));
+ void Update(ScreenBase const & screen)
+ {
+ m_scalePtoG = screen.GetScale();
+ GetBegEnd(m_begin, m_end);
- for (int i = 0; i < buffers.size(); ++i)
- buffers[i].m_offset += advance;
+ SetIsValid(!m_begin.BeginAgain() && !m_end.BeginAgain());
+ if (!IsValid())
+ return;
- curBuffer.m_offset = 0;
+ if (screen.GtoP(m_end.m_pos).x < screen.GtoP(m_begin.m_pos).x)
+ m_isForward = false;
+ else
+ m_isForward = true;
+ }
+ m2::RectD GetPixelRect(ScreenBase const & screen) const
+ {
+ ASSERT(IsValid(), ());
+ ASSERT(!m_begin.BeginAgain(), ());
+ ASSERT(!m_end.BeginAgain(), ());
+
+ AccumulateRect f(screen);
+ m_spline->ForEachNode(m_begin, m_end, f);
+ float const pixelHeight = m_layout->GetPixelHeight();
+ f.m_pixelRect.Inflate(2 * pixelHeight, 2 * pixelHeight);
+ return f.m_pixelRect;
+ }
- m2::RectF const & rect = region.GetTexRect();
- float const textureNum = (region.GetTextureNode().m_textureOffset << 1) + needOutline;
+ void GetAttributeMutation(dp::RefPointer<dp::AttributeBufferMutator> mutator) const
+ {
+ ASSERT(IsValid(), ());
+ uint32_t byteCount = 4 * m_layout->GetGlyphCount() * sizeof(glsl_types::vec2);
+ void * buffer = mutator->AllocateMutationBuffer(byteCount);
+ df::IntrusiveVector<glsl_types::vec2> positions(buffer, byteCount);
+ // m_splineOffset set offset to Center of text.
+ // By this we calc offset for start of text in mercator
+ m_layout->LayoutPathText(m_begin, m_scalePtoG, positions, m_isForward);
+
+ TOffsetNode const & node = GetOffsetNode(PathGlyphPositionID);
+ dp::MutateNode mutateNode;
+ mutateNode.m_region = node.second;
+ mutateNode.m_data = dp::MakeStackRefPointer<void>(buffer);
+ mutator->AddMutation(node.first, mutateNode);
+ }
- dp::ColorF const base(m_params.m_textFont.m_color);
- dp::ColorF const outline(m_params.m_textFont.m_outlineColor);
+ private:
+ void GetBegEnd(Spline::iterator & beg, Spline::iterator & end) const
+ {
+ beg = m_spline.CreateIterator();
+ end = m_spline.CreateIterator();
+ float const textLangth = m_layout->GetPixelLength() * m_scalePtoG;
+ float const step = max(0.0f, m_splineOffset - textLangth / 2.0f);
+ if (step > 0.0f)
+ beg.Step(step);
+ end.Step(step + textLangth);
+ }
- curBuffer.m_uvs.push_back(vec4(rect.minX(), rect.maxY(), textureNum, m_params.m_depth));
- curBuffer.m_uvs.push_back(vec4(rect.minX(), rect.minY(), textureNum, m_params.m_depth));
- curBuffer.m_uvs.push_back(vec4(rect.maxX(), rect.maxY(), textureNum, m_params.m_depth));
- curBuffer.m_uvs.push_back(vec4(rect.maxX(), rect.minY(), textureNum, m_params.m_depth));
+ private:
+ m2::SharedSpline m_spline;
+ m2::Spline::iterator m_begin;
+ m2::Spline::iterator m_end;
- int const newSize = curBuffer.m_baseColor.size() + 4;
- curBuffer.m_baseColor.resize(newSize, base);
- curBuffer.m_outlineColor.resize(newSize, outline);
- curBuffer.m_pos.resize(newSize, vec2(0.0f, 0.0f));
- }
+ df::SharedTextLayout m_layout;
+ float m_scalePtoG;
+ float m_splineOffset;
+ bool m_isForward;
+ };
- for (int i = 0; i < buffers.size(); ++i)
+ void BatchPathText(m2::SharedSpline const & spline,
+ buffer_vector<float, 32> const & offsets,
+ float depth,
+ dp::RefPointer<dp::Batcher> batcher,
+ df::SharedTextLayout const & layout,
+ vector<glsl_types::vec2> & positions,
+ vector<glsl_types::Quad4> & texCoord,
+ vector<glsl_types::Quad4> & fontColor,
+ vector<glsl_types::Quad4> & outlineColor)
{
- if (buffers[i].m_pos.empty())
- continue;
+ ASSERT(!offsets.empty(), ());
+ layout->InitPathText(depth, texCoord, fontColor, outlineColor);
dp::GLState state(gpu::PATH_FONT_PROGRAM, dp::GLState::OverlayLayer);
- state.SetTextureSet(i);
+ state.SetTextureSet(layout->GetTextureSet());
state.SetBlending(dp::Blending(true));
- dp::AttributeProvider provider(4, buffers[i].m_pos.size());
- {
- dp::BindingInfo position(1, PathTextHandle::DirectionAttributeID);
- dp::BindingDecl & decl = position.GetBindingDecl(0);
- decl.m_attributeName = "a_position";
- decl.m_componentCount = 2;
- decl.m_componentType = gl_const::GLFloatType;
- decl.m_offset = 0;
- decl.m_stride = 0;
- provider.InitStream(0, position, dp::MakeStackRefPointer(&buffers[i].m_pos[0]));
- }
+ for (size_t i = 0; i < offsets.size(); ++i)
{
- dp::BindingInfo texcoord(1);
- dp::BindingDecl & decl = texcoord.GetBindingDecl(0);
- decl.m_attributeName = "a_texcoord";
- decl.m_componentCount = 4;
- decl.m_componentType = gl_const::GLFloatType;
- decl.m_offset = 0;
- decl.m_stride = 0;
- provider.InitStream(1, texcoord, dp::MakeStackRefPointer(&buffers[i].m_uvs[0]));
+ dp::AttributeProvider provider(4, 4 * layout->GetGlyphCount());
+ {
+ dp::BindingInfo positionBind(1, PathTextHandle::PathGlyphPositionID);
+ dp::BindingDecl & decl = positionBind.GetBindingDecl(0);
+ decl.m_attributeName = "a_position";
+ decl.m_componentCount = 2;
+ decl.m_componentType = gl_const::GLFloatType;
+ decl.m_offset = 0;
+ decl.m_stride = 0;
+ provider.InitStream(0, positionBind, dp::MakeStackRefPointer(&positions[0]));
+ }
+ {
+ dp::BindingInfo texCoordBind(1);
+ dp::BindingDecl & decl = texCoordBind.GetBindingDecl(0);
+ decl.m_attributeName = "a_texcoord";
+ decl.m_componentCount = 4;
+ decl.m_componentType = gl_const::GLFloatType;
+ decl.m_offset = 0;
+ decl.m_stride = 0;
+ provider.InitStream(1, texCoordBind, dp::MakeStackRefPointer(&texCoord[0]));
+ }
+ {
+ dp::BindingInfo fontColorBind(1);
+ dp::BindingDecl & decl = fontColorBind.GetBindingDecl(0);
+ decl.m_attributeName = "a_color";
+ decl.m_componentCount = 4;
+ decl.m_componentType = gl_const::GLFloatType;
+ decl.m_offset = 0;
+ decl.m_stride = 0;
+ provider.InitStream(2, fontColorBind, dp::MakeStackRefPointer(&fontColor[0]));
+ }
+ {
+ dp::BindingInfo outlineColorBind(1);
+ dp::BindingDecl & decl = outlineColorBind.GetBindingDecl(0);
+ decl.m_attributeName = "a_outline_color";
+ decl.m_componentCount = 4;
+ decl.m_componentType = gl_const::GLFloatType;
+ decl.m_offset = 0;
+ decl.m_stride = 0;
+ provider.InitStream(3, outlineColorBind, dp::MakeStackRefPointer(&outlineColor[0]));
+ }
+
+ dp::OverlayHandle * handle = new PathTextHandle(spline, layout, offsets[i], depth);
+ batcher->InsertListOfStrip(state, dp::MakeStackRefPointer(&provider), dp::MovePointer(handle), 4);
}
- {
- dp::BindingInfo base_color(1);
- dp::BindingDecl & decl = base_color.GetBindingDecl(0);
- decl.m_attributeName = "a_color";
- decl.m_componentCount = 4;
- decl.m_componentType = gl_const::GLFloatType;
- decl.m_offset = 0;
- decl.m_stride = 0;
- provider.InitStream(2, base_color, dp::MakeStackRefPointer(&buffers[i].m_baseColor[0]));
- }
- {
- dp::BindingInfo outline_color(1);
- dp::BindingDecl & decl = outline_color.GetBindingDecl(0);
- decl.m_attributeName = "a_outline_color";
- decl.m_componentCount = 4;
- decl.m_componentType = gl_const::GLFloatType;
- decl.m_offset = 0;
- decl.m_stride = 0;
- provider.InitStream(3, outline_color, dp::MakeStackRefPointer(&buffers[i].m_outlineColor[0]));
- }
-
- dp::OverlayHandle * handle = new PathTextHandle(m_spline, m_params, buffers[i].m_info, buffers[i].m_maxSize, length);
-
- batcher->InsertListOfStrip(state, dp::MakeStackRefPointer(&provider), dp::MovePointer(handle), 4);
}
}
-m2::RectD PathTextHandle::GetPixelRect(ScreenBase const & screen) const
+namespace df
{
- int const cnt = m_infos.size();
-
- vec2 const & v1 = m_positions[1];
- vec2 const & v2 = m_positions[2];
- PointF centr((v1.x + v2.x) / 2.0f, (v1.y + v2.y) / 2.0f);
- centr = screen.GtoP(centr);
- float minx, maxx, miny, maxy;
- minx = maxx = centr.x;
- miny = maxy = centr.y;
- for (int i = 1; i < cnt; i++)
- {
- vec2 const & v1 = m_positions[i * 4 + 1];
- vec2 const & v2 = m_positions[i * 4 + 2];
- PointF centr((v1.x + v2.x) / 2.0f, (v1.y + v2.y) / 2.0f);
- centr = screen.GtoP(centr);
- if(centr.x > maxx)
- maxx = centr.x;
- if(centr.x < minx)
- minx = centr.x;
- if(centr.y > maxy)
- maxy = centr.y;
- if(centr.y < miny)
- miny = centr.y;
- }
-
- return m2::RectD(minx - m_maxSize, miny - m_maxSize, maxx + m_maxSize, maxy + m_maxSize);
-}
-
-PathTextHandle::PathTextHandle(m2::SharedSpline const & spl, PathTextViewParams const & params,
- vector<LetterInfo> const & info, float maxSize, float textLength)
- : OverlayHandle(FeatureID()
- , dp::Center, 0.0f)
- , m_path(spl)
+PathTextShape::PathTextShape(m2::SharedSpline const & spline,
+ PathTextViewParams const & params,
+ float const scaleGtoP)
+ : m_spline(spline)
, m_params(params)
- , m_infos(info)
- , m_scaleFactor(1.0f)
- , m_positions(info.size() * 4)
- , m_maxSize(maxSize)
- , m_textLength(textLength)
+ , m_scaleGtoP(scaleGtoP)
{
}
-void PathTextHandle::Update(ScreenBase const & screen)
+void PathTextShape::Draw(dp::RefPointer<dp::Batcher> batcher, dp::RefPointer<dp::TextureSetHolder> textures) const
{
- switch(ChooseDirection(screen))
+ SharedTextLayout layout(new TextLayout(strings::MakeUniString(m_params.m_text),
+ m_params.m_textFont,
+ textures));
+
+ //we leave a little space on either side of the text that would
+ //remove the comparison for equality of spline portions
+ float const TextBorder = 4.0f;
+ float const textLength = TextBorder + layout->GetPixelLength();
+ float const textHalfLength = textLength / 2.0f;
+ float const pathGlbLength = m_spline->GetLength();
+
+ // on next readable scale m_scaleGtoP will be twice
+ if (textLength > pathGlbLength * 2 * m_scaleGtoP)
+ return;
+
+ float const pathLength = m_scaleGtoP * m_spline->GetLength();
+
+ /// copied from old code
+ /// @todo Choose best constant for minimal space.
+ float const etalonEmpty = max(200 * df::VisualParams::Instance().GetVisualScale(), (double)textLength);
+ float const minPeriodSize = etalonEmpty + textLength;
+ float const twoTextAndEmpty = minPeriodSize + textLength;
+
+ uint32_t glyphCount = layout->GetGlyphCount();
+ vector<glsl_types::vec2> positions(glyphCount, vec2(0.0, 0.0));
+ vector<glsl_types::Quad4> texCoords(glyphCount);
+ vector<glsl_types::Quad4> fontColor(glyphCount);
+ vector<glsl_types::Quad4> outlineColor(glyphCount);
+ buffer_vector<float, 32> offsets;
+
+ float const scalePtoG = 1.0f / m_scaleGtoP;
+
+ if (pathLength < twoTextAndEmpty)
{
- case -1:
- DrawReverse(screen);
- break;
- case 0:
- ClearPositions();
- break;
- case 1:
- DrawForward(screen);
- break;
- }
-}
-
-int PathTextHandle::ChooseDirection(ScreenBase const & screen)
-{
- m_scaleFactor = screen.GetScale();
- Spline::iterator itr = m_path.CreateIterator();
- itr.Step(m_params.m_offsetStart * m_scaleFactor);
- PointF const p1 = screen.GtoP(itr.m_pos);
- itr.Step(m_textLength * m_scaleFactor);
- PointF const p2 = screen.GtoP(itr.m_pos);
- if (itr.BeginAgain())
- return 0;
-
- if ((p2 - p1).x >= 0 )
- return 1;
- else
- return -1;
-}
+ // if we can't place 2 text and empty part on path
+ // we place only one text on center of path
+ offsets.push_back(pathGlbLength / 2.0f);
-void PathTextHandle::ClearPositions()
-{
- std::fill(m_positions.begin(), m_positions.end(), vec2(0.0f, 0.0f));
-}
-
-void PathTextHandle::DrawReverse(ScreenBase const & screen)
-{
- m_scaleFactor = screen.GetScale();
- int const cnt = m_infos.size();
- Spline::iterator itr = m_path.CreateIterator();
- itr.Step(m_params.m_offsetStart * m_scaleFactor);
-
- for (int i = cnt - 1; i >= 0; i--)
+ }
+ else if (pathLength < twoTextAndEmpty + minPeriodSize)
{
- float const advance = m_infos[i].m_advance * m_scaleFactor;
- float const halfWidth = m_infos[i].m_halfWidth;
- float const halfHeight = m_infos[i].m_halfHeight;
- float const xOffset = m_infos[i].m_xOffset + halfWidth;
- float const yOffset = m_infos[i].m_yOffset + halfHeight;
-
- ASSERT_NOT_EQUAL(advance, 0.0, ());
- PointF const pos = itr.m_pos;
- itr.Step(advance);
- ASSERT(!itr.BeginAgain(), ());
-
- PointF dir = itr.m_avrDir.Normalize();
- PointF norm(-dir.y, dir.x);
- PointF norm2 = norm;
- dir *= halfWidth * m_scaleFactor;
- norm *= halfHeight * m_scaleFactor;
-
- float const fontSize = m_params.m_textFont.m_size * m_scaleFactor / 2.0f;
- PointF const pivot = dir * xOffset / halfWidth + norm * yOffset / halfHeight + pos + norm2 * fontSize;
-
- int index = i * 4;
- m_positions[index++] = pivot + dir + norm;
- m_positions[index++] = pivot + dir - norm;
- m_positions[index++] = pivot - dir + norm;
- m_positions[index++] = pivot - dir - norm;
+ // if we can't place 3 text and 2 empty path
+ // we place 2 text with empty space beetwen
+ // and some offset from path end
+ float const endOffset = (pathLength - (2 * textLength + etalonEmpty)) / 2;
+
+ // division on m_scaleGtoP give as global coord frame (Mercator)
+ offsets.push_back((endOffset + textHalfLength) * scalePtoG);
+ offsets.push_back((pathLength - (textHalfLength + endOffset)) * scalePtoG);
}
-}
-
-void PathTextHandle::DrawForward(ScreenBase const & screen)
-{
- m_scaleFactor = screen.GetScale();
- int const cnt = m_infos.size();
- Spline::iterator itr = m_path.CreateIterator();
- itr.Step(m_params.m_offsetStart * m_scaleFactor);
-
- for (int i = 0; i < cnt; i++)
+ else
{
- float const advance = m_infos[i].m_advance * m_scaleFactor;
- float const halfWidth = m_infos[i].m_halfWidth;
- float const halfHeight = m_infos[i].m_halfHeight;
- /// TODO Can be optimized later (filling stage)
- float const xOffset = m_infos[i].m_xOffset + halfWidth;
- float const yOffset = -m_infos[i].m_yOffset - halfHeight;
-
- ASSERT_NOT_EQUAL(advance, 0.0, ());
- PointF const pos = itr.m_pos;
- itr.Step(advance);
- ASSERT(!itr.BeginAgain(), ());
-
- PointF dir = itr.m_avrDir.Normalize();
- PointF norm(-dir.y, dir.x);
- PointF norm2 = norm;
- dir *= halfWidth * m_scaleFactor;
- norm *= halfHeight * m_scaleFactor;
-
- float const fontSize = m_params.m_textFont.m_size * m_scaleFactor / 2.0f;
- PointF const pivot = dir * xOffset / halfWidth + norm * yOffset / halfHeight + pos - norm2 * fontSize;
-
- int index = i * 4;
- m_positions[index++] = pivot - dir - norm;
- m_positions[index++] = pivot - dir + norm;
- m_positions[index++] = pivot + dir - norm;
- m_positions[index++] = pivot + dir + norm;
+ // here we place 2 text on the ends of path
+ // then we place as much as possible text on center path uniformly
+ offsets.push_back(textHalfLength * scalePtoG);
+ offsets.push_back((pathLength - textHalfLength) * scalePtoG);
+ float const emptySpace = pathLength - 2 * textLength;
+ uint32_t textCount = static_cast<uint32_t>(ceil(emptySpace / minPeriodSize));
+ float const offset = (emptySpace - textCount * textLength) / (textCount + 1);
+ for (size_t i = 0; i < textCount; ++i)
+ offsets.push_back((textHalfLength + (textLength + offset) * (i + 1)) * scalePtoG);
}
-}
-
-void PathTextHandle::GetAttributeMutation(dp::RefPointer<dp::AttributeBufferMutator> mutator) const
-{
- TOffsetNode const & node = GetOffsetNode(DirectionAttributeID);
- dp::MutateNode mutateNode;
- mutateNode.m_region = node.second;
- mutateNode.m_data = dp::MakeStackRefPointer<void>(&m_positions[0]);
- mutator->AddMutation(node.first, mutateNode);
+ BatchPathText(m_spline, offsets, m_params.m_depth, batcher, layout,
+ positions, texCoords, fontColor, outlineColor);
}
}
diff --git a/drape_frontend/path_text_shape.hpp b/drape_frontend/path_text_shape.hpp
index 5b40ef638e..3921ed6132 100644
--- a/drape_frontend/path_text_shape.hpp
+++ b/drape_frontend/path_text_shape.hpp
@@ -14,57 +14,18 @@
namespace df
{
-using m2::PointF;
-
-struct LetterInfo
-{
- LetterInfo(float xOff, float yOff, float adv, float hw, float hh)
- : m_xOffset(xOff), m_yOffset(yOff), m_advance(adv),
- m_halfWidth(hw), m_halfHeight(hh){}
-
- LetterInfo(){}
-
- float m_xOffset;
- float m_yOffset;
- float m_advance;
- float m_halfWidth;
- float m_halfHeight;
-};
-
class PathTextShape : public MapShape
{
public:
- PathTextShape(m2::SharedSpline const & spline, PathTextViewParams const & params);
+ PathTextShape(m2::SharedSpline const & spline,
+ PathTextViewParams const & params,
+ float const scaleGtoP);
virtual void Draw(dp::RefPointer<dp::Batcher> batcher, dp::RefPointer<dp::TextureSetHolder> textures) const;
private:
m2::SharedSpline m_spline;
PathTextViewParams m_params;
-};
-
-class PathTextHandle : public dp::OverlayHandle
-{
-public:
- static const uint8_t DirectionAttributeID = 1;
- PathTextHandle(m2::SharedSpline const & spl, PathTextViewParams const & params,
- vector<LetterInfo> const & info, float maxSize, float textLength);
-
- virtual void Update(ScreenBase const & screen);
- void DrawReverse(ScreenBase const & screen);
- void DrawForward(ScreenBase const & screen);
- void ClearPositions();
- int ChooseDirection(ScreenBase const & screen);
- virtual m2::RectD GetPixelRect(ScreenBase const & screen) const;
- virtual void GetAttributeMutation(dp::RefPointer<dp::AttributeBufferMutator> mutator) const;
-
-private:
- m2::SharedSpline m_path;
- PathTextViewParams m_params;
- vector<LetterInfo> m_infos;
- float m_scaleFactor;
- mutable vector<glsl_types::vec2> m_positions;
- float m_maxSize;
- float m_textLength;
+ float const m_scaleGtoP;
};
} // namespace df
diff --git a/drape_frontend/text_layout.cpp b/drape_frontend/text_layout.cpp
new file mode 100644
index 0000000000..62d9f98287
--- /dev/null
+++ b/drape_frontend/text_layout.cpp
@@ -0,0 +1,315 @@
+#include "text_layout.hpp"
+
+#include "../std/numeric.hpp"
+#include "../std/algorithm.hpp"
+#include "../std/bind.hpp"
+
+using glsl_types::vec4;
+using glsl_types::Quad4;
+
+namespace
+{
+ void FillColor(vector<Quad4> & data, dp::Color const & color)
+ {
+ Quad4 c;
+ c.v[0] = c.v[1] = c.v[2] = c.v[3] = vec4(dp::ColorF(color));
+ fill(data.begin(), data.end(), c);
+ }
+}
+
+namespace df
+{
+
+class StraightTextHandle : public dp::OverlayHandle
+{
+public:
+ StraightTextHandle(FeatureID const & id, m2::PointD const & pivot,
+ m2::PointD const & pxSize, m2::PointD const & offset,
+ double priority)
+ : OverlayHandle(id, dp::LeftBottom, priority)
+ , m_pivot(pivot)
+ , m_offset(offset)
+ , m_size(pxSize)
+ {
+ }
+
+ m2::RectD GetPixelRect(ScreenBase const & screen) const
+ {
+ m2::PointD const pivot = screen.GtoP(m_pivot) + m_offset;
+ return m2::RectD(pivot, pivot + m_size);
+ }
+
+private:
+ m2::PointD m_pivot;
+ m2::PointD m_offset;
+ m2::PointD m_size;
+};
+
+namespace
+{
+
+#ifdef DEBUG
+ void ValidateTextureSet(buffer_vector<dp::TextureSetHolder::GlyphRegion, 32> const & metrics)
+ {
+ if (metrics.size() < 2)
+ return;
+
+ ASSERT(metrics[0].IsValid(), ());
+ uint32_t textureSet = metrics[0].GetTextureNode().m_textureSet;
+ for (size_t i = 1; i < metrics.size(); ++i)
+ {
+ ASSERT(metrics[i].IsValid(), ());
+ ASSERT_EQUAL(metrics[i].GetTextureNode().m_textureSet, textureSet, ());
+ }
+ }
+#endif
+
+ float const BASE_HEIGHT = 28.0f;
+}
+
+TextLayout::TextLayout(strings::UniString const & string,
+ df::FontDecl const & font,
+ dp::RefPointer<dp::TextureSetHolder> textures)
+ : m_font(font)
+ , m_textSizeRatio(font.m_size / BASE_HEIGHT)
+{
+ ASSERT(!string.empty(), ());
+ m_metrics.reserve(string.size());
+ for_each(string.begin(), string.end(), bind(&TextLayout::InitMetric, this, _1, textures));
+#ifdef DEBUG
+ ValidateTextureSet(m_metrics);
+#endif
+}
+
+dp::OverlayHandle * TextLayout::LayoutText(const FeatureID & featureID,
+ m2::PointF const & pivot,
+ m2::PointF const & pixelOffset,
+ float depth,
+ vector<Quad4> & positions,
+ vector<Quad4> & texCoord,
+ vector<Quad4> & fontColor,
+ vector<Quad4> & outlineColor) const
+{
+ STATIC_ASSERT(sizeof(vec4) == 4 * sizeof(float));
+ STATIC_ASSERT(sizeof(Quad4) == 4 * sizeof(vec4));
+
+ size_t glyphCount = GetGlyphCount();
+ ASSERT(glyphCount <= positions.size(), ());
+ ASSERT(glyphCount <= texCoord.size(), ());
+ ASSERT(glyphCount <= fontColor.size(), ());
+ ASSERT(glyphCount <= outlineColor.size(), ());
+
+ FillColor(fontColor, m_font.m_color);
+ FillColor(outlineColor, m_font.m_outlineColor);
+
+ float glyphOffset = 0.0;
+ for (size_t i = 0; i < glyphCount; ++i)
+ {
+ GlyphRegion const & region = m_metrics[i];
+ ASSERT(region.IsValid(), ());
+ GetTextureQuad(region, depth, texCoord[i]);
+
+ float xOffset, yOffset, advance;
+ region.GetMetrics(xOffset, yOffset, advance);
+
+ xOffset *= m_textSizeRatio;
+ yOffset *= m_textSizeRatio;
+ advance *= m_textSizeRatio;
+
+ m2::PointU size;
+ region.GetPixelSize(size);
+ double const h = size.y * m_textSizeRatio;
+ double const w = size.x * m_textSizeRatio;
+
+ Quad4 & position = positions[i];
+ position.v[0] = vec4(pivot, m2::PointF(glyphOffset + xOffset, yOffset) + pixelOffset);
+ position.v[1] = vec4(pivot, m2::PointF(glyphOffset + xOffset, yOffset + h) + pixelOffset);
+ position.v[2] = vec4(pivot, m2::PointF(glyphOffset + w + xOffset, yOffset) + pixelOffset);
+ position.v[3] = vec4(pivot, m2::PointF(glyphOffset + w + xOffset, yOffset + h) + pixelOffset);
+ glyphOffset += advance;
+ }
+
+ return new StraightTextHandle(featureID, pivot, m2::PointD(glyphOffset, m_font.m_size),
+ pixelOffset, depth);
+}
+
+void TextLayout::InitPathText(float depth,
+ vector<glsl_types::Quad4> & texCoord,
+ vector<glsl_types::Quad4> & fontColor,
+ vector<glsl_types::Quad4> & outlineColor) const
+{
+ STATIC_ASSERT(sizeof(vec4) == 4 * sizeof(float));
+ STATIC_ASSERT(sizeof(Quad4) == 4 * sizeof(vec4));
+
+ size_t glyphCount = GetGlyphCount();
+ ASSERT(glyphCount <= texCoord.size(), ());
+ ASSERT(glyphCount <= fontColor.size(), ());
+ ASSERT(glyphCount <= outlineColor.size(), ());
+
+ FillColor(fontColor, m_font.m_color);
+ FillColor(outlineColor, m_font.m_outlineColor);
+
+ for (size_t i = 0; i < glyphCount; ++i)
+ GetTextureQuad(m_metrics[i], depth, texCoord[i]);
+}
+
+void TextLayout::LayoutPathText(m2::Spline::iterator const & iterator,
+ float const scalePtoG,
+ IntrusiveVector<glsl_types::vec2> & positions,
+ bool isForwardDirection) const
+{
+ if (!isForwardDirection)
+ positions.SetFillDirection(df::Backward);
+
+ m2::Spline::iterator itr = iterator;
+
+ uint32_t glyphCount = GetGlyphCount();
+ int32_t startIndex = isForwardDirection ? 0 : glyphCount - 1;
+ int32_t endIndex = isForwardDirection ? glyphCount : -1;
+ int32_t incSign = isForwardDirection ? 1 : -1;
+
+ for (int32_t i = startIndex; i != endIndex; i += incSign)
+ {
+ float xOffset, yOffset, advance;
+ float halfWidth, halfHeight;
+ GetMetrics(i, xOffset, yOffset, advance, halfWidth, halfHeight);
+ advance *= scalePtoG;
+
+ ASSERT_NOT_EQUAL(advance, 0.0, ());
+ m2::PointF const pos = itr.m_pos;
+ itr.Step(advance);
+ ASSERT(!itr.BeginAgain(), ());
+
+ m2::PointF dir = itr.m_avrDir.Normalize();
+ m2::PointF norm(-dir.y, dir.x);
+ m2::PointF norm2 = norm;
+ dir *= halfWidth * scalePtoG;
+ norm *= halfHeight * scalePtoG;
+
+ float const halfFontSize = m_textSizeRatio * scalePtoG / 2.0f;
+ m2::PointF const dirComponent = dir * xOffset / halfWidth;
+ m2::PointF const normalComponent = -norm * incSign * yOffset / halfHeight;
+ m2::PointF const fontSizeComponent = norm2 * incSign * halfFontSize;
+ m2::PointF const pivot = dirComponent + normalComponent + pos - fontSizeComponent;
+
+ positions.PushBack(glsl_types::vec2(pivot - dir + norm));
+ positions.PushBack(glsl_types::vec2(pivot - dir - norm));
+ positions.PushBack(glsl_types::vec2(pivot + dir + norm));
+ positions.PushBack(glsl_types::vec2(pivot + dir - norm));
+ }
+}
+
+uint32_t TextLayout::GetGlyphCount() const
+{
+ return m_metrics.size();
+}
+
+uint32_t TextLayout::GetTextureSet() const
+{
+ return m_metrics[0].GetTextureNode().m_textureSet;
+}
+
+float TextLayout::GetPixelLength() const
+{
+ return m_textSizeRatio * accumulate(m_metrics.begin(), m_metrics.end(), 0.0,
+ bind(&TextLayout::AccumulateAdvance, this, _1, _2));
+}
+
+float TextLayout::GetPixelHeight() const
+{
+ return m_font.m_size;
+}
+
+void TextLayout::GetTextureQuad(GlyphRegion const & region,
+ float depth,
+ Quad4 & quad) const
+{
+ ASSERT(region.IsValid(), ());
+
+ m2::RectF const & rect = region.GetTexRect();
+ uint8_t needOutline = m_font.m_needOutline ? 1 : 0;
+ float textureOffset = static_cast<float>((region.GetTextureNode().m_textureOffset << 1) + needOutline);
+ quad.v[0] = vec4(rect.minX(), rect.minY(), textureOffset, depth);
+ quad.v[1] = vec4(rect.minX(), rect.maxY(), textureOffset, depth);
+ quad.v[2] = vec4(rect.maxX(), rect.minY(), textureOffset, depth);
+ quad.v[3] = vec4(rect.maxX(), rect.maxY(), textureOffset, depth);
+}
+
+float TextLayout::AccumulateAdvance(double const & currentValue, GlyphRegion const & reg1) const
+{
+ ASSERT(reg1.IsValid(), ());
+
+ return currentValue + reg1.GetAdvance();
+}
+
+void TextLayout::InitMetric(strings::UniChar const & unicodePoint,
+ dp::RefPointer<dp::TextureSetHolder> textures)
+{
+ GlyphRegion region;
+ if (textures->GetGlyphRegion(unicodePoint, region))
+ m_metrics.push_back(region);
+}
+
+void TextLayout::GetMetrics(int32_t const index, float & xOffset, float & yOffset, float & advance,
+ float & halfWidth, float & halfHeight) const
+{
+ GlyphRegion const & region = m_metrics[index];
+ m2::PointU size;
+ region.GetPixelSize(size);
+ region.GetMetrics(xOffset, yOffset, advance);
+
+ halfWidth = m_textSizeRatio * size.x / 2.0f;
+ halfHeight = m_textSizeRatio * size.y / 2.0f;
+
+ xOffset = xOffset * m_textSizeRatio + halfWidth;
+ yOffset = yOffset * m_textSizeRatio + halfHeight;
+ advance *= m_textSizeRatio;
+}
+
+///////////////////////////////////////////////////////////////
+
+SharedTextLayout::SharedTextLayout()
+{
+}
+
+SharedTextLayout::SharedTextLayout(TextLayout * layout)
+ : m_layout(layout)
+{
+}
+
+SharedTextLayout::SharedTextLayout(SharedTextLayout const & other)
+{
+ m_layout = other.m_layout;
+}
+
+SharedTextLayout const & SharedTextLayout::operator=(SharedTextLayout const & other)
+{
+ if (&other != this)
+ m_layout = other.m_layout;
+
+ return *this;
+}
+
+bool SharedTextLayout::IsNull() const
+{
+ return m_layout == NULL;
+}
+
+void SharedTextLayout::Reset(TextLayout * layout)
+{
+ m_layout.reset(layout);
+}
+
+TextLayout * SharedTextLayout::operator->()
+{
+ return m_layout.get();
+}
+
+TextLayout const * SharedTextLayout::operator->() const
+{
+ return m_layout.get();
+}
+
+
+
+}
diff --git a/drape_frontend/text_layout.hpp b/drape_frontend/text_layout.hpp
new file mode 100644
index 0000000000..6cf6293904
--- /dev/null
+++ b/drape_frontend/text_layout.hpp
@@ -0,0 +1,85 @@
+#pragma once
+
+#include "common_structures.hpp"
+#include "shape_view_params.hpp"
+#include "intrusive_vector.hpp"
+
+#include "../drape/pointers.hpp"
+#include "../drape/texture_set_holder.hpp"
+#include "../drape/overlay_handle.hpp"
+
+#include "../geometry/spline.hpp"
+
+#include "../base/string_utils.hpp"
+#include "../base/buffer_vector.hpp"
+
+#include "../std/vector.hpp"
+#include "../std/shared_ptr.hpp"
+
+namespace df
+{
+
+class TextLayout
+{
+ typedef dp::TextureSetHolder::GlyphRegion GlyphRegion;
+public:
+ TextLayout(strings::UniString const & string,
+ df::FontDecl const & font,
+ dp::RefPointer<dp::TextureSetHolder> textures);
+
+ dp::OverlayHandle * LayoutText(FeatureID const & featureID,
+ m2::PointF const & pivot,
+ m2::PointF const & pixelOffset,
+ float depth,
+ vector<glsl_types::Quad4> & positions,
+ vector<glsl_types::Quad4> & texCoord,
+ vector<glsl_types::Quad4> & fontColor,
+ vector<glsl_types::Quad4> & outlineColor) const;
+
+ void InitPathText(float depth,
+ vector<glsl_types::Quad4> & texCoord,
+ vector<glsl_types::Quad4> & fontColor,
+ vector<glsl_types::Quad4> & outlineColor) const;
+ void LayoutPathText(m2::Spline::iterator const & iterator,
+ float const scalePtoG,
+ IntrusiveVector<glsl_types::vec2> & positions,
+ bool isForwardDirection) const;
+
+ uint32_t GetGlyphCount() const;
+ uint32_t GetTextureSet() const;
+ float GetPixelLength() const;
+ float GetPixelHeight() const;
+
+private:
+ void GetTextureQuad(GlyphRegion const & region, float depth, glsl_types::Quad4 & quad) const;
+ float AccumulateAdvance(double const & currentValue, GlyphRegion const & reg2) const;
+ void InitMetric(strings::UniChar const & unicodePoint, dp::RefPointer<dp::TextureSetHolder> textures);
+
+ void GetMetrics(int32_t const index, float & xOffset, float & yOffset, float & advance,
+ float & halfWidth, float & halfHeight) const;
+
+private:
+ buffer_vector<GlyphRegion, 32> m_metrics;
+ df::FontDecl m_font;
+ float m_textSizeRatio;
+};
+
+class SharedTextLayout
+{
+public:
+ SharedTextLayout();
+ SharedTextLayout(TextLayout * layout);
+ SharedTextLayout(SharedTextLayout const & other);
+ SharedTextLayout const & operator= (SharedTextLayout const & other);
+
+ bool IsNull() const;
+ void Reset(TextLayout * layout);
+
+ TextLayout * operator->();
+ TextLayout const * operator->() const;
+
+private:
+ shared_ptr<TextLayout> m_layout;
+};
+
+}
diff --git a/drape_frontend/text_shape.cpp b/drape_frontend/text_shape.cpp
index 61eb793998..8c2b9c6914 100644
--- a/drape_frontend/text_shape.cpp
+++ b/drape_frontend/text_shape.cpp
@@ -1,8 +1,8 @@
#include "text_shape.hpp"
#include "common_structures.hpp"
+#include "text_layout.hpp"
#include "fribidi.hpp"
-
#include "../drape/shader_def.hpp"
#include "../drape/attribute_provider.hpp"
#include "../drape/glstate.hpp"
@@ -23,14 +23,10 @@ namespace df
{
using m2::PointF;
-using glsl_types::vec2;
-using glsl_types::vec3;
-using glsl_types::vec4;
namespace
{
- static float const realFontSize = 28.0f;
- static float const fontOffset = 1.3f;
+ float const TEXT_EXPAND_FACTOR = 1.3f;
PointF GetShift(dp::Anchor anchor, float width, float height)
{
@@ -49,25 +45,67 @@ namespace
}
}
- class TextHandle : public dp::OverlayHandle
+ void BatchText(dp::RefPointer<dp::Batcher> batcher, int32_t textureSet,
+ vector<glsl_types::Quad4> const & positions,
+ vector<glsl_types::Quad4> const & texCoord,
+ vector<glsl_types::Quad4> const & fontColors,
+ vector<glsl_types::Quad4> const & outlineColor,
+ size_t glyphCount,
+ dp::OverlayHandle * handle)
{
- public:
- TextHandle(FeatureID const & id, m2::PointD const & pivot, m2::PointD const & pxSize,
- m2::PointD const & offset, double priority)
- : OverlayHandle(id, dp::LeftBottom, priority), m_pivot(pivot)
- , m_offset(offset), m_size(pxSize) {}
+ ASSERT(glyphCount <= positions.size(), ());
+ ASSERT(positions.size() == texCoord.size(), ());
+ ASSERT(positions.size() == fontColors.size(), ());
+ ASSERT(positions.size() == outlineColor.size(), ());
+
+ dp::GLState state(gpu::FONT_PROGRAM, dp::GLState::OverlayLayer);
+ state.SetTextureSet(textureSet);
+ state.SetBlending(dp::Blending(true));
- m2::RectD GetPixelRect(ScreenBase const & screen) const
+ dp::AttributeProvider provider(4, 4 * glyphCount);
+ {
+ dp::BindingInfo position(1);
+ dp::BindingDecl & decl = position.GetBindingDecl(0);
+ decl.m_attributeName = "a_position";
+ decl.m_componentCount = 4;
+ decl.m_componentType = gl_const::GLFloatType;
+ decl.m_offset = 0;
+ decl.m_stride = 0;
+ provider.InitStream(0, position, dp::MakeStackRefPointer((void*)&positions[0]));
+ }
{
- m2::PointD const pivot = screen.GtoP(m_pivot) + m_offset;
- return m2::RectD(pivot, pivot + m_size);
+ dp::BindingInfo texcoord(1);
+ dp::BindingDecl & decl = texcoord.GetBindingDecl(0);
+ decl.m_attributeName = "a_texcoord";
+ decl.m_componentCount = 4;
+ decl.m_componentType = gl_const::GLFloatType;
+ decl.m_offset = 0;
+ decl.m_stride = 0;
+ provider.InitStream(1, texcoord, dp::MakeStackRefPointer((void*)&texCoord[0]));
+ }
+ {
+ dp::BindingInfo base_color(1);
+ dp::BindingDecl & decl = base_color.GetBindingDecl(0);
+ decl.m_attributeName = "a_color";
+ decl.m_componentCount = 4;
+ decl.m_componentType = gl_const::GLFloatType;
+ decl.m_offset = 0;
+ decl.m_stride = 0;
+ provider.InitStream(2, base_color, dp::MakeStackRefPointer((void*)&fontColors[0]));
+ }
+ {
+ dp::BindingInfo outline_color(1);
+ dp::BindingDecl & decl = outline_color.GetBindingDecl(0);
+ decl.m_attributeName = "a_outline_color";
+ decl.m_componentCount = 4;
+ decl.m_componentType = gl_const::GLFloatType;
+ decl.m_offset = 0;
+ decl.m_stride = 0;
+ provider.InitStream(3, outline_color, dp::MakeStackRefPointer((void*)&outlineColor[0]));
}
- private:
- m2::PointD m_pivot;
- m2::PointD m_offset;
- m2::PointD m_size;
- };
+ batcher->InsertListOfStrip(state, dp::MakeStackRefPointer(&provider), MovePointer(handle), 4);
+ }
}
TextShape::TextShape(m2::PointF const & basePoint, TextViewParams const & params)
@@ -76,209 +114,80 @@ TextShape::TextShape(m2::PointF const & basePoint, TextViewParams const & params
{
}
-void TextShape::DrawTextLine(TextLine const & textLine, dp::RefPointer<dp::Batcher> batcher, dp::RefPointer<dp::TextureSetHolder> textures) const
+void TextShape::Draw(dp::RefPointer<dp::Batcher> batcher, dp::RefPointer<dp::TextureSetHolder> textures) const
{
- int const size = textLine.m_text.size();
- int const maxTextureSetCount = textures->GetMaxTextureSet();
- buffer_vector<int, 16> sizes(maxTextureSetCount);
-
- for (int i = 0; i < size; i++)
- {
- dp::TextureSetHolder::GlyphRegion region;
- if (!textures->GetGlyphRegion(textLine.m_text[i], region))
- continue;
- ++sizes[region.GetTextureNode().m_textureSet];
- }
-
- for (int i = 0; i < maxTextureSetCount; ++i)
+ ASSERT(!m_params.m_primaryText.empty(), ());
+ if (m_params.m_secondaryText.empty())
{
- if (sizes[i])
- DrawUnicalTextLine(textLine, i, sizes[i], batcher, textures);
+ df::FontDecl const & primaryFont = m_params.m_primaryTextFont;
+ TextLayout const primaryLayout(fribidi::log2vis(strings::MakeUniString(m_params.m_primaryText)), primaryFont, textures);
+ PointF const pixelOffset = GetShift(m_params.m_anchor, primaryLayout.GetPixelLength(), primaryFont.m_size) + m_params.m_primaryOffset;
+
+ size_t glyphCount = primaryLayout.GetGlyphCount();
+ vector<glsl_types::Quad4> positions(glyphCount);
+ vector<glsl_types::Quad4> texCoord(glyphCount);
+ vector<glsl_types::Quad4> fontColor(glyphCount);
+ vector<glsl_types::Quad4> outlineColor(glyphCount);
+
+ dp::OverlayHandle * handle = primaryLayout.LayoutText(m_params.m_featureID, m_basePoint,
+ pixelOffset, m_params.m_depth,
+ positions, texCoord, fontColor, outlineColor);
+ BatchText(batcher, primaryLayout.GetTextureSet(),
+ positions, texCoord,
+ fontColor, outlineColor,
+ glyphCount, handle);
}
-}
-
-void TextShape::DrawUnicalTextLine(TextLine const & textLine, int setNum, int letterCount,
- dp::RefPointer<dp::Batcher> batcher, dp::RefPointer<dp::TextureSetHolder> textures) const
-{
- strings::UniString text = textLine.m_text;
- float fontSize = textLine.m_font.m_size;
- float needOutline = textLine.m_font.m_needOutline;
- PointF anchorDelta = textLine.m_offset;
-
- int const numVert = letterCount * 4;
- vector<vec4> vertex(numVert);
- vec4 * vertexPt = &vertex[0];
- vector<vec4> texture(numVert);
- vec4 * texturePt = &texture[0];
-
- float stride = 0.0f;
- int textureSet;
-
- dp::TextureSetHolder::GlyphRegion region;
- for(int i = 0, j = 0 ; i < text.size() ; i++)
+ else
{
- if (!textures->GetGlyphRegion(text[i], region))
- continue;
- float xOffset, yOffset, advance;
- region.GetMetrics(xOffset, yOffset, advance);
- float const aspect = fontSize / realFontSize;
- advance *= aspect;
- if (region.GetTextureNode().m_textureSet != setNum)
- {
- stride += advance;
- continue;
- }
-
- textureSet = region.GetTextureNode().m_textureSet;
- m2::RectF const rect = region.GetTexRect();
- float const textureNum = (region.GetTextureNode().m_textureOffset << 1) + needOutline;
- m2::PointU pixelSize;
- region.GetPixelSize(pixelSize);
- float const h = pixelSize.y * aspect;
- float const w = pixelSize.x * aspect;
- yOffset *= aspect;
- xOffset *= aspect;
-
- PointF const leftBottom(stride + xOffset + anchorDelta.x, yOffset + anchorDelta.y);
- PointF const rightBottom(stride + w + xOffset + anchorDelta.x, yOffset + anchorDelta.y);
- PointF const leftTop(stride + xOffset + anchorDelta.x, yOffset + h + anchorDelta.y);
- PointF const rightTop(stride + w + xOffset + anchorDelta.x, yOffset + h + anchorDelta.y);
+ df::FontDecl const & primaryFont = m_params.m_primaryTextFont;
+ df::FontDecl const & secondaryFont = m_params.m_secondaryTextFont;
- *vertexPt = vec4(m_basePoint, leftTop);
- vertexPt++;
- *vertexPt = vec4(m_basePoint, leftBottom);
- vertexPt++;
- *vertexPt = vec4(m_basePoint, rightTop);
- vertexPt++;
- *vertexPt = vec4(m_basePoint, rightBottom);
- vertexPt++;
+ TextLayout const primaryLayout(fribidi::log2vis(strings::MakeUniString(m_params.m_primaryText)), primaryFont, textures);
+ TextLayout const secondaryLayout(fribidi::log2vis(strings::MakeUniString(m_params.m_secondaryText)), secondaryFont, textures);
- *texturePt = vec4(rect.minX(), rect.maxY(), textureNum, m_params.m_depth);
- texturePt++;
- *texturePt = vec4(rect.minX(), rect.minY(), textureNum, m_params.m_depth);
- texturePt++;
- *texturePt = vec4(rect.maxX(), rect.maxY(), textureNum, m_params.m_depth);
- texturePt++;
- *texturePt = vec4(rect.maxX(), rect.minY(), textureNum, m_params.m_depth);
- texturePt++;
+ float const primaryTextLength = primaryLayout.GetPixelLength();
+ float const secondaryTextLength = secondaryLayout.GetPixelLength();
+ bool const isPrimaryLonger = primaryTextLength > secondaryTextLength;
+ float const maxLength = max(primaryTextLength, secondaryTextLength);
+ float const minLength = min(primaryTextLength, secondaryTextLength);
+ float const halfLengthDiff = (maxLength - minLength) / 2.0;
- j++;
- stride += advance;
- }
+ float const textHeight = TEXT_EXPAND_FACTOR * (primaryFont.m_size + secondaryFont.m_size);
+ PointF const anchorOffset = GetShift(m_params.m_anchor, maxLength, textHeight);
- vector<vec4> color(numVert, vec4(textLine.m_font.m_color));
- vector<vec4> color2(numVert, vec4(textLine.m_font.m_outlineColor));
+ float const primaryDx = isPrimaryLonger ? 0.0f : halfLengthDiff;
+ float const primaryDy = (1.0f - TEXT_EXPAND_FACTOR) * primaryFont.m_size - TEXT_EXPAND_FACTOR * secondaryFont.m_size;
+ PointF const primaryPixelOffset = PointF(primaryDx, primaryDy) + anchorOffset + m_params.m_primaryOffset;
- dp::GLState state(gpu::FONT_PROGRAM, dp::GLState::OverlayLayer);
- state.SetTextureSet(textureSet);
- state.SetBlending(dp::Blending(true));
+ size_t glyphCount = max(primaryLayout.GetGlyphCount(), secondaryLayout.GetGlyphCount());
+ vector<glsl_types::Quad4> positions(glyphCount);
+ vector<glsl_types::Quad4> texCoord(glyphCount);
+ vector<glsl_types::Quad4> fontColor(glyphCount);
+ vector<glsl_types::Quad4> outlineColor(glyphCount);
- dp::AttributeProvider provider(4, 4 * letterCount);
- {
- dp::BindingInfo position(1);
- dp::BindingDecl & decl = position.GetBindingDecl(0);
- decl.m_attributeName = "a_position";
- decl.m_componentCount = 4;
- decl.m_componentType = gl_const::GLFloatType;
- decl.m_offset = 0;
- decl.m_stride = 0;
- provider.InitStream(0, position, dp::MakeStackRefPointer((void*)&vertex[0]));
- }
- {
- dp::BindingInfo texcoord(1);
- dp::BindingDecl & decl = texcoord.GetBindingDecl(0);
- decl.m_attributeName = "a_texcoord";
- decl.m_componentCount = 4;
- decl.m_componentType = gl_const::GLFloatType;
- decl.m_offset = 0;
- decl.m_stride = 0;
- provider.InitStream(1, texcoord, dp::MakeStackRefPointer((void*)&texture[0]));
- }
- {
- dp::BindingInfo base_color(1);
- dp::BindingDecl & decl = base_color.GetBindingDecl(0);
- decl.m_attributeName = "a_color";
- decl.m_componentCount = 4;
- decl.m_componentType = gl_const::GLFloatType;
- decl.m_offset = 0;
- decl.m_stride = 0;
- provider.InitStream(2, base_color, dp::MakeStackRefPointer((void*)&color[0]));
- }
- {
- dp::BindingInfo outline_color(1);
- dp::BindingDecl & decl = outline_color.GetBindingDecl(0);
- decl.m_attributeName = "a_outline_color";
- decl.m_componentCount = 4;
- decl.m_componentType = gl_const::GLFloatType;
- decl.m_offset = 0;
- decl.m_stride = 0;
- provider.InitStream(3, outline_color, dp::MakeStackRefPointer((void*)&color2[0]));
- }
-
- PointF const dim = PointF(textLine.m_length, fontOffset * textLine.m_font.m_size);
- dp::OverlayHandle * handle = new TextHandle(m_params.m_featureID, m_basePoint, dim, anchorDelta, m_params.m_depth);
- batcher->InsertListOfStrip(state, dp::MakeStackRefPointer(&provider), MovePointer(handle), 4);
-}
-
-void TextShape::Draw(dp::RefPointer<dp::Batcher> batcher, dp::RefPointer<dp::TextureSetHolder> textures) const
-{
- strings::UniString const text = fribidi::log2vis(strings::MakeUniString(m_params.m_primaryText));
- int const size = text.size();
- float const fontSize = m_params.m_primaryTextFont.m_size;
- float textLength = 0.0f;
- vector<TextLine> lines(4);
-
- for (int i = 0 ; i < size ; i++)
- {
- dp::TextureSetHolder::GlyphRegion region;
- if (!textures->GetGlyphRegion(text[i], region))
{
- LOG(LDEBUG, ("Symbol not found ", text[i]));
- continue;
+ dp::OverlayHandle * handle = primaryLayout.LayoutText(m_params.m_featureID, m_basePoint,
+ primaryPixelOffset, m_params.m_depth,
+ positions, texCoord, fontColor, outlineColor);
+ BatchText(batcher, primaryLayout.GetTextureSet(),
+ positions, texCoord,
+ fontColor, outlineColor,
+ primaryLayout.GetGlyphCount(), handle);
}
- float xOffset, yOffset, advance;
- region.GetMetrics(xOffset, yOffset, advance);
- textLength += advance * fontSize / realFontSize;
- }
-
- if (m_params.m_secondaryText.empty())
- {
- PointF const anchorDelta = GetShift(m_params.m_anchor, textLength, fontSize) + m_params.m_primaryOffset;
- lines[0] = TextLine(anchorDelta, text, textLength, m_params.m_primaryTextFont);
- DrawTextLine(lines[0], batcher, textures);
- return;
- }
- strings::UniString const auxText = fribidi::log2vis(strings::MakeUniString(m_params.m_secondaryText));
- int const auxSize = auxText.size();
- float const auxFontSize = m_params.m_secondaryTextFont.m_size;
- float auxTextLength = 0.0f;
+ float const secondaryDx = isPrimaryLonger ? halfLengthDiff : 0.0f;
+ PointF const secondaryPixelOffset = PointF(secondaryDx, 0.0f) + anchorOffset + m_params.m_primaryOffset;
- for (int i = 0 ; i < auxSize ; i++)
- {
- dp::TextureSetHolder::GlyphRegion region;
- if (!textures->GetGlyphRegion(auxText[i], region))
{
- LOG(LDEBUG, ("Symbol not found(aux) ", auxText[i]));
- continue;
+ dp::OverlayHandle * handle = secondaryLayout.LayoutText(m_params.m_featureID, m_basePoint,
+ secondaryPixelOffset, m_params.m_depth,
+ positions, texCoord, fontColor, outlineColor);
+ BatchText(batcher, secondaryLayout.GetTextureSet(),
+ positions, texCoord,
+ fontColor, outlineColor,
+ secondaryLayout.GetGlyphCount(), handle);
}
- float xOffset, yOffset, advance;
- region.GetMetrics(xOffset, yOffset, advance);
- auxTextLength += advance * auxFontSize / realFontSize;
}
-
- float const length = max(textLength, auxTextLength);
- PointF const anchorDelta = GetShift(m_params.m_anchor, length, fontOffset * fontSize + fontOffset * auxFontSize);
- float dx = textLength > auxTextLength ? 0.0f : (auxTextLength - textLength) / 2.0f;
- PointF const textDelta = PointF(dx, -fontOffset * auxFontSize + (1.0f - fontOffset) * fontSize) + anchorDelta + m_params.m_primaryOffset;
- dx = textLength > auxTextLength ? (textLength - auxTextLength) / 2.0f : 0.0f;
- PointF const auxTextDelta = PointF(dx, 0.0f) + anchorDelta + m_params.m_primaryOffset;
-
- lines[0] = TextLine(textDelta, text, textLength, m_params.m_primaryTextFont);
- lines[1] = TextLine(auxTextDelta, auxText, auxTextLength, m_params.m_secondaryTextFont);
-
- DrawTextLine(lines[0], batcher, textures);
- DrawTextLine(lines[1], batcher, textures);
}
} //end of df namespace
diff --git a/drape_frontend/text_shape.hpp b/drape_frontend/text_shape.hpp
index 13f085b566..f5d8804ee3 100644
--- a/drape_frontend/text_shape.hpp
+++ b/drape_frontend/text_shape.hpp
@@ -10,32 +10,12 @@
namespace df
{
-namespace
-{
- struct TextLine
- {
- m2::PointF m_offset;
- strings::UniString m_text;
- float m_length;
- FontDecl m_font;
-
- TextLine() {}
- TextLine(m2::PointF const & offset, strings::UniString const & text, float length, FontDecl const & font)
- : m_offset(offset), m_text(text), m_length(length), m_font(font) {}
- };
-}
-
class TextShape : public MapShape
{
public:
TextShape(m2::PointF const & basePoint, TextViewParams const & params);
- virtual void Draw(dp::RefPointer<dp::Batcher> batcher, dp::RefPointer<dp::TextureSetHolder> textures) const;
-
-private:
- void DrawTextLine(TextLine const & textLine, dp::RefPointer<dp::Batcher> batcher, dp::RefPointer<dp::TextureSetHolder> textures) const;
- void DrawUnicalTextLine(TextLine const & textLine, int setNum, int letterCount,
- dp::RefPointer<dp::Batcher> batcher, dp::RefPointer<dp::TextureSetHolder> textures) const;
+ void Draw(dp::RefPointer<dp::Batcher> batcher, dp::RefPointer<dp::TextureSetHolder> textures) const;
private:
m2::PointF m_basePoint;