                          - SEPTIC'S DEMOSKOLA -

                                Lektion 10
                                ¯¯¯¯¯¯¯¯¯¯
                        Skriven av Vicious / Septic

                                 3 Dec 93



                                 Inledning
                                 ¯¯¯¯¯¯¯¯¯
Hejsan igen! Ännu en spännande programmeringslektion färdig att läsas! Den
här gången tänkte jag gå igenom hur blitterns mycket intressanta linje-
ritnings funktion fungerar och även visa det med ett programexempel (som
jag brukar göra, givetvis...) där några linjer ritas ut.
  Okej, vi kör väl igång!


                                   Teori
                                   ¯¯¯¯¯
En linje är som bekant en rad med sammanhängande punkter. Den har en start-
punkt och en slutpunkt och med de två koordinaterna kan man räkna fram
linjens lutning i X och Y-led, plus hur många pixlar som behövs för att
representera linjen.
  Detta är precis vad man får göra för att rita en linje med processorn,
och det blir alltså en massa strulande hit och dit med beräkningar och
pixel-sättningar plus att det kräver en massa rastertid vid bara ett fåtal
linjer. PC-coders och C64-coders är tvungna att göra på det här viset, men
Amiga-coders är lyckligt lottade genom den fantastiska lilla blittern som
klarar av linjeritandet mycket smidigt.
  Att rita en linje med blittern kan verka lite kryptiskt och svårt, men
det är faktiskt ganska enkelt när man kan det (är det inte så med allt,
egentligen?) Precis som vanligt, när det gäller blittern, kan processorn
fortsätta att arbeta medan blittern ritar linjen.

Blittern behöver en oktant till att börja med, som beskriver linjens
riktning. Här är en bild över de olika riktningarna som kan förekomma:

          \ 3 | 1 /
           \  |  /
          7 \ | / 6
          ___\|/___
             /|\
          5 / | \ 4
           /  |  \
          / 2 | 0 \

Numren som står inom de olika fälten anger oktant-numret som skall ges till
blittern senare. (De diagonala strecken ska bilda 45° vinkel med både den
vertikala och den horisontella linjen, givetvis. Det är bara inte så lätt
att rita det i textmode.)
  Sedan måste vi räkna ut ett par variabler, DX och DY, som kan sägas vara
linjens koordinater omräknat till oktant 6 (vilket är fält 0, om vi gått
efter en vanlig 360° enhetscirkel).

  DX är maxvärdet av (X2-X1) och (Y2-Y1).
  DY är minvärdet av (X2-X1) och (Y2-Y1).

X1 och Y1 är alltså linjens startkoordinat, och X2 samt Y2 är slut-
koordinaten.

Det var allt teoretiskt sett...Låt oss gå vidare med vad de olika registren
ska innehålla!


                                 Register
                                 ¯¯¯¯¯¯¯¯
Vid linjeritning används i princip samma register som vid vanlig kopiering
med blittern. Skillnaden är att genom att sätta en speciell LINEDRAW-bit i
BLTCON1 ($DFF042) så får de flesta av registren en helt annan innebörd.
  Till att börja med ska man alltid sätta BLTADAT ($DFF074) till $8000. I
BLTBDAT ($DFF072) ska man skriva in linjens mask. Denna mask är 16 bitar
stor, alltså ett word, och den anger hur linjen ska se ut. Om alla bitar är
satta och wordet är $FFFF så får vi en solid linje utan hål, och det är
oftast det man vill ha.
  Vidare måste man ställa BLTAxWM ($DFF044) till $FFFFFFFF för att inte
maska bort något på linjen.
  Sedan ska man använda sig av DX och DY och föra in 4*(DX-DY) i BLTAMOD
($DFF064), 4*DY i BLTBMOD ($DFF062) och till sist (4*DY)-(2*DX) i BLTAPT
($DFF074).
  I BLTCMOD ($DFF060) och BLTDMOD ($DFF066) skall bredden på skärmen i
bytes skrivas in.
  BLTCPT ($DFF048) och BLTDPT ($DFF054) ska innehålla linjens första pixels
position i ett word. Med det menas egentligen bara de lägsta fyra bitarna i
X-koordinaten. Om X t.ex är 134, %10000110 binärt, ger siffran 6 som är de
fyra lägsta bitarna %0110.

  BLTCON0 ska se ut följer:

BIT#   BLTCON0   Beskrivning
----   -------   -----------
 15    START3    I bit 12-15 ska de fyra lägsta bitarna i första
 14    START2    X-koordinaten skrivas in.
 13    START1
 12    START0
 11      1       Den här biten är SRCA-biten egentligen. Den ska alltid
                 vara 1 när man ritar linjer.
 10      0       SRCB ska alltid vara 0
 09      1       SRCC ska alltid vara 1
 08      1       DEST ska också alltid vara 1!
 07     LF7      Minterm bit
 06     LF6        "      "
 05     LF5        "      "
 04     LF4        "      "
 03     LF3        "      "
 02     LF2        "      "
 01     LF1        "      "
 00     LF0        "      "

Mintermen brukar oftast vara AB+aC, dvs A och B eller icke A och C. Detta
gör att en helt vanlig linje ritas ut utan några modifikationer. Om
mintermen ABc+aC väljs, alltså A och B och icke C eller icke A och C,
kommer en EOR-linje ritas ut. EOR betyder att linjen inverteras när den
skrivs över redan existerande pixlar. Detta kan vara användbart om man vill
plocka bort linjer snabbt. Då behöver man alltså bara rita ut linjen ännu
en gång på samma ställe och så plockas ju linjen automatiskt bort.
  EOR-metoden ska vi använda när vi gör fyllda vektorer. Där krävs EOR för
att ytorna ska färgläggas rätt, men det kommer i någon lektion längre fram.

Okej, i BLTCON1 måste vi skriva in följande saker:

BIT#   BLTCON1   Beskrivning
----   -------   -----------
 15    TEXTURE3  Start bit i ett word för linjens mask.
 14    TEXTURE2
 13    TEXTURE1
 12    TEXTURE0
 11       0      Reserverade för nya funktioner
 10       0
 09       0
 08       0
 07       0
 06      SIGN    Tecken-flagga. Ska sättas om BLTAPT är negativt
 05       0
 04      SUD     De här tre bitarna (SUD, SUL och AUL) anger oktant-numret
 03      SUL
 02      AUL
 01      SING    Endast en pixel per rad. Används vid areafyllning.
 00      LINE    Ska sättas till 1 vid linjeritning.

Allra sist (som vanligt) ska man skriva in linjens storlek i BLTSIZE
($DFF058) och det fungerar så att blithöjden (bit 6-15) är linjens längd
och blitbredden är alltid 2.
  Sådär, nu ska vi titta på hur programexemplet är konstruerat!


                              Programexemplet
                              ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
Programmet jag gjort den här gången visar hur en linjerutin fungerar, och
det ritar upp två enkla figurer för att demonstrera att rutinen funkar.
  Om vi tittar på sourcen så ser vi att den inte bjuder på några direkta
nyheter fram till subrutinen DRAW.
  Där lägger jag in de värden som krävs av linjeritnings rutinen, dvs
skärmens början, dess bredd i bytes och linjens mask eller textur. Sen
skriver jag in linjens start X, start Y och slut X, slut Y i D0, D1, D2 och
D3. Efter det hoppar jag till rutinen DrawLine som ritar ut linjen.
  Detta upprepar jag tre gånger för att rita triangelns tre sidor.
  Sedan ritar jag ut fyrhörningens sidor på ett smartare sätt, som går ut
på att jag läser från en tabell istället och ritar varje linje så att den
hänger ihop med den förra.
  Jag gjorde de olika objekten på dessa sätt bara för att ni skulle förstå
hur linjerutinen fungerar, och sen för att se en enklare metod att rita
linjer på.
  Om vi vandrar vidare ner i sourcen så ser vi snart rutinen DrawLine.
  I början av den rutinen kollar vi så att inte linjen börjar och slutar på
samma punkt, för i så fall kan vi inte rita ut den, och då hoppar vi
istället ut.
  Sedan räknar vi ut, precis som vid vanlig blitteranvändning, var första
Y-koordinaten hamnar i för byte-rad när den multiplicerats med
skärmbredden. Vi tar även fram ett delta Y värde och ett delta X värde som
sedan används både till att ta fram rätt oktant och till variablerna DX och
DY.
  Oktanten tas fram på ett ganska smart sätt genom att använda sig av
SUB-instruktionens sättning av X-flaggan när resultatet blir negativt. På
så sätt kan man genom tre subtraktioner och tre ROXL-instruktioner (som
skiftar in X-flaggan i registrets lägsta bit) få fram en trebitars
oktant-kombination som pekar på ett visst värde i en oktant-tabell där rätt
oktant-värde finns placerat som en byte.
  Detta är mycket smidigare än att jämföra delta-värdena och hoppa hit och
dit för att sätta olika värden på oktanten.

Efter det tar vi reda på vilket av våra delta-värden som är störst,
eftersom DX ska innehålla det största talet.
  Sedan sätter jag alla framräknade värden i blitter-registren. Notera att
jag använder mintermen AB+aC för att rita en vanlig, OR-linje utan
modifikationer.
  Det var nog allt, tror jag. Om ni inte förstår något så kan ni alltid
fråga mig, så ska jag förklara så gott jag kan.
  I nästa lektion ska jag förklara hur tredimensionell vektor-rotering går
till! Men tills dess, håll tillgodo med linjeritningen!
