mirror of
https://github.com/kevinbentley/Descent3.git
synced 2025-01-22 11:28:56 +00:00
de0af3b10d
``` git grep -l mem_malloc | xargs perl -i -lpe 's{\((uint8_t) \*\)mem_malloc\((\S+)\)}{mem_rmalloc<$1>($2)}' ```
1139 lines
31 KiB
C++
1139 lines
31 KiB
C++
/*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
|
|
--- HISTORICAL COMMENTS FOLLOW ---
|
|
|
|
* $Logfile: /DescentIII/Main/grtext/grfont.cpp $
|
|
* $Revision: 25 $
|
|
* $Date: 11/16/99 4:56p $
|
|
* $Author: Samir $
|
|
*
|
|
*
|
|
*
|
|
* $Log: /DescentIII/Main/grtext/grfont.cpp $
|
|
*
|
|
* 25 11/16/99 4:56p Samir
|
|
* upped max texture count per font.
|
|
*
|
|
* 24 11/16/99 3:18p Samir
|
|
* added new data to font file and kept compatibility with D3 fonts:
|
|
* tracking value.
|
|
*
|
|
* 23 8/10/99 5:11p Jeff
|
|
* close open files
|
|
*
|
|
* 22 6/08/99 5:45p Samir
|
|
* correctly take care of values about 128 when character passed to
|
|
* grfont_GetCharWidth
|
|
*
|
|
* 21 4/24/99 8:41p Samir
|
|
* fixed clipped text scaling probs.
|
|
*
|
|
* 20 4/17/99 6:16p Samir
|
|
* added kerning and 4444 alphaed font support.
|
|
*
|
|
* 19 4/14/99 1:15a Jeff
|
|
* fixed case mismatched #includes
|
|
*
|
|
* 18 4/01/99 5:23p Samir
|
|
* Added function to get character info.
|
|
*
|
|
* 17 3/02/99 6:26p Samir
|
|
* added font template width and height functions.
|
|
*
|
|
* 16 2/21/99 6:39p Samir
|
|
* added function to get ascii value of font character.
|
|
*
|
|
* 15 10/16/98 1:54p Kevin
|
|
* Changes for Demo Beta 4
|
|
*
|
|
* 14 5/22/98 12:44p Samir
|
|
* fixed grayscale conversion bug.
|
|
*
|
|
* 13 5/15/98 5:36p Samir
|
|
* reset references count of font when freeing.
|
|
*
|
|
* 12 5/08/98 5:23p Samir
|
|
* added font brightness and grayscale caps.
|
|
*
|
|
* 11 5/01/98 3:09p Samir
|
|
* properly translate monochrome fonts to 555 output.
|
|
*
|
|
* 10 4/27/98 3:46p Samir
|
|
* scaling fonts.
|
|
*
|
|
* 9 4/24/98 8:00a Samir
|
|
* hopefully fixed font pixel format translation to 555 problem.
|
|
*
|
|
* 8 4/23/98 6:38p Jason
|
|
* made bitmaps use 1555 format
|
|
*
|
|
* 7 4/15/98 12:10p Samir
|
|
* commented out unnecessary mprints.
|
|
*
|
|
* 6 3/31/98 3:49p Jason
|
|
* added memory lib
|
|
*
|
|
* 5 1/12/98 7:03p Samir
|
|
* Centering works fully.
|
|
*
|
|
* 4 1/12/98 5:24p Samir
|
|
* Fixed font reading and created font spew test function.
|
|
*
|
|
* 3 1/02/98 12:53p Samir
|
|
* Convert lowercase to uppercase if there are no lowercase chars in the
|
|
* font.
|
|
*
|
|
* 2 12/29/97 5:48p Samir
|
|
* Fixed problem with non clipping text rendering (a hack.)
|
|
*
|
|
* 1 12/29/97 3:24p Samir
|
|
* Initial revision
|
|
*
|
|
* $NoKeywords: $
|
|
*/
|
|
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <cctype>
|
|
|
|
#include "bitmap.h"
|
|
#include "cfile.h"
|
|
#include "ddio.h"
|
|
#include "grtextlib.h"
|
|
#include "log.h"
|
|
#include "mem.h"
|
|
#include "pserror.h"
|
|
#include "renderer.h"
|
|
|
|
const int MAX_FONTS = 16, MAX_FONT_BITMAPS = 32;
|
|
|
|
#define FT_UPPERCASE 128
|
|
|
|
#define GRFONT_SURFACE_WIDTH 128
|
|
#define GRFONT_SURFACE_HEIGHT 128
|
|
|
|
#define BITS_TO_BYTES(_c) (((_c) + 7) >> 3)
|
|
#define BITS_TO_SHORTS(_c) (((_c) + 15) >> 4)
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Variables
|
|
|
|
struct tFontInfo {
|
|
char filename[32]; // filename of font
|
|
int references; // number of references of that font
|
|
int bmps[MAX_FONT_BITMAPS]; // font bitmap handles
|
|
uint8_t *ch_u, *ch_v, *ch_w, *ch_h;
|
|
int *ch_bmp;
|
|
float *ch_uf, *ch_vf, *ch_wf, *ch_hf;
|
|
tFontFileInfo font;
|
|
};
|
|
|
|
// Font information stored here.
|
|
static tFontInfo Fonts[MAX_FONTS];
|
|
static bool Font_init = false;
|
|
|
|
#define GRFONT_SURFACE_WIDTH 128
|
|
#define GRFONT_SURFACE_HEIGHT 128
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Macros for file io.
|
|
// ----------------------------------------------------------------------------
|
|
|
|
typedef CFILE *FONTFILE;
|
|
|
|
static inline int READ_FONT_INT(FONTFILE ffile);
|
|
static inline int16_t READ_FONT_SHORT(FONTFILE ffile);
|
|
static inline uint8_t READ_FONT_BYTE(FONTFILE ffile);
|
|
static inline int READ_FONT_DATA(FONTFILE ffile, void *buf, int size, int nelem);
|
|
static inline FONTFILE OPEN_FONT(char *filename);
|
|
static inline void CLOSE_FONT(FONTFILE ffile);
|
|
|
|
inline int READ_FONT_INT(FONTFILE ffile) { return cf_ReadInt(ffile); }
|
|
|
|
inline int16_t READ_FONT_SHORT(FONTFILE ffile) { return cf_ReadShort(ffile); }
|
|
|
|
inline uint8_t READ_FONT_BYTE(FONTFILE ffile) { return (uint8_t)cf_ReadByte(ffile); }
|
|
|
|
inline int READ_FONT_DATA(FONTFILE ffile, void *buf, int size, int nelem) {
|
|
int i;
|
|
|
|
i = cf_ReadBytes((uint8_t *)buf, size * nelem, ffile);
|
|
|
|
ASSERT(i == (size * nelem));
|
|
|
|
return i;
|
|
}
|
|
|
|
inline FONTFILE OPEN_FONT(const char *filename) {
|
|
FONTFILE fp;
|
|
int file_id;
|
|
|
|
fp = (FONTFILE)cfopen(filename, "rb");
|
|
if (!fp)
|
|
return nullptr;
|
|
|
|
file_id = READ_FONT_INT(fp);
|
|
if (file_id != 0xfeedbaba)
|
|
return (FONTFILE)(-1);
|
|
|
|
return fp;
|
|
}
|
|
|
|
inline void CLOSE_FONT(FONTFILE ffile) { cfclose(ffile); }
|
|
|
|
typedef FILE *FONTFILE2;
|
|
|
|
static inline int WRITE_FONT_INT(FONTFILE2 ffile, int i);
|
|
static inline int WRITE_FONT_SHORT(FONTFILE2 ffile, int16_t s);
|
|
static inline int WRITE_FONT_BYTE(FONTFILE2 ffile, uint8_t c);
|
|
static inline int WRITE_FONT_DATA(FONTFILE2 ffile, void *buf, int size, int nelem);
|
|
static inline FONTFILE2 OPEN_FONT2(char *filename);
|
|
static inline void CLOSE_FONT2(FONTFILE2 ffile);
|
|
|
|
inline int WRITE_FONT_INT(FONTFILE2 ffile, int i) { return fwrite(&i, sizeof(i), 1, (FILE *)ffile); }
|
|
|
|
inline int WRITE_FONT_SHORT(FONTFILE2 ffile, int16_t s) { return fwrite(&s, sizeof(s), 1, (FILE *)ffile); }
|
|
|
|
inline int WRITE_FONT_BYTE(FONTFILE2 ffile, uint8_t c) { return fwrite(&c, sizeof(c), 1, (FILE *)ffile); }
|
|
|
|
inline int WRITE_FONT_DATA(FONTFILE2 ffile, void *buf, int size, int nelem) {
|
|
int i;
|
|
i = (int)fwrite(buf, size, nelem, (FILE *)ffile);
|
|
|
|
ASSERT(i == nelem);
|
|
|
|
return i;
|
|
}
|
|
|
|
inline FONTFILE2 OPEN_FONT2(const char *filename) {
|
|
FONTFILE2 fp;
|
|
|
|
fp = (FONTFILE2)fopen(filename, "wb");
|
|
if (!fp)
|
|
return nullptr;
|
|
|
|
return fp;
|
|
}
|
|
|
|
inline void CLOSE_FONT2(FONTFILE2 ffile) { fclose((FILE *)ffile); }
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Functions
|
|
|
|
static void grfont_Close();
|
|
static void grfont_TranslateToBitmaps(int handle);
|
|
static void grfont_XlateMonoChar(int bmp_handle, int x, int y, int index, tFontFileInfo *ft, int width);
|
|
static void grfont_XlateColorChar(int bmp_handle, int x, int y, int index, tFontFileInfo *ft, int width);
|
|
static void grfont_XlateColorGrayChar(int bmp_handle, int x, int y, int index, tFontFileInfo *ft, int width);
|
|
static void grfont_ClearBitmap(int bmp_handle);
|
|
|
|
// clears out font buffer.
|
|
void grfont_Reset() {
|
|
int i;
|
|
|
|
if (Font_init) {
|
|
// free all allocated fonts.
|
|
grfont_Close();
|
|
} else {
|
|
atexit(grfont_Close);
|
|
}
|
|
|
|
for (i = 0; i < MAX_FONTS; i++)
|
|
Fonts[i].references = 0;
|
|
|
|
Font_init = true;
|
|
}
|
|
|
|
void grfont_Close() {
|
|
int i;
|
|
|
|
ASSERT(Font_init);
|
|
|
|
for (i = 0; i < MAX_FONTS; i++)
|
|
if (Fonts[i].references)
|
|
grfont_Free(i);
|
|
|
|
Font_init = false;
|
|
}
|
|
|
|
// returns a handle to a loaded font.
|
|
int grfont_Load(const char *fname) {
|
|
FONTFILE ff;
|
|
tFontFileInfo fnt;
|
|
char fontname[32];
|
|
int num_char, i, handle = -1;
|
|
|
|
ASSERT(Font_init);
|
|
|
|
// check if font is in list. if so, just return the handle.
|
|
|
|
// find free slot in font list.
|
|
for (i = 0; i < MAX_FONTS; i++) {
|
|
if (Fonts[i].references == 0)
|
|
break;
|
|
}
|
|
ASSERT(i < MAX_FONTS);
|
|
|
|
handle = i;
|
|
|
|
// open file.
|
|
ff = OPEN_FONT(fname);
|
|
if (!ff) {
|
|
return false;
|
|
} else if (ff == (FONTFILE)0xffffffff) {
|
|
LOG_ERROR.printf("Illegal font file: %s.\n", fname);
|
|
return false;
|
|
}
|
|
|
|
// read header information
|
|
fnt.width = READ_FONT_SHORT(ff);
|
|
fnt.height = READ_FONT_SHORT(ff);
|
|
fnt.flags = READ_FONT_SHORT(ff);
|
|
fnt.baseline = READ_FONT_SHORT(ff);
|
|
fnt.min_ascii = READ_FONT_BYTE(ff);
|
|
fnt.max_ascii = READ_FONT_BYTE(ff);
|
|
READ_FONT_DATA(ff, fontname, 32, 1);
|
|
|
|
// read new info
|
|
if (fnt.flags & FT_FFI2) {
|
|
fnt.ffi2.tracking = READ_FONT_SHORT(ff);
|
|
READ_FONT_DATA(ff, fnt.ffi2.reserved, sizeof(fnt.ffi2.reserved), 1);
|
|
} else {
|
|
fnt.ffi2.tracking = 0;
|
|
}
|
|
|
|
fnt.brightness = ((fnt.baseline >> 8) / 10.0f);
|
|
/*
|
|
mprintf(0, "%s font.\n", fname);
|
|
mprintf(0, " <ht %d>::<min %d>::<max %d>::<base %d>", fnt.height, fnt.min_ascii, fnt.max_ascii, fnt.baseline);
|
|
*/
|
|
num_char = fnt.max_ascii - fnt.min_ascii + 1;
|
|
|
|
if (fnt.max_ascii < 'a') {
|
|
fnt.flags |= FT_UPPERCASE;
|
|
}
|
|
|
|
// Read in all widths
|
|
if (fnt.flags & FT_PROPORTIONAL) {
|
|
fnt.char_widths = mem_rmalloc<uint8_t>(num_char);
|
|
for (i = 0; i < num_char; i++)
|
|
fnt.char_widths[i] = (uint8_t)READ_FONT_SHORT(ff);
|
|
} else {
|
|
fnt.char_widths = nullptr;
|
|
}
|
|
|
|
// Read in kerning data
|
|
if (fnt.flags & FT_KERNED) {
|
|
int n_pairs = (int)READ_FONT_SHORT(ff);
|
|
fnt.kern_data = mem_rmalloc<uint8_t>(sizeof(uint8_t) * 3 * (n_pairs + 1));
|
|
for (i = 0; i < n_pairs; i++) {
|
|
fnt.kern_data[i * 3] = READ_FONT_BYTE(ff);
|
|
fnt.kern_data[i * 3 + 1] = READ_FONT_BYTE(ff);
|
|
fnt.kern_data[i * 3 + 2] = READ_FONT_BYTE(ff);
|
|
}
|
|
fnt.kern_data[i * 3] = 255;
|
|
fnt.kern_data[i * 3 + 1] = 255;
|
|
fnt.kern_data[i * 3 + 2] = 0;
|
|
} else {
|
|
fnt.kern_data = nullptr;
|
|
}
|
|
|
|
// Read in pixel data.
|
|
// for color fonts, read in byte count and then the data,
|
|
// generate character data pointer table
|
|
// for mono fonts, read in byte count, then the data, convert to bits and store
|
|
// generate character data pointer table
|
|
int bytesize = READ_FONT_INT(ff);
|
|
|
|
fnt.raw_data = mem_rmalloc<uint8_t>(bytesize);
|
|
fnt.char_data = mem_rmalloc<uint8_t *>(num_char);
|
|
|
|
READ_FONT_DATA(ff, fnt.raw_data, bytesize, 1);
|
|
|
|
if (fnt.flags & FT_COLOR) {
|
|
int off = 0;
|
|
// mprintf(0, "::color");
|
|
for (i = 0; i < num_char; i++) {
|
|
fnt.char_data[i] = fnt.raw_data + off;
|
|
if (fnt.flags & FT_PROPORTIONAL)
|
|
off += (fnt.char_widths[i] * fnt.height * BITS_TO_BYTES(BPP_16));
|
|
else
|
|
off += (fnt.width * fnt.height * BITS_TO_BYTES(BPP_16));
|
|
}
|
|
} else { // Monochrome
|
|
uint8_t *ptr = fnt.raw_data;
|
|
// mprintf(0, "::mono");
|
|
for (i = 0; i < num_char; i++) {
|
|
fnt.char_data[i] = ptr;
|
|
if (fnt.flags & FT_PROPORTIONAL)
|
|
ptr += BITS_TO_BYTES(fnt.char_widths[i]) * fnt.height;
|
|
else
|
|
ptr += BITS_TO_BYTES(fnt.width) * fnt.height;
|
|
}
|
|
}
|
|
|
|
// Then read in
|
|
CLOSE_FONT(ff);
|
|
|
|
// mprintf(0, "\n");
|
|
|
|
strcpy(Fonts[handle].filename, fname);
|
|
Fonts[handle].references = 1;
|
|
Fonts[handle].font = fnt;
|
|
|
|
// draw font to bitmaps, load into surfaces too.
|
|
grfont_TranslateToBitmaps(handle);
|
|
|
|
return handle;
|
|
}
|
|
|
|
// frees a loaded font
|
|
void grfont_Free(int handle) {
|
|
tFontInfo *ft;
|
|
int i;
|
|
|
|
ASSERT(Font_init);
|
|
ASSERT(handle > -1 && handle < MAX_FONTS);
|
|
|
|
// delete font surface info.
|
|
ft = &Fonts[handle];
|
|
if (ft->ch_bmp)
|
|
delete[] ft->ch_bmp;
|
|
if (ft->ch_wf)
|
|
delete[] ft->ch_wf;
|
|
if (ft->ch_hf)
|
|
delete[] ft->ch_hf;
|
|
if (ft->ch_uf)
|
|
delete[] ft->ch_uf;
|
|
if (ft->ch_vf)
|
|
delete[] ft->ch_vf;
|
|
if (ft->ch_w)
|
|
delete[] ft->ch_w;
|
|
if (ft->ch_h)
|
|
delete[] ft->ch_h;
|
|
if (ft->ch_u)
|
|
delete[] ft->ch_u;
|
|
if (ft->ch_v)
|
|
delete[] ft->ch_v;
|
|
|
|
for (i = 0; i < MAX_FONT_BITMAPS; i++) {
|
|
if (ft->bmps[i] != -1)
|
|
bm_FreeBitmap(ft->bmps[i]);
|
|
}
|
|
|
|
// delete font file info.
|
|
if ((ft->font.flags & FT_KERNED) && ft->font.kern_data) {
|
|
mem_free(ft->font.kern_data);
|
|
}
|
|
|
|
if (ft->font.flags & FT_PROPORTIONAL) {
|
|
mem_free(ft->font.char_widths);
|
|
}
|
|
|
|
ft->references = 0;
|
|
|
|
mem_free(ft->font.raw_data);
|
|
mem_free(ft->font.char_data);
|
|
}
|
|
|
|
// loads a font template
|
|
bool grfont_LoadTemplate(const char *fname, tFontTemplate *ft) {
|
|
FONTFILE ff;
|
|
char fontname[32];
|
|
int16_t ft_width, ft_height, ft_flags, ft_minasc, ft_maxasc, num_char, i;
|
|
tFontFileInfo2 ffi2;
|
|
|
|
// open file.
|
|
ff = OPEN_FONT(fname);
|
|
if (!ff) {
|
|
Error("Unable to open font %s.\n", fname);
|
|
} else if (ff == (FONTFILE)0xffffffff) {
|
|
Error("Illegal font file: %s.\n", fname);
|
|
}
|
|
|
|
// read header information
|
|
ft_width = READ_FONT_SHORT(ff);
|
|
ft_height = READ_FONT_SHORT(ff);
|
|
ft_flags = READ_FONT_SHORT(ff);
|
|
READ_FONT_SHORT(ff); // skip baseline value (HACKED FOR BRIGHTNESS)
|
|
ft_minasc = READ_FONT_BYTE(ff);
|
|
ft_maxasc = READ_FONT_BYTE(ff);
|
|
READ_FONT_DATA(ff, fontname, 32, 1); // read namae
|
|
|
|
// read ffi2 font info
|
|
if (ft_flags & FT_FFI2) {
|
|
ffi2.tracking = READ_FONT_SHORT(ff);
|
|
READ_FONT_DATA(ff, &ffi2.reserved, sizeof(ffi2.reserved), 1);
|
|
}
|
|
|
|
num_char = ft_maxasc - ft_minasc + 1;
|
|
|
|
// Read in all widths
|
|
if (ft_flags & FT_PROPORTIONAL) {
|
|
ft->ch_widths = mem_rmalloc<uint8_t>(num_char);
|
|
for (i = 0; i < num_char; i++)
|
|
ft->ch_widths[i] = (uint8_t)READ_FONT_SHORT(ff);
|
|
} else {
|
|
ft->ch_widths = nullptr;
|
|
}
|
|
|
|
if (ft_flags & FT_KERNED) {
|
|
int n_pairs = (int)READ_FONT_SHORT(ff);
|
|
ft->kern_data = mem_rmalloc<uint8_t>(sizeof(uint8_t) * 3 * (n_pairs + 1));
|
|
for (i = 0; i < n_pairs; i++) {
|
|
ft->kern_data[i * 3] = READ_FONT_BYTE(ff);
|
|
ft->kern_data[i * 3 + 1] = READ_FONT_BYTE(ff);
|
|
ft->kern_data[i * 3 + 2] = READ_FONT_BYTE(ff);
|
|
}
|
|
ft->kern_data[i * 3] = 255;
|
|
ft->kern_data[i * 3 + 1] = 255;
|
|
ft->kern_data[i * 3 + 2] = 0;
|
|
} else {
|
|
ft->kern_data = NULL;
|
|
}
|
|
|
|
ft->ch_height = (uint8_t)ft_height;
|
|
ft->ch_maxwidth = (uint8_t)ft_width;
|
|
ft->max_ascii = ft_maxasc;
|
|
ft->min_ascii = ft_minasc;
|
|
ft->proportional = (ft_flags & FT_PROPORTIONAL) ? true : false;
|
|
ft->uppercase = (ft_maxasc < 'a');
|
|
ft->monochromatic = (ft_flags & FT_COLOR) ? false : true;
|
|
ft->newstyle = (ft_flags & FT_FMT4444) ? true : false;
|
|
ft->ffi2 = (ft_flags & FT_FFI2) ? true : false;
|
|
|
|
ft->ch_tracking = (int8_t)((ft_flags & FT_FFI2) ? ffi2.tracking : 0);
|
|
|
|
CLOSE_FONT(ff);
|
|
|
|
return true;
|
|
}
|
|
|
|
// frees a font template
|
|
void grfont_FreeTemplate(tFontTemplate *ft) {
|
|
if (ft->kern_data) {
|
|
mem_free(ft->kern_data);
|
|
ft->kern_data = nullptr;
|
|
}
|
|
if (ft->ch_widths) {
|
|
mem_free(ft->ch_widths);
|
|
ft->ch_widths = nullptr;
|
|
}
|
|
}
|
|
|
|
// MTS: unused?
|
|
// sets a template to a font, be careful.
|
|
bool grfont_SetTemplate(const char *pathname, const tFontTemplate *ft) {
|
|
// okay, load the font manually, set the template members, then save it out.
|
|
tFontFileInfo fnt;
|
|
char tempstr[32];
|
|
FONTFILE ffin;
|
|
FONTFILE2 ffout;
|
|
int num_char, i;
|
|
|
|
tFontFileInfo2 ffi2;
|
|
|
|
ffin = OPEN_FONT(pathname);
|
|
if (!ffin) {
|
|
return false;
|
|
} else if (ffin == (FONTFILE)0xffffffff) {
|
|
LOG_ERROR.printf("Illegal font file %s\n", pathname);
|
|
return false;
|
|
}
|
|
|
|
// read header information
|
|
fnt.width = READ_FONT_SHORT(ffin);
|
|
fnt.height = READ_FONT_SHORT(ffin);
|
|
fnt.flags = READ_FONT_SHORT(ffin);
|
|
fnt.baseline = READ_FONT_SHORT(ffin);
|
|
fnt.min_ascii = READ_FONT_BYTE(ffin);
|
|
fnt.max_ascii = READ_FONT_BYTE(ffin);
|
|
READ_FONT_DATA(ffin, tempstr, 32, 1);
|
|
|
|
// read ffi2 font info
|
|
if (fnt.flags & FT_FFI2) {
|
|
ffi2.tracking = READ_FONT_SHORT(ffin);
|
|
READ_FONT_DATA(ffin, &ffi2.reserved, sizeof(ffi2.reserved), 1);
|
|
}
|
|
|
|
fnt.brightness = ((fnt.baseline >> 8) / 10.0f);
|
|
|
|
num_char = fnt.max_ascii - fnt.min_ascii + 1;
|
|
|
|
// Read in all widths
|
|
if (fnt.flags & FT_PROPORTIONAL) {
|
|
fnt.char_widths = mem_rmalloc<uint8_t>(num_char);
|
|
for (i = 0; i < num_char; i++)
|
|
fnt.char_widths[i] = (uint8_t)READ_FONT_SHORT(ffin);
|
|
} else {
|
|
fnt.char_widths = nullptr;
|
|
}
|
|
|
|
// Read in kerning data
|
|
if (fnt.flags & FT_KERNED) {
|
|
int n_pairs = (int)READ_FONT_SHORT(ffin);
|
|
fnt.kern_data = mem_rmalloc<uint8_t>(sizeof(uint8_t) * 3 * (n_pairs + 1));
|
|
for (i = 0; i < n_pairs; i++) {
|
|
fnt.kern_data[i * 3] = READ_FONT_BYTE(ffin);
|
|
fnt.kern_data[i * 3 + 1] = READ_FONT_BYTE(ffin);
|
|
fnt.kern_data[i * 3 + 2] = READ_FONT_BYTE(ffin);
|
|
}
|
|
fnt.kern_data[i * 3] = 255;
|
|
fnt.kern_data[i * 3 + 1] = 255;
|
|
fnt.kern_data[i * 3 + 2] = 0;
|
|
} else {
|
|
fnt.kern_data = nullptr;
|
|
}
|
|
|
|
// Read in pixel data.
|
|
int bytesize = READ_FONT_INT(ffin);
|
|
|
|
fnt.raw_data = mem_rmalloc<uint8_t>(bytesize);
|
|
|
|
READ_FONT_DATA(ffin, fnt.raw_data, bytesize, 1);
|
|
|
|
CLOSE_FONT(ffin);
|
|
|
|
// set template values
|
|
fnt.width = ft->ch_maxwidth;
|
|
fnt.height = ft->ch_height;
|
|
fnt.flags = (ft->proportional ? FT_PROPORTIONAL : 0) + ((!ft->monochromatic) ? FT_COLOR : 0) +
|
|
(ft->kern_data ? FT_KERNED : 0) + (ft->newstyle ? FT_FMT4444 : 0);
|
|
fnt.min_ascii = (uint8_t)ft->min_ascii;
|
|
fnt.max_ascii = (uint8_t)ft->max_ascii;
|
|
|
|
if (ft->ffi2)
|
|
fnt.flags |= FT_FFI2;
|
|
|
|
if (fnt.kern_data) {
|
|
mem_free(fnt.kern_data);
|
|
}
|
|
if (fnt.char_widths) {
|
|
mem_free(fnt.char_widths);
|
|
}
|
|
fnt.kern_data = ft->kern_data;
|
|
fnt.char_widths = ft->ch_widths;
|
|
|
|
// write out font.
|
|
ffout = OPEN_FONT2(pathname);
|
|
if (!ffout) {
|
|
return false;
|
|
}
|
|
|
|
// Write file id.
|
|
WRITE_FONT_INT(ffout, 0xfeedbaba);
|
|
WRITE_FONT_SHORT(ffout, fnt.width);
|
|
WRITE_FONT_SHORT(ffout, fnt.height);
|
|
WRITE_FONT_SHORT(ffout, fnt.flags);
|
|
WRITE_FONT_SHORT(ffout, fnt.baseline);
|
|
WRITE_FONT_BYTE(ffout, fnt.min_ascii);
|
|
WRITE_FONT_BYTE(ffout, fnt.max_ascii);
|
|
WRITE_FONT_DATA(ffout, tempstr, 32, 1);
|
|
|
|
if (fnt.flags & FT_FFI2) {
|
|
WRITE_FONT_SHORT(ffout, (int16_t)ft->ch_tracking);
|
|
WRITE_FONT_DATA(ffout, ffi2.reserved, sizeof(ffi2.reserved), 1);
|
|
}
|
|
|
|
num_char = ft->max_ascii - ft->min_ascii + 1;
|
|
|
|
// Write widths now if necessary.(FT_PROPORTIONAL)
|
|
if (fnt.flags & FT_PROPORTIONAL) {
|
|
for (i = 0; i < num_char; i++)
|
|
WRITE_FONT_SHORT(ffout, (int16_t)fnt.char_widths[i]);
|
|
}
|
|
|
|
if (fnt.flags & FT_KERNED) {
|
|
// iterate new kerning info bytes
|
|
uint8_t *ch = fnt.kern_data;
|
|
int n_bytes = 0, n_pairs;
|
|
while (ch[n_bytes] != 255) {
|
|
n_bytes += 3;
|
|
}
|
|
|
|
ASSERT((n_bytes % 3) == 0);
|
|
n_pairs = n_bytes / 3;
|
|
WRITE_FONT_SHORT(ffout, (int16_t)n_pairs);
|
|
|
|
for (i = 0; i < n_pairs; i++) {
|
|
WRITE_FONT_BYTE(ffout, ch[i * 3]);
|
|
WRITE_FONT_BYTE(ffout, ch[i * 3 + 1]);
|
|
WRITE_FONT_BYTE(ffout, ch[i * 3 + 2]);
|
|
}
|
|
}
|
|
|
|
WRITE_FONT_INT(ffout, bytesize);
|
|
WRITE_FONT_DATA(ffout, fnt.raw_data, bytesize, 1);
|
|
|
|
CLOSE_FONT2(ffout);
|
|
|
|
// free raw data loaded, don't free kern and widths, already freed, template versions remain
|
|
mem_free(fnt.raw_data);
|
|
|
|
return true;
|
|
}
|
|
|
|
// MTS: Unused?
|
|
// sets a font's template without saving...
|
|
bool grfont_SetKerning(int font, uint8_t *kern_data) {
|
|
tFontInfo *oldft = &Fonts[font];
|
|
int n_pairs = 0;
|
|
|
|
// reset kerning...
|
|
if (oldft->font.kern_data) {
|
|
mem_free(oldft->font.kern_data);
|
|
oldft->font.kern_data = nullptr;
|
|
}
|
|
|
|
if (kern_data) {
|
|
while (kern_data[n_pairs * 3] != 255)
|
|
n_pairs++;
|
|
|
|
oldft->font.kern_data = (uint8_t *)mem_malloc((n_pairs + 1) * 3 * sizeof(uint8_t));
|
|
n_pairs = 0;
|
|
while (kern_data[n_pairs * 3] != 255) {
|
|
oldft->font.kern_data[n_pairs * 3] = kern_data[n_pairs * 3];
|
|
oldft->font.kern_data[n_pairs * 3 + 1] = kern_data[n_pairs * 3 + 1];
|
|
oldft->font.kern_data[n_pairs * 3 + 2] = kern_data[n_pairs * 3 + 2];
|
|
n_pairs++;
|
|
}
|
|
oldft->font.kern_data[n_pairs * 3] = 255;
|
|
oldft->font.kern_data[n_pairs * 3 + 1] = 255;
|
|
oldft->font.kern_data[n_pairs * 3 + 2] = 0;
|
|
}
|
|
|
|
// we're not going to reset other stuff for now... just kerning!
|
|
return true;
|
|
}
|
|
|
|
// MTS: Unused?
|
|
// sets a font's tracking
|
|
bool grfont_SetTracking(int font, int tracking) {
|
|
ASSERT(font >= 0 && font < MAX_FONTS);
|
|
|
|
tFontInfo *oldft = &Fonts[font];
|
|
|
|
oldft->font.ffi2.tracking = (int16_t)tracking;
|
|
|
|
return false;
|
|
}
|
|
|
|
int grfont_GetTracking(int font) {
|
|
ASSERT(font >= 0 && font < MAX_FONTS);
|
|
// if (Fonts[font].font.flags & FT_FFI2) {
|
|
return (int)Fonts[font].font.ffi2.tracking;
|
|
// }
|
|
|
|
// return 0;
|
|
}
|
|
|
|
// render a character
|
|
int grfont_BltChar(int font, tCharBlt *cbi) {
|
|
ASSERT(font > -1 && font < MAX_FONTS);
|
|
|
|
tFontInfo *ft = &Fonts[font];
|
|
|
|
// save current x and get this font
|
|
if (cbi->ch > ft->font.max_ascii && (ft->font.flags & FT_UPPERCASE)) {
|
|
cbi->ch = toupper(cbi->ch);
|
|
}
|
|
|
|
if ((cbi->ch < ft->font.min_ascii) || (cbi->ch > ft->font.max_ascii))
|
|
return (cbi->x + 1);
|
|
|
|
cbi->ch = cbi->ch - ft->font.min_ascii;
|
|
|
|
if (!cbi->clipped) {
|
|
|
|
if (ft->font.flags & FT_PROPORTIONAL)
|
|
cbi->sw = (int)(ft->font.char_widths[cbi->ch]);
|
|
else
|
|
cbi->sw = (int)(ft->font.width);
|
|
cbi->sh = (int)(ft->font.height);
|
|
cbi->sx = 0;
|
|
cbi->sy = 0;
|
|
|
|
rend_DrawFontCharacter(ft->bmps[ft->ch_bmp[cbi->ch]], cbi->x, cbi->y, (int)(cbi->x + cbi->sw * cbi->dsw),
|
|
(int)(cbi->y + cbi->sh * cbi->dsh), ft->ch_uf[cbi->ch], ft->ch_vf[cbi->ch],
|
|
ft->ch_wf[cbi->ch], ft->ch_hf[cbi->ch]);
|
|
return (cbi->x + (int)(cbi->sw * cbi->dsw));
|
|
//@@ rend_DrawFontCharacter (ft->bmps[ft->ch_bmp[cbi->ch]], cbi->x,cbi->y,
|
|
//@@ cbi->x+ft->ch_w[cbi->ch], cbi->y+ft->ch_h[cbi->ch],
|
|
//@@ ft->ch_uf[cbi->ch],
|
|
// ft->ch_vf[cbi->ch],
|
|
//@@ ft->ch_wf[cbi->ch],
|
|
// ft->ch_hf[cbi->ch]);
|
|
//@@ return (cbi->x + ft->ch_w[cbi->ch] - 1);
|
|
} else {
|
|
rend_DrawFontCharacter(
|
|
ft->bmps[ft->ch_bmp[cbi->ch]], cbi->x, cbi->y,
|
|
(int)(cbi->x + cbi->sw), // don't scale since these values are already scaled
|
|
(int)(cbi->y + cbi->sh), ft->ch_uf[cbi->ch] + (((float)cbi->sx) / ((float)GRFONT_SURFACE_WIDTH)),
|
|
ft->ch_vf[cbi->ch] + (((float)cbi->sy) / ((float)GRFONT_SURFACE_HEIGHT)),
|
|
((float)cbi->sw) / ((float)GRFONT_SURFACE_WIDTH), ((float)cbi->sh) / ((float)GRFONT_SURFACE_HEIGHT));
|
|
return (cbi->x + (int)(cbi->sw)); // scaled value already
|
|
}
|
|
}
|
|
|
|
// returns a character's width
|
|
int grfont_GetCharWidth(int font, int ch) {
|
|
tFontFileInfo *ft;
|
|
|
|
ASSERT(font > -1 && font < MAX_FONTS);
|
|
|
|
ft = &Fonts[font].font;
|
|
ch = (int)((uint8_t)ch);
|
|
|
|
if (ch > ft->max_ascii && (ft->flags & FT_UPPERCASE)) {
|
|
ch = toupper(ch);
|
|
}
|
|
|
|
if (ch < ft->min_ascii || ch > ft->max_ascii)
|
|
return 0;
|
|
else if (ft->flags & FT_PROPORTIONAL)
|
|
return ft->char_widths[ch - ft->min_ascii];
|
|
else
|
|
return ft->width;
|
|
}
|
|
|
|
// returns a font's height
|
|
int grfont_GetHeight(int font) {
|
|
ASSERT(font > -1 && font < MAX_FONTS);
|
|
return Fonts[font].font.height;
|
|
}
|
|
|
|
// translates raw font data to bitmaps.
|
|
void grfont_TranslateToBitmaps(int handle) {
|
|
tFontFileInfo *fntfile;
|
|
tFontInfo *fnt;
|
|
int i;
|
|
|
|
fnt = &Fonts[handle];
|
|
fntfile = &Fonts[handle].font;
|
|
|
|
// start creating font surfaces, map these surfaces onto bitmaps created via bitmap library
|
|
// this is needed for the renderer library.
|
|
// create a 128x128 bitmap.
|
|
// draw each character into bitmap until we need to create another
|
|
// surface.
|
|
uint8_t u = 0, v = 0, w;
|
|
int ch, num_ch;
|
|
uint8_t surf_index = 0;
|
|
|
|
num_ch = fntfile->max_ascii - fntfile->min_ascii + 1;
|
|
|
|
// initialize memory
|
|
fnt->ch_w = new uint8_t[num_ch];
|
|
fnt->ch_h = new uint8_t[num_ch];
|
|
fnt->ch_u = new uint8_t[num_ch];
|
|
fnt->ch_v = new uint8_t[num_ch];
|
|
fnt->ch_bmp = new int[num_ch];
|
|
fnt->ch_uf = new float[num_ch];
|
|
fnt->ch_vf = new float[num_ch];
|
|
fnt->ch_wf = new float[num_ch];
|
|
fnt->ch_hf = new float[num_ch];
|
|
|
|
for (i = 0; i < MAX_FONT_BITMAPS; i++)
|
|
fnt->bmps[i] = -1;
|
|
|
|
fnt->bmps[surf_index] = bm_AllocBitmap(GRFONT_SURFACE_WIDTH, GRFONT_SURFACE_HEIGHT, 0);
|
|
if (fnt->bmps[surf_index] == -1 || fnt->bmps[surf_index] == BAD_BITMAP_HANDLE)
|
|
Error("TranslateToBitmaps <Bitmap allocation error>");
|
|
if (fntfile->flags & FT_FMT4444) {
|
|
GameBitmaps[fnt->bmps[surf_index]].format = BITMAP_FORMAT_4444;
|
|
}
|
|
|
|
grfont_ClearBitmap(fnt->bmps[surf_index]);
|
|
surf_index++;
|
|
|
|
for (ch = 0; ch < num_ch; ch++) {
|
|
if (fntfile->flags & FT_PROPORTIONAL)
|
|
w = (int)fntfile->char_widths[ch];
|
|
else
|
|
w = (int)fntfile->width;
|
|
|
|
if ((u + w) > GRFONT_SURFACE_WIDTH) {
|
|
u = 0;
|
|
v += fntfile->height;
|
|
if ((v + fntfile->height) > GRFONT_SURFACE_HEIGHT) {
|
|
if (surf_index == MAX_FONT_BITMAPS)
|
|
Int3();
|
|
fnt->bmps[surf_index] = bm_AllocBitmap(GRFONT_SURFACE_WIDTH, GRFONT_SURFACE_HEIGHT, 0);
|
|
if (fnt->bmps[surf_index] == -1 || fnt->bmps[surf_index] == BAD_BITMAP_HANDLE)
|
|
Error("TranslateToBitmaps <Bitmap allocation error>");
|
|
if (fntfile->flags & FT_FMT4444) {
|
|
GameBitmaps[fnt->bmps[surf_index]].format = BITMAP_FORMAT_4444;
|
|
}
|
|
grfont_ClearBitmap(fnt->bmps[surf_index]);
|
|
surf_index++;
|
|
v = 0;
|
|
}
|
|
}
|
|
|
|
// blt each character
|
|
if (fntfile->flags & FT_COLOR) {
|
|
if (fntfile->flags & FT_GRADIENT)
|
|
grfont_XlateColorGrayChar(fnt->bmps[surf_index - 1], u, v, ch, fntfile, w);
|
|
// else
|
|
grfont_XlateColorChar(fnt->bmps[surf_index - 1], u, v, ch, fntfile, w);
|
|
} else { // font monochrome, convert bits to pixels
|
|
grfont_XlateMonoChar(fnt->bmps[surf_index - 1], u, v, ch, fntfile, w);
|
|
}
|
|
|
|
fnt->ch_h[ch] = (uint8_t)fntfile->height;
|
|
fnt->ch_w[ch] = w;
|
|
fnt->ch_u[ch] = u;
|
|
fnt->ch_v[ch] = v;
|
|
fnt->ch_bmp[ch] = surf_index - 1;
|
|
fnt->ch_hf[ch] = ((float)fntfile->height) / ((float)GRFONT_SURFACE_HEIGHT);
|
|
fnt->ch_wf[ch] = ((float)w) / ((float)GRFONT_SURFACE_WIDTH);
|
|
fnt->ch_uf[ch] = ((float)u) / ((float)GRFONT_SURFACE_WIDTH);
|
|
fnt->ch_vf[ch] = ((float)v) / ((float)GRFONT_SURFACE_HEIGHT);
|
|
|
|
// check to adjust uv's if we are outside surface.
|
|
u += w;
|
|
}
|
|
}
|
|
|
|
// Font translation routines
|
|
void grfont_XlateMonoChar(int bmp_handle, int x, int y, int index, tFontFileInfo *ft, int width) {
|
|
int row, col; // byte width of char
|
|
uint8_t bit_mask = 0, byte = 0;
|
|
uint8_t *fp;
|
|
|
|
fp = ft->char_data[index];
|
|
|
|
/* draw one-bit one color. */
|
|
uint16_t *dest_ptr;
|
|
uint16_t col_w = GR_COLOR_TO_16(GR_RGB(255, 255, 255));
|
|
int rowsize_w;
|
|
|
|
dest_ptr = bm_data(bmp_handle, 0);
|
|
rowsize_w = bm_rowsize(bmp_handle, 0) >> 1;
|
|
dest_ptr += (y * rowsize_w) + x;
|
|
|
|
for (row = 0; row < ft->height; row++) {
|
|
bit_mask = 0;
|
|
for (col = 0; col < width; col++) {
|
|
if (bit_mask == 0) {
|
|
byte = *fp++;
|
|
bit_mask = 0x80;
|
|
}
|
|
|
|
if (byte & bit_mask)
|
|
dest_ptr[col] = (col_w | OPAQUE_FLAG);
|
|
|
|
bit_mask >>= 1;
|
|
}
|
|
dest_ptr += rowsize_w;
|
|
}
|
|
}
|
|
|
|
void grfont_XlateColorChar(int bmp_handle, int x, int y, int index, tFontFileInfo *ft, int width) {
|
|
/* 16-bit copy from source bitmap to destination surface just created and
|
|
locked
|
|
This function performs scaling if the source width and height don't match
|
|
that of the destinations - JL
|
|
*/
|
|
uint16_t *dptr, *sptr;
|
|
int row, col;
|
|
int rowsize_w;
|
|
|
|
dptr = bm_data(bmp_handle, 0);
|
|
sptr = (uint16_t *)ft->char_data[index];
|
|
rowsize_w = bm_rowsize(bmp_handle, 0) / 2;
|
|
|
|
// height = std::min(h, ddsfObj.h);
|
|
// width = std::min(w, ddsfObj.w);
|
|
dptr = dptr + (y * rowsize_w);
|
|
|
|
if (ft->flags & FT_FMT4444) {
|
|
for (row = 0; row < ft->height; row++) {
|
|
for (col = 0; col < width; col++) {
|
|
dptr[x + col] = *(sptr++);
|
|
}
|
|
dptr += rowsize_w;
|
|
}
|
|
} else {
|
|
// old style
|
|
for (row = 0; row < ft->height; row++) {
|
|
for (col = 0; col < width; col++) {
|
|
uint16_t col565 = *(sptr++);
|
|
if (col565 == 0x07e0)
|
|
dptr[x + col] = NEW_TRANSPARENT_COLOR;
|
|
else
|
|
dptr[x + col] = (((col565 & 0xf800) >> 1) | ((col565 & 0x07c0) >> 1) | (col565 & 0x001f)) | OPAQUE_FLAG;
|
|
}
|
|
dptr += rowsize_w;
|
|
}
|
|
}
|
|
}
|
|
|
|
void grfont_XlateColorGrayChar(int bmp_handle, int x, int y, int index, tFontFileInfo *ft, int width) {
|
|
/* 16-bit copy from source bitmap to destination surface just created and
|
|
locked
|
|
This function performs scaling if the source width and height don't match
|
|
that of the destinations - JL
|
|
*/
|
|
uint16_t *dptr, *sptr;
|
|
int row, col;
|
|
int rowsize_w;
|
|
|
|
dptr = bm_data(bmp_handle, 0);
|
|
sptr = (uint16_t *)ft->char_data[index];
|
|
rowsize_w = bm_rowsize(bmp_handle, 0) / 2;
|
|
|
|
// height = std::min(h, ddsfObj.h);
|
|
// width = std::min(w, ddsfObj.w);
|
|
dptr = dptr + (y * rowsize_w);
|
|
|
|
float recip32 = 1.0f / 32.0f;
|
|
|
|
for (row = 0; row < ft->height; row++) {
|
|
for (col = 0; col < width; col++) {
|
|
uint16_t col565 = *(sptr++);
|
|
if (col565 == 0x07e0)
|
|
dptr[x + col] = NEW_TRANSPARENT_COLOR;
|
|
else {
|
|
uint8_t r = (uint8_t)((col565 & 0xf800) >> 11);
|
|
uint8_t g = (uint8_t)((col565 & 0x07c0) >> 6);
|
|
uint8_t b = (uint8_t)(col565 & 0x001f);
|
|
float brightness = ((r * 0.30f) + (g * 0.59f) + (b * 0.11f)) * recip32;
|
|
uint8_t elem = (uint8_t)(255 * brightness * ft->brightness);
|
|
if ((brightness * ft->brightness) > 1.0f)
|
|
elem = 255;
|
|
dptr[x + col] = GR_RGB16(elem, elem, elem) | OPAQUE_FLAG;
|
|
}
|
|
}
|
|
dptr += rowsize_w;
|
|
}
|
|
}
|
|
|
|
void grfont_ClearBitmap(int bmp_handle) {
|
|
int dx, dy;
|
|
int rowsize_w = bm_rowsize(bmp_handle, 0) / 2;
|
|
uint16_t *bmpdata = bm_data(bmp_handle, 0);
|
|
|
|
for (dy = 0; dy < bm_h(bmp_handle, 0); dy++) {
|
|
for (dx = 0; dx < rowsize_w; dx++)
|
|
bmpdata[dx] = NEW_TRANSPARENT_COLOR;
|
|
|
|
bmpdata += rowsize_w;
|
|
}
|
|
}
|
|
|
|
#ifndef RELEASE
|
|
void grfont_Spew(int font, int x, int y) {
|
|
int i;
|
|
tFontInfo *fnt;
|
|
|
|
fnt = &Fonts[font];
|
|
|
|
for (i = 0; i < MAX_FONT_BITMAPS; i++)
|
|
if (fnt->bmps[i] > -1)
|
|
rend_DrawScaledBitmap(i * GRFONT_SURFACE_WIDTH, 0, (i + 1) * GRFONT_SURFACE_WIDTH, GRFONT_SURFACE_HEIGHT,
|
|
fnt->bmps[i], 0, 0, 1.0, 1.0);
|
|
}
|
|
#endif
|
|
|
|
// returns character equivalent in font (converts lowercase to uppercase if no lowercase version avail)
|
|
// similar to ddio_KeyToAscii
|
|
int grfont_KeyToAscii(int font, int key) {
|
|
key = ddio_KeyToAscii(key);
|
|
|
|
if (font >= 0 && font < MAX_FONTS) {
|
|
tFontInfo *ft = &Fonts[font];
|
|
|
|
// save current x and get this font
|
|
if (key > ft->font.max_ascii && (ft->font.flags & FT_UPPERCASE)) {
|
|
return toupper(key);
|
|
}
|
|
}
|
|
|
|
return key;
|
|
}
|
|
|
|
// MTS: Unused?
|
|
// returns the raw bitmap data for a character in a font, its width and height
|
|
// returned data should be in 565 hicolor format if (*mono) is false. if (*mono) is true,
|
|
// then a bitmask will be returned, and you should treat a bit as a pixel.
|
|
uint16_t *grfont_GetRawCharacterData(int font, int ch, int *w, int *h, bool *mono) {
|
|
tFontFileInfo *fntfile;
|
|
tFontInfo *fnt;
|
|
|
|
ASSERT(font > -1 && font < MAX_FONTS);
|
|
|
|
fnt = &Fonts[font];
|
|
fntfile = &fnt->font;
|
|
|
|
if (ch > fnt->font.max_ascii && (fntfile->flags & FT_UPPERCASE)) {
|
|
ch = toupper(ch);
|
|
}
|
|
|
|
if ((ch < fnt->font.min_ascii) || (ch > fnt->font.max_ascii))
|
|
return nullptr;
|
|
|
|
ch = ch - fnt->font.min_ascii;
|
|
*mono = !(fnt->font.flags & FT_COLOR);
|
|
|
|
if (fnt->font.flags & FT_PROPORTIONAL) {
|
|
*w = (int)(fnt->font.char_widths[ch]);
|
|
} else {
|
|
*w = (int)(fnt->font.width);
|
|
}
|
|
|
|
*h = fnt->font.height;
|
|
|
|
return (uint16_t *)fnt->font.char_data[ch];
|
|
}
|
|
|
|
// returns a character's width
|
|
int grfont_GetKernedSpacing(int font, int ch1, int ch2) {
|
|
tFontFileInfo *ft;
|
|
|
|
ASSERT(font > -1 && font < MAX_FONTS);
|
|
|
|
ft = &Fonts[font].font;
|
|
|
|
if (ft->kern_data) {
|
|
uint8_t *kern = ft->kern_data;
|
|
while (kern[0] != 255) {
|
|
if (ch1 == kern[0] && ch2 == kern[1]) {
|
|
return (int)((int8_t)kern[2]);
|
|
}
|
|
kern += 3;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// returns a character's width
|
|
int grfont_GetKernedSpacingTemp(const tFontTemplate *ft, int ch1, int ch2) {
|
|
if (ft->kern_data) {
|
|
uint8_t *kern = ft->kern_data;
|
|
while (kern[0] != 255) {
|
|
if (ch1 == kern[0] && ch2 == kern[1]) {
|
|
return (int)((int8_t)kern[2]);
|
|
}
|
|
kern += 3;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|