                          - SEPTIC'S DEMOSKOLA -

                                 Lektion 8
                                 ¯¯¯¯¯¯¯¯¯
                        Skriven av Vicious / Septic

                                 10 Aug 93



                                 Inledning
                                 ¯¯¯¯¯¯¯¯¯
Först av allt, ursäkta att den här delen av skolan blev några dagar
försenad. Jag hade helt enkelt inte tid att göra den förrän nu.
nu kan vi traska vidare i Amigans hårdvara och - efter att ha
lärt oss att scrolla med blittern - kika på Blitter OBjectS, så kallade
BOBS.


                                   Teori
                                   ¯¯¯¯¯
Som jag sa förra gången, så kan man med blittern kopiera data från ett
ställe till ett annat. Genom diverse manipulationer kan man då få fram
bobs, som är objekt liknande spritar, fast med nästan obegränsad bredd och
höjd, plus att de kan ha fler färger och inte är begränsade till antal.
  När man kopierar med blittern specificerar man som bekant ett fyrkantigt
fält som skall flyttas. En bob brukar dock inte vara ett sånt exakt,
fyrkantigt fält, utan kanske är runt eller mångformat, som tex en liten
gubbe. Det är då man ska plocka fram masken (som fiskaren sa :-) och vid
kopieringen maska boben så att bakgrunden lyser igenom där objektet inte
har någon grafik. På det sättet kan ett runt objekt flyta runt på skärmen
utan en svart fyrkant runt om sig.
  En mask är helt enkelt en 1-bitplansversion av boben där alla bitplanen
finns lagrade (?!?!) genom logisk OR. Hmmmm, kanske inte så bra
förklaring...Om vi säger att vi har en 4-bitplansbob som vi vill göra en
mask till och en rad i den 16 pixlar breda boben ser ut så här:

   %0101110110101110   ; Första bitplanet
   %1001000010000011   ; Andra bitplanet
   %0000010110100101   ; Tredje shitplanet
   %1001010111100000   ; Fjärde bitplanet

Då kommer masken att se ut så här:

   %1101110111101111   ; Mask

Som ni ser så (och på det sättet funkar ju också OR) är masken 0 (noll)
ENDAST när ALLA bitplanen är noll. Och NÄR är alla bitplanen NOLL? Jo! När
färg 0 ska visas i boben, och färg noll brukar alltid vara transparent
vilket betyder att när masken är noll så ska bakgrunden synas igenom.
  Vi kan alltså utan större problem tänka ut en minterm som passar.
Blittern ska läsa från bobgrafiken när masken är 1, och läsa från
bakgrunden (så att den syns igenom boben) när masken är 0. Om vi använder
alla tre källor i blittern så kan vi låta den första peka på masken, den
andra på boben och den tredje på bakgrundsgrafiken.
  Vår minterm ser då ut så här:

   AB + aC   (Eller (A&B)!(NA&C))

Detta läser vi som A and B or not A and C, vilket betyder att blittern ska
läsa från källa B om A är 1, och från källa C om A är 0. Det senare
uttrycket ((A&B)!(NA&C)) kan sättas in precis som det är i programmet,
eftersom jag redan har fördefinerade värden för mintermarna och det gör det
hela mycket lättare att handskas med. (Titta i slutet på programexemplet så
ser du en massa konstiga siffror...DET är mina fördefinerade mintermar, om
du inte visste det!)
  Så långt, allt väl, så vi kan hoppa vidare på hur shiftningen ska gå till
när man flyttar bobs.
  I förra lektionen gick jag igenom varför shiftningen fanns, och för den
som inte minns, kan jag tala om att den används för att flytta data till de
pixlar som ligger mellan WORD-kanterna, alltså mellan var 16:de pixel. Jag
använde också shiftningen för att scrolla texten åt sidan.
  Shiftning vid bobhantering fixar alltså så att man kan placera sin bob på
ojämna pixlar som 11, 75 eller 120 (som inte ligger på jämn 16-pixel-adress
alltså) istället för bara 16, 32, 48, 64 osv...Det är ju förträffligt bra,
eller hur?!
  Så, hur puttar man ut sin lilla fina gubbe på en speciell koordinat nu
då? - Jo, om vi säger att vi ska sätta boben på X-koordinat 57, så måste vi
först ta reda på vad vi ska ha för shiftvärde, alltså hur långt in på
wordet som boben sitter.
  Detta kan man göra genom att dividera värdet med 16, och sedan kika på
divisionsresten i det höga wordet. Så rekommenderar många att man gör, men
jag skrattar blott åt dem, ty jag vet bättre vägar att färdas :-) (hmmm,
sitter visst och blir poetisk här....grrmhgfmhf....) En division tar MÅNGA
cykler att utföra, och vi vill ju inte ha slöa rutiner i onödan, så
istället plockar vi helt enkelt bara ut de 4 lägsta bitarna, som på talet
57 (binärt %00111001) är %1001. Decimalt är %1001 9, så 9 är alltså
shift-talet! Magiskt eller hur?!
  Sedan shiftar vi vårt 57 åt höger 4 steg, vilket är samma sak som att
dividera med 16 (fast snabbare) och då vet vi i vilket word boben finns i.
Vi multiplicerar då med 2 för att få bytevärdet vi ska addera till
skärmpekaren och så är vi färdiga!
  Ja, svårare är det inte, men man måste komma ihåg följande:

 * Shiftningen sker alltid åt HÖGER, om man inte befinner sig i DESCending
mode, och det gör ni inte än, för det kommer när jag tar upp area-fyllning!

 * Grafiken shiftas RUNT! Så bobgrafik som shiftas 8 steg åt höger kommer
in på bobens högerkant igen och det ser inte alls snyggt ut! Därför: Blitta
alltid ett word extra, med BLTAxWM ($dff044) som maskar bort grafiken där,
så att genomskinlig data shiftas in från höger istället!

En användning man också kan ha blittern till är att rensa areor, tex en hel
skärm. Detta är mycket bra om man tex gör en effekt med processorn, för då
kan blittern rensa en separat skärm medan man ritar sin effekt med
processorn samtidigt på en annan skärm. Det sparar man ganska mycket tid
på.
  För att rensa med blittern behöver man inte kopiera svart bakgrund eller
något sånt, utan helt enkelt bara strunta i källorna. Man använder alltså
BARA destinationen, och vips! så RENSAR blittern, eftersom den inte har
något speciellt, mer än nollor, att skriva med! Och mintermen skall
givetvis också vara noll...


                                 Register
                                 ¯¯¯¯¯¯¯¯
Inte mycket nytt i registerväg den här gången. Förutom att vi måste använda
oss av BLTCON1 nu också, när vi använder fler källor. (Titta i förra
lektionen om ni inte minns dess uppställning.) Vi för helt enkelt in samma
shiftvärde i BLTCON1 som i BLTCON0, för att bobgrafiken ska shiftas också,
och inte bara masken, vilket bara leder till fel.
  BLTAFWM ($dff044) och BLTALWM ($dff046) är blitterns maskregister som
kommer till användning när man jobbar med bobs. BLTAFWM (BLiTter source A
First Word Mask) och BLTALWM (BLiTter source A Last Word Mask) brukar jag
beteckna som BLTAxWM istället, och adressera det som ett helt longword, där
höga wordet är First Word Masken och låga wordet är Last Word Masken. Att
maska bort görs med logisk AND, och för att tex maska bort de sexton sista
pixlarna på boben (när vi har blittat ett word för mycket, för att kunna
shifta utan buggar, till exempel) skickar man bara #$ffff0000 till BLTAxWM,
så behandlas inte de 16 sista bitarna på varje rad.
  Man kan även använda maskning om man vill kopiera saker som inte ligger
på jämna words. Kanske ett grafisk block som börjar på pixel 18 i och
slutar på pixel 125 i x-led. Då blittar man helt enkelt från pixel 16 (som
ju är jämnt) till pixel 128 (också jämnt :-D ), och maskar bort de två
pixlarna i början och de tre i slutet. Enkelt, eller hur?


                              Programexemplet
                              ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
Något "Unlimited Bobs"-rekord blir det inte den här gången, utan endast 20
stycken små 16*16 pixels bollar som åker på skärmen. Jag säger åker,
eftersom de inte glider fram på en sinuskurva...Det är nämligen UTMANINGEN!
Yippi! Läs mera längre ner!
  Rutinen är alltså inte särskilt optimerad, men den visar hur man använder
bobs (och de är ju i FYRA bitplan, vilket är ganska mycket att hålla på och
kopiera för den stackars lille blittern), och det är ju huvudsaken.
  Jag har också (för första gången i här i demoskolan) använt mig utav
dubbelbuffring! Med dubbelbuffring menas att man har två istället för en
skärm, och medan man VISAR den ena så RITAR man på den andra. När man så
ritat färdigt på RITA-SKÄRMEN, så byter man dem helt enkelt, så att det man
ritat kommer fram! Med den här metoden undviker man dumma flimmer-buggar på
ett trevligt sätt! Man kan då även göra rutiner som inte flyter fram i 50
frames per sekund, men de blir ju lite hackigare då...
  Okej, ska vi titta på vad programmet sysslar med?
  Som alltid gör vi det vanliga i början, initialiserar, sätter vår DMA och
bitplanspekare...Men, efter det kommer en rutin som heter CreateMask! Den
gör precis vad man kan tänka sig, nämligen skapar en mask av vår boll-bob.
Som ni ser i den rutinen, så stegar jag i tur och ordning genom alla fyra
bitplanen och ORar dem på masken. Inga svårigheter alls...
  Sen hoppar jag till en rutin som heter InitCoords. Vad den gör är att
sätta upp koordinater för alla bollarna, samt införa dess riktning i X och
Y, i en speciell tabell som vi kan läsa av sedan när vi puttar ut bobsen
(eller heter det bobarna? Eller bobsingarna? :-D)
  Sedan hoppar vi raskt vidare till MAIN, där jag först syncar, som alltid,
och så hoppar jag till SwapPages, som helt enkelt sköter om
dubbelbuffringen...Den flippar fram skärmen vi senast ritade på och låter
den som senast visades bli den nya "rit-skärmen".
  Nästa rutin är ShowBobs. Vi hoppar ner och tittar vad den gör...
  Först nollställer vi D0 och D1 för att det inte ska inträffa konstiga
buggar när vi jobbar med words längre ner. Sen hämtar vi adressen till
"rit-skärmen", alltså the DrawPage! Vi pekar också på ballen - eh, ooops...
sorry... - alltså, på the ball, som är bob-bollen och på masken. Varför vi
gör detta så tidigt är för att slippa göra det tjugo gånger inne i bob-
puttnings-loopen och alltså spara några värdefulla rasterrader.
  Först rensar vi de gamla bollarna i en liten rutin som läser
koordinaterna från vår lilla tabell i tur och ordning och sedan hoppar till
ClearBob-rutinen.
  I ClearBob-rutinen händer följande...
  Först subtraherar jag 8 från D1, alltså Y-koordinaten, eftersom jag vill
rensa runt om bollen och behöver lite extra kanter. Sedan multiplicerar jag
det med skärmbredden i bytes (kan göras snabbare, men det får ni lista ut
själva :-) Jag lär ut grunden, sen får ni lära er fortsättningen med
tiden...) Jag lägger på värdet på skärmpekaren så att vi kommer ner till
rätt Y-rad. Sen subtraherar jag från X-koordinaten också, på samma sätt, 8
pixlar, skiftar det åt höger fyra steg (=division med 16) och multiplicerar
med 2, genom aritmetisk skift åt vänster ett steg. Också detta värde lägger
jag på skärmpekaren.
  Därefter för jag in BLTCON-värdet, som ju bara är DEST när man ska rensa
med blittern, i D0, sätter antal bitplan, för loopen, i D1, och väntar på
att blittern ska bli färdig.
  Sen för jag in BLTCON-värdet i - hör och häpna! - BLTCON0!!! Wow! Och
efter det sätter vi masken #$ffffffff, för vi behöver inte maska bort något
nu, och så ställer jag in BLTDPT och sätter korrekt modulo. Storleken
sätter jag till 48 pixlar bred, vilket alltså blir 8 extra på högerkanten
när vi flyttade 8 steg åt vänster tidigare, och 32 pixlar hög, vilket blir
samma sak.
  Sen adderar jag till bitplans-pekaren så att vi kommer till nästa bitplan
och så loopar jag tillbaka.
  Sådär...Tillbaks till ShowBobs-rutinen, där jag direkt hoppar vidare till
MoveBobs. MoveBobs gör kort och gott detta:
  Hämtar X och Y-koordinat i tur och ordning, ökar dem med deras
ADD-värden, kollar om de är utanför en viss skärmgräns och negerar i så
fall ADD-värdet så att den byter riktning.
  Återigen i ShowBobs-rutinen...Här kommer en kodsnutt som liknar
ClearBob-grejen tidigare, fast den här puttar ut bollarna istället för att
plocka bort dem.
  I rutinen PutBob multiplicerar jag först Y-koordinaten (precis som i
ClearBob-rutinen) och adderar den till skärmpekaren.
  Sen för jag in en krånglig minterm i D7, som säger: "Använd källa A, B
och C, plus destination D. Mintermen ska vara (B&A)!(C&NA), alltså läs från
källa B om A är 1, och från källa C om A är 0."
  Jag kör en swap på D7 sen, för att kränga upp talet i höga wordet
(eftersom jag ska skriva till BLTCON som ett helt longword) och så hämtar
jag låga byten av X-koordinaten. Jag ANDar med 15 eftersom vi bara behöver
de 4 lägsta bitarna.
  Sen delar jag med 16 och gångar med 2 för att få fram rätt bytevärde.
Detta värde adderar jag till skärmpekaren.
  Sedan skiftar jag runt D6 fyra steg åt höger, så att skiftvärdet vi
plockade fram innan hamnar på rätt position och så ORar jag på det på
BLTCON-värdet vi har i D7. Sen swappar jag D6 och ORar på det igen,
eftersom vi ska skifta källa B också!
  Sen ställer jag in skärmmodulon och bobmodulon. Hmmm, minus 2?! Ja,
eftersom boben bara är 16 pixlar bred, och vi blittar 32 pixlar (för att
kunna shifta rätt, om du kommer ihåg?) så modulon måste alltså vara negativ
för att hoppa tillbaka till rätt rad...
  .BltWt väntar på att blittern ska bli färdig, och när vi får klartecken
skriver jag in D7 i BLTCON, sätter masken till #$ffff0000 (som vi kom
överens om ovan, för att shiftningen ska gå bra) och ställer in en massa
pekare på både masken, boben och skärmen.
  Efter det ställer jag in rätt modulo för A, B, C och D och slutligen
startar vi blittern genom att ange storlek på vårt blit-fält. Två words,
alltså 32 pixlar, och 16 högt.
  Sen adderar jag bitplansstorleken till skärmpekaren, så att vi hamnar på
exakt samma ställe fast i nästa bitplan, och gör samma sak med boben.
Notera att vi INTE ska addera något till maskpekaren, eftersom den bara är
i ett bitplan, och fungerar för alla bitplan i boben.
  Sådär, det var det mesta om det mesta...Hoppas verkligen att ni hänger
med och att ni förstår.
  Notera att jag inkluderat en liten rutin jag fått från Leviticus också
(hej, hej!), som gör en Setclock Load, alltså ställer in systemklockan rätt.
Detta är bra att ha, eftersom demos - när man stänger av multitasking och
gör allmänt stygga saker - gör så att klockan går fel. Tack för det,
Leviticus!

Det var allt om programmet den här gången. För att enklare följa det hela
kan ni ju printa ut den här textfilen och läsa den samtidigt som ni tittar
på programmet, eller så kan ni ladda in det i någon texteditor som klarar
av flera filer åt gången i olika fönster (typ Cygnus Ed, yeah!) som jag
själv använder.

