Viete, co je to linearny interpolator ? Pekne odborne to znie, vsak ?
(Pre niektorych mozno aj odporne...) A pritom sa nejedna o nic ineho,
ako spojenie dvoch bodov "vzdusnou" ciarou. Pokial mate na papieri
zadane dva body (A a B), po ruke pravitko a nejake zapisovacie
zariadenie (to ako ceruzku), tak nie je ziadny problem - prelozite
pravitko cez obidva body a nakreslite ciaru.
Avsak tato jednoduchost razom pominie, ked to chcete naprogramovat do
pocitaca. V tom pripade ciara medzi bodmi A a B vznikne tak, ze
vykreslite postupne vsetky body nachadzajuce sa na spojnici bodov A a B.
Ale ako vypocitat, ktore body to vlastne mame vykreslit ?
V romke ZX Spektra, medzi obsluznymi rutinkami prikazu DRAW, sa
nachadza takyto linearny interpolator, ktory dokaze vypocitat
suradnice bodov, ktore treba vykreslit na spojnici dvoch zadanych
bodov. Rutinka tohto interpolatora sa nachadza na adrese #24B7 a
samotny vypocet suradnic bodov robi pomerne efektivne, takze keby sme
ju doplnili nasou rutinkou "bod" z minulej casti a spravili nejake
kozmeticke upravy pri odovzdavani parametrov, ziskali by sme velmi
rychlu a efektivnu rutinku na kreslenie vseobecnych ciar. A problem
mame vyrieseny a mozeme to pre dnesok zabalit...
Dufam, ze ste moje predchadzajuce slova nezobrali celkom vazne. Teda
nie ze by neboli pravdive, to nie, ale... Spravne tusite, ze este ani
zdaleka nie je koniec tejto casti. Skusim vam do hlavy nasadit takeho
malickeho chrobaka. Vo vyssie spominanej rutinke sa vzdy najprv
pocitaju suradnice bodu, a potom z tychto suradnic sa pocita adresa
vo videoramke a maska bodu a nakoniec sa podla tejto adresy a masky
vykresli samotny bod. Nedalo by sa ten linearny interpolator upravit
nejak tak, aby nepocital suradnice bodov, ale priamo adresu a masku ?
Potom by sme mohli vyuzit to minule spomenute sialene 7 taktove
vykreslenie bodu jedinou instrukciou...
Podme si situaciu trosku rozanalyzovat. Interpolator pocita jednotlive
body tak, ze v kazdom kroku svojej cinnosti vezme bod vypocitany
v minulom kroku a urcitymi matematickymi postupmi urci v akej polohe
voci nemu sa nachadza dalsi vykreslovany bod - ci je nad nim, pod nim,
vedla neho vpravo, vlavo, pripadne kombinacia tychto poloh (vpravo nad
nim, vlavo pod nim, atd...). Dajme tomu, ze pozname adresu a masku pre
bod vypocitany v minulom kroku a ideme urcovat adresu a masku pre dalsi
bod na zaklade informacii ktore nam poskytne interpolator.
Ak sa novy bod nachadza sikmo od stareho, mozno vypocet jeho polohy
rozlozit na dva vypocty typu hore-dole, nalavo-napravo. Vypocet v
pripade ak sa novy bod nachadza presne pod povodnym uz mame hotovy -
je to presne nasa uz dobre znama rutinka "dole". Vypocet do strany
(nalavo alebo napravo) sa spravi jednoducho rotaciou masky pre bajt a
ak nahodou rotacia "pretecie" (nahoda je blbec) tak sa este adresa
zmeni o jednotku. Nech HL je adresa a A je maska:
left | rlca | right | rrca | ||
jr | nc,llll | jr | nc,rrrr | ||
dec | l | inc | l | ||
llll | ... | rrrr | ... |
Ale co v pripade, ked je novy bod nad povodnym ? Urcite by nebol
problem napisat rutinku "hore" ktora by bola v podstate analogicka s
rutinou "dole", ale ja vam ponukam ine, ovela zaujimavejsie riesenie:
akonahle by sa vyskytla potreba pri kresleni ciary pouzit rutinku
"hore", tak jednoducho navzajom vymenime suradnice oboch krajnych
bodov a namiesto "hore" budeme potrebovat len "dole". Logicky sme
spravili to, ze problem posunu adresy hore sme previedli na problem
posunu adresy dole. Fyzicky sme vlastne spravili akurat to, ze
interpolator bude kreslit ciaru vzdy zhora nadol.
Nasa rutinka interpolatora sa vola "line" a na vstupe ocakava
suradnice dvoch bodov v registroch BC a DE: prvy bod X=C,Y=B a druhy
X=E,Y=D. Rutinka si najprv prehodi suradnice bodov tak, aby ciaru
kreslila vzdy zhora nadol, potom si zisti, ci bude kreslit ciaru
zlava doprava alebo zprava dolava a podla toho si nastavi rotaciu
masky a pripadny inkrement/dekrement adresy. Potom si podla
predpocitanej tabulky z minulej casti vypocita adresu a masku prveho
vykreslovaneho bodu, este sa rozhodne ci sa bude viackrat posuvat do
strany alebo dole (ludsky povedane, ci ciara bude "vodorovnejsia"
alebo "zvislejsia") a nakoniec sa priamo vrhne na vypocet a
vykreslovanie vsetkych bodov leziacich na spojnici medzi dvomi
zadanymi bodmi na vstupe.
Ako obvykle, rutinka "run" ukazuje priklad pouzitia interpolatora a
rutinka "over" urcuje sposob vykreslovania ciary (OVER 0 alebo OVER 1).
tabbod | = | #6000 |
run | call | mkbod |
ld | bc,#00 | |
ld | de,#bfff | |
call | line | |
ld | bc,#1525 | |
ld | de,#2343 | |
call | line | |
ld | bc,#8142 | |
ld | de,#4767 | |
jp | line | |
mkbod | ... | (ako minule) |
dole | ... | (ako minule) |
over | rrca | |
sbc | a,a | |
and | #18 | |
xor | #b6 | |
ld | (lnov1),a | |
ld | (lnov2),a | |
ld | (bodset),a | |
ret | ||
line | ld | a,d |
cp | b | |
jr | nc,lnxch | |
ld | d,b | |
ld | b,a | |
ld | a,e | |
ld | e,c | |
ld | c,a | |
lnxch | ld | a,c |
cp | e | |
sbc | a,a | |
and | #08 | |
ld | l,#2d | |
jr | z,#01 | |
dec | l | |
inc | a | |
ld | (rot1+1),a | |
ld | (rot2+1),a | |
ld | a,l | |
ld | (deci1),a | |
ld | (deci2),a | |
ld | a,d | |
sub | b | |
ld | d,a | |
ld | a,e | |
sub | c | |
ld | e,a | |
jr | nc,#03 | |
neg | ||
ld | e,a | |
hitab | = | >tabbod |
lnbod | ld | h,hitab+3 |
ld | l,c | |
ld | c,(hl) | |
dec | h | |
ld | a,(hl) | |
dec | h | |
ld | l,b | |
or | (hl) | |
dec | h | |
ld | h,(hl) | |
ld | l,a | |
ld | a,e | |
cp | d | |
jr | nc,lnaaa | |
ld | b,d | |
inc | b | |
ld | a,e | |
sub | d | |
ld | e,a | |
xor | a | |
xor | d | |
rra | ||
lnn1 | ex | af,af |
ld | a,c | |
lnov1 | xor | (hl) |
ld | (hl),a | |
inc | h | |
ld | a,h | |
and | #07 | |
jr | z,dolu1 | |
hore1 | ex | af,af |
add | a,e | |
jr | nc,ln11 | |
rot1 | rrc | c |
jr | c,deci1 | |
djnz | lnn1 | |
ret | ||
deci1 | dec | l |
djnz | lnn1 | |
ret | ||
ln11 | add | a,d |
djnz | lnn1 | |
ret | ||
dolu1 | ld | a,#20 |
add | a,l | |
ld | l,a | |
jr | c,hore1 | |
ld | a,#f8 | |
add | a,h | |
ld | h,a | |
jp | hore1 | |
lnaaa | ld | b,e |
inc | b | |
ld | a,e | |
sub | d | |
ld | d,a | |
xor | a | |
xor | e | |
rra | ||
ex | af,af | |
jr | hore2 | |
lnn2 | ex | af,af |
inc | h | |
ld | a,h | |
and | #07 | |
jr | z,dole2 | |
hore2 | ld | a,c |
lnov2 | xor | (hl) |
ld | (hl),a | |
rot2 | rrc | c |
jr | c,deci2 | |
ex | af,af | |
sub | d | |
jr | c,ln22 | |
djnz | lnn2 | |
ret | ||
deci2 | dec | l |
ex | af,af | |
sub | d | |
jr | c,ln22 | |
djnz | lnn2 | |
ret | ||
ln22 | add | a,e |
ex | af,af | |
djnz | hore2 | |
ret | ||
dole2 | ld | a,#20 |
add | a,l | |
ld | l,a | |
jr | c,hore2 | |
ld | a,#f8 | |
add | a,h | |
ld | h,a | |
jp | hore2 |
Nabuduce si ukazeme, ako nakreslit bod rychlejsie ako za jeden jediny takt hodin procesora !
Vas Busy.