Читайте также:
|
|
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <dos.h>
#include "paral.h"
#include "tiles.h"
char *MemBuf,
*BackGroundBmp,
*ForeGroundBnip,
*VideoRam;
PcxFile pcx;
int volatile KeyScan;
int frames=0,
PrevMode;
int background,
foreground, position;
char *tiles[NUM_TILES+l];
int tilemap[TILES_TOTAL];
void interrupt (*OldInt9)(void);
//
//
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 PCX_NOFILE;
fread(&pcx->hdr,sizeof(PcxHeader),l,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 > Oxbf)
{ nbytes=abyte & 0x3f;
abyte=fgetc(f);
if(-—nbytes > 0) mode=RLE;
}
}
else if(--nbytes ==0)
mode=NORMAL;
*p++=abyte;
}
fseek(f,-768L,SEEK_END);
fread(pcx->pal,768,1, f);
p=pcx->pal;
for(i=0;i<768;i++) *p++=*p>>2;
fclose(f);
return PCX_OK;
}
//
void _interrupt NewInt9(void) {
register char x;
KeyScan=inp(Ox60);
x=inp(0х61);
outp(0x61,(x|0x80));
outp(0x61,x);
outp(0х20,0х20);
if(KeyScan == RIGHT__ARROW__REL ||
KeyScan == LEFT__ARROW_REL)
KeyScan=0;
}
//
void RestoreKeyboard(void) {
_dos_setvect(KEYBOARD,OldInt9);
}
//
void InitKeyboard(void)
{
Oldlnt9=_dos_getvect(KEYBOARD);
_dos_setvect(KEYBOARD,Newlnt9);
}
//
void SetAllRgbPalettefchar *pal)
{
struct SREGS s;
union REGS r;
segread(&s);
s.es=FP_SEG((void far*)pal);
r.x.dx=FP_OFF((void far*)pal);
r.x.ax=0xl012;
r.x.bx=0;
r.x.cx=256;
int86x(0xl0,&r,&r,&s);
}
//
void InitVideo()
{
union REGS r;
r.h.ah=0x0f;
int86(0xl0,&r,&r); PrevMode=r.h.al;
r.x.ax=0xl3;
int86(0xl0,&r,&r);
VideoRam=MK_FP(0xa000,0);
}
//
void RestoreVideo()
{
union REGS r;
r.x.ax=PrevMode;
int86(0xl0,&r,&r);
}
//
int InitBitmaps()
{
int r;
background=foreground=l;
r=ReadPcxFile("backgrnd.pcx",&pcx);
if(r!= PCX_OK) return FALSE;
BackGroundBnip=pcx.bitmap;
SetAllRgbPalette(pcx.pal);,
r=ReadPcxFile("foregrnd.pcx",&pcx);
if(r!= PCX_OK) 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);
FreeTiles(};
}
//
void DrawLayers()
{ OpaqueBlt(BackGroundBmp,0,100,background);
TransparentBIt(ForeGroundBmp,50,100,foreground);
DrawTiles(position,54);
}
//
void AnimLoop() {
while(KeyScan!= ESC_PRESSED)
{
switch(KeyScan)
{ case RIGHT_ARROW_PRESSED:
position+=4;
if(position > TOTAL_SCROLL) {
position=TOTAL_SCROLL;
break;
}
background-=1;
if(background < 1)
background+=VIEW_WIDTH;
foreground-=2; if(foreground < 1)
foreground+=VIEW_WIDTH;
break;
case LEFT_ARROW_PRESSED:
position-=4;
if(position < 0) {
position=0;
break;
}
background+=1;
if(background > VIEW_WIDTH-1) background-=VIEW_WIDTH;
foreground+=2;
if (foreground > VIEW_WIDTH-1) foreground-=VIEW_WIDTH;
break;
default:
break;
} DrawLayers();
memcpy(VideoRam,MemBuf,MEMBLK);
frames++;
} }
//
void Initialize()
{
position=0;
InitVideo(};
InitKeyboard();
if(!InitBitmaps())
{
Cleanup();
printf("\nError loading bitmaps\n");
exit(l);
} ReadTileMap("tilemap.dat");
ReadTiles();
}
// void Cleanup() {
RestoreVideo();
RestoreKeyboard();
FreeMem();
}
void ReadTiles(void)
{
PcxFile pcx;
char buf[80];
int i,result;
tiles[0]=NULL;
for(i=l;i<=NUM_TILES;i++)
{
sprintf(buf,"t%d.pcx",i);
result=ReadPcxFile(buf,&pcx);
if(result!= PCX_OK) (printf("\nerror reading file: %s\n",buf);
exit(1);
} tiles[i]=pcx.bitmap;
} }
void FreeTiles() { int i;
for(i=0;i<NUM_TILES;i++) free(tiles[i]);
}
void ReadTileMap(char *filename)
{
int i;
FILE *f;
f=fopen(filename,"rt");
for (i=0; i<TILES__TOTAL; i-H-) {
fscanf(f,"%d",&(tilemap[i]));
}
fclose(f);
}
//
void DrawTile(char *bmp,int x,int y,int offset, int width)
{
char *dest;
int i;
if(bmp == NULL) return;
dest=MemBuf+y*VIEW_WIDTH+x;
bmp+=offset;
for(i=0;i<TILE_HEIGHT;i++) {
memcpy(dest,bmp,width);
dest+=VIEW_WIDTH;
bmp+=TILE_WIDTH;
} }
//
void DrawTiles(int VirtualX,int Starty)
{
int i,x,index,offset,row,limit;
index=VirtualX>>SHIFT;
offset=VirtualX - (index<<SHIFT);
limit=TILES_PER_ROW;
if(offset==0)
limit--;
for(row=Starty;row<Starty+TILE_HEIGHT*TILE_ROWS;
row+=TILE_HEIGHT) {
x=TILE_WIDTH-of£set;
DrawTile(tiles[tilemap[index]],0,row,offset,
TILE_WIDTH-offset);
for(i=index+l;i<index+limit;i++)
{
DrawTile(tiles [tilemap [i]], x, row, 0, TILE_WIDTH);
x+=TILE_WIDTH;
} DrawTile(tiles [tilemap[i] ],x, row, 0,offset);
index+=TILE_COLS;
}
}
//
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;
)
Устранение эффекта сдвига кадра
На медленных машинах или на машинах с медленными видеокартами можно заметить некий сдвиг изображения, как будто оно копируется на экран. Из-за эффекта сдвига изображение выглядит как бы разорванным. Этот интересный но нежелательный эффект появляется оттого, что адаптер сканирует видеобуфер и рисует изображение на дисплее примерно 60 раз в секунду. Этот процесс называется регенерацией экрана. Если программа в момент начала регенерации дисплея находится в процессе рисования кадра, вы заметите эффект сдвига изображения.
К счастью, существуют методы проверки статуса регенерации экрана. На VGA-карте есть регистр, сообщающий, регенерируется ли экран в настоящее время- Все, что требуется для устранения эффекта сдвига кадра, это подождать, пока регенерация экрана завершится. Затем можно начать рисовать изображение.
В Листинге 17.7 содержится фрагмент программы, ожидающей завершения цикла регенерации экрана. Это дает вам примерно 1/60 секунды, чтобы нарисовать следующий кадр. Данный фрагмент можно поместить непосредственно перед функцией, перемещающей кадр из системной памяти в видеобуфер. Выполняйте такую проверку каждый раз перед копированием буфера на экран. Только на очень быстрых машинах или при использовании небольшого окна вывода, одной шестидесятой секунды будет достаточно для изображения нескольких планов и их копирования на экран. Это главный недостаток режима 13h. Единственная альтернатива проверке на регенерацию экрана — это использование видеорежимов, поддерживающих несколько видеостраниц, и переключение между ними.
Дата добавления: 2015-07-12; просмотров: 70 | Нарушение авторских прав
<== предыдущая страница | | | следующая страница ==> |
Листинг 17.4. Оптимизированная подпрограмма (BLIT.ASM). | | | Листинг 17.7. Проверка вертикальной трассировки. |