/*==LICENSE==* CyanWorlds.com Engine - MMOG client, server and tools Copyright (C) 2011 Cyan Worlds, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . You can contact Cyan Worlds, Inc. by email legal@cyan.com or by snail mail at: Cyan Worlds, Inc. 14617 N Newport Hwy Mead, WA 99021 *==LICENSE==*/ #include "HeadSpin.h" #include "hsTypes.h" #include #include "res/resource.h" #include #include #include #include #include "hsStream.h" #include "hsResMgr.h" #include "plFontFreeType.h" #include "../plGImage/plFont.h" #include "../plGImage/plMipmap.h" #include "../pnKeyedObject/plUoid.h" #include "../pnKeyedObject/plKeyImp.h" extern HINSTANCE gInstance; // My global font that i'm working on plFont *gFont = nil; // Preview bitmap HDC gPreviewHDC = nil; HBITMAP gPreviewBitmap = nil; void IMakeFontGoAway( void ) { if( gFont != nil ) { plKeyImp *imp = (plKeyImp *)(gFont->GetKey()); if( imp != nil ) imp->SetObjectPtr( nil ); gFont = nil; } } void IMakeNewFont( void ) { IMakeFontGoAway(); gFont = new plFont(); } BOOL CALLBACK AboutDialogProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { if( msg == WM_COMMAND ) EndDialog( hWnd, 0 ); return 0; } bool PromptForFile( HWND parent, const char *prompt, const char *filter, char *fileName, int fileNameMax, bool save ) { OPENFILENAME openInfo; memset( &openInfo, 0, sizeof( OPENFILENAME ) ); openInfo.hInstance = gInstance; openInfo.hwndOwner = parent; openInfo.lStructSize = sizeof( OPENFILENAME ); openInfo.lpstrFile = fileName; openInfo.nMaxFile = fileNameMax; openInfo.lpstrFilter = filter; openInfo.lpstrTitle = prompt; openInfo.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY; if( !save ) openInfo.Flags |= OFN_READONLY; if( save ) return GetSaveFileName( &openInfo ) ? true : false; return GetOpenFileName( &openInfo ) ? true : false; } void IUpdateInfo( HWND hDlg ) { const int TEST_STRING_SIZE = 512; static wchar_t testString[ TEST_STRING_SIZE ] = L"The quick brown fox jumped over the lazy dog! ABCabc012345;,."; if( gFont == nil ) { SetDlgItemText( hDlg, IDC_FACE, "" ); SetDlgItemText( hDlg, IDC_FSIZE, "" ); SetDlgItemText( hDlg, IDC_STARTG, "" ); SetDlgItemText( hDlg, IDC_GCOUNT, "" ); SetDlgItemText( hDlg, IDC_WIDTH, "" ); SetDlgItemText( hDlg, IDC_HEIGHT, "" ); SetDlgItemText( hDlg, IDC_BPP, "" ); CheckDlgButton( hDlg, IDC_BOLD, false ); CheckDlgButton( hDlg, IDC_ITALIC, false ); return; } SetDlgItemText( hDlg, IDC_FACE, gFont->GetFace() ); SetDlgItemInt( hDlg, IDC_FSIZE, gFont->GetSize(), false ); SetDlgItemInt( hDlg, IDC_STARTG, gFont->GetFirstChar(), false ); SetDlgItemInt( hDlg, IDC_GCOUNT, gFont->GetNumChars(), false ); SetDlgItemInt( hDlg, IDC_WIDTH, gFont->GetBitmapWidth(), false ); SetDlgItemInt( hDlg, IDC_HEIGHT, gFont->GetBitmapHeight(), false ); SetDlgItemInt( hDlg, IDC_BPP, gFont->GetBitmapBPP(), false ); CheckDlgButton( hDlg, IDC_BOLD, gFont->IsFlagSet( plFont::kFlagBold ) ); CheckDlgButton( hDlg, IDC_ITALIC, gFont->IsFlagSet( plFont::kFlagItalic ) ); if( gPreviewHDC != nil ) { DeleteObject( gPreviewHDC ); DeleteObject( gPreviewBitmap ); gPreviewHDC = nil; gPreviewBitmap = nil; } // Get the size of our preview RECT r; GetClientRect( GetDlgItem( hDlg, IDC_PREVIEW ), &r ); MapWindowPoints( GetDlgItem( hDlg, IDC_PREVIEW ), hDlg, (POINT *)&r, 2 ); InvalidateRect( hDlg, &r, false ); if( gFont->GetNumChars() == 0 ) return; // Our preview bitmap HDC deskDC = GetDC( nil ); gPreviewHDC = CreateCompatibleDC( deskDC ); gPreviewBitmap = CreateCompatibleBitmap( deskDC, r.right - r.left, r.bottom - r.top ); SelectObject( gPreviewHDC, gPreviewBitmap ); ReleaseDC( nil, deskDC ); ::GetDlgItemTextW( hDlg, IDC_PREVTEXT, testString, TEST_STRING_SIZE ); // Create us a mipmap to render onto, render onto it, then copy that to our DC plMipmap *mip = new plMipmap( r.right - r.left, r.bottom - r.top, plMipmap::kARGB32Config, 1 ); memset( mip->GetImage(), 0xff, mip->GetWidth() * mip->GetHeight() * 4 ); gFont->SetRenderColor( 0xff000000 ); gFont->SetRenderFlag( plFont::kRenderClip, true ); gFont->SetRenderClipRect( 0, 0, (Int16)(r.right - r.left), (Int16)(r.bottom - r.top) ); UInt16 w, h, a, lastX, lastY; UInt32 firstCC; gFont->CalcStringExtents( testString, w, h, a, firstCC, lastX, lastY ); int cY = ( ( ( r.bottom - r.top ) - h ) >> 1 ) + a; if( cY < 0 ) cY = 0; else if( cY > r.bottom - r.top - 1 ) cY = r.bottom - r.top - 1; memset( mip->GetAddr32( 8, cY ), 0xc0, ( r.right - r.left - 8 ) * 4 ); gFont->RenderString( mip, 8, cY, testString ); int x, y; for( y = 0; y < r.bottom - r.top; y++ ) { for( x = 0; x < r.right - r.left; x++ ) { UInt32 color = *mip->GetAddr32( x, y ); hsColorRGBA rgba; rgba.FromARGB32( color ); if( color != 0xffffffff && color != 0xff000000 ) { int q = 0; } SetPixel( gPreviewHDC, x, y, RGB( rgba.r * 255.f, rgba.g * 255.f, rgba.b * 255.f) ); } } delete mip; } class plSetKeyObj : public hsKeyedObject { public: void SetMyKey( const plKey &key ) { SetKey( key ); } }; class plMyBDFCallback : public plBDFConvertCallback { protected: HWND fDlg; clock_t fLastTime; UInt16 fPoint; void IPumpMessageQueue( void ) { MSG msg; while( PeekMessage( &msg, fDlg, 0, 0, PM_REMOVE ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } } public: plMyBDFCallback( HWND dlg ) : fDlg( dlg ) {} virtual void NumChars( UInt16 chars ) { ::SendDlgItemMessage( fDlg, IDC_PROGRESS, PBM_SETRANGE, 0, MAKELPARAM( 0, chars ) ); IPumpMessageQueue(); fLastTime = clock(); fPoint = 0; } virtual void CharDone( void ) { fPoint++; if( clock() - fLastTime > CLOCKS_PER_SEC / 16 ) { ::SendDlgItemMessage( fDlg, IDC_PROGRESS, PBM_SETPOS, fPoint, 0 ); IPumpMessageQueue(); fLastTime = clock(); } } }; BOOL CALLBACK ProgressWndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) { return 0; } void IImportFNT( HWND hWnd, const char *path ) { IMakeNewFont(); if( !gFont->LoadFromFNT( path ) ) MessageBox( hWnd, "Failure converting FNT file", "ERROR", MB_OK | MB_ICONEXCLAMATION ); IUpdateInfo( hWnd ); } void IImportBDF( HWND hWnd, const char *path ) { IMakeNewFont(); HWND dialog = CreateDialog( gInstance, MAKEINTRESOURCE( IDD_PROGRESS ), hWnd, ProgressWndProc ); ShowWindow( dialog, SW_SHOW ); EnableWindow( hWnd, false ); plMyBDFCallback callback( dialog ); if( !gFont->LoadFromBDF( path, &callback ) ) MessageBox( hWnd, "Failure converting BDF file", "ERROR", MB_OK | MB_ICONEXCLAMATION ); DestroyWindow( dialog ); EnableWindow( hWnd, true ); IUpdateInfo( hWnd ); } void IOpenP2F( HWND hWnd, const char *path ) { IMakeNewFont(); if( !gFont->LoadFromP2FFile( path ) ) MessageBox( hWnd, "Failure opening P2F file", "ERROR", MB_OK | MB_ICONEXCLAMATION ); IUpdateInfo( hWnd ); } struct ResRecord { HRSRC fHandle; char fName[ 512 ]; ResRecord() { fHandle = nil; fName[ 0 ] = 0; } ResRecord( HRSRC h, const char *n ) { fHandle = h; strncpy( fName, n, sizeof( fName ) ); } }; BOOL CALLBACK ResEnumProc( HMODULE module, LPCTSTR type, LPTSTR name, LONG_PTR lParam ) { HRSRC res = FindResource( module, name, type ); if( res != nil ) { hsTArray *array = (hsTArray *)lParam; array->Append( new ResRecord( res, name ) ); } return true; } BOOL CALLBACK ResListWndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) { switch( message ) { case WM_INITDIALOG: { SendDlgItemMessage( hWnd, IDC_RESLIST, LB_RESETCONTENT, 0, 0 ); hsTArray *array = (hsTArray *)lParam; for( UInt32 i = 0; i < array->GetCount(); i++ ) { ResRecord *rec = array->Get( i ); int idx = SendDlgItemMessage( hWnd, IDC_RESLIST, LB_ADDSTRING, 0, (LPARAM)rec->fName ); SendDlgItemMessage( hWnd, IDC_RESLIST, LB_SETITEMDATA, idx, (LPARAM)rec ); } } return 0; case WM_COMMAND: if( wParam == IDCANCEL ) EndDialog( hWnd, nil ); else { int idx = SendDlgItemMessage( hWnd, IDC_RESLIST, LB_GETCURSEL, 0, 0 ); if( idx == LB_ERR ) EndDialog( hWnd, nil ); else { ResRecord *rec = (ResRecord *)SendDlgItemMessage( hWnd, IDC_RESLIST, LB_GETITEMDATA, idx, 0 ); EndDialog( hWnd, (int)rec ); } } return true; } return 0; } void IImportFON( HWND hWnd, const char *path ) { // FON files are really just resource modules IMakeNewFont(); HMODULE file = LoadLibraryEx( path, nil, LOAD_LIBRARY_AS_DATAFILE | DONT_RESOLVE_DLL_REFERENCES ); if( file == nil ) { char msg[ 512 ], msg2[ 1024 ]; FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nil, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)msg, sizeof( msg ), nil ); sprintf( msg2, "Failure importing FON file: can't open as resource library (%s)", msg ); MessageBox( hWnd, msg2, "Error", MB_OK | MB_ICONEXCLAMATION ); } else { hsTArray resList; if( EnumResourceNames( file, "Font", ResEnumProc, (LPARAM)&resList ) ) { // Put up a list of the resources so the user can choose which one ResRecord *res = (ResRecord *)DialogBoxParam( gInstance, MAKEINTRESOURCE( IDD_FONCHOOSER ), hWnd, ResListWndProc, (LPARAM)&resList ); if( res != nil ) { // Load the resource into a ram stream hsRAMStream stream; HGLOBAL glob = LoadResource( file, res->fHandle ); if( glob != nil ) { void *data = LockResource( glob ); if( data != nil ) { stream.Write( SizeofResource( file, res->fHandle ), data ); stream.Rewind(); if( !gFont->LoadFromFNTStream( &stream ) ) MessageBox( hWnd, "Failure importing FON file: can't parse resource as FNT", "Error", MB_OK | MB_ICONEXCLAMATION ); } } } } else { char msg[ 512 ], msg2[ 1024 ]; FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nil, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)msg, sizeof( msg ), nil ); sprintf( msg2, "Failure importing FON file: can't enumerate resources (%s)", msg ); MessageBox( hWnd, msg2, "Error", MB_OK | MB_ICONEXCLAMATION ); } UInt32 i; for( i = 0; i < resList.GetCount(); i++ ) delete resList[ i ]; resList.Reset(); FreeLibrary( file ); } IUpdateInfo( hWnd ); } BOOL CALLBACK FreeTypeDlgProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) { static plFontFreeType::Options *info; switch( message ) { case WM_INITDIALOG: info = (plFontFreeType::Options *)lParam; SetDlgItemInt( hWnd, IDC_PSIZE, info->fSize, false ); SetDlgItemInt( hWnd, IDC_RES, info->fScreenRes, false ); SetDlgItemInt( hWnd, IDC_MAXCHAR, info->fMaxCharLimit, false ); CheckRadioButton( hWnd, IDC_BITDEPTH, IDC_BITDEPTH2, info->fBitDepth == 1 ? IDC_BITDEPTH : IDC_BITDEPTH2 ); return 0; case WM_COMMAND: if( wParam == IDOK || wParam == IDCANCEL || wParam == IDC_BATCH ) { info->fSize = GetDlgItemInt( hWnd, IDC_PSIZE, nil, false ); info->fScreenRes = GetDlgItemInt( hWnd, IDC_RES, nil, false ); info->fMaxCharLimit = GetDlgItemInt( hWnd, IDC_MAXCHAR, nil, false ); if( IsDlgButtonChecked( hWnd, IDC_BITDEPTH ) ) info->fBitDepth = 1; else info->fBitDepth = 8; EndDialog( hWnd, wParam ); } return 1; } return 0; } void IBatchFreeType( HWND hWnd, const char *path ); void IImportFreeType( HWND hWnd, const char *path ) { static plFontFreeType::Options info; int ret = DialogBoxParam( gInstance, MAKEINTRESOURCE( IDD_FREETYPE ), hWnd, FreeTypeDlgProc, (LPARAM)&info ); if( ret == IDCANCEL ) return; else if( ret == IDC_BATCH ) { IBatchFreeType( hWnd, path ); return; } IMakeNewFont(); HWND dialog = CreateDialog( gInstance, MAKEINTRESOURCE( IDD_PROGRESS ), hWnd, ProgressWndProc ); ShowWindow( dialog, SW_SHOW ); EnableWindow( hWnd, false ); plMyBDFCallback callback( dialog ); plFontFreeType *ft2Convert = (plFontFreeType *)gFont; if( !ft2Convert->ImportFreeType( path, &info, &callback ) ) MessageBox( hWnd, "Failure converting TrueType file", "ERROR", MB_OK | MB_ICONEXCLAMATION ); DestroyWindow( dialog ); EnableWindow( hWnd, true ); IUpdateInfo( hWnd ); } static UInt8 sNumSizes = 0; static UInt8 sSizeArray[ 256 ]; static char sFontName[ 256 ]; // desired font name for FreeType conversions BOOL CALLBACK FreeTypeBatchDlgProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) { static plFontFreeType::Options *info; switch( message ) { case WM_INITDIALOG: info = (plFontFreeType::Options *)lParam; SetDlgItemText( hWnd, IDC_PSIZE, "12" ); SetDlgItemText( hWnd, IDC_FONTNAME, "Untitled" ); SetDlgItemInt( hWnd, IDC_RES, info->fScreenRes, false ); SetDlgItemInt( hWnd, IDC_MAXCHAR, info->fMaxCharLimit, false ); CheckRadioButton( hWnd, IDC_BITDEPTH, IDC_BITDEPTH2, info->fBitDepth == 1 ? IDC_BITDEPTH : IDC_BITDEPTH2 ); return 0; case WM_COMMAND: if( wParam == IDOK || wParam == IDCANCEL ) { sNumSizes = 0; char *c, *lastC, str[ 1024 ]; GetDlgItemText( hWnd, IDC_PSIZE, str, sizeof( str ) ); lastC = str; while( ( c = strchr( lastC, ',' ) ) != nil && sNumSizes < 255 ) { *c = 0; sSizeArray[ sNumSizes++ ] = atoi( lastC ); lastC = c + 1; } sSizeArray[ sNumSizes++ ] = atoi( lastC ); info->fScreenRes = GetDlgItemInt( hWnd, IDC_RES, nil, false ); info->fMaxCharLimit = GetDlgItemInt( hWnd, IDC_MAXCHAR, nil, false ); if( IsDlgButtonChecked( hWnd, IDC_BITDEPTH ) ) info->fBitDepth = 1; else info->fBitDepth = 8; GetDlgItemText( hWnd, IDC_FONTNAME, sFontName, sizeof(sFontName) ); EndDialog( hWnd, wParam ); } return 1; } return 0; } void IBatchFreeType( HWND hWnd, const char *path ) { static plFontFreeType::Options info; if( DialogBoxParam( gInstance, MAKEINTRESOURCE( IDD_FREETYPEBATCH ), hWnd, FreeTypeBatchDlgProc, (LPARAM)&info ) == IDCANCEL ) return; BROWSEINFO bInfo; LPITEMIDLIST itemList; LPMALLOC shMalloc; static char destPath[ MAX_PATH ] = ""; memset( &bInfo, 0, sizeof( bInfo ) ); bInfo.hwndOwner = hWnd; bInfo.pidlRoot = NULL; bInfo.pszDisplayName = destPath; bInfo.lpszTitle = "Select a path to write the P2F fonts to:"; bInfo.ulFlags = BIF_EDITBOX; itemList = SHBrowseForFolder( &bInfo ); if( itemList != NULL ) { SHGetPathFromIDList( itemList, destPath ); SHGetMalloc( &shMalloc ); shMalloc->Free( itemList ); shMalloc->Release(); } else return; HWND dialog = CreateDialog( gInstance, MAKEINTRESOURCE( IDD_PROGRESS ), hWnd, ProgressWndProc ); ShowWindow( dialog, SW_SHOW ); EnableWindow( hWnd, false ); plMyBDFCallback callback( dialog ); callback.NumChars( sNumSizes ); UInt8 i; for( i = 0; i < sNumSizes; i++ ) { IMakeNewFont(); plFontFreeType *ft2Convert = (plFontFreeType *)gFont; info.fSize = sSizeArray[ i ]; if( !ft2Convert->ImportFreeType( path, &info, nil ) ) { MessageBox( hWnd, "Failure converting TrueType file", "ERROR", MB_OK | MB_ICONEXCLAMATION ); continue; } gFont->SetFace(sFontName); char fileName[ MAX_PATH ]; sprintf( fileName, "%s\\%s-%d.p2f", destPath, gFont->GetFace(), gFont->GetSize() ); hsUNIXStream stream; if( !stream.Open( fileName, "wb" ) ) MessageBox( hWnd, "Can't open file for writing", "Error", MB_OK | MB_ICONEXCLAMATION ); else { gFont->WriteRaw( &stream ); stream.Close(); } callback.CharDone(); } DestroyWindow( dialog ); EnableWindow( hWnd, true ); IUpdateInfo( hWnd ); } BOOL CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) { char fileName[ MAX_PATH ]; PAINTSTRUCT paintInfo; HDC myDC; RECT r; switch( message ) { case WM_PAINT: myDC = BeginPaint( hWnd, &paintInfo ); GetClientRect( GetDlgItem( hWnd, IDC_PREVIEW ), &r ); MapWindowPoints( GetDlgItem( hWnd, IDC_PREVIEW ), hWnd, (POINT *)&r, 2 ); if( gPreviewHDC != nil ) BitBlt( myDC, r.left, r.top, r.right - r.left, r.bottom - r.top, gPreviewHDC, 0, 0, SRCCOPY ); else FillRect( myDC, &r, GetSysColorBrush( COLOR_3DFACE ) ); DrawEdge( myDC, &r, EDGE_SUNKEN, BF_RECT ); EndPaint( hWnd, &paintInfo ); return 0; case WM_INITDIALOG: SendMessage( hWnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon( gInstance, MAKEINTRESOURCE( IDI_APPICON ) ) ); SetDlgItemTextW( hWnd, IDC_PREVTEXT, L"The quick brown fox jumped over the lazy dog! ABCabc012345;,." ); return 0; case WM_COMMAND: if( wParam == ID_FILE_ABOUT ) { DialogBox( gInstance, MAKEINTRESOURCE( IDD_ABOUT ), hWnd, AboutDialogProc ); } else if( wParam == ID_FILE_EXIT ) PostQuitMessage( 0 ); else if( wParam == ID_FILE_FNT ) { fileName[ 0 ] = 0; if( PromptForFile( hWnd, "Choose a FNT file to convert", "Windows FNT files\0*.fnt\0All files\0*.*\0", fileName, sizeof( fileName ), false ) ) IImportFNT( hWnd, fileName ); } else if( wParam == ID_FILE_P2F ) { fileName[ 0 ] = 0; if( PromptForFile( hWnd, "Choose a P2F file to open", "Plasma 2 font files\0*.p2f\0All files\0*.*\0", fileName, sizeof( fileName ), false ) ) IOpenP2F( hWnd, fileName ); } else if( wParam == ID_FILE_FON ) { fileName[ 0 ] = 0; if( PromptForFile( hWnd, "Choose a FON file to convert", "Windows FON files\0*.fon\0All files\0*.*\0", fileName, sizeof( fileName ), false ) ) IImportFON( hWnd, fileName ); } else if( wParam == ID_FILE_TRUETYPE ) { fileName[ 0 ] = 0; if( PromptForFile( hWnd, "Choose a TrueType font to convert", "TrueType files\0*.ttf\0TrueType Collections\0*.ttc\0All files\0*.*\0", fileName, sizeof( fileName ), false ) ) IBatchFreeType( hWnd, fileName ); } else if( wParam == ID_FILE_EXPORT ) { // Grab updated values for the font GetDlgItemText( hWnd, IDC_FACE, fileName, sizeof( fileName ) ); gFont->SetFace( fileName ); gFont->SetSize( GetDlgItemInt( hWnd, IDC_FSIZE, nil, false ) ); gFont->SetFlag( plFont::kFlagBold, IsDlgButtonChecked( hWnd, IDC_BOLD ) == BST_CHECKED ); gFont->SetFlag( plFont::kFlagItalic, IsDlgButtonChecked( hWnd, IDC_ITALIC ) == BST_CHECKED ); // Write out sprintf( fileName, "%s-%d.p2f", gFont->GetFace(), gFont->GetSize() ); if( PromptForFile( hWnd, "Specify a file to export to", "Plasma 2 font files\0*.p2f\0", fileName, sizeof( fileName ), true ) ) { hsUNIXStream stream; if( !stream.Open( fileName, "wb" ) ) MessageBox( hWnd, "Can't open file for writing", "Error", MB_OK | MB_ICONEXCLAMATION ); else { /* sprintf( fileName, "%s-%d", gFont->GetFace(), gFont->GetSize() ); if( gFont->GetKey() == nil ) hsgResMgr::ResMgr()->NewKey( fileName, gFont, plLocation::kGlobalFixedLoc ); */ gFont->WriteRaw( &stream ); stream.Close(); } } } else if( LOWORD( wParam ) == IDC_PREVTEXT && HIWORD( wParam ) == EN_CHANGE ) { IUpdateInfo( hWnd ); } return true; case WM_CLOSE: PostQuitMessage( 0 ); return true; case WM_DROPFILES: { int i, fileCount = DragQueryFile( (HDROP)wParam, -1, nil, nil ); char path[ MAX_PATH ]; for( i = 0; i < fileCount; i++ ) { if( DragQueryFile( (HDROP)wParam, i, path, sizeof( path ) ) > 0 ) { char *ext = PathFindExtension( path ); if( stricmp( ext, ".fnt" ) == 0 ) IImportFNT( hWnd, path ); else if( stricmp( ext, ".bdf" ) == 0 ) IImportBDF( hWnd, path ); else if( stricmp( ext, ".fon" ) == 0 ) IImportFON( hWnd, path ); else if( stricmp( ext, ".exe" ) == 0 ) IImportFON( hWnd, path ); else if(( stricmp( ext, ".ttf" ) == 0 ) || ( stricmp( ext, ".ttc" ) == 0 )) IImportFreeType( hWnd, path ); else if( stricmp( ext, ".p2f" ) == 0 ) IOpenP2F( hWnd, path ); else // Try using our freeType converter IImportFreeType( hWnd, path ); } } IUpdateInfo( hWnd ); } break; } return 0;//DefWindowProc( hWnd, message, wParam, lParam ); }