   #Start Contents

                          Wyswietlanie obrazkow BMP

   Jesli przejrzeliscie moj poprzedni kurs zwiazany z grafika, to umiecie
   juz cos samodzielnie narysowac.

   Ale przeciez w Internecie (i nie tylko) jest tyle ciekawych rysunkow,
   nie mowiac juz o tych, ktore moglibyscie stworzyc dla jakiegos
   specjalnego celu, na przyklad swojej wlasnej gry. Dlatego teraz
   pokaze, jak takie rysunki wyswietlac. Ze wzgledu na prostote formatu,
   wybralem pliki typu BMP. Plik, ktory chcecie wyswietlic powinien miec
   rozmiar 320x200 pikseli w 256 kolorach (jak pamietamy, taki rysunek
   pasuje jak ulal do trybu graficznego 13h).
   Wszystkie operacje na pliku zostaly juz przez mnie szczegolowo opisane
   w jednej z czesci mojego kursu, wiec tutaj nie bedziemy poswiecac im
   zbyt wiele uwagi.
   Ale przejdzmy wreszcie do interesujacych nas szczegolow.

   Powinniscie zaopatrzyc sie w cokolwiek, co opisuje format BMP.
   Informacje, z ktorych bede tutaj korzystal, znalazlem w Internecie
   (niestety, nie pamietam juz gdzie, ale mozecie poszukac na
   Wotsit.org).
   A oto naglowek pliku BMP (skladnia jezyka Pascal niestety, info:
   "Piotr Sokolowski, 6 maja 1998r"):
   (przeskocz opis naglowka)
        Type
         TBitMapHeader =
          Record
                bfType :             Word; (dwa bajty)
                bfSize :             LongInt; (cztery bajty)
                bfReserved :         LongInt;
                bfOffBits :          LongInt;
                biSize :             LongInt;
                biWidth :            LongInt;
                biHeight :           LongInt;
                biPlanes :           Word;
                biBitCount :         Word;
                biCompression :      LongInt;
                biSizeImage :        LongInt;
                biXPelsPerMeter :    LongInt;
                biYPelsPerMeter :    LongInt;
                biClrUsed :          LongInt;
                biClrImportant :     LongInt;
          End;

   Gdzie:
     * bftype - jest to dwubajtowa sygnatura "BM"
     * bfsize - czterobajtowy rozmiar pliku
     * bfreserved - pole zarezerwowane (0)
     * bfoffbits - przesuniecie (adres) poczatku danych graficznych
     * bisize - podaje rozmiar naglowka
     * biwidth - wysokosc bitmapy w pikselach
     * biheight - szerokosc bitmapy w pikselach
     * biplanes - liczba planow (prawie zawsze ma wartosc 1)
     * bibitcound - liczba bitow na piksel. Przyjmuje wartosc 1,4,8 lub
       24.
     * bicompression - sposob kompresji
     * bisizeimag - rozmiar obrazka w bajtach. W przypadku bitmapy
       nieskompresowanej rowne 0.
     * biXpelspermeter, biYpelspermeter - liczba pikseli na metr
     * biclrused - liczba kolorow istniejacej palety, a uzywanych wlasnie
       przez bitmape
     * biclrimporant - okresla, ktory kolor bitmapy jest najwazniejszy,
       gdy rowny 0 to wszystkie sa tak samo istotne.

   Ale spokojnie - nie musicie znac tych wszystkich pol, bo my nie
   bedziemy wszystkich uzywac. Scisle mowiac, nie bedziemy uzywac ani
   jednego z tych pol!
   No to po co to wszystko?
   Po to, aby znac dlugosc naglowka pliku (54 bajty), ktory ominiemy przy
   analizie pliku.

   Po naglowku idzie paleta 256 kolorow * 4 bajty/kolor = kolejny 1kB.
   Jesli macie jakies watpliwosci co do tego 1 kilobajta, to slusznie.
   Oczywiscie, do opisu koloru wystarcza 3 bajty (odpowiadajace kolorom
   czerwonemu, zielonemu i niebieskiemu - RGB), co daje razem 768 bajtow.
   Co czwarty bajt nie zawiera zadnej istotnej informacji i bedziemy go
   pomijac (zmienna "z").

   Zaraz po palecie idzie obraz, piksel po pikselu. Niestety, nie jest to
   tak logiczne ustawienie, jak bysmy sobie tego zyczyli. Otoz, pierwsze
   320 bajtow to ostatni wiersz obrazka, drugie 320 - przedostatni, itd.
   Dlatego trzeba bedzie troszke pokombinowac.

   Zanim jeszcze zaczniemy, nalezy sie przyjrzec, ktorych portow (choc to
   samo mozna uzyskac wywolujac odpowiednie przerwanie) i dlaczego
   bedziemy uzywac (patrzymy do pliku "ports.lst" w Spisie Przerwan Ralfa
   Brown'a):
   (przeskocz opis portow)
        03C8  RW  (VGA,MCGA) PEL address register (write mode)
                 Sets DAC in write mode and assign start of color register
                 index (0..255) for following write accesses to 3C9h.
                 Don't read from 3C9h while in write mode. Next access to
                 03C8h will stop pending mode immediatly.
        03C9  RW  (VGA,MCGA) PEL data register
                 Three consequtive reads (in read mode) or writes (in write
                 mode) in the order: red, green, blue. The internal DAC index
                 is incremented each 3rd access.
                  bit7-6: HiColor VGA DACs only: color-value bit7-6
                  bit5-0:                        color-value bit5-0

   Czyli najpierw na port 3C8h idzie numer rejestru dla danego koloru
   (rejestrow jest 256 i kolorow tez), a potem na 3C9h ida trzy wartosci
   kolorow: czerwonego, zielonego i niebieskiego, ktorych polaczenie daje
   nam zadany kolor.

   Ale dobierzmy sie wreszcie do kodu:
   (przeskocz program)
; Program wyswietla na ekranie kolorowy rysunek o rozmiarze
; 320x200 w 256 kolorach, umieszczony w pliku.
;
; nasm -O999 -o bmp1.com -f bin bmp1.asm
;
; Autor: Bogdan D., bogdandr (at) op (kropka) pl
;
; na podstawie kodu podpisanego "Piotr Sokolowski",
; napisanego w jezyku Pascal

org 100h

start:
        mov     ax, 13h
        int     10h     ; uruchamiamy tryb graficzny 13h - 320x200x256

        mov     ax, 3d00h               ; otwieramy plik tylko do odczytu
        mov     dx, nazwa_pliku
        int     21h

        jnc     otw_ok

        mov     ah, 9
        mov     dx, blad_plik           ; wyswietlane, gdy wystapil blad
        int     21h

err:
        mov     ax, 4c01h               ; wyjscie z kodem bledu=1
        int     21h

otw_ok:
        mov     bx, ax                  ; bx = uchwyt do pliku
        mov     ah, 3fh                 ; czytanie z pliku
        mov     cx, 54                  ; wyrzucamy 54 bajty naglowka
        mov     dx, smieci
        int     21h
        jc      err

; wczytywanie palety z pliku:


        xor     si, si                  ; indeks do tablicy "paleta"

czytaj_pal:
        mov     ah, 3fh                 ; czytanie z pliku
        mov     cx, 4                   ; czytam po 4 bajty - do b,g,r i z.
                                        ; ("z" nas nie interesuje)
        mov     dx, b
        int     21h
        jc      err

                                        ; ustawiamy palete:
        mov     al, [r]
        shr     al, 2
        mov     [paleta+si], al         ; paleta[si] = [r] / 4

        mov     al, [g]
        shr     al, 2
        mov     [paleta+si+1], al       ; paleta[si] = [g] / 4

        mov     al, [b]
        shr     al, 2
        mov     [paleta+si+2], al       ; paleta[si] = [b] / 4

        add     si, 3                   ; przejdz o 3 miejsca dalej -
                                        ; na kolejne wartosci RGB

        cmp     si, 256*3               ; sprawdz, czy nie zapisalismy
                                        ; juz wszystkich kolorow
        jb      czytaj_pal

; wysylanie palety do karty graficznej:

        xor     ax, ax
        xor     si, si                  ; SI = indeks do palety

        mov     dx, 3c8h                ; port karty graficznej
wyslij_palete:
        out     dx, al                  ; wysylamy numer rejestru,
                                        ; wszystkie od 0 do 255

        inc     dx                      ; DX = port 3C9h

        push    ax
                                        ; zapisujemy kolorki:
                                        ; czerwony, zielony, niebieski.

        mov     al, [paleta+si]         ; AL = czerwony
                                        ; (patrz: petla "czytaj_pal")
        out     dx, al

        mov     al, [paleta+si+1]       ; AL = zielony
        out     dx, al

        mov     al, [paleta+si+2]       ; AL = niebieski
        out     dx, al

        pop     ax

        add     si, 3                   ; przejdz do nastepnych kolorow

        dec     dx                      ; DX z powrotem 3C8h

        inc     ax                      ; wybierzemy kolejny rejestr koloru
                                        ; w karcie graficznej

        cmp     ax, 256                 ; sprawdz, czy juz koniec pracy
        jb      wyslij_palete

; wczytywanie obrazka:

        mov     ax, 0a000h
        mov     ds, ax          ; czytaj bezposrednio do pamieci ekranu

        mov     dx, 64000-320           ; DX = adres ostatniego wiersza

        mov     cx, 320                 ; z pliku czytamy po 320 bajtow

obrazek:
        mov     ah, 3fh
        int     21h                     ; czytaj 320 bajtow prosto na ekran
        jc      err

        sub     dx, 320                 ; przejdz do wczesniejszego wiersza
        jnc     obrazek                 ; dopoki nie musimy pozyczac
                                        ; do odejmowania. Pozyczymy dopiero
                                        ; wtedy, gdy DX < 320 - a to sie
                                        ; zdarzy dopiero, gdy DX = 0, czyli
                                        ; przerobilismy caly obrazek i ekran.
                                        ; Wtedy konczymy prace.


; koniec programu:

        mov     ah, 3eh
        int     21h                     ; zamknij plik
        jc      err

        xor     ah, ah
        int     16h                     ; czekamy na klawisz

        mov     ax, 3
        int     10h                     ; powrot do trybu tekstowego

        mov     ax, 4c00h
        int     21h

; dane:


nazwa_pliku     db      "rys1.bmp",0
blad_plik       db      "Blad operacji na pliku!$"

smieci:         times   54      db 0
paleta:         times   768     db 0
b               db 0
g               db 0
r               db 0
z               db 0
kolor           db 0

   Mam nadzieje, ze kod jest dosc jasny. Nawet jesli znacie asemblera
   tylko w takim stopniu, w jakim to jest mozliwe po przeczytaniu mojego
   kursu, zrozumienie tego programu nie powinno sprawic Wam wiecej
   klopotow niz mnie sprawilo przetlumaczenie go z Pascala.

   Spis tresci off-line (klawisz dostepu 1)
   Spis tresci on-line (klawisz dostepu 2)
   Ulatwienia dla niepelnosprawnych (klawisz dostepu 0)
