1
0

PatternFont.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. /*
  2. * PatternFont.cpp
  3. * ---------------
  4. * Purpose: Code for creating pattern font bitmaps
  5. * Notes : (currently none)
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. #include "stdafx.h"
  10. #include "PatternFont.h"
  11. #include "Mptrack.h"
  12. #include "Mainfrm.h"
  13. #include "TrackerSettings.h"
  14. #include "../soundlib/Tables.h"
  15. OPENMPT_NAMESPACE_BEGIN
  16. //////////////////////////////////////////////
  17. // Font Definitions
  18. // Medium Font (Default)
  19. static constexpr PATTERNFONT gDefaultPatternFont =
  20. {
  21. nullptr,
  22. nullptr,
  23. 92,13, // Column Width & Height
  24. 0,0, // Clear location
  25. 130,8, // Space Location.
  26. {20, 20, 24, 9, 15}, // Element Widths
  27. {0, 0, 0, 0, 0}, // Padding pixels contained in element width
  28. 20,13, // Numbers 0-F (hex)
  29. 30,13, // Numbers 10-29 (dec)
  30. 64,26, // A-M#
  31. 78,26, // N-Z? // MEDIUM FONT !!!
  32. 0, 0,
  33. { 7, 5 }, 8, // Note & Octave Width
  34. 42,13, // Volume Column Effects
  35. 8,8,
  36. -1,
  37. 8, // 8+7 = 15
  38. -3, -1, 12,
  39. 1, // Margin for first digit of PC event parameter number
  40. 2, // Margin for first digit of PC event parameter value
  41. 1, // Margin for second digit of parameter
  42. 13, // Vertical spacing between letters in the bitmap
  43. };
  44. //////////////////////////////////////////////////
  45. // Small Font
  46. static constexpr PATTERNFONT gSmallPatternFont =
  47. {
  48. nullptr,
  49. nullptr,
  50. 70,11, // Column Width & Height
  51. 92,0, // Clear location
  52. 130,8, // Space Location.
  53. {16, 14, 18, 7, 11}, // Element Widths
  54. {0, 0, 0, 0, 0}, // Padding pixels contained in element width
  55. 108,13, // Numbers 0-F (hex)
  56. 120,13, // Numbers 10-29 (dec)
  57. 142,26, // A-M#
  58. 150,26, // N-Z? // SMALL FONT !!!
  59. 92, 0, // Notes
  60. { 5, 5 }, 6, // Note & Octave Width
  61. 132,13, // Volume Column Effects
  62. 6,5,
  63. -1,
  64. 6, // 8+7 = 15
  65. -3, 1, 9, // InstrOfs + nInstrHiWidth
  66. 1, // Margin for first digit of PC event parameter number
  67. 2, // Margin for first digit of PC event parameter value
  68. 1, // Margin for second digit of parameter
  69. 13, // // Vertical spacing between letters in the bitmap
  70. };
  71. // NOTE: See also CViewPattern::DrawNote() when changing stuff here
  72. // or adding new fonts - The custom tuning note names might require
  73. // some additions there.
  74. const PATTERNFONT *PatternFont::currentFont = nullptr;
  75. static MODPLUGDIB customFontBitmap;
  76. static MODPLUGDIB customFontBitmapASCII;
  77. static void DrawChar(HDC hDC, WCHAR ch, int x, int y, int w, int h)
  78. {
  79. CRect rect(x, y, x + w, y + h);
  80. ::DrawTextW(hDC, &ch, 1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
  81. }
  82. static void DrawChar(HDC hDC, CHAR ch, int x, int y, int w, int h)
  83. {
  84. CRect rect(x, y, x + w, y + h);
  85. ::DrawTextA(hDC, &ch, 1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
  86. }
  87. #if MPT_CXX_AT_LEAST(20)
  88. static void DrawChar(HDC hDC, char8_t ch8, int x, int y, int w, int h)
  89. {
  90. CRect rect(x, y, x + w, y + h);
  91. CHAR ch = mpt::unsafe_char_convert<char>(ch8);
  92. ::DrawTextA(hDC, &ch, 1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
  93. }
  94. #endif
  95. template<typename char_t>
  96. static void DrawString(HDC hDC, const char_t *text, int len, int x, int y, int w, int h)
  97. {
  98. for(int i = 0; i < len; i++)
  99. {
  100. DrawChar(hDC, text[i], x, y, w, h);
  101. x += w;
  102. }
  103. }
  104. void PatternFont::UpdateFont(HWND hwnd)
  105. {
  106. FontSetting font = TrackerSettings::Instance().patternFont;
  107. const PATTERNFONT *builtinFont = nullptr;
  108. if(font.name == PATTERNFONT_SMALL || font.name.empty())
  109. {
  110. builtinFont = &gSmallPatternFont;
  111. } else if(font.name == PATTERNFONT_LARGE)
  112. {
  113. builtinFont = &gDefaultPatternFont;
  114. }
  115. if(builtinFont != nullptr && font.size < 1)
  116. {
  117. currentFont = builtinFont;
  118. return;
  119. }
  120. static PATTERNFONT pf = { 0 };
  121. currentFont = &pf;
  122. static FontSetting previousFont;
  123. if(previousFont == font)
  124. {
  125. // Nothing to do
  126. return;
  127. }
  128. previousFont = font;
  129. DeleteFontData();
  130. pf.dib = &customFontBitmap;
  131. pf.dibASCII = nullptr;
  132. // Upscale built-in font?
  133. if(builtinFont != nullptr)
  134. {
  135. // Copy and scale original 4-bit bitmap
  136. LimitMax(font.size, 10);
  137. font.size++;
  138. customFontBitmap.bmiHeader = CMainFrame::bmpNotes->bmiHeader;
  139. customFontBitmap.bmiHeader.biWidth *= font.size;
  140. customFontBitmap.bmiHeader.biHeight *= font.size;
  141. customFontBitmap.bmiHeader.biSizeImage = customFontBitmap.bmiHeader.biWidth * customFontBitmap.bmiHeader.biHeight / 2;
  142. customFontBitmap.lpDibBits = new uint8[customFontBitmap.bmiHeader.biSizeImage];
  143. // Upscale the image (ugly code ahead)
  144. const uint8 *origPixels = CMainFrame::bmpNotes->lpDibBits;
  145. uint8 *scaledPixels = customFontBitmap.lpDibBits;
  146. const int bytesPerLine = customFontBitmap.bmiHeader.biWidth / 2, scaleBytes = bytesPerLine * font.size;
  147. bool outPos = false;
  148. for(int y = 0; y < CMainFrame::bmpNotes->bmiHeader.biHeight; y++, scaledPixels += scaleBytes - bytesPerLine)
  149. {
  150. for(int x = 0; x < CMainFrame::bmpNotes->bmiHeader.biWidth; x++)
  151. {
  152. uint8 pixel = *origPixels;
  153. if(x % 2u == 0)
  154. {
  155. pixel >>= 4;
  156. } else
  157. {
  158. pixel &= 0x0F;
  159. origPixels++;
  160. }
  161. for(int scaleX = 0; scaleX < font.size; scaleX++)
  162. {
  163. if(!outPos)
  164. {
  165. for(int scaleY = 0; scaleY < scaleBytes; scaleY += bytesPerLine)
  166. {
  167. scaledPixels[scaleY] = pixel << 4;
  168. }
  169. } else
  170. {
  171. for(int scaleY = 0; scaleY < scaleBytes; scaleY += bytesPerLine)
  172. {
  173. scaledPixels[scaleY] |= pixel;
  174. }
  175. scaledPixels++;
  176. }
  177. outPos = !outPos;
  178. }
  179. }
  180. }
  181. pf.nWidth = (builtinFont->nWidth - 4) * font.size + 4;
  182. pf.nHeight = builtinFont->nHeight * font.size;
  183. pf.nClrX = builtinFont->nClrX * font.size;
  184. pf.nClrY = builtinFont->nClrY * font.size;
  185. pf.nSpaceX = builtinFont->nSpaceX * font.size;
  186. pf.nSpaceY = builtinFont->nSpaceY * font.size;
  187. for(std::size_t i = 0; i < std::size(pf.nEltWidths); i++)
  188. {
  189. pf.nEltWidths[i] = builtinFont->nEltWidths[i] * font.size;
  190. pf.padding[i] = builtinFont->padding[i] * font.size;
  191. }
  192. pf.nNumX = builtinFont->nNumX * font.size;
  193. pf.nNumY = builtinFont->nNumY * font.size;
  194. pf.nNum10X = builtinFont->nNum10X * font.size;
  195. pf.nNum10Y = builtinFont->nNum10Y * font.size;
  196. pf.nAlphaAM_X = builtinFont->nAlphaAM_X * font.size;
  197. pf.nAlphaAM_Y = builtinFont->nAlphaAM_Y * font.size;
  198. pf.nAlphaNZ_X = builtinFont->nAlphaNZ_X * font.size;
  199. pf.nAlphaNZ_Y = builtinFont->nAlphaNZ_Y * font.size;
  200. pf.nNoteX = builtinFont->nNoteX * font.size;
  201. pf.nNoteY = builtinFont->nNoteY * font.size;
  202. pf.nNoteWidth[0] = builtinFont->nNoteWidth[0] * font.size;
  203. pf.nNoteWidth[1] = builtinFont->nNoteWidth[1] * font.size;
  204. pf.nOctaveWidth = builtinFont->nOctaveWidth * font.size;
  205. pf.nVolX = builtinFont->nVolX * font.size;
  206. pf.nVolY = builtinFont->nVolY * font.size;
  207. pf.nVolCmdWidth = builtinFont->nVolCmdWidth * font.size;
  208. pf.nVolHiWidth = builtinFont->nVolHiWidth * font.size;
  209. pf.nCmdOfs = builtinFont->nCmdOfs * font.size;
  210. pf.nParamHiWidth = builtinFont->nParamHiWidth * font.size;
  211. pf.nInstrOfs = builtinFont->nInstrOfs * font.size;
  212. pf.nInstr10Ofs = builtinFont->nInstr10Ofs * font.size;
  213. pf.nInstrHiWidth = builtinFont->nInstrHiWidth * font.size;
  214. pf.pcParamMargin = builtinFont->pcParamMargin * font.size;
  215. pf.pcValMargin = builtinFont->pcValMargin * font.size;
  216. pf.paramLoMargin = builtinFont->paramLoMargin * font.size;
  217. pf.spacingY = builtinFont->spacingY * font.size;
  218. // Create 4-pixel border
  219. const int bmWidth2 = pf.dib->bmiHeader.biWidth / 2;
  220. for(int y = 0, x = (customFontBitmap.bmiHeader.biHeight - pf.nClrY - pf.nHeight) * bmWidth2 + (pf.nClrX + pf.nWidth - 4) / 2; y < pf.nHeight; y++, x += bmWidth2)
  221. {
  222. pf.dib->lpDibBits[x] = 0xEC;
  223. pf.dib->lpDibBits[x + 1] = 0xC4;
  224. }
  225. return;
  226. }
  227. // Create our own font!
  228. CDC hDC;
  229. hDC.CreateCompatibleDC(CDC::FromHandle(::GetDC(hwnd)));
  230. // Point size to pixels
  231. font.size = -MulDiv(font.size, Util::GetDPIy(hwnd), 720);
  232. CFont gdiFont;
  233. gdiFont.CreateFont(font.size, 0, 0, 0, font.flags[FontSetting::Bold] ? FW_BOLD : FW_NORMAL, font.flags[FontSetting::Italic] ? TRUE : FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_RASTER_PRECIS, CLIP_DEFAULT_PRECIS, NONANTIALIASED_QUALITY, FIXED_PITCH | FF_DONTCARE, mpt::ToCString(font.name));
  234. CFont *oldFont = hDC.SelectObject(&gdiFont);
  235. CPoint pt = hDC.GetTextExtent(_T("W"));
  236. const int charWidth = pt.x, charHeight = pt.y;
  237. const int spacing = charWidth / 4;
  238. const int width = charWidth * 12 + spacing * 2 + 4, height = charHeight * 21;
  239. pf.nWidth = width; // Column Width & Height, including 4-pixels border
  240. pf.nHeight = charHeight;
  241. pf.nClrX = pf.nClrY = 0; // Clear (empty note) location
  242. pf.nSpaceX = charWidth * 7; // White location (must be big enough)
  243. pf.nSpaceY = charHeight;
  244. pf.nEltWidths[0] = charWidth * 3; // Note
  245. pf.padding[0] = 0;
  246. pf.nEltWidths[1] = charWidth * 3 + spacing; // Instr
  247. pf.padding[1] = spacing;
  248. pf.nEltWidths[2] = charWidth * 3 + spacing; // Volume
  249. pf.padding[2] = spacing;
  250. pf.nEltWidths[3] = charWidth; // Command letter
  251. pf.padding[3] = 0;
  252. pf.nEltWidths[4] = charWidth * 2; // Command param
  253. pf.padding[4] = 0;
  254. pf.nNumX = charWidth * 3; // Vertically-oriented numbers 0x00-0x0F
  255. pf.nNumY = charHeight;
  256. pf.nNum10X = charWidth * 4; // Numbers 10-29
  257. pf.nNum10Y = charHeight;
  258. pf.nAlphaAM_X = charWidth * 6; // Letters A-M +#
  259. pf.nAlphaAM_Y = charHeight * 2;
  260. pf.nAlphaNZ_X = charWidth * 7; // Letters N-Z +?
  261. pf.nAlphaNZ_Y = charHeight * 2;
  262. pf.nNoteX = 0; // Notes ..., C-, C#, ...
  263. pf.nNoteY = 0;
  264. pf.nNoteWidth[0] = charWidth; // Total width of note (C#)
  265. pf.nNoteWidth[1] = charWidth; // Total width of note (C#)
  266. pf.nOctaveWidth = charWidth; // Octave Width
  267. pf.nVolX = charWidth * 8; // Volume Column Effects
  268. pf.nVolY = charHeight;
  269. pf.nVolCmdWidth = charWidth; // Width of volume effect
  270. pf.nVolHiWidth = charWidth; // Width of first character in volume parameter
  271. pf.nCmdOfs = 0; // XOffset (-xxx) around the command letter
  272. pf.nParamHiWidth = charWidth;
  273. pf.nInstrOfs = -charWidth;
  274. pf.nInstr10Ofs = 0;
  275. pf.nInstrHiWidth = charWidth * 2;
  276. pf.pcParamMargin = 0;
  277. pf.pcValMargin = 0;
  278. pf.paramLoMargin = 0; // Margin for second digit of parameter
  279. pf.spacingY = charHeight;
  280. {
  281. pf.dib->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  282. pf.dib->bmiHeader.biWidth = ((width + 7) & ~7); // 4-byte alignment
  283. pf.dib->bmiHeader.biHeight = -(int32)height;
  284. pf.dib->bmiHeader.biSizeImage = pf.dib->bmiHeader.biWidth * height / 2;
  285. pf.dib->bmiHeader.biPlanes = 1;
  286. pf.dib->bmiHeader.biBitCount = 4;
  287. pf.dib->bmiHeader.biCompression = BI_RGB;
  288. pf.dib->lpDibBits = new uint8[pf.dib->bmiHeader.biSizeImage];
  289. pf.dib->bmiColors[0] = rgb2quad(RGB(0x00, 0x00, 0x00));
  290. pf.dib->bmiColors[15] = rgb2quad(RGB(0xFF, 0xFF, 0xFF));
  291. uint8 *data = nullptr;
  292. HBITMAP bitmap = ::CreateDIBSection(hDC, (BITMAPINFO *)&pf.dib->bmiHeader, DIB_RGB_COLORS, (void **)&data, nullptr, 0);
  293. if(!bitmap)
  294. {
  295. hDC.SelectObject(oldFont);
  296. gdiFont.DeleteObject();
  297. hDC.DeleteDC();
  298. currentFont = &gDefaultPatternFont;
  299. return;
  300. }
  301. HGDIOBJ oldBitmap = hDC.SelectObject(bitmap);
  302. hDC.FillSolidRect(0, 0, width - 4, height, RGB(0xFF, 0xFF, 0xFF));
  303. hDC.SetTextColor(RGB(0x00, 0x00, 0x00));
  304. hDC.SetBkColor(RGB(0xFF, 0xFF, 0xFF));
  305. hDC.SetTextAlign(TA_TOP | TA_LEFT);
  306. // Empty cells (dots - i-th bit set = dot in the i-th column of a cell)
  307. const uint8 dots[5] = { 1 | 2 | 4, 2 | 4, 2 | 4, 1, 1 | 2 };
  308. const auto dotStr = TrackerSettings::Instance().patternFontDot.Get();
  309. auto dotChar = dotStr.empty() ? UC_(' ') : dotStr[0];
  310. for(int cell = 0, offset = 0; cell < static_cast<int>(std::size(dots)); cell++)
  311. {
  312. uint8 dot = dots[cell];
  313. for(int i = 0; dot != 0; i++)
  314. {
  315. if(dot & 1) DrawChar(hDC, dotChar, pf.nClrX + offset + i * charWidth, pf.nClrY, charWidth, charHeight);
  316. dot >>= 1;
  317. }
  318. offset += pf.nEltWidths[cell];
  319. }
  320. // Notes
  321. for(int i = 0; i < 12; i++)
  322. {
  323. DrawString(hDC, NoteNamesSharp[i], 2, pf.nNoteX, pf.nNoteY + (i + 1) * charHeight, charWidth, charHeight);
  324. }
  325. DrawString(hDC, "^^", 2, pf.nNoteX, pf.nNoteY + 13 * charHeight, charWidth, charHeight);
  326. DrawString(hDC, "==", 2, pf.nNoteX, pf.nNoteY + 14 * charHeight, charWidth, charHeight);
  327. DrawString(hDC, "PC", 2, pf.nNoteX, pf.nNoteY + 15 * charHeight, charWidth, charHeight);
  328. DrawString(hDC, "PCs", 3, pf.nNoteX, pf.nNoteY + 16 * charHeight, charWidth, charHeight);
  329. DrawString(hDC, "~~", 2, pf.nNoteX, pf.nNoteY + 17 * charHeight, charWidth, charHeight);
  330. // Hex chars
  331. const char hexChars[] = "0123456789ABCDEF";
  332. for(int i = 0; i < 16; i++)
  333. {
  334. DrawChar(hDC, hexChars[i], pf.nNumX, pf.nNumY + i * charHeight, charWidth, charHeight);
  335. }
  336. // Double-digit numbers
  337. for(int i = 0; i < 20; i++)
  338. {
  339. char s[2];
  340. s[0] = char('1' + i / 10);
  341. s[1] = char('0' + i % 10);
  342. DrawString(hDC, s, 2, pf.nNum10X, pf.nNum10Y + i * charHeight, charWidth, charHeight);
  343. }
  344. // Volume commands
  345. const char volEffects[]= " vpcdabuhlrgfe:o";
  346. static_assert(mpt::array_size<decltype(volEffects)>::size - 1 == MAX_VOLCMDS);
  347. for(int i = 0; i < MAX_VOLCMDS; i++)
  348. {
  349. DrawChar(hDC, volEffects[i], pf.nVolX, pf.nVolY + i * charHeight, charWidth, charHeight);
  350. }
  351. // Letters A-Z
  352. for(int i = 0; i < 13; i++)
  353. {
  354. DrawChar(hDC, char('A' + i), pf.nAlphaAM_X, pf.nAlphaAM_Y + i * charHeight, charWidth, charHeight);
  355. DrawChar(hDC, char('N' + i), pf.nAlphaNZ_X, pf.nAlphaNZ_Y + i * charHeight, charWidth, charHeight);
  356. }
  357. // Special chars
  358. DrawChar(hDC, '#', pf.nAlphaAM_X, pf.nAlphaAM_Y + 13 * charHeight, charWidth, charHeight);
  359. DrawChar(hDC, '?', pf.nAlphaNZ_X, pf.nAlphaNZ_Y + 13 * charHeight, charWidth, charHeight);
  360. DrawChar(hDC, 'b', pf.nAlphaAM_X, pf.nAlphaAM_Y + 14 * charHeight, charWidth, charHeight);
  361. DrawChar(hDC, '\\', pf.nAlphaNZ_X, pf.nAlphaNZ_Y + 14 * charHeight, charWidth, charHeight);
  362. DrawChar(hDC, '-', pf.nAlphaAM_X, pf.nAlphaAM_Y + 15 * charHeight, charWidth, charHeight);
  363. DrawChar(hDC, ':', pf.nAlphaNZ_X, pf.nAlphaNZ_Y + 15 * charHeight, charWidth, charHeight);
  364. DrawChar(hDC, '+', pf.nAlphaAM_X, pf.nAlphaAM_Y + 16 * charHeight, charWidth, charHeight);
  365. DrawChar(hDC, '*', pf.nAlphaNZ_X, pf.nAlphaNZ_Y + 16 * charHeight, charWidth, charHeight);
  366. DrawChar(hDC, 'd', pf.nAlphaAM_X, pf.nAlphaAM_Y + 17 * charHeight, charWidth, charHeight);
  367. ::GdiFlush();
  368. std::memcpy(pf.dib->lpDibBits, data, pf.dib->bmiHeader.biSizeImage);
  369. // Create 4-pixel border
  370. const int bmWidth2 = pf.dib->bmiHeader.biWidth / 2;
  371. for(int y = 0, x = width / 2 - 2; y < height; y++, x += bmWidth2)
  372. {
  373. pf.dib->lpDibBits[x] = 0xEC;
  374. pf.dib->lpDibBits[x + 1] = 0xC4;
  375. }
  376. hDC.SelectObject(oldBitmap);
  377. DeleteBitmap(bitmap);
  378. }
  379. {
  380. pf.dibASCII = &customFontBitmapASCII;
  381. pf.dibASCII->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  382. pf.dibASCII->bmiHeader.biWidth = ((charWidth * 128 + 7) & ~7); // 4-byte alignment
  383. pf.dibASCII->bmiHeader.biHeight = -(int32)charHeight;
  384. pf.dibASCII->bmiHeader.biSizeImage = pf.dibASCII->bmiHeader.biWidth * charHeight / 2;
  385. pf.dibASCII->bmiHeader.biPlanes = 1;
  386. pf.dibASCII->bmiHeader.biBitCount = 4;
  387. pf.dibASCII->bmiHeader.biCompression = BI_RGB;
  388. pf.dibASCII->lpDibBits = new uint8[pf.dibASCII->bmiHeader.biSizeImage];
  389. pf.dibASCII->bmiColors[0] = rgb2quad(RGB(0x00, 0x00, 0x00));
  390. pf.dibASCII->bmiColors[15] = rgb2quad(RGB(0xFF, 0xFF, 0xFF));
  391. uint8 *data = nullptr;
  392. HBITMAP bitmap = ::CreateDIBSection(hDC, (BITMAPINFO *)&pf.dibASCII->bmiHeader, DIB_RGB_COLORS, (void **)&data, nullptr, 0);
  393. if(!bitmap)
  394. {
  395. hDC.SelectObject(oldFont);
  396. gdiFont.DeleteObject();
  397. hDC.DeleteDC();
  398. currentFont = &gDefaultPatternFont;
  399. return;
  400. }
  401. HGDIOBJ oldBitmap = hDC.SelectObject(bitmap);
  402. hDC.FillSolidRect(0, 0, pf.dibASCII->bmiHeader.biWidth, -pf.dibASCII->bmiHeader.biHeight, RGB(0xFF, 0xFF, 0xFF));
  403. hDC.SetTextColor(RGB(0x00, 0x00, 0x00));
  404. hDC.SetBkColor(RGB(0xFF, 0xFF, 0xFF));
  405. hDC.SetTextAlign(TA_TOP | TA_LEFT);
  406. for(uint32 c = 32; c < 128; ++c)
  407. {
  408. DrawChar(hDC, (char)(unsigned char)c, charWidth * c, 0, charWidth, charHeight);
  409. }
  410. ::GdiFlush();
  411. std::memcpy(pf.dibASCII->lpDibBits, data, pf.dibASCII->bmiHeader.biSizeImage);
  412. hDC.SelectObject(oldBitmap);
  413. DeleteBitmap(bitmap);
  414. }
  415. hDC.SelectObject(oldFont);
  416. gdiFont.DeleteObject();
  417. hDC.DeleteDC();
  418. }
  419. void PatternFont::DeleteFontData()
  420. {
  421. delete[] customFontBitmap.lpDibBits;
  422. customFontBitmap.lpDibBits = nullptr;
  423. delete[] customFontBitmapASCII.lpDibBits;
  424. customFontBitmapASCII.lpDibBits = nullptr;
  425. }
  426. OPENMPT_NAMESPACE_END