Шаг 21 - Класс шрифтов CGIFont

Вроде все научились выводить, а вот шрифты еще пока нет. Давайте создадим новый класс для шрифтов. Или Вы их хотите сами рисовать попиксельно ?!

Думаю не надо объяснять, что существует два вида шрифтов: векторные и растровые. Векторные шрифты не плохи (даже круты :-), но на данном этапе лично мне сложно написать за час класс выводящий шрифты Windows TTF или хотя бы Borland CHR. Так что давайте не будем мучиться и разработаем класс для работы с растровыми шрифтами.

Формат наших шрифтов будет чуть похож на формат спрайтов, описанных ранее. Вообще-то видимо я не с этого начинаю :-) Давайте разберемся как мы вообще будем представлять шрифты в памяти.

Для начала надо выбрать размер шрифтов. Горизонтальный размер символа в этом конкретном случае не будет превышать 8 пикселов. По высоте он не ограничен. С чем это связано ? С тем, что мы будем хранить в памяти битовую маску символов. Т.е. если бит в байте равен единице, значит в соответствующем положении на экране будет выведен пиксел. Пример символа "A":

...oo...  0x18
..oooo..  0x3C
.oo..oo.  0x66
oo....oo  0xC3
oooooooo  0xFF
oo....oo  0xC3
oo....oo  0xC3
В памяти этот символ будет представлен в виде массива байтов:
	{0x18,0x3C,0x66,0xC3,0xFF,0xC3,0xC3}
Как видите при таком способе хранения максимальная ширина символа может быть 8 пикселов, а вертикальный размер не ограничен. В принципе никто не мешает нам расширить нашу битовую матрицу до 16 бит, но я думаю символы такой величины не понадобятся.

В памяти будем представлять шрифт таким способом:

1 байт - Ширина символа
2 байт - Высота символа
3 байт - Первая битовая маска первого символа
.....
Если коротко, то первые два байта это физические размеры символов шрифта, а далее битовые образы всех 256 символов. У меня на компьютере имеется несколько интересных шрифтов такого формата. Но для вас напишем утилитку, которая сможет генерить такие шрифты, хотя многие из Вас смогут написать и сами.

Теперь описание класса CGIFont:

class CGIFont{
	char *Font;
public:
	CGIFont(char *FileName);
	~CGIFont();
	void WriteChar(CGIScreen *scr,int x,int y, unsigned char color,
		 unsigned char color1,
		 int bol,unsigned char ch);
	void WriteString(CGIScreen *scr,int x,int y, unsigned char color,
		 unsigned char color1,
		 int bol,unsigned char *S);
};
Конструктор будет сразу инициализировать шрифт и загружать его из файла с именем FileName:
CGIFont::CGIFont(char *FileName){
	FILE *f;
	unsigned char l,k;
	long len;
	Font=NULL;
	if ((f = fopen(FileName, "rb")) == NULL) return;
	fread(&k,1,1,f);
	fread(&l,1,1,f);
	rewind(f);
	len=l*256+2;
	if((Font=(char *)malloc(len))==NULL){
		fclose(f);
		return;
	};
	fread(Font,len,1,f);
	fclose(f);
};

Деструктор, можно сказать, в старом стиле:

CGIFont::~CGIFont(){
	if (Font!=NULL) free(Font);
};
Теперь осталась процедура вывода символа и строки.
void CGIFont::WriteChar(CGIScreen *scr,int x,int y, unsigned char color,
		 unsigned char color1,
		 int bol,unsigned char ch)
{
  unsigned char i,j,Number,N;
  if (Font==NULL) return;
  char l=*Font;
  char k=*(Font+1);
  for (j=0;j<=k-1;j++)
  {
	Number=*(Font+2+ch*k+j);
	for (i=0;i<=l-1;i++)
	{
		N = Number << i;
		N >>= 7;
	  if (N==1) scr->PutPixel(x+i,y+j,color);
	  else if (bol==0) scr->PutPixel(x+i,y+j,color1);
    }
  }
};

Здесь scr - это тот виртуальный экран, на который нам надо вывести символ. Позиция для вывода символа задается координатами x,y. Цвет символов задается параметром color, а фон цветом color1. При этом, если признак bol равен 1, то фон не выводится. Этот эффект похож на прозрачность в спрайтах. Параметр ch задает тот символ, который надо вывести.

Теперь на базе этой процедуры строим процедуру вывода строки на экран:

void CGIFont::WriteString(CGIScreen *scr,int x,int y, unsigned char color,
		 unsigned char color1,
		 int bol,unsigned char *S)
{
  unsigned char l;
  if (Font==NULL) return;
  l=*Font;
  int i=0;
  while (*S!='\0')
  {
    if (*S!='\n')
     {
	  WriteChar(scr,x+(i*l),y,color,color1,bol,*S);
      i++;
     }
    else {i=0;y+=*(Font+1);}
	S++;
  };
};

Все параметры аналогичны предыдущей процедуре. Строка задается указателем *S.

Теперь можно выводить символы на виртуальный экран. Графические возможности нашего CGI приложения постоянно растут :-)


Предыдущий Шаг | Следующий Шаг | Оглавление
Автор Кузин Андрей - 12.05.2000