1#include "painter.h"
2#include "textrender.h"
3#include <framework/core/logger.h>
4#include <framework/core/eventdispatcher.h>
5
6TextRender g_text;
7
8void TextRender::init()
9{
10
11}
12
13void TextRender::terminate()
14{
15 for (auto& cache : m_cache) {
16 cache.clear();
17 }
18}
19
20void TextRender::poll()
21{
22 static int iteration = 0;
23 int index = (iteration++) % INDEXES;
24 std::lock_guard<std::mutex> lock(m_mutex[index]);
25 auto& cache = m_cache[index];
26 if (cache.size() < 100)
27 return;
28
29 ticks_t dropPoint = g_clock.millis();
30 if (cache.size() > 500)
31 dropPoint -= 10;
32 else if (cache.size() > 250)
33 dropPoint -= 100;
34 else
35 dropPoint -= 1000;
36
37 for (auto it = cache.begin(); it != cache.end(); ) {
38 if (it->second->lastUse < dropPoint) {
39 it = cache.erase(it);
40 continue;
41 }
42 ++it;
43 }
44}
45
46uint64_t TextRender::addText(BitmapFontPtr font, const std::string& text, const Size& size, Fw::AlignmentFlag align)
47{
48 if (!font || text.empty() || !size.isValid())
49 return 0;
50 uint64_t hash = 1125899906842597ULL;
51 for (size_t i = 0; i < text.length(); ++i) {
52 hash = hash * 31 + text[i];
53 }
54 hash = hash * 31 + size.width();
55 hash = hash * 31 + size.height();
56 hash = hash * 31 + (uint64_t)align;
57 hash = hash * 31 + (uint64_t)font->getId();
58
59 int index = hash % INDEXES;
60 m_mutex[index].lock();
61 auto it = m_cache[index].find(hash);
62 if (it == m_cache[index].end()) {
63 m_cache[index][hash] = std::shared_ptr<TextRenderCache>(new TextRenderCache{ font, text, size, align, font->getTexture(), CoordsBuffer(), g_clock.millis() });
64 }
65 m_mutex[index].unlock();
66 return hash;
67}
68
69void TextRender::drawText(const Rect& rect, const std::string& text, BitmapFontPtr font, const Color& color, Fw::AlignmentFlag align, bool shadow)
70{
71 VALIDATE_GRAPHICS_THREAD();
72 uint64_t hash = addText(font, text, rect.size(), align);
73 drawText(rect.topLeft(), hash, color, shadow);
74}
75
76void TextRender::drawText(const Point& pos, uint64_t hash, const Color& color, bool shadow)
77{
78 VALIDATE_GRAPHICS_THREAD();
79 int index = hash % INDEXES;
80 m_mutex[index].lock();
81 auto _it = m_cache[index].find(hash);
82 if (_it == m_cache[index].end()) {
83 m_mutex[index].unlock();
84 return;
85 }
86 auto it = _it->second;
87 it->lastUse = g_clock.millis();
88 m_mutex[index].unlock();
89 if (it->font) { // calculate text coords
90 it->font->calculateDrawTextCoords(it->coords, it->text, Rect(0, 0, it->size), it->align);
91 it->coords.cache();
92 it->text.clear();
93 it->font.reset();
94 }
95
96 if (shadow) {
97 auto shadowPos = Point(pos);
98 shadowPos.x += 1;
99 shadowPos.y += 1;
100 g_painter->drawText(shadowPos, it->coords, Color::black, it->texture);
101 }
102
103 g_painter->drawText(pos, it->coords, color, it->texture);
104}
105
106void TextRender::drawColoredText(const Point& pos, uint64_t hash, const std::vector<std::pair<int, Color>>& colors, bool shadow)
107{
108 VALIDATE_GRAPHICS_THREAD();
109 if (colors.empty())
110 return drawText(pos, hash, Color::white);
111 int index = hash % INDEXES;
112 m_mutex[index].lock();
113 auto _it = m_cache[index].find(hash);
114 if (_it == m_cache[index].end()) {
115 m_mutex[index].unlock();
116 return;
117 }
118 auto it = _it->second;
119 it->lastUse = g_clock.millis();
120 m_mutex[index].unlock();
121 if (it->font) { // calculate text coords
122 it->font->calculateDrawTextCoords(it->coords, it->text, Rect(0, 0, it->size), it->align);
123 it->coords.cache();
124 it->text.clear();
125 it->font.reset();
126 }
127 g_painter->drawText(pos, it->coords, colors, it->texture);
128}
129
130