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