Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / 3d / font_manager.cpp
blob43f0e44accea23dcc0d51448af79555b9a6bdf06
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010-2021 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "std3d.h"
22 #include <string>
23 //#include <sstream>
25 #include "nel/3d/font_manager.h"
26 #include "nel/3d/font_generator.h"
27 #include "nel/3d/texture_font.h"
28 #include "nel/3d/computed_string.h"
29 #include "nel/3d/index_buffer.h"
30 #include "nel/3d/material.h"
31 #include "nel/misc/smart_ptr.h"
32 #include "nel/misc/debug.h"
34 #include "nel/misc/file.h"
36 using namespace std;
38 #ifdef DEBUG_NEW
39 #define new DEBUG_NEW
40 #endif
42 namespace NL3D {
46 // ***************************************************************************
47 CMaterial* CFontManager::getFontMaterial()
49 if (_TexFont == NULL)
51 _TexFont = new CTextureFont;
52 _TexCacheNr++;
55 if (_MatFont == NULL)
57 _MatFont= new CMaterial;
58 _MatFont->initUnlit();
59 _MatFont->setSrcBlend(CMaterial::srcalpha);
60 _MatFont->setDstBlend(CMaterial::invsrcalpha);
61 _MatFont->setBlend(true);
62 _MatFont->setTexture(0, _TexFont);
63 _MatFont->texEnvOpRGB(0, CMaterial::Replace);
64 _MatFont->texEnvArg0RGB(0, CMaterial::Diffuse, CMaterial::SrcColor);
66 return _MatFont;
69 // ***************************************************************************
70 void CFontManager::computeString (NLMISC::CUtfStringView sv,
71 CFontGenerator *fontGen,
72 const NLMISC::CRGBA &color,
73 uint32 fontSize,
74 bool embolden,
75 bool oblique,
76 IDriver *driver,
77 CComputedString &output,
78 bool keep800x600Ratio)
80 output.Color = color;
82 // resize fontSize if window not of 800x600.
83 if (keep800x600Ratio)
85 uint32 width, height;
86 driver->getWindowSize (width, height);
87 if ((height == 0) || (width == 0))
88 return;
90 // keep the 800*600 ratio
91 fontSize = (uint32)floor(fontSize*height/600.f);
92 fontSize = max(fontSize, (uint32)2);
95 // Setting vertices format
96 output.Vertices.setNumVertices (4 * (uint32)sv.largestSize());
98 // 1 character <-> 1 quad
99 sint32 penx = 0, dx;
100 sint32 penz = 0, dz;
101 float x1, z1, x2, z2;
102 float u1, v1, u2, v2;
103 CMaterial *pMatFont = getFontMaterial();
104 CTextureFont *pTexFont = (CTextureFont*)(pMatFont->getTexture (0));
105 float TexRatioW = 1.0f / pTexFont->getWidth();
106 float TexRatioH = 1.0f / pTexFont->getHeight();
107 /*float hlfPixTexW = 0.5f * TexRatioW;
108 float hlfPixTexH = 0.5f * TexRatioH;
109 float hlfPixScrW = 0.5f;
110 float hlfPixScrH = 0.5f;*/
111 // Yoyo: Do not need Half Pixel/Texel displacement!!
112 float hlfPixTexW = 0;
113 float hlfPixTexH = 0;
114 float hlfPixScrW = 0;
115 float hlfPixScrH = 0;
118 CTextureFont::SLetterKey k;
120 // string bound.
121 output.XMin= FLT_MAX;
122 output.XMax= -FLT_MAX;
123 output.ZMin= FLT_MAX;
124 output.ZMax= -FLT_MAX;
126 // string info.
127 sint32 nMaxZ = -1000000, nMinZ = 1000000;
128 output.StringHeight = 0;
130 // save string info for later rebuild as needed
131 if (sv.ptr() != output.Text.c_str()) // don't resave if rebuilding
132 output.Text = sv.toUtf8();
133 output.CacheVersion = getCacheVersion();
135 uint j = 0;
136 size_t idx = 0;
138 CVertexBufferReadWrite vba;
139 output.Vertices.lock (vba);
141 hlfPixScrW = 0.f;
142 hlfPixScrH = 0.f;
144 // For all chars
145 for (NLMISC::CUtfStringView::iterator it(sv.begin()), end(sv.end()); it != end; ++it, ++idx)
147 // Creating font
148 k.Char = *it;
149 // draw tab as space
150 if (k.Char == '\t')
151 k.Char = ' ';
152 if (k.Char < 0x20) // Control Characters
153 k.Char += 0x2400;
154 if (k.Char == 0x7F) // DEL
155 k.Char = 0x2421;
156 k.FontGenerator = fontGen;
157 k.Size = fontSize;
158 k.Embolden = embolden;
159 k.Oblique = oblique;
160 // render letter
161 CTextureFont::SLetterInfo *pLI = pTexFont->getLetterInfo (k, true);
162 if(pLI != NULL)
164 if (pLI->glyph)
166 // If letter is heavily upscaled, then there is noticeable clipping on edges
167 // fixing UV will make it bit better
168 if ((pLI->Size >> 1) > pLI->glyph->Size)
170 hlfPixTexW = 0.5f * TexRatioW;
171 hlfPixTexH = 0.5f * TexRatioH;
174 // Creating vertices
175 dx = pLI->Left;
176 dz = -((sint32)pLI->CharHeight - (sint32)(pLI->Top));
178 x1 = (penx + dx) - hlfPixScrW;
179 z1 = (penz + dz) - hlfPixScrH;
180 x2 = (penx + dx + (sint32)pLI->CharWidth) + hlfPixScrW;
181 z2 = (penz + dz + (sint32)pLI->CharHeight) + hlfPixScrH;
183 vba.setVertexCoord (j, x1, 0, z1);
184 vba.setTexCoord (j, 0, pLI->glyph->U0-hlfPixTexW, pLI->glyph->V1+hlfPixTexH);
185 ++j;
187 vba.setVertexCoord (j, x2, 0, z1);
188 vba.setTexCoord (j, 0, pLI->glyph->U1+hlfPixTexW, pLI->glyph->V1+hlfPixTexH);
189 ++j;
191 vba.setVertexCoord (j, x2, 0, z2);
192 vba.setTexCoord (j, 0, pLI->glyph->U1+hlfPixTexW, pLI->glyph->V0-hlfPixTexH);
193 ++j;
195 vba.setVertexCoord (j, x1, 0, z2);
196 vba.setTexCoord (j, 0, pLI->glyph->U0-hlfPixTexW, pLI->glyph->V0-hlfPixTexH);
197 ++j;
199 // String Bound
200 output.XMin= min(output.XMin, x1);
201 output.XMin= min(output.XMin, x2);
202 output.XMax= max(output.XMax, x1);
203 output.XMax= max(output.XMax, x2);
204 output.ZMin= min(output.ZMin, z1);
205 output.ZMin= min(output.ZMin, z2);
206 output.ZMax= max(output.ZMax, z1);
207 output.ZMax= max(output.ZMax, z2);
209 // String info
210 sint32 nZ1 = (sint32)pLI->Top-(sint32)pLI->CharHeight;
211 sint32 nZ2 = pLI->Top;
213 if (nZ1 < nMinZ) nMinZ = nZ1;
214 if (nZ2 > nMaxZ) nMaxZ = nZ2;
216 penx += pLI->AdvX;
219 // Building Material
220 output.Material = pMatFont;
223 output.Vertices.setNumVertices (j);
224 output.Length = idx;
225 nlassert(output.Length == NLMISC::CUtfStringView(output.Text).count());
227 // compile string info
228 output.StringWidth = (float)penx;
229 if(nMaxZ>nMinZ)
231 output.StringHeight = (float)(nMaxZ - nMinZ);
232 output.StringLine = -(float)nMinZ;
234 else
236 output.StringHeight = 0;
237 output.StringLine = 0;
242 // ***************************************************************************
243 void CFontManager::computeStringInfo ( NLMISC::CUtfStringView sv,
244 CFontGenerator *fontGen,
245 const NLMISC::CRGBA &color,
246 uint32 fontSize,
247 bool embolden,
248 bool oblique,
249 IDriver *driver,
250 CComputedString &output,
251 bool keep800x600Ratio )
253 computeStringInfo(sv, sv.largestSize(), fontGen, color, fontSize, embolden, oblique, driver, output, keep800x600Ratio);
257 // ***************************************************************************
258 void CFontManager::computeStringInfo ( NLMISC::CUtfStringView sv,
259 size_t len,
260 CFontGenerator *fontGen,
261 const NLMISC::CRGBA &color,
262 uint32 fontSize,
263 bool embolden,
264 bool oblique,
265 IDriver *driver,
266 CComputedString &output,
267 bool keep800x600Ratio )
269 output.Color = color;
271 // save string info for later rebuild as needed
272 if (sv.ptr() != output.Text.c_str()) // don't resave if rebuilding
273 output.Text = sv.toUtf8();
274 output.CacheVersion = 0;
276 if (sv.empty())
278 output.StringWidth = 0.f;
279 output.StringHeight = 0;
280 output.StringLine = 0;
282 return;
285 // resize fontSize if window not of 800x600.
286 if (keep800x600Ratio)
288 uint32 width, height;
289 driver->getWindowSize (width, height);
290 if ((height == 0) || (width == 0))
291 return;
292 // keep the 800*600 ratio
293 fontSize = (uint32)floor(fontSize*height/600.f);
294 fontSize = max(fontSize, (uint32)2);
297 sint32 penx = 0;
298 sint32 nMaxZ = -1000000, nMinZ = 1000000;
299 CMaterial *pMatFont = getFontMaterial();
300 CTextureFont *pTexFont = (CTextureFont*)(pMatFont->getTexture (0));
302 CTextureFont::SLetterKey k;
303 CTextureFont::SLetterInfo *pLI;
305 size_t idx = 0;
306 for (NLMISC::CUtfStringView::iterator it(sv.begin()), end(sv.end()); it != end && idx < len; ++it, ++idx)
308 // Creating font
309 k.Char = *it;
310 // draw tab as space
311 if (k.Char == '\t')
312 k.Char = ' ';
313 if (k.Char < 0x20)
314 k.Char += 0x2400;
315 k.FontGenerator = fontGen;
316 k.Size = fontSize;
317 k.Embolden = embolden;
318 k.Oblique = oblique;
319 pLI = pTexFont->getLetterInfo (k, false);
320 if(pLI != NULL)
322 if ((pLI->CharWidth > 0) && (pLI->CharHeight > 0))
324 // String info
325 sint32 nZ1 = (sint32)pLI->Top-(sint32)pLI->CharHeight;
326 sint32 nZ2 = pLI->Top;
328 if (nZ1 < nMinZ) nMinZ = nZ1;
329 if (nZ2 > nMaxZ) nMaxZ = nZ2;
331 penx += pLI->AdvX;
334 output.Length = idx;
335 nlassert(output.Length == std::min(len, NLMISC::CUtfStringView(output.Text).count()));
337 // compile string info
338 output.StringWidth = (float)penx;
339 if(nMaxZ>nMinZ)
341 output.StringHeight = (float)(nMaxZ - nMinZ);
342 output.StringLine = -(float)nMinZ;
344 else
346 output.StringHeight = 0;
347 output.StringLine = 0;
353 // ***************************************************************************
354 string CFontManager::getCacheInformation() const
356 string str;
357 str = "MaxMemory: " + NLMISC::toString(_MaxMemory) + " MemSize: " + NLMISC::toString(_MemSize) + " NbChar: " + NLMISC::toString(_NbChar);
358 return str;
361 // ***************************************************************************
362 void CFontManager::invalidate()
364 if (_TexFont)
365 _TexFont = NULL;
367 _TexFont = new CTextureFont;
368 _TexCacheNr++;
370 getFontMaterial()->setTexture(0, _TexFont);
375 } // NL3D