Главная страница Случайная страница Разделы сайта АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
Листинг 17.6. Демонстрационная программа мозаичного смещающегося слоя (TILES.C).
#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. Единственная альтернатива проверке на регенерацию экрана — это использование видеорежимов, поддерживающих несколько видеостраниц, и переключение между ними.
|