Wyświelanie bitmapy w trybie 13h
Oleksy_Adam
Program ten umożliwia wyswietlenie bitmapy 320x200x256 w trybie graficznym 13h. Program działa w wierszu polecenia. Jako parametr podaje się nazwę pliku do wyświetlenia.
PROGRAM Viewer;
USES Dos, Crt;
{ procedura wykonujaca petle dopuki uzytkownik nie nacisnie klawisza ESC }
PROCEDURE WaitForESC;
VAR ch :char;
BEGIN
REPEAT
IF KeypRessed THEN ch:=ReadKey;
UNTIL ch = #27;
END; { wait }
TYPE
PBuf = ^TBuf;
TBuf = ARRAY [0..63999] OF byte;
{ Paleta pliku *.BMP zapisanego w 256 kolorach }
{ Opis pol: }
{ B - skladowa niebieska }
{ G - skladowa zielona }
{ R - skladowa czerwona }
{ Z - pole zarezerwowane }
PPalBMP = ^TPalBMP;
TPalBMP = ARRAY [0..255] OF RECORD B, G, R, Z :byte; END;
{ Naglowek pliku *.BMP. W programie zastosowany do kontroli formatu }
{ zdjec poddawanych obrobce. W nawiasach podano offset pola wzgledem }
{ poczatku pliku }
THeader = RECORD
{ typ - Specyfikator typu pliku okreslajacy typ }
{ przechowywanego obrazu }
{ BM - BitMapa }
{ BA - Bitmap Array (tablica bitmapy }
{ CI - Color Icon (kolorowa ikona) }
{ CP - Color Pionter (kursor myszy) }
{ IC - Icon (ikona) }
{ PT - Pointer (kursor myszy) }
{ 00h } typ :ARRAY [0..1] OF char;
{ FSIze - Rozmiar calego pliku podany w bajtach. Nas }
{ interesuje tylko rozmiar 65078 }
{ 02h } FSize :LongInt;
{ wolne1 i wolne2 - Pola zarezerwowane, zawsze 0 }
{ 06h } wolne1 :word;
{ 08h } wolne2 :word;
{ offset - Odleglosc od poczatku pliku pierwszego bajtu }
{ obrazu, podana w pikselach }
{ 0Ah } offset :LongInt;
{ info - Rozmiar naglowka informacyjnego bitmapy podany }
{ w bajtach. Dla bitmap tworzonych w roznych systemach }
{ moze przybierac rozna wartosc: }
{ 12 - dla systemu OS/2 1.x, }
{ 40 - dla systemu Windows 3.x, }
{ 64 - dla systemu OS/2 2.x }
{ 0Eh } info :LongInt;
{ szer - Szerokosc obrazu podana w pikselach. Dla programu }
{ musi byc rowna 320 }
{ 12h } szer :LongInt;
{ wys - Wysokosc obrazu podana w pikselach. Dla programu }
{ musi byc 200 }
{ 16h } wys :LongInt;
{ plany - liczba planow w obrazie, zawsze 1. Inne wartosci }
{ mozna spotkac w animowanych gifach }
{ 1Ah } plany :word;
{ BitPerPixel - Liczba bitow uzywana do reprezentacji }
{ jednego piksela: }
{ 1 - bitmapa monochromatyczna (czarno - biala), }
{ 4 - bitmapa 16-kolorowa, }
{ 8 - bitmapa 256-kolorowa, }
{ 24 - bitmapa sklada sie z pikseli mogacych przybierac jeden }
{ z 16777216 kolorow, plik bitmapy nie ma palety kolorow, }
{ kazde kolejne trzy bajty obrazu oznaczaja intenywnosc }
{ barwy czerwonej, zielonej i niebieskej dla kolejnych }
{ pikseli }
{ 1Ch } BitPerPixel :word;
{ kompresja - Typ kompresji obrazu: }
{ 0 - BI_RGB, obraz nieskompresowany, }
{ 1 - BI_RLE, 8 bitowa kompresja RLE, }
{ 2 - BI_RLE, 4 bitowa kompresja RLE }
{ 1Eh } kompresja :LongInt;
{ rozmiar - Rozmiar obrazu podany w bajtach }
{ 22h } rozmiar :LongInt;
{ HDPI Horizontal Dots Per Inch - Pozioma rozdzielczosc obrazu }
{ podana w ilosci punktow na cal kwadratowy }
{ 26h } HDPI :LongInt;
{ VDPI Vetical Dots Per Inch - Pionowa rozdzielczosc obrazu }
{ podana w ilosci punktow na cal kwadratowy }
{ 2Ah } VDPI :LongInt;
{ kolory - Jezeli liczba uzywanych kolorow wynosi zero, bitmapa }
{uzywa liczby kolorow zgodnej z liczba bitow uzywanych do }
{ reprezenatcji jednego piksela; jezeli pole zawiera wartosc }
{ niezerowa, okresla ona liczbe wzorcow koloru uzywanych do }
{ wyswietlania obrazu }
{ 2Eh } kolory :LongInt;
{ znaczace - Liczba wzorcow koloru brana pod uwage podczas }
{ ustalania kolorow pikseli; jezeli to pole zawiera 0, to }
{ znaczy, ze wszystkie kolory sa uzywane }
{ 32h } znaczace :LongInt;
END;
CONST
SizePalBMP = 1024; { rozmiar palety bitmapy 8 bitowej }
HeaderSize = 54; { rozmiar naglowka informacyjnego }
PictureSize = 64000; { rozmiar danych obrazu }
Safety = 4096; { obszar bezpieczenstwa - 4kb }
VAR
F1 :FILE; { F1 - do odczytu }
PalBMP :PPalBMP; { wskaznik na palete BMP }
Header :THeader; { naglowek pliku bitmapy }
Buf :PBuf; { wskaznik na dane obrazu }
i, j :Word; { liczniki petli }
BEGIN
{ sprawdzamy czy jest co wyswietlic na ekranie }
IF ParamCount = 0 THEN
BEGIN
WriteLn('Wywolanie: VIEWER.EXE nazwa_pliku.bmp');
Halt(1);
END;
{ na samym poczatku sprawdzamy czy jest wystarczajaco pamieci }
IF PictureSize > MaxAvail-Safety THEN
BEGIN
WriteLn('Program ma za malo pamieci do pokazania obrazka');
Halt(1);
END;
ASM { uruchamiamy tryb graficzny 320x200x256 }
MOV AX, 13h
INT 10h
END;
Assign(F1, ParamStr(1)); { skojaz plik F1 }
Reset(F1, 1); { do odczytu }
BlockRead(F1, Header, HeaderSize); { odczyt naglowka bitmapy }
IF (Header.FSize = 65078) AND { sprawdzamy rozmiar pliku }
(Header.Szer = 320) AND { oraz szerokosc, }
(Header.Wys = 200) AND { wysokosc i }
(Header.Typ = 'BM') THEN { typ obrazu }
BEGIN { jezeli OK to }
Seek(F1, 54); { skok za naglowek bitmapy }
New(PalBMP); { tworzymy zmienne na palety }
BlockRead(F1, PalBMP^, SizePalBMP); { odczyt palety bitmapy }
Port[$3C8] := 0; { zapis nowej palety poczawszy }
FOR i:=0 TO 255 DO { od pierwszego wzorca }
BEGIN
Port[$3C9] := PalBMP^[i].R SHR 2; { skladowe nalezy podzielic }
Port[$3C9] := PalBMP^[i].G SHR 2; { przez 4 }
Port[$3C9] := PalBMP^[i].B SHR 2;
END;
Dispose(PalBMP); { zwalniamy pamiec na palete }
New(Buf); { utworzenie bufora ekranu }
Seek(F1, 1078); { skok za palte kolorow }
BlockRead(F1, Buf^, PictureSize); { odczyt }
Close(F1); { zamykamy plik }
{ Ponizszy algorytm wyswiela bmp na ekranie. Najszybszy z algorytmow jaki napisalem }
{ Można użyć pętli i Mem[segment:offset] }
ASM
PUSH DS { zapamietujemy segment danych }
MOV AX, $A000 { ES = segment ekranu }
MOV ES, AX { ES:[DI] = $A000:0000 }
MOV DI, 0 { DI = offset ekranu }
LDS SI, Buf[0] { DS = segment bufora }
MOV SI, 64000-320 { SI = offset ostatniej linii }
MOV CX, 200 { licznik wierszy }
@@1: { etykieta }
MOV BX, CX { zapamietujemy CX }
MOV CX, 320 { licznik kolumn }
REP MOVSB { ES:[DI] = DS:[SI] (x320) }
SUB SI, 640 { nastepny wiersz }
MOV CX, BX { odtworz CX }
LOOP @@1
POP DS
END;
Dispose(Buf); { zwalniamy pamiec na zdjecie }
WaitForESC; { czekamy na eskejp-a }
END { IF Header } ELSE WriteLn('Plik: '+ParamStr(1)+' jest niedobry');
ASM { przywracamy tryb tekstowy }
MOV AX, 03h { 80x25x16 }
INT 10h
END;
END. { Koniec programu }
bez kombinacji mozna to przyspieszyc dwukrotrnie przez
mov cx, 160 i
rep movsw
bedzie to samo ale 2 razy szybciej
a
gdy w lini:
@@1: { etykieta }
MOV BX, CX { zapamietujemy CX }
{teraz 4 razy mniej bo bedzie 4 razy wiecej na raz czyli 320/4=80}
MOV CX, 80 { licznik kolumn }
{zmienimy REP MOVSB na: MOVSDW - jego kod w assemblerze}
Db $F3,$66,$A5 {kopiowanie bedzie 32 a nie 8 bitowe - ok. 4 krotnie szybsze - b. przydatne przy tworzeniu gier z szybka grafika. Na tej podstawie tworzy sie projekty wyciagajace do 1500klatek na sekunde w trybie 13h }
SUB SI, 640 { nastepny wiersz }
MOV CX, BX
wiecej informacji o szybkiej grafice:
http://www.programowanie.virtual.avx.pl/index.php?page=91