Put_Pixel ( )
Jaha, då var det äntligen dags att sätta lite färg på skärmen. Som du
redan vet använder sig Mode 13h av en skärmupplösning på 320x200 punkter
med 256 färger. En pixel (en punkt på skärmen) i Mode 13h representerar
exakt 8 bitar (28 = 256) eller en byte. Det betyder att vi behöver
320*200 = 64000 bytes för att kunna representera alla skärmens pixlar i minnet.
Skärmens koordinater skiljer sig lite från ett vanligt koordinatsystem.
Skärmens första pixel ligger längst upp till vänster, inte längst ned till
vänster som man lätt skulle kunna tro. Lägg också märke till att skärmens första
koordinat inte är (1,1) utan (0,0).
Om du vill visa en pixel på skärmen har du två metoder att välja på.
Antingen väljer du att anropa ett BIOS avbrott, eller också väljer du
att skriva direkt till grafik minnet. Vi kommer uteslutande att använda den
sistnämnda, eftersom den är klart snabbast och det är ju snabbhet vi är ute
efter. Eller hur? Men det skadar ju inte om man kan båda metoderna,
så jag tänker även gå igenom den långsamma.
Vi börjar med BIOS metoden och sparar det goda till sist. Precis som när
vi ställde in Mode 13h, så kommer vi nu att använda oss av avbrott 10h.
Detsamma gäller faktiskt alla grafiska operationer genom BIOS. Vi lägger helt
enkelt x-koordinaten i CX, y-koordinaten i DX och färgen
i AL. Sedan anropar vi avbrott 10h med funktionen 0Ch. Om vi
översätter detta till en funktion i C, så blir det ungefär så här:
void Put_Pixel_BIOS(int x, int y, int color)
{
union REGS inregs,outregs;
inregs.h.ah = 0x0C;
inregs.h.al = color;
inregs.x.cx = x;
inregs.x.dx = y;
int86(0x10, &inregs, &outregs);
}
Som jag förut påpekade är den här funktionen väldigt långsam. Den enda
fördelen med den här funktionen är att den kontrollerar så att (x,y) koordinaterna
ligger inom skärmens gränser.
Nu går vi vidare med den snabba metoden. Videominnet ligger från
adress 0xA000:0000h till adress 0xA000:F9FFh. Minnes adresserna är linjära,
dvs de ligger i en linje efter varandra med start vid det översta vänstra
hörnet av skärmen och slutar vid det nedersta högra hörnet av skärmen.
Adressen 0xA000:0000h motsvarar alltså (0,0) koordinaten. Det första du bör
göra är att peka på adressen med en pekare.
unsigned char far *video_buffer = (unsigned char far *)0xA0000000L;
Om du nu vill visa skärmens första pixel med färgen 35, så skriver du
helt enkelt:
video_buffer[0] = 35. Det här verkar ju enkelt,
men hur gör jag om jag vill visa en pixel med koordinaten (50,50)? Jo, vi måste finna ett
samband mellan pixelns placering i minnet och dess placering på skärmen.
Detta samband lyder enligt följande: minne_placering = y * 320 + x.
I så fall skulle (50,50) koordinaten få placeringen 50*320+50 = 16050 i minnet.
Nu återstår det bara att översätta detta till C.
void Put_Pixel(int x, int y, int color)
{
video_buffer[y*320+x] = (unsigned char)color;
}
Oerhört enkelt!! Men nu är det så att det finns en ännu snabbare funktion
för detta endamål.
void Put_Pixel(int x, int y, int color)
{
video_buffer[(y<<8)+(x<<6)+x] = (unsigned char)color;
}
Skillnaden mellan den här funktionen och den föregående är att vi här
har ersatt en "långsam" multiplikation med två snabba shiftningar och på
så sätt fått en cirka tre gånger snabbare funktion (enligt mina beräkningar).
Jaha, då var ännu en lektionen klar. Nu återstår bara att hämta hem källkoden
och testa om det fungerar i praktiken. Och du, försök INTE att skriva till en
pixel utanför skärmens gränser, för då kan det hända mycket otrevliga saker! ;-)
|