                          - SEPTIC'S DEMOSKOLA -

                                Lektion 12
                                
                        Skriven av Vicious / Septic

                                 4 Feb 94



                                 Inledning
                                 
Jag hoppas verkligen ni fljde med och frstod allt i frra lektionen, ven
om det var lite krngligt. Den hr gngen ska vi nmligen fortstta med
vektorobjekt, men lra oss hur man fyller dem! Med andra ord, fyllda
vektorer blir en barnlek efter att ni lst genom den hr delen av
Demoskolan!


                                   Teori
                                   
Nu ska vi ntligen ta upp blitterns skojiga fill-funktion, som kan anvndas
till mycket trevliga effekter. Vi ska dock endast fylla vra vektorobjekt
med den, och det r ju fullt tillrckligt!
  En fyllning gr egentligen till s att man fr varje rasterrad tar reda
p startpixeln fr fyllningen och slutpixeln, och sedan drar man ett streck
mellan de tv pixlarna. Detta fr man sedan gra fr alla 256 (eller vad
man nu har fr skrmhjd) raderna p bilden fr att ett stort vektorobjekt
ska fyllas.
  Anvnder vi istllet blitterns fyllning s skter blittern helt och
hllet det hr trkiga (och rasterkrvande) arbetet. Vi mste dock gra p
samma stt ungefr, dvs stta en start och en slutpunkt. Blittern fungerar
nmligen s i fillmode, att den letar tills den hittar en punkt, slr p
fyllningen och fyller tills den hittar nsta punkt. Nr man ritar vanliga
linjer s kan det ju dessvrre hamna fler n en pixel per rad om linjen
t.ex. bara r tre pixlar i Y-led men 50 i X-led.
  Som tur r finns det till ens hjlp en bra funktion nr man ritar linjer,
som heter SING. Stter man SING-biten nr man ritar linjen s kommer det
bara att hamna en pixel per rad, och detta r ju perfekt fr fyllningen.
  Fr att fyllningen ska bli alldeles mste vi ocks se till att vi ritar
ut alla linjer t samma vertikala hll, dvs alltid uppifrn och ner eller
tvrtom. Dessutom mste vi gra en EOR med linjens frsta pixel fr att
undvika att spetsiga hrn som bara har en pixel slr p fyllningen och
bildar fula "trdar" ut mot kanten frn vectorfacets hrn.
  Allts, frst och frmst mste vi ndra lite i linjeritnings rutinen, men
sedan r det bara att fylla p!
  Nr man sysslar med konvexa vektorobjekt, dvs sdana objekt dr en synlig
polygon ALDRIG verlappar en annan synlig polygon (som tex en kub), s kan
man anvnda den smidiga metoden att rita ut alla polygoner p en gng och
sedan fylla hela skrmsidan. Ska man ha inkonvexa objekt, som tex en torus
(ser ut som ett tjockt O), s fr man sortera alla faces och sedan rita ut
dem med brjan p det lngs bak, fylla varje fr sig och dessutom kopiera
dem p bilden. Man kan anvnda sig av en kombinerad konvex/inkonvex rutin
som klarar att hantera inkonvexa objekt uppbyggda av konvexa. Jag kommer
dock inte g in p inkonvexa vektorer i den hr Demokursen, utan endast
konvexa.
  Som jag sa, s kan man allts rita ut alla polygoner p en gng och sedan
fylla objektet med blittern. Detta r ju vldigt smidigt, men medfr
samtidigt ett problem...De polygoner som INTE r synliga mste plockas bort
p ngot stt, annars kommer ju blittern att fylla dem ocks, och d kommer
objektet att se mycket konstigt ut.
  S, vi mste allts p ngot stt knna av nr ett face r vnt bort
ifrn oss, och det kan man gra genom att ta fram polygonens normal.
Normalen r den vektor som pekar rakt ut ifrn ett face, och denna blir
(vanligtvis) negativ nr ytan r vnd bort frn oss. Att ta fram normalen
fr en yta r inte s vrst svrt.
  Frst och frmst behver man polygonens tre frsta koordinater. Det r
viktigt att koordinaterna ligger medurs runt objektet, annars kan normalen
f motsatt betydelse, s att den r negativ nr den r synlig. Hur som
helst r det inte hela vrlden, eftersom det d r ltt att vnda p
koordinaterna, s att tex koordinatfljden 0,1,2,3 blir 3,2,1,0. Detta
kommer ni skerligen stta p nr ni gr egna objekt.
  Vi gr berkningen EFTER att vi konverterat 3d till 2d. Genom att
subtrahera koordinat 1 och sedan koordinat 2 med koordinat 3 s fr man ut
hur polygonen r vnd. Genom fljande formel fr vi sedan fram normalens
vrde:

   Vx1=X1-X3
   Vy1=Y1-Y3
   Vx2=X2-X3
   Vy2=Y2-Y3

   Normal=(Vx1*Vx2)-(Vy1*Vy2)

Om denna normal r negativ s r polygonen allts osynlig. Lt oss g
vidare...


                                 Register
                                 
Registren som anvnds fr fyllning r desamma som vid vanlig kopiering med
blittern. Man kan sga att fyllning R en vanlig kopiering, eftersom man
kopierar det man ska fylla p sig sjlvt, s att sga...(Man kan
visserligen ocks kopiera frn ett stlle till ett annat samtidigt som man
fyller, men jag har valt att ta upp endast det enkla fyllsttet.)
  Precis som vid den ltta, vanliga kopieringen behver vi endast Source A
och Destination D i blittern. Vi mste ocks stta en speciell mode kallad
Descending mode som jag inte gtt in p s mycket n. Descending mode krvs
av fyllrutinen, men kan anvndas ven vid vanlig kopiering. Vad moden gr
r helt enkelt att den vnder p hela blitteroperationens utfrande, s att
blittern brjar kopiera i slutet p blocket och sedan MINSKAR pekarna till
nsta word, s att den allts kopierar det framfrvarande ordet. Modulo
vrdena SUBTRAHERAS ocks, istllet fr att adderas vid ett radslut.
Shiftningar sker t VNSTER istllet fr t hger. Och blitter maskningen
fungerar ocks bakvnt, s att FIRST WORD MASK maskar SISTA wordet p raden
(men detta blir ju egentligen det frsta eftersom det hmtas frst nr allt
r baklnges :-)   Pekarna stlles allts in s att de pekar p sista
wordet i det man ska kopiera.
  Descending mode r bra om man ska kopiera tex en bob som sitter p
skrmen till en position lngre ner som verlappar bobens nuvarande
position. Problemet med en vanlig blittning blir ju d att bobens vre data
kommer att skriva ver de understa raderna innan man hunnit kopiera dem,
och boben frstrs allts. Kopierar man istllet baklnges s slipper man
detta problem.
  Vi har tittat p BLTCON1 ($DFF042) tidigare, men fr skerhets skull tar
vi det en gng till, fr att kika nrmare p fill-bitarna...

BIT#   BLTCON1
----   -------
 15    BSH3
 14    BSH2
 13    BSH1
 12    BSH0
 11     x
 10     x
 09     x
 08     x
 07     x
 06     x
 05     x
 04    EFE
 03    IFE
 02    FCI
 01    DESC
 00    LINE

Som ni ser r Descending mode bit #1, men sen finns det ven ngra andra
skojiga bitar kvar.
  EFE str fr Exclusive Fill Enable och med det menas att blittern fyller
arean mellan tv pixlar och tar bort den vnstra av dem. Ett word med
fljande utseende:

   %0001000010000000

Skulle allts bli:

   %0000111110000000

Arean r fylld men pixlen lngst till vnster r borttagen. Detta r bra
att anvnda vid fyllda vektorer, eftersom alla faces som ligger bredvid
varandra annars skulle verlappa varandra precis i kanterna och bilda
strande buggar. Vi ska allts sl p EFE i vr vektorrutin.
  IFE r, som ni kanske listat ut, Inclusive Fill Enable, och den lmnar
de yttre grnserna intakta:

   %0001000010000000

Blir med Inclusive Fill Mode:

   %0001111110000000

Man mste vlja antingen EFE eller IFE fr att fylla en yta. Den sista
intressanta biten, FCI, betyder Fill Carry In. Med det menas att blittern
fyller utanfr ytan istllet. Vrt word:

   %0001000010000000

Blir allts d (med IFE):

   %1111000011111111

Och med EFE blir det:

   %1111000001111111

Svrare r det allts inte att fylla. Resten r bara en standard SRCA->DEST
kopiering som vi lrde oss i Lektion 7.


                              Programexemplet
                              
Programmet den hr gngen r en vidareutveckligen av frra lektionens
exempel. Vr kub r nu istllet FYLLD!
  Eftersom programmet i princip r identiskt med det frra s gr jag bara
igenom de ndringar jag gjort.
  Fr det frsta har jag gjort om programmet s att det anvnder tv
bitplan istllet fr ett. Detta medfr att vi kan anvnda tre olika frger
vilket r ndvndigt fr att visa en kub (tre sidor maximalt visas
samtidigt).
  De frsta ndringarna kommer i rutinen DrawCube. En bit nedanfr labeln
.nxtpoly ser ni att jag hoppar till en rutin som kallas Hiddenface. Den
rutinen rknar fram normalen som jag beskrev tidigare. Om den r positiv
hoppar vi till .visible fr att rita ut polygonen.
  Fr att veta i vilket bitplan jag ska rita ut linjerna gr jag s att jag
shiftar runt frgnumret och kollar om det r negativt, dvs nr hgsta biten
i byten r satt. r den det betyder det att en linje ska ritas. Det kanske
verkar lite krngligt gjort, och jag borde kanske anpassat rutinen fr ett
valfritt antal frger men d hade jag ftt krngla lite mer med registren
s jag tyckte det fick g nd.
  I DrawLine rutinen har jag lagt till vid labeln .x2gx1 lite smart kod som
gr att ett spetsigt hrn i en polygon trubbas av s att blitterns
fyllrutin inte skapar fula rnder i kanterna. Prova grna att plocka bort
koden fram till .notfix s ser ni vad jag menar.
  Jag har ocks ndrat mintermen en bit under labeln .signnl till att
anvnda EOR mode. Detta r ndvndigt i vektorrutiner fr att kunna fylla
faces som hnger ihop korrekt. Ytor som ligger precis kant i kant och ska
fyllas kommer d att rita ut linjen tv gnger dr de verlappar varandra
och sledes invertera linjen (=plocka bort den) s att fyllningen fungerar
perfekt.
  I tabellen Octant_Table har jag bytt ut +1 mot +3, vilket stter SING
biten i oktanten. SING betyder SINGle point per line och krvs vid fyllning
fr att slippa flera punkter p samma rad fr samma linje.
  Rutinen FillPage r ocks ny. Den liknar allts en vanlig kopiering, men
som ni ser adderar jag (Screensize*Nrofbpl)-2 fr att peka p det allra
sista wordet i det jag fyller. I BLTCON1 skriver jag in Exclusive Fill
Enable och Descending mode som vi diskuterade tidigare. Resten r normalt
fr SRCA!DEST-kopiering.
  Jag har lagt till de tv sidorna som inte behvdes i frra program
exemplet vid labeln Lines. De sex raderna beskriver vektorobjektets alla
polygon-ytor. Det enda nya r att jag infogat ett frgnummer fre koordinat
numren. Genom att ange samma frgvrde fr sidorna som sitter mitt emot
varandra s undviker man att de hamnar s att man inte ser grnsen mellan
ytorna. Prova grna att stta alla frger till 1 s ser ni att det inte r
s lyckat.
