Minule sme si ukazali, ako sa da nakreslit nejaka vseobecna ciara.
V praxi sa velmi casto vyskytuju aplikacie, v ktorych potrebujeme
prave vodorovne a zvisle ciary. Linearny interpolator by sa sice
v pohode dal pouzit aj na tento ucel (pretoze zvlada akekolvek ciary),
ale bolo by to asi ako ist s kanonom na vrabca. Urcite sami uznate
ze zdrzovat sa vypoctom kde bude lezat nasledujuci bod ked to uz
v podstate vopred vieme, by sa nam urcite nepacilo. Preto by sme si
mohli napisat dve rutinky, z ktorych jedna by kreslila len vodorovne
a druha len zvisle ciary. Rutinky by boli vysoko optimalizovane na
tento specialny ucel a nevedeli by nic ine. Tym by sme dosiahli
ovela vyssiu rychlost kreslenia ako keby sme vsetky ciary kreslili
klasickym linearnym interpolatorom.
Lenze, to sa lahko povie (napise), ale ako to spravit ? Uz samotny
interpolator je velmi efektivny, ved priamo s adresou a maskou pocita
posunutie pre nasledujuci bod. Da sa to este vobec nejak zefektivnit ?
Spravne tusite, ze keby sa nedalo, tak by som tuto otazku nekladol.
Pametate si este na tu sialenu najrychlejsiu rutinku pre nakreslenie
bodu ktora pozostava z jedinej instrukcie "ld (hl),a" ? Tak teraz vam
ukazem, ze tento sposob kreslenia bodov nie je ani zdaleka najrychlejsi !
Predstavte si, ze chceme nakreslit niekolko bodov vedla seba, ktorych
bity dajme tomu lezia vsetky v jednom bajte vo videoramke. (Uz tusite
kam mierim ?) Potom nam staci spravit logicky sucet masiek tychto bodov,
vlozit ho do registra A, do HL este dame adresu tohto bajtu a zavolame
tu nasu sedemtaktovu rutinku. Maximalny pocet bodov, ktore takto za
sedem taktov mozeme nakreslit, je osem, co vychadza 0.875 taktu na
nakreslenie jedneho bodu ! Nie je to uzasne ?
Pravda, musi ale platit, ze tie body su v jednom bajte a tym
vzhladom na usporiadanie videoramky lezia vodorovne vedla seba.
Co keby sme to skusili nejak vyuzit pri kresleni vodorovnej ciary ?
Tak teda skusme. Nasa rutinka "rovno" na kreslenie vodorovnych ciar
najprv otestuje, ci sa obidva krajne body ciary nachadzaju v jednom
bajte videoramky. Ak ano, vypocita masku pre vsetky body medzi nimi,
a rovno vsetky tieto body jedinou instrukciou nakresli. Adresu tohto
bajtu urci pomocou tabulky "tabbod". V pripade, ze sa krajne body
nenachadzaju v tom istom bajte, vyrobi dve masky pre zakoncenia ciary,
tie aplikuje na bajty s krajnymi bodmi ciary, a na vsetky bajty, ktore
sa nachadzaju medzi bajtami s krajnymi bodmi, aplikuje masku 255.
Pri kresleni zvislej ciary az tolko moznosti na optimalizaciu nemame.
Na zaciatku musime pomocou tabulky "tabbod" urcit adresu a masku pre
prvy bod ciary, potom v slucke kreslime jednotlive body pricom
posun na dalsi bod urobime pomocou uz klasickej rutinky "dole".
Este mozeme preskupit instrukcie a rutinku "dole" priamo vlozit
do slucky (usetrime cas na call a ret).
tabbod | = | #6000 |
hitbod | = | >tabbod |
run | call | mkbod |
ld | a,#01 | |
call | over | |
ld | bc,#00 | |
ld | d,#ff | |
call | rovno | |
ld | bc,#1f00 | |
ld | d,#ff | |
call | rovno | |
ld | bc,#0100 | |
ld | d,#1e | |
call | zvislo | |
ld | bc,#01ff | |
ld | d,#1e | |
call | zvislo | |
ld | bc,#0303 | |
ld | d,#fc | |
call | rovno | |
ld | bc,#1c03 | |
ld | d,#fc | |
call | rovno | |
ld | bc,#0403 | |
ld | d,#1b | |
call | zvislo | |
ld | bc,#04fc | |
ld | d,#1b | |
jp | zvislo | |
over | rrca | |
sbc | a,a | |
and | #18 | |
xor | #b6 | |
ld | (ooset1),a | |
ld | (ooset2),a | |
ld | (ooset3),a | |
ld | (ooset4),a | |
ld | (bodset),a | |
ret | ||
rovno | ld | a,d |
cp | c | |
jr | nc,rov01 | |
ld | d,c | |
ld | c,a | |
rov01 | ld | h,hitbod+2 |
ld | l,c | |
ld | a,(hl) | |
dec | h | |
ld | l,b | |
or | (hl) | |
dec | h | |
ld | h,(hl) | |
ld | l,a | |
ld | a,c | |
and | #f8 | |
ld | e,a | |
ld | a,d | |
and | #f8 | |
cp | e | |
jr | nz,r2byte | |
ld | a,c | |
and | #07 | |
ld | b,a | |
ld | a,#ff | |
jr | z,rov02 | |
rov03 | srl | a |
djnz | rov03 | |
rov02 | ld | c,a |
rov99 | ld | a,d |
and | #07 | |
ld | b,a | |
ld | a,#80 | |
jr | z,rov04 | |
rov05 | scf | |
rra | ||
djnz | rov05 | |
rov04 | and | c |
ooset1 | xor | (hl) |
ld | (hl),a | |
ret | ||
r2byte | sub | e |
rrca | ||
rrca | ||
rrca | ||
ld | e,a | |
ld | a,c | |
and | #07 | |
ld | b,a | |
ld | a,#ff | |
jr | z,ooset2 | |
rov06 | srl | a |
djnz | rov06 | |
ooset2 | xor | (hl) |
ld | (hl),a | |
ld | b,c | |
ld | c,#ff | |
rov40 | inc | l |
dec | e | |
jr | z,rov99 | |
ld | a,c | |
ooset3 | xor | (hl) |
ld | (hl),a | |
jr | rov40 | |
zvislo | ld | a,d |
cp | b | |
jr | nc,zv2 | |
ld | d,b | |
ld | b,a | |
zv2 | ld | a,d |
sub | b | |
ret | c | |
inc | a | |
ld | d,a | |
ld | h,hitbod+3 | |
ld | l,c | |
ld | e,(hl) | |
dec | h | |
ld | a,(hl) | |
dec | h | |
ld | l,b | |
or | (hl) | |
dec | h | |
ld | h,(hl) | |
ld | l,a | |
ld | a,b | |
zvis | cpl | |
and | #07 | |
inc | a | |
ld | b,a | |
zv1 | ld | a,e |
ooset4 | xor | (hl) |
ld | (hl),a | |
inc | h | |
dec | d | |
ret | z | |
djnz | zv1 | |
ld | b,#08 | |
ld | a,#20 | |
add | a,l | |
ld | l,a | |
jr | c,zv1 | |
ld | a,#f8 | |
add | a,h | |
ld | h,a | |
jr | zv1 |
Vstupne parametre do rutiniek "rovno" a "zvislo" su taketo:
V registri BC sa vzdy nachadzaju suradnice jedneho krajneho
bodu ciary (B=Y,C=X) a register D obsahuje suradnicu druheho
bodu. V pripade "rovno" je to X suradnica a pri "zvislo" je to Y.
Ako uz tradicne, rutinka "over" nastavuje sposob vykreslovania
ciary a rutinka "run" je malicky priklad pouzitia tychto rutiniek.
Skuseni optimalizatori urcite zbadaju dalsie moznosti ako este
viac urychlit kreslenie vodorovnych a zvislych ciar. Napriklad
rozvinutie slucky, rozvetvenie jednej univerzalnej casti na
viacero specializovanejsich... Skuste nad tym pouvazovat.
A co vas caka a menimie nabuduce ? Rotacny zemiakoid...
Ale nie, nabuduce si budeme kreslit kruznice.
Vas Busy.