home *** CD-ROM | disk | FTP | other *** search
- (*--------------------------------------------------------------*)
- (* HERCULES.INC *)
- (* Bibliothek, um unter Turbo Pascal mit der Hercules-Karte *)
- (* Grafiken programmieren zu koennen. *)
- (*--------------------------------------------------------------*)
- (* Konstanten, Typen und Variablen fuer die Hercules--Karte *)
- TYPE HercStr = STRING[255];
-
- CONST Segm: ARRAY[0..1] OF INTEGER = ($B800, $B000);
- BitPos: ARRAY[1..8] OF BYTE = (1, 2, 4, 8,
- 16, 32, 64, 128);
- BildGr = $7FFF; (* Bildgröße 32767 Bytes *)
- HercPage : INTEGER = 0; (* Gerade aktive Bildschirmseite *)
- HercSeg : INTEGER = $B800; (* Segment d. Bildschirmseite *)
- HercXOr : BOOLEAN = FALSE; (* Flag fuer XOr-Modus *)
-
- VAR Bild: ARRAY[0..BildGr] OF BYTE ABSOLUTE $B800:$00;
- BildPuffer: ARRAY[0..BildGr] OF BYTE ABSOLUTE $B000:$00;
-
- (*------------------------------------------------------------*)
- (* Hochaufloesenden Grafik-Modus einschalten *)
- PROCEDURE HiRes;
-
- CONST IndexReg = $03B4; (* I 6845 Index Register *)
- DataReg = $03B5; (* I/O 6845 Data Register *)
- ModeCont = $03B8; (* O Display Mode Control Port *)
- ConfigSw = $03BF; (* O Configuration Switch *)
- TextVal: ARRAY[0..11] OF BYTE = ($61, $50, $52, $0F, $19,
- $06, $19, $19, $02, $0D,
- $0B, $0C);
- GrphVal: ARRAY[0..11] OF BYTE = ($35, $2D, $2E, $07, $5B,
- $02, $57, $57, $02, $03,
- $00, $00);
-
- VAR on, graph, RegSel: INTEGER;
-
- BEGIN
- graph:= $82; on:= graph + $8; Port[ModeCont]:= graph;
- FOR RegSel:=0 TO 11 DO BEGIN
- Port[IndexReg]:= RegSel; Port[DataReg]:= GrphVal[RegSel];
- END;
- Port[ConfigSw]:= 3; (* Full Mode *)
- Port[ModeCont]:= on; (* Einschalten *)
- END; (* Hires *)
- (*------------------------------------------------------------*)
- (* Zurueck in den Textmodus *)
- PROCEDURE TextMode;
-
- CONST IndexReg = $03B4; (* I 6845 Index Register *)
- DataReg = $03B5; (* I/O 6845 Data Register *)
- ModeCont = $03B8; (* O Display Mode Control Port *)
- ConfigSw = $03BF; (* O Configuration Switch *)
- TextVal: ARRAY[0..11] OF BYTE = ($61, $50, $52, $0F, $19,
- $06, $19, $19, $02, $0D,
- $0B, $0C);
- GrphVal: ARRAY[0..11] OF BYTE = ($35, $2D, $2E, $07, $5B,
- $02, $57, $57, $02, $03,
- $00, $00);
-
- VAR on, txt, RegSel: INTEGER;
-
- BEGIN
- txt := $20; on:= txt + $8; Port[ModeCont]:= txt;
- FOR RegSel:=0 TO 11 DO BEGIN
- Port[IndexReg]:= RegSel; Port[DataReg]:= TextVal[RegSel];
- END;
- Port[ConfigSw]:= 1; (* Diag Mode *)
- Port[ModeCont]:= on; (* Einschalten *)
- END; (* TextMode *)
- (*------------------------------------------------------------*)
- (* XOr-Modus Ein-/Ausschalten *)
- PROCEDURE HercXOrMode(flag : BOOLEAN);
-
- BEGIN
- HercXOr := flag;
- END;
- (*------------------------------------------------------------*)
- (* Aktive Bildschirmseite waehlen *)
- PROCEDURE SelectPage(Page : INTEGER);
- BEGIN
- HercPage := Page MOD 2;
- HercSeg := Segm[HercPage];
- END;
- (*------------------------------------------------------------*)
- (* Gerade aktive Bildschirmseite loeschen *)
- PROCEDURE ClrScr;
- BEGIN
- IF Odd(HercPage) THEN FillChar(BildPuffer, BildGr, $00)
- ELSE FillChar(Bild, BildGr, $00);
- END; (* ClrScr *)
- (*------------------------------------------------------------*)
- (* Gerade aktive Bildschirmseite hell schalten *)
- PROCEDURE LightScreen;
- BEGIN
- IF Odd(HercPage) THEN FillChar(BildPuffer, BildGr, $FF)
- ELSE FillChar(Bild, BildGr, $FF);
- END; (* LightScreen *)
- (*------------------------------------------------------------*)
- (* Gerade aktive Bildschirmseite invertieren *)
- PROCEDURE InvertScreen;
-
- VAR B : INTEGER;
- Puffer: ARRAY[0..BildGr] OF BYTE;
-
- BEGIN
- IF Odd(HercPage) THEN BEGIN
- FOR B:= 0 TO BildGr DO Puffer[B]:= NOT BildPuffer[B];
- Move(Puffer, BildPuffer, BildGr);
- END
- ELSE BEGIN
- FOR B:= 0 TO BildGr DO Puffer[B]:= NOT Bild[B];
- Move(Puffer, Bild, BildGr);
- END;
- END; (* InvertScreen *)
- (*------------------------------------------------------------*)
- (* Bildschirmseite "Page" (0 oder 1) in die andere kopieren. *)
- PROCEDURE CopyPage (Page: INTEGER);
- BEGIN
- IF Odd(Page) THEN Move(BildPuffer, Bild, BildGr)
- ELSE Move(Bild, BildPuffer, BildGr);
- END; (* CopyPage *)
- (*------------------------------------------------------------*)
- (* Einige Hilfsfunktionen fuer Berechnungenn *)
- FUNCTION ByteOffset(x, y: INTEGER): INTEGER;
- BEGIN
- ByteOffset:= $2000 * (y MOD 4) + 90*(y SHR 2) + (x SHR 3);
- END;
- (*------------------------------------------------------------*)
- FUNCTION BitOffset(x: INTEGER): INTEGER;
- BEGIN
- BitOffset:= 8 - (x MOD 8);
- END;
- (*------------------------------------------------------------*)
- (* Pruefen ob Pixel auf dem Bildschirm gesetzt ist (1=ja) *)
- FUNCTION GetDotColor(x,y: INTEGER): INTEGER;
- BEGIN
- GetDotColor := Ord(NOT(((Mem[Segm[Ord(Odd(HercPage))]
- :ByteOffset(x,y)]
- AND BitPos[BitOffset(x)]) = 0)));
- END; (* GetDotColor *)
- (*------------------------------------------------------------*)
- (* Punkt setzen *)
- PROCEDURE Plot(x, y : INTEGER; Farbe : INTEGER);
-
- VAR Offs : INTEGER;
-
- BEGIN
- Offs:= ByteOffset(x,y);
- IF HercXOr THEN
- Mem[HercSeg:Offs]:= Mem[HercSeg:Offs] XOR BitPos[BitOffset(x)]
- ELSE
- IF Farbe = 1 THEN
- Mem[HercSeg:Offs]:= (Mem[HercSeg:Offs] OR BitPos[BitOffset(x)])
- ELSE
- Mem[HercSeg:Offs]:=
- (Mem[HercSeg:Offs] AND (255-BitPos[BitOffset(x)]));
- END; (* Plot *)
- (*------------------------------------------------------------*)
- (* Ganzes Byte in den Bildschirmspeicher schreiben *)
- PROCEDURE ByteHerc (x, y : INTEGER; Farbe : INTEGER);
- BEGIN
- IF Farbe = 1 THEN Mem[HercSeg:ByteOffset(x,y)]:= $FF
- ELSE Mem[HercSeg:ByteOffset(x,y)]:= $00;
- END; (* ByteHerc *)
- (*------------------------------------------------------------*)
- (* Ein Zeichen an die Position x,y schreiben *)
- PROCEDURE WriteChar (ch : CHAR;
- x, y : INTEGER; invers : BOOLEAN);
-
- VAR OrdChar, i: INTEGER;
- Zeichensatz: ARRAY[0..127,0..7] OF BYTE ABSOLUTE $FFA6:$E;
-
- BEGIN
- x := (x-1)*8;
- CASE ch OF (* Umlaute abfangen *)
- #0..#127: OrdChar:= Ord(ch);
- 'ä': OrdChar:= Ord('a');
- 'ö': OrdChar:= Ord('o');
- 'ü': OrdChar:= Ord('u');
- 'Ä': OrdChar:= Ord('A');
- 'Ö': OrdChar:= Ord('O');
- 'Ü': OrdChar:= Ord('U');
- ELSE OrdChar:= 0;
- END; (*case ch *)
- FOR i:=0 TO 7 DO
- Mem[HercSeg:ByteOffset(x,y+i)]:= Zeichensatz[OrdChar,i];
- (* Fuer Umlaute noch Puenktchen setzen ! *)
- CASE ch OF
- 'ä','ö','ü': Mem[HercSeg:ByteOffset(x,y)]:= $66;
- 'Ä','Ö': BEGIN
- Mem[HercSeg:ByteOffset(x,y)]:= $66;
- Mem[HercSeg:ByteOffset(x,y+1)]:= $1C;
- Mem[HercSeg:ByteOffset(x,y+2)]:= $66;
- END;
- 'Ü': Mem[HercSeg:ByteOffset(x,y+1)]:= $00;
- 'ß': BEGIN
- Mem[HercSeg:ByteOffset(x,y+0)]:= $00;
- Mem[HercSeg:ByteOffset(x,y+1)]:= $7C;
- Mem[HercSeg:ByteOffset(x,y+2)]:= $C6;
- Mem[HercSeg:ByteOffset(x,y+3)]:= $FC;
- Mem[HercSeg:ByteOffset(x,y+4)]:= $C6;
- Mem[HercSeg:ByteOffset(x,y+5)]:= $FC;
- Mem[HercSeg:ByteOffset(x,y+6)]:= $C0;
- Mem[HercSeg:ByteOffset(x,y+7)]:= $40;
- END;
- END; (* case ch *)
- IF invers THEN
- FOR i:=0 TO 7 DO
- Mem[HercSeg:ByteOffset(x,y+i)] :=
- NOT Mem[HercSeg:ByteOffset(x,y+i)];
- END; (* WriteChar *)
- (*------------------------------------------------------------*)
- (* Ein Zeichen von Position x,y lesen *)
- FUNCTION GetScreenChar (x, y: INTEGER) : CHAR;
-
- VAR i, C: INTEGER;
- NumFind, invers,
- endwhile : BOOLEAN;
- Zeichen : ARRAY[0..7] OF BYTE;
- Zeichensatz : ARRAY[0..127,0..7] OF BYTE ABSOLUTE $FFA6:$E;
-
- LABEL Inv;
-
- BEGIN
- x:= (x-1)*8;
- invers:= FALSE; endwhile := FALSE;
- FOR i:=0 TO 7 DO Zeichen[i] := Mem[HercSeg:ByteOffset(x,y+i)];
- WHILE (NOT NumFind) AND (NOT endwhile) DO BEGIN
- C:= 0; NumFind:= FALSE;
- WHILE NOT NumFind AND (C < 128) DO BEGIN
- i:= 0;
- WHILE (Zeichen[i] <> Zeichensatz[C,i]) AND (C < 128) DO C := C+1;
- IF C < 128 THEN
- WHILE (Zeichen[i] = Zeichensatz[C,i]) AND (i < 8) DO i := i+1;
- IF i = 8 THEN NumFind:= TRUE
- ELSE C := C+1;
- END;
- IF NumFind THEN GetScreenChar := Chr(C)
- ELSE BEGIN (* Zeichen vielleicht invers ?! *)
- FOR i:=0 TO 7 DO Zeichen[i]:= NOT Zeichen[i];
- endwhile := TRUE;
- END
- END; (* WHILE *)
- IF NOT(NumFind) THEN GetScreenChar := Chr(0);
- END; (* GetScreenChar *)
- (*------------------------------------------------------------*)
- (* Kompletten String schreiben *)
- PROCEDURE WriteString(Str : HercStr;
- x, y: INTEGER; invers: BOOLEAN);
-
- VAR i : INTEGER;
-
- BEGIN
- FOR i := 1 TO Length(Str) DO
- WriteChar(Str[i], x+i-1, y, invers);
- END; (* WriteString *)
- (*------------------------------------------------------------*)
- (* Kompletten String (Laenge n) vom Screen lesen *)
- PROCEDURE ReadScreenStr(VAR Str : HercStr; x, y, n: INTEGER);
-
- VAR i : INTEGER;
- ch: CHAR;
-
- BEGIN
- Str := '';
- FOR i := 1 TO n DO Str := Str + GetScreenChar(x+i-1, y);
- END; (* ReadScreenStr *)
- (*------------------------------------------------------------*)
- (* Text gepackt (Byte-Reihe) in Bildschirmspeicher schreiben *)
- PROCEDURE WritePacked(Str : HercStr; x, y : INTEGER);
-
- VAR Offs, L, i: INTEGER;
-
- BEGIN
- x:= (x - 1) * 8; Offs:= ByteOffset(x,y);
- FOR i := 1 TO Length(Str) DO
- Mem[HercSeg:Offs+i-1]:= Ord(Str[i]);
- END; (* WritePacked *)
- (*------------------------------------------------------------*)
- (* Gepackten Text (Laenge n) wieder auslesen *)
- PROCEDURE ReadPacked(VAR Str: HercStr; x, y, n: INTEGER);
-
- VAR Offs, i : INTEGER;
- ch : CHAR;
-
- BEGIN
- x:= (x - 1) * 8; Offs := ByteOffset(x,y); Str := '';
- FOR i := 1 TO n DO BEGIN
- ch := Chr(Mem[HercSeg:Offs+i-1]);
- IF ch > #0 THEN Str := Str + ch;
- END;
- END; (* ReadLine *)
- (*------------------------------------------------------------*)
- (* Linie zeichnen *)
- PROCEDURE Draw(x1, y1, x2, y2, Farbe : INTEGER);
-
- VAR delta_x, delta_y, (* Differenzen Anfangs-..Endpunkt *)
- Zaehler, (* Zaehler fuer die Punkte *)
- Abweichung, (* Abweichung von der Linie *)
- x, y, temp : INTEGER; (* Plot-Koordinaten, Swap-Var. *)
-
- BEGIN (* Initialisierung *)
- Abweichung := 0;
- delta_x := x2 - x1;
- delta_y := y2 - y1;
- IF delta_y < 0 THEN (* Anfangs- und Endpunkte muessen vertauscht werden *)
- BEGIN
- temp := x1; x1 := x2; x2 := temp;
- temp := y1; y1 := y2; y2 := temp;
- delta_y := -delta_y; (* Die Steigungen wechseln *)
- delta_x := -delta_x; (* entsprechend das Vorzeichen *)
- END;
- Plot(x1, y1, Farbe); (* Ersten Punkt setzen *)
- x := x1; (* x und y initialisieren *)
- y := y1;
- IF delta_x >= 0 THEN (* Steigung positiv ==> Fall 1 oder 2 *)
- IF delta_x < delta_y THEN (* Steigung > 1 ==> Fall 1 *)
- FOR Zaehler := 1 TO Pred(delta_y) DO
- IF Abweichung < 0 THEN
- BEGIN
- x := Succ(x);
- y := Succ(y);
- Plot(x, y, Farbe);
- Abweichung := Abweichung + delta_y - delta_x;
- END
- ELSE
- BEGIN (* Abweichung >= 0 *)
- y := Succ(y);
- Plot(x, y, Farbe);
- Abweichung := Abweichung - delta_x;
- END
- ELSE (* 0 <= Steigung <= 1 ==> Fall 2 *)
- FOR Zaehler := 1 TO Pred(delta_x) DO
- IF Abweichung <= 0 THEN
- BEGIN
- x := Succ(x);
- Plot(x, y, Farbe);
- Abweichung := Abweichung + delta_y;
- END
- ELSE
- BEGIN (* Abweichung > 0 *)
- x := Succ(x);
- y := Succ(y);
- Plot(x, y, Farbe);
- Abweichung := Abweichung + delta_y - delta_x;
- END
- ELSE (* ==> Steigung negativ *)
- IF abs(delta_x) >= delta_y THEN (* 0 > Steigung >= -1 ==> Fall 3 *)
- FOR Zaehler := 1 TO Pred(abs(delta_x)) DO
- IF Abweichung <= 0 THEN
- BEGIN
- x := Pred(x);
- Plot(x, y, Farbe);
- Abweichung := Abweichung + delta_y;
- END
- ELSE
- BEGIN
- x := Pred(x);
- y := Succ(y);
- Plot(x, y, Farbe);
- Abweichung := Abweichung + delta_x + delta_y;
- END
- ELSE (* Steigung < -1 ==> Fall 4 *)
- FOR Zaehler := 1 TO Pred(delta_y) DO
- IF Abweichung < 0 THEN
- BEGIN
- x := Pred(x);
- y := Succ(y);
- Plot(x, y, Farbe);
- Abweichung := Abweichung + delta_x + delta_y;
- END
- ELSE
- BEGIN
- y := Succ(y);
- Plot(x, y, Farbe);
- Abweichung := Abweichung + delta_x;
- END;
- Plot(x2, y2, Farbe) (* letzten Punkt setzen *)
- END; (* Draw *)
- (*------------------------------------------------------------*)
- (* Rechteck zeichnen *)
- PROCEDURE Rechteck (x1, y1, x2, y2, Farbe : INTEGER);
-
- VAR x, y: INTEGER;
-
- BEGIN
- IF x1 > x2 THEN BEGIN x:= x2; x2:= x1; x1:= x; END;
- IF y1 > y2 THEN BEGIN y:= y2; y2:= y1; y1:= y; END;
- FOR x:= x1+1 TO x2-1 DO BEGIN
- Plot(x, y1, Farbe); Plot(x, y2, Farbe);
- END;
- FOR y:= y1 TO y2 DO BEGIN
- Plot(x1, y, Farbe); Plot(x2, y, Farbe);
- END;
- END; (* Rechteck *)
- (*------------------------------------------------------------*)
- (* Kreise Zeichnen *)
- PROCEDURE Circle (x_center, y_center,
- radius, Farbe : INTEGER);
- CONST Aspect_Ratio = 0.75; (* Entzerrungsfaktor *)
- Pi = 3.1415926;
-
- VAR zwei_r_quadrat, (* 2 mal radius hoch 2. INTEGER !!!! *)
- x_ende, (* Endwert x-Koordinate Achtel-Kreis *)
- AspRX, (* round(Aspect_Ratio*x) *)
- AspRY, (* round(Aspect_Ratio*y) *)
- x, y : INTEGER; (* Berechnete Koordinaten *)
-
- BEGIN (* Koordinaten initialisieren *)
- x := 0;
- y := radius;
- x_ende := Round(radius*Cos(Pi/4)); (* Endwert x-Koordinate berechnen *)
- zwei_r_quadrat := 2*radius*radius;
- REPEAT
- AspRX := Round(Aspect_Ratio*x);
- AspRY := Round(Aspect_Ratio*y);
- Plot(x_center + x, y_center + AspRY, Farbe);
- Plot(x_center - x, y_center + AspRY, Farbe);
- Plot(x_center + x, y_center - AspRY, Farbe);
- Plot(x_center - x, y_center - AspRY, Farbe);
- Plot(x_center + y, y_center + AspRX, Farbe);
- Plot(x_center - y, y_center + AspRX, Farbe);
- Plot(x_center + y, y_center - AspRX, Farbe);
- Plot(x_center - y, y_center - AspRX, Farbe);
- (* Neue x- und y-Werte berechnen *)
- IF (2*Succ(x)*Succ(x) + y*y + Pred(y)*Pred(y) - zwei_r_quadrat) > 0 THEN
- BEGIN (* naechster Punkt rechts unterhalb *)
- x := Succ(x);
- y := Pred(y);
- END
- ELSE (* naechster Punkt rechts davon *)
- x := Succ(x);
- UNTIL (x > x_ende);
- END; (* Draw *)
- (*------------------------------------------------------------*)
- (* Bildschirm-Hardcopy auf den Drucker (Epson-kompatible) *)
- PROCEDURE HardCopy (invers: BOOLEAN);
-
- CONST XRes = 720; (* Spalten- & Zeilenauflösung *)
- YRes = 348;
-
- VAR x, y: INTEGER;
- ch: CHAR;
- PortVal: BYTE;
-
- LABEL Exit;
-
- BEGIN
- Write(Lst, #27#108#12); (* Linker Rand in Spalte 12 *)
- FOR x:=0 TO (XRes-1) SHR 3 DO BEGIN
- Write(Lst, #27#75#92#1); (* BitImageMode 348 Images *)
- FOR y:=YRes-1 DOWNTO 0 DO BEGIN
- PortVal:= Mem[HercSeg:ByteOffset(x*8,y)];
- IF invers THEN PortVal:= NOT PortVal;
- Write(Lst, Chr(PortVal));
- END; (* for y *)
- WriteLn(Lst, #27#106#12); (* 12/216" Zeilenabstand zurück *)
- (* Abbruch des Drucks *)
- IF KeyPressed THEN Read(Kbd, ch);
- IF ch = #27 THEN GOTO Exit; (* Sorry, ist am einfachsten *)
- END; (* for x *)
- Exit: Write(Lst, #27#64); (* Drucker - Reset *)
- END; (* HardCopy *)
-
- (*****************************************************************)
- (* Ende HERCULES.INC *)
-