Главная Случайная страница


Полезное:

Как сделать разговор полезным и приятным Как сделать объемную звезду своими руками Как сделать то, что делать не хочется? Как сделать погремушку Как сделать так чтобы женщины сами знакомились с вами Как сделать идею коммерческой Как сделать хорошую растяжку ног? Как сделать наш разум здоровым? Как сделать, чтобы люди обманывали меньше Вопрос 4. Как сделать так, чтобы вас уважали и ценили? Как сделать лучше себе и другим людям Как сделать свидание интересным?


Категории:

АрхитектураАстрономияБиологияГеографияГеологияИнформатикаИскусствоИсторияКулинарияКультураМаркетингМатематикаМедицинаМенеджментОхрана трудаПравоПроизводствоПсихологияРелигияСоциологияСпортТехникаФизикаФилософияХимияЭкологияЭкономикаЭлектроника






Листинг 17.3. Простой двойной параллакс (PARAL1.C)





#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <time.h>

#include <dos.h>

#include "paral.h"

char *MemBuf, // указатель на дублирующий буфер

*BackGroundBmp, // указатель на битовую карту фона

*ForeGroundBmp, // указатель на битовую карту

// ближнего плана

*VideoRam; // указатель на видеобуфер

PcxFile pcx; // структура данных

// для чтения PCX-файла

int volatile KeyScan; // заполняется обработчиком

// прерывания клавиатуры

int frames=0, // количество нарисованных кадров

PrevMode; // исходный видеорежим

int background, // позиция прокрутки фона

foreground, //позиция прокрутки битовой карты

// ближнего плана position; // общее расстояние прокрутки

void _interrupt (*OldInt9)(void); // указатель на обработчик

// прерывания клавиатуры BIOS

// Функция загружает 256 - цветный PCX-файл

int ReadPcxFile(char *filename,PcxFile *pcx)

{

long i;

int mode=NORMAL,nbytes;

char abyte,*p;

FILE *f;

f=fopen(filename,"rb");

if(f==NULL)

return FCX_NOFILE;

fread(&pcx->hdr,sizeof(PcxHeader),1, f);

pcx_width=1+pcx->hdr.xmax-pcx->hdr.xmin;

pcx->height=1+pcx->hdr.ymax-pcx->hdr.ymin;

pcx->imagebytes=(unsigned int) (pcx->width*pcx->height);

if(pcx->imagebytes > PCX_MAX_SIZE) return PCX_TOOBIG;

pcx->bitmap= (char*)malloc (pcx->imagebytes);

if(pcx->bitmap == NULL) return PCX_NOMEM;

p=pcx->bitmap;

for(i=0;i<pcx->imagebytes;i++)

{

if(mode == NORMAL)

{

abyte=fgetc(f);

if((unsigned char)abyte > 0xbf)

{ nbytes=abyte & 0x3f;

abyte=fgetc(f);

if(--nbytes > 0)

mode=RLE;

}

}

else if(-—nbytes == 0) mode=NORMAL;

*p++=abyte;

}

fseek(f,-768L,SEEK_END); // получить палитру,из PCX-файла

fread(pcx->pal,768,1,f);

p=pcx->pal;

for(i=0;i<768;i++) // битовый сдвиг цветов в палитре

*р++=*р >>2;

fclose(f);

return PCX_OK;

}

// Новый обработчик прерывания клавиатуры для программы прокрутки

// Он используется для интерактивной прокрутки изображения.

// если стандартный обработчик прерывания 9h не будет заблокирован

// длительное нажатие на клавиши управления курсором приведет

// к переполнению буфера клавиатуры и появлению крайне неприятного

// звука из динамика.

void _interrupt Newlnt9(void)

{

register char x;

KeyScan=inp(0х60);// прочитать код клавиши

x=inp(0x61); // сообщить клавиатуре, что символ обработан

outp(0x61, (х|0х80));

outp(0х61,х);

outp(0х20,0х20); // сообщить о завершении прерывания

if(KeyScan == RIGHT_ARROW_REL ||// проверка кода клавиши

KeyScan == LEFT_ARROW_REL) KeyScan=0;

}

// Функция восстанавливает исходный обработчик прерываний клавиатуры

void RestoreKeyboard(void)

{

_dos_setvect(KEYBOARD,OldInt9); // восстанавливаем

// обработчик BIOS

}

// Эта функция сохраняет прежнее значение вектора прерывания // клавиатуры и устанавливает новый обработчик нашей программы.

void InitKeyboard(void)

{

OldInt9= _dos_getvect(KEYBOARD); // сохраняем адрес

// обработчика BIOS

_dos_setvect(KEYBOARD,NewInt9); // устанавливаем новый

// обработчик прерывания 9h

}

// Эта функция использует функции BIOS для установки в регистрах

// видеоконтроллера значений, необходимых для работы с цветами,

// определяемыми массивом раl[]

void SetAllRgbPalette(char *pal)

{

struct SREGS s;

union REGS r;

segread(&s); // читаем текущее значение сегментных регистров

s.es=FP_SEG((void far*)pal); // в ES загружаем сегмент ра1[]

r.x.dx=FP OFF((void far*}pal);// в DX загружаем смещение pal[]

r.x.ax=0xl012; // готовимся к.вызову подфункции // 12h функции BIOS 10h

r.x.bx=0; /;/ номер начального регистра палитры

r.х.сх=256; // номер последнего изменяемого регистра

int86x(0xl0,&r,&r,&s);// вызов видео BIOS

}

// Функция устанавливает режим 13h

// Это MCGA-совместимыЙ режим 320х200х256 цветов

void InitVideo()

{

union REGS r;

r.h.ah=0x0f; // функция Ofh - установка видеорежима

int86(0xl0,&r,&r); // вызов видео BIOS

PrevMode=r.h.al; // сохраняем старое значение режима

r.x.ax=0xl3; // устанавливаем режим 13h

int86(0х10,&r,sr); // вызов видео BIOS

VideoRam=MK_FP(0xa000,0); // создаем указатель на видеопамять

}

//Эта функция восстанавливает исходный видеорежим

void RestoreVideo()

{

union REGS r;

r.x,ax=PrevMode; //исходный видеорежим

int86(0х10,&r,&r); // вызов видео BIOS

}

// Функция загрузки битовых карт слоев

int InitBitmaps()

{

int r;

// начальное положение линии деления

background=foreground=1;

// читаем битовую карту фона

r=ReadPcxFile("backgrnd.pcx",&pcx);

// проверка на ошибки чтения if(r!= РСХ_ОК)

return FALSE;

// запоминаем указатель на битовую карту

BackGroundBmp=pcx.bitmap;

// устанавливаем палитру

SetAllRgbPalette(pcx.pal);

// читаем битовую карту переднего слоя

r=ReadPcxFile("foregrnd.pcx",&pcx);

// проверка на ошибки чтения

if (r!= РСХ_ОК) return FALSE;

//запоминаем указатель на битовую карту

ForeGroundBmp=pcx.bitmap;

// создаем буфер в памяти

MemBuf=malloc(MEMBLK);

// проверка на ошибки распределения памяти

if(MemBuf == NULL) return FALSE;

memset(MemBuf,0,MEMBLK); // очистка буфера

return TRUE;

// все в порядке!

}

// функция освобождает выделенную память

void FreeMem()

(

free(MemBuf);

free(BackGroundBmp);

free(ForeGroundBmp);

}

// Функция рисует слои параллакса.

// Порядок отрисовки определяется координатой слоя по оси Z.

void DrawLayers()

{

OpaqueBlt(BackGroundBmp,0,100,background);

TransparentBlt(ForeGroundBmp,50,100,foreground);

}

// Эта функция осуществляет анимацию. Учтите, что это наиболее

// критичная по времени часть программы. Для оптимизации отрисовки

// как сама функция, так и те функции, которые она вызывает,

// следует переписать на ассемблере. Как правило, это увеличивает

// быстродействие на 100 процентов.

void AnimLoop()

{

while(KeyScan!= ESC_PRESSED) // пока не нажата клавиша ESC

(

switch(KeyScan) // определяем, какая клавиша была нажата

{

case RIGHT_ARROW_PRESSED: //нажата "стрелка вправо"

position--; // изменяем позицию

if(position < 0) // останавливаем прокрутку,

// если дошли до конца

{

position=0;

break;

} backgrpund —=1; // прокручиваем фон влево на 2 пикселя

if(background < 1) // дошли до конца?

background+=VIEW_WIDTH; //...если да - возврат к началу

foreground-=2; // прокручиваем верхний

// слой влево на 4 пикселя

if(foreground < 1) // дошли до конца?

foreground+=VIEW_WIDTH; //...если да - возврат к началу

break;

case LEFT_ARROW_PRESSED: // нажата "стрелка влево"

position++; // изменяем текущую позицию прокрутки

if(position > TOTAL_SCROLL) // останавливаем прокрутку,

// если дошли до конца

{

position=TOTAL_SCROLL;

break;

}

background+=l; // прокручиваем фон вправо на 2 пикселя

if(background > VIEW_WIDTH-1) // дошли до конца?

background-=VIEW_WIDTH; //...если да - возврат к началу

foreground+=2; // прокручиваем верхний слой

// вправо на 4 пикселя

if(foreground > VIEW_WIDTH-1) // дошли до конца?

foreground-=VIEW_WIDTH; //...если да - возврат к началу

break;

default: // игнорируем остальные клавиши

break;

}

DrawLayers(); // рисуем слои в буфере в

// оперативной памяти

memcpy(VideoRam,MemBuf,MEMBLK); // копируем буфер в

// видеопамять

frames++; // увеличиваем счетчик кадров

) }

//эта функция осуществляет необходимую инициализацию

void Initialize()

{

position=0;

InitVideo(); // устанавливаем видеорежим 13h

InitKeyboard(); // устанавливаем наш обработчик

// прерывания клавиатуры

if(!InitBitmaps()) // загружаем битовые карты

{

CleanUp(); //освобождаем память

printf("\nError loading bitmaps\n");

exit(1);

} }

// функция выполняет всю необходимую очистку

void Cleanup()

{

RestoreVideo(); // восстанавливаем исходный видеорежим

RestoreKeyboard(); // восстанавливаем обработчик

// прерывания клавиатуры BIOS

FreeMem(); // освобождаем всю выделенную память

}

// Это начало программы. Функция вызывает процедуры инициализации.

// Затем читает текущее значение системного таймера и запускает

// анимацию. Потом вновь читается значение системного таймера.

// Разница между исходным и конечным значениями таймера

// используется для вычисления скорости анимации.

int main()

{

clock_t begin,fini;

Initialize(}; // проводим инициализацию

begin=clock(); // получаем исходное значение таймера

AnimLoop(); // выполняем анимацию

fini=clock(); // получаем значение таймера

CleanUp(); // восстанавливаем измененные параметры

printf("Frames: %d\nfps: %f\n",frames,

(float)CLK_TCK*frames/(fini-begin));

return 0;

}

Оптимизированные версии OpaqueBlt() и TransparentBlt()

Листинг 17.4 содержит оптимизированные ассемблерные версии подпрограмм OpaqueBlt() и TransparentBlt(), которые имеются и на дискете (BLIT.ASM). Эти подпрограммы можно использовать вместо соответствующих функций на Си, что увеличит быстродействие программы примерно на 30 процентов.

Демонстрационная программа PARAL использует ассемблерные версии этих подпрограмм. Они были написаны с тем расчетом, чтобы могли работать с процессором 286. Поскольку они заполняют буфер системной памяти, их можно оптимизировать и дальше, применив 32-битовые команды перемещения банных.

Date: 2015-09-18; view: 413; Нарушение авторских прав; Помощь в написании работы --> СЮДА...



mydocx.ru - 2015-2024 year. (0.006 sec.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав - Пожаловаться на публикацию