📄 fontgen.c
字号:
/*----------------------------------------------
FONTGEN.C -- Create Font ver 1.1
(c) Emuman 2003
----------------------------------------------*/
#include <windows.h>
#include <mbstring.h>
#include <stdio.h>
#include "resource.h"
/***************************************************************************
Global variables
***************************************************************************/
static PTSTR szAppName = TEXT ("FontGen");
static UINT scalex, scaley, index, elecount; //target scale x, y, current index, total entry
static POINT ptOffset; //offset when generating font bmp
static LOGFONT lf; //currently selected font
//DEBUG
static int ccc,h;
static LOGFONT lf0; //temp font for enum
static TCHAR szFontList[32][LF_FACESIZE];
/***************************************************************************
Structures
***************************************************************************/
struct Tile
{
WCHAR unicode;
HBITMAP hBitmap;
};
/***************************************************************************
Function prototypes
***************************************************************************/
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
void Txt2TileArray (PTSTR, Tile[]);
HBITMAP Char2Bmp (PTSTR);
void TileArray2Byte (Tile[], PBYTE, int);
void Byte2TileArray (PBYTE, Tile[]);
void Txt2TileArrayCode (PTSTR, Tile[]);
void TileArrayCode2Txt (Tile[], PTSTR);
BOOL ReadTextFile (PTSTR, PTSTR);
int ReadXFile (PTSTR, LPVOID);
BOOL WriteXFile (PTSTR, LPCVOID, int);
void RemoveDupDBCS (PTSTR);
int CleanTileArray (Tile[]);
HBITMAP MakeShadow (HBITMAP);
int CALLBACK EnumFontFamExProc(ENUMLOGFONTEX *, NEWTEXTMETRICEX *, DWORD, LPARAM);
/***************************************************************************
Functions
***************************************************************************/
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = DLGWINDOWEXTRA ; // Note!
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) (COLOR_BTNSHADOW) ;
wndclass.lpszMenuName = szAppName ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateDialog (hInstance, szAppName, 0, NULL) ;
ShowWindow (hwnd, iCmdShow) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return (int)msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static bool is_init = 1; //program init flag
static OPENFILENAME ofn;
static TCHAR szFileName[MAX_PATH];
static TCHAR szTextBuf[0xA00000]; //max 10M text
static BYTE byBuf[0xffff * 32]; //buffer to receive whole Tile bitmaps. UnicodeRange * 16px * 2bpp
HWND hCtrl;
HDC hdc, hdcMem, hdcMemShadow, hdcMemRaw;
HGDIOBJ hobj;
static HBRUSH hbrush;
PAINTSTRUCT ps;
static COLORREF cr0, cr1;
static HBITMAP hBitmap, hBitmapRaw, hBitmap0, hBitmapShadow; //hBitmap0: original bitmap before edit
static RECT rc, rc2; //redraw rect
static POINT pt;
static Tile aTile[0xffff], aTile2[0xffff];
int i;
switch (message)
{
case WM_CREATE:
// Initialize OPENFILENAME
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hwnd;
ofn.lpstrFile = szFileName;
// Set lpstrFile[0] to '\0' so that GetOpenFileName does not
// use the contents of szFile to initialize itself.
ofn.lpstrFile[0] = '\0';
ofn.nMaxFile = sizeof(szFileName);
ofn.lpstrFilter = '\0';
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
return 0;
case WM_SIZE:
if (is_init) //DLGWINDOWEXTRA can't init in WM_CREATE
{
//initialize font combobox
hdc = CreateIC (TEXT ("DISPLAY"), NULL, NULL, NULL);
memset(&lf0,0,sizeof(lf0));
lf0.lfFaceName[0] = '\0';
lf0.lfCharSet = GB2312_CHARSET;
EnumFontFamiliesEx( hdc, &lf0, (FONTENUMPROC)EnumFontFamExProc, 0, 0 );
lf0.lfCharSet = CHINESEBIG5_CHARSET;
EnumFontFamiliesEx( hdc, &lf0, (FONTENUMPROC)EnumFontFamExProc, 0, 0 );
lf0.lfCharSet = SHIFTJIS_CHARSET;
EnumFontFamiliesEx( hdc, &lf0, (FONTENUMPROC)EnumFontFamExProc, 0, 0 );
DeleteDC (hdc);
i = 0;
hCtrl = GetDlgItem(hwnd,IDC_FONT_COMBO);
while (lstrcmp(szFontList[i],TEXT("")))
SendMessage (hCtrl, CB_ADDSTRING,0,(LPARAM)(LPCTSTR)szFontList[i++]);
SendMessage (hCtrl, CB_SETCURSEL,0,0);
GetDlgItemText (hwnd, IDC_FONT_COMBO, lf.lfFaceName, LF_FACESIZE);
//initialize font parameter
SetDlgItemText (hwnd, IDC_SRC_HEIGHT_EDIT, (LPCTSTR)TEXT("13"));
SetDlgItemText (hwnd, IDC_SCX_EDIT, (LPCTSTR)TEXT("7"));
SetDlgItemText (hwnd, IDC_SCY_EDIT, (LPCTSTR)TEXT("13"));
SetDlgItemText (hwnd, IDC_OFFSETY_EDIT, (LPCTSTR)TEXT("2"));
SetDlgItemText (hwnd, IDC_SHADOW_EDIT, (LPCTSTR)TEXT("0"));
//initialize scrollbar
hCtrl = GetDlgItem (hwnd, IDC_NAVIGATE_SCROLLBAR) ;
SetScrollRange (hCtrl, SB_CTL, 0, 0, FALSE) ;
SetScrollPos (hCtrl, SB_CTL, 0, FALSE) ;
//disable controls
hCtrl = GetDlgItem(hwnd, IDC_NAVIGATE_SCROLLBAR);
EnableWindow (hCtrl, FALSE);
hCtrl = GetDlgItem(hwnd, IDC_SAV_CHECK);
EnableWindow (hCtrl, FALSE);
//font rect for redraw
rc.left = 300;
rc.top = 50;
rc.bottom = 300;
rc.right = 500;
//preview font rect for redraw
rc2.left = 250;
rc2.top = 100;
rc2.right = 300;
rc2.bottom = 150;
hbrush = CreateSolidBrush(RGB (0xb8, 0xb8, 0xb8));
is_init = 0;
}
return 0;
case WM_COMMAND:
switch (LOWORD (wParam))
{
case IDC_FONT_COMBO:
if (HIWORD (wParam) == CBN_SELCHANGE)
{
if (!hBitmap0) //current bmp never edited
hBitmap0 = aTile[index].hBitmap; //backup current bmp
else //current bmp is edited (has backup)
DeleteObject (aTile[index].hBitmap);
GetDlgItemText (hwnd, IDC_FONT_COMBO, lf.lfFaceName, LF_FACESIZE);
aTile[index].hBitmap = Char2Bmp(&aTile[index].unicode); // put a new bmp to current bmp
InvalidateRect (hwnd, &rc, TRUE) ;
InvalidateRect (hwnd, &rc2, TRUE);
}
return 0 ;
case IDC_SRC_HEIGHT_EDIT:
if (HIWORD (wParam) == EN_UPDATE)
lf.lfHeight = GetDlgItemInt (hwnd, IDC_SRC_HEIGHT_EDIT, NULL, FALSE);
return 0 ;
case IDC_SCX_EDIT:
if (HIWORD (wParam) == EN_UPDATE)
{
scalex = GetDlgItemInt (hwnd, IDC_SCX_EDIT, NULL, FALSE);
rc.right = (scalex>8)?570:500;
}
return 0 ;
case IDC_SCY_EDIT:
if (HIWORD (wParam) == EN_UPDATE)
scaley = GetDlgItemInt (hwnd, IDC_SCY_EDIT, NULL, FALSE);
return 0 ;
case IDC_OFFSETY_EDIT:
if (HIWORD (wParam) == EN_UPDATE)
ptOffset.y = GetDlgItemInt (hwnd, IDC_OFFSETY_EDIT, NULL, TRUE);
return 0 ;
case IDM_FILE_OPENTXT: //read txt, remove all duplicate kanji, generate tiles in memory
ofn.lpstrFilter = TEXT("Text\0*.txt\0");
if (GetOpenFileName(&ofn))
{
if (!ReadTextFile (szFileName, szTextBuf))
{
MessageBox (hwnd, TEXT ("Could not read txt file!"), 0, MB_OK | MB_ICONEXCLAMATION) ;
szFileName[0] = '\0' ;
return 0;
}
RemoveDupDBCS(szTextBuf);
elecount = 8 * ((lstrlen(szTextBuf) + 7) / 8); //align 8
CleanTileArray(aTile); //clean all existing tiles
Txt2TileArray(szTextBuf, aTile);
hCtrl = GetDlgItem (hwnd, IDC_NAVIGATE_SCROLLBAR) ;
SetScrollRange (hCtrl, SB_CTL, 0, elecount - 1, FALSE) ;
EnableWindow (hCtrl, TRUE);
hCtrl = GetDlgItem(hwnd, IDC_SAV_CHECK);
EnableWindow (hCtrl, TRUE);
InvalidateRect (hwnd, NULL, TRUE) ;
}
return 0 ;
case ID_FILE_IMPORTTEXT: //not finished
ofn.lpstrFilter = TEXT("Text\0*.txt\0");
if (GetOpenFileName(&ofn))
{
if (!ReadTextFile (szFileName, szTextBuf))
{
MessageBox (hwnd, TEXT ("Could not import txt file!"), 0, MB_OK | MB_ICONEXCLAMATION) ;
szFileName[0] = '\0' ;
return 0;
}
RemoveDupDBCS(szTextBuf);
int j;
for (i = 0; i < lstrlen(szTextBuf); i++)
{
for (j = 0; j < elecount; j++)
{
if (CSTR_EQUAL == CompareString(LOCALE_USER_DEFAULT, 0, &szTextBuf[i], 1, &aTile[j].unicode, 1))
{
aTile2[i].hBitmap = aTile[j].hBitmap;
break;
}
}
}
szFileName[wcsstr(szFileName,L".txt")-szFileName]='\0'; //cut off "*.txt"
if (GetDlgItemInt (hwnd, IDC_SHADOW_EDIT, NULL, FALSE))
{
ZeroMemory (byBuf, 0xffff * 32);
TileArray2Byte(aTile2, byBuf, 0);
wcscat(szFileName,L"_noshadow.gb"); //concatenate w/ another file ext
WriteXFile(szFileName, byBuf, lstrlen(szTextBuf) * 32 * 2);
szFileName[wcsstr(szFileName,L"_noshadow.gb")-szFileName]='\0';
}
ZeroMemory (byBuf, 0xffff * 32);
TileArray2Byte(aTile2, byBuf, GetDlgItemInt (hwnd, IDC_SHADOW_EDIT, NULL, FALSE));
wcscat(szFileName,L".gb");
WriteXFile(szFileName, byBuf, lstrlen(szTextBuf) * 32 * 2);
}
return 0;
case ID_FILE_OPENROM:
ofn.lpstrFilter = TEXT("2bpp .gb ROM with .txt index\0*.gb\0");
if (GetOpenFileName(&ofn))
{
ZeroMemory (byBuf, 0xffff * 32);
if ((elecount = ReadXFile (szFileName, byBuf) / (32 * 2)) < 0)
{
MessageBox (hwnd, TEXT ("Could not read .gb ROM"), 0, MB_OK | MB_ICONEXCLAMATION);
szFileName[0] = '\0';
return 0;
}
CleanTileArray (aTile);
Byte2TileArray (byBuf, aTile);
szFileName[wcsstr(szFileName,L".gb")-szFileName]='\0';
wcscat(szFileName,L".txt");
if (!ReadTextFile (szFileName, szTextBuf))
{
MessageBox (hwnd, TEXT ("Could not read .txt index!"), 0, MB_OK | MB_ICONEXCLAMATION) ;
szFileName[0] = '\0' ;
return 0;
}
Txt2TileArrayCode (szTextBuf, aTile);
hCtrl = GetDlgItem (hwnd, IDC_NAVIGATE_SCROLLBAR) ;
SetScrollRange (hCtrl, SB_CTL, 0, elecount - 1, FALSE) ;
EnableWindow (hCtrl, TRUE);
hCtrl = GetDlgItem(hwnd, IDC_SAV_CHECK);
EnableWindow (hCtrl, TRUE);
InvalidateRect (hwnd, NULL, TRUE) ;
}
return 0 ;
case ID_FILE_MERGEROM:
ofn.lpstrFilter = TEXT("2bpp .gb ROM with .txt index\0*.gb\0");
if (GetOpenFileName(&ofn))
{
ZeroMemory (byBuf, 0xffff * 32);
if (ReadXFile (szFileName, byBuf) / (32 * 2) < 0)
{
MessageBox (hwnd, TEXT ("Could not read .gb ROM"), 0, MB_OK | MB_ICONEXCLAMATION);
szFileName[0] = '\0';
return 0;
}
CleanTileArray (aTile2);
Byte2TileArray (byBuf, aTile2);
szFileName[wcsstr(szFileName,L".gb")-szFileName]='\0';
wcscat(szFileName,L".txt");
if (!ReadTextFile (szFileName, szTextBuf))
{
MessageBox (hwnd, TEXT ("Could not read .txt index!"), 0, MB_OK | MB_ICONEXCLAMATION) ;
szFileName[0] = '\0' ;
return 0;
}
Txt2TileArrayCode (szTextBuf, aTile2);
int j;
for (i = 0; i < lstrlen(szTextBuf); i++)
{
for (j = 0; j < elecount; j++)
{
if (CSTR_EQUAL == CompareString(LOCALE_USER_DEFAULT, 0, &szTextBuf[i], 1, &aTile[j].unicode, 1))
{
int y = DeleteObject(aTile[j].hBitmap);
aTile[j].hBitmap = aTile2[i].hBitmap;
break;
}
else
{
aTile[elecount] = aTile2[i];
elecount++;
}
}
}
hCtrl = GetDlgItem (hwnd, IDC_NAVIGATE_SCROLLBAR) ;
SetScrollRange (hCtrl, SB_CTL, 0, elecount - 1, FALSE) ;
}
return 0 ;
case ID_FILE_SAVEROM:
ofn.lpstrFilter = TEXT("2bpp .gb ROM with .txt index\0*.gb\0");
if (GetSaveFileName(&ofn))
{
if (GetDlgItemInt (hwnd, IDC_SHADOW_EDIT, NULL, FALSE))
{
ZeroMemory (byBuf, 0xffff * 32);
TileArray2Byte(aTile, byBuf, 0);
WriteXFile(TEXT("noshadow.gb"), byBuf, elecount * 32 * 2);
}
ZeroMemory (byBuf, 0xffff * 32);
TileArray2Byte(aTile, byBuf, GetDlgItemInt (hwnd, IDC_SHADOW_EDIT, NULL, FALSE));
WriteXFile(szFileName, byBuf, elecount * 32 * 2);
TileArrayCode2Txt (aTile, szTextBuf);
szFileName[wcsstr(szFileName,L".gb")-szFileName]='\0';
wcscat(szFileName,L".txt");
WriteXFile(szFileName, szTextBuf, elecount * 2 + 2);
}
return 0;
}
break ;
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
pt.x = LOWORD (lParam);
pt.y = HIWORD (lParam);
if (PtInRect(&rc, pt))
{
hdc = CreateIC (TEXT ("DISPLAY"), NULL, NULL, NULL);
hdcMem = CreateCompatibleDC (hdc);
SelectObject (hdcMem, aTile[index].hBitmap);
cr0 = GetPixel(hdcMem, (pt.x-rc.left)*((scalex>8)?16:8)/(rc.right-rc.left), (pt.y-rc.top)*16/(rc.bottom-rc.top));
if (wParam == MK_LBUTTON)
SetPixel (hdcMem, (pt.x-rc.left)*((scalex>8)?16:8)/(rc.right-rc.left), (pt.y-rc.top)*16/(rc.bottom-rc.top), 0xffffff);
else if (wParam == MK_RBUTTON)
SetPixel (hdcMem, (pt.x-rc.left)*((scalex>8)?16:8)/(rc.right-rc.left), (pt.y-rc.top)*16/(rc.bottom-rc.top), 0x000000);
cr1 = GetPixel(hdcMem, (pt.x-rc.left)*((scalex>8)?16:8)/(rc.right-rc.left), (pt.y-rc.top)*16/(rc.bottom-rc.top));
if (cr0 != cr1)
{
InvalidateRect (hwnd, &rc, TRUE);
InvalidateRect (hwnd, &rc2, TRUE);
}
DeleteDC (hdcMem);
DeleteDC (hdc);
}
return 0;
case WM_MOUSEMOVE:
pt.x = LOWORD (lParam);
pt.y = HIWORD (lParam);
if (PtInRect(&rc, pt)&&((wParam == MK_SHIFT)||(wParam == MK_CONTROL)))
{
hdc = CreateIC (TEXT ("DISPLAY"), NULL, NULL, NULL);
hdcMem = CreateCompatibleDC (hdc);
SelectObject (hdcMem, aTile[index].hBitmap);
cr0 = GetPixel(hdcMem, (pt.x-rc.left)*((scalex>8)?16:8)/(rc.right-rc.left), (pt.y-rc.top)*16/(rc.bottom-rc.top));
if (wParam == MK_SHIFT)
SetPixel (hdcMem, (pt.x-rc.left)*((scalex>8)?16:8)/(rc.right-rc.left), (pt.y-rc.top)*16/(rc.bottom-rc.top), 0xffffff);
else if (wParam == MK_CONTROL)
SetPixel (hdcMem, (pt.x-rc.left)*((scalex>8)?16:8)/(rc.right-rc.left), (pt.y-rc.top)*16/(rc.bottom-rc.top), 0x000000);
cr1 = GetPixel(hdcMem, (pt.x-rc.left)*((scalex>8)?16:8)/(rc.right-rc.left), (pt.y-rc.top)*16/(rc.bottom-rc.top));
if (cr0 != cr1)
{
InvalidateRect (hwnd, &rc, TRUE);
InvalidateRect (hwnd, &rc2, TRUE);
}
DeleteDC (hdcMem);
DeleteDC (hdc);
}
return 0;
case WM_HSCROLL:
if (hBitmap0) //current bmp is edited (has backup)
{
if(BST_CHECKED == IsDlgButtonChecked (hwnd, IDC_SAV_CHECK)) //save edit?
{
DeleteObject (hBitmap0);
}
else
{
DeleteObject (aTile[index].hBitmap);
aTile[index].hBitmap = hBitmap0;
}
hBitmap0 = 0;
}
hCtrl = (HWND) lParam ;
switch (LOWORD (wParam))
{
case SB_THUMBPOSITION:
case SB_THUMBTRACK:
index = HIWORD (wParam) ;
break;
case SB_LINELEFT:
index --;
if (index < 0) index = 0;
break;
case SB_LINERIGHT:
index ++;
if (index > elecount - 1) index = elecount - 1;
break;
case SB_PAGELEFT:
index -= 20;
if (index < 0) index = 0;
break;
case SB_PAGERIGHT:
index += 20;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -