Pixel setzen in den VESA-Modi $101/$103/$105 Nun geht es ans Eingemachte. Das, was ich im Theorieteil er- klrt habe, wird jetzt in die Pascal-Praxis umgesetzt. Ihr werdet sehen, da ich einige Sachen anders mache, als in der Theorie be- schrieben. Bei der Umsetzung in Assembler mach ich es wieder an- ders... aber ich erklr's Euch schon (wenn Ihr nicht von selbst drauf kommt). Nun ersteinmal ein Prog, das genau das macht, was die berschrift besagt: Punkte setzen. Und zwar 10000 Pixel an 10000 zufllig ge- whlte Koordinaten in zuflliger Farbe. Lat es ersteinmal auf Euch wirken: PROGRAM SetVESAPixel; USES CRT,DOS; TYPE Zeiger = RECORD Offset,Segment : WORD; END; VAR Regs : Registers; i,j,xAufloesung : WORD; Granu : LONGINT; Puffer : ARRAY[0..255] OF BYTE; { FensterProc : Zeiger;} PROCEDURE SetVESAPixPascal(x,y : LONGINT; Farbe : BYTE); VAR Anzahl : WORD; Offset : LONGINT; BEGIN Offset := y * xAufloesung + x; {Offset berechnen} Anzahl := Offset DIV Granu; {Wie oft mu Fenster verschoben werden?} Offset := Offset MOD Granu; {Neuer Offset im verschobenen Fenster} WITH Regs DO BEGIN AX := $4F05; BX := $0000; DX := Anzahl; INTR($10,Regs); {Fenster verschieben} END; {ASM XOR BX,BX MOV DX,Anzahl CALL DWORD PTR FensterProc; {Fenster verschieben END;} MEM[$A000:Offset] := Farbe; END; PROCEDURE InitSetVESAPixPascal; BEGIN WITH Regs DO BEGIN AX := $4F03; INTR($10,Regs); {Liefert VESAModus in BX zurck} CX := BX; {Vesa-Modus nach CX} ES := Seg(Puffer); {Segment von Puffer nach ES} DI := Ofs(Puffer); {Offset von Puffer nach DI} AX := $4F01; {Vesa-Infos holen} INTR($10,Regs); {und in ES:DI/Puffer ablegen} xAufloesung := Puffer[$13] * 256 + Puffer[$12]; Granu := (Puffer[$05] * 256 + Puffer[$04]) SHL 10; {Granu = Granu * 1024} { FensterProc.Offset := Puffer[$0D] * 256 + Puffer[$0C]; FensterProc.Segment := Puffer[$0F] * 256 + Puffer[$0E]; {Offset+Segment der Routine zum Fensterverschieben} END; END; BEGIN Randomize; WITH Regs DO BEGIN AX := $4F02; BX := $101; {Modus : 101h/480x640x256} INTR($10,Regs); {Initialisiere VESA-Modus} END; InitSetVESAPixPascal; FOR i := 1 TO 50000 DO SetVesaPixPascal(Random(640),Random(480),Random(256)); ReadLn; Regs.AX := $0003; INTR($10,Regs); {Zurck in den Textmodus} END. Das Prog schaltet am Anfang in den Modus $101, also in den Modus 640x480x256. Ich habe bewut auf direkte Assemblerprogrammierung verzichtet, damit auch diejenigen, die nicht mehr TP6 (oder hher arbeiten), das Prog zum Laufen bekommen. Euch wird aber aufgefal- len sein, da sich ein paar Zeilen, in denen auch Assemblerpro- grammierung vorkommt, als Kommentar eingefgt sind. Doch dazu unten mehr. Soweit drfte das Prog wohl noch verstanden worden sein. Nun wird InitSetVESAPixPascal aufgerufen, wo zuerst die Unterfunktion 03h aufgerufen wird, um den aktuellen VESA-Modus zu ermitteln. Das mag zwar berflssig erscheinen, schlielich knnte man diesen ja auch bergeben, doch wird so die Routine noch ein wenig mehr 'unabhngiger'. Danach ist die Unterfunk- tion $01 dran, die in dem Puffer, auf den ES:DI zeigt, einige Infos ablegt. Wichtig fr uns dabei sind die WORDs bei Puf- fer[$12] und Puffer[$04]. An Offset $12 steht nmlich das Wort (WORD), das die x-Auflsung angibt. Da es sich aber -wie gesagt- um ein Word handelt, und der Puffer nur aus lauter Bytes besteht, mssen die Inhalte der Offsetadressen $12 und $13 zusammengelegt werden. Nach Intel liegt das Lo-Byte immer vor dem Hi-Byte, wo- raus folgt: man mu das Hi-Byte an Offset $13 und das Lo-Byte an Offset $11 suchen. Um nun den endgltigen Wert fr die x-Aufl- sung zu erhalten, mu man das Hi-Byte mit 256 multiplizieren und dann das Lo-Byte addieren (verstanden?)! Mit der Granularitt, die im Puffer bei $04 zu finden ist, und bei der es sich wiederum um ein Word handelt, verfhrt man genauso: Puffer[$05]*256+Puf- fer[$04]. Nun steht hier aber nur die Kilobytezahl und nicht die Bytes selber. Also multiplizieren wir das ganze mit 1024 bzw. fhren einen 'Linksshift' um zehn Bits durch, was das gleiche be- wirkt. So, dann geht's zurck zum Hauptprogramm. Diese Init-Prozedur ist nicht unbedingt ntig - man knnte die genannten Infos auch je- desmal in der eigentlichen SetPix-Routine ermitteln. Doch drfte es dann um einiges langsamer werden, als es sowieso schon ist! Das Hauptprogramm luft weiter, indem nun 50000 mal die Prozedur SetPix mit zuflligen Koordinaten und Farben aufgerufen wird. Dann wartet es auf Enter und schaltet zurck in den Textmodus. Jetzt zu SetPix: Der PseudoOffset(oben: 'Offset') berechnet sich wie im Theorieteil gesagt: y-Koordinate mal x-Auflsung + x-Koor- dinate. Die Anzahl, wie oft das Videofenster verschoben werden mu, wird berechnet, indem der PseudoOffset durch die Granulari- tt geteilt wird (PseudoOffset DIV Granularitt). Der richtige Offset (oben auch als 'Offset') ergibt sich aus dem Rest der vor- herigen, ganzzahligen Division (PseudoOffset MOD Granularitt). Nun wird einfach noch das Fenster mittels der Unterfunktion $05 verschoben und dann die Farbe in $A000:Offset eingetragen. Fertig! Nun noch zu den oben erwhnten Kommentar-Zeilen. Diese dienen dazu, den relativ langsamen Interrupt-Aufruf, der das Video- fenster verschiebt (Unterfunktion $05), zu ersetzen, indem die Routine, die das Fenster verschiebt, direkt anzuspringen. Aller- dings geht das nur mittels einem FAR-CALL, also einem Aufruf einer Routine, die hchstwahrscheinlich auerhalb des eigent- lichen Code-Segments liegt. Aber das soll hier auch nicht weiter interessieren. Das eigentliche Problem liegt darin: Ich habe keine Ahnung, wie ich solch einen FAR-CALL in Pascal erzeugen soll, ohne den intergrierten Assembler zu benutzen. Also habe ich genau das getan: den intergrierten Assembler benutzt! Der Vorteil: Mit dieser Routine geht es um einiges schneller. Wer also TP 6 oder grer besitzt, sollte unbedingt die Kommentar- klammern entfernen. Einmal im Deklarationsteil (FensterProc), einmal in SetVESAPixPascal (der einzige Assemblerteil) und dann noch in InitSetVESAPixPascal, wo FensterProc mit der Adresse der Routine geladen wird. Zustzlich mu noch die alte 'Fensterver- schiebe-Routine' in Kommentarklammern gesetzt oder auch ganz ent- fernt werden. Das ist der Teil in SetVesaPixPascal von 'WITH Regs DO BEGIN' bis zum nchsten 'END;'. Ich hoffe es klappt bei Euch! Die Routine drfte noch nicht optimal sein. Dafr setzt sie aber in jedem der drei Modi Punkte. Allerdings wre es wahrscheinlich sinnvoller, fr jeden Modus eine eigene Routine zu schreiben, wenn man auf Geschwindigkeit aus ist. Auerdem wre dann natr- lich eine Assemblerroutine, die eingelinkt wird, vorteilhafter. Die Assemblerroutine gibt's schon diesmal (im Assemblerteil, wo auch sonst?!?), die Routinen fr jeden Modus einzeln gibt's beim nchsten mal. Wobei diese auch nicht allzu schwer sein drften. Wenn Ihr Routinen habt oder jetzt entwickeln werdet, dann schickt sie uns doch zu, wir stellen sie dann in MC #4 vor! Kemil