Algoritmy rovinnΘ grafiky

     Obrßzek vytvß°en² na obrazovce se sklßdß z r∙zn²ch
elementßrnφch objekt∙: bod∙, ·seΦek, kruh∙, elips atd.
Zobrazenφ t∞chto objekt∙ je r∙zn∞ slo₧itΘ. Bodu odpovφdß
jeden bit obrazovΘ pam∞ti, zde nenφ ₧ßdn² problΘm.
U slo₧it∞jÜφch objekt∙ (Φßra, kruh) je situace pon∞kud
slo₧it∞jÜφ. Z Φist∞ matematickΘho hlediska jsou tyto objekty
slo₧eny z nekoneΦnΘho poΦtu bod∙. Obrazovka samoz°ejm∞
nem∙₧e zobrazit tak velk² poΦet nekoneΦn∞ mal²ch bod∙ a tak
musφ b²t provedena urΦitß aproximace, kdy se vykreslφ pixely
le₧φcφ nejblφ₧e skuteΦnΘmu umφst∞nφ k°ivky. Algoritmy pro
rovinou grafiku majφ za ·kol, co nejrychleji
a nejjednoduÜeji, urΦit polohu aproximovan²ch pixel∙.
Z t∞chto algoritm∙ je nejjednoduÜÜφ algoritmus pro kreslenφ
·seΦek. Rozebereme ho zde tedy pon∞kud podrobn∞ji.

Bresenham∙v algoritmus pro kresbu ·seΦky
     Z matematiky si jeÜt∞ mo₧nß pamatujete, ₧e rovnici
p°φmky lze zapsat ve tvaru:

     y = mx + b,                         ( 1 )

kde m je sm∞rnice a b posun na ose y. Je-li ·seΦka urΦena
poΦßteΦnφm a koncov²m bodem (sou°adnicmi bod∙ [x1,y1] a
[x2,y2]), m∙₧eme sm∞rnici a posunutφ vyjßd°it nßsledujφcφmi
vztahy:
           y2-y1     δy
     m =  ------- = ----
           x2-x1     δx
                                         ( 2 )
          x2y1-x1y2     x2y1-x1y2
     b = ----------- = -----------.
            x2-x1           δx

Algoritmy pro zobrazenφ ·seΦky vychßzejφ z rovnic 1 a 2.
Na n∞jakΘm intervalu δx se sou°adnice y zm∞nφ o hodnotu δy
podle nßsledujφcφho vztahu:

     δy = m δx.

     J.E.Bresenham vymyslel algoritmus, kter² p°i generovßnφ
·seΦky vystaΦφ s celoΦφselnou aritmetikou. Na obrßzku 10 je
nakreslena Φßst obrazovky, na kterΘ majφ b²t zobrazeny
pixely ·seΦky. Po nakreslenφ levΘho koncovΘho bodu ·seΦky
mßme rozhodnout, zda nßsledujφcφ bod bude vykreslen na
pozici se sou°adnicφ y stejnou jako p°edchozφ bod nebo o
jedna v∞tÜφ. Z t∞chto dvou mo₧nostφ umφst∞nφ nßsledujφcφho
pixelu vybereme tu, kterß le₧φ blφ₧e skuteΦnΘ poloze bodu
·seΦky.
     PopφÜeme si zde zp∙sob, jak pomocφ Bresenhamova
algoritmu vykreslit ·seΦku s kladnou sm∞rnicφ menÜφ ne₧ 1.
Ostatnφ sm∞ry jsou pouze obm∞nou dßle uvdednΘho postupu. V
p°φpad∞, ₧e ·seΦka mß kladnou sm∞rnici menÜφ ne₧ jedna je
°φdφcφ osou osa x. Znamenß to, ₧e postupn∞ pro vÜechny
sou°adnice x m∞n∞nΘ o jedniΦku, urΦφme jim odpovφdajφcφ
sou°adnice y. P°edpokoklßdejme, ₧e pixel o sou°adnicφch
[xi,yi] ji₧ byl nakreslen a my mßme rozhodnou o poloze
nßsledujφcφho. Na v²b∞r mßme ze dvou mo₧nostφ [xi+1,yi] a
[xi+1,yi+1]. Vzdßlenost t∞chto dvou bod∙ od skuteΦnΘho bodu
·seΦky je na obraßzku 10 vyznaΦena jako d1 a d2. Pro
skuteΦnou sou°adnci y platφ:

     y = m (xi + 1) + b.

Pak platφ:

     d1 = y - yi       = m (xi + 1) + b - yi

     d2 = yi + 1 - y   = yi + 1 - m (xi + 1) - b

Rozdφl t∞chto dvou vzdßlenostφ je:

     δd = d1 - d2 = 2m (xi + 1) - 2yi + 2b - 1    ( 3 )

Podle prom∞nΘ δd m∙₧eme urΦit, kter² ze dvou pixel∙ le₧φ
blφ₧e skuteΦnΘmu umφst∞nφ useΦky. Kladnß hodnota δd, znamenß
₧e d1 > d2 a tudφ₧ bli₧Üφ je pixel o sou°adnicφch
[xi+1,yi+1]. Naopak zßpornß hodnota δd (d1 < d2) vybere
pixel o sou°adnicφch [xi+1,yi]. Nenφ tedy d∙le₧itß hodnota
δd, ale jejφ znamΘnko. Bohu₧el δd nenφ dφky m celoΦφslenß.
Celou rovnici 3 vÜak m∙₧eme vynßsobit δx a dostßvßme:

     pi = δd δx = 2 δy xi - 2 δx yi + 2 δy + δx (2b - 1),  ( 4 )

kde 2 δy + δx (2b - 1) je konstanta, kterß bude p°i
nßsledujφcφch ·pravßch vylouΦena. Hodnotu p, podle jejφho₧
znamΘnka urΦujeme polohu nßsledujφcφch pixel∙ nazveme
predikcφ. Predikci nßsledujcφho bodu pi+1 m∙₧eme zapsat
jako:

     pi+1 = 2 δy xi+1 - 2 δx yi+1 + konstanta        ( 5 )

Rovnice 4 a 5 m∙₧eme odeΦφst, vyjßd°φme tak pi+1 pomocφ pi:

     pi+1 = pi + 2 δy - 2 δx (yi+1 - yi),            ( 6 )

za p°edpokladu, ₧e xi+1 = xi + 1.
     Nßsledujφcφ vztahy vyjad°ujφ zßvislost hodnoty pi+1 na
hodnot∞ pi:
   /---------------------------------------------\
   | pi < 0      =>    pi+1 = pi + 2 δy          |
   |---------------------------------------------|
   | pi ≥ 0      =>    pi+1 = pi + 2 δy - 2 δx   |
   \---------------------------------------------/
Prvnφ hodnota predikce p1 se zφskß dosazenφm poΦßteΦnφho
bodu ·seΦky do rovnice 4. Dostaneme p1 = 2 δy - δx.
     Predikce tvo°φ zßkladnφ kritΘrium pro v²b∞r pixel∙
tvo°φcφch rastrov² obraz ·seΦky. Hodnotu pi pro ka₧d² pixel
postupn∞ aktualizujeme podle jednoduch²ch vztah∙ v tabulce.
ZnamΘnko predikce urΦuje polohu nßsledujφcφho pixelu. Pokud
je predikce zßpornß, y sou°adnice nßsledujφcφho pixelu se
nem∞nφ. Pokud je kladnß, zv∞tÜφ se o jedna.
     V p°φpad∞, kdy je sm∞rnice v∞tÜφ ne₧ jedna zam∞nφme
sou°adnice x a y a algoritmus z∙stane stejn². Pokud je
sm∞rnice ·seΦky zßpornß, jedna ze sou°adnic se zmenÜuje a
zbytek postupu je shodn².

                     P°φklad na zßv∞r

     N∞kterΘ zde uvedenΘ poznatky shrneme do ukßzkovΘho
programu. Je jφm jednoduchß grafickß knihovna, kterß dovede
pouze kreslit Φßry r∙zn²mi barvami a r∙zn²m zp∙sobem je
kombinovat s ji₧ nakreslen²mi objekty. Knihovna je ve tvaru
unity pro Turbo Pascal, co₧ je pro v∞tÜinu z vßs asi
nejdostupn∞jÜφ a nejsrozumiteln∞jÜφ programovacφ jazyk. Pro
dosa₧enφ vysokΘ rychlosti jsou jejφ klφΦovΘ Φßsti napsßnΘ
v assembleru.

Unit SGraph;

interface

Const
  { Konstanty pro typ kreslenφ }
  NormalPut = 0;              { P°episovßnφ }
  ANDPut    = 8;              { LogickΘ AND }
  ORPut     = 16;             { LogickΘ OR }
  XORPut    = 24;             { LogickΘ XOR }

{ HlaviΦky exportovan²ch procedur }
procedure Line( X1, Y1, X2, Y2: word);  { Kreslenφ Φßry }
procedure InitGraph;                    { Inicializace grafiky }
procedure CloseGraph;                   { Obnovenφ p∙vodnφho videom≤du }
procedure SetColor( Color: byte);       { Nastavenφ barvy pro kreslenφ Φar }
procedure SetWriteMode( Mode: byte);    { Volba druhu kombinace kreslen²ch a
                                          ji₧ zobrazen²ch dat }

implementation

Const
  ActColor: byte = 15;          { Prom∞nß slou₧φcφ k ulo₧enφ aktußlnφ barvy
                                  Standardn∞ je nastavena bφlß barva }
  WriteMode: byte = 0;          { Zapisovacφ re₧im 0 = p°episovßnφ
                                                   8 = AND
                                                  16 = OR
                                                  24 = XOR          }
  BytesPerRow = 80;             { PoΦet byte v jednΘ °ßdce (640/8 = 80) }
  IsGraphicsMode: boolean
                  = false;      { Indikace zda jsme v grafice }
  PixelsPerByte      = 3;            { PoΦet bod∙ v jednom bite udan²
                                       v bitov²ch posuvech }
  ModMask            = 7;            { Bitovß maska pro zφskßnφ MOD 8 (zbytku
                                       po d∞lenφ osmi }
  BMask              = 128;          { Bitovß maska pro kreslenφ bodu }
  VRAMSegment        = $a000;        { Segment poΦßtku obrazovΘ pam∞ti }
  GraphicsAR         = $3ce;         { Port Graphics 1 and 2 Address Register }
  ModeRegister       = 5;            { Index registru zapisovacφho m≤du }
  DataRotate         = 3;            { Index registru pro rotaci a kombinaci dat }
  BitMask            = 8;            { Index registru bitovΘ masky }

var
   OldVMode: byte;                   { Prom∞nß slou₧φcφ pro uchovßnφ Φφsla
                                       zobrazovacφho re₧imu }
   delta: word;                      { PomocnΘ prom∞nΘ pro uchovßnφ 2dx nebo 2dy}

procedure Line( X1, Y1, X2, Y2: word); assembler;
{ Kreslφ Φßru z X1, Y1 do X2, Y2 }
const
     neg_dx     = 2;            { ZnamΘnko od delta x }
     neg_dy     = 4;            { ZnamΘnko od delta y }

asm
        push    BP              { Uchovßnφ registr∙ BP }
        push    DS              {                 a DS }

        mov     AX, X1          { NaΦtenφ sou°adnic do registr∙ procesoru }
        mov     BX, Y1
        mov     CX, X2
        mov     DX, Y2

        xor     BP, BP          { Smazßnφ registru BP }
        mov     DI, CX          { SpoΦφtßnφ hodnoty deltax }
        sub     DI, AX
        jg      @p_dx           { Je deltax kladnΘ ? }
        or      BP, neg_dx      { ne => ulo₧ znamΘnko do BP }
        neg     DI              {       absolutnφ hodnota DI tj. deltax }

  @p_dx:
        mov     SI, DX          { UrΦenφ hodnoty deltay }
        sub     SI, BX
        jg      @p_dy           { Je deltay kladnΘ ? }
        or      BP, neg_dy      { ne => ulo₧ znamΘnko do BP }
        neg     SI              {       absolutnφ hodnota delaty }

  @p_dy:
        cmp     DI, SI          { Porovnßnφ deltax a deltay }
        jb      @vertical_dir   { deltax > deltay <=> absolutnφ hodnota sm∞rnice > 1
                                                          => vertikßlnφ sm∞r
                                  deltax <= deltay <=> absolutnφ hodnota sm∞rnice <= 1
                                                          => horizontßlnφ sm∞r          }

  @horizontal_dir:
        test    BP, neg_dx      { Porovnßnφ X1 a X2 }
        jz      @hor_init       { Je sm∞r zprava doleva ? }
        xchg    AX, CX          { ne => vym∞n sou°adnice poΦßtku a konce Φßry }
        xchg    BX, DX
        xor     BP, neg_dy      { uprav znamΘnko deltay }

  @hor_init:                    { V²poΦet adresy prvnφho bodu }
        mov     CX, AX          { Do CX X1 }
        xchg    AX, BX          { BX = X1, AX = X2 }
        mov     DX, BytesPerRow        { DX = PoΦet byte na jednΘ °ßdce (80) }
        mul     DX                     { AX:DX = Y1 * 80 }
        shr     BX, PixelsPerByte      { BX = BX div 8 }
        add     BX, AX                 { V BX je offset prvnφho bodu Φßry }

        mov     AX, DS                 { Do ES p°esuneme DS }
        mov     ES, AX

        mov     AX, VRAMSegment        { Segment obrazovΘ pam∞ti do DS }
        mov     DS, AX
        mov     DX, GraphicsAR            { Port adresovΘho registru grafickΘho kontroleru }
        mov     AX, ModeRegister + $0200  { Nastavφ zapisovacφ m≤d 2 }
        out     DX, AX

        mov     AL, DataRotate            { Nastavφ zp∙sob kombinace dat z CPU }
        mov     AH, ES: WriteMode         { s latch-registry }
        out     DX, AX

        and     CX, ModMask             { CX = X1 and 7 }
        mov     AH, BMask               { AH = 80h, tj. nastaven je lev² pixel }
        shr     AH, CL                  { Rotace AH. Po rotaci je v AH bitovß maska bodu }

        mov     DX, BP                  { Uchovß znamΘnka deltax a deltay v DX }

        mov     CX, DI                  { CX = deltax }
        inc     CX                      { CX = deltax - 1, tj. poΦet bod∙ na Φß°e }
                                        { V²poΦet predikce do BP: }
        shl     SI, 1                   { SI = 2*deltay }
        mov     BP, SI                  { BP = 2*deltay }
        sub     BP, DI                  { BP = 2*deltax - deltay }
        shl     DI, 1                   { DI = 2*deltax }

        mov     ES: delta, DI           { Ulo₧enφ hodnoty 2*deltax }

        mov     DI, BX                  { Do DI offset adresy 1. bodu }

        test    DX, neg_dy              { UrΦenφ sm∞ru }
        pushf                           { Uchovßnφ flag∙ }
        mov     DX, GraphicsAR          { Nastavφ index graf. kontroleru na Bit mask reg. }
        mov     AL, BitMask
        out     DX, AL
        inc     DX                      { DX = datov² port graf. kontroleru }
        popf                            { Obnovφ flagy s v²sledkem testu sm∞ru }
        jnz     @hor_neg_dy_init        { Rozskok, podle znamΘnka sm∞rnice }

  @hor_pos_dy_init:                     { Kladnß sm∞rnice, y sou°adnice je zvyÜovßna }
        mov     BL, ES: ActColor        { BL = Barva Φßry }
        mov     BH, BL                  { BH = Barva Φßry }
        mov     AL, AH                  { AL = Bitovß maska prvnφho bodu }

  @hor_pos_dy:
        cmp      BP, 0                  { Test predikce }
        jng      @hor_pos_dy_L1
        out      DX, AL                 { predikce >= 0 }
        mov      BL, BH                 { BL = Barva bodu }
        xchg     [DI], BL               { Nakresli bod }
        xor      AL, AL                 { Vynuluje st°ßdanou masku }
        sub      BP, ES: delta          { Upravφ predikaci P = P - 2*deltax }
        add      DI, BytesPerRow        { Zv∞tÜenφ y sou°adnice }
  @hor_pos_dy_L1:
        add      BP, SI                 { ┌prava predikce P = P + 2*deltay }
        ror      AH, 1                  { Zv∞tÜenφ x sou°adnice }
        jc       @hor_pos_dy_L2         { P°esßhli jsme jeden byte ? }
        or       AL, AH                 { Uprav masku byte }
        loop     @hor_pos_dy            { DalÜφ bod }
        jmp      @hor_pos_dy_lastbyte   { DoÜli jsme do koncovΘho bodu }
  @hor_pos_dy_L2:
        out      DX, AL                 { Nastavφ novou bitovou masku }
        mov      BL, BH
        xchg     [DI], BL               { Nakreslφ body jednoho byte }
        mov      AL, AH                 { Inicializuje bitovou masku }
        inc      DI                     { Zv∞tÜφ x sou°adnici }
        loop     @hor_pos_dy            { Byl to poslednφ bod ? }
        jmp      @l_done                {        => konec kreslenφ Φßry }
  @hor_pos_dy_lastbyte:
        xor      AL, AH                 { Poslednφ bit je neplatn², odstranit }
        out      DX, AL                 { Nastavenφ bitovΘ masky }
        mov      BL, BH                 { BL = Barva Φßry }
        xchg     [DI], BL               { Nakreslenφ bodu }
        jmp      @l_done                { UkonΦenφ kreslenφ Φßry }

  @hor_neg_dy_init:                     { Zßpornß sm∞rnice, y sou°adnice je zmenÜovßna }
        mov     BL, ES: ActColor        { BL = Barva Φßry }
        mov     BH, BL                  { BH = Barva Φßry }
        mov     AL, AH                  { AL = Bitovß maska prvnφho bodu }

  @hor_neg_dy:
        cmp      BP, 0                  { Test predikce }
        jng      @hor_neg_dy_L1
        out      DX, AL                 { predikce >= 0 }
        mov      BL, BH                 { BL = Barva bodu }
        xchg     [DI], BL               { Nakresli bod }
        xor      AL, AL                 { Vynuluje st°ßdanou masku }
        sub      BP, ES: delta          { Upravφ predikaci P = P - 2*deltax }
        sub      DI, BytesPerRow        { ZmenÜenφ y sou°adnice }
  @hor_neg_dy_L1:
        add      BP, SI                 { ┌prava predikce P = P + 2*deltay }
        ror      AH, 1                  { Zv∞tÜenφ x sou°adnice }
        jc       @hor_neg_dy_L2         { P°esßhli jsme jeden byte ? }
        or       AL, AH                 { Uprav masku byte }
        loop     @hor_neg_dy            { DalÜφ bod }
        jmp      @hor_neg_dy_lastbyte   { DoÜli jsme do koncovΘho bodu }
  @hor_neg_dy_L2:
        out      DX, AL                 { Nastavφ novou bitovou masku }
        mov      BL, BH
        xchg     [DI], BL               { Nakreslφ body jednoho byte }
        mov      AL, AH                 { Inicializuje bitovou masku }
        inc      DI                     { Zv∞tÜφ x sou°adnici }
        loop     @hor_neg_dy            { Byl to poslednφ bod ? }
        jmp      @l_done                {        => konec kreslenφ Φßry }
  @hor_neg_dy_lastbyte:
        xor      AL, AH                 { Poslednφ bit je neplatn², odstranit }
        out      DX, AL                 { Nastavenφ bitovΘ masky }
        mov      BL, BH                 { BL = Barva Φßry }
        xchg     [DI], BL               { Nakreslenφ bodu }
        jmp      @l_done                { UkonΦenφ kreslenφ Φßry }


  @vertical_dir:                        { V²poΦet adresy 1. bodu }
        test    BP, neg_dy              { Kreslφme shora dol∙ ? }
        jz      @vert_init
        xchg    AX, CX                  { Prohozenφ sou°adnic }
        xchg    BX, DX
        xor     BP, neg_dx              { ┌prava znamΘnka }

  @vert_init:
        mov     CX, AX                  { CX = X1 }
        xchg    AX, BX                  { AX = Y1, BX = X1 }
        mov     DX, BytesPerRow         { DX = PoΦet byte na °ßdku (80) }
        mul     DX                      { AX:DX = Y1 * 80 }
        shr     BX, PixelsPerByte       { BX = X1 div 8 }
        add     BX, AX                  { BX = Offset adresy 1. bodu }

        mov     AX, DS                  { Ulo₧φ datov² segment do ES }
        mov     ES, AX

        mov     AX, VRAMSegment         { DS = Segment obrazovΘ pam∞ti }
        mov     DS, AX
        mov     DX, GraphicsAR             { Port adresovΘho registru graf. kontroleru }
        mov     AX, ModeRegister + $0200   { Nastavφ zapisovacφ m≤d 2 }
        out     DX, AX

        mov     AL, DataRotate          { Nastavenφ zp∙sobu kombinovßnφ dat z CPU }
        mov     AH, ES: WriteMode       { s latch-registry                        }
        out     DX, AX

        and     CX, ModMask             { CX = X1 and 7 }
        mov     AH, BMask               { Bitovß maska pro lev² bod (80h) }
        shr     AH, CL                  { Rotacφ vytvo°φ sprßvnou masku }

        mov     DX, BP                  { Ulo₧φ znamΘnka do DX }

        mov     CX, SI                  { CX = DΘlka Φßry }
        inc     CX
                                        { UrΦenφ predikace }
        shl     DI, 1                   { DI = 2*deltax }
        add     BP, DI                  { BP = 2*deltax }
        sub     BP, SI                  { BP = 2*deltax - deltay }
        shl     SI, 1                   { SI = 2*deltay }

        mov     ES: delta, SI           { ulo₧φ 2*deltay }
        mov     SI, DI                  { SI = 2*deltax }

        mov     DI, BX                  { DI = Offset adresy 1. bodu }

        test    DX, neg_dx              { ZjiÜt∞nφ sm∞ru }
        mov     DX, GraphicsAR          { DX = adresov² port graf. kontroleru }
        jnz     @vert_neg_dx_init       { Rozskok podle znamΘnka sm∞rnice }

  @vert_pos_dx_init:                    { Kladnß sm∞rnice }
        mov     BL, ES: ActColor        { BL = Barva Φßry }
        mov     BH, BL                  { BH = Barva Φßry }
        mov     AL, BitMask             { Index Bit mask registru }
        out     DX, AX
        inc     DX                      { DX = datov² registr graf. kontroleru }
        mov     AL, AH                  { AL = Bitovß maska }

  @vert_pos_dx:
        mov     BL, BH                  { BL = Barva Φßry }
        xchg    [DI], BL                { Nakreslφ bod }
        cmp     BP, 0                   { Test predikce }
        jng     @vert_pos_dx_L1
        sub     BP, ES: delta           { P >= 0, P = P - 2*deltay }
        ror     AL, 1                   { ZvyÜ sou°adnici x }
        adc     DI, 0                   { P°esun do dalÜφho byte }
        out     DX, AL                  { Nastav novou bitovou masku }

  @vert_pos_dx_L1:
        add     BP, SI                  { P = P + 2*deltax }
        add     DI, BytesPerRow         { ZvyÜ sou°adnici y }
        loop    @vert_pos_dx            { DalÜφ bod }
        jmp     @l_done                 { Konec Φßry }

  @vert_neg_dx_init:                    { Zßpornß sm∞rnice }
        mov     BL, ES: ActColor        { BL = Barva Φßry }
        mov     BH, BL                  { BH = Barva Φßry }
        mov     AL, BitMask             { Index Bit mask registru }
        out     DX, AX
        inc     DX                      { DX = datov² registr graf. kontroleru }
        mov     AL, AH                  { AL = Bitovß maska }

  @vert_neg_dx:
        mov     BL, BH                  { BL = Barva Φßry }
        xchg    [DI], BL                { Nakreslφ bod }
        cmp     BP, 0                   { Test predikce }
        jng     @vert_neg_dx_L1
        sub     BP, ES: delta           { P >= 0, P = P - 2*deltay }
        rol     AL, 1                   { ZmenÜi sou°adnici x }
        sbb     DI, 0                   { P°esun do dalÜφho byte }
        out     DX, AL                  { Nastav novou bitovou masku }

  @vert_neg_dx_L1:
        add     BP, SI                  { P = P + 2*deltax }
        add     DI, BytesPerRow         { ZvyÜ sou°adnici y }
        loop    @vert_neg_dx            { DalÜφ bod }
        jmp     @l_done                 { Konec Φßry }

  @l_done:
        mov     DX, GraphicsAR          { Smazßnφ bitovΘ masky }
        mov     AX, BitMask
        out     DX, AX
        mov     AX, ModeRegister
        out     DX, AX                  { Nastavφ zapisovacφ m≤d 0 }
        mov     AX, DataRotate
        out     DX, AX                  { Vypne rotyci dat, standardnφ kombinovßnφ dat }

  @exit:
        pop      DS                     { Obnovφ obsah registr∙ DS }
        pop      BP                     {                       BP }
end;

procedure SetMode( Mode: byte); assembler;
{ Nastavφ aktußlnφ zobrazovacφ re₧im pomocφ slu₧by 00h BIOS }
asm
        mov     AH, 00h
        mov     AL, Mode
        int     10h
end;
function GetMode: byte; assembler;
{ Slu₧bou BIOS zjistφ zobrazovacφ re₧im }
asm
        mov     AH, 0fh
        int     10h
end;

procedure InitGraph;
{ Inicializace grafiky }
begin
  if not IsGraphicsMode then
    OldVMode := GetMode;        { Ulo₧φ Φφslo aktivnφho zobrazovacφho re₧imu }
  SetMode( $12);                { Nastavφ zobrazovacφ re₧im 640 x 480, 16 barev }
  IsGraphicsMode := True;       { Nastavφ p°φznak p°epnutφ do grafiky }
end;

procedure CloseGraph;
{ UkonΦφ grafick² re₧im }
begin
  if IsGraphicsMode then SetMode( OldVMode);    { Obnovφ p∙vodnφ zobr. re₧im }
  IsGraphicsMode := False;
end;

procedure SetColor( Color: byte);
{ Nastavφ barvu pou₧itou pro kreslenφ }
begin
  ActColor := Color;
end;

procedure SetWriteMode( Mode: byte);
{ Nastavφ zapisovacφ re₧im pro kreslenφ }
begin
  WriteMode := Mode;
end;

begin
end.


Pou₧itφ grafickΘ knihovny demonstruje nßsledujφcφ krßtk²
program, kter² navφc vyu₧φvß n∞kterΘ z registr∙ karty VGA
k snadnΘ implementaci vertikßlnφho scrolovßnφ dv∞ma sm∞ry
zßrove≥. VÜimn∞te si, ₧e scrolovßnφ bude stejn∞ rychlΘ na
vÜech poΦφtaΦφch, bez ohledu na jejich rychlost. Je to
zp∙sobeno tφm, ₧e jednotlivΘ animaΦnφ kroky jsou odd∞leny
Φekßnφm na vertikßlnφ zp∞tn² chod, kter² je v tomto
zobrazovacφm re₧imu generovßn s frekvencφ p°ibli₧n∞ 60 Hz.
Program pro svojφ sprßvnou Φinnost pot°ebuje kartu VGA.


Uses
    Sgraph,                     { Pou₧vß jednotku SGraph }
    Crt;                        {               a Crt    }

procedure SetStartAdr( Adr: word); assembler;
{ Procedura nastavujφcφ registry CRTC poΦßteΦnφ adresa index 0ch a 0dh }
asm
        mov     DX, 3dah         { Vstupnφ stavov² registr 1 }
  @wait_retrace:
        in      AL, DX
        and     AL, 8
        jz      @wait_retrace    { ╚ekßnφ na vertikßlnφ zp∞tn² chod }
  @wait_display:
        in      AL, DX
        and     AL, 8
        jnz     @wait_display    { ╚ekßnφ na aktivnφ zobrazovacφ signßl }

        mov     cx, Adr
        mov     dx, 03d4h       { CRTC adresov² registr }
        mov     al, 0ch         { index poΦßteΦnφ adresa - vyÜÜφ byte }
        mov     ah, ch
        out     dx, ax
        inc     al              { index poΦßteΦnφ adresa - ni₧Üφ byte }
        mov     ah, cl          { ni₧Üφ byte adresy }
        out     dx, ax
end;

procedure SetLineComp( Line: word); assembler;
{ Nastavφ registr CRTC porovnßnφ °ßdky vΦetn∞ 9. a 10. bitu }
asm
        mov     DX, 03d4h       { CRTC adresov² registr }
        mov     AL, 18h         { index registru porovnßnφ °ßdky }
        out     DX, AL
        mov     CX, Line
        mov     AL, CL
        inc     DX
        out     DX, AL          { zßpis 8 ni₧Üφch byte Φφsla °ßdky }
        dec     DX
        mov     AL, 07h         { index registru p°eteΦenφ }
        out     DX, AL
        inc     DX
        in      AL, DX          { Φte nastavenφ registru p°eteΦenφ }
        mov     CL, CH
        and     CL, 1
        shl     CL, 4
        and     AL, 11101111b   { sma₧e 9. bit Φφsla °ßdky pro porovnßnφ }
        or      AL, CL          { nastavφ 9. bit }
        out     DX, AL          { zapφÜe registr }
        dec     DX
        mov     AL, 09h         { registr poΦet °ßdek na znak - obsahuje 10. bit }
        out     DX, AL
        inc     DX
        in      AL, DX
        shr     CH, 1
        and     CH, 1
        shl     CH, 6
        and     AL, 10111111b   { smazßnφ starΘ hodnoty 10. bitu }
        or      AL, CH          { novß hodnota 10. bitu }
        out     DX, AL          { zapsßnφ registru }
end;

const
     MaxX = 639;                { Maximßlnφ hodnota sou°adnice x }
     MaxY = 479;                { Maximßlnφ hodnota sou°adnice y }

var
   i: word;                     { PomocnΘ prom∞nnΘ }
   x: word;

begin
  InitGraph;                    { Inicializace grafiky }
  SetWriteMode( XORPut);        { Nastavenφ zapisovacφho zp∙sobu }

  { Nakreslenφ jednoduchΘho obrazce p°es celou obrazovku }
  for x := 0 to MaxX do
    Line( MaxX div 2, MaxY div 2, x, 0);
  for x := 0 to MaxY do
    Line( MaxX div 2, MaxY div 2, MaxX, x);
  for x := MaxX downto 0 do
    Line( MaxX div 2, MaxY div 2, x, MaxY);
  for x := MaxY downto 0 do
    Line( MaxX div 2, MaxY div 2, 0, x);

  { Jednoduchß animace }
  for i := 0 to MaxY div 2 do
  begin
    SetLineComp( i);                    { Scrolovßnφ dol∙ pomocφ porovnßnφ °ßdky }
    SetStartAdr( i* 80);                { Zßrove≥ scrolovßnφ nahor∙ pomocφ poΦßteΦnφ adresy }
  end;

  { Obrßcen² sm∞r animace }
  for i := MaxY div 2 downto 0 do
  begin
    SetLineComp( i);
    SetStartAdr( i* 80);
  end;

  Delay( 300);                  { Malß pauza nakonec }
  SetLineComp( 1023);           { Nastavenφ standardnφ hodnoty }
  CloseGraph;                   { UkonΦenφ grafiky, p°edchozφ zobr. re₧im }
end.


Literatura:

[1]  Kliewer, B.D. - EGA/VGA A programmer's reference guide
     371 stran, McGraw-Hill Publishing Company, 1990

[2]  Äßra, J. - PoΦφtaΦovß grafika - principy a algoritmy
     472 stran, Grada a.s., 1992

[3]  Brown, R. - Interrupt List - freewarovß el. p°φruΦka
     1993

[Obsah]


Copyright © Ji°φ Kosek