OpenGothic
Open source reimplementation of Gothic I and II
Loading...
Searching...
No Matches
gthfont.cpp
Go to the documentation of this file.
1#include "gthfont.h"
2
3#include <Tempest/Size>
4#include "resources.h"
5
6using namespace Tempest;
7
8GthFont::GthFont():pfnt(new zenkit::Font("", 16, {})) {
9 }
10
11GthFont::GthFont(zenkit::Read& data, std::string_view ftex, const Color &cl)
12 :pfnt(std::make_shared<zenkit::Font>()), color(cl) {
13 pfnt->load(&data);
14 tex = Resources::loadTexture(ftex);
15 setScale(1);
16 }
17
18int GthFont::pixelSize() const {
19 return int(fntHeight);
20 }
21
22void GthFont::setScale(float s) {
23 scale = s;
24 fntHeight = uint32_t(std::max(float(pfnt->height)*scale, 1.f)); // avoid division by zero
25 }
26
27void GthFont::drawText(Painter &p, int bx, int by, int bw, int bh,
28 std::string_view txt, Tempest::AlignFlag align, int firstLine) const {
29 if(tex==nullptr || txt.empty())
30 return;
31
32 auto b = p.brush();
33 p.setBrush(Brush(*tex,color));
34 processText(&p,bx,by,bw,bh,txt,align,firstLine);
35 p.setBrush(b);
36 }
37
38Size GthFont::processText(Painter* p, int bx, int by, int bw, int bh,
39 std::string_view txtView, AlignFlag align, int firstLine) const {
40 const uint8_t* txt = reinterpret_cast<const uint8_t*>(txtView.data());
41 const auto& fnt = *pfnt;
42
43 int h = pixelSize();
44 int x = bx, y=by-h;
45 float tw = float(tex->w());
46 float th = float(tex->h());
47
48 int lwidth = 0;
49
50 Size ret = {0,0};
51 while(*txt) {
52 auto t = getLine(txt,bw,lwidth);
53 auto sz = textSize(txt,t);
54 auto next = t;
55
56 if(*next=='\n')
57 ++next;
58 while(*next==' ')
59 ++next; // lead spaces of next line
60
61 if(firstLine>0) {
62 txt = next;
63 --firstLine;
64 continue;
65 }
66 if(ret.h+sz.h>bh && bh>0) {
67 break;
68 }
69
70 ret.w = std::max(ret.w,sz.w);
71 ret.h += sz.h;
72
73 if(align!=NoAlign && align!=AlignLeft) {
74 int x1 = x;
75 if(align & AlignHCenter)
76 x1 = x + (bw-sz.w)/2;
77 if(align & AlignRight)
78 x1 = x + (bw-sz.w);
79 x = x1;
80 }
81
82 for(auto i=txt; i!=t; ++i) {
83 uint8_t id = *i;
84 auto& uv1 = fnt.glyphs[id].uv[0];
85 auto& uv2 = fnt.glyphs[id].uv[1];
86 int w = int(fnt.glyphs[id].width * scale);
87
88 if(p!=nullptr) {
89 p->drawRect(x,y, w,h,
90 tw*uv1.x,th*uv1.y, tw*uv2.x,th*uv2.y);
91 }
92 x += w;
93 }
94
95 txt = next;
96 x = bx;
97 y += sz.h;
98 }
99
100 return ret;
101 }
102
103void GthFont::drawText(Tempest::Painter &p, int bx, int by, std::string_view txtChar) const {
104 if(tex==nullptr || txtChar.empty())
105 return;
106
107 const uint8_t* txt = reinterpret_cast<const uint8_t*>(txtChar.data());
108 const auto& fnt = *pfnt;
109
110 auto b = p.brush();
111 p.setBrush(Brush(*tex,color));
112
113 int h = pixelSize();
114 int x = bx, y=by-h;
115 float tw = float(tex->w());
116 float th = float(tex->h());
117
118 for(size_t i=0;txt[i];++i) {
119 uint8_t id = txt[i];
120 auto& uv1 = fnt.glyphs[id].uv[0];
121 auto& uv2 = fnt.glyphs[id].uv[1];
122 int w = int(fnt.glyphs[id].width * scale);
123
124 p.drawRect(x,y, w,h,
125 tw*uv1.x,th*uv1.y, tw*uv2.x,th*uv2.y);
126 x += w;
127 }
128 p.setBrush(b);
129 }
130
131Size GthFont::textSize(std::string_view txt) const {
132 if(txt.empty())
133 return Size();
134 return textSize(txt.data(),txt.data()+txt.size());
135 }
136
137Size GthFont::textSize(const char* cb, const char* ce) const {
138 const uint8_t* b = reinterpret_cast<const uint8_t*>(cb);
139 const uint8_t* e = reinterpret_cast<const uint8_t*>(ce);
140 return textSize(b,e);
141 }
142
143Size GthFont::textSize(const uint8_t* b, const uint8_t* e) const {
144 const auto& fnt = *pfnt;
145
146 int h = pixelSize();
147 int x = 0, y = h;
148 int totalW = 0;
149
150 for(size_t i=0;;) {
151 uint8_t id = b[i];
152 if(b+i==e) {
153 totalW = std::max(totalW,x);
154 break;
155 }
156 else if(id=='\n') {
157 totalW = std::max(totalW,x);
158 ++i;
159 while(b[i]==' ' && b+i!=e)
160 ++i;
161 y+=h;
162 x=0;
163 }
164 else if(id>=fnt.glyphs.size()) {
165 x += 10;
166 ++i;
167 }
168 else {
169 int w = int(fnt.glyphs[id].width * scale);
170 x += w;
171 ++i;
172 }
173 }
174
175 return Size(totalW,y);
176 }
177
178Size GthFont::textSize(int bw, std::string_view txt) const {
179 if(tex==nullptr || txt.empty())
180 return Size();
181 return processText(nullptr,0,0,bw,0,txt,NoAlign,0);
182 }
183
184int32_t GthFont::lineCount(int bw, std::string_view txt) const {
185 if(tex==nullptr || txt.empty())
186 return 0;
187 auto ret = processText(nullptr,0,0,bw,0,txt,NoAlign,0);
188 return ret.h/pixelSize();
189 }
190
191const uint8_t* GthFont::getLine(const uint8_t *txt, int bw, int& width) const {
192 width = 0;
193 int x = 0;
194 int wwidth = 0, wspace = 0;
195
196 // always draw at least one word
197 txt = getWord(txt,wwidth,wspace);
198 x += wwidth+wspace;
199
200 while(*txt!='\0' && *txt!='\n') {
201 auto t = getWord(txt,wwidth,wspace);
202 x += wwidth+wspace;
203 if(x>bw)
204 return txt;
205 width = x;
206 txt = t;
207 }
208
209 // if(*txt=='\0')
210 // return txt;
211 // return txt+1;
212 return txt;
213 }
214
215const uint8_t* GthFont::getWord(const uint8_t *txt, int& width, int& space) const {
216 width = 0;
217 space = 0;
218
219 const auto& fnt = *pfnt;
220 while(true) {
221 uint8_t id = *txt;
222 if(id=='\0' || id=='\n')
223 return txt;
224 if(id!=' ')
225 break;
226 space += int(fnt.glyphs[id].width * scale);
227 ++txt;
228 }
229
230 while(true) {
231 uint8_t id = *txt;
232 if(id=='\0' || id=='\n' || id==' ')
233 return txt;
234
235 width += int(fnt.glyphs[id].width * scale);
236 ++txt;
237 }
238 }
239
240bool GthFont::isSpace(uint8_t ch) {
241 return ch==' ' || ch=='\n';
242 }
GthFont()
Definition gthfont.cpp:8
auto lineCount(int w, std::string_view txt) const -> int32_t
Definition gthfont.cpp:184
void drawText(Tempest::Painter &p, int x, int y, int w, int h, std::string_view txt, Tempest::AlignFlag align, int firstLine=0) const
void setScale(float s)
Definition gthfont.cpp:22
auto textSize(const std::string_view txt) const -> Tempest::Size
Definition gthfont.cpp:131
int pixelSize() const
Definition gthfont.cpp:18
static const Tempest::Texture2d * loadTexture(std::string_view name, bool forceMips=false)