3 This file is part of the Free Pascal run time library.
4 Copyright (c) 1999-2000 by the Free Pascal development team
6 Graph unit implementation part
8 See the file COPYING.FPC, included in this distribution,
9 for details about the copyright.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 **********************************************************************}
21 firstCallOfInitGraph: boolean = true;
27 function strf(l: longint): string;
32 Procedure Log(Const s: String);
39 Procedure LogLn(Const s: string);
48 StdBufferSize = 4096; { Buffer size for FloodFill }
53 tinttable = array[0..16383] of smallint;
54 pinttable = ^tinttable;
56 WordArray = Array [0..StdbufferSize] Of word;
57 PWordArray = ^WordArray;
61 { Mask for each bit in byte used to determine pattern }
62 BitArray: Array[0..7] of byte =
63 ($01,$02,$04,$08,$10,$20,$40,$80);
64 RevbitArray: Array[0..7] of byte =
65 ($80,$40,$20,$10,$08,$04,$02,$01);
67 { pre expanded line patterns }
68 { 0 = LSB of byte pattern }
69 { 15 = MSB of byte pattern }
70 LinePatterns: Array[0..15] of BOOLEAN =
71 (TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,
72 TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE);
75 BGIPath : string = '.';
78 { Default font 8x8 system from IBM PC }
86 CurrentX : smallint; { viewport relative }
87 CurrentY : smallint; { viewport relative }
89 ClipPixels: Boolean; { Should cliiping be enabled }
92 CurrentWriteMode: smallint;
95 _GraphResult : smallint;
98 LineInfo : LineSettingsType;
99 FillSettings: FillSettingsType;
101 { information for Text Output routines }
102 CurrentTextInfo : TextSettingsType;
103 CurrentXRatio, CurrentYRatio: graph_float;
104 installedfonts: longint; { Number of installed fonts }
107 StartXViewPort: smallint; { absolute }
108 StartYViewPort: smallint; { absolute }
109 ViewWidth : smallint;
110 ViewHeight: smallint;
113 IsGraphMode : Boolean; { Indicates if we are in graph mode or not }
116 ArcCall: ArcCoordsType; { Information on the last call to Arc or Ellipse }
121 { ******************** HARDWARE INFORMATION ********************* }
122 { Should be set in InitGraph once only. }
123 IntCurrentMode : smallint;
124 IntCurrentDriver : smallint; { Currently loaded driver }
125 IntCurrentNewDriver: smallint;
128 MaxX : smallint; { Maximum resolution - ABSOLUTE }
129 MaxY : smallint; { Maximum resolution - ABSOLUTE }
131 PaletteSize : longint; { Maximum palette entry we can set, usually equal}
133 HardwarePages : byte; { maximum number of hardware visual pages }
135 DirectColor : Boolean ; { Is it a direct color mode? }
136 ModeList : PModeInfo;
138 newModeList: TNewModeInfo;
140 DirectVideo : Boolean; { Direct access to video memory? }
145 {--------------------------------------------------------------------------}
147 { LINE AND LINE RELATED ROUTINES }
149 {--------------------------------------------------------------------------}
153 procedure HLineDefault(x,x2,y: smallint); {$ifndef fpc}far;{$endif fpc}
159 { must we swap the values? }
166 { First convert to global coordinates }
167 X := X + StartXViewPort;
168 X2 := X2 + StartXViewPort;
169 Y := Y + StartYViewPort;
172 if LineClipped(x,y,x2,y,StartXViewPort,StartYViewPort,
173 StartXViewPort+ViewWidth, StartYViewPort+ViewHeight) then
181 procedure VLineDefault(x,y,y2: smallint); {$ifndef fpc}far;{$endif fpc}
186 { must we swap the values? }
193 { First convert to global coordinates }
194 X := X + StartXViewPort;
195 Y2 := Y2 + StartYViewPort;
196 Y := Y + StartYViewPort;
199 if LineClipped(x,y,x,y2,StartXViewPort,StartYViewPort,
200 StartXViewPort+ViewWidth, StartYViewPort+ViewHeight) then
203 for y := y to y2 do Directputpixel(x,y)
206 Procedure DirectPutPixelClip(x,y: smallint);
207 { for thickwidth lines, because they may call DirectPutPixel for coords }
208 { outside the current viewport (bug found by CEC) }
210 If (Not ClipPixels) Or
211 ((X >= StartXViewPort) And (X <= (StartXViewPort + ViewWidth)) And
212 (Y >= StartYViewPort) And (Y <= (StartYViewPort + ViewHeight))) then
218 procedure LineDefault(X1, Y1, X2, Y2: smallint); {$ifndef fpc}far;{$endif fpc}
221 deltax, deltay : smallint;
222 d, dinc1, dinc2: smallint;
228 Flag : Boolean; { determines pixel direction in thick lines }
229 NumPixels : smallint;
230 PixelCount : smallint;
231 OldCurrentColor: Word;
233 TmpNumPixels : smallint;
235 {******************************************}
237 {******************************************}
238 if lineinfo.LineStyle = SolidLn then
240 { we separate normal and thick width for speed }
241 { and because it would not be 100% compatible }
242 { with the TP graph unit otherwise }
245 {******************************************}
246 { SOLID LINES HORIZONTAL }
247 {******************************************}
248 if lineinfo.Thickness=NormWidth then
261 {******************************************}
262 { SOLID LINES VERTICAL }
263 {******************************************}
264 if lineinfo.Thickness=NormWidth then
276 { Convert to global coordinates. }
277 x1 := x1 + StartXViewPort;
278 x2 := x2 + StartXViewPort;
279 y1 := y1 + StartYViewPort;
280 y2 := y2 + StartYViewPort;
281 { if fully clipped then exit... }
284 if LineClipped(x1,y1,x2,y2,StartXViewPort, StartYViewPort,
285 StartXViewPort+ViewWidth, StartYViewPort+ViewHeight) then
288 {******************************************}
289 { SLOPED SOLID LINES }
290 {******************************************}
293 { Calculate deltax and deltay for initialisation }
294 deltax := abs(x2 - x1);
295 deltay := abs(y2 - y1);
297 { Initialize all vars based on which is the independent variable }
298 if deltax >= deltay then
302 { x is independent variable }
303 numpixels := deltax + 1;
304 d := (2 * deltay) - deltax;
305 dinc1 := deltay Shl 1;
306 dinc2 := (deltay - deltax) shl 1;
316 { y is independent variable }
317 numpixels := deltay + 1;
318 d := (2 * deltax) - deltay;
319 dinc1 := deltax Shl 1;
320 dinc2 := (deltax - deltay) shl 1;
327 { Make sure x and y move in the right directions }
339 { Start drawing at <x1, y1> }
344 If LineInfo.Thickness=NormWidth then
349 for i := 1 to numpixels do
351 DirectPutPixel(x, y);
364 CurrentColor := OldCurrentColor;
368 { Thick width lines }
371 for i := 1 to numpixels do
373 { all depending on the slope, we can determine }
374 { in what direction the extra width pixels will be put }
377 DirectPutPixelClip(x-1,y);
378 DirectPutPixelClip(x,y);
379 DirectPutPixelClip(x+1,y);
383 DirectPutPixelClip(x, y-1);
384 DirectPutPixelClip(x, y);
385 DirectPutPixelClip(x, y+1);
399 CurrentColor := OldCurrentColor;
405 {******************************************}
406 { begin patterned lines }
407 {******************************************}
409 { Convert to global coordinates. }
410 x1 := x1 + StartXViewPort;
411 x2 := x2 + StartXViewPort;
412 y1 := y1 + StartYViewPort;
413 y2 := y2 + StartYViewPort;
414 { if fully clipped then exit... }
417 if LineClipped(x1,y1,x2,y2,StartXViewPort, StartYViewPort,
418 StartXViewPort+ViewWidth, StartYViewPort+ViewHeight) then
422 OldCurrentColor := CurrentColor;
426 { Check if we must swap }
433 if LineInfo.Thickness = NormWidth then
435 for PixelCount:=x1 to x2 do
436 { optimization: PixelCount mod 16 }
437 if LinePatterns[PixelCount and 15] = TRUE then
439 DirectPutPixel(PixelCount,y2);
446 for PixelCount:=x1 to x2 do
447 { Optimization from Thomas - mod 16 = and 15 }
448 {this optimization has been performed by the compiler
449 for while as well (JM)}
450 if LinePatterns[PixelCount and 15] = TRUE then
452 DirectPutPixelClip(PixelCount,y2+i);
460 { Check if we must swap }
467 if LineInfo.Thickness = NormWidth then
469 for PixelCount:=y1 to y2 do
470 { compare if we should plot a pixel here , compare }
471 { with predefined line patterns... }
472 if LinePatterns[PixelCount and 15] = TRUE then
474 DirectPutPixel(x1,PixelCount);
481 for PixelCount:=y1 to y2 do
482 { compare if we should plot a pixel here , compare }
483 { with predefined line patterns... }
484 if LinePatterns[PixelCount and 15] = TRUE then
486 DirectPutPixelClip(x1+i,PixelCount);
493 oldCurrentColor := CurrentColor;
494 { Calculate deltax and deltay for initialisation }
495 deltax := abs(x2 - x1);
496 deltay := abs(y2 - y1);
498 { Initialize all vars based on which is the independent variable }
499 if deltax >= deltay then
503 { x is independent variable }
504 numpixels := deltax + 1;
505 d := (2 * deltay) - deltax;
506 dinc1 := deltay Shl 1;
507 dinc2 := (deltay - deltax) shl 1;
517 { y is independent variable }
518 numpixels := deltay + 1;
519 d := (2 * deltax) - deltay;
520 dinc1 := deltax Shl 1;
521 dinc2 := (deltax - deltay) shl 1;
528 { Make sure x and y move in the right directions }
540 { Start drawing at <x1, y1> }
544 If LineInfo.Thickness=ThickWidth then
547 TmpNumPixels := NumPixels-1;
549 for i := 0 to TmpNumPixels do
551 { all depending on the slope, we can determine }
552 { in what direction the extra width pixels will be put }
555 { compare if we should plot a pixel here , compare }
556 { with predefined line patterns... }
557 if LinePatterns[i and 15] = TRUE then
559 DirectPutPixelClip(x-1,y);
560 DirectPutPixelClip(x,y);
561 DirectPutPixelClip(x+1,y);
566 { compare if we should plot a pixel here , compare }
567 { with predefined line patterns... }
568 if LinePatterns[i and 15] = TRUE then
570 DirectPutPixelClip(x,y-1);
571 DirectPutPixelClip(x,y);
572 DirectPutPixelClip(x,y+1);
591 { instead of putting in loop , substract by one now }
592 TmpNumPixels := NumPixels-1;
594 for i := 0 to TmpNumPixels do
596 if LinePatterns[i and 15] = TRUE then
615 {******************************************}
616 { end patterned lines }
617 {******************************************}
619 CurrentColor:=OldCurrentColor;
624 {********************************************************}
625 { Procedure DummyPatternLine() }
626 {--------------------------------------------------------}
627 { This is suimply an procedure that does nothing which }
628 { can be passed as a patternlineproc for non-filled }
630 {********************************************************}
631 Procedure DummyPatternLine(x1, x2, y: smallint); {$ifdef tp} far; {$endif tp}
636 {********************************************************}
637 { Procedure InternalEllipse() }
638 {--------------------------------------------------------}
639 { This routine first calculates all points required to }
640 { draw a circle to the screen, and stores the points }
641 { to display in a buffer before plotting them. The }
642 { aspect ratio of the screen is taken into account when }
643 { calculating the values. }
644 {--------------------------------------------------------}
645 { INPUTS: X,Y : Center coordinates of Ellipse. }
646 { XRadius - X-Axis radius of ellipse. }
647 { YRadius - Y-Axis radius of ellipse. }
648 { stAngle, EndAngle: Start angle and end angles of the }
649 { ellipse (used for partial ellipses and circles) }
650 { pl: procedure which either draws a patternline (for }
651 { FillEllipse) or does nothing (arc etc) }
652 {--------------------------------------------------------}
655 {********************************************************}
657 Procedure InternalEllipseDefault(X,Y: smallint;XRadius: word;
658 YRadius:word; stAngle,EndAngle: word; pl: PatternLineProc); {$ifndef fpc}far;{$endif fpc}
659 Const ConvFac = Pi/180.0;
662 j, Delta, DeltaEnd: graph_float;
663 NumOfPixels: longint;
664 TempTerm: graph_float;
665 xtemp, ytemp, xp, yp, xm, ym, xnext, ynext,
666 plxpyp, plxmyp, plxpym, plxmym: smallint;
667 BackupColor, TmpAngle, OldLineWidth: word;
669 If LineInfo.ThickNess = ThickWidth Then
670 { first draw the two outer ellipses using normwidth and no filling (JM) }
672 OldLineWidth := LineInfo.Thickness;
673 LineInfo.Thickness := NormWidth;
674 InternalEllipseDefault(x,y,XRadius,YRadius,StAngle,EndAngle,
675 {$ifdef fpc}@{$endif fpc}DummyPatternLine);
676 InternalEllipseDefault(x,y,XRadius+1,YRadius+1,StAngle,EndAngle,
677 {$ifdef fpc}@{$endif fpc}DummyPatternLine);
678 If (XRadius > 0) and (YRadius > 0) Then
679 { draw the smallest ellipse last, since that one will use the }
680 { original pl, so it could possibly draw patternlines (JM) }
686 { restore line thickness }
687 LineInfo.Thickness := OldLineWidth;
689 { Adjust for screen aspect ratio }
690 XRadius:=(longint(XRadius)*10000) div XAspect;
691 YRadius:=(longint(YRadius)*10000) div YAspect;
692 If xradius = 0 then inc(xradius);
693 if yradius = 0 then inc(yradius);
694 { check for an ellipse with negligable x and y radius }
695 If (xradius <= 1) and (yradius <= 1) then
697 putpixel(x,y,CurrentColor);
706 { check if valid angles }
707 stangle := stAngle mod 361;
708 EndAngle := EndAngle mod 361;
709 { if impossible angles then swap them! }
710 if Endangle < StAngle then
716 { approximate the number of pixels required by using the circumference }
717 { equation of an ellipse. }
718 { Changed this formula a it (trial and error), but the net result is that }
719 { less pixels have to be calculated now }
720 NumOfPixels:=Round(Sqrt(3)*sqrt(sqr(XRadius)+sqr(YRadius)));
721 { Calculate the angle precision required }
722 Delta := 90.0 / NumOfPixels;
723 { for restoring after PatternLine }
724 BackupColor := CurrentColor;
725 { removed from inner loop to make faster }
726 { store some arccall info }
729 TempTerm := (StAngle)*ConvFac;
730 ArcCall.XStart := round(XRadius*Cos(TempTerm)) + X;
731 ArcCall.YStart := round(YRadius*Sin(TempTerm+Pi)) + Y;
732 TempTerm := (EndAngle)*ConvFac;
733 ArcCall.XEnd := round(XRadius*Cos(TempTerm)) + X;
734 ArcCall.YEnd := round(YRadius*Sin(TempTerm+Pi)) + Y;
735 { Always just go over the first 90 degrees. Could be optimized a }
736 { bit if StAngle and EndAngle lie in the same quadrant, left as an }
737 { exercise for the reader :) (JM) }
739 { calculate stop position, go 1 further than 90 because otherwise }
740 { 1 pixel is sometimes not drawn (JM) }
748 { this is used by both sin and cos }
749 TempTerm := (j+Delta)*ConvFac;
751 xnext := round(XRadius*Cos(TempTerm));
752 ynext := round(YRadius*Sin(TempTerm+Pi));
758 plxpyp := maxsmallint;
759 plxmyp := -maxsmallint-1;
760 plxpym := maxsmallint;
761 plxmym := -maxsmallint-1;
762 If (j >= StAngle) and (j <= EndAngle) then
765 PutPixel(xp,yp,CurrentColor);
767 If ((180-j) >= StAngle) and ((180-j) <= EndAngle) then
770 PutPixel(xm,yp,CurrentColor);
772 If ((j+180) >= StAngle) and ((j+180) <= EndAngle) then
775 PutPixel(xm,ym,CurrentColor);
777 If ((360-j) >= StAngle) and ((360-j) <= EndAngle) then
780 PutPixel(xp,ym,CurrentColor);
782 If (ynext <> ytemp) and
785 CurrentColor := FillSettings.Color;
786 pl(plxmyp+1,plxpyp-1,yp);
787 pl(plxmym+1,plxpym-1,ym);
788 CurrentColor := BackupColor;
791 Until j > (DeltaEnd);
794 {********************************************************}
795 { Procedure InternalEllipse() }
796 {--------------------------------------------------------}
797 { This routine first calculates all points required to }
798 { draw a circle to the screen, and stores the points }
799 { to display in a buffer before plotting them. The }
800 { aspect ratio of the screen is taken into account when }
801 { calculating the values. }
802 {--------------------------------------------------------}
803 { INPUTS: X,Y : Center coordinates of Ellipse. }
804 { XRadius - X-Axis radius of ellipse. }
805 { YRadius - Y-Axis radius of ellipse. }
806 { stAngle, EndAngle: Start angle and end angles of the }
807 { ellipse (used for partial ellipses and circles) }
808 {--------------------------------------------------------}
809 { NOTE: - uses the current write mode. }
810 { - Angles must both be between 0 and 360 }
811 {********************************************************}
813 Procedure InternalEllipseDefault (x, y : smallint;
814 xradius, yradius, stAngle, EndAngle : Word; pl: PatternLineProc); {$ifndef fpc} far; {$endif fpc}
815 { Draw an ellipse arc. Crude but it works (anyone have a better one?) }
817 aSqr, bSqr, twoaSqr, twobSqr, xa, ya, twoXbSqr, twoYaSqr, error : LongInt;
818 Alpha, TempTerm : graph_float;
820 plxpyp, plxmyp, plxpym, plxmym: smallint;
825 Procedure PlotPoints;
836 plxpyp := maxsmallint;
837 plxmyp := -maxsmallint-1;
838 plxpym := maxsmallint;
839 plxmym := -maxsmallint-1;
840 if LineInfo.Thickness = Normwidth then
842 If (Alpha+270>=StAngle) And (Alpha+270<=EndAngle) then
845 PutPixel (xm,ym, CurrentColor);
847 If ((180+270)-Alpha>=StAngle) And ((180+270)-Alpha<=EndAngle) then
850 PutPixel (xm,yp, CurrentColor);
852 If ((180+270)+Alpha>=StAngle) And ((180+270)+Alpha<=EndAngle) then
855 PutPixel (xp,yp, CurrentColor);
857 If ((360+270)-Alpha>=StAngle) And ((360+270)-Alpha<=EndAngle) then
860 PutPixel (xp,ym, CurrentColor);
865 If (Alpha+270>=StAngle) And (Alpha+270<=EndAngle) then
870 PutPixel (xm+i,ym+j, CurrentColor);
872 If ((180+270)-Alpha>=StAngle) And ((180+270)-Alpha<=EndAngle) then
877 PutPixel (xm+i,yp+j, CurrentColor);
879 If ((180+270)+Alpha>=StAngle) And ((180+270)+Alpha<=EndAngle) then
884 PutPixel (xp+i,yp+j, CurrentColor);
886 If ((360+270)-Alpha>=StAngle) And ((360+270)-Alpha<=EndAngle) then
891 PutPixel (xp+i,ym+j, CurrentColor);
896 CurrentColor := FillSettings.Color;
897 pl(plxmyp+1,plxpyp-1,yp);
898 pl(plxmym+1,plxpym-1,ym);
899 CurrentColor := BackupColor;
904 { check for an ellipse with negligable x and y radius }
905 If (xradius <= 1) and (yradius <= 1) then
907 putpixel(x,y,CurrentColor);
916 { for restoring after PatternLine }
917 BackupColor := CurrentColor;
918 If xradius = 0 then inc(xradius);
919 if yradius = 0 then inc(yradius);
920 { store arccall info }
923 TempTerm := StAngle*RadToDeg;
924 ArcCall.XStart := round(XRadius*Cos(TempTerm)) + X;
925 ArcCall.YStart := round(YRadius*Sin(TempTerm+Pi)) + Y;
926 TempTerm := EndAngle*RadToDeg;
927 ArcCall.XEnd := round(XRadius*Cos(TempTerm)) + X;
928 ArcCall.YEnd := round(YRadius*Sin(TempTerm+Pi)) + Y;
930 StAngle:=StAngle MOD 361;
931 EndAngle:=EndAngle MOD 361;
932 StAngle := StAngle + 270;
933 EndAngle := EndAngle + 270;
934 If StAngle>EndAngle then
936 StAngle:=StAngle Xor EndAngle; EndAngle:=EndAngle Xor StAngle; StAngle:=EndAngle Xor StAngle;
938 { Adjust for screen aspect ratio }
939 XRadius:=(longint(XRadius)*10000) div XAspect;
940 YRadius:=(longint(YRadius)*10000) div YAspect;
941 aSqr:=LongInt (xradius)*LongInt (xradius);
942 bSqr:=LongInt (yradius)*LongInt (yradius);
948 twoYaSqr:=ya*twoaSqr;
950 While twoXbSqr<=twoYaSqr Do Begin
951 If ya=0 then Alpha:=90 Else Alpha:=RadToDeg*Arctan (xa/ya); { Crude but it works }
954 Inc (twoXbSqr,twobSqr);
955 Inc (error,twoXbSqr-bSqr);
956 If error>=0 then Begin
958 Dec (twoYaSqr,twoaSqr);
959 Dec (error,twoYaSqr);
964 twoXbSqr:=xa*twobSqr;
967 While twoXbSqr>twoYaSqr Do Begin
968 If ya=0 then Alpha:=90 Else Alpha:=RadToDeg*Arctan (xa/ya);
971 Inc (twoYaSqr,twoaSqr);
972 Inc (error,twoYaSqr-aSqr);
973 If error>=0 then Begin
975 Dec (twoXbSqr,twobSqr);
976 Dec (error,twoXbSqr);
981 procedure PatternLineDefault(x1,x2,y: smallint); {$ifndef fpc}far;{$endif fpc}
982 {********************************************************}
983 { Draws a horizontal patterned line according to the }
984 { current Fill Settings. }
985 {********************************************************}
987 { - CurrentColor must be set correctly before entering }
989 {********************************************************}
991 NrIterations: smallint;
994 TmpFillPattern : byte;
996 OldCurrentColor : word;
998 { convert to global coordinates ... }
999 x1 := x1 + StartXViewPort;
1000 x2 := x2 + StartXViewPort;
1001 y := y + StartYViewPort;
1002 { if line was fully clipped then exit...}
1003 if LineClipped(x1,y,x2,y,StartXViewPort,StartYViewPort,
1004 StartXViewPort+ViewWidth, StartYViewPort+ViewHeight) then
1007 OldWriteMode := CurrentWriteMode;
1008 CurrentWriteMode := NormalPut;
1011 { Get the current pattern }
1012 TmpFillPattern := FillPatternTable
1013 [FillSettings.Pattern][(y and $7)+1];
1015 Case TmpFillPattern Of
1018 OldCurrentColor := CurrentColor;
1019 CurrentColor := CurrentBkColor;
1020 { hline converts the coordinates to global ones, but that has been done }
1021 { already here!!! Convert them back to local ones... (JM) }
1022 HLine(x1-StartXViewPort,x2-StartXViewPort,y-StartYViewPort);
1023 CurrentColor := OldCurrentColor;
1027 HLine(x1-StartXViewPort,x2-StartXViewPort,y-StartYViewPort);
1031 { number of times to go throuh the 8x8 pattern }
1032 NrIterations := abs(x2 - x1+8) div 8;
1033 For i:= 0 to NrIterations do
1038 if RevBitArray[x1 and 7] and TmpFillPattern <> 0 then
1039 DirectPutpixel(x1,y)
1042 { According to the TP graph manual, we overwrite everything }
1043 { which is filled up - checked against VGA and CGA drivers }
1045 OldCurrentColor := CurrentColor;
1046 CurrentColor := CurrentBkColor;
1047 DirectPutPixel(x1,y);
1048 CurrentColor := OldCurrentColor;
1053 CurrentWriteMode := OldWriteMode;
1060 CurrentWriteMode := OldWriteMode;
1066 procedure LineRel(Dx, Dy: smallint);
1069 Line(CurrentX, CurrentY, CurrentX + Dx, CurrentY + Dy);
1070 CurrentX := CurrentX + Dx;
1071 CurrentY := CurrentY + Dy;
1075 procedure LineTo(x,y : smallint);
1078 Line(CurrentX, CurrentY, X, Y);
1086 procedure Rectangle(x1,y1,x2,y2:smallint);
1089 { Do not draw the end points }
1090 Line(x1,y1,x2-1,y1);
1091 Line(x1,y1+1,x1,y2);
1092 Line(x2,y1,x2,y2-1);
1093 Line(x1+1,y2,x2,y2);
1097 procedure GetLineSettings(var ActiveLineInfo : LineSettingsType);
1100 Activelineinfo:=Lineinfo;
1104 procedure SetLineStyle(LineStyle: word; Pattern: word; Thickness: word);
1111 if (LineStyle > UserBitLn) or ((Thickness <> Normwidth) and (Thickness <> ThickWidth)) then
1112 _GraphResult := grError
1115 LineInfo.Thickness := Thickness;
1116 LineInfo.LineStyle := LineStyle;
1118 UserBitLn: Lineinfo.Pattern := pattern;
1119 SolidLn: Lineinfo.Pattern := $ffff; { ------- }
1120 DashedLn : Lineinfo.Pattern := $F8F8; { -- -- --}
1121 DottedLn: LineInfo.Pattern := $CCCC; { - - - - }
1122 CenterLn: LineInfo.Pattern := $FC78; { -- - -- }
1124 { setup pattern styles }
1129 { bitwise mask for each bit in the word }
1130 if (word($01 shl i) AND LineInfo.Pattern) <> 0 then
1131 LinePatterns[j]:=TRUE
1133 LinePatterns[j]:=FALSE;
1141 {--------------------------------------------------------------------------}
1143 { VIEWPORT RELATED ROUTINES }
1145 {--------------------------------------------------------------------------}
1148 Procedure ClearViewPortDefault; {$ifndef fpc}far;{$endif fpc}
1151 OldWriteMode, OldCurColor: word;
1152 LineSets : LineSettingsType;
1154 { CP is always RELATIVE coordinates }
1158 { Save all old settings }
1159 OldCurColor := CurrentColor;
1160 CurrentColor:=CurrentBkColor;
1161 OldWriteMode:=CurrentWriteMode;
1162 CurrentWriteMode:=NormalPut;
1163 GetLineSettings(LineSets);
1164 { reset to normal line style...}
1165 SetLineStyle(SolidLn, 0, NormWidth);
1166 { routines are relative here...}
1167 { ViewHeight is Height-1 ! }
1168 for J:=0 to ViewHeight do
1169 HLine(0, ViewWidth , J);
1171 { restore old settings...}
1172 SetLineStyle(LineSets.LineStyle, LineSets.Pattern, LineSets.Thickness);
1173 CurrentColor := OldCurColor;
1174 CurrentWriteMode := OldWriteMode;
1178 Procedure SetViewPort(X1, Y1, X2, Y2: smallint; Clip: Boolean);
1180 if (X1 > GetMaxX) or (X2 > GetMaxX) or (X1 > X2) or (X1 < 0) then
1183 logln('invalid setviewport parameters: ('
1184 +strf(x1)+','+strf(y1)+'), ('+strf(x2)+','+strf(y2)+')');
1185 logln('maxx = '+strf(getmaxx)+', maxy = '+strf(getmaxy));
1187 _GraphResult := grError;
1190 if (Y1 > GetMaxY) or (Y2 > GetMaxY) or (Y1 > Y2) or (Y1 < 0) then
1193 logln('invalid setviewport parameters: ('
1194 +strf(x1)+','+strf(y1)+'), ('+strf(x2)+','+strf(y2)+')');
1195 logln('maxx = '+strf(getmaxx)+', maxy = '+strf(getmaxy));
1197 _GraphResult := grError;
1200 { CP is always RELATIVE coordinates }
1203 StartXViewPort := X1;
1204 StartYViewPort := Y1;
1211 procedure GetViewSettings(var viewport : ViewPortType);
1213 ViewPort.X1 := StartXViewPort;
1214 ViewPort.Y1 := StartYViewPort;
1215 ViewPort.X2 := ViewWidth + StartXViewPort;
1216 ViewPort.Y2 := ViewHeight + StartYViewPort;
1217 ViewPort.Clip := ClipPixels;
1220 procedure ClearDevice;
1222 ViewPort: ViewPortType;
1228 ViewPort.X1 := StartXviewPort;
1229 ViewPort.X2 := ViewWidth - StartXViewPort;
1230 ViewPort.Y1 := StartYViewPort;
1231 ViewPort.Y2 := ViewHeight - StartYViewPort;
1232 ViewPort.Clip := ClipPixels;
1233 { put viewport to full screen }
1234 StartXViewPort := 0;
1236 StartYViewPort := 0;
1240 { restore old viewport }
1241 StartXViewPort := ViewPort.X1;
1242 ViewWidth := ViewPort.X2-ViewPort.X1;
1243 StartYViewPort := ViewPort.Y1;
1244 ViewHeight := ViewPort.Y2-ViewPort.Y1;
1245 ClipPixels := ViewPort.Clip;
1250 {--------------------------------------------------------------------------}
1252 { BITMAP PUT/GET ROUTINES }
1254 {--------------------------------------------------------------------------}
1257 Procedure GetScanlineDefault (X1, X2, Y : smallint; Var Data); {$ifndef fpc}far;{$endif fpc}
1258 {**********************************************************}
1259 { Procedure GetScanLine() }
1260 {----------------------------------------------------------}
1261 { Returns the full scanline of the video line of the Y }
1262 { coordinate. The values are returned in a WORD array }
1263 { each WORD representing a pixel of the specified scanline }
1264 { note: we only need the pixels inside the ViewPort! (JM) }
1265 { note2: extended so you can specify start and end X coord }
1266 { so it is usable for GetImage too (JM) }
1267 {**********************************************************}
1274 WordArray(Data)[x-x1]:=GetPixel(x, y);
1279 Function DefaultImageSize(X1,Y1,X2,Y2: smallint): longint; {$ifndef fpc}far;{$endif fpc}
1281 { each pixel uses two bytes, to enable modes with colors up to 64K }
1283 DefaultImageSize := 12 + (((X2-X1+1)*(Y2-Y1+1))*2);
1286 Procedure DefaultPutImage(X,Y: smallint; var Bitmap; BitBlt: Word); {$ifndef fpc}far;{$endif fpc}
1288 pt = array[0..$fffffff] of word;
1289 ptw = array[0..2] of longint;
1292 oldCurrentColor: word;
1293 oldCurrentWriteMode, i, j, y1, x1, deltaX, deltaX1, deltaY: smallint;
1296 LogLn('putImage at ('+strf(x)+','+strf(y)+') with width '+strf(ptw(Bitmap)[0])+
1297 ' and height '+strf(ptw(Bitmap)[1]));
1300 inc(x,startXViewPort);
1301 inc(y,startYViewPort);
1302 x1 := ptw(Bitmap)[0]+x; { get width and adjust end coordinate accordingly }
1303 y1 := ptw(Bitmap)[1]+y; { get height and adjust end coordinate accordingly }
1307 k := 3 * sizeOf(Longint) div sizeOf(Word); { Three reserved longs at start of bitmap }
1308 { check which part of the image is in the viewport }
1311 if y < startYViewPort then
1313 deltaY := startYViewPort - y;
1314 inc(k,(x1-x+1)*deltaY);
1315 y := startYViewPort;
1317 if y1 > startYViewPort+viewHeight then
1318 y1 := startYViewPort+viewHeight;
1319 if x < startXViewPort then
1321 deltaX := startXViewPort-x;
1322 x := startXViewPort;
1324 if x1 > startXViewPort + viewWidth then
1326 deltaX1 := x1 - (startXViewPort + viewWidth);
1327 x1 := startXViewPort + viewWidth;
1331 LogLn('deltax: '+strf(deltax)+', deltax1: '+strf(deltax1)+',deltay: '+strf(deltay));
1333 oldCurrentColor := currentColor;
1334 oldCurrentWriteMode := currentWriteMode;
1335 currentWriteMode := bitBlt;
1341 currentColor := pt(bitmap)[k];
1342 directPutPixel(i,j);
1347 currentWriteMode := oldCurrentWriteMode;
1348 currentColor := oldCurrentColor;
1351 Procedure DefaultGetImage(X1,Y1,X2,Y2: smallint; Var Bitmap); {$ifndef fpc}far;{$endif fpc}
1353 pt = array[0..$fffffff] of word;
1354 ptw = array[0..2] of longint;
1359 k:= 3 * Sizeof(longint) div sizeof(word); { Three reserved longs at start of bitmap }
1363 GetScanLine(x1,x2,j,pt(Bitmap)[k]);
1366 ptw(Bitmap)[0] := X2-X1; { First longint is width }
1367 ptw(Bitmap)[1] := Y2-Y1; { Second longint is height }
1368 ptw(bitmap)[2] := 0; { Third longint is reserved}
1376 Procedure GetArcCoords(var ArcCoords: ArcCoordsType);
1378 ArcCoords.X := ArcCall.X;
1379 ArcCoords.Y := ArcCall.Y;
1380 ArcCoords.XStart := ArcCall.XStart;
1381 ArcCoords.YStart := ArcCall.YStart;
1382 ArcCoords.XEnd := ArcCall.XEnd;
1383 ArcCoords.YEnd := ArcCall.YEnd;
1387 procedure SetVisualPageDefault(page : word); {$ifndef fpc}far;{$endif fpc}
1392 procedure SetActivePageDefault(page : word); {$ifndef fpc}far;{$endif fpc}
1396 procedure DirectPutPixelDefault(X,Y: smallint);
1398 Writeln(stderr,'Error: Not in graphics mode (use InitGraph and test GraphResult afterwards)');
1402 function GetPixelDefault(X,Y: smallint): word;
1404 Writeln(stderr,'Error: Not in graphics mode (use InitGraph and test GraphResult afterwards)');
1406 exit(0); { avoid warning }
1409 procedure PutPixelDefault(X,Y: smallint; Color: Word);
1411 Writeln(stderr,'Error: Not in graphics mode (use InitGraph and test GraphResult afterwards)');
1415 procedure SetRGBPaletteDefault(ColorNum, RedValue, GreenValue, BlueValue: smallint);
1417 Writeln(stderr,'Error: Not in graphics mode (use InitGraph and test GraphResult afterwards)');
1421 procedure GetRGBPaletteDefault(ColorNum: smallint; var
1422 RedValue, GreenValue, BlueValue: smallint);
1424 Writeln(stderr,'Error: Not in graphics mode (use InitGraph and test GraphResult afterwards)');
1429 procedure OutTextXYDefault(x,y : smallint;const TextString : string);forward;
1430 procedure CircleDefault(X, Y: smallint; Radius:Word);forward;
1432 Procedure DefaultHooks;
1433 {********************************************************}
1434 { Procedure DefaultHooks() }
1435 {--------------------------------------------------------}
1436 { Resets all hookable routine either to nil for those }
1437 { which need overrides, and others to defaults. }
1438 { This is called each time SetGraphMode() is called. }
1439 {********************************************************}
1441 { All default hooks procedures }
1444 DirectPutPixel := {$ifdef fpc}@{$endif}DirectPutPixelDefault;
1445 PutPixel := {$ifdef fpc}@{$endif}PutPixelDefault;
1446 GetPixel := {$ifdef fpc}@{$endif}GetPixelDefault;
1447 SetRGBPalette := {$ifdef fpc}@{$endif}SetRGBPaletteDefault;
1448 GetRGBPalette := {$ifdef fpc}@{$endif}GetRGBPaletteDefault;
1451 SetActivePage := {$ifdef fpc}@{$endif}SetActivePageDefault;
1452 SetVisualPage := {$ifdef fpc}@{$endif}SetVisualPageDefault;
1453 ClearViewPort := {$ifdef fpc}@{$endif}ClearViewportDefault;
1454 PutImage := {$ifdef fpc}@{$endif}DefaultPutImage;
1455 GetImage := {$ifdef fpc}@{$endif}DefaultGetImage;
1456 ImageSize := {$ifdef fpc}@{$endif}DefaultImageSize;
1457 GraphFreeMemPtr := nil;
1458 GraphGetMemPtr := nil;
1459 GetScanLine := {$ifdef fpc}@{$endif}GetScanLineDefault;
1460 Line := {$ifdef fpc}@{$endif}LineDefault;
1461 InternalEllipse := {$ifdef fpc}@{$endif}InternalEllipseDefault;
1462 PatternLine := {$ifdef fpc}@{$endif}PatternLineDefault;
1463 HLine := {$ifdef fpc}@{$endif}HLineDefault;
1464 VLine := {$ifdef fpc}@{$endif}VLineDefault;
1465 OuttextXY := {$ifdef fpc}@{$endif}OuttextXYDefault;
1466 Circle := {$ifdef fpc}@{$endif}CircleDefault;
1470 {********************************************************}
1471 { Procedure InitVars() }
1472 {--------------------------------------------------------}
1473 { Resets all internal variables, and resets all }
1474 { overridable routines. }
1475 {********************************************************}
1477 DirectVideo := TRUE; { By default use fastest access possible }
1480 ArcCall.XStart := 0;
1481 ArcCall.YStart := 0;
1484 { Reset to default values }
1485 IntCurrentMode := 0;
1486 IntCurrentDriver := 0;
1487 IntCurrentNewDriver := 0;
1494 DirectColor := FALSE;
1496 if hardwarepages=0 then; { remove note }
1503 function InstallUserDriver(Name: string; AutoDetectPtr: Pointer): smallint;
1505 _graphResult := grError;
1506 InstallUserDriver:=grError;
1509 function RegisterBGIDriver(driver: pointer): smallint;
1512 _graphResult := grError;
1513 RegisterBGIDriver:=grError;
1518 { ----------------------------------------------------------------- }
1521 Procedure Arc(X,Y : smallint; StAngle,EndAngle,Radius: word);
1524 OldWriteMode: word;}
1527 { Only if we are using thickwidths lines do we accept }
1528 { XORput write modes. }
1529 { OldWriteMode := CurrentWriteMode;
1530 if (LineInfo.Thickness = NormWidth) then
1531 CurrentWriteMode := NormalPut;}
1532 InternalEllipse(X,Y,Radius,Radius,StAngle,Endangle,{$ifdef fpc}@{$endif}DummyPatternLine);
1533 { CurrentWriteMode := OldWriteMode;}
1537 procedure Ellipse(X,Y : smallint; stAngle, EndAngle: word; XRadius,YRadius: word);
1539 InternalEllipse(X,Y,XRadius,YRadius,StAngle,Endangle,{$ifdef fpc}@{$endif}DummyPatternLine);
1543 procedure FillEllipse(X, Y: smallint; XRadius, YRadius: Word);
1544 {********************************************************}
1545 { Procedure FillEllipse() }
1546 {--------------------------------------------------------}
1547 { Draws a filled ellipse using (X,Y) as a center point }
1548 { and XRadius and YRadius as the horizontal and vertical }
1549 { axes. The ellipse is filled with the current fill color}
1550 { and fill style, and is bordered with the current color.}
1551 {********************************************************}
1553 InternalEllipse(X,Y,XRadius,YRadius,0,360,PatternLine)
1558 procedure CircleDefault(X, Y: smallint; Radius:Word);
1559 {********************************************************}
1560 { Draws a circle centered at X,Y with the given Radius. }
1561 {********************************************************}
1562 { Important notes: }
1563 { - Thickwidth circles use the current write mode, while}
1564 { normal width circles ALWAYS use CopyPut/NormalPut }
1565 { mode. (Tested against VGA BGI driver -CEC 13/Aug/99 }
1566 {********************************************************}
1567 var OriginalArcInfo: ArcCoordsType;
1571 if (Radius = 0) then
1574 if (Radius = 1) then
1576 { only normal put mode is supported by a call to PutPixel }
1577 PutPixel(X, Y, CurrentColor);
1581 { save state of arc information }
1582 { because it is not needed for }
1584 move(ArcCall,OriginalArcInfo, sizeof(ArcCall));
1585 if LineInfo.Thickness = Normwidth then
1587 OldWriteMode := CurrentWriteMode;
1588 CurrentWriteMode := CopyPut;
1590 InternalEllipse(X,Y,Radius,Radius,0,360,{$ifdef fpc}@{$endif}DummyPatternLine);
1591 if LineInfo.Thickness = Normwidth then
1592 CurrentWriteMode := OldWriteMode;
1593 { restore arc information }
1594 move(OriginalArcInfo, ArcCall,sizeof(ArcCall));
1597 procedure SectorPL(x1,x2,y: smallint); {$ifndef fpc}far;{$endif fpc}
1598 var plx1, plx2: smallint;
1599 {$ifdef sectorpldebug}
1601 {$endif sectorpldebug}
1603 {$ifdef sectorpldebug}
1604 assign(t,'sector.log');
1606 writeln(t,'Got here for line ',y);
1608 {$endif sectorpldebug}
1609 If (x1 = -maxsmallint) Then
1610 If (x2 = maxsmallint-1) Then
1611 { no ellipse points drawn on this line }
1612 If (((Y < ArcCall.Y) and (Y > ArcCall.YStart)) or
1613 ((Y > ArcCall.Y) and (Y < ArcCall.YStart))) Then
1614 { there is a part of the sector at this y coordinate, but no }
1615 { ellips points are plotted on this line, so draw a patternline }
1616 { between the lines connecting (arccall.x,arccall.y) with }
1617 { the start and the end of the arc (JM) }
1618 { use: y-y1=(y2-y1)/(x2-x1)*(x-x1) => }
1619 { x = (y-y1)/(y2-y1)*(x2-x1)+x1 }
1621 {$ifdef sectorpldebug}
1622 If (ArcCall.YStart-ArcCall.Y) = 0 then
1629 {$endif sectorpldebug}
1630 plx1 := (y-ArcCall.Y)*(ArcCall.XStart-ArcCall.X)
1631 div (ArcCall.YStart-ArcCall.Y)+ArcCall.X;
1632 {$ifdef sectorpldebug}
1633 If (ArcCall.YEnd-ArcCall.Y) = 0 then
1640 {$endif sectorpldebug}
1641 plx2 := (y-ArcCall.Y)*(ArcCall.XEnd-ArcCall.X)
1642 div (ArcCall.YEnd-ArcCall.Y)+ArcCall.X;
1645 plx1 := plx1 xor plx2;
1646 plx2 := plx1 xor plx2;
1647 plx1 := plx1 xor plx2;
1649 {$ifdef sectorpldebug}
1651 writeln(t,'lines: ',plx1,' - ',plx2);
1653 {$endif sectorpldebug}
1655 { otherwise two points which have nothing to do with the sector }
1658 { the arc is plotted at the right side, but not at the left side, }
1659 { fill till the line between (ArcCall.X,ArcCall.Y) and }
1660 { (ArcCall.XStart,ArcCall.YStart) }
1662 If (y < ArcCall.Y) then
1664 {$ifdef sectorpldebug}
1665 If (ArcCall.YEnd-ArcCall.Y) = 0 then
1672 {$endif sectorpldebug}
1673 plx1 := (y-ArcCall.Y)*(ArcCall.XEnd-ArcCall.X)
1674 div (ArcCall.YEnd-ArcCall.Y)+ArcCall.X
1676 else if (y > ArcCall.Y) then
1678 {$ifdef sectorpldebug}
1679 If (ArcCall.YStart-ArcCall.Y) = 0 then
1686 {$endif sectorpldebug}
1687 plx1 := (y-ArcCall.Y)*(ArcCall.XStart-ArcCall.X)
1688 div (ArcCall.YStart-ArcCall.Y)+ArcCall.X
1690 else plx1 := ArcCall.X;
1692 {$ifdef sectorpldebug}
1694 writeln(t,'right: ',plx1,' - ',plx2);
1696 {$endif sectorpldebug}
1699 If (x2 = maxsmallint-1) Then
1700 { the arc is plotted at the left side, but not at the rigth side. }
1701 { the right limit can be either the first or second line. Just take }
1702 { the closest one, but watch out for division by zero! }
1704 If (y < ArcCall.Y) then
1706 {$ifdef sectorpldebug}
1707 If (ArcCall.YStart-ArcCall.Y) = 0 then
1714 {$endif sectorpldebug}
1715 plx2 := (y-ArcCall.Y)*(ArcCall.XStart-ArcCall.X)
1716 div (ArcCall.YStart-ArcCall.Y)+ArcCall.X
1718 else if (y > ArcCall.Y) then
1720 {$ifdef sectorpldebug}
1721 If (ArcCall.YEnd-ArcCall.Y) = 0 then
1728 {$endif sectorpldebug}
1729 plx2 := (y-ArcCall.Y)*(ArcCall.XEnd-ArcCall.X)
1730 div (ArcCall.YEnd-ArcCall.Y)+ArcCall.X
1732 else plx2 := ArcCall.X;
1734 {$ifdef sectorpldebug}
1736 writeln(t,'left: ',plx1,' - ',plx2);
1738 {$endif sectorpldebug}
1741 { the arc is plotted at both sides }
1745 {$ifdef sectorpldebug}
1747 writeln(t,'normal: ',plx1,' - ',plx2);
1749 {$endif sectorpldebug}
1753 {$ifdef sectorpldebug}
1755 Writeln(t,'drawing...');
1757 {$endif sectorpldebug}
1758 PatternLine(plx1,plx2,y);
1762 procedure Sector(x, y: smallint; StAngle,EndAngle, XRadius, YRadius: Word);
1764 internalellipse(x,y,XRadius, YRadius, StAngle, EndAngle, {$ifdef fpc}@{$endif}SectorPL);
1765 Line(ArcCall.XStart, ArcCall.YStart, x,y);
1766 Line(x,y,ArcCall.Xend,ArcCall.YEnd);
1771 procedure SetFillStyle(Pattern : word; Color: word);
1774 { on invalid input, the current fill setting will be }
1776 if (Pattern > UserFill) or (Color > GetMaxColor) then
1779 logln('invalid fillstyle parameters');
1781 _GraphResult := grError;
1784 FillSettings.Color := Color;
1785 FillSettings.Pattern := Pattern;
1789 procedure SetFillPattern(Pattern: FillPatternType; Color: word);
1790 {********************************************************}
1791 { Changes the Current FillPattern to a user defined }
1792 { pattern and changes also the current fill color. }
1793 { The FillPattern is saved in the FillPattern array so }
1794 { it can still be used with SetFillStyle(UserFill,Color) }
1795 {********************************************************}
1800 if Color > GetMaxColor then
1803 logln('invalid fillpattern parameters');
1805 _GraphResult := grError;
1809 FillSettings.Color := Color;
1810 FillSettings.Pattern := UserFill;
1812 { Save the pattern in the buffer }
1814 FillPatternTable[UserFill][i] := Pattern[i];
1818 procedure Bar(x1,y1,x2,y2:smallint);
1819 {********************************************************}
1820 { Important notes for compatibility with BP: }
1821 { - WriteMode is always CopyPut }
1822 { - No contour is drawn for the lines }
1823 {********************************************************}
1825 origcolor : longint;
1826 origlinesettings: Linesettingstype;
1827 origwritemode : smallint;
1829 origlinesettings:=lineinfo;
1830 origcolor:=CurrentColor;
1838 { Always copy mode for Bars }
1839 origwritemode := CurrentWriteMode;
1840 CurrentWriteMode := CopyPut;
1842 { All lines used are of this style }
1843 Lineinfo.linestyle:=solidln;
1844 Lineinfo.thickness:=normwidth;
1846 case Fillsettings.pattern of
1849 Currentcolor:=CurrentBkColor;
1855 CurrentColor:=FillSettings.color;
1861 CurrentColor:=FillSettings.color;
1863 patternline(x1,x2,y);
1866 CurrentColor:= Origcolor;
1867 LineInfo := OrigLineSettings;
1868 CurrentWriteMode := OrigWritemode;
1874 procedure bar3D(x1, y1, x2, y2 : smallint;depth : word;top : boolean);
1876 origwritemode : smallint;
1877 OldX, OldY : smallint;
1879 origwritemode := CurrentWriteMode;
1880 CurrentWriteMode := CopyPut;
1882 Rectangle(x1,y1,x2,y2);
1884 { Current CP should not be updated in Bar3D }
1885 { therefore save it and then restore it on }
1892 Lineto(x1+depth,y1-depth);
1893 Lineto(x2+depth,y1-depth);
1898 Moveto(x2+depth,y1-depth);
1899 Lineto(x2+depth,y2-depth);
1905 CurrentWriteMode := origwritemode;
1910 {--------------------------------------------------------------------------}
1912 { COLOR AND PALETTE ROUTINES }
1914 {--------------------------------------------------------------------------}
1917 procedure SetColor(Color: Word);
1920 CurrentColor := Color;
1924 function GetColor: Word;
1927 GetColor := CurrentColor;
1930 function GetBkColor: Word;
1933 GetBkColor := CurrentBkColor;
1937 procedure SetBkColor(ColorNum: Word);
1938 { Background color means background screen color in this case, and it is }
1939 { INDEPENDANT of the viewport settings, so we must clear the whole screen }
1942 ViewPort: ViewportType;
1944 GetViewSettings(Viewport);
1946 logln('calling setviewport from setbkcolor');
1948 SetViewPort(0,0,MaxX,MaxY,FALSE);
1950 logln('calling setviewport from setbkcolor done');
1952 CurrentBkColor := ColorNum;
1954 if not DirectColor and (ColorNum<256) then
1956 DefaultColors[ColorNum].Red,
1957 DefaultColors[ColorNum].Green,
1958 DefaultColors[ColorNum].Blue);
1959 SetViewport(ViewPort.X1,Viewport.Y1,Viewport.X2,Viewport.Y2,Viewport.Clip);
1963 function GetMaxColor: word;
1964 { Checked against TP VGA driver - CEC }
1967 GetMaxColor:=MaxColor-1; { based on an index of zero so subtract one }
1975 Procedure MoveRel(Dx, Dy: smallint);
1977 CurrentX := CurrentX + Dx;
1978 CurrentY := CurrentY + Dy;
1981 Procedure MoveTo(X,Y: smallint);
1982 {********************************************************}
1983 { Procedure MoveTo() }
1984 {--------------------------------------------------------}
1985 { Moves the current pointer in VIEWPORT relative }
1986 { coordinates to the specified X,Y coordinate. }
1987 {********************************************************}
1994 function GraphErrorMsg(ErrorCode: smallint): string;
1998 grOk,grFileNotFound,grInvalidDriver: exit;
1999 grNoInitGraph: GraphErrorMsg:='Graphics driver not installed';
2000 grNotDetected: GraphErrorMsg:='Graphics hardware not detected';
2001 grNoLoadMem,grNoScanMem,grNoFloodMem: GraphErrorMsg := 'Not enough memory for graphics';
2002 grNoFontMem: GraphErrorMsg := 'Not enough memory to load font';
2003 grFontNotFound: GraphErrorMsg:= 'Font file not found';
2004 grInvalidMode: GraphErrorMsg := 'Invalid graphics mode';
2005 grError: GraphErrorMsg:='Graphics error';
2006 grIoError: GraphErrorMsg:='Graphics I/O error';
2007 grInvalidFont,grInvalidFontNum: GraphErrorMsg := 'Invalid font';
2008 grInvalidVersion: GraphErrorMsg:='Invalid driver version';
2015 Function GetMaxX: smallint;
2016 { Routine checked against VGA driver - CEC }
2021 Function GetMaxY: smallint;
2022 { Routine checked against VGA driver - CEC }
2030 Function GraphResult: smallint;
2032 GraphResult := _GraphResult;
2033 _GraphResult := grOk;
2037 Function GetX: smallint;
2043 Function GetY: smallint;
2048 Function GetDriverName: string;
2050 GetDriverName:=DriverName;
2054 procedure graphdefaults;
2055 { PS: GraphDefaults does not ZERO the ArcCall structure }
2056 { so a call to GetArcCoords will not change even the }
2057 { returned values even if GraphDefaults is called in }
2062 lineinfo.linestyle:=solidln;
2063 lineinfo.thickness:=normwidth;
2064 { reset line style pattern }
2066 LinePatterns[i] := TRUE;
2068 { By default, according to the TP prog's reference }
2069 { the default pattern is solid, and the default }
2070 { color is the maximum color in the palette. }
2071 fillsettings.color:=GetMaxColor;
2072 fillsettings.pattern:=solidfill;
2073 { GraphDefaults resets the User Fill pattern to $ff }
2074 { checked with VGA BGI driver - CEC }
2076 FillPatternTable[UserFill][i] := $ff;
2079 CurrentColor:=white;
2083 { Reset the viewport }
2084 StartXViewPort := 0;
2085 StartYViewPort := 0;
2095 { normal write mode }
2096 CurrentWriteMode := CopyPut;
2098 { Schriftart einstellen }
2099 CurrentTextInfo.font := DefaultFont;
2100 CurrentTextInfo.direction:=HorizDir;
2101 CurrentTextInfo.charsize:=1;
2102 CurrentTextInfo.horiz:=LeftText;
2103 CurrentTextInfo.vert:=TopText;
2105 XAspect:=10000; YAspect:=10000;
2109 procedure GetAspectRatio(var Xasp,Yasp : word);
2115 procedure SetAspectRatio(Xasp, Yasp : word);
2122 procedure SetWriteMode(WriteMode : smallint);
2123 { TP sets the writemodes according to the following scheme (JM) }
2126 xorput, andput: CurrentWriteMode := XorPut;
2127 notput, orput, copyput: CurrentWriteMode := CopyPut;
2132 procedure GetFillSettings(var Fillinfo:Fillsettingstype);
2134 Fillinfo:=Fillsettings;
2137 procedure GetFillPattern(var FillPattern:FillPatternType);
2139 FillPattern:=FillpatternTable[UserFill];
2147 procedure DrawPoly(numpoints : word;var polypoints);
2150 ppointtype = ^pointtype;
2151 pt = array[0..16000] of pointtype;
2157 if numpoints < 2 then
2159 _GraphResult := grError;
2162 for i:=0 to numpoints-2 do
2163 line(pt(polypoints)[i].x,
2164 pt(polypoints)[i].y,
2165 pt(polypoints)[i+1].x,
2166 pt(polypoints)[i+1].y);
2170 procedure PieSlice(X,Y,stangle,endAngle:smallint;Radius: Word);
2172 Sector(x,y,stangle,endangle,radius,radius);
2178 procedure internDetectGraph(var GraphDriver, GraphMode:smallint;
2179 calledFromInitGraph: boolean);
2180 var LoMode, HiMode: smallint;
2182 CpyDriver: smallint;
2186 {$ifndef nonewmodes}
2187 if not calledFromInitGraph or
2188 (graphDriver < lowNewDriver) or
2189 (graphDriver > highNewDriver) then
2191 { Search lowest supported bitDepth }
2192 graphdriver := D1bit;
2193 while (graphDriver <= highNewDriver) and
2196 getModeRange(graphDriver,loMode,hiMode);
2202 _GraphResult := grNotDetected;
2207 GetModeRange(GraphDriver,LoMode,HiMode);
2208 { save the highest mode possible...}
2210 logln('Found driver '+strf(graphdriver)+' with modes '+
2211 strf(lomode)+' - '+strf(himode));
2213 if HiMode <> -1 then
2216 CpyDriver:=GraphDriver;
2218 { go to next driver if it exists...}
2220 until (graphDriver > highNewDriver);
2225 getModeRange(graphDriver,loMode,hiMode);
2226 if hiMode <> -1 then
2228 cpyDriver := graphDriver;
2234 _GraphResult := grNotDetected;
2241 { search all possible graphic drivers in ascending order...}
2242 { usually the new driver numbers indicate newest hardware...}
2243 { Internal driver numbers start at VGA=9 }
2245 GetModeRange(GraphDriver,LoMode,HiMode);
2246 { save the highest mode possible...}
2248 logln('Found driver '+strf(graphdriver)+' with modes '+
2249 strf(lomode)+' - '+strf(himode));
2251 if HiMode = -1 then break;
2253 CpyDriver:=GraphDriver;
2254 { go to next driver if it exists...}
2257 { If this is equal to -1 then no graph mode possible...}
2258 if CpyMode = -1 then
2260 _GraphResult := grNotDetected;
2264 _GraphResult := grOK;
2265 GraphDriver := CpyDriver;
2266 GraphMode := CpyMode;
2269 procedure detectGraph(var GraphDriver: smallint; var GraphMode:smallint);
2271 internDetectGraph(graphDriver,graphMode,false);
2274 procedure InitGraph(var GraphDriver:smallint;var GraphMode:smallint;
2275 const PathToDriver:String);
2284 { path to the fonts (where they will be searched)...}
2285 bgipath:=PathToDriver;
2286 if (Length(bgipath) > 0) and (bgipath[length(bgipath)]<>dirchar) then
2287 bgipath:=bgipath+dirchar;
2289 if not assigned(SaveVideoState) then
2291 DriverName:=InternalDriverName; { DOS Graphics driver }
2293 if (Graphdriver=Detect)
2294 {$ifndef nonewmodes}
2295 or (GraphMode = detectMode)
2299 internDetectGraph(GraphDriver,GraphMode,true);
2300 If _GraphResult = grNotDetected then Exit;
2302 { _GraphResult is now already set to grOK by DetectGraph }
2303 IntCurrentDriver := GraphDriver;
2304 IntCurrentNewDriver := GraphDriver;
2305 { Actually set the graph mode...}
2306 if firstCallOfInitgraph then
2309 firstCallOfInitgraph := false;
2311 SetGraphMode(GraphMode);
2315 { Search if that graphics modec actually exists...}
2316 if SearchMode(GraphDriver,GraphMode) = nil then
2318 _GraphResult := grInvalidMode;
2323 _GraphResult := grOK;
2324 IntCurrentDriver := GraphDriver;
2325 IntCurrentNewDriver := GraphDriver;
2326 if firstCallOfInitgraph then
2329 firstCallOfInitgraph := false;
2331 SetGraphMode(GraphMode);
2337 procedure SetDirectVideo(DirectAccess: boolean);
2339 DirectVideo := DirectAccess;
2342 function GetDirectVideo: boolean;
2344 GetDirectVideo := DirectVideo;
2347 procedure GraphExitProc; {$ifndef fpc} far; {$endif fpc}
2348 { deallocates all memory allocated by the graph unit }
2354 { restore old exitproc! }
2355 exitproc := exitsave;
2356 if IsGraphMode and ((errorcode<>0) or (erroraddr<>nil)) then
2358 { release memory allocated for fonts }
2359 for c := 1 to installedfonts do
2361 If assigned(instr) Then
2362 Freemem(instr,instrlength);
2363 { release memory allocated for modelist }
2365 while assigned(list) do
2371 {$ifndef nonewmodes}
2372 for c := lowNewDriver to highNewDriver do
2374 list := newModeList.modeinfo[c];
2375 while assigned(list) do
2384 { We had copied the buffer of mode information }
2385 { and allocated it dynamically... now free it }
2386 { Warning: if GetVESAInfo returned false, this buffer is not allocated! (JM)}
2388 Dispose(VESAInfo.ModeList);
2393 procedure InitializeGraph;
2396 assign(debuglog,'grlog.txt');
2400 isgraphmode := false;
2402 {$ifndef nonewmodes}
2403 fillChar(newModeList.modeinfo,sizeof(newModeList.modeinfo),#0);
2404 { lo and hi modenumber are -1 currently (no modes supported) }
2405 fillChar(newModeList.loHiModeNr,sizeof(newModeList.loHiModeNr),#255);
2407 SaveVideoState := nil;
2408 RestoreVideoState := nil;
2414 { This must be called at startup... because GetGraphMode may }
2415 { be called even when not in graph mode. }
2417 LogLn('Calling QueryAdapterInfo...');
2420 { Install standard fonts }
2421 { This is done BEFORE startup... }
2422 InstalledFonts := 0;
2423 InstallUserFont('TRIP');
2424 InstallUserFont('LITT');
2425 InstallUserFont('SANS');
2426 InstallUserFont('GOTH');
2427 InstallUserFont('SCRI');
2428 InstallUserFont('SIMP');
2429 InstallUserFont('TSCR');
2430 InstallUserFont('LCOM');
2431 InstallUserFont('EURO');
2432 InstallUserFont('BOLD');
2433 { This installs an exit procedure which cleans up the mode list...}
2434 ExitSave := ExitProc;
2435 ExitProc := @GraphExitProc;
2437 charmessagehandler:=nil;
2442 Revision 1.1 2002/02/19 08:25:34 sasu
2445 Revision 1.1.2.1 2000/07/16 07:47:02 jonas
2446 * fixed several savevideo/restorevideostate related problems
2447 * moved exitsave pointer from graphh.inc to grap.inc to avoid name
2448 conflicts with people using this name in their own programs
2450 Revision 1.1 2000/07/13 06:30:51 michael
2453 Revision 1.39 2000/07/07 17:29:30 jonas
2454 * fixed setgraphmode together with the new graphdrivers
2456 Revision 1.38 2000/06/27 13:37:04 jonas
2457 * released -dnewmodes
2459 Revision 1.37 2000/06/23 19:56:37 jonas
2460 * setviewport was sometimes called with parameters from the previous
2461 active mode, either directly from setgraphmode or from
2464 Revision 1.36 2000/06/18 18:41:18 peter
2465 * detectmode between ifdef
2467 Revision 1.35 2000/06/18 08:11:53 jonas
2468 * release memory of newmodeinfo in graphexitproc
2470 Revision 1.34 2000/06/18 06:11:20 jonas
2471 + added missing detectMode stuff for -dnewmodes
2473 Revision 1.33 2000/06/17 19:09:22 jonas
2474 * new platform independent mode handling (between -dnewmodes)
2476 Revision 1.32 2000/06/07 07:33:42 jonas
2477 * calling a graph function when initgraph is not yet called now prints
2478 a nice error message instead of giving a Run Time Error
2480 Revision 1.31 2000/04/02 12:13:36 florian
2481 * some more procedures can be now hooked by the OS specific implementation
2483 Revision 1.30 2000/03/24 18:16:32 florian
2484 * introduce a DrawBitmapCharHoriz procedure variable to accelerate output on
2487 Revision 1.29 2000/03/24 13:01:15 florian
2488 * ClearViewPort fixed
2490 Revision 1.28 2000/03/19 11:20:13 peter
2491 * graph unit include is now independent and the dependent part
2493 * ggigraph unit for linux added
2495 Revision 1.60 2000/03/18 10:45:07 sg
2496 * Fix for ClearViewportDefault: The width and the height of the rectangle
2497 it filled has been one pixel too high.
2499 Revision 1.59 2000/03/17 13:28:54 sg
2500 * Use linux unit under Linux
2502 Revision 1.58 2000/03/08 14:20:14 jonas
2503 * writemode was not set to normalput during clearviewport (and it uses hline)
2505 Revision 1.57 2000/02/27 14:41:25 peter
2506 * removed warnings/notes
2508 Revision 1.56 2000/02/06 01:47:15 sg
2509 * For Linux, "/" is added to the bgipath instead of "\" if this character
2510 isn't already there.
2512 Revision 1.55 2000/01/07 16:41:37 daniel
2515 Revision 1.54 2000/01/07 16:32:25 daniel
2516 * copyright 2000 added
2518 Revision 1.53 2000/01/02 19:02:39 jonas
2519 * removed/commented out (inited but) unused vars and unused types
2521 Revision 1.52 1999/12/29 17:26:00 jonas
2522 + by default, also attempt to install the fonts that come with TP7
2524 Revision 1.51 1999/12/26 10:33:06 jonas
2525 * XAspect and YAspect are now words instead of smallints, they
2526 overflowed for resolutions > 640x480 otherwise
2527 * the number of pixels required for an ellipse in internalellipsedef
2528 is now calculated after the aspectratios have been taken into
2531 Revision 1.50 1999/12/21 17:42:17 jonas
2532 * changed vesa.inc do it doesn't try to use linear modes anymore (doesn't work
2534 * fixed mode detection so the low modenumber of a driver doesn't have to be zero
2535 anymore (so VESA autodetection now works)
2537 Revision 1.49 1999/12/21 09:16:48 pierre
2538 + CloseGraph if errors
2540 Revision 1.48 1999/12/20 11:22:36 peter
2541 * integer -> smallint to overcome -S2 switch needed for ggi version
2543 Revision 1.47 1999/12/12 13:34:20 jonas
2544 * putimage now performs the lipping itself and uses directputpixel
2545 (note: this REQUIRES or/and/notput support in directputpixel,
2546 this is not yet the case in the assembler versions!)
2547 * YOffset addition moved in hlinevesa256 and vlinevesa256
2548 because it uses still putpixel afterwards
2550 Revision 1.46 1999/12/11 23:41:38 jonas
2551 * changed definition of getscanlineproc to "getscanline(x1,x2,y:
2552 smallint; var data);" so it can be used by getimage too
2553 * changed getimage so it uses getscanline
2554 * changed floodfill, getscanline16 and definitions in Linux
2555 include files so they use this new format
2556 + getscanlineVESA256 for 256 color VESA modes (banked)
2558 Revision 1.45 1999/12/10 12:47:41 pierre
2559 * SetBkColor like BP by changing Palette entry zero
2561 Revision 1.44 1999/11/30 08:57:46 michael
2562 + Removed charmessagehandler declaration, it is in graphh.inc
2564 Revision 1.43 1999/11/28 16:13:55 jonas
2565 * corrected misplacement of call to initvars in initgraph
2566 + some extra debugging commands (for -dlogging) in the mode functions
2568 Revision 1.42 1999/11/28 12:19:59 jonas
2569 * _GraphResult is now properly set to grOK by DetectGraph and
2570 InitGraph if there are no errors
2572 Revision 1.41 1999/11/27 21:48:01 jonas
2573 * fixed VlineVESA256 and re-enabled it in graph.inc
2574 * added procedure detectgraph to interface of graph unit
2576 Revision 1.40 1999/11/25 17:44:14 pierre
2577 * memory corruption within GetImage removed
2579 Revision 1.39 1999/11/24 23:42:31 pierre
2580 * PutImage used an smallint index that became negative !!!!
2581 * Default needed procedure now genrate a RTE 218 instead of a
2582 GPF by call to nil pointer !
2584 Revision 1.38 1999/11/11 17:55:07 florian
2585 * the size was calculated wrong by imagesize
2587 Revision 1.37 1999/11/11 14:07:14 florian
2588 * better looking font
2590 Revision 1.36 1999/11/08 15:01:38 peter
2593 Revision 1.35 1999/11/08 11:15:22 peter
2594 * move graph.inc to the target dir
2596 Revision 1.34 1999/11/03 20:23:01 florian
2597 + first release of win32 gui support
2599 Revision 1.33 1999/10/17 10:20:13 jonas
2600 * fixed clipping for thickwidth lines (bug 659)
2601 * fixed the faster internalellipsedefault, but it doesn't plot
2602 all pixels (there are gaps in the ellipses)
2604 Revision 1.32 1999/09/28 15:07:46 jonas
2605 * fix for disposing font data because it can contain #0 chars
2607 Revision 1.31 1999/09/28 13:56:25 jonas
2608 * reordered some local variables (first 4 byte vars, then 2 byte vars
2610 * font data is now disposed in exitproc, exitproc is now called
2611 GraphExitProc (was CleanModes) and resides in graph.pp instead of in
2614 Revision 1.30 1999/09/27 23:34:41 peter
2615 * new graph unit is default for go32v2
2616 * removed warnings/notes
2618 Revision 1.29 1999/09/26 13:31:06 jonas
2619 * changed name of modeinfo variable to vesamodeinfo and fixed
2620 associated errors (fillchar(modeinfo,sizeof(tmodeinfo),#0) instead
2621 of sizeof(TVesamodeinfo) etc)
2622 * changed several sizeof(type) to sizeof(varname) to avoid similar
2623 errors in the future
2625 Revision 1.28 1999/09/25 11:48:43 jonas
2627 * small change to internalellipsedefault so less pixels are
2629 * some small corrections to graph.tex
2631 Revision 1.27 1999/09/24 22:52:38 jonas
2632 * optimized patternline a bit (always use hline when possible)
2633 * isgraphmode stuff cleanup
2634 * vesainfo.modelist now gets disposed in cleanmode instead of in
2635 closegraph (required moving of some declarations from vesa.inc to
2637 * queryadapter gets no longer called from initgraph (is called from
2638 initialization of graph unit)
2639 * bugfix for notput in 32k and 64k vesa modes
2640 * a div replaced by / in fillpoly
2642 Revision 1.26 1999/09/22 13:13:35 jonas
2643 * renamed text.inc -> gtext.inc to avoid conflict with system unit
2645 * isgraphmode now gets properly updated, so mode restoring works
2648 Revision 1.25 1999/09/18 22:21:10 jonas
2649 + hlinevesa256 and vlinevesa256
2650 + support for not/xor/or/andput in vesamodes with 32k/64k colors
2651 * lots of changes to avoid warnings under FPC
2653 Revision 1.24 1999/09/18 16:03:37 jonas
2654 * graph.pp: removed pieslice and sector from ToDo list
2655 * closegraph: exits now immidiately if isgraphmode = false (caused
2656 RTE 204 with VESA enabled if you set exitproc to call closegraph
2657 and also called closegraph explicitely before exit, like bgidemo)
2659 Revision 1.23 1999/09/17 13:58:31 jonas
2660 * another fix for a case where internalellipsedefault went haywire
2661 * sector() and pieslice() fully implemented!
2662 * small change to prevent buffer overflow with floodfill
2664 Revision 1.22 1999/09/15 13:37:50 jonas
2665 * small change to internalellipsedef to be TP compatible
2666 * fixed directputpixel for vga 320*200*256
2668 Revision 1.21 1999/09/13 12:49:08 jonas
2669 * fixed Arc: internallellipse went into an endless loop if StAngle =
2671 * FillEllipse is now much faster: no more floodfill,
2672 InternalEllipseDefault now draws the patternlines immediatety!
2674 Revision 1.20 1999/09/12 17:29:00 jonas
2675 * several changes to internalellipse to make it faster
2676 and to make sure it updates the ArcCall correctly
2677 (not yet done for width = 3)
2678 * Arc mostly works now, only sometimes an endless loop, don't know
2681 Revision 1.19 1999/09/11 19:43:01 jonas
2682 * FloodFill: did not take into account current viewport settings
2683 * GetScanLine: only get line inside viewport, data outside of it
2685 * InternalEllipseDefault: fix for when xradius or yradius = 0 and
2686 increase xradius and yradius always by one (TP does this too)
2687 * fixed conlict in vesa.inc from last update
2688 * some conditionals to avoid range check and overflow errors in
2689 places where it doesn't matter
2691 Revision 1.18 1999/07/26 09:38:41 florian
2692 * bar: y2 can be less y1, fixed
2693 * settextstyle: charsize can be 0, must be changed into 1
2695 Revision 1.17 1999/07/18 15:07:20 jonas
2696 + xor-, and and- orput support for VESA256 modes
2697 * compile with -dlogging if you wnt some info to be logged to grlog.txt
2699 Revision 1.16 1999/07/14 18:18:04 florian