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