Полезное:
Как сделать разговор полезным и приятным
Как сделать объемную звезду своими руками
Как сделать то, что делать не хочется?
Как сделать погремушку
Как сделать так чтобы женщины сами знакомились с вами
Как сделать идею коммерческой
Как сделать хорошую растяжку ног?
Как сделать наш разум здоровым?
Как сделать, чтобы люди обманывали меньше
Вопрос 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-битовые команды перемещения банных.
|