Exempel med en Mandelbrotmängd på en VGA-skärm :

Fanvare ser ut här, den här sidan måste jag nog korta ner innan jag skriver vidare på den :-)

Till startsidan Föregående sida Innehåll

I exemplet nedan så har funktioner och algoritmer beskrivits med hjälp av pseudokod.

. Inledning :

En VGA-skärm går att nå på ena eller andra sättet på en normal PC, det är den skärmen du får om du startar MS-Windows i felsäkert läge. Det är även den skärmen som normalt används av PC-D.O.S. VGA har endast 640x480 pixlar i 16 färger och är kanske inte mycket att visa en Mandelbrotmängd på men det är ett utmärkt system om man vill visa hur det fungerar samtidigt som skärmmoden är tillgänglig för dom flesta.

Det finns en uppsjö med freeware / sharewarekompilatorer i allehanda prorammeringsspråk och format att ladda ner från internet. Väldigt många av dessa kompilatorer erbjuder möjlighet att nå VGA läget och har metoder/ funktioner för att skriva grafik inbyggt i systemet eller som tillläggsbibliotek. Kan du programmera bara en smula i något språk och är intresserad av att följa exemplen nedan så är möjligheterna inte långt borta. Programmerandet får du stå för själv då jag inte vet vilket språk / plattform du använder. Algoritmer däremot erbjuds det av mig. Det här är tänkt att vara så plattforms / implementationsoberoende som möjligt. Programmerar du till exempel i Java så är VGA ganska långt borta men det är nog inget hinder då det bara är att ändra storleken på bredd och höjd för bilden och finna en lämplig metod att skriva färger så skall det nog vara ganska lätt att använda algoritmen nedan.

. Åtkomst av nödvändiga variabler och konstanter :

När man programmerar datorer så karävs det att man skapar dom konstanter och variabler som används av programmet. Själva skapandet består i att allokera lämplig mängd minnesutrymme (eller ett processor / flyttalsprocessor-register) och samtidigt skapa en pekare / referens till detta minne så att man har det åtkomligt och även sätta (initiera) variabelns utgångsvärde. Dom flesta programerinsspråk erbjuder en sådan funktion. En del låter det ske automatiskt och man behöver då inte skapa variabeln uttryckligen utan kompilatorn gör lämpligt utrymme tillgängligt vid första användandet av variabeln. C++ och många Basicdialekter till exempel. ANSI-C och givetvis assembler däremot kräver att man skapar utrymmet först innan det används.

Eftersom bildytan hos VGA har bredd / höjdförhållandet 4:3 så multipliceras bredden för z-planet med 4 och divideras sedan med 3 för att bilden skall få rätt propotioner med en enkel metod. Det är därför det ser lite rörigt ut i definitionen av z-planet nedan. Origo för z-planet (z = [0.0, 0.0]) kommer att hamna mitt i bilden.

: Först Konstanterna :
Skapa Flyttal max_längd = 2.0          : Det största belopp z tillåts anta.

Skapa Heltal Dubbelord max_iterationer = 256 : Den övre gränsen för iterationsräknaren.

Skapa Heltal Ord bredd = 640 - 1       : Skärmens breddd i antal punkter. (Kommentar)
Skapa Heltal Ord höjd  = 480 - 1       : Skärmens höjd i antal punkter.

Skapa Flyttal sx = (-2*4) / 3          : Startkoordinat för z-plantets x koordinater.
Skapa Flyttal sy = -2                  : Startkoordinat för z-plantets y koordinater.
Skapa Flyttal dx = (4*4) / 3) / bredd  : Beräkning av avståndet mellan två pixlar i x led.
Skapa Flyttal dy = 4 / höjd            : Beräkning av avståndet mellan två pixlar i y led.
: Sedan variablerna :
Skapa Heltal Ord pixel_x = 0           : Räknare för skärmens x koordinater
Skapa Heltal Ord pixel_y = 0           : Räknare y,
Skapa Heltal Dubbelord iterationer = 0 : Indexräknare för iterationer.

Skapa Flyttal x = 0                    : Parameter som motsvarar realdelen av z, (Re z).
Skapa Flyttal y = 0                    : Motsvarande imaginärdel, (Im z).

Skapa Flyttal tx = 0                   : Temporär Re z,
Skapa Flyttal a = 0                    : Räknare för z-planets x koordinater.
Skapa Flyttal b = 0                    : Räknare för z-planets y koordinater.
.

Vad som krävs förutom detta är en metod för att skapa loopar, det är något som i stort sett alla programerinsspråk erbjuder så det är inget problem. Vad vi mer behöver och som är intressantare i det här sammanhanget är en metod att får tillgänglighet till skärmen, en metod att skriva pixlar på den samt en metod att ange vilken färg som man vill att den aktuella pixeln skall ha. Dom två senare metoderna kan ibland vara kombinerade i en metod.

. Åtkomst av Skärmen :

Metoden som öppnar skärmytan brukar kräva att man anger skärmmoden som en ingångsparameter till funktionen. Skulle åtkomst av begärd skärmmode inte vara möjlig brukar funktionen normalt retunera en felkod (ett värde skilt från noll). Om funktionsanropet är framgångsrikt brukar normalt Falskt (en nolla) att retuneras. Vad skärmmode skall vara beror på implementation och bör kollas i motsvarande dokumentation. I Pc Video ROM BIOS standrad anrop som vanligtvis används från DOS anges VGA-moden 640x480 / 16 till : mode 0x12 (som är ett hexadecimalt tal och motsvaras av 18 i det decimala talsystemet).

Om man vill kan man lägga hela funktionsanropet i en villkorssats som kapslar in hela huvudloopen som då förbigås om villkoret inte uppfylls = funktionen retunerar ett värde = felmeddelande. Då kan även en alternativ sats utföras där medelandet skrivs ut :

Först testas om anropet retunerat en felkod. Om så är fallet avbryts programmet.
Sätt felkod Till Öppna_skärm [skärmmode]
Om [felkod Är Lika_med Falskt] [
  Anropet var framgångsrikt så programkörningen fortsätter här.
]
Annars
[
  Visa_felmedelande [felkod]
  Invänta användarens respons (ex: tangenttryckning) och avsluta sedan.
]
Omslut
Slut

Om man inte bryr sig i felkoder och liknande och "kör på chans" så räcker det vanligtvis med att bara anropa funktionen som öppnar skärmen och markera att man vill ignorera resultatet därav :

Ignorera Öppna_skärm [skärmmode] 

eller ännu mera hardcore, raka rör å bara vräka upp skiiiten :-)

Öppna_skärm [skärmmode] 

När programmet sedan avslutas så kan det finnas en funktion som återställer skärmen, det behövs då ingen ingångsparameter :

Stäng_skärm []
Slut 

Ibland så kan det vara så att samma funktion används i båda fallen och resutatet som retuneras när man anropar funktionen är då av två olika typer. Är det ett negativt tal så är det vanligtvis en felkod och om det är ett positivt tal så är det den tidigare skärmmoden. Det retunerade värdet används då för att återställa skärmen. Resultatet är vid återställandet ointressant och kan ignoreras (vi vet ju redan vilken skärmmode vi använt under programkörningen och skulle något gått fel vid återställandet är det inte mycket att göra, vi försöker ju avsluta programmet :-/ skulle det hända kan vi lungt säga att vi kraschat prylarna och konstatera att det är dags att börja debugga koden :-)

Sätt tidigare_skärmmode = Öppna_skärm [skärmmode]
Här testas om tidigre_skärmmode inte innehåller ett felmedelande,
programmet fortsätter i sådant fall på samma sätt som ovan.
Om [tidigare_skärmmode Är Större_än Eller Lika_med 0] [
  Här utförs funktionerna som visar fraktalen.
  när programkörningen avslutas återställs den tidigare skärmen.
  Ignorera Öppna_skärm [tidigare_skärmmode]
]
Annars
[
  Visa felmedelande om villoret inte uppfyllts.
]
Omslut
Slut  
. Skrivning till skärmen :

Nu behövs det även funktioner för att välja aktuell färg och skriva pixlar i den färgen.

En detalj att tänka på är att datorns minne som motsvarar bilden är uppradat från vänster till höger i skärmrad efter skärmrad uppifrån och ned. y Koordinter räknas däremot normalt nerifrån och upp inom matematiken och man bör därför alltid använda höjd - y när man anger skärmens y koordinat eller räkna skärmkoordinaterna för y "baklänges" i förhållande till räknaren för y i z-planet och då starta räknaren i koordinaten höjd -1 och därifrån räkna nedåt till noll för att på sådant sätt visa en matematiskt korrekt presenterad bild :

Aktuell_färg [färgnummer]
Skriv_pixel [x_koordinat, höjd - y_koordinat]

Nu Ibland så är dessa funktioner sammanbakade till en och kan då se ut så här :

Skriv_pixel [x_koordinat, höjd - y_koordinat, färgnummer]

Eller anges som en vektor i parentesen och med färgnummret efter separerat med ett komma (en mycket vanlig syntax) så här :

Skriv_pixel [x_koordinat, höjd - y_koordinat], färgnummer
. Skrivning med pekare vid alternativa skärmmoder :

Man kan även göra funktionen till en pekare med parentesen som plats för att ange index på pekaren (pekare = basadress, index = position relativt basadressen). Det här är inte direkt aktuellt för VGA men kan finnas som alternativ om man använder en av dom många VESA-moderna som finns på dom flesta grafikkort från en 32-bitars-plattform eller om man använder MCGA 320x200 pixlar i 256 färger (mode 0x13 i BIOS), då är det möjligt att skriva färgnummret direkt till grafikminnet och då adressera på det med ett index som räknas fram genom att man mutiplicerar y koordinaten med antal pixlar i x-led (bredd) och sedan addera x koordinaten, exempel vid MCGA:

Ignorera Öppna_skärm [0x13] : Öppna MCGA-skärm.
Skapa Heltal Ord bredd = 320
Skapa Heltal Ord höjd  = 200
Skapa Heltal Dubbelord index = 0
Skapa Heltal Byte färgnummer = 0
Skapa Pekare Till Byte skärmpekare = referens till skärmen (0xA000:0000 i Pc Video ROM BIOS mode MCGA)
Här defineras övriga konstanter och variabler på samma sätt som ovan.
Sätt färgnummer Till Mandelbrot[här anges z=[0.0, 0.0], c=[a, b] samt max_iterationer]
Sätt index Till (höjd - y_koordinat) · bredd + x_koordinat
Sätt skärmpekare [index] Till färgnummer : Motsvarar funktionen Skriv_pixel[...].
Den sista raden Tilldelar minnescellen som "skärmpekare [index]" pekar på värdet "färgnummer".

Det här fungerar inte så bra på 16 färgers VGA då bara fyra bitar används för att ange färgen på varje pixel vilket ger ett något krångligt handhavande, jag har därför valt att referera till "BIOS funktionen alternativt programspråkets eller operativsystemets funktion för att skriva pixlar" i VGA exemplet.

Om man har öppnat en skärm som har 32 bitars färgdjup och sedan skaffat sig en pekare dit (något som är möjligt om man använder till exempel DirectX) och sedan vill skriva in 8 bitars RGB värden direkt så gör man det på samma sätt. "index" kan i det här fallet behöva multipliceras med fyra för att på sådant sätt referera till Dubbelord (32 bitars minnesceller) då vissa kompilatorer alltid tolkar "index" som en referens till Byte (8 bitars minnesceller) :

Skapa Heltal Byte R = röd komponent
Skapa Heltal Byte G = grön komponent
Skapa Heltal Byte B = blå komponent
Skapa Pekare Till Dubbelord skärmpekare = referens till skärmen
Sätt skärmpekare [index (· 4)] Till (Dubbelord) (R · 0x10000 + G · 0x100 + B)
. Programmets sturktur :

Om man bara vill visa mandelbrotmängden i helfigur utan att kunna zooma eller ändra några andra parametrar så kräver programmet inte mycket struktur. Det räcker med en räknare för y koordinterna och en för x samt en iterationsloop :

: Först initeras prorammets konstanter och variabler som ovan
  och sedan så kommer vi till renderingsloopen :
Sätt b till sy
Räkna pixel_y från 0 till höjd -1
  Sätt a till sx
  Räkna pixel_x från 0 till bredd -1
    Sätt z till [0, 0]
    Sätt c till [a, b]
    Sätt iterationer till 0
    Upprepa
      Sätt z till z² + c      : Här beräknas z = z² + c, mer om det nedan. :
      Öka iterationer med 1
    Tills |z| > max_längd eller iterationer = max_iterationer
    Sätt Aktuell_färg Till iterationer
    Skriv_pixel [pixel_x, höjd - pixel_y]
  Nästa pixel_x
Nästa pixel_y

Fortsättning följer ...

Till startsidan Föregående sida Innehåll

Har du synpunkter på innehållet? Vill du rätta fel? Göra tillägg? Ställa frågor? då kan du kontakta Fractalus.