If you have comments or questions concerning this source file, discuss them in the forum.
/*
Copyright (c) 2002 Nicolai Haehnle
See the license.txt for details. If that file was not included in the
source distributions, please email <prefect@rtts.org>
*/
// hal_font.cpp - font implementation
#include "library.h"
#include "hal.h"
/*
==============================================================================
HFixedFont IMPLEMENTATION
==============================================================================
*/
class HFixedFont : public HFont {
public:
HPicture *m_pic;
public:
HFixedFont(const char *pszName);
virtual ~HFixedFont();
inline int Line(const char *string, int width, const char **pend);
virtual void CharRect(const char *string, int num,
int align, int width, int yspacing, LRect *rc);
virtual void StringSize(const char *string, int width, int yspacing,
int *pw, int *ph);
virtual void DrawChar(int dstx, int dsty, char c,
int r = 255, int g = 255, int b = 255, int a = 255);
virtual void DrawString(int dstx, int dsty, const char *string,
int align, int width, int yspacing,
int r = 255, int g = 255, int b = 255, int a = 255);
};
/*
==============
HFixedFont::HFixedFont
Load the required picture
==============
*/
HFixedFont::HFixedFont(const char *pszName)
: HFont(pszName)
{
m_pic = HPicture::Get(pszName, pic_redalpha, 0);
}
/*
==============
HFixedFont::~HFixedFont
Release allocated resources
==============
*/
HFixedFont::~HFixedFont()
{
m_pic->Release();
}
/*
==============
HFixedFont::Line
Returns the width of the line in pixels, and sets a point to the first
character no longer belonging to the line
==============
*/
inline int HFixedFont::Line(const char *string, int width, const char **pend)
{
const char *p;
int totalw, w;
totalw = 0;
p = string;
for(;;) {
while(*p && *p != '\n' &&
((*p != ' ' && *p != '\t') || p == string)) p++;
w = (p - string) * 16;
if (width > 0 && totalw && totalw+w > width) { // wrap around
*pend = string;
return totalw;
}
totalw += w;
string = p;
if (!*p || *p == '\n') {
*pend = string;
return totalw;
}
}
}
/*
==============
HFixedFont::CharRect
Return the enclosing rectangle for a given char
==============
*/
void HFixedFont::CharRect(const char *string, int num, int align, int width, int yspacing,
LRect *rc)
{
const char *p, *line;
int y, w;
int i;
bool gotit;
if (!(align & align_wrap))
width = -1;
y = 0;
p = string;
gotit = false;
for(;;) {
line = p;
w = Line(p, width, &p);
if (!gotit && num <= p-string) {
i = num - (line-string);
rc->pos[0] = i*16;
rc->pos[1] = y;
switch(align & halign_mask) {
case halign_center:
rc->pos[0] -= w / 2;
break;
case halign_right:
rc->pos[0] -= w;
break;
}
gotit = true;
}
if (!*p)
break;
p++;
y += yspacing + 16;
}
y += 16;
switch(align & valign_mask) {
case valign_center:
rc->pos[1] -= y / 2;
break;
case valign_bottom:
rc->pos[1] -= y;
break;
}
rc->size[0] = 16;
rc->size[1] = 16;
}
/*
==============
HFixedFont::StringSize
Returns the rectangular size, in pixels, of the string.
==============
*/
void HFixedFont::StringSize(const char *string, int width, int yspacing,
int *pw, int *ph)
{
int maxw, w, h;
maxw = 0;
h = 16;
for(;;) {
w = Line(string, width, &string);
if (w > maxw)
maxw = w;
if (!*string)
break;
string++;
h += yspacing + 16;
}
if (pw)
*pw = maxw;
if (ph)
*ph = h;
}
/*
==============
HFixedFont::DrawChar
Draw a single character at the given location
==============
*/
void HFixedFont::DrawChar(int dstx, int dsty, char c, int r, int g, int b, int a)
{
m_pic->DrawEx(dstx, dsty, (byte)c << 4, (byte)c & 0xf0, 16, 16, r, g, b, a);
}
/*
==============
HFixedFont::DrawString
Draw a colored string at the given location
==============
*/
void HFixedFont::DrawString(int dstx, int dsty, const char *string,
int align, int width, int yspacing,
int r, int g, int b, int a)
{
const char *p;
int x, y;
int w;
if (!(align & align_wrap))
width = -1;
if (align & valign_mask) {
int h;
StringSize(string, width, yspacing, 0, &h);
switch(align & valign_mask) {
case valign_center:
dsty -= h / 2;
break;
case valign_bottom:
dsty -= h;
break;
}
}
y = dsty;
while(*string) {
x = dstx;
w = Line(string, width, &p);
switch(align & halign_mask) {
case halign_center:
x -= w / 2;
break;
case halign_right:
x -= w;
break;
}
while(string < p) {
m_pic->DrawEx(x, y, (byte)(*string << 4), (byte)(*string & 0xf0),
16, 16, r, g, b, a);
x += 16;
string++;
}
if (!*string)
break;
string++;
y += yspacing + 16;
}
}
/*
==============================================================================
GENERIC HFont IMPLEMENTATION
==============================================================================
*/
HFont *HFont::m_pList = 0;
/*
==============
HFont::HFont
Add the font to the linked list
==============
*/
HFont::HFont(const char *pszName)
{
xstrcpy(m_szName, sizeof(m_szName), pszName);
m_iUsed = 1;
m_iCacheCycle = HAL::cachecycle;
m_ppPrev = &m_pList;
m_pNext = m_pList;
if (m_pNext)
m_pNext->m_ppPrev = &m_pNext;
m_pList = this;
}
/*
==============
HFont::~HFont
Unlink the font
==============
*/
HFont::~HFont()
{
if (m_pNext)
m_pNext->m_ppPrev = m_ppPrev;
*m_ppPrev = m_pNext;
}
/*
==============
HFont::CacheCycle
Evict unused fonts
==============
*/
void HFont::CacheCycle()
{
HFont *next, *font;
next = m_pList;
while(next) {
font = next;
next = next->m_pNext;
if (font->m_iUsed)
font->m_iCacheCycle = HAL::cachecycle;
else {
if (HAL::cachecycle-font->m_iCacheCycle > 2)
delete font;
}
}
}
/*
==============
HFont::Cleanup
Complain about potential font leaks, free all cached fonts
==============
*/
void HFont::Cleanup()
{
while(m_pList) {
if (m_pList->m_iUsed)
L_Printf("%s: font leak\n", m_pList->m_szName);
delete m_pList;
}
}
/*
==============
HFont::Get
Search for the font and load it if necessary
==============
*/
HFont *HFont::Get(const char *name)
{
HFont *font;
for(font = m_pList; font; font = font->m_pNext) {
if (!strcmp(font->m_szName, name)) {
font->AddRef();
return font;
}
}
font = new HFixedFont(name);
return font;
}