Assembler Cursus - Les 5 In deze les leren we hoe we Horizontale en vertikale Scroll's kunnnen maken met een plaatje, en nog enkele andere speciale effecten. Laten we biginnen met de horizontale Scroll (Beeld naar links of rechts schuiven): De Amiga bezit een speciaal Register dat voor deze opgave gemaakt is, BPLCON1 ($dff102). Dit register kan een beeld naar links of rechts schuiven over een bereik van 1 tot 15 pixels per keer. Dat wordt door de Copper bereikt, als we de Data-transfer van BitPlanes een of meer Pixels te laat laten aankomen. De even en oneven bitplanes kunnen ook apart verschoven worden. De oneven Bitplanes worden PLAYFIELD1 genaamd (1,3,5), de even PLAYFIELD2 (2,4,6). $dff102 is een Word lang, en in twee Bytes onderverdeeld: Het Hoogwaardige,dus links ($xx00) dat uit de bits 15 tot 8 bestaat, en het laagwaardige ($00xx). Het hoogwaardige Byte wordt niet gebruikt, en moeten we om deze reden op 0 laten. Het laagwaardige byte controleert de scroll: $dff102, BPLCON1 - Bit Plane Control Register 1 Bits Naam/Functie 15 - X 14 - X 13 - X 12 - X 11 - X 10 - X 09 - X 08 - X 07 - PF2H3\ 06 - PF2H2 \4 Bits voor Scrollen van de even PLANES 05 - PF2H1 / (Playfield 2) 04 - PF2H0/ 03 - PF1H3\ 02 - PF1H2 \4 Bits voor Scrollen van de oneven PLANES 01 - PF1H1 / (Playfield 1) 00 - PF1H0/ We werken met dit word net als bij de kleurregisters: Werken we bij de kleurregisters met drie componenten (Rood,Groen en Blauw of RGB), hier werken we met twee componenten, die beide van $0 tot $f gaan. dc.w $102,$00xy ;Bplcon1 - Waarbij: X Scrollen Even Planes Y Scrollen Oneven Planes Enkele voorbeelde voor de Copperlist: dc.w $102,$0000 ; BPLCON1 - Scroll NULL, normale Positie dc.w $102,$0011 ; BPLCON1 - Scroll = 1 in beide Playfields, ; we bewegen dus het hele beeld dc.w $102,$0055 ; BPLCON1 - Scroll = 5 voor hele beeld dc.w $102,$00FF ; "" Scroll op maximum waarde voor hele beeld dc.w $102,$0030 ; "" Scroll = 3 voor even Bitplanes dc.w $102,$00b0 ; "" Scroll = $B voor oneven Bitplanes dc.w $102,$003e ; "" Scroll = 3 voor even Bitplanes, $e voor ; oneven Bitplanes Niets zo makkelijk! Simpelweg de waarde van de scroll bij elke frame wisselen en we hebben een scroll die het hele beeldscherm met 1 Move beweegt. Laad Listing5a.s in om te zien wat er in de praktijk gebeurt. In dit voorbeeld wordt BPLCON1 - $dff102 - aan het begin van de Copperlist verandert, daarom beweegt het hele beeld. Het is ook mogelijk meerdere "$dff102"'s op verschillende plaatsen in de copperlist te zetten. Wat daardoor ontstaan kan zietu in listing5b.s. Daar gebruiken we twee scrolls die het plaatje doormidden scheuren. Wordt er een $dff102 per lijn gegeven, dan krijgt men het alombekende wave-effect. Laten we eens kijken naar de verticale scroll. De eenvoudigste soort is gewoon hoger of lager in de BitplanePoiters van de copperlist te pointen. Daardoor verschijnt het beeld ook hoger of lager. Laten we eens een voorstelling proberen te maken: --------------- | | 1 | | 2 | AMIGA | 3 | | 4 | | 5 --------------- In dit geval staat AMIGA in het midden van het scherm, en staan de bitplanepointers gewoon op 1, dus daar waar het scherm begint. Omdat we op 1 beginnen staat AMIGA op (denkbeeldige) lijn 3. Als we nu naar 2 pointen, wat gebeurt er dan?? --------------- | | 2 | AMIGA | 3 | | 4 | | 5 | | 6 --------------- Dat gebeurt er dan. AMIGA 'stijgt' een lijn, omdat het beeld zakt, of anders gezegd de pointer staat 1 lijn lager. Bewegingen zijn relatief. Om dat uit te leggen is een simpel voorbeeldje genoeg. Als u in een trein zit, en u ziet het perron bewegen (of een boom etc.) dan beweegt het perron niet, maar u bent degene die beweegt. Hier gebeurt hetzelfde. Maar hoeveel moeten we optellen/aftrekken van de bitplanepointer om dit te bereiken? Het aantal bytes van 1 lijn! Dus 40 als het plaatje in Lowres 320*256 is, of 80 als het plaatje in High Res 640*256 is. Laten we een voorbeeldje maken: 1234567890 .......... ....++.... ...+..+... ...++++... ...+..+... ...+..+... .......... We hebben een denkbeeldig Bitplane, met 10 bytes per lijn, dat 0 (.) of 1 (+) kan zijn. Hier staat dus een 'A'. Om deze A naar boven te scrollen moeten we 1 lijn 'dieper' pointen. Om dieper te pointen, moeten we 10 Bytes erbij optellen (Add.l #10,Pointer): 1234567890 ....++.... ...+..+... ...++++... ...+..+... ...+..+... .......... .......... Op diezelfde manier, om het plaatje te laten zakken, moeten we 1 lijn hoger beginnen, dus 10 bytes minder: (Sub.l #10,Pointer) 1234567890 .......... .......... ....++.... ...+..+... ...++++... ...+..+... ...+..+... Om dat in de praktijk te bereiken moeten we eraan denken dat de Pointer in de Copperlist het adres van de planes bevat (dat we dan veranderen), en dat dit adres in twee words is opgedeeld. Dit probleem is makkelijk op te lossen als men enkele kleine veranderingen in de routine voor het Pointen naar de bitplanes aanbrengt. We moeten dit adres uit de copperlist halen (omgekeerde operatie), 40 erbij optellen of aftrekken (80 bij HiRes), en dan dit adres weer in de copperlist terugzetten. Voor deze laatste stap kan ook de oude routine dienen. Kijk eens naar listing5c.s waar we dit systeem gebruiken. In listing5d.s ziet u nog een keer de Horizontale scroll (met $dff102) en de verticale scroll tegelijkertijd. In listing5d2 ziet u nog een keer het gebruik van horizontaal scrollen samen met een 'buig-effect' d.m.v. $dff102 (BPLCON1). Nu zullen we het belangrijkste register voor Video-special-effects met de Amiga eens gaan bekijken: De Modulo. $dff108 en $dff10a (BPL1MOD en BPL2MOD). Er zijn 2 modulo registers zodat ze onafhankelijk van de even en oneven planes veranderd kunnen worden. Om ons beeld met 3 bitplanes te kunnen gebruiken, moeten we beide registers aanroepen. U zult gemerkt hebben dat bij een beeld in Low-Res 320x256 de Beam alle 40 bytes een nieuwe lijn begint, maar de data (voor het beeld) zelf staat achter elkaar. Precies zo gaat het bij Hires, waar de beam elke 80 bytes een nieuwe lijn begint. Deze waarde wordt automatisch toegewezen als we $dff100 (BPLCON0) zetten: Wordt lowres gekozen, dan weet de copper dat hij elke 40 bytes een nieuwe lijn moet beginnen. Hij begint dus linksboven, tekent 40 bytes en de eerste lijn staat er. Dan begin alles weer opnieuw. De volgende 40 bytes worden gelezen en getekend, en de tweede lijn staat er. Dit gaat door totdat allen 256 lijnen getekend zijn. In het geheugen echter liggen de gegevens achter elkaar. Het geheugen is als een ketting, waarop alle gegevens achter elkaar zijn geregen. Stel u voor dat u alle 256 lijnen achter elkaar kon leggen in een lange rij. Zo ziet het er ook uit in het geheugen. Als we nu de Modulo op 0 laten, dan veranderen we niets, en blijven de waarden dus 40 voor Lowres of 80 voor HiRes. Als we nu een waarde in de Modulo stoppen, wordt bij de Bitplanepointer die waarde AAN HET EINDE VAN DE LIJN erbij geteld, dus als we de 40 bytes hebben bereikt. Daardoor kunnen we bytes overslaan, die niet getoond worden. Als we b.v. 40 bytes bij elk einde optellen, dan wordt na elke lijn 1 lijn overgeslagen: - NORMAAL BEELD - .................... .........+.......... ........+++......... .......+++++........ ......+++++++....... .......+++++........ ........+++......... .........+.......... .................... Het resultaat zou als volgt zijn: - BEELD Modulo 40 - .................... ........+++......... ......+++++++....... ........+++......... .................... .................... .................... .................... .................... Het beeld zal dan 'geplet' uitzien, de helft zo lang.We zien dan ook bytes 'onder' het beeld zoals we al gezien hebben omdat het beeld eindigt bij 256 lijnen: praktisch worden er maar 256 lijnen getoond, maar omdat we elke tweede lijn tonen worden er 512 getoond. Laad nog eens listing4b.s in en verander de modulo in de copperlist als volgt: dc.w $108,40 ; BPL1MOD dc.w $10a,40 ; BPL2MOD U zult merken dat het beeld, zoals verwacht, maar de helft zo groot is, en dat het onderste gedeelte van het beeldscherm gevuld is met troep. Probeer nu eens 2 lijnen over te slaan, als u de modulo 80 maakt: dc.w $108,40*2 ; Bpl1Mod dc.w $10a,40*2 ; Bpl2Mod Het plaatje is nu nogmaals gehalveerd, en daaronder verschijnt nog meer troep. U zult een halvering van het beeld opmerken die als volgt is: 40 X Aantal keren Halveren. (Bij Hires is dit 80!). Als u een modulo gebruikt die geen veelvoud van 40 is,krijgt u en vertekend beeld, omdat de copper de lijnen niet meer vanaf het begin tekent, maar vanaf een punt, dat van lijn tot lijn verschillend is. Laad Listing5e.s in, om een snelle Routine te zien die 40 bij de modulo optelt, om het plaatje te halveren. De Modulo Registers kunnen behalve Positief ook Negatief zijn. In dat geval wordt het getal aan het einde van de lijn afgetrokken. Hierdoor kunnen komische effecten ontstaan. Stelt u zich voor: U zet de modulo op -40. De copper leest dus 40 bytes, tekent de eerste lijn, en gaat dan 40 bytes terug en tekent die lijn weer. Hij komt dus nooit over die 40 bytes heen! Als bijvoorbeeld de eerste lijn helemaal zwart is, dan worden alle volgende lijnen ook zwart, omdat ze de eerste kopieëren! Als er een punt in het midden van de eerste lijn zou staan, dan hebben alle lijnen deze punt: ..........+........ ; Lijn 1 (Steeds opnieuw getekend; ..........+........ ; Lijn 2 Modulo -40!) ..........+........ ; Lijn 3 ..........+........ ; Lijn 4 ..........+........ ; Lijn 5 ..........+........ ; Lijn 6 ..........+........ ; Lijn 7 ..........+........ ; Lijn 8 ..........+........ ; Lijn 9 ..........+........ ; Lijn 10 Zo zal elke kleur een soort 'smelteffect' krijgen, die tot het einde van het scherm duurt. Dit effect wordt in veel spellen (Zoals Full Contact) gebruikt. Laten we eens kijken hoe dat in de praktijk uitziet. Listing5f.s..... Zeer indrukwekkend, en toch simpel te maken, niet? Dit wordt ook wel het FLOOD effect genoemd. De modulo wordt aan elk einde van de lijn bij de bitplane-pointers opgeteld. We tellen dus een negatief getal erbij op. Dit gaat als volgt: +---->->->--------+ | | |BPL POINTER= X+ 0......................................39 | | | |Begin Lijn-------+---xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx---+- Laatste Byte | (X) | | | | (X+39) | +---+ +---+ | | | Volgende Lijn -+----xxxx[...] ^ | | | +-X+ 40 (De pointer is op de laatste positie blijven staan, ^ | wat niets anders betekent dan dat we de volgende 40 | | bytes (dus de volgende lijn) kunnen tekenen. ^ | | +-> (Hier wordt de pointer veranderd van elk plane. We | | Tellen er iets bij op (in ons geval -40) | +-> X=X+(-40) => X=X-40 => X=0 >-+ | | | +----------<-<-<--+------------<-<-<---------------+ Gezien? Net als de pointer op het einde is aangekomen, trekken we er weer 40 van af, en toont hij weer dezelfde lijn. We hebben in listing5f.s ook het 'Spiegel-effect' gezien, dus Modulo -80. Laten we eens kijken wat er in Listing5g.s gebeurt... Nu zien we hoe we door het gebruik van vele $dff102's achter elkaar in de copperlist een golf-effect kunnen bereiken. Listing5h.s is hier een voorbeeld van. Laten we nu eens kijke naar listing5i.s. Dit is een zgn. Graphic-Scanner, een programma dat het gehele chip-geheugen doorloopt, en daardoor alle zichtbare dingen ook zichtbaar maakt. Dit wordt vaak gebruikt in GFX-Rippers (Programma's om beelden uit programma's te "stelen"). Nog een voorbeeld is listing5l.s, deze keer om een beeld in de lengte uit te rekken, i.p.v. het te krimpen. In listing5m.s zien we een andere methode om beelden naar boven of naar beneden te verschuiven. Deze keer doen we dat door het veranderen van DIWSTART ($dff08e). De registers DIWSTART en DIWSTOP bepalen het begin en het einde van het 'video-beeld', dus het rechthoekige gedeelte van het scherm dat getoond wordt. DIWSTART bevat de YYXX-Coördinaten van de Linker- bovenhoek van het scherm, DIWSTOP de coördinaten van rechtsbeneden: DIWSTART o---------------- | | | | | | | | | | ----------------o DIWSTOP In deze registers kan men echter niet alle gewenste waarden inzetten, want XX en YY zijn Bytes, en zoals bekend kan een Byte maar een Maximale waarde van 255 hebben ($00-$ff). Laten we eens bekijken waar we het scherm kunnen laten beginnen mew DiwStart en stoppen met DiwStop: dc.w $8e,$2c81 ; DiwStrt YY=$2c, XX=$81 dc.w $90,$2cc1 ; DiwStop YY=$2c(+$ff), XX=$c1(+$ff) Het normale beeld heeft deze waarden voor DiwStart en DiwStop; de vertikale positie YY functioneert hetzelfde als bij een WAIT van de Copper: Als we met de Copper b.v. lijn $2c afwachten, en daar van kleur veranderen, dan is deze kleurwisseling niet te zien, omdat $2c te hoog boven ligt. Hetzelfde geldt voor Waits NA lijn $FF, die dan weer bij $00 beginnen (eigenlijk dus $ff+1), Het scherm begint bij $2c, en eindigt bij $2c na lijn $ff. Daardoor komen we dus op 256 lijnen per beeld. Voor een beeld dat maar 200 lijnen lang is moeten we de volgende DiwStop zetten: dc.w $90,$f4c1 ; DiwStop YY=$2c(+ff), XX=$f4 In de zin dat $f4-$2c = 200. Als we $00,$01... zetten, bedoelen we vanaf nu de lijnen NA $FF. De limieten zijn als volgt: DiwStart kan zich verticaal tussen $00 en $ff bewegen, dus tot lijn 200.(Klinkt onlogisch he? Uitleg volgt zometeen!). Het video-scherm kan dus niet meer op lijn 201 beginnen, altijd eerder. Voor DiwStop hebben de Ingenieurs die de Amiga ontworpen een strategie bedacht: Als de waarde onder $80 (128) is, dan is dit NA lijn $FF. $2c is dus eigenlijn $2c + $FF!. Is het getal groter als $80 dan wordt het getal genomen zoals het is ( ook omdat lijn $80+$ff ( =383 ) niet bestaat ). Dus $70 = $70 enz.. DiwStart kan dus maximaal tot $ff gaan, bij NUL startend, DiwStop kan echter $ff overschrijden en over de Limiet van het scherm heengaan, maar kan weer niet onder (eigenlijk boven) lijn $80 komen! Wat de horizontale Lengte betreft, kunt u elke waarde tussen $00 en $ff nemen, dus tot Positie 256 (Denk eraan dat het scherm bij $81 en niet bij $00 begint, dus bij 126!). DiwStop daarentegen interpreteert $00 als 127, en dat gaat zo verder tot de rechterkant. Er wordt bij DiwStop dus altijd $FF opgeteld! In Listing5m2.s zal een en ander duidelijk worden ( hoop ik! ). Als afsluiting van Les 5, kunt u Listing5n.s proberen, die een samenvatting is van zo'n beetje alle vorige Listings, en daarbij ook nog een muziekstuk afspeelt! Eenmaal deze listing begrepen, blijft er niets anders over dan Les6.txt in te laden!