MuckyFoot-UrbanChaos/thrust/font.cpp

510 lines
7.4 KiB
C++
Raw Permalink Normal View History

2017-05-20 03:14:17 +02:00
//
// A font! That's all there is to it.
//
#include "always.h"
#include "font.h"
#include "os.h"
#include "tga.h"
//
// Each of the letters
//
typedef struct
{
float u;
float v;
float uwidth;
} FONT_Letter;
#define FONT_LETTER_HEIGHT 20
#define FONT_LOWERCASE 0
#define FONT_UPPERCASE 26
#define FONT_NUMBERS 52
#define FONT_PUNCT_PLING 62
#define FONT_PUNCT_DQUOTE 63
#define FONT_PUNCT_POUND 64
#define FONT_PUNCT_DOLLAR 65
#define FONT_PUNCT_PERCENT 66
#define FONT_PUNCT_POWER 67
#define FONT_PUNCT_AMPERSAND 68
#define FONT_PUNCT_ASTERISK 69
#define FONT_PUNCT_OPEN 70
#define FONT_PUNCT_CLOSE 71
#define FONT_PUNCT_COPEN 72
#define FONT_PUNCT_CCLOSE 73
#define FONT_PUNCT_SOPEN 74
#define FONT_PUNCT_SCLOSE 75
#define FONT_PUNCT_LT 76
#define FONT_PUNCT_GT 77
#define FONT_PUNCT_BSLASH 78
#define FONT_PUNCT_FSLASH 79
#define FONT_PUNCT_COLON 80
#define FONT_PUNCT_SEMICOLON 81
#define FONT_PUNCT_QUOTE 82
#define FONT_PUNCT_AT 83
#define FONT_PUNCT_HASH 84
#define FONT_PUNCT_TILDE 85
#define FONT_PUNCT_QMARK 86
#define FONT_PUNCT_MINUS 87
#define FONT_PUNCT_EQUALS 88
#define FONT_PUNCT_PLUS 89
#define FONT_PUNCT_DOT 90
#define FONT_PUNCT_COMMA 81
#define FONT_NUM_LETTERS 92
FONT_Letter FONT_letter[FONT_NUM_LETTERS];
//
// This is the order the punctuation characters come in.
//
CBYTE FONT_punct[] =
{
"!\"<EFBFBD>$%^&*(){}[]<>\\/:;'@#~?-=+.,"
};
//
// The texture and another place where we store the font data
// apart from the texture!
//
OS_Texture *FONT_ot;
TGA_Pixel FONT_data[256][256];
//
// The format of the text.
//
ULONG FONT_flag;
float FONT_bbox_x1;
float FONT_bbox_y1;
float FONT_bbox_x2;
float FONT_bbox_y2;
void FONT_format(
ULONG flag,
float bbox_x1,
float bbox_y1,
float bbox_x2,
float bbox_y2)
{
FONT_flag = flag;
FONT_bbox_x1 = bbox_x1;
FONT_bbox_y1 = bbox_y1;
FONT_bbox_x2 = bbox_x2;
FONT_bbox_y2 = bbox_y2;
}
//
// Returns TRUE if it finds pixel data at (x,y)
//
SLONG FONT_found_data(SLONG x, SLONG y)
{
SLONG dy;
SLONG px;
SLONG py;
ASSERT(WITHIN(x, 0, 255));
for (dy = -15; dy <= 4; dy++)
{
px = x;
py = y + dy;
if (WITHIN(py, 0, 255))
{
if (FONT_data[255- py][px].alpha)
{
return TRUE;
}
}
}
return FALSE;
}
void FONT_init()
{
SLONG i;
SLONG y;
SLONG x;
SLONG line;
FONT_Letter *fl;
//
// Load the texture.
//
FONT_ot = OS_texture_create("font.tga");
//
// Load in the font bitmap.
//
TGA_Info ti;
ti = TGA_load(
"Textures\\font.tga",
256,
256,
&FONT_data[0][0]);
ASSERT(ti.valid);
ASSERT(ti.width == 256);
ASSERT(ti.height == 256);
//
// Work out the position of each of the letters.
//
#define FONT_NUM_BASELINES 8
SLONG baseline[FONT_NUM_BASELINES] =
{
17, 42, 67, 90, 113, 134, 160
};
x = 0;
y = baseline[0];
line = 0;
for (i = 0; i < FONT_NUM_LETTERS; i++)
{
fl = &FONT_letter[i];
//
// Look for the start of the letter.
//
while(!FONT_found_data(x,y))
{
x += 1;
if (x >= 256)
{
x = 0;
line += 1;
ASSERT(WITHIN(line, 0, FONT_NUM_BASELINES - 1));
y = baseline[line];
}
}
fl->u = float(x);
fl->v = float(y);
//
// Look for the end of the letter.
//
x += 3;
while(FONT_found_data(x,y))
{
x += 1;
}
fl->uwidth = (x - fl->u) * (1.0F / 256.0F);
//
// Convert the (u,v)s
//
fl->u *= 1.0F / 256.0F;
fl->v *= 1.0F / 256.0F;
fl->v -= 15.0F / 256.0F;
}
}
//
// Returns the index of the given character
//
SLONG FONT_get_index(CBYTE chr)
{
SLONG letter;
//
// Find our letter index.
//
if (WITHIN(chr, 'a', 'z'))
{
letter = FONT_LOWERCASE + chr - 'a';
}
else
if (WITHIN(chr, 'A', 'Z'))
{
letter = FONT_UPPERCASE + chr - 'A';
}
else
if (WITHIN(chr, '0', '9'))
{
letter = FONT_NUMBERS + chr - '0';
}
else
{
//
// Look for the punctuation letter.
//
letter = FONT_PUNCT_PLING;
for (CBYTE *ch = FONT_punct; *ch && *ch != chr; ch++, letter++);
}
if (!WITHIN(letter, 0, FONT_NUM_LETTERS - 1))
{
letter = FONT_PUNCT_QMARK;
}
return letter;
}
SLONG FONT_char_is_valid(CBYTE ch)
{
if (FONT_get_index(ch) == FONT_PUNCT_QMARK && ch != '?')
{
return FALSE;
}
else
{
return TRUE;
}
}
float FONT_get_letter_width(CBYTE chr)
{
SLONG letter;
if (chr == ' ')
{
return 8.0F / 256.0F;
}
letter = FONT_get_index(chr);
ASSERT(WITHIN(letter, 0, FONT_NUM_LETTERS - 1));
return FONT_letter[letter].uwidth + (1.0F / 256.0F);
}
float FONT_draw_letter(
OS_Buffer *ob,
CBYTE chr,
float x,
float y,
ULONG colour = 0xffffffff,
float scale = 1.0F)
{
SLONG letter;
float width;
FONT_Letter *fl;
//
// Space is a special case!
//
if (chr == ' ')
{
width = (8.0F / 256.0F) * scale;
}
else
{
letter = FONT_get_index(chr);
ASSERT(WITHIN(letter, 0, FONT_NUM_LETTERS - 1));
fl = &FONT_letter[letter];
width = fl->uwidth;
OS_buffer_add_sprite(
ob,
x,
y,
x + fl->uwidth * scale,
y + (FONT_LETTER_HEIGHT * 1.33F / 256.0F) * scale,
fl->u,
1.0F - (fl->v),
fl->u + fl->uwidth,
1.0F - (fl->v + (FONT_LETTER_HEIGHT / 256.0F)),
0.0F,
colour);
}
return (width + 1.0F / 256.0F) * scale;
}
//
// Returns the width of the given string.
//
float FONT_get_width(CBYTE *str, float scale)
{
float ans = 0.0F;
for (CBYTE *ch = str; *ch; ch++)
{
ans += FONT_get_letter_width(*ch) * scale;
}
return ans;
}
void FONT_format(
SLONG flag = FONT_FLAG_JUSTIFY_LEFT,
float bbox_x1 = 0.0F, float bbox_y1 = 0.0F,
float bbox_x2 = 1.0F, float bbox_y2 = 1.0F)
{
FONT_flag = flag;
FONT_bbox_x1 = bbox_x1;
FONT_bbox_y1 = bbox_y1;
FONT_bbox_x2 = bbox_x2;
FONT_bbox_y2 = bbox_y2;
}
void FONT_draw(float start_x, float start_y, ULONG colour, float scale, SLONG cursor, CBYTE *fmt, ...)
{
CBYTE message[4096];
va_list ap;
if (fmt == NULL)
{
sprintf(message, "<NULL>");
}
else
{
va_start(ap, fmt);
vsprintf(message, fmt, ap);
va_end (ap);
}
//
// So that a scale of 1.0F is normal size.
//
scale *= 0.5F;
//
// The buffer we use to hold the sprites.
//
OS_Buffer *ob = OS_buffer_new();
//
// Make sure the colour component has alpha- otherwise the
// font will be invisible!
//
colour |= 0xff000000;
float x = start_x;
float y = start_y;
if (FONT_flag & FONT_FLAG_JUSTIFY_CENTRE)
{
x -= FONT_get_width(message, scale) * 0.5F;
}
else
if (FONT_flag & FONT_FLAG_JUSTIFY_RIGHT)
{
x -= FONT_get_width(message, scale);
}
CBYTE *ch = message;
while(*ch)
{
if (iscntrl(*ch))
{
if (*ch == '\n')
{
x = start_x;
y += (FONT_LETTER_HEIGHT + 1.0F) * scale;
}
}
else
{
if (cursor-- == 0)
{
//
// Draw a cursor here.
//
{
OS_Buffer *ob = OS_buffer_new();
OS_buffer_add_sprite(
ob,
x, y, x + 0.01F * scale, y + (FONT_LETTER_HEIGHT * 1.33F / 256.0F) * scale,
0.0F, 0.0F,
1.0F, 1.0F,
0.0F,
0xeeeeeff);
OS_buffer_draw(ob, NULL, NULL);
}
}
x += FONT_draw_letter(ob, *ch, x, y, colour, scale);
}
ch += 1;
}
if (cursor-- == 0)
{
//
// Draw a cursor here.
//
{
OS_Buffer *ob = OS_buffer_new();
OS_buffer_add_sprite(
ob,
x, y, x + 0.01F * scale, y + (FONT_LETTER_HEIGHT * 1.33F / 256.0F) * scale,
0.0F, 0.0F,
1.0F, 1.0F,
0.0F,
0xeeeeeff);
OS_buffer_draw(ob, NULL, NULL);
}
}
OS_buffer_draw(ob, FONT_ot, NULL, OS_DRAW_DOUBLESIDED | OS_DRAW_ZALWAYS | OS_DRAW_NOZWRITE | OS_DRAW_ALPHABLEND);
}