Retrospel för dummies: pixelgrafik


Den ofrivilliga artikelserien ”Retrospel för dummies” rullar vidare; tidigare har vi pratat om 8 bitar och arpeggio – nu är det dags för pixelgrafik.

Det har under 2000-talet fullkomligen skyfflats ut spel som på ett eller annat sätt efterapar klassisk pixelgrafik från 8 bitarsmaskiner som Commodore 64. Men många av dem bryr sig inte om de verkliga begränsningarna som gäller. De tänkte jag att vi skulle kika lite närmare på.

ghosts_adVi känner alla till de grafiska begränsningarna för datorer och spelkonsoler från tidigt 80-tal. En C64 har till exempel en upplösning på 320 x 200 pixlar innanför ramen och en palett på 16 färger. Detta är begränsningar de flesta retrospeltillverkare av i dag på moderna plattformar brukar kunna hålla sig till – men i övrigt är de frikostiga med att kombinera pixlar och färger lite hur som helst. Det är tillräckligt svårt ändå, eller hur?

Den verkliga utmaningen är dock att de flesta 8 bitarsmaskiner inte tillåter att vilken pixel som helst på skärmen kan tilldelas vilken färg som helst ur paletten, av ganska elementära skäl. Häng med så ska vi försöka bena ut varför exempelvis C64-grafiker är mycket mer awesome än du kanske tror.

SARGE1 (-, -, C64)_21_rawGrafikprestanda handlar nu som då inte bara om att särskilda grafikkretsar avlastar huvudprocessorn, utan även om hur mycket minne datorn eller spelkonsolen klarar av att skyffla fram och tillbaka.

I en Commodore 64 vet ju de flesta att det ryms cirka 64 kilobyte – men allt kan givetvis inte tilldelas enbart grafiken. Det är mycket som ska få plats på ett begränsat utrymme och alla processer delar på samma minne.

Matematiken är egentligen ganska enkel – om din burk klarar av att visa grafik med en upplösning av 320 x 200 pixlar så innebär det en total skärmstorlek på 64.000 pixlar. Om var och en av dessa pixlar ska kunna visa vilken färg som helst ur en palett på 16 färger så innebär det att varje pixel tar upp 4 bitar av minneskapaciteten; en bit kan ju bestå av antingen 0 eller 1 (2 färger) och fyra bitar är givetvis fyra gånger så mycket (16 färger).

Det innebär att en hel C64-skärm med 16 färger på varje pixel tar upp 64.000 x 4 = 256.000 bitar, vilket är 32.000 byte eftersom en byte är 8 bitar. Alltså tar en C64-skärm upp 32 kilobyte, vilket är halva minneskapaciteten för hela datorn. Om du håller dig till endast två färger eller svartvitt tar ändå hela skärmen upp 8 kilobyte, vilket också är mycket. Det är givetvis ohållbart att tillåta varje pixel att kunna visa var och en av de 16 färgerna ur paletten. Så …hur gör man då?

breath_640

Jo, 8-bitarsgrafiker är givetvis medveten om minnesproblematiken och måste inte bara hantera svårigheten med låg upplösning och begränsad färgpalett – utan även hur man får grafiken att slösa så lite minne som möjligt. Det finns flera olika sätt på vilket hårdvaran adresserar det hela men vi kan börja med det enklaste – det som på en C64 kallas HiRes Mode.

C64_screen_cells

Om en C64 alltså inte är så bra på att hantera hela skärmar med massor av färger så väljer man istället att dela upp skärmen i mindre bitar som var och en hanterar ett lägre antal färger, så kallade färgceller. En typisk färgcell är 8 x 8 pixlar och rymmer i HiRes-läget bara 2 färger – hämtade ur en palett bestående av alla de 16 färgerna.

breath_close-up

En färgcell med färgerna blå och röd kan till exempel läggas bredvid en annan färgcell med färgerna vit och gul – och så pusslar grafikern ihop en bild bestående av 40 x 25 = 1.000 färgceller som i bilden ovan. På detta vis tar varje enskild färgcell endast upp 8 byte eftersom 8 x 8 pixlar x 1 bit är 64 bitar, alltså 8 byte. Gångar du detta med 1.000 färgceller tar en sådan fullskärmsbild upp 8 kilobyte, alltså en fjärdedel av de 32 kilobyte som krävs för att alla pixlar ska kunna visa samtliga färger.

Men …som du kanske läst råkar antalet färgceller på en skärm (40 x 25 stycken) sammanfalla exakt med hur många tecken (alltså bokstäver och siffror) det får plats på skärmen – och kanske börjar vi förstå varför. Ett tecken i en Commodore 64 är också 8 x 8 pixlar stort på skärmen och tar upp 8 byte i teckentabellen som rymmer 256 olika tecken. Varje ”A” du skriver tar alltså inte upp 8 byte varje gång utan refererar till en plats i teckentabellen där ”A” ligger sparat.

Detta faktum kan en grafiker också utnyttja då datorns 256 standardtecken kan bytas ut mot precis vad du vill och sparas i teckentabellen. Istället för att spara färgvärdet för varje enskild pixel i en cell kan en grafiker alltså välja från upp till 256 olika fördefinierade mönster, fördela färgvärden till dem (fortfarande två färger per tecken) och rita ut dem bredvid varandra.

c64reset

Eftersom ett tecken tar upp en byte och skärmen rymmer 1.000 tecken (färgceller) tar alltså skärmens innehåll endast upp en enda kilobyte. Varje enskilt tecken består av en cell på 8 x 8 pixlar som var och en rymmer en av två färger, vilket blir 64 x 256 = 16.384 / 8 = alltså ytterligare drygt 2 kilobyte. Slutligen tar en färgtabell som innehåller färgerna för varje färgcell ytterligare en kilobyte.

Det innebär att en bild som använder sig av en fördefinierad teckentabell endast använder 4 kilobyte minne, vilket är ytterligare en halvering jämfört med HiRes Mode – med begränsningen att varje cell bara får bestå av ett av 256 olika tecken och innehålla två färger.

gfxhack1

Om du väljer att strunta i att fylla teckentabellen med egna tecken frigör du de 2 kilobyte som krävs och får därmed en fullskärmsbild som endast tar upp 2 kilobyte totalt! Det kräver dock sin man eller kvinna att rita snygga bilder med sådana kraftiga begränsningar – och just därför menar jag att de grafiker som lyckas göra vacker grafik på en C64 alltså är mycket skickligare än vi kanske först anar.

C64_characters

Ytterligare ett knep på en Commodore 64 är att använda sig av Multicolor Mode, vilket i praktiken innebär att varje pixel blir lika hög som i HiRes Mode men dubbelt så bred. Det innebär att upplösningen alltså bara är hälften så hög men å andra sidan kan varje färgcell innehålla hela fyra färger; tre av färgerna kan vara unika men en bakgrundsfärg måste vara samma över hela skärmen. Du har bytt ett större färgdjup mot en lägre upplösning.

ghostsn-goblins

Detta är det grafikläge de flesta C64-spel använder – antagligen för att antalet färger spelar större roll för spelaren än själva upplösningen – de flesta av oss ser inte skillnaden om vi inte går nära bilden. Pixlarna i många C64-spel ser alltså ut mer som tegelstenar än kvadrater, vilket du också ser om du studerar en skärmbild i detalj.

ghosts_multimode_example

Ungefär så fungerar det. Att bara ta sina 64.000 pixlar och laborera med 16 färger i varje pixel är alltså en dramatisk skillnad gentemot hur det verkligen fungerar. Jag förstår att de flesta retrospelsutvecklare av i dag tar dessa genvägar – men det är bra att veta hur det egentligen ligger till och varför grafiken trots allt ser ut som den gör.

Det här är såklart inga revolutionerande saker, detta har C64-grafiker vetat om sedan maskinen släpptes, men eftersom så stor del av dagens retroinspirerade aldrig tar hänsyn till de här högst verkliga utmaningarna – för att de inte behöver – så är retroinspirerade spel och riktiga retrospel också svåra att jämföra. Nästa gång tror jag att vi ska diskutera sprites.

Ha en fortsatt härlig tisdagkväll!

 


4 svar till “Retrospel för dummies: pixelgrafik”

  1. Superintressant!
    Men från en som inte kan så mycket om sånt här; borde inte varje pixel enligt din matematik kräva 8 bitar? (1 bit max två färger = 8 bitar 16 färger)

  2. @pascal: Hej, det är nog meningen nedan som ställer till det.

    ”[E]n bit kan ju bestå av antingen 0 eller 1 (2 färger) och fyra bitar är givetvis fyra gånger så mycket (16 färger)”

    Jag håller med om att detta inte är superbra förklarat, trots att jag verkligen försökte :) Men det är korrekt att 4 bitar kan innehålla ett värde mellan 0-15.

    0000 = 0
    0001 = 1
    0010 = 2
    0011 = 3
    0100 = 4
    0101 = 5
    0110 = 6
    0111 = 7
    1000 = 8
    1001 = 9
    1010 = 10
    1011 = 11
    1100 = 12
    1101 = 13
    1110 = 14
    1111 = 15

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *