/* * Descent 3 * Copyright (C) 2024 Parallax Software * * 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 . --- HISTORICAL COMMENTS FOLLOW --- * $Logfile: /DescentIII/Main/editor/GrFontDialog.cpp $ * $Revision: 1.1.1.1 $ * $Date: 2003-08-26 03:57:38 $ * $Author: kevinb $ * * Font Editor * * $Log: not supported by cvs2svn $ * * 11 4/17/99 6:15p Samir * replaced gr.h with grdefs.h and fixed resulting compile bugs. * * 10 5/08/98 5:23p Samir * added font brightness and grayscale caps. * * 9 4/30/98 3:02p Samir * better error checking. * * 8 4/29/98 3:13p Samir * fixed font translation. * * 7 4/23/98 6:38p Jason * made bitmaps use 1555 format * * 6 3/31/98 3:49p Jason * added memory lib * * 5 3/06/98 3:34p Samir * Fixed font image scanning to scan multiple rows of fonts. * * 4 1/28/98 3:29p Samir * Increased max height of font. * * 3 1/12/98 5:22p Samir * Fixed up font reading. * * 2 9/02/97 3:28p Matt * Got rid of warnings * * 6 6/03/97 5:37p Mark * * 6 6/03/97 5:32p Jeff * Added Context Sensitive Help * * 5 2/06/97 3:08p Samir * Improved font saving for monochrome fonts * * $NoKeywords: $ */ // GrFontDialog.cpp : implementation file // #include "stdafx.h" #include #include #include "editor.h" #include "GrFontDialog.h" #include "gr.h" #include "mono.h" #include "bitmap.h" #include "gametexture.h" #include "manage.h" #include "mem.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define COLOR_FONT 1 #define MONOCHROME_FONT 2 #define GRADIENT_FONT 3 #define FT_COLOR 1 #define FT_PROPORTIONAL 2 #define FT_KERNED 4 #define FT_GRADIENT 8 // Font File stuff typedef FILE* FONTFILE; #define BITS_TO_BYTES(x) (((x)+7)>>3) inline int WRITE_FONT_INT(FONTFILE ffile, int i) { return fwrite(&i, sizeof(i), 1, (FILE *)ffile); } inline int WRITE_FONT_SHORT(FONTFILE ffile, int16_t s) { return fwrite(&s, sizeof(s), 1, (FILE *)ffile); } inline int WRITE_FONT_BYTE(FONTFILE ffile, uint8_t c) { return fwrite(&c, sizeof(c), 1, (FILE *)ffile); } inline int WRITE_FONT_DATA(FONTFILE ffile, void *buf, int size, int nelem) { int i; i = (int)fwrite(buf, size, nelem, (FILE *)ffile); ASSERT(i == nelem); return i; } inline FONTFILE OPEN_FONT(char *filename) { FONTFILE fp; fp = (FONTFILE)fopen(filename, "wb"); if (!fp) return NULL; return fp; } inline void CLOSE_FONT(FONTFILE ffile) { fclose((FILE *)ffile); } ///////////////////////////////////////////////////////////////////////////// // CGrFontDialog dialog CGrFontDialog::CGrFontDialog(CWnd* pParent /*=NULL*/) : CDialog(CGrFontDialog::IDD, pParent) { //{{AFX_DATA_INIT(CGrFontDialog) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT m_FontPicBm = -1; m_DataBuffer = NULL; ZeroMemory(&m_FontRecord, sizeof(m_FontRecord)); } void CGrFontDialog::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CGrFontDialog) // NOTE: the ClassWizard will add DDX and DDV calls here //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CGrFontDialog, CDialog) //{{AFX_MSG_MAP(CGrFontDialog) ON_BN_CLICKED(IDC_NEW, OnNew) ON_WM_PAINT() ON_WM_CREATE() ON_BN_CLICKED(IDC_SAVEAS, OnSaveAs) ON_BN_CLICKED(IDC_SAVE, OnSave) ON_WM_DESTROY() ON_EN_KILLFOCUS(IDC_EDIT_MINASCII, OnKillfocusEditMinascii) ON_EN_KILLFOCUS(IDC_EDIT_FONTNAME, OnKillfocusEditFontname) ON_BN_CLICKED(IDC_LOCK, OnLock) ON_BN_CLICKED(IDC_CHECKIN, OnCheckin) ON_WM_HELPINFO() ON_EN_KILLFOCUS(IDC_BRIGHTNESS, OnKillfocusBrightness) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CGrFontDialog message handlers void CGrFontDialog::OnNew() { // TODO: Add your control notification handler code here // Bring up Open TGA dialog. CString filter = "D3 bitmap files (*.tga; *lbm; *.bbm)|*.tga; *.lbm; *.bbm|Targa files (*.tga)|*.tga|IFF files (*.bbm; *.lbm)|*.bbm; *.lbm||"; CFileDialog dlg_open(TRUE, 0,0, OFN_FILEMUSTEXIST, (LPCTSTR)filter, this); if (dlg_open.DoModal() == IDCANCEL) return; // Okay, load in the proper picture for the font char filename[255]; int bm_handle; lstrcpy(filename, dlg_open.GetPathName()); if (m_FontPicBm > -1) bm_FreeBitmap(m_FontPicBm); m_FontPicBm = -1; mprintf(0, "Loading font template: %s...", filename); bm_handle = bm_AllocLoadFileBitmap(filename, 0); if (bm_handle<0) { mprintf(0, "shit!\n"); OutrageMessageBox ("Couldn't open the font template file."); return; } mprintf(0, "finished!\n"); m_FontPicBm = bm_handle; // Get MinAscii and other needed info before extracting font. if (!extract_font(&m_FontRecord)) { OutrageMessageBox("Unable to generate font from template %s.", filename); return; } UpdateDialog(); // Display font on screen. CWnd::Invalidate(); } void CGrFontDialog::OnPaint() { CPaintDC dc(this); // device context for painting CWnd *fontwnd; RECT rect; int w, h; if (m_FontPicBm > -1) { grHardwareSurface surf(bm_w(m_FontPicBm, 0), bm_h(m_FontPicBm, 0), bm_bpp(m_FontPicBm)); fontwnd = GetDlgItem(IDC_STATIC_FONTVIEW); fontwnd->GetWindowRect(&rect); ScreenToClient(&rect); w = rect.right-rect.left-4; h = rect.bottom-rect.top-4; if (w > (surf.width()-4)) w = surf.width() - 4; if (h > (surf.height()-4)) h = surf.height() - 4; // load bitmap, convert transparency to pure black and then blt surf.load(m_FontPicBm); surf.replace_color(TRANSPARENT_COLOR32, 0); Desktop_surf->attach_to_window((unsigned)m_hWnd); Desktop_surf->blt(rect.left+2,rect.top+2,&surf, 0, 0, w, h); Desktop_surf->attach_to_window((unsigned)NULL); } } int CGrFontDialog::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CDialog::OnCreate(lpCreateStruct) == -1) return -1; return 0; } BOOL CGrFontDialog::OnInitDialog() { CDialog::OnInitDialog(); // TODO: Add extra initialization here CButton *radio; CButton *gray_check = (CButton *)GetDlgItem(IDC_PROP_GRADIANT); CEdit *brightness = (CEdit *)GetDlgItem(IDC_BRIGHTNESS); char str[8]; gray_check->EnableWindow(FALSE); radio = (CButton *)GetDlgItem(IDC_PROP_MONO); radio->SetCheck(0); lstrcpy(m_FontName, "Untitled"); lstrcpy(m_FontFileName, "Untitled"); m_Brightness = 10; sprintf(str, "%.1f", m_Brightness/10.0f); brightness->SetWindowText(str); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } void CGrFontDialog::OnSaveAs() { CString filter = "Outrage font files (*.fnt)|*.fnt||"; CFileDialog dlg(FALSE, 0, 0, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, (LPCTSTR)filter, this); if (dlg.DoModal() == IDCANCEL) return; lstrcpy(m_FontFileName, dlg.GetPathName()); save_font_file(&m_FontRecord); UpdateDialog(); } void CGrFontDialog::OnSave() { if (strcmp(m_FontFileName, "Untitled") == 0) OnSaveAs(); else { save_font_file(&m_FontRecord); } } void CGrFontDialog::OnDestroy() { CDialog::OnDestroy(); if (m_DataBuffer) delete[] m_DataBuffer; if (m_FontPicBm > -1) bm_FreeBitmap(m_FontPicBm); m_FontPicBm = -1; } void CGrFontDialog::UpdateDialog() { CButton *radio; CEdit *edit; CStatic *text; char buf[64]; // Setup any necessary changes to control states in the dialog reflecting extraction of font. radio = (CButton *)GetDlgItem(IDC_PROP_MONO); radio->SetCheck(0); radio = (CButton *)GetDlgItem(IDC_PROP_BITMAPPED); radio->SetCheck(0); radio = (CButton *)GetDlgItem(IDC_PROP_GRADIANT); radio->SetCheck(0); switch (m_FontType) { case COLOR_FONT: radio = (CButton *)GetDlgItem(IDC_PROP_BITMAPPED); radio->SetCheck(1); break; case MONOCHROME_FONT: radio = (CButton *)GetDlgItem(IDC_PROP_MONO); radio->SetCheck(1); break; default: Int3(); } // Set filename static text. Set 'Untitled' name. Change static text font info. edit = (CEdit *)GetDlgItem(IDC_EDIT_MINASCII); _itoa(m_FontRecord.min_ascii, buf, 10); edit->SetWindowText(buf); text = (CStatic *)GetDlgItem(IDC_STATIC_MAXASCII); _itoa(m_FontRecord.max_ascii, buf, 10); text->SetWindowText(buf); text = (CStatic *)GetDlgItem(IDC_STATIC_FONTNAME); text->SetWindowText(m_FontFileName); edit = (CEdit *)GetDlgItem(IDC_EDIT_FONTNAME); edit->SetWindowText(m_FontName); if (m_FontProp) { text = (CStatic *)GetDlgItem(IDC_STATIC_PROP); text->SetWindowText("Proportional"); } else { text = (CStatic *)GetDlgItem(IDC_STATIC_PROP); text->SetWindowText(""); } } void CGrFontDialog::OnKillfocusEditMinascii() { CEdit *edit = (CEdit *)GetDlgItem(IDC_EDIT_MINASCII); char buf[4]; int num_char = m_FontRecord.max_ascii - m_FontRecord.min_ascii + 1;; edit->GetWindowText(buf, 4); m_FontRecord.min_ascii = atoi(buf); m_FontRecord.max_ascii = m_FontRecord.min_ascii + num_char-1; UpdateDialog(); } void CGrFontDialog::OnKillfocusEditFontname() { CEdit *edit = (CEdit *)GetDlgItem(IDC_EDIT_FONTNAME); edit->GetWindowText(m_FontName,32); } // ======================================================================================== // Font Extraction from Bitmap routines // ======================================================================================== #define PIX(_x,_y) m_FontBmData[(_x) + (_y) * m_FontBmW] inline uint16_t MAKE_565_FROM_555(uint16_t jcol) { ddgr_color pix32=GR_16_TO_COLOR (jcol); int red=GR_COLOR_RED(pix32); int green=GR_COLOR_GREEN (pix32); int blue=GR_COLOR_BLUE (pix32); uint16_t newpix=((red>>3)<<11)|((green>>2)<<5)|(blue>>3); return newpix; } BOOL CGrFontDialog::extract_font(gr_font_file_record *ft) { int bmx, bmy; int cur_char; // grab font template bitmap data from the bitmap library and retrieve characters // store relevent information in file record. m_FontBmData = bm_data(m_FontPicBm, 0); m_FontBmW = bm_w(m_FontPicBm,0); m_FontBmH = bm_h(m_FontPicBm, 0); m_CharMaxWidth = m_CharHeight = 0; m_FontProp = FALSE; m_FontType = MONOCHROME_FONT; m_FgColor = NEW_TRANSPARENT_COLOR; if (m_DataBuffer) delete[] m_DataBuffer; m_DataBuffer = new uint16_t[1024*MAX_FONT_CHARS]; m_DataPtr = m_DataBuffer; // assume upper left pixel is background color, and first-found other // color is box color m_BgColor = PIX(0,0); for (bmy = 0;bmy < m_FontBmH; bmy++) { for (bmx = 0;bmx < m_FontBmW && PIX(bmx,bmy)==m_BgColor; bmx++) ; if (PIX(bmx,bmy)!= m_BgColor) break; } m_BoxColor = PIX(bmx,bmy); // Get all data from current line. mprintf(0, "Parsing font..."); mprintf(0," read_characters: "); for (cur_char=0;bmy < m_FontBmH && cur_charwidth = m_CharMaxWidth; ft->height = m_CharHeight; ft->flags = (m_FontProp?FT_PROPORTIONAL:0) + ((m_FontType==COLOR_FONT)?FT_COLOR:0); ft->baseline = m_CharHeight; ft->min_ascii = 0; ft->max_ascii = cur_char-1; ft->raw_data = (uint8_t *)m_DataBuffer; ft->char_data = NULL; ft->char_widths = m_CharWidths; ft->kern_data= NULL; CButton *gray_check = (CButton *)GetDlgItem(IDC_PROP_GRADIANT); if (ft->flags & FT_COLOR) gray_check->EnableWindow(TRUE); else gray_check->EnableWindow(FALSE); return TRUE; } int CGrFontDialog::read_font_line(int cur_char, int& bmx, int& bmy) { while (bmx < m_FontBmW && PIX(bmx+1,bmy) == m_BoxColor) { int res; res = read_font_char(cur_char, bmx, bmy); if (res == 0) return -1; else if (res == 1) { bmx += m_CharWidths[cur_char]+1; cur_char++; } else if (res == 2) { break; } else break; } return cur_char; } int CGrFontDialog::read_font_char(int cur_char, int& bmx, int& bmy) { int w,h,x,y; bool box_edge = false; mprintf(0," %d-(%d,%d)",cur_char,bmx,bmy); while (PIX(bmx+1,bmy+1) == m_BoxColor) bmx++; //deal with double-thick vertical lines for (w=0;PIX(bmx+1+w,bmy+1)!=m_BoxColor;w++) { if (PIX(bmx+1+w,bmy)!=m_BoxColor) { if (box_edge) { OutrageMessageBox("Read probable premature eol at (%d,%d).\n", bmx+1+w, bmy); w--; return 2; } else { OutrageMessageBox("Suspected error at pixel coordindates %d,%d (char %d)",bmx+1+w,bmy, cur_char); return 0; } } else { box_edge = true; } } box_edge = false; for (h=0;PIX(bmx+1,bmy+1+h)!=m_BoxColor;h++) { if (PIX(bmx,bmy+1+h)!=m_BoxColor) { if (box_edge) { OutrageMessageBox("Read probable premature end of row at (%d,%d).\n", bmx, bmy+1+h); h--; return 2; } else { OutrageMessageBox("Suspected error at pixel coordindates %d,%d (char %d)",bmx,bmy+1+h, cur_char); return 0; } } else { box_edge = true; } } if (w==0 || h==0) { OutrageMessageBox("Character %d has width of %d and height of %d",cur_char,w,h); return 0; } m_CharWidths[cur_char] = w; if (m_CharMaxWidth !=0 && w != m_CharMaxWidth) m_FontProp = TRUE; if (w > m_CharMaxWidth) m_CharMaxWidth = w; if (m_CharHeight == 0) m_CharHeight = h; else if (m_CharHeight != h) { OutrageMessageBox("Char %d is wrong height (height = %d, correct height = %d)",cur_char,h,m_CharHeight); return 0; } for (y=0;yGetCheck() == 1) grayed_font = true; else grayed_font = false; // save data pointers. We don't write these out to the file. tmp_data = ft->raw_data; tmp_widths = ft->char_widths; tmp_cdata = ft->char_data; // Adjust font record for file write. ft->flags = (m_FontProp?FT_PROPORTIONAL:0) + ((m_FontType==COLOR_FONT)?FT_COLOR:0) + ((m_FontType==GRADIENT_FONT)?FT_GRADIENT:0) + (grayed_font?FT_GRADIENT:0); ft->raw_data = NULL; ft->char_data = NULL; ft->char_widths = NULL; ft->kern_data= NULL; // write to file mprintf(0, "Saving font data..."); // sprintf(filename, "%s\\%s", LocalManageGraphicsDir, m_FontFileName); ffile = OPEN_FONT(m_FontFileName); if (!ffile) { OutrageMessageBox("Unable to save font %s.", m_FontFileName); return FALSE; } // Write file id. WRITE_FONT_INT(ffile, id); // Write Header // baseline brightness located in upper 8 bits. ft->baseline = ft->baseline & 0x00ff; ft->baseline = ft->baseline | (m_Brightness << 8); WRITE_FONT_SHORT(ffile, ft->width); WRITE_FONT_SHORT(ffile, ft->height); WRITE_FONT_SHORT(ffile, ft->flags); WRITE_FONT_SHORT(ffile, ft->baseline); WRITE_FONT_BYTE(ffile, ft->min_ascii); WRITE_FONT_BYTE(ffile, ft->max_ascii); WRITE_FONT_DATA(ffile, m_FontName, 32, 1); num_char = ft->max_ascii - ft->min_ascii + 1; // Write widths now if necessary.(FT_PROPORTIONAL) if (ft->flags & FT_PROPORTIONAL) { for (int i = 0; i < num_char; i++) WRITE_FONT_SHORT(ffile, tmp_widths[i]); } if (ft->flags & FT_COLOR) { WRITE_FONT_INT(ffile, (int)(m_DataPtr-m_DataBuffer)*sizeof(uint16_t)); WRITE_FONT_DATA(ffile, (uint8_t *)m_DataBuffer, (m_DataPtr-m_DataBuffer)*sizeof(uint16_t), 1); } else { // bitpack for mono font storage:: 16bpp -> 8 bits/1 byte int i,x,y,w,cnt=0; uint16_t *p = m_DataBuffer; uint8_t *bits; bits = (uint8_t *)mem_malloc(256 * MAX_FONT_CHARS); for (i = 0; i < num_char; i++) { for (y = 0; y < ft->height; y++) { uint8_t mask, datum; w = (ft->flags & FT_PROPORTIONAL) ? tmp_widths[i] : ft->width; ASSERT(w <= 48); // Max width size shall be 32 pixels mask = 0x80; datum = 0; for (x = 0; x < w; x++) { if (mask == 0) { bits[cnt++] = datum; datum = 0; mask = 0x80; } if (*p++ != 0x07e0) datum |= mask; mask >>= 1; } bits[cnt++] = datum; } } WRITE_FONT_INT(ffile, cnt); WRITE_FONT_DATA(ffile, bits, cnt, 1); mem_free(bits); } // We should add kerning support here. // Close font. CLOSE_FONT(ffile); mprintf(0, "Done.\n"); ft->raw_data = tmp_data; ft->char_widths = tmp_widths; ft->char_data = tmp_cdata; return TRUE; } void CGrFontDialog::OnLock() { // TODO: Add your control notification handler code here } void CGrFontDialog::OnCheckin() { // TODO: Add your control notification handler code here } BOOL CGrFontDialog::OnHelpInfo(HELPINFO* pHelpInfo) { // TODO: Add your message handler code here and/or call default WinHelp(HID_FONTEDITORDLG,HELP_CONTEXT); return TRUE; //return CDialog::OnHelpInfo(pHelpInfo); } void CGrFontDialog::OnKillfocusBrightness() { CEdit *edit = (CEdit *)GetDlgItem(IDC_BRIGHTNESS); char str[8]; edit->GetWindowText(str, 7); m_Brightness = (int)(atof(str) * 10.0); }