1 
2 
3 #include "graphics/software/FontManager.h"
4 #include "graphics/software/VFNTFont.h"
5 #include "graphics/software/NVGFont.h"
6 #include "graphics/software/font.h"
7 #include "graphics/software/font_internal.h"
8 
9 #include "graphics/paths/PathRenderer.h"
10 
11 #include "bmpman/bmpman.h"
12 #include "cfile/cfile.h"
13 
14 namespace font
15 {
16 
17 	SCP_map<SCP_string, TrueTypeFontData> FontManager::allocatedData;
18 	SCP_map<SCP_string, std::unique_ptr<font>> FontManager::vfntFontData;
19 	SCP_vector<std::unique_ptr<FSFont>> FontManager::fonts;
20 
21 	FSFont* FontManager::currentFont = NULL;
22 
getFont(const SCP_string & name)23 	FSFont* FontManager::getFont(const SCP_string& name)
24 	{
25 		for (SCP_vector<std::unique_ptr<FSFont>>::iterator iter = fonts.begin(); iter != fonts.end(); iter++)
26 		{
27 			if ((*iter)->getName() == name)
28 				return iter->get();
29 		}
30 
31 		return NULL;
32 	}
33 
getFontByFilename(const SCP_string & filename)34 	FSFont* FontManager::getFontByFilename(const SCP_string& filename)
35 	{
36 		for (auto & iter : fonts)
37 		{
38 			if (iter->getFilename() == filename)
39 				return iter.get();
40 		}
41 		return nullptr;
42 	}
43 
getCurrentFont()44 	FSFont *FontManager::getCurrentFont()
45 	{
46 		return currentFont;
47 	}
48 
getCurrentFontIndex()49 	int FontManager::getCurrentFontIndex()
50 	{
51 		if (!FontManager::isReady())
52 			return -1;
53 
54 		return FontManager::getFontIndex(currentFont);
55 	}
56 
getFontIndex(const SCP_string & name)57 	int FontManager::getFontIndex(const SCP_string& name)
58 	{
59 		int index = 0;
60 
61 		for (SCP_vector<std::unique_ptr<FSFont>>::iterator iter = fonts.begin(); iter != fonts.end(); iter++, index++)
62 		{
63 			if ((*iter)->getName() == name)
64 				return index;
65 		}
66 
67 		return -1;
68 	}
69 
getFontIndex(FSFont * font)70 	int FontManager::getFontIndex(FSFont *font)
71 	{
72 		if (font == NULL)
73 			return -1;
74 
75 		int index = 0;
76 
77 		for (SCP_vector<std::unique_ptr<FSFont>>::iterator iter = fonts.begin(); iter != fonts.end(); iter++, index++)
78 		{
79 			if (iter->get() == font)
80 				return index;
81 		}
82 
83 		return -1;
84 	}
85 
numberOfFonts()86 	int FontManager::numberOfFonts()
87 	{
88 		return (int)fonts.size();
89 	}
90 
isReady()91 	bool FontManager::isReady()
92 	{
93 		return currentFont != NULL;
94 	}
95 
isFontNumberValid(int id)96 	bool FontManager::isFontNumberValid(int id)
97 	{
98 		return id >= 0 && id < (int)fonts.size();
99 	}
100 
setCurrentFont(FSFont * font)101 	void FontManager::setCurrentFont(FSFont *font)
102 	{
103 		Assertion(font != NULL, "New font pointer may not be NULL!");
104 		currentFont = font;
105 	}
106 
loadFontOld(const SCP_string & typeface)107 	font* FontManager::loadFontOld(const SCP_string& typeface)
108 	{
109 		if (vfntFontData.find(typeface) != vfntFontData.end())
110 		{
111 			font* data = vfntFontData[typeface].get();
112 
113 			Assert(data != NULL);
114 
115 			return data;
116 		}
117 
118 		bool localize = true;
119 
120 		CFILE* fp = cfopen(typeface.c_str(), "rb", CFILE_NORMAL, CF_TYPE_ANY, localize);
121 		if (fp == NULL)
122 		{
123 			mprintf(("Unable to find font file \"%s\"\n", typeface.c_str()));
124 			return NULL;
125 		}
126 
127 		std::unique_ptr<font> fnt(new font());
128 		if (!fnt)
129 		{
130 			mprintf(("Unable to allocate memory for \"%s\"\n", typeface.c_str()));
131 			return NULL;
132 		}
133 
134 		strcpy_s(fnt->filename, typeface.c_str());
135 		cfread(&fnt->id, 4, 1, fp);
136 		cfread(&fnt->version, sizeof(int), 1, fp);
137 		cfread(&fnt->num_chars, sizeof(int), 1, fp);
138 		cfread(&fnt->first_ascii, sizeof(int), 1, fp);
139 		cfread(&fnt->w, sizeof(int), 1, fp);
140 		cfread(&fnt->h, sizeof(int), 1, fp);
141 		cfread(&fnt->num_kern_pairs, sizeof(int), 1, fp);
142 		cfread(&fnt->kern_data_size, sizeof(int), 1, fp);
143 		cfread(&fnt->char_data_size, sizeof(int), 1, fp);
144 		cfread(&fnt->pixel_data_size, sizeof(int), 1, fp);
145 
146 		fnt->id = INTEL_SHORT(fnt->id); //-V570
147 		fnt->version = INTEL_INT(fnt->version); //-V570
148 		fnt->num_chars = INTEL_INT(fnt->num_chars); //-V570
149 		fnt->first_ascii = INTEL_INT(fnt->first_ascii); //-V570
150 		fnt->w = INTEL_INT(fnt->w); //-V570
151 		fnt->h = INTEL_INT(fnt->h); //-V570
152 		fnt->num_kern_pairs = INTEL_INT(fnt->num_kern_pairs); //-V570
153 		fnt->kern_data_size = INTEL_INT(fnt->kern_data_size); //-V570
154 		fnt->char_data_size = INTEL_INT(fnt->char_data_size); //-V570
155 		fnt->pixel_data_size = INTEL_INT(fnt->pixel_data_size); //-V570
156 
157 		if (fnt->kern_data_size)	{
158 			fnt->kern_data = (font_kernpair *)vm_malloc(fnt->kern_data_size);
159 			Assert(fnt->kern_data != NULL);
160 			cfread(fnt->kern_data, fnt->kern_data_size, 1, fp);
161 		}
162 		else {
163 			fnt->kern_data = NULL;
164 		}
165 		if (fnt->char_data_size)	{
166 			fnt->char_data = (font_char *)vm_malloc(fnt->char_data_size);
167 			Assert(fnt->char_data != NULL);
168 			cfread(fnt->char_data, fnt->char_data_size, 1, fp);
169 
170 			for (int i = 0; i<fnt->num_chars; i++) {
171 				fnt->char_data[i].spacing = INTEL_INT(fnt->char_data[i].spacing); //-V570
172 				fnt->char_data[i].byte_width = INTEL_INT(fnt->char_data[i].byte_width); //-V570
173 				fnt->char_data[i].offset = INTEL_INT(fnt->char_data[i].offset); //-V570
174 				fnt->char_data[i].kerning_entry = INTEL_INT(fnt->char_data[i].kerning_entry); //-V570
175 				fnt->char_data[i].user_data = INTEL_SHORT(fnt->char_data[i].user_data); //-V570
176 			}
177 		}
178 		else {
179 			fnt->char_data = NULL;
180 		}
181 		if (fnt->pixel_data_size)	{
182 			fnt->pixel_data = (ubyte *)vm_malloc(fnt->pixel_data_size);
183 			Assert(fnt->pixel_data != NULL);
184 			cfread(fnt->pixel_data, fnt->pixel_data_size, 1, fp);
185 		}
186 		else {
187 			fnt->pixel_data = NULL;
188 		}
189 		cfclose(fp);
190 
191 		// Create a bitmap for hardware cards.
192 		// JAS:  Try to squeeze this into the smallest square power of two texture.
193 		// This should probably be done at font generation time, not here.
194 		int w, h;
195 		if (fnt->pixel_data_size * 4 < 64 * 64) {
196 			w = h = 64;
197 		}
198 		else if (fnt->pixel_data_size * 4 < 128 * 128) {
199 			w = h = 128;
200 		}
201 		else if (fnt->pixel_data_size * 4 < 256 * 256) {
202 			w = h = 256;
203 		}
204 		else if (fnt->pixel_data_size * 4 < 512 * 512) {
205 			w = h = 512;
206 		}
207 		else {
208 			w = h = 1024;
209 		}
210 
211 		fnt->bm_w = w;
212 		fnt->bm_h = h;
213 		fnt->bm_data = (ubyte *)vm_malloc(fnt->bm_w*fnt->bm_h);
214 		fnt->bm_u = (int *)vm_malloc(sizeof(int)*fnt->num_chars);
215 		fnt->bm_v = (int *)vm_malloc(sizeof(int)*fnt->num_chars);
216 
217 		memset(fnt->bm_data, 0, fnt->bm_w * fnt->bm_h);
218 
219 		int i, x, y;
220 		x = y = 0;
221 		for (i = 0; i<fnt->num_chars; i++)	{
222 			ubyte * ubp;
223 			int x1, y1;
224 			ubp = &fnt->pixel_data[fnt->char_data[i].offset];
225 			if (x + fnt->char_data[i].byte_width >= fnt->bm_w)	{
226 				x = 0;
227 				y += fnt->h + 2;
228 				if (y + fnt->h > fnt->bm_h) {
229 					Error(LOCATION, "Font too big!\n");
230 				}
231 			}
232 			fnt->bm_u[i] = x;
233 			fnt->bm_v[i] = y;
234 
235 			for (y1 = 0; y1<fnt->h; y1++)	{
236 				for (x1 = 0; x1<fnt->char_data[i].byte_width; x1++)	{
237 					uint c = *ubp++;
238 					if (c > 14) c = 14;
239 					// The font pixels only have ~4 bits of information in them (since the value is at maximum 14) but
240 					// the bmpman code expects 8 bits of pixel information. To fix that we simply rescale this value to
241 					// fit into the [0, 255] range (15 * 17 is 255). This was adapted from the previous version where
242 					// the graphics code used an internal array for converting these values
243 					fnt->bm_data[(x + x1) + (y + y1)*fnt->bm_w] = (unsigned char)(c * 17);
244 				}
245 			}
246 			x += fnt->char_data[i].byte_width + 2;
247 		}
248 
249 		fnt->bitmap_id = bm_create(8, fnt->bm_w, fnt->bm_h, fnt->bm_data, BMP_AABITMAP);
250 
251 		auto ptr = fnt.get();
252 
253 		vfntFontData[typeface] = std::move(fnt);
254 
255 		return ptr;
256 	}
257 
loadVFNTFont(const SCP_string & name)258 	VFNTFont *FontManager::loadVFNTFont(const SCP_string& name)
259 	{
260 		font* font = FontManager::loadFontOld(name);
261 
262 		if (font == NULL)
263 		{
264 			return NULL;
265 		}
266 		else
267 		{
268 			std::unique_ptr<VFNTFont> vfnt(new VFNTFont(font));
269 
270 			auto ptr = vfnt.get();
271 
272 			fonts.push_back(std::move(vfnt));
273 
274 			return ptr;
275 		}
276 	}
277 
loadNVGFont(const SCP_string & fileName,float fontSize)278 	NVGFont *FontManager::loadNVGFont(const SCP_string& fileName, float fontSize)
279 	{
280 		if (allocatedData.find(fileName) == allocatedData.end())
281 		{
282 			CFILE *fontFile = cfopen(const_cast<char*>(fileName.c_str()), "rb", CFILE_NORMAL, CF_TYPE_ANY);
283 
284 			if (fontFile == NULL)
285 			{
286 				mprintf(("Couldn't open font file \"%s\"\n", fileName.c_str()));
287 				return NULL;
288 			}
289 
290 			size_t size = static_cast<size_t>(cfilelength(fontFile));
291 
292 			std::unique_ptr<ubyte[]> fontData(new ubyte[size]);
293 
294 			if (!fontData)
295 			{
296 				mprintf(("Couldn't allocate " SIZE_T_ARG " bytes for reading font file \"%s\"!\n", size, fileName.c_str()));
297 				cfclose(fontFile);
298 				return NULL;
299 			}
300 
301 			if (!cfread(fontData.get(), (int)size, 1, fontFile))
302 			{
303 				mprintf(("Error while reading font data from \"%s\"\n", fileName.c_str()));
304 				cfclose(fontFile);
305 				return NULL;
306 			}
307 
308 			cfclose(fontFile);
309 
310 			TrueTypeFontData newData;
311 
312 			newData.size = size;
313 			std::swap(newData.data, fontData);
314 
315 			allocatedData.insert(std::make_pair(fileName, std::move(newData)));
316 		}
317 
318 		auto data = &allocatedData.find(fileName)->second;
319 
320 		auto path = graphics::paths::PathRenderer::instance();
321 
322 		int handle = path->createFontMem(fileName.c_str(), data->data.get(), (int)data->size, 0);
323 
324 		if (handle < 0)
325 		{
326 			mprintf(("Couldn't couldn't create font for file \"%s\"\n", fileName.c_str()));
327 			return NULL;
328 		}
329 
330 		std::unique_ptr<NVGFont> nvgFont(new NVGFont());
331 		nvgFont->setHandle(handle);
332 		nvgFont->setSize(fontSize);
333 
334 		auto ptr = nvgFont.get();
335 
336 		fonts.push_back(std::move(nvgFont));
337 
338 		return ptr;
339 	}
340 
init()341 	void FontManager::init()
342 	{
343 	}
344 
close()345 	void FontManager::close()
346 	{
347 		allocatedData.clear();
348 		vfntFontData.clear();
349 		fonts.clear();
350 
351 		currentFont = NULL;
352 	}
353 }
354