font.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. /* -*- mode: c; tab-width: 4; c-basic-offset: 4; c-file-style: "linux" -*- */
  2. //
  3. // Copyright (c) 2009-2011, Wei Mingzhi <whistler_wmz@users.sf.net>.
  4. // Copyright (c) 2011-2017, SDLPAL development team.
  5. // All rights reserved.
  6. //
  7. // This file is part of SDLPAL.
  8. //
  9. // SDLPAL is free software: you can redistribute it and/or modify
  10. // it under the terms of the GNU General Public License as published by
  11. // the Free Software Foundation, either version 3 of the License, or
  12. // (at your option) any later version.
  13. //
  14. // This program is distributed in the hope that it will be useful,
  15. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. // GNU General Public License for more details.
  18. //
  19. // You should have received a copy of the GNU General Public License
  20. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. //
  22. #include "font.h"
  23. #include "util.h"
  24. #include "text.h"
  25. #define _FONT_C
  26. #include "fontglyph.h"
  27. #include "fontglyph_cn.h"
  28. #include "fontglyph_tw.h"
  29. #include "fontglyph_jp.h"
  30. #include "ascii.h"
  31. static int _font_height = 16;
  32. static uint8_t reverseBits(uint8_t x) {
  33. uint8_t y = 0;
  34. for (int i = 0 ; i < 8; i++){
  35. y <<= 1;
  36. y |= (x & 1);
  37. x >>= 1;
  38. }
  39. return y;
  40. }
  41. #ifdef DEBUG
  42. void dump_font(BYTE *buf,int rows, int cols)
  43. {
  44. for(int row=0;row<rows;row++)
  45. {
  46. for( int bit=0;bit<cols;bit++)
  47. if( buf[row] & (uint8_t)pow(2,bit) )
  48. printf("*");
  49. else
  50. printf(" ");
  51. printf("\n");
  52. }
  53. }
  54. static uint16_t reverseBits16(uint16_t x)
  55. {
  56. //specified to unifont structure; not common means
  57. uint8_t l = reverseBits(x);
  58. uint8_t h = reverseBits(x >> 8);
  59. return h << 8 | l;
  60. }
  61. void dump_font16(WORD *buf,int rows, int cols)
  62. {
  63. for(int row=0;row<rows;row++)
  64. {
  65. for( int bit=0;bit<cols;bit++)
  66. if( reverseBits16(buf[row]) & (uint16_t)pow(2,bit) )
  67. printf("*");
  68. else
  69. printf(" ");
  70. printf("\n");
  71. }
  72. }
  73. #endif
  74. static void PAL_LoadISOFont(void)
  75. {
  76. int i, j;
  77. for (i = 0; i < sizeof(iso_font) / 15; i++)
  78. {
  79. for (j = 0; j < 15; j++)
  80. {
  81. unicode_font[i][j] = reverseBits(iso_font[i * 15 + j]);
  82. }
  83. unicode_font[i][15] = 0;
  84. font_width[i] = 16;
  85. }
  86. }
  87. static void PAL_LoadEmbeddedFont(void)
  88. {
  89. FILE *fp;
  90. char *char_buf;
  91. wchar_t *wchar_buf;
  92. size_t nBytes;
  93. int nChars, i;
  94. //
  95. // Load the wor16.asc file.
  96. //
  97. if (NULL == (fp = UTIL_OpenFile("wor16.asc")))
  98. {
  99. return;
  100. }
  101. //
  102. // Get the size of wor16.asc file.
  103. //
  104. fseek(fp, 0, SEEK_END);
  105. nBytes = ftell(fp);
  106. //
  107. // Allocate buffer & read all the character codes.
  108. //
  109. if (NULL == (char_buf = (char *)malloc(nBytes)))
  110. {
  111. fclose(fp);
  112. return;
  113. }
  114. fseek(fp, 0, SEEK_SET);
  115. if (fread(char_buf, 1, nBytes, fp) < nBytes)
  116. {
  117. fclose(fp);
  118. return;
  119. }
  120. //
  121. // Close wor16.asc file.
  122. //
  123. fclose(fp);
  124. //
  125. // Detect the codepage of 'wor16.asc' and exit if not BIG5 or probability < 99
  126. // Note: 100% probability is impossible as the function does not recognize some special
  127. // characters such as bopomofo that may be used by 'wor16.asc'.
  128. //
  129. if (PAL_DetectCodePageForString(char_buf, nBytes, CP_BIG5, &i) != CP_BIG5 || i < 99)
  130. {
  131. free(char_buf);
  132. return;
  133. }
  134. //
  135. // Convert characters into unicode
  136. // Explictly specify BIG5 here for compatibility with codepage auto-detection
  137. //
  138. nChars = PAL_MultiByteToWideCharCP(CP_BIG5, char_buf, nBytes, NULL, 0);
  139. if (NULL == (wchar_buf = (wchar_t *)malloc(nChars * sizeof(wchar_t))))
  140. {
  141. free(char_buf);
  142. return;
  143. }
  144. PAL_MultiByteToWideCharCP(CP_BIG5, char_buf, nBytes, wchar_buf, nChars);
  145. free(char_buf);
  146. //
  147. // Read bitmaps from wor16.fon file.
  148. //
  149. fp = UTIL_OpenFile("wor16.fon");
  150. //
  151. // The font glyph data begins at offset 0x682 in wor16.fon.
  152. //
  153. fseek(fp, 0x682, SEEK_SET);
  154. //
  155. // Replace the original fonts
  156. //
  157. for (i = 0; i < nChars; i++)
  158. {
  159. wchar_t w = (wchar_buf[i] >= unicode_upper_base) ? (wchar_buf[i] - unicode_upper_base + unicode_lower_top) : wchar_buf[i];
  160. if (fread(unicode_font[w], 30, 1, fp) == 1)
  161. {
  162. unicode_font[w][30] = 0;
  163. unicode_font[w][31] = 0;
  164. }
  165. font_width[w] = 32;
  166. }
  167. free(wchar_buf);
  168. fclose(fp);
  169. _font_height = 15;
  170. }
  171. INT
  172. PAL_LoadUserFont(
  173. LPCSTR pszBdfFileName
  174. )
  175. /*++
  176. Purpose:
  177. Loads a BDF bitmap font file.
  178. Parameters:
  179. [IN] pszBdfFileName - Name of BDF bitmap font file..
  180. Return value:
  181. 0 = success, -1 = failure.
  182. --*/
  183. {
  184. char buf[4096];
  185. int state = 0, fstate = 0;
  186. int codepage = -1;
  187. DWORD dwEncoding = 0;
  188. BYTE bFontGlyph[32] = {0};
  189. int iCurHeight = 0;
  190. int bbw = 0, bbh = 0, bbox, bboy;
  191. FILE *fp = UTIL_OpenFileForMode(pszBdfFileName, "r");
  192. if (fp == NULL)
  193. {
  194. return -1;
  195. }
  196. _font_height = 16;
  197. while (fgets(buf, 4096, fp) != NULL)
  198. {
  199. if (state == 0)
  200. {
  201. if (strncmp(buf, "CHARSET_REGISTRY", 16) == 0)
  202. {
  203. if (strcasestr(buf, "Big5") != NULL)
  204. {
  205. codepage = CP_BIG5;
  206. }
  207. else if (strcasestr(buf, "GBK") != NULL || strcasestr(buf, "GB2312") != NULL)
  208. {
  209. codepage = CP_GBK;
  210. }
  211. else if (strcasestr(buf, "ISO10646") != NULL)
  212. {
  213. codepage = CP_UCS;
  214. }
  215. //else if (strstr(buf, "JISX0208") != NULL)
  216. //
  217. // codepage = CP_JISX0208;
  218. //}
  219. else
  220. {
  221. TerminateOnError("Charset of %s is %s, which is not a supported yet.",pszBdfFileName,buf);
  222. }
  223. }
  224. else if (strncmp(buf, "ENCODING", 8) == 0)
  225. {
  226. dwEncoding = atoi(buf + 8);
  227. }
  228. else if (strncmp(buf, "SIZE", 3) == 0)
  229. {
  230. int bytes_consumed = 0, bytes_now;
  231. int got_size;
  232. BOOL got_expected = FALSE;
  233. char size[10];
  234. sscanf(buf + bytes_consumed, "%s%n", size, &bytes_now);
  235. bytes_consumed += bytes_now;
  236. while (sscanf(buf + bytes_consumed, "%d%n", &got_size, &bytes_now))
  237. {
  238. bytes_consumed += bytes_now;
  239. if (got_size == 16 || got_size == 15)
  240. {
  241. _font_height = got_size;
  242. got_expected = TRUE;
  243. }
  244. }
  245. if (!got_expected)
  246. TerminateOnError("%s not contains expected font size 15/16!", pszBdfFileName);
  247. }
  248. else if (strncmp(buf, "BBX", 3) == 0)
  249. {
  250. int bytes_consumed = 0, bytes_now;
  251. char bbx[10];
  252. sscanf(buf+bytes_consumed,"%s%n",bbx,&bytes_now);bytes_consumed += bytes_now;
  253. sscanf(buf+bytes_consumed,"%d%n",&bbw,&bytes_now);bytes_consumed += bytes_now;
  254. sscanf(buf+bytes_consumed,"%d%n",&bbh,&bytes_now);bytes_consumed += bytes_now;
  255. sscanf(buf+bytes_consumed,"%d%n",&bbox,&bytes_now);bytes_consumed += bytes_now;
  256. sscanf(buf+bytes_consumed,"%d%n",&bboy,&bytes_now);bytes_consumed += bytes_now;
  257. }
  258. else if (strncmp(buf, "BITMAP", 6) == 0)
  259. {
  260. state = 1;
  261. iCurHeight = 0;
  262. for(iCurHeight=0;iCurHeight<bboy;iCurHeight++){
  263. bFontGlyph[iCurHeight * 2] = 0;
  264. bFontGlyph[iCurHeight * 2 + 1] = 0;
  265. }
  266. memset(bFontGlyph, 0, sizeof(bFontGlyph));
  267. }
  268. }
  269. else if (state == 1)
  270. {
  271. if (strncmp(buf, "ENDCHAR", 7) == 0)
  272. {
  273. //
  274. // Replace the original fonts
  275. //
  276. BYTE szCp[3];
  277. szCp[0] = (dwEncoding >> 8) & 0xFF;
  278. szCp[1] = dwEncoding & 0xFF;
  279. szCp[2] = 0;
  280. if (codepage == CP_GBK && dwEncoding > 0xFF)
  281. {
  282. szCp[0] |= 0x80;
  283. szCp[1] |= 0x80;
  284. }
  285. wchar_t wc[2] = { 0 };
  286. PAL_MultiByteToWideCharCP(codepage, (LPCSTR)szCp, 2, wc, 1);
  287. if (wc[0] != 0)
  288. {
  289. wchar_t w = (wc[0] >= unicode_upper_base) ? (wc[0] - unicode_upper_base + unicode_lower_top) : wc[0];
  290. if (w < sizeof(unicode_font) / sizeof(unicode_font[0]))
  291. {
  292. memcpy(unicode_font[w], bFontGlyph, sizeof(bFontGlyph));
  293. }
  294. }
  295. state = 0;
  296. }
  297. else
  298. {
  299. if (iCurHeight < bbh )
  300. {
  301. WORD wCode = strtoul(buf, NULL, 16);
  302. if(bbw <= 8)
  303. {
  304. switch(fstate)
  305. {
  306. case 0:
  307. bFontGlyph[iCurHeight * 2] = wCode;
  308. fstate = 1;
  309. break;
  310. case 1:
  311. bFontGlyph[iCurHeight * 2+1] = wCode;
  312. fstate = 0;
  313. iCurHeight++;
  314. break;
  315. }
  316. }else{
  317. bFontGlyph[iCurHeight * 2] = (wCode >> 8);
  318. bFontGlyph[iCurHeight * 2 + 1] = (wCode & 0xFF);
  319. iCurHeight++;
  320. }
  321. }
  322. }
  323. }
  324. }
  325. fclose(fp);
  326. return 0;
  327. }
  328. int
  329. PAL_InitFont(
  330. const CONFIGURATION* cfg
  331. )
  332. {
  333. #define PAL_LOAD_INTERNAL_FONT(fontdata, height) \
  334. { \
  335. for (int i = 0; i < sizeof(fontdata) / sizeof(fontdata[0]); i++) \
  336. { \
  337. wchar_t w = fontdata[i].code; \
  338. w = (w >= unicode_upper_base) ? (w - unicode_upper_base + unicode_lower_top) : w; \
  339. if (w < sizeof(unicode_font) / sizeof(unicode_font[0])) \
  340. { \
  341. memcpy(unicode_font[w], fontdata[i].data, 32); \
  342. font_width[w] = 32; \
  343. } \
  344. } \
  345. _font_height = height; \
  346. }
  347. if (!cfg->pszMsgFile)
  348. {
  349. PAL_LoadEmbeddedFont();
  350. }
  351. if (g_TextLib.fUseISOFont)
  352. {
  353. PAL_LoadISOFont();
  354. }
  355. if (cfg->pszFontFile)
  356. {
  357. PAL_LoadUserFont(cfg->pszFontFile);
  358. }
  359. else if (_font_height != 15)
  360. {
  361. switch (g_TextLib.iFontFlavor)
  362. {
  363. case kFontFlavorAuto:
  364. switch (PAL_GetCodePage())
  365. {
  366. case CP_GBK:
  367. PAL_LOAD_INTERNAL_FONT(fontglyph_cn, 16);
  368. break;
  369. case CP_BIG5:
  370. PAL_LOAD_INTERNAL_FONT(fontglyph_tw, 15);
  371. break;
  372. default:
  373. break;
  374. }
  375. break;
  376. case kFontFlavorSimpChin:
  377. PAL_LOAD_INTERNAL_FONT(fontglyph_cn, 16);
  378. break;
  379. case kFontFlavorTradChin:
  380. PAL_LOAD_INTERNAL_FONT(fontglyph_tw, 15);
  381. break;
  382. case kFontFlavorJapanese:
  383. PAL_LOAD_INTERNAL_FONT(fontglyph_jp, 16);
  384. break;
  385. case kFontFlavorUnifont:
  386. default:
  387. break;
  388. }
  389. }
  390. return 0;
  391. }
  392. void
  393. PAL_FreeFont(
  394. void
  395. )
  396. {
  397. }
  398. void
  399. PAL_DrawCharOnSurface(
  400. uint16_t wChar,
  401. SDL_Surface *lpSurface,
  402. PAL_POS pos,
  403. uint8_t bColor,
  404. BOOL fUse8x8Font
  405. )
  406. {
  407. int i, j;
  408. int x = PAL_X(pos), y = PAL_Y(pos);
  409. //
  410. // Check for NULL pointer & invalid char code.
  411. //
  412. if (lpSurface == NULL || (wChar >= unicode_lower_top && wChar < unicode_upper_base) ||
  413. wChar >= unicode_upper_top || (_font_height == 8 && wChar >= 0x100))
  414. {
  415. return;
  416. }
  417. //
  418. // Locate for this character in the font lib.
  419. //
  420. if (wChar >= unicode_upper_base)
  421. {
  422. wChar -= (unicode_upper_base - unicode_lower_top);
  423. }
  424. //
  425. // Draw the character to the surface.
  426. //
  427. LPBYTE dest = (LPBYTE)lpSurface->pixels + y * lpSurface->pitch + x;
  428. LPBYTE top = (LPBYTE)lpSurface->pixels + lpSurface->h * lpSurface->pitch;
  429. if (fUse8x8Font)
  430. {
  431. for (i = 0; i < 8 && dest < top; i++, dest += lpSurface->pitch)
  432. {
  433. for (j = 0; j < 8 && x + j < lpSurface->w; j++)
  434. {
  435. if (iso_font_8x8[wChar][i] & (1 << j))
  436. {
  437. dest[j] = bColor;
  438. }
  439. }
  440. }
  441. }
  442. else
  443. {
  444. if (font_width[wChar] == 32)
  445. {
  446. for (i = 0; i < _font_height * 2 && dest < top; i += 2, dest += lpSurface->pitch)
  447. {
  448. for (j = 0; j < 8 && x + j < lpSurface->w; j++)
  449. {
  450. if (unicode_font[wChar][i] & (1 << (7 - j)))
  451. {
  452. dest[j] = bColor;
  453. }
  454. }
  455. for (j = 0; j < 8 && x + j + 8 < lpSurface->w; j++)
  456. {
  457. if (unicode_font[wChar][i + 1] & (1 << (7 - j)))
  458. {
  459. dest[j + 8] = bColor;
  460. }
  461. }
  462. }
  463. }
  464. else
  465. {
  466. for (i = 0; i < _font_height && dest < top; i++, dest += lpSurface->pitch)
  467. {
  468. for (j = 0; j < 8 && x + j < lpSurface->w; j++)
  469. {
  470. if (unicode_font[wChar][i] & (1 << (7 - j)))
  471. {
  472. dest[j] = bColor;
  473. }
  474. }
  475. }
  476. }
  477. }
  478. }
  479. int
  480. PAL_CharWidth(
  481. uint16_t wChar
  482. )
  483. {
  484. if ((wChar >= unicode_lower_top && wChar < unicode_upper_base) || wChar >= unicode_upper_top)
  485. {
  486. return 0;
  487. }
  488. //
  489. // Locate for this character in the font lib.
  490. //
  491. if (wChar >= unicode_upper_base)
  492. {
  493. wChar -= (unicode_upper_base - unicode_lower_top);
  494. }
  495. return font_width[wChar] >> 1;
  496. }
  497. int
  498. PAL_FontHeight(
  499. void
  500. )
  501. {
  502. return _font_height;
  503. }