In VESA-Modi Pixel setzen Tja, ich habe lange berlegt, ob ich hier eine Routine fr einen speziellen VESA-Modus vorstellen soll, so zum Beispiel fr den 640x480x256-Modus (101h), oder ob ich eine Routine bringen soll, die fr jeden Grafikmodus benutzt werden kann. Dabei stellte sich mir allerdings die Frage, ob so eine Routine a) berhaupt mglich ist, ohne ganz billig einfach abzufragen, in welchem Modus man sich befindet, und dann verschiedene Prozeduren einfach anspringt und dort die Punkte setzt b) ob es sinnvoll ist, solch eine Prozedur zu schreiben, da man schlielich einiges an Rechenzeit verschwenden wird, wenn man immer erst unterscheiden mu, in welchem Modus man ist und dem entsprechend verschieden verfahren mu. Ich bin darauf gekommen, eine Routine zu schreiben, die bei allen 256-Farben Modi funktioniert. Dabei mu ich nicht allzu viel fr die verschiedenen Prozeduren verndern, habe EINE Routine fr alles und bin noch relativ schnell weg. Allerdings: Wenn man eine optimale Routine haben will, sollte man sie sich tatschlich ganz speziell fr den gewnschten Modus schreiben, alles Andere kostet einfach zuviel Zeit. Also: 256 Farben Modi, was sagt uns das? In einem solchen Modus nimmt ein Pixel immer genau 1 Byte ein, das heit: Der Adresse A000h:0000h steht immer fr den links oben erscheinenden Pixel, die Adresse A000h:0001h immer fr den rechts daneben stehenden usw. Da ein Byte genau 256 verschiedene Werte aufnehmen kann (2^8 = 256 / 0 - 255), sollte dieses klar sein. Der einzige Unterschied: Die Anzahl der Zeilen und Spalten sind anders. Im Modus 101h habe ich 640 Spalten und 480 Zeilen, im Modus 103h hat 800 Spalten und 600 Zeilen und der Modus 105h hat 1024 Spalten und 768 Zeilen. Daraus ergibt sich, da natrlich mehr Speicher fr den Modus 105h als fr den Modus 103h und dieser mehr als fr den Modus 101h bentigt. Das wiederum heit, da ich, wenn ich den aller letzten Punkt in jedem Modus setzen will, ich bei den hheren Modi das 'Videofenster' in den Videospeicher der Grafikkarte weiter verschieben mu, als in den niedrigeren. Aber dazu sp- ter noch mehr. Was uns nun beschftigen soll, ist: Wie finde ich heraus, in wel- chem Modus ich mich befinde, wenn ich mich innerhalb meiner 'SetzePunkt' Prozedur befinde und nicht extra angeben will, welcher Modus es ist (was zwar auch mglich ist, doch wre das sicherlich nicht so 'elegant', als wrde diese Info die Pro- zedur alleine herausfinden). Dafr gibt es eine ganz einfache Lsung: Die Unterfunktion 01h des VESA-Treibers, der ber die Funktion 4Fhh des Video-Interrupts 10h angesprochen wird, liefert einem eine ganze Menge an Informationen ber einen angegebenen Modus zurck. Unter anderem auch die x/y-Auflsung. Allerdings ist dies leider keine Pflicht fr jeden Treiber. Doch ist mir bisher keine andere Mglichkeit bekannt, die Auflsung dann doch zu erhalten. Das einzige, was wir dafr noch bentigen, ist der Modus selber, und den erhalten wir mit der Unterfunktion 03h. Also: Zuerst fragen wir in unserer Routine die aktuellen Video- modus ab, indem wir die Unterfunktion 03h befragen. Der Modus wird uns in BX zugeteilt. Hier sollten wir dann kurz berprfen, ob der Modus 101h, 103h oder 105h ist, und ansonsten die Pro- zedur (eventuell mit einem Fehlercode) beenden. Diesen Wert mssen wir dann ins CX-Register laden und die Unter- funktion 02h aufrufen. Gleichzeitig mssen wir aber mit ES:DI einen 29 Byte groen Puffer gekennzeichnet haben. Nun knnen wir im Bit 1 (das 2. Bit) des Offsets 0 im Puffer ablesen, ob die optionalen Informationen (darunter auch die Angabe ber die x/y-Auflsung) mitgeliefert wurde. Wenn ja, ist das Bit 1 ge- setzt. Ansonsten mssen wir wiederum die Prozedur verlassen. Nungut, wir haben jetzt die x/y-Auflsung des gesetzten Modus. Im Puffer an dem Offset 12h steht die x-Auflsung, und an dem Offset 14h finden wir die vertikale (y-) Auflsung. Was nun? Der Prozedur sollte die x und die y Koordinate des gewnschten Punktes sowie dessen Farbe bergeben werden. Um nun an die ge- wnschte Offsetadresse im Videosegment bei A000h zu kommen, mu man die y-Koordinate mit der x-Auflsung multiplizieren und dann die x-Koordinate hinzu addieren. Beispiel: Modus 101h: x-Auflsung : 640, y-Auflsung : 480; x-Koordinate : 56, y-Koordinate : 60. yK * xA = 60 * 640 = 38400. 38400 + xK = 38400 + 56 = 38456. Der Pixel mu also an die Adresse A000h:38456d bzw. A000h:9638h geschrieben werden. Nimmt man aber nun das Beispiel xK = 56 und yK = 400, dann wrde als Offset die Zahl 256056d bzw. 3E838h herauskommen. Nicht schlimm? Doch! Denn dieser Offset wrde schon in einem ganz an- deren Segment liegen! Man mu also einen Wert erhalten, der innerhalb der Segmentgrenzen liegt, also grer oder gleich 0 und kleiner oder gleich 65535 sein mu. Nun wird es kompliziert: Liegt der bestimmte Offset auerhalb dieser Schranken, dann mu er in dieser 'hereingeschoben' werden. Das heit, er mu verringert werden. Aber nicht ohne Ausgleich! Um den gleichen Wert, um den der Offset verringert wird, mu gleichzeitig die Adresse des Videofensters vergrert werden. Zur Erinnerung: Das Videofenster dient als Zeiger in den Grafik- speicher der Grafikkarte. Es wird beim Segment A000h im Haupt- speicher eingeblendet. Da dieses Fenster im Allgemeinen auch nur maximal 64 Kilobyte gro ist (also ein Segment umfat), mu es im Videospeicher der Grafikkarte verschoben werden, um Modi, die mehr als 64 Kb Speicher verbrauchen zu adressieren. Wenn ich also zum Beispiel im Modus 101h den Pixel mit der 'Offsetadresse' 65536 setzen will, so mte ich das Videofenster ersteinmal z.B. auf da zweite Segment im Speicher der Grafikkarte setzen (es zeigt nun also auf die Pixel 65536-131071) und dann an die Off- setadresse 0000h den Pixel plazieren. Ich knnte das Videofenster aber auch so verlegen, da es auf die Pixel 32768-98303 zeigt und dann die Offsetadresse 32767 einen Punkt plazieren. Der Effekt wre der gleiche. ABER: WENN IHR DAS JETZT NICHT VOLLSTNDIG ODER VIELLEICHT NICHT EINMAL ANSATZWEISE VERSTANDEN HABT: MACHT NIX! LEST ES NOCH 50 ODER 60 MAL, VIELLEICHT BLEIBT DANN ZUMINDEST ETWAS HNGEN... (Ich hoffe nur, da ich mich bei den Zahlen nicht verrechnet habe). Was aber auf jeden Fall nun klar sein sollte: Ich kann nicht ein- fach den ermittelten Offset verringern, wenn ich nicht gleich- zeitig das Videofenster nach 'rechts' verschiebe, also dessen Lage im Grafikspeicher der Karte auf eine um den gleichen Wert erhhten Offset setze. Wie gehe ich nun dabei vor? Das einfachste ist, wenn man nun die Granularitt ermittelt, mit der das Fenster verschoben werden kann. Sie steht an der Offsetadresse 04h des Puffers. Zu beachten ist, da diese in Kb angegeben ist, man mu den Wert also noch mit 1024 multiplizieren, um auf die Byteanzahl zu kommen. Man kann sich aber auch die beliebte binre Logik als Brainstorming an tun, und die dort angegebene Zahl einfach um 10 Bits nach links verschieben - geht schneller und ist schner... Also: Granularitt nehmen und um 10 Stellen nach links shiften. Das Ergebnis nehmen, und wenn der Offsetwert grer als die oben angegebenen Grenzen sein sollten, diese solange um das 'Granularittsergebnis' (das so eben berechnete, um 10 Stellen nach links geshiftete Ergebnis) verringern, bis es innerhalb der genannten Grenzen liegt. Dabei mu man sich aber unbedingt die Anzahl der Abzge merken. Nun nehme ich diese Anzahl, stecke sie ins DX-Register, und verschiebe das Videofenster mittels der Unterfunktion 05h. Nun ist fast alles geschafft! Ich mu jetzt nur noch an die neue (eventuell verringerte) Offsetadresse (A000h:Offset) den Wert der Farbe schreiben, die zuvor der Routine bergeben wurde. Beispiel: xA : 1024, yA : 768; xK : 376, yK : 677. Ermittlung des 'PseudoOffsets': yK * xA = 677 * 1024 = 639248. 639248 + xK = 639248 + 376 = 639624 = PseudoOffset. Nun schaue man im Puffer nach und hole sich die Granularitt. Granu z.B. = 32. 32 * 1024 = 32768. Offset Anzahl 639624 0 606856 1 574088 2 541320 3 508552 4 475784 5 443016 6 410248 7 377480 8 344712 9 311944 10 279176 11 246408 12 213640 13 180872 14 148104 15 115336 16 82568 17 49800 18 Man mu das Videofenster also um 18 multipliziert mit der Granu- laritt verschieben (hier : um 589824 Bytes). Hat man das getan, ldt man an die Adresse A000h:49800d bzw. A000h:C288h den Wert der Farbe und darf sich glcklich schtzen. Natrlich mu man den Wert der Granularitt nicht unbedingt jedesmal abziehen. Man kann den 'PseudoOffset' auch die die Granularitt teilen, das Videofenster um das ganzzahlige Ergebnis multipliziert mit der Granularitt verschieben, und den Rest der Division als neuen Offset benutzen. Geschmackssache! Tja, nun. Ich glaube, da war relativ schwierig. Auch fr mich. Wahrscheinlich verstehe ich beim nchsten durchlesen selber nicht mehr, was ich da alles meinte. Pech! Das gute: Ich werde gleich ersteinmal ausprobieren, ob die Sachen berhaupt stimmen... Weitere Ergebnisse bekommt Ihr dann in der Assembler und vielleicht auch noch in der Pascalrubrik zu sehen. Schaut mal rein, wenn Euch die Theorie nicht schon ganz abgeschreckt hat. Vielleicht versteht Ihr im Programm dann ja auch dies oder das noch besser. Mein Tip: Unbedingt noch einmal lesen! Nun noch eine Komplettbersicht, die Euch als Zusammenfassung dienen soll: Um einen Pixel in einem der Modi 101h, 103h oder 105h zu setzen, sind folgende Schritte zu tun: - Man multipliziert die y-Koordinate mit der x-Auflsung und addiert zum Ergebnis die x-Koordinate. Das Ergebnis wird im folgenden PseudoOffset genannt. - Man finde die Granularitt heraus, und multipliziere sie mit 1024 = GRANU. - Man ziehe vom PseudoOffset GRANU sooft ab, bis dieser innerhalb der Schranken von 0 bis 65535 liegt. - Man merke sich gleichzeitg aber, wie oft man GRANU abgezogen hat = ANZAHL. - Man verschiebe das Videofenster mittels der Unterfunktion 05h der VESA-Treiber um ANZAHL*GRANU (ANZAHL wird ins DX-Register geladen). - Offset = eventuell verringerter Pseudooffset. Man lade die Farbe an die Adresse A000h:Offset und freu sich ber einen neuen Klecks am Monitor. Kemil * Hier ein paar Dinge, die eventuell behilflich sein knnten: - Lest den Text, in dem die VESA-Treiber-Funktionen erlutert werden (ein Button ber diesem!). - Die Koordinaten reichen immer von 0 bis zu ihrer Auflsung-1! Das heit: Auflsung 640x480: xK von 0 bis 639, yK von 0 bis 479. - 2^10 = 1024 - Schnelle Punkte setzen in einzelnen Modi erst in der nchsten Ausgabe - Es gibt (k?)ein Leben nach dem Selbstmord! PS: Ich habe hier auch irgendwo gesagt, da die Unterfunktion 01h einen Zeiger ES:DI braucht, der auf einen 29 Byte groen Puffer zeigt (dafr sind Zeiger schlielich da...). Nun reichen diese 29 Byte aber irgendwie einfach nicht aus. Daher: nehmt einen Puffer mit einer Grer von 256 Byte. Das klappt (zumindest bei mir).