

         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

