Шаг 19 - Вывод спрайтов на экран

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

Естественно запрограммировать вывод этой картинки попиксельно в программе очень сложно. Тут приходят на помощь спрайты. Спрайтами принято называть графические объекты(кусочки изображения) помещенные в память или в файл на диске. Для тех кто слабо себе представляет понятие спрайт поясню: в играх, например, это любой человечек, цветочек, стена и т.д. Когда много спрайтов одного и того же объекта(но с изменениями) быстро выводят на экран получается анимация. Но нам анимация естественно не пригодится :-)

Физически спрайт в наших понятиях это такой же экран, но меньшего размера и заполненный информацией. Поэтому для него также справедливо понятие линейности хранения в памяти.

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

void MoveLineOfImage(char *Source,char *Dest,unsigned int Count,char Bol)
{
	for (int i=0; i<Count; i++){
		if ((*Source)!=0)
			*Dest=*Source;
		else {
			if (Bol!=1)
				*Dest=*Source;
		};
		Source++;
		Dest++;
	};
}

Здесь Source - указатель на источник в памяти, Dest - указатель на получателя, Count - количество копируемых байт. Признак Bol - это признак копирования нулевых байтов. Если этот признак установлен в 1, то процедура не копирует нулевые байты, при этом не стирается изображение, которое уже было на экране, т.е. достигается эффект прозрачности областей спрайта, которые состоят из нулей.

Теперь на базе этой процедуры можно строить процедуру, которая будет выводить спрайт на виртуальный экран. Разработка данной процедуры и доведение ее до окончательного нормального вида заняла у меня в свое время пару месяцев. Сейчас я Вам привожу код этой процедуры, но только пришлось убрать все ассемблерные вставки (над которыми я так долго работал) на их менее быстродействующие аналоги языка C++. Рассказывать о выводе спрайта не буду, так как сам доходил до этого долго и не та у нас тематика.

void CGIScreen::PutImage(char *p,int x,int y,int bol)
{
	int xs = *p; //ширина изображения
	int ys = *(p+2); //высота изобажения
	int lsx;
	if ((x>width) || (y>height) || (x+xs<=0) || (y+ys<=0)) return;
	int x1,y1,x2,y2;
	x1=y1=0;
	x2=xs;
	y2=ys;
	if (x<0) x1=-x;
	if (y<0) y1=-y;
	if (x+xs>width) x2=width-x;
	if (y+ys>height) y2=height-y;
	lsx=x2-x1;
	char *p1=p+4+y1*xs+x1;
	int i;
	long Addr=(y+y1)*width+x+x1;

	for (i=y1;i<y2;i++)
	{
		MoveLineOfImage(p1,scr+Addr,lsx,bol);
		p1+=xs;
		Addr+=width;
	}
};/*PutImage*/

Указатель *p указывает на область памяти, в которой содержится спрайт. Координаты вывода задаются параметрами x,y причем они могут быть меньше нуля. Если при этом кусок спрайта попадает на экран, то будет выводиться именно этот кусок. Признак bol указывает на прозрачность спрайта и используется процедурой копирования строк изображения описанной выше.

Осталось только сказать о формате хранения спрайта в памяти. Как некоторые наверно уже успели заметить кроме самого содержимого спрайта в нем еще содержатся его физические размеры. Эти размеры записаны в самом начале спрайта и занимают 4 байта, т.е. два числа типа int - горизонтальный и вертикальный размер. Естественно формат спрайтов не подчиняется ни одному стандартному формату графических данных и при загрузке спрайта надо обеспечить его преобразование во внутренний формат. В будущем для облегчения работы мы напишем процедуру считывания спрайтов из файлов какого-нибудь типа, например, как самый легкий возьмем BMP. Но для этого надо еще обеспечить работу с палитрами. Скорее всего этим займемся в дальнейших шагах.


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