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             }

1 komentarz

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