                          - SEPTIC'S DEMOSKOLA -

                                Lektion 13
                                
                        Skriven av Vicious / Septic

                                11 Mars 94



                                 Inledning
                                 
Hejsan igen! Nu kan ni snart det mesta inom demo-programmering, men vi har
ngra saker kvar att g igenom. I den hr lektionen ska vi behandla det
sista inom vektor-blocket, nmligen 2d-klippning. Visserligen finns det en
hel hg med saker man skulle kunna g in p, s som inkonvexa, komplexa
vektorer, 3d-klippning, glenz/RGB/shadow-vektorer osv. men de r egentligen
ganska enkla nr man vl behrskar de grundlggande vektor-operationerna
som jag skrivit om i skolan.
  Dremot har vi lite intressanta saker kvar som sfrer och bitmap-
rotation/zoom att ta upp, s hll er till tls! Nu r det 2d-klippning som
gller...

                                   Teori
                                   
Att klippa tvdimensionellt r - som namnet frtljer - ett stt att
begrnsa vektorobjektets tvdimensionella bild till ett fnster med
speciella koordinater. Detta r frmst anvndbart fr att kunna lta ett
objekt glida in p skrmen frn en kant, eller fr att ha ett objekt som r
mycket strre n skrmen, utan att skrmen behver vara jttestor, fr att
frhindra att vektorn ritas utanfr skrmen (och frstr annan viktig
information i minnet).
  Detta stadkommer man genom att klippa VARJE ny linje som ritas ut i en
polygon. Man mste ven ta hnsyn till hur blitterns fyllfunktion fungerar,
och lgga till extra linjer dr det behvs fr att fyllningen ska bli
korrekt (frutsatt att man ska anvnda fyllda vektorer, givetvis...)
  2d-klippning utfrs precis innan linjen ska ritas ut p skrmen, allts
efter all rotation och 3d->2d-konvertering, och klipp-rutinen ska kunna
behandla alla mjliga fall som kan uppkomma. T.ex kan linjen HELT plockas
bort, delvis klippas en eller tv gnger, eller inte klippas alls.
  Hr r alla mjliga klippsituationer som kan frekomma:

     ____________________________________
    |                                    |
    |                                    | <-Skrm
    |                                    |
    |            /                       |     \
    |           /                        |      \
    |         A/                         |       \D
    |         /                          |        \
    |        /                           | /       \
    |       /                            |/C
    |                                    /
    |          \                        /|
    |___________\______________________/_|
                B\                    /
                  \                  /
                   \

Linje A ligger helt och hllet inom skrmens grnser och skall inte klippas
alls. Linje B ligger delvis utanfr skrmen, allts ska vi klippa den, och
samma sak gller linjen C, fast med skillnaden att den bryter grnserna TV
gnger. Till sist, linjen D, skall plockas bort, eftersom den inte r
synlig p ngot stlle p skrmen.
  Efter klippning ska vi allts f fljande skrmutseende:

     ____________________________________
    |                                    |
    |                                    | <-Skrm
    |                                    |
    |            /                       |
    |           /                        |
    |         A/                         |
    |         /                          |
    |        /                           |
    |       /                            |
    |                                    |
    |          \B                      C/|
    |___________\______________________/_|

Nr vi ska klippa fyllda polygoner mste vi som sagt ta hnsyn till
blitterns fyllnings-krav, och med det menar jag att ytan mste vara helt
sluten fr att fyllas korrekt. Om d vissa delar av den ligger utanfr
skrmen mste man automatiskt knyta ihop stllena dr klippning gde rum.
  Titta p fljande bild fr att frst lttare:

     ____________________________________
    |                                    |
    |                                    | <-Skrm
    |                                    |
    |                                ____|___
    |                               /    |F  \ <-Polygon
    |                             A/     |    \E
    |                             /      |     \
    |                             \      |     /
    |                              \     |    /
    |                              B\    |   /D
    |                                \___|__/
    |____________________________________|C

Om vi ska klippa ovanstende polygon mste vi gra det p fljande stt:

1.Rita ut linje A (utan klippning eftersom den ligger inom skrmgrnserna)
2.Rita ut linje B (ocks utan klippning...)
3.Rita ut linje C, och klipp linjen. Kom ihg klipp-koordinat.
4.Linje D ligger utanfr, och drfr ritar vi inte ut den.
5.Samma sak gller linje E.
6.Linje F klipps som linje C, men istllet fr att komma ihg en ny
klipp-koordinat, mrker vi att det redan finns en gammal klipp-koordinat
lagrad. Allts ritar vi ut en linje mellan dessa tv koordinater och rensar
sedan den lagrade klipp-koordinaten.

Om vi har ett annorlunda fall, dr en del av polygonen gr utanfr skrmen
bde i understa kanten och den hgra gr vi p ungefr samma stt...Vi
erinrar oss bara att blittern endast behver extra linjer i hger och
vnsterkanten (eftersom den fyller mellan punkter frn hger till vnster).

     ____________________________________
    |                                    |
    |                                    | <-Skrm
    |                                    |
    |                                    |
    |                                    |
    |                                    |
    |                                  __|__
    |                                 /  |F \
    |                               A/   |   \E
    |                               /    |    \
    |                               \    |     \
    |________________________________\___|     /
                                     B\       /D
                                       \_____/
                                          C
1.Linje A ritas ut utan klippning.
2.Linje B klipps och klipp-koordinaten lagras. Eftersom vi bara ska rita ut
linjer i hger/vnster kant ser vi nu att vi inte behver X-koordinaten.
Y-koordinaten rcker allts.
3.Linje C, D och E ritas inte ut.
4.Linje F klipps och vi ser att vi har en klipp-koordinat lagrad. Allts
ritar vi ut en extra linje frn F, rakt nedt i skrmkanten till den
understa kanten.
  Till sist, fr att behandla det fall d en linje skr en kant tv gnger
gr man s att man klipper fr den ena kanten frst, och sen den andra
kanten. P s stt delar man upp det hela och det blir inte svrare n en
normal "en-skrnings"-klippning.

Detta kan skert verka lite svrt och obegripbart till en brjan, men jag
tror ni kommer frst allt snart.
  Okej, nu till den verkliga frgan: Hur GR man fr att klippa en linje?

Jo, det r inte alls s svrt. Det bygger helt enkelt p lite likformighet
igen. Vi tittar p ett klippningsfall:

              Klippgrns
             |
             |
             |  x1;y1
             |  /<-Linje
             | /
             |/
             |
            /|
           / |
          /  |
         /   |
     x2;y2   |

Vi knner till linjens start och slutkoordinat, dvs x1;y1 och x2;y2, och vi
knner ven till klippgrnsen eftersom vi satt den sjlv.
  Vi har ftt tv trianglar som r likformiga och dr endast en lngd r
oknd:

              Klippgrns
             |
             |
             |        _
             |  /|     |                     a - Stora triangelns hjd
             | / |     |                     b - Store triangelns bredd
             |/  |     |                     c - Lilla triangelns hjd
             |   |     |- a=y2-y1            d - Lilla triangelns bredd
            /|   |     |
           / |c  |     |
          /  |   |     |
         /___|___|    _|
             |        

         |___|
           |
           d=Klippgrns-x2
         |_______|
             |
             b=x2-x1

Vi vet allts a,b och d, men inte c. Och vad anger c? Jo, den anger allts
hur lngt ifrn y2 som det nya y1 ska ligga. Vi har allts skapat nya
vrden fr x1;y1, dr x1=Klippgrnsen och y1=y2-c.
  Vrdet p c bestms genom likformighet:

   a   c
   - = -
   b   d

       a*d
   c = ---
        b

Den hr formeln kan givetvis ven anvndas vid klippning mot de vriga
kanterna ocks! Koordinaterna behver endast bytas ut mot de aktuella
istllet. Hur det ska gras kan ni se i programexemplet...

Tja, det var allt jag tnkte frklara om klippning. Tnk p att det inte
BARA behver anvndas fr att klippa i skrmens utkanter. Man kan t.ex gra
snygga saker genom att klippa i ett litet fnster p skrmen samtidigt som
andra saker frekommer dr. Det blir allts enklare att designa ngot
hftigt om man kan klippa vektorerna...


                                 Register
                                 
Inga nya register i den hr lektionen. Klippningen fr sktas helt och
hllet av processorn.


                              Programexemplet
                              
Dagens progamexempel innehller, inte helt ovntat, en vektorkub som klipps
i skrmkanterna!
  Som ni ser klipper jag en bit p skrmen fr att ni ska se hur
klippningen gr till. I vanliga fall brukar man klippa i skrmens utkant
och d syns det ju inte.
  Tja, det enda nya r egentligen klipp-rutinen (konstigt nog :-) och den
heter Clip2d. Vi anropar den precis innan vi ska rita ut vr rutin,
eftersom den modifierar linjens start och/eller slutpunkt s att linjen
klipps till de grnser vi satt. Den kan ocks lmna en returkod p -6000
och d betyder det att linjen ligger helt utanfr skrmen och inte ska
ritas ut alls.
  Okej, jag kan g igenom vad rutinen gr lite mer steg fr steg kanske...
Frst och frmst lagrar jag linjens frgvrde fr att vi kan behva det nr
vi ritar ut en extra linje.
  Sedan gr jag en liten speciell sak som kanske inte r s sjlvklar.
Genom att frskra mig om att X1 r mindre n X2 rcker det sedan att testa
om X1 ska klippas mot vnsterkanten eller om X2 ska klippas mot hger-
kanten! Man behver allts inte testa bda vrdena mot bda kanterna med
den hr metoden. Antingen ligger ju bara X1 till vnster om klippgrnsen
eller ocks s ligger de bda utanfr och d ska linjen inte ritas ut alls.
  Om nu X1 bara ligger utanfr d, s kommer vi en bit lngre ner i koden,
till labeln .CutLeft.
  Hr gr jag diverse berkningar enligt formeln ovan, fr att slutligen f
fram den nya Y koordinaten i den frkortade linjen. Jag lagrar ven det hr
vrdet om det inte redan finns ett gammalt vrde. Finns det ett gammalt
vrde lagrat s betyder det att vi klippt en gng och allts vandrat ivg
utanfr skrmen med vr polygon. Nu nr vi kommer tillbaka in mste
polygonen bindas ihop med en extra linje, och drfr hoppar jag till
rutinen XtraLineLeft.
  De andra klippningarna gr till p ungefr samma stt, och notera ven
att jag gr samma koll med Y1 och Y2 som jag i brjan gjorde med X1 och X2,
allt fr att slippa att kolla dubbelt.
  Om vi kikar p rutinen XtraLineLeft nu d, s upptcker ni att det inte
r ngra egentliga konstigheter hr. Jag bara kollar s att den extra
linjen hamnar innanfr grnserna och sedan ritar jag ut den i rtt bitplan.
  Nere bland variablerna hittar vi ClipLeft, ClipRight, ClipUp och
ClipDown. Dessa r, som namnen avsljar, klipp-koordinaterna som bestmmer
fnstrets storlek. Testa grna att ndra dem, men akta er fr att stta dem
strre n skrmens storlek, eftersom det skerligen leder till att datorn
kraschar.
  Sdr, svrare var det inte!
