gfx gfx
gfx
homegfxgaestebuchgfxforumgfxkontaktgfximpressum
gfx
QBasic
  1. QB-Forum
  2. QB-Forum
  QB-MonsterFAQ
  Tutorials
AK-LIB
  Download
  Archiv
  Hilfe
  TroubleFAQ
  Tools
Projekte
  DosFont
Extras
  Links
Statistik
Tutorials
SVGA in Qbasic
Autor: Andre Klein

         Vorwort   letzte Aktualisierung: 11.07.2003
Wer viel mit Grafiken arbeitet kennt das Problem, entweder hat man zu wenig Farben(SCREEN 12) oder eine zu kleine Auflösung(SCREEN 13).
Hier die Lösung:
Schreib dir einfach eigene Grafik-Routinen die es möglich machen Auflösungen bis zu 1600x1200x16Mc zu benutzen.
wie du das machst wird hier Schritt für Schritt erklärt.

       Abschnitt 1   Womit fange ich an?
Bevor wir anfangen müßen wir uns einmal "Grafik" als solches vornehmen. Zum Erklären beziehe ich mich in allen Beispielen auf SCREEN 13 (320x200x256).

       Abschnitt 2   Was ist VRAM?
VRAM wird der Speicher genannt der auf der Grafik-Karte eingebaut ist und wird in MB angegeben. Diese Angabe ist sehr wichtig und steht meistens direkt auf der Verpackung der Karte. Wenn es dort nicht steht kann man die Speichergröße auch anders herausfinden, aber dazu später. Im VRAM selber ist das gespeichert was später auf dem Bildschirm zu sehen ist.

       Abschnitt 3   Wie arbeitet der VRAM mit Grafik?
Als Beispiel nehmen wir einen VRAM mir der Größe von 1 MB.
Jetzt ist es so, das immer ein 64KB-Fenster dieser 1 MB im normalen Arbeitsspeicher zur Verfügung steht.
Jedesmal wenn man der Grafikkarte sagt welches Fenster gelesen werden soll, dann kopiert sie die jeweiligen 64KB in das sogenannte VIDEO-SEGMENT.
Und dann, mehrmals in der Sekunde, wird dieses Video-Segment wieder von der Grafikkarte ausgelesen und wieder in den VRAM geschrieben.
Das ganze bewirkt, das wenn man im Video-Segment etwas verändert, es auch automatisch in den VRAM übertragen wird.
Dieses Video-Segment hat in IBM-Kompatiblen PC's immer das SEGMENT &HA000 und fängt beim OFFSET &H0 an.

Das was später auf dem Bildschirm zu sehen ist, sind mehrere Fenster aus dem VRAM. Auch dort kann man einstellen welche Fenster zu sehen sind.
Das hat den Vorteil das man in nicht sichtbaren Fenstern, Grafiken zwischenspeichern kann.
Wenn man dann diese Grafiken in Spielen benutzt, geht das natürlich schneller, da die Grafiken ja nicht erst aus dem RAM gehölt werden müssen.

       Abschnitt 4   Was ist eine PALETTE?
PSET (100,100),15
Wenn du in QB einen Pixel malst der die Farbnummer 15 hat dann erscheint auf dem Bildschirm ein weißer Pixel.
Aber woher weiß QB oder die Grafikkarte das 15 = weiß ist?
Und zwar ist es so das es eine Tabelle gibt. Wenn die Grafikkarte die Farbe 15 darstellen soll, schaut sie einfach in diese Tabelle an die Position 15. Dort stehen die Rot, Grün und Blauanteile der Farbe. Auch RGB genannt. Und aus diesen Anteilen setzt die Grafikkarte die Farben zusammen die auf dem Bildschirm zu sehen sind.
Diese Tabelle mit den Farbanteilen nennt man PALETTE!
Natürlich kann man diese Farbanteile auch verändern. In QB geht das z.B. mit dem PALETTE-Befehl!
Ein Palette kann maximal 256 Farbnummern speichern. Also von 0-255.

       Abschnitt 5   Das erste Beispiel: PSET mal anders
Das folgende Beispielprogramm zeichnet einen weißen Punkt in die linke, obere Ecke des Bildschirms.
SCREEN 13 Auflösung setzen (320x200x256)
DEF SEG = &HA000 SEGMENT festlegen mit dem wir arbeiten wollen
offset& = 0 Das OFFSET im SEGMENT bestimmen
farbe% = 15 Die Farbe des Punktes festlegen
POKE offset&, (farbe% AND 255) Pixel in den Speicher schreiben
DEF SEG QB-Standart-Segment wiederherstellen
SLEEP

Damit dir das ganze Programm ein wenig verständlicher wird, spiel mal mit den Werten offset& und farbe% herum.
Nimm z.B. für das offset& bei einem Test 319 und beim nächsten Test 320. Wenn du das machst, müßtest du sehen das der Speicher linear aufgebaut ist. Also ein Offset von 319 hat die XY-Koordinaten 319,0 und ein Offset von 320 hat die XY-Koordinaten von 0,1.
Das heißt wenn du einen Pixel an eine bestimmte Position setzen willst dann mußt du das dazugehörige OFFSET berechnen.
Das macht man so:
x& = 200
y& = 100
offset& = (y&*320) + x& Die 320 stehen für die X-Auflösung

Das komplette Programm sieht dann so aus:
SCREEN 13 Auflösung setzen (320x200x256)
DEF SEG = &HA000 SEGMENT festlegen mit dem wir arbeiten wollen
x& = 200
y& = 100
offset& = (y&*320) + x& Die 320 stehen für die X-Auflösung
farbe% = 15 Die Farbe des Punktes festlegen
POKE offset&, (farbe% AND 255) Pixel in den Speicher schreiben
DEF SEG QB-Standart-Segment wiederherstellen
SLEEP



       Abschnitt 6   Das zweite Beispiel: POINT mal anders
Das folgende Beispielprogramm gibt die Farbe eines Pixels zurück:
SCREEN 13 Auflösung setzen (320x200x256)
DEF SEG = &HA000 SEGMENT festlegen mit dem wir arbeiten wollen
x& = 200
y& = 100
offset& = (y&*320) + x& Die 320 stehen für die X-Auflösung
farbe% = PEEK(offset&) Pixel aus dem Speicher lesen
DEF SEG QB-Standart-Segment wiederherstellen
PRINT farbe%
SLEEP


       Abschnitt 7   SVGA jetzt gehts los.
Um SVGA zu benutzen ist es das einfachste mit der VESA-Schnittstelle zu arbeiten.
Was ist die VESA-Schnittstelle?
VESA-Schnittstelle bedeutet einfach nur das das BIOS schon (halb)-fertige Programme besitzt die der Anwender selber benutzen kann. So spart man sich das direkte Ansteuern der Grafik-Karte.
Diese Schnittstelle kann man benutzen wenn man den Software-Interrupt &H10 des BIOS benutzt.
Was ist ein Interrupt?.


       Abschnitt 8   Dinge die ich für folgende Beispiele voraussetze:
1. QB ab Version 4.0
2. QB muß mit der Option /L aufgerufen werden um die QB.QLB zu laden.
siehe "Was ist eine Bibliothek?".
3. folgendes Programm muß am Anfang der QB-Datei stehen.
TYPE regtypex
ax AS INTEGER
bx AS INTEGER
cx AS INTEGER
dx AS INTEGER
bp AS INTEGER
si AS INTEGER
di AS INTEGER
flags AS INTEGER
ds AS INTEGER
es AS INTEGER
END TYPE
DIM SHARED reg AS regtypex


       Abschnitt 9   Überprüfen ob unsere Grafik-Karte VESA-kompatibel ist.
Mit dem folgenden Programm kann man überprüfen ob die Grafik-Karte VESA-kompatibel ist. Das muß sein, weil die anderen Programme sonst nicht laufen würden.(logischerweise)
puffer$ = SPACE$(280) Datenpuffer für Daten anlegen
reg.ax = &H4F00 als Funktion AH = &H4F festlegen
reg.es = VARSEG(puffer$) SEGMENT von puffer$ speichern
reg.di = SADD(puffer$) OFFSET von puffer$ speichern
CALL INTERRUPTX (&H10, reg, reg) INT &H10 aufrufen (BIOS-Grafik-INT)
IF reg.ax <> &H4F THEN Wenn reg.ax = &H4F dann ist VESA vorhanden.
PRINT "kein VESA!"
END
END IF
puffer$="" Speicher von puffer$ freigeben (muß nicht!)


       Abschnitt 10   Welche VESA-Auflösungen unterstützt meine Grafikkarte?
Das kann man mit dem folgenden Programm herausfinden.
CLS Bildschirm löschen
FOR i% = 256 TO 304 Modi in diesem Bereich überprüfen, denn dort sind die besten
dat$ = SPACE$(259) Puffer für Daten anlegen
reg.ax = &H4F01 Funktion AH = &H4F und Unterfunktion AL = &01 festlegen
reg.cx = i% reg.cx ist die jeweilige Modusnummer
reg.es = VARSEG(dat$) SEGMENT von dat$ merken
reg.di = SADD(dat$) OFFSET von dat$ merken
CALL INTERRUPTX(&H10, reg, reg) BIOS-Grafik-Int &H10 aufrufen
IF reg.ax = &H4F THEN Wenn reg.ax = &H4F dann wird dieser Modus von der Grafikkarte unterstützt
Xres% = CVI(MID$(dat$, 19, 2)) X-Resolution, X-Auflösung rausfinden
Yres% = CVI(MID$(dat$, 21, 2)) Y-Resolution, Y-Auflösung rausfinden
bpp& = ASC(MID$(dat$, 26, 1)) BitsPerPixel rausfinden
farben& = 2 ^ bpp& Anzahl der Farben berechnen
PRINT "&H";HEX$(i%); " "; Xres%; "x"; Yres%; "x"; farben& Die wichtigsten Daten auf den Bildschirm schreiben
END IF
NEXT i% nächsten Modus überprüfen
Anmerkungen:
Jede Auflösung hat eine andere Modus-Nummer. Zwischen den Nummern 256 (&H100) und 304(&H130) befinden sich die besten SVGA-Moden. Darunter und darüber gibt es auch noch welche aber sind kaum zu gebrauchen.

       Abschnitt 11   Wie setze ich einen Grafik-Modus?
Bevor man einen Grafik-Modus setzt muß natürlich geschaut werden ob man eine VESA-kompatible Grafikkarte hat. Desweiteren mußt du unbedingt BEVOR du einen SVGA-Modus setzt z.B. SCREEN 13 aufrufen. Das ganze dient dazu das QB ja nicht weiß das wir einen SVGA-Modus gesetzt haben und deswegen schaltet es auch nicht automatisch zurück. Wenn man vorher z.B. SCREEN 13 setzt, dann weiß QB das es nach beenden des QB-Programmes wieder in den Textmodus zurückschalten muß!
!!!WICHTIG!!!
Für ab hier beschriebene Programme übernehme ich in Schadensfällen keine Haftung!
Es kann nämlich sein das der MONITOR die gewählte Auflösung nicht unterstützt. Das merkt man z.B. daran das auf dem Bildschirm plötzlich überlagerte Bilder angezeigt werden oder der Bildschirm sich abschaltet während das Programm LÄUFT!
Mir ist zwar während der ganzen Programmierung kein Schadensfall bekannt geworden, aber ich möchte trotzdem darauf hinweisen!!!

Hier das Programm zum setzen eines SVGA-Modus:
CLS
SCREEN 13
reg.ax = &H4F02 reg.ax auf AH = &H4F und AL = &H02 setzen
reg.bx = &H101 Modusnummer setzen, (hier als Beispiel &H101, 640x480x256)
CALL INTERRUPTX (&H10, reg, reg) BIOS-Grafik-Int &H10 aufrufen
IF reg.ax <> &H4F THEN nochmal kontrollieren ob der Modus unterstützt wird!
PRINT "Modus nicht vorhanden!"
END
END IF


       Abschnitt 12   Wie gehts jetzt weiter?
Wenn du jetzt mal die QB-Befehler PSET, LINE, PRINT usw ausprobierst müßtest du sehen das das alles nicht mehr richtig funktioniert. Ist ja auch logisch, da QB ja kein SVGA kennt. Also müssen wir uns alle Grafikroutinen selber schreiben. Das ist ein Haufen Arbeit und ich werde dir hier jetzt nur noch zeigen wie man einen Pixel setzt und liest. Alles andere kann man ja davon ableiten.

       Abschnitt 13   Wie setze ich einen SVGA-Pixel?
Genauso wie im SCREEN 13 von QB wie es am Anfang des Tutorials beschrieben wurde. Also mit dem direkten schreiben der Farbnummer ins Video-Segment (&HA000).
zur Erinnerung nochmal das Programm:

SCREEN 13 Auflösung setzen (320x200x256)
DEF SEG = &HA000 SEGMENT festlegen mit dem wir arbeiten wollen
x& = 200
y& = 100
offset& = (y&*320) + x& Die 320 stehen für die X-Auflösung
farbe% = 15 Die Farbe des Punktes festlegen
POKE offset&, (farbe% AND 255) Pixel in den Speicher schreiben
DEF SEG QB-Standart-Segment wiederherstellen
SLEEP
Anstatt der 320 müssen wir jetzt 640 eintragen da wir ja eine Auflösung von 640x480x256 haben. Den SCREEN 13-Befehl können wir jetzt wegnehmen da wir ja schon einen SVGA-Modus (wie oben beschrieben) gesetzt haben.
Das Programm sieht dann so aus:
DEF SEG = &HA000 SEGMENT festlegen mit dem wir arbeiten wollen
x& = 200
y& = 100
offset& = (y&*640) + x& Die 640 stehen für die X-Auflösung
farbe% = 15 Die Farbe des Punktes festlegen
POKE offset&, (farbe% AND 255) Pixel in den Speicher schreiben
DEF SEG QB-Standart-Segment wiederherstellen
SLEEP
Dann probieren wir das ganze mal aus mit den XY-Koordinaten 0,0 ; 639,0 und 0,479!
Ahhhh! Was ist das? ein Überlauf bei den letzten Koordinaten? Wo kommt der denn her?
Und zwar:
wenn wir mal offset& per "Hand" berechnen kommen wir auf einen Wert von 306560. Und jetzt haben wir ein Problem, denn POKE kann ja nur an Adressen schreiben die einen Wert von 0-65535 haben.
Wieso hat es dann beim SCREEN 13 funktioniert?
weil da das maximale OFFSET 63999 war(319,199). Und das funktioniert ja noch einwandfrei!
Wie lautet die Lösung für das Problem?
Und zwar hat man es so gemacht das der VRAM auf der Grafikkarte in sogenannte "Bänke" unterteilt ist.
Die 1. Bank (0) ist ganz vorne im Speicher und enthält die OFFSET's von 0-65535, die 2. Bank(1) enthält alle OFFSET's von 65536-131071 usw.
Also muß man jetzt ausrechnen in welcher Bank das OFFSET liegt, diese Bank zum schreiben aktivieren und den Pixel reinschreiben!
Wie berechne ich die Bank?
bank& = offset& \ 65536 damit schauen wir wieviel mal die Bank ins Offset passt
oder
bank& = FIX(offset& / 65536)
Dann müssen wir das OFFSET (neu) berechnen
offset& = offset& - bank& * 65536 damit ziehen wir vom Offset die "Banken ab"
So, erstmal fertig. Jetzt haben wir eine bestimmte BANK und ein bestimmtes OFFSET. In dem Beispiel mit 0,479 ist BANK jetzt 4 und das OFFSET 44416.
wie setze ich jetzt eine Bank und was bewirkt das eigentlich?
Das Programm zum Bank setzen:
reg.ax = &H4F05 reg.ax auf AH = &H4F und AL = &H05 setzen
reg.bx = 0
reg.dx =bank& Bank die gesetzt werden soll
CALL INTERRUPTX (&H10, reg, reg) BIOS-Grafik-Int &H10 aufrufen
Das ganze bewirkt jetzt das, das was im Video-Segment liegt, genau der BANK-Bereich ist den wir beschreiben wollen.
Das gleiche funktioniert auch fürs Lesen von Pixeln.
Jetzt noch den Pixel an das OFFSET schreiben, und siehe da er erscheint an der richtigen Position.
Wenn er nicht an die richtige Position gesetzt wurde dann kann das folgenden Grund haben:
Wir haben ja vorweggenommen das eine BANK eine Größe von 65536 Byte hat. ABER das ist leider nicht immer so!!!!
bei einer Grafik-Karte von mir z.B. ist die Bank-Größe nur 4096 Byte. Und da muß man dann fürs Rechnen auch diese 4096 Byte nehmen, sonst sieht das ganze nicht so toll aus auf dem Bildschirm.
Wie finde ich heraus was für eine Bank-Größe meine Grafik-Karte im Moment hat?
Das macht man so:
dat$ = SPACE$(259) Puffer für Daten anlegen
reg.ax = &H4F01 Funktion AH = &H4F und Unterfunktion AL = &01 festlegen
reg.cx = &H101 reg.cx ist die Modusnummer
reg.es = VARSEG(dat$) SEGMENT von dat$ merken
reg.di = SADD(dat$) OFFSET von dat$ merken
CALL INTERRUPTX(&H10, reg, reg) BIOS-Grafik-Int &H10 aufrufen
banksize& = CVI(MID$(dat$,5,2)) * 1024 Bank-Größe herausfinden
banksize& setzt man dann in die Berechnung ein.
Beim Lesen eines Pixels ist es das genau das gleiche Prinzip. Bloß das man anstatt POKE -> PEEK benutzt.
Und das wars auch schon. Jetzt kann man sich seine eigenen Grafik-Routinen schreiben für 256Farben-Moden.

Wie mache ich das aber mit 32768, 65536 und 16777216 Farben?
Da machst du fast genau das gleiche.
Moden mit 32768 und 65536 Farben benötigen 2 Byte im Speicher anstatt 1 Byte wie mit 256 Farben. Also mußt du einfach bei 640x480 offset& * 2 nehmen und dann 2 Byte in den Speicher schreiben.
Und bei 16Mc * 3 nehmen. Und 3 Byte in den Speicher schreiben.
Zu sagen ist noch das Moden die mehr als 256 Farben haben, keine Palette mehr besitzen. Dort werden die Farbanteile direkt in das Video-Segment geschrieben.
bei 32768 und 65536 Farben sind jeweils 5 Bit für RGB zuständig. Bei 16Mc steht ein Byte für Rot, eins für Grün und eins für Blau.

       Abschnitt 14   Sichtbaren Bereich festlegen:
Man kann mit der beschriebenen Pixel-Routine natürlich auch außerhalb des Bildschirms einen Pixel setzen.
ein Beispiel wäre an den XY-Koordinaten 100,1000.
Das Programm führt das auch korrekt aus und der Pixel "landet" auf der Grafikkarte. Aber in einem Bereich der im Moment nicht an den Bildschirm übertragen wird.
Und so gibt es natürlich die möglich der Grafikkarte zu sagen ab wo denn nun der sichtbare Bereich anfängt.
Das ganze macht man so:
reg.ax = &H4F07 reg.ax auf AH = &H4F und AL = &H07 setzen
reg.bx = 0 reg.bx auf 0 setzen
reg.cx = 0 reg.cx auf 0 setzen
reg.dx = y& reg.dx ist die Y-Koordinate die in der allerersten Bildschirmzeile zu sehen ist
CALL INTERRUPTX (&H10, reg, reg) BIOS-Grafik-Int &H10 aufrufen
Wenn man dann weiterüberlegt dann kommt man auf die Idee einfach mehrere Bildschirme auf der Grafikkarte abzuspeichern.
Das heißt für den 1. Bildschirm wird y&+0 genommen (Da sie ja ganz vorne ist).
Für den 2. Bildschirm wird y& + Yres& genommen (also + die Y-Auflösung) usw usw...
Und wenn man das macht hat man am Ende sogenannte BILDSCHIRMSEITEN.
Aber wozu sind die gut?
Man kann z.B. Grafiken aus Dateien laden und sie erstmal auf einer Nichtsichtbaren Bildschirmseite unterbringen. Da dann nicht immer von der Festplatte gelesen werden muß kann man so Grafiken schneller aufbauen.
Oder aber man benutzt es für PAGE-FLIPPING oder DOUBLE-BUFFERING.
Was nichts anderes heißt als das man den kompletten Bildschirm auf einer nichtsichtbaren Bildschirmseite aufbaut und wenn das fertig ist wird einfach nur der sichtbare Bereich auf die jeweilige Seite gelegt. So kann man auch das Flackern von Animationen verhindern usw usw...
Wieviele Bildschirmseiten man anlegen kann ist abhängig vom VRAM auf der Grafikkarte!
Wenn man einen Wert nimmt der ausserhalb des VRAM's liegt dann fängt der VRAM einfach wieder von vorne an.

         Abschluss   letzte Aktualisierung: 11.07.2003
So ich hoffe das war verständlich genug. Wenn du weitere Fragen hast oder ich irgend etwas falsch beschrieben habe, dann Mail an Webmaster.




Werbung
Partner